mirror of
https://github.com/libretro/RetroArch.git
synced 2025-04-02 10:51:52 -04:00
(Android) Reimplement native glue code
This commit is contained in:
parent
01399a2295
commit
3837a503b7
9 changed files with 398 additions and 487 deletions
|
@ -52,8 +52,6 @@ LOCAL_SRC_FILES = $(RARCH_PATH)/retroarch.c \
|
|||
$(RARCH_PATH)/gfx/state_tracker.c \
|
||||
$(RARCH_PATH)/input/null.c \
|
||||
input_android.c \
|
||||
android_native_app_glue.c \
|
||||
$(RARCH_PATH)/screenshot.c \
|
||||
$(RARCH_PATH)/conf/config_file.c \
|
||||
$(RARCH_PATH)/autosave.c \
|
||||
$(RARCH_PATH)/thread.c \
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef _ANDROID_GENERAL_H
|
||||
#define _ANDROID_GENERAL_H
|
||||
|
||||
#include <android_native_app_glue.h>
|
||||
#include "../../../boolean.h"
|
||||
|
||||
struct droid
|
||||
{
|
||||
struct android_app* app;
|
||||
bool init_quit;
|
||||
bool window_inited;
|
||||
};
|
||||
|
||||
extern struct droid g_android;
|
||||
|
||||
#endif
|
32
android/native/jni/android_general.h
Normal file
32
android/native/jni/android_general.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2012 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ANDROID_GENERAL_H
|
||||
#define _ANDROID_GENERAL_H
|
||||
|
||||
#include "android_glue.h"
|
||||
#include "../../../boolean.h"
|
||||
|
||||
struct droid
|
||||
{
|
||||
struct android_app* app;
|
||||
bool init_quit;
|
||||
bool window_inited;
|
||||
};
|
||||
|
||||
extern struct droid g_android;
|
||||
|
||||
#endif
|
|
@ -1,22 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ANDROID_NATIVE_APP_GLUE_H
|
||||
#define _ANDROID_NATIVE_APP_GLUE_H
|
||||
#ifndef _ANDROID_GLUE_H
|
||||
#define _ANDROID_GLUE_H
|
||||
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
|
@ -97,15 +80,6 @@ extern "C" {
|
|||
* Java objects.
|
||||
*/
|
||||
struct android_app {
|
||||
// Fill this in with the function to process main app commands (APP_CMD_*)
|
||||
void (*onAppCmd)(struct android_app* app, int32_t cmd);
|
||||
|
||||
// Fill this in with the function to process input events. At this point
|
||||
// the event has already been pre-dispatched, and it will be finished upon
|
||||
// return. Return 1 if you have handled the event, 0 for any default
|
||||
// dispatching.
|
||||
int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
|
||||
|
||||
// The ANativeActivity object instance that this app is running in.
|
||||
ANativeActivity* activity;
|
||||
|
||||
|
@ -283,26 +257,6 @@ extern "C" {
|
|||
APP_CMD_DESTROY,
|
||||
};
|
||||
|
||||
/**
|
||||
* Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
|
||||
* app command message.
|
||||
*/
|
||||
int8_t android_app_read_cmd(struct android_app* android_app);
|
||||
|
||||
/**
|
||||
* Call with the command returned by android_app_read_cmd() to do the
|
||||
* initial pre-processing of the given command. You can perform your own
|
||||
* actions for the command after calling this function.
|
||||
*/
|
||||
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
|
||||
|
||||
/**
|
||||
* Call with the command returned by android_app_read_cmd() to do the
|
||||
* final post-processing of the given command. You must have done your own
|
||||
* actions for the command before calling this function.
|
||||
*/
|
||||
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
|
||||
|
||||
/**
|
||||
* Dummy function you can call to ensure glue code isn't stripped.
|
||||
*/
|
||||
|
@ -314,11 +268,10 @@ extern "C" {
|
|||
*/
|
||||
extern void android_main(struct android_app* app);
|
||||
|
||||
extern void process_input(void);
|
||||
extern void process_cmd(void);
|
||||
extern void engine_handle_cmd(struct android_app* android_app, int32_t cmd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ANDROID_NATIVE_APP_GLUE_H */
|
||||
#endif
|
|
@ -1,401 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "android-general.h"
|
||||
#include "android_native_app_glue.h"
|
||||
|
||||
int8_t android_app_read_cmd(struct android_app* android_app)
|
||||
{
|
||||
int8_t cmd;
|
||||
|
||||
if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_SAVE_STATE:
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void print_cur_config(struct android_app* android_app)
|
||||
{
|
||||
char lang[2], country[2];
|
||||
AConfiguration_getLanguage(android_app->config, lang);
|
||||
AConfiguration_getCountry(android_app->config, country);
|
||||
|
||||
/*
|
||||
LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
|
||||
"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
|
||||
"modetype=%d modenight=%d",
|
||||
AConfiguration_getMcc(android_app->config),
|
||||
AConfiguration_getMnc(android_app->config),
|
||||
lang[0], lang[1], country[0], country[1],
|
||||
AConfiguration_getOrientation(android_app->config),
|
||||
AConfiguration_getTouchscreen(android_app->config),
|
||||
AConfiguration_getDensity(android_app->config),
|
||||
AConfiguration_getKeyboard(android_app->config),
|
||||
AConfiguration_getNavigation(android_app->config),
|
||||
AConfiguration_getKeysHidden(android_app->config),
|
||||
AConfiguration_getNavHidden(android_app->config),
|
||||
AConfiguration_getSdkVersion(android_app->config),
|
||||
AConfiguration_getScreenSize(android_app->config),
|
||||
AConfiguration_getScreenLong(android_app->config),
|
||||
AConfiguration_getUiModeType(android_app->config),
|
||||
AConfiguration_getUiModeNight(android_app->config));
|
||||
*/
|
||||
}
|
||||
|
||||
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_INPUT_CHANGED:
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_detachLooper(android_app->inputQueue);
|
||||
|
||||
android_app->inputQueue = android_app->pendingInputQueue;
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_attachLooper(android_app->inputQueue,
|
||||
android_app->looper, LOOPER_ID_INPUT, NULL,
|
||||
&android_app->inputPollSource);
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_INIT_WINDOW:
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->window = android_app->pendingWindow;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
break;
|
||||
case APP_CMD_RESUME:
|
||||
case APP_CMD_START:
|
||||
case APP_CMD_PAUSE:
|
||||
case APP_CMD_STOP:
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->activityState = cmd;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_CONFIG_CHANGED:
|
||||
AConfiguration_fromAssetManager(android_app->config,
|
||||
android_app->activity->assetManager);
|
||||
print_cur_config(android_app);
|
||||
break;
|
||||
case APP_CMD_DESTROY:
|
||||
android_app->destroyRequested = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->window = NULL;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_SAVE_STATE:
|
||||
break;
|
||||
case APP_CMD_RESUME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void app_dummy()
|
||||
{
|
||||
}
|
||||
|
||||
static void android_app_destroy(struct android_app* android_app)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_detachLooper(android_app->inputQueue);
|
||||
|
||||
AConfiguration_delete(android_app->config);
|
||||
android_app->destroyed = 1;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
// Can't touch android_app object after this.
|
||||
}
|
||||
|
||||
void process_input(void)
|
||||
{
|
||||
struct android_app* app = g_android.app;
|
||||
|
||||
AInputEvent* event = NULL;
|
||||
|
||||
if (AInputQueue_getEvent(app->inputQueue, &event) >= 0)
|
||||
{
|
||||
if (AInputQueue_preDispatchEvent(app->inputQueue, event))
|
||||
return;
|
||||
|
||||
int32_t handled = 0;
|
||||
|
||||
if (app->onInputEvent != NULL)
|
||||
handled = app->onInputEvent(app, event);
|
||||
|
||||
AInputQueue_finishEvent(app->inputQueue, event, handled);
|
||||
}
|
||||
}
|
||||
|
||||
void process_cmd(void)
|
||||
{
|
||||
struct android_app* app = g_android.app;
|
||||
int8_t cmd = android_app_read_cmd(app);
|
||||
|
||||
android_app_pre_exec_cmd(app, cmd);
|
||||
|
||||
if (app->onAppCmd != NULL)
|
||||
app->onAppCmd(app, cmd);
|
||||
|
||||
android_app_post_exec_cmd(app, cmd);
|
||||
}
|
||||
|
||||
static void* android_app_entry(void* param)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)param;
|
||||
|
||||
android_app->config = AConfiguration_new();
|
||||
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
|
||||
|
||||
print_cur_config(android_app);
|
||||
|
||||
android_app->cmdPollSource = LOOPER_ID_MAIN;
|
||||
android_app->inputPollSource = LOOPER_ID_INPUT;
|
||||
|
||||
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
|
||||
&android_app->cmdPollSource);
|
||||
android_app->looper = looper;
|
||||
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->running = 1;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
android_main(android_app);
|
||||
|
||||
android_app_destroy(android_app);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Native activity interaction (called from main thread)
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static struct android_app* android_app_create(ANativeActivity* activity,
|
||||
void* savedState, size_t savedStateSize)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
|
||||
memset(android_app, 0, sizeof(struct android_app));
|
||||
android_app->activity = activity;
|
||||
|
||||
pthread_mutex_init(&android_app->mutex, NULL);
|
||||
pthread_cond_init(&android_app->cond, NULL);
|
||||
|
||||
int msgpipe[2];
|
||||
if (pipe(msgpipe))
|
||||
return NULL;
|
||||
|
||||
android_app->msgread = msgpipe[0];
|
||||
android_app->msgwrite = msgpipe[1];
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
|
||||
|
||||
// Wait for thread to start.
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
while (!android_app->running)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
return android_app;
|
||||
}
|
||||
|
||||
static void android_app_write_cmd(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd);
|
||||
}
|
||||
|
||||
static void android_app_set_input(struct android_app* android_app,
|
||||
AInputQueue* inputQueue)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->pendingInputQueue = inputQueue;
|
||||
android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
|
||||
|
||||
while (android_app->inputQueue != android_app->pendingInputQueue)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_set_window(struct android_app* android_app, ANativeWindow* window)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
if (android_app->pendingWindow != NULL)
|
||||
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
|
||||
|
||||
android_app->pendingWindow = window;
|
||||
|
||||
if (window != NULL)
|
||||
android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
|
||||
|
||||
while (android_app->window != android_app->pendingWindow)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
android_app_write_cmd(android_app, cmd);
|
||||
|
||||
while (android_app->activityState != cmd)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_free(struct android_app* android_app)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app_write_cmd(android_app, APP_CMD_DESTROY);
|
||||
|
||||
while (!android_app->destroyed)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
close(android_app->msgread);
|
||||
close(android_app->msgwrite);
|
||||
pthread_cond_destroy(&android_app->cond);
|
||||
pthread_mutex_destroy(&android_app->mutex);
|
||||
free(android_app);
|
||||
}
|
||||
|
||||
static void onDestroy(ANativeActivity* activity)
|
||||
{
|
||||
android_app_free((struct android_app*)activity->instance);
|
||||
}
|
||||
|
||||
static void onStart(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
|
||||
}
|
||||
|
||||
static void onResume(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
|
||||
}
|
||||
|
||||
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void onPause(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
|
||||
}
|
||||
|
||||
static void onStop(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
|
||||
}
|
||||
|
||||
static void onConfigurationChanged(ANativeActivity* activity)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)activity->instance;
|
||||
android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
|
||||
}
|
||||
|
||||
static void onLowMemory(ANativeActivity* activity)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)activity->instance;
|
||||
android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
|
||||
}
|
||||
|
||||
static void onWindowFocusChanged(ANativeActivity* activity, int focused)
|
||||
{
|
||||
android_app_write_cmd((struct android_app*)activity->instance,
|
||||
focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
|
||||
}
|
||||
|
||||
static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
|
||||
{
|
||||
android_app_set_window((struct android_app*)activity->instance, window);
|
||||
}
|
||||
|
||||
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
|
||||
{
|
||||
android_app_set_window((struct android_app*)activity->instance, NULL);
|
||||
}
|
||||
|
||||
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
|
||||
{
|
||||
android_app_set_input((struct android_app*)activity->instance, queue);
|
||||
}
|
||||
|
||||
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
|
||||
{
|
||||
android_app_set_input((struct android_app*)activity->instance, NULL);
|
||||
}
|
||||
|
||||
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
|
||||
size_t savedStateSize)
|
||||
{
|
||||
activity->callbacks->onDestroy = onDestroy;
|
||||
activity->callbacks->onStart = onStart;
|
||||
activity->callbacks->onResume = onResume;
|
||||
activity->callbacks->onPause = onPause;
|
||||
activity->callbacks->onStop = onStop;
|
||||
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
|
||||
activity->callbacks->onLowMemory = onLowMemory;
|
||||
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
|
||||
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
|
||||
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
|
||||
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
|
||||
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
|
||||
|
||||
activity->instance = android_app_create(activity, savedState, savedStateSize);
|
||||
}
|
|
@ -15,7 +15,8 @@
|
|||
*/
|
||||
|
||||
#include <android/keycodes.h>
|
||||
#include "android-general.h"
|
||||
#include <unistd.h>
|
||||
#include "android_general.h"
|
||||
#include "../../../benchmark.h"
|
||||
#include "../../../general.h"
|
||||
#include "../../../driver.h"
|
||||
|
@ -278,7 +279,6 @@ static void setup_state_ids(void)
|
|||
|
||||
static void *android_input_init(void)
|
||||
{
|
||||
g_android.app->onInputEvent = engine_handle_input;
|
||||
pads_connected = 0;
|
||||
|
||||
|
||||
|
@ -321,15 +321,35 @@ static void android_input_poll(void *data)
|
|||
|
||||
// Read all pending events.
|
||||
int event;
|
||||
struct android_app* android_app = g_android.app;
|
||||
int id = ALooper_pollOnce(0, NULL, &event, NULL);
|
||||
|
||||
// Process this event.
|
||||
if(event)
|
||||
{
|
||||
if(id == LOOPER_ID_INPUT)
|
||||
process_input();
|
||||
{
|
||||
AInputEvent* event = NULL;
|
||||
|
||||
if (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
|
||||
{
|
||||
if (AInputQueue_preDispatchEvent(android_app->inputQueue, event))
|
||||
return;
|
||||
|
||||
int32_t handled = engine_handle_input(android_app, event);
|
||||
|
||||
AInputQueue_finishEvent(android_app->inputQueue, event, handled);
|
||||
}
|
||||
}
|
||||
else
|
||||
process_cmd();
|
||||
{
|
||||
int8_t cmd;
|
||||
|
||||
if (!read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
|
||||
cmd = -1;
|
||||
|
||||
engine_handle_cmd(android_app, cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,18 @@
|
|||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "android-general.h"
|
||||
#include "android_general.h"
|
||||
#include "../../../general.h"
|
||||
|
||||
static inline void android_app_write_cmd(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt)
|
||||
{
|
||||
return JNI_VERSION_1_2;
|
||||
|
@ -28,13 +36,55 @@ JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt)
|
|||
|
||||
JNIEXPORT void JNICALL JNI_OnUnLoad( JavaVM *vm, void *pvt) { }
|
||||
|
||||
static void print_cur_config(struct android_app* android_app)
|
||||
{
|
||||
char lang[2], country[2];
|
||||
AConfiguration_getLanguage(android_app->config, lang);
|
||||
AConfiguration_getCountry(android_app->config, country);
|
||||
|
||||
/*
|
||||
LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
|
||||
"keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
|
||||
"modetype=%d modenight=%d",
|
||||
AConfiguration_getMcc(android_app->config),
|
||||
AConfiguration_getMnc(android_app->config),
|
||||
lang[0], lang[1], country[0], country[1],
|
||||
AConfiguration_getOrientation(android_app->config),
|
||||
AConfiguration_getTouchscreen(android_app->config),
|
||||
AConfiguration_getDensity(android_app->config),
|
||||
AConfiguration_getKeyboard(android_app->config),
|
||||
AConfiguration_getNavigation(android_app->config),
|
||||
AConfiguration_getKeysHidden(android_app->config),
|
||||
AConfiguration_getNavHidden(android_app->config),
|
||||
AConfiguration_getSdkVersion(android_app->config),
|
||||
AConfiguration_getScreenSize(android_app->config),
|
||||
AConfiguration_getScreenLong(android_app->config),
|
||||
AConfiguration_getUiModeType(android_app->config),
|
||||
AConfiguration_getUiModeNight(android_app->config));
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the next main command.
|
||||
*/
|
||||
static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
||||
void engine_handle_cmd(struct android_app* android_app, int32_t cmd)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case APP_CMD_INPUT_CHANGED:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_INPUT_CHANGED.\n");
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_detachLooper(android_app->inputQueue);
|
||||
|
||||
android_app->inputQueue = android_app->pendingInputQueue;
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_attachLooper(android_app->inputQueue,
|
||||
android_app->looper, LOOPER_ID_INPUT, NULL,
|
||||
&android_app->inputPollSource);
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_SAVE_STATE:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_SAVE_STATE.\n");
|
||||
// The system has asked us to save our current state. Do so.
|
||||
|
@ -42,25 +92,52 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|||
case APP_CMD_INIT_WINDOW:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_INIT_WINDOW.\n");
|
||||
// The window is being shown, get it ready.
|
||||
if (g_android.app->window != NULL)
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->window = android_app->pendingWindow;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
if (android_app->window != NULL)
|
||||
g_android.window_inited = true;
|
||||
break;
|
||||
case APP_CMD_START:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_START.\n");
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->activityState = cmd;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_RESUME:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_RESUME.\n");
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->activityState = cmd;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_STOP:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_STOP.\n");
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->activityState = cmd;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_PAUSE:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_PAUSE.\n");
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->activityState = cmd;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
g_android.init_quit = true;
|
||||
break;
|
||||
case APP_CMD_TERM_WINDOW:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_TERM_WINDOW.\n");
|
||||
// The window is being hidden or closed, clean it up.
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->window = NULL;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
break;
|
||||
case APP_CMD_GAINED_FOCUS:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_GAINED_FOCUS.\n");
|
||||
|
@ -68,9 +145,21 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
|
|||
break;
|
||||
case APP_CMD_LOST_FOCUS:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_LOST_FOCUS.\n");
|
||||
if (!g_android.window_inited)
|
||||
{
|
||||
}
|
||||
/*
|
||||
if (!g_android.window_inited)
|
||||
{
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case APP_CMD_CONFIG_CHANGED:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_CONFIG_CHANGED.\n");
|
||||
AConfiguration_fromAssetManager(android_app->config,
|
||||
android_app->activity->assetManager);
|
||||
print_cur_config(android_app);
|
||||
break;
|
||||
case APP_CMD_DESTROY:
|
||||
RARCH_LOG("engine_handle_cmd: APP_CMD_DESTROY.\n");
|
||||
android_app->destroyRequested = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +208,8 @@ void android_main(struct android_app* state)
|
|||
|
||||
g_android.app = state;
|
||||
|
||||
struct android_app* android_app = g_android.app;
|
||||
|
||||
char rom_path[512];
|
||||
char libretro_path[512];
|
||||
|
||||
|
@ -133,8 +224,6 @@ void android_main(struct android_app* state)
|
|||
/* ugly hack for now - hardcode libretro path to 'allowed' dir */
|
||||
snprintf(libretro_path, sizeof(libretro_path), "/data/data/com.retroarch/lib/libretro.so");
|
||||
|
||||
g_android.app->onAppCmd = engine_handle_cmd;
|
||||
|
||||
int argc = 0;
|
||||
char *argv[MAX_ARGS] = {NULL};
|
||||
|
||||
|
@ -156,10 +245,17 @@ void android_main(struct android_app* state)
|
|||
{
|
||||
// Process this event.
|
||||
if (id)
|
||||
process_cmd();
|
||||
{
|
||||
int8_t cmd;
|
||||
|
||||
if (!read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
|
||||
cmd = -1;
|
||||
|
||||
engine_handle_cmd(android_app, cmd);
|
||||
}
|
||||
|
||||
// Check if we are exiting.
|
||||
if (g_android.app->destroyRequested != 0)
|
||||
if (android_app->destroyRequested != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -167,5 +263,234 @@ void android_main(struct android_app* state)
|
|||
RARCH_LOG("Starting RetroArch...\n");
|
||||
|
||||
rarch_main(argc, argv);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
void app_dummy()
|
||||
{
|
||||
}
|
||||
|
||||
static void* android_app_entry(void* param)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)param;
|
||||
|
||||
/* Init */
|
||||
android_app->config = AConfiguration_new();
|
||||
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
|
||||
|
||||
print_cur_config(android_app);
|
||||
|
||||
android_app->cmdPollSource = LOOPER_ID_MAIN;
|
||||
android_app->inputPollSource = LOOPER_ID_INPUT;
|
||||
|
||||
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
||||
ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
|
||||
&android_app->cmdPollSource);
|
||||
android_app->looper = looper;
|
||||
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->running = 1;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
/* Main function */
|
||||
android_main(android_app);
|
||||
|
||||
/* Destroy */
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
if (android_app->inputQueue != NULL)
|
||||
AInputQueue_detachLooper(android_app->inputQueue);
|
||||
|
||||
AConfiguration_delete(android_app->config);
|
||||
android_app->destroyed = 1;
|
||||
pthread_cond_broadcast(&android_app->cond);
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
// Can't touch android_app object after this.
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Native activity interaction (called from main thread)
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static struct android_app* android_app_create(ANativeActivity* activity,
|
||||
void* savedState, size_t savedStateSize)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
|
||||
memset(android_app, 0, sizeof(struct android_app));
|
||||
android_app->activity = activity;
|
||||
|
||||
pthread_mutex_init(&android_app->mutex, NULL);
|
||||
pthread_cond_init(&android_app->cond, NULL);
|
||||
|
||||
int msgpipe[2];
|
||||
if (pipe(msgpipe))
|
||||
return NULL;
|
||||
|
||||
android_app->msgread = msgpipe[0];
|
||||
android_app->msgwrite = msgpipe[1];
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
|
||||
|
||||
// Wait for thread to start.
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
while (!android_app->running)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
return android_app;
|
||||
}
|
||||
|
||||
|
||||
static void android_app_set_input(struct android_app* android_app,
|
||||
AInputQueue* inputQueue)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app->pendingInputQueue = inputQueue;
|
||||
android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
|
||||
|
||||
while (android_app->inputQueue != android_app->pendingInputQueue)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_set_window(struct android_app* android_app, ANativeWindow* window)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
if (android_app->pendingWindow != NULL)
|
||||
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
|
||||
|
||||
android_app->pendingWindow = window;
|
||||
|
||||
if (window != NULL)
|
||||
android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
|
||||
|
||||
while (android_app->window != android_app->pendingWindow)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
|
||||
android_app_write_cmd(android_app, cmd);
|
||||
|
||||
while (android_app->activityState != cmd)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
}
|
||||
|
||||
static void android_app_free(struct android_app* android_app)
|
||||
{
|
||||
pthread_mutex_lock(&android_app->mutex);
|
||||
android_app_write_cmd(android_app, APP_CMD_DESTROY);
|
||||
|
||||
while (!android_app->destroyed)
|
||||
pthread_cond_wait(&android_app->cond, &android_app->mutex);
|
||||
|
||||
pthread_mutex_unlock(&android_app->mutex);
|
||||
|
||||
close(android_app->msgread);
|
||||
close(android_app->msgwrite);
|
||||
pthread_cond_destroy(&android_app->cond);
|
||||
pthread_mutex_destroy(&android_app->mutex);
|
||||
free(android_app);
|
||||
}
|
||||
|
||||
static void onDestroy(ANativeActivity* activity)
|
||||
{
|
||||
android_app_free((struct android_app*)activity->instance);
|
||||
}
|
||||
|
||||
static void onStart(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
|
||||
}
|
||||
|
||||
static void onResume(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
|
||||
}
|
||||
|
||||
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void onPause(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
|
||||
}
|
||||
|
||||
static void onStop(ANativeActivity* activity)
|
||||
{
|
||||
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
|
||||
}
|
||||
|
||||
static void onConfigurationChanged(ANativeActivity* activity)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)activity->instance;
|
||||
android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
|
||||
}
|
||||
|
||||
static void onLowMemory(ANativeActivity* activity)
|
||||
{
|
||||
struct android_app* android_app = (struct android_app*)activity->instance;
|
||||
android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
|
||||
}
|
||||
|
||||
static void onWindowFocusChanged(ANativeActivity* activity, int focused)
|
||||
{
|
||||
android_app_write_cmd((struct android_app*)activity->instance,
|
||||
focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
|
||||
}
|
||||
|
||||
static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window)
|
||||
{
|
||||
android_app_set_window((struct android_app*)activity->instance, window);
|
||||
}
|
||||
|
||||
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
|
||||
{
|
||||
android_app_set_window((struct android_app*)activity->instance, NULL);
|
||||
}
|
||||
|
||||
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
|
||||
{
|
||||
android_app_set_input((struct android_app*)activity->instance, queue);
|
||||
}
|
||||
|
||||
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
|
||||
{
|
||||
android_app_set_input((struct android_app*)activity->instance, NULL);
|
||||
}
|
||||
|
||||
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
|
||||
size_t savedStateSize)
|
||||
{
|
||||
activity->callbacks->onDestroy = onDestroy;
|
||||
activity->callbacks->onStart = onStart;
|
||||
activity->callbacks->onResume = onResume;
|
||||
activity->callbacks->onPause = onPause;
|
||||
activity->callbacks->onStop = onStop;
|
||||
activity->callbacks->onConfigurationChanged = onConfigurationChanged;
|
||||
activity->callbacks->onLowMemory = onLowMemory;
|
||||
activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
|
||||
activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
|
||||
activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
|
||||
activity->callbacks->onInputQueueCreated = onInputQueueCreated;
|
||||
activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
|
||||
|
||||
activity->instance = android_app_create(activity, savedState, savedStateSize);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "android/native/jni/android-general.h"
|
||||
#include "android/native/jni/android_general.h"
|
||||
#endif
|
||||
|
||||
#if defined(XENON) || defined(__CELLOS_LV2__)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <EGL/egl.h> /* Requires NDK r5 or newer */
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include "../../android/native/jni/android-general.h"
|
||||
#include "../../android/native/jni/android_general.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue