diff --git a/frontend/drivers/android_native_app_glue.c b/frontend/drivers/android_native_app_glue.c new file mode 100644 index 0000000000..fc55a86e91 --- /dev/null +++ b/frontend/drivers/android_native_app_glue.c @@ -0,0 +1,330 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2015 - Daniel De Matteis + * Copyright (C) 2012-2015 - Michael Lelli + * + * 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 . + */ + +#include "platform_android.h" + +struct android_app *g_android; +struct android_app_userdata *g_android_userdata; + +void android_app_write_cmd(struct android_app *android_app, int8_t cmd) +{ + if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) + RARCH_ERR("Failure writing android_app cmd: %s\n", strerror(errno)); +} + +static void android_app_set_input(void *data, AInputQueue* inputQueue) +{ + struct android_app *android_app = (struct android_app*)data; + + if (!android_app) + return; + + slock_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) + scond_wait(android_app->cond, android_app->mutex); + + slock_unlock(android_app->mutex); +} + +static void android_app_set_window(void *data, ANativeWindow* window) +{ + struct android_app *android_app = (struct android_app*)data; + + if (!android_app) + return; + + slock_lock(android_app->mutex); + if (android_app->pendingWindow) + android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); + + android_app->pendingWindow = window; + + if (window) + android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); + + while (android_app->window != android_app->pendingWindow) + scond_wait(android_app->cond, android_app->mutex); + + slock_unlock(android_app->mutex); +} + +static void android_app_set_activity_state(void *data, int8_t cmd) +{ + struct android_app *android_app = (struct android_app*)data; + + if (!android_app) + return; + + slock_lock(android_app->mutex); + android_app_write_cmd(android_app, cmd); + while (android_app->activityState != cmd + && android_app->activityState != APP_CMD_DEAD) + scond_wait(android_app->cond, android_app->mutex); + slock_unlock(android_app->mutex); + + if (android_app->activityState == APP_CMD_DEAD) + RARCH_LOG("RetroArch native thread is dead.\n"); +} + +static void onDestroy(ANativeActivity* activity) +{ + struct android_app *android_app = (struct android_app*)activity->instance; + + if (!android_app) + return; + + RARCH_LOG("onDestroy: %p\n", activity); + sthread_join(android_app->thread); + RARCH_LOG("Joined with RetroArch native thread.\n"); + + close(android_app->msgread); + close(android_app->msgwrite); + scond_free(android_app->cond); + slock_free(android_app->mutex); + + free(android_app); +} + +static void onStart(ANativeActivity* activity) +{ + RARCH_LOG("Start: %p\n", activity); + android_app_set_activity_state((struct android_app*) + activity->instance, APP_CMD_START); +} + +static void onResume(ANativeActivity* activity) +{ + RARCH_LOG("Resume: %p\n", activity); + android_app_set_activity_state((struct android_app*) + activity->instance, APP_CMD_RESUME); +} + +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) +{ + struct android_app* android_app = (struct android_app*)activity->instance; + void* savedState = NULL; + + slock_lock(android_app->mutex); + android_app->stateSaved = 0; + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); + while (!android_app->stateSaved) + scond_wait(android_app->cond, android_app->mutex); + + if (android_app->savedState != NULL) + { + savedState = android_app->savedState; + *outLen = android_app->savedStateSize; + android_app->savedState = NULL; + android_app->savedStateSize = 0; + } + + slock_unlock(android_app->mutex); + + return savedState; +} + +static void onPause(ANativeActivity* activity) +{ + RARCH_LOG("Pause: %p\n", activity); + android_app_set_activity_state((struct android_app*) + activity->instance, APP_CMD_PAUSE); +} + +static void onStop(ANativeActivity* activity) +{ + RARCH_LOG("Stop: %p\n", 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; + + if (!android_app) + return; + + RARCH_LOG("ConfigurationChanged: %p\n", activity); + 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) +{ + RARCH_LOG("WindowFocusChanged: %p -- %d\n", activity, 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) +{ + RARCH_LOG("NativeWindowCreated: %p -- %p\n", activity, window); + android_app_set_window((struct android_app*)activity->instance, window); +} + +static void onNativeWindowDestroyed(ANativeActivity* activity, + ANativeWindow* window) +{ + RARCH_LOG("NativeWindowDestroyed: %p -- %p\n", activity, window); + android_app_set_window((struct android_app*)activity->instance, NULL); +} + +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) +{ + RARCH_LOG("InputQueueCreated: %p -- %p\n", activity, queue); + android_app_set_input((struct android_app*)activity->instance, queue); +} + +static void onInputQueueDestroyed(ANativeActivity* activity, + AInputQueue* queue) +{ + RARCH_LOG("InputQueueDestroyed: %p -- %p\n", activity, queue); + android_app_set_input((struct android_app*)activity->instance, NULL); +} + +static void android_app_entry(void *param) +{ + struct android_app* android_app = (struct android_app*)param; + ALooper *looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, + ALOOPER_EVENT_INPUT, NULL, NULL); + android_app->looper = looper; + + slock_lock(android_app->mutex); + android_app->running = 1; + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); + + android_main(android_app); +} + +static struct android_app* android_app_create(ANativeActivity* activity, + void* savedState, size_t savedStateSize) +{ + int msgpipe[2]; + struct android_app* android_app = (struct android_app*) + calloc(1, sizeof(*android_app)); + android_app->activity = activity; + + android_app->mutex = slock_new(); + android_app->cond = scond_new(); + + if (savedState != NULL) + { + android_app->savedState = malloc(savedStateSize); + android_app->savedStateSize = savedStateSize; + memcpy(android_app->savedState, savedState, savedStateSize); + } + + if (pipe(msgpipe)) + { + RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); + activity->instance = NULL; + } + android_app->msgread = msgpipe[0]; + android_app->msgwrite = msgpipe[1]; + + android_app->thread = sthread_create(android_app_entry, android_app); + + /* Wait for thread to start. */ + slock_lock(android_app->mutex); + while (!android_app->running) + scond_wait(android_app->cond, android_app->mutex); + slock_unlock(android_app->mutex); + + /* These are set only for the native activity, + * and are reset when it ends. */ + ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON + | AWINDOW_FLAG_FULLSCREEN, 0); + + return android_app; +} + +/* + * Native activity interaction (called from main thread) + **/ + +void ANativeActivity_onCreate(ANativeActivity* activity, + void* savedState, size_t savedStateSize) +{ + RARCH_LOG("Creating Native Activity: %p\n", activity); + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + 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); +} + +int system_property_get(const char *name, char *value) +{ + FILE *pipe; + int length = 0; + char buffer[PATH_MAX_LENGTH]; + char cmd[PATH_MAX_LENGTH]; + char *curpos = NULL; + + snprintf(cmd, sizeof(cmd), "getprop %s", name); + + pipe = popen(cmd, "r"); + + if (!pipe) + { + RARCH_ERR("Could not create pipe.\n"); + return 0; + } + + curpos = value; + + while (!feof(pipe)) + { + if (fgets(buffer, 128, pipe) != NULL) + { + int curlen = strlen(buffer); + + memcpy(curpos, buffer, curlen); + + curpos += curlen; + length += curlen; + } + } + + *curpos = '\0'; + + pclose(pipe); + + return length; +} diff --git a/frontend/drivers/platform_android.c b/frontend/drivers/platform_android.c index addf9a7940..2f8bfc69c5 100644 --- a/frontend/drivers/platform_android.c +++ b/frontend/drivers/platform_android.c @@ -27,166 +27,8 @@ #include "../../general.h" #include -struct android_app *g_android; -struct android_app_userdata *g_android_userdata; static pthread_key_t thread_key; -void android_app_write_cmd(struct android_app *android_app, int8_t cmd) -{ - if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) - RARCH_ERR("Failure writing android_app cmd: %s\n", strerror(errno)); -} - -static void android_app_set_input(void *data, AInputQueue* inputQueue) -{ - struct android_app *android_app = (struct android_app*)data; - - if (!android_app) - return; - - slock_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) - scond_wait(android_app->cond, android_app->mutex); - - slock_unlock(android_app->mutex); -} - -static void android_app_set_window(void *data, ANativeWindow* window) -{ - struct android_app *android_app = (struct android_app*)data; - - if (!android_app) - return; - - slock_lock(android_app->mutex); - if (android_app->pendingWindow) - android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); - - android_app->pendingWindow = window; - - if (window) - android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); - - while (android_app->window != android_app->pendingWindow) - scond_wait(android_app->cond, android_app->mutex); - - slock_unlock(android_app->mutex); -} - -static void android_app_set_activity_state(void *data, int8_t cmd) -{ - struct android_app *android_app = (struct android_app*)data; - - if (!android_app) - return; - - slock_lock(android_app->mutex); - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd - && android_app->activityState != APP_CMD_DEAD) - scond_wait(android_app->cond, android_app->mutex); - slock_unlock(android_app->mutex); - - if (android_app->activityState == APP_CMD_DEAD) - RARCH_LOG("RetroArch native thread is dead.\n"); -} - -static void onDestroy(ANativeActivity* activity) -{ - struct android_app *android_app = (struct android_app*)activity->instance; - - if (!android_app) - return; - - RARCH_LOG("onDestroy: %p\n", activity); - sthread_join(android_app->thread); - RARCH_LOG("Joined with RetroArch native thread.\n"); - - close(android_app->msgread); - close(android_app->msgwrite); - scond_free(android_app->cond); - slock_free(android_app->mutex); - - free(android_app); -} - -static void onStart(ANativeActivity* activity) -{ - RARCH_LOG("Start: %p\n", activity); - android_app_set_activity_state((struct android_app*) - activity->instance, APP_CMD_START); -} - -static void onResume(ANativeActivity* activity) -{ - RARCH_LOG("Resume: %p\n", activity); - android_app_set_activity_state((struct android_app*) - activity->instance, APP_CMD_RESUME); -} - -static void onPause(ANativeActivity* activity) -{ - RARCH_LOG("Pause: %p\n", activity); - android_app_set_activity_state((struct android_app*) - activity->instance, APP_CMD_PAUSE); -} - -static void onStop(ANativeActivity* activity) -{ - RARCH_LOG("Stop: %p\n", 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; - - if (!android_app) - return; - - RARCH_LOG("ConfigurationChanged: %p\n", activity); - android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); -} - -static void onWindowFocusChanged(ANativeActivity* activity, int focused) -{ - RARCH_LOG("WindowFocusChanged: %p -- %d\n", activity, 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) -{ - RARCH_LOG("NativeWindowCreated: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, window); -} - -static void onNativeWindowDestroyed(ANativeActivity* activity, - ANativeWindow* window) -{ - RARCH_LOG("NativeWindowDestroyed: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, NULL); -} - -static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) -{ - RARCH_LOG("InputQueueCreated: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, queue); -} - -static void onInputQueueDestroyed(ANativeActivity* activity, - AInputQueue* queue) -{ - RARCH_LOG("InputQueueDestroyed: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, NULL); -} - JNIEnv *jni_thread_getenv(void) { JNIEnv *env; @@ -219,21 +61,15 @@ static void jni_thread_destruct(void *value) pthread_setspecific(thread_key, NULL); } -static void android_app_entry(void *data) +void android_main(struct android_app *android_app) { char *argv[1]; int argc = 0; int ret_iterate; - struct android_app *android_app = (struct android_app*)data; g_android = android_app; g_android_userdata = (struct android_app_userdata*)calloc(1, sizeof(*g_android_userdata)); - slock_lock(android_app->mutex); - android_app->running = 1; - scond_broadcast(android_app->cond); - slock_unlock(android_app->mutex); - if (rarch_main(argc, argv, android_app) != 0) goto end; @@ -242,7 +78,7 @@ static void android_app_entry(void *data) }while(ret_iterate != 1); end: - main_exit(data); + main_exit(android_app); if (g_android_userdata) free(g_android_userdata); @@ -251,110 +87,6 @@ end: exit(0); } -/* - * Native activity interaction (called from main thread) - **/ - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) -{ - int msgpipe[2]; - struct android_app* android_app; - - (void)savedState; - (void)savedStateSize; - - RARCH_LOG("Creating Native Activity: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = NULL; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onLowMemory = NULL; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - - /* These are set only for the native activity, - * and are reset when it ends. */ - ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON - | AWINDOW_FLAG_FULLSCREEN, 0); - - if (pthread_key_create(&thread_key, jni_thread_destruct)) - RARCH_ERR("Error initializing pthread_key\n"); - - android_app = (struct android_app*)calloc(1, sizeof(*android_app)); - - memset(android_app, 0, sizeof(struct android_app)); - - android_app->activity = activity; - android_app->mutex = slock_new(); - android_app->cond = scond_new(); - - if (pipe(msgpipe)) - { - RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); - activity->instance = NULL; - } - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; - - android_app->thread = sthread_create(android_app_entry, android_app); - - /* Wait for thread to start. */ - slock_lock(android_app->mutex); - while (!android_app->running) - scond_wait(android_app->cond, android_app->mutex); - slock_unlock(android_app->mutex); - - activity->instance = android_app; -} - - -int system_property_get(const char *name, char *value) -{ - FILE *pipe; - int length = 0; - char buffer[PATH_MAX_LENGTH]; - char cmd[PATH_MAX_LENGTH]; - char *curpos = NULL; - - snprintf(cmd, sizeof(cmd), "getprop %s", name); - - pipe = popen(cmd, "r"); - - if (!pipe) - { - RARCH_ERR("Could not create pipe.\n"); - return 0; - } - - curpos = value; - - while (!feof(pipe)) - { - if (fgets(buffer, 128, pipe) != NULL) - { - int curlen = strlen(buffer); - - memcpy(curpos, buffer, curlen); - - curpos += curlen; - length += curlen; - } - } - - *curpos = '\0'; - - pclose(pipe); - - return length; -} - static void frontend_android_get_name(char *name, size_t sizeof_name) { int len = system_property_get("ro.product.model", name); @@ -832,7 +564,6 @@ static void frontend_android_init(void *data) { int32_t sdk; JNIEnv *env; - ALooper *looper; jclass class = NULL; jobject obj = NULL; struct android_app* android_app = (struct android_app*)data; @@ -842,10 +573,8 @@ static void frontend_android_init(void *data) if (!android_app) return; - looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, - ALOOPER_EVENT_INPUT, NULL, NULL); - android_app->looper = looper; + if (pthread_key_create(&thread_key, jni_thread_destruct)) + RARCH_ERR("Error initializing pthread_key\n"); RARCH_LOG("Waiting for Android Native Window to be initialized ...\n"); diff --git a/frontend/drivers/platform_android.h b/frontend/drivers/platform_android.h index aeb1a89c3a..a52ba40903 100644 --- a/frontend/drivers/platform_android.h +++ b/frontend/drivers/platform_android.h @@ -401,4 +401,6 @@ void android_app_write_cmd(struct android_app *android_app, int8_t cmd); extern struct android_app *g_android; extern struct android_app_userdata *g_android_userdata; +void android_main(struct android_app *android_app); + #endif /* _PLATFORM_ANDROID_H */ diff --git a/griffin/griffin.c b/griffin/griffin.c index 37fe8b65c6..a2a68b744d 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -612,6 +612,7 @@ FRONTEND #elif defined(__QNX__) #include "../frontend/drivers/platform_qnx.c" #elif defined(ANDROID) +#include "../frontend/drivers/android_native_app_glue.c" #include "../frontend/drivers/platform_android.c" #elif defined(__linux__) && !defined(ANDROID) #include "../frontend/drivers/platform_linux.c"