From 55562a96af230be9a8970c64e60ccf3baa511a43 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 3 Nov 2012 22:52:41 +0100 Subject: [PATCH] (Android) Clean up native glue code + inline some stuff --- android/native/jni/input_android.c | 62 +-- android/native/jni/main.c | 777 ++++++++++++++--------------- 2 files changed, 399 insertions(+), 440 deletions(-) diff --git a/android/native/jni/input_android.c b/android/native/jni/input_android.c index ca503634d7..089902f0c3 100644 --- a/android/native/jni/input_android.c +++ b/android/native/jni/input_android.c @@ -68,50 +68,6 @@ static uint64_t state[MAX_PADS]; static int8_t state_device_ids[MAX_DEVICE_IDS]; static int64_t keycode_lut[LAST_KEYCODE]; -static int32_t handle_touch(AInputEvent* event, int i) -{ - RARCH_PERFORMANCE_INIT(handle_touch); - RARCH_PERFORMANCE_START(handle_touch); -#ifdef RARCH_INPUT_DEBUG - int source = AInputEvent_getSource(event); - - switch(source) - { - case AINPUT_SOURCE_DPAD: - RARCH_LOG("AINPUT_SOURCE_DPAD, pad: %d.\n", i); - break; - case AINPUT_SOURCE_TOUCHSCREEN: - RARCH_LOG("AINPUT_SOURCE_TOUCHSCREEN, pad: %d.\n", i); - break; - case AINPUT_SOURCE_TOUCHPAD: - RARCH_LOG("AINPUT_SOURCE_TOUCHPAD, pad: %d.\n", i); - break; - case AINPUT_SOURCE_ANY: - RARCH_LOG("AINPUT_SOURCE_ANY, pad: %d.\n", i); - break; - case 0: - default: - RARCH_LOG("AINPUT_SOURCE_DEFAULT, pad: %d.\n", i); - break; - } -#endif - - float x = AMotionEvent_getX(event, 0); - float y = AMotionEvent_getY(event, 0); -#ifdef RARCH_INPUT_DEBUG - RARCH_LOG("AINPUT_EVENT_TYPE_MOTION, pad: %d, x: %f, y: %f.\n", i, x, y); -#endif - state[i] &= ~((1 << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT) | - (1 << RETRO_DEVICE_ID_JOYPAD_UP) | (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)); - state[i] |= PRESSED_LEFT(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; - state[i] |= PRESSED_RIGHT(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; - state[i] |= PRESSED_UP(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_UP) : 0; - state[i] |= PRESSED_DOWN(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; - - RARCH_PERFORMANCE_STOP(handle_touch); - return 1; -} - static void setup_keycode_lut(void) { for(int i = 0; i < LAST_KEYCODE; i++) @@ -316,7 +272,7 @@ static void android_input_poll(void *data) { (void)data; - // Read all pending events. + // Read all pending events. int do_event; struct android_app* android_app = g_android.app; int id = ALooper_pollOnce(0, NULL, &do_event, NULL); @@ -350,7 +306,21 @@ static void android_input_poll(void *data) #endif if(type == AINPUT_EVENT_TYPE_MOTION) - handled = handle_touch(event, i); + { + float x = AMotionEvent_getX(event, 0); + float y = AMotionEvent_getY(event, 0); +#ifdef RARCH_INPUT_DEBUG + RARCH_LOG("AINPUT_EVENT_TYPE_MOTION, pad: %d, x: %f, y: %f.\n", i, x, y); +#endif + state[i] &= ~((1 << RETRO_DEVICE_ID_JOYPAD_LEFT) | (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT) | + (1 << RETRO_DEVICE_ID_JOYPAD_UP) | (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)); + state[i] |= PRESSED_LEFT(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_LEFT) : 0; + state[i] |= PRESSED_RIGHT(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT) : 0; + state[i] |= PRESSED_UP(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_UP) : 0; + state[i] |= PRESSED_DOWN(x, y) ? (1 << RETRO_DEVICE_ID_JOYPAD_DOWN) : 0; + + handled = 1; + } else if(input_state < (1 << RARCH_FIRST_META_KEY)) { int action = AKeyEvent_getAction(event); diff --git a/android/native/jni/main.c b/android/native/jni/main.c index 9fec943420..a9ca539678 100644 --- a/android/native/jni/main.c +++ b/android/native/jni/main.c @@ -66,22 +66,6 @@ static void print_cur_config(struct android_app* android_app) AConfiguration_getUiModeNight(android_app->config)); } -static void android_app_destroy(struct android_app* android_app) -{ - RARCH_LOG("android_app_destroy!"); - free_saved_state(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. -} - static void android_get_char_argv(char *argv, size_t sizeof_argv, const char *arg_name) { JNIEnv *env; @@ -108,384 +92,6 @@ static void android_get_char_argv(char *argv, size_t sizeof_argv, const char *ar (*rarch_vm)->DetachCurrentThread(rarch_vm); } -#define MAX_ARGS 32 - -/** - * This is the main entry point of a native application that is using - * android_native_app_glue. It runs in its own thread, with its own - * event loop for receiving input events and doing other things. - */ - -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); - - ALooper* looper = 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; - - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - - memset(&g_android, 0, sizeof(g_android)); - g_android.app = android_app; - - char rom_path[512]; - char libretro_path[512]; - - // Get arguments */ - android_get_char_argv(rom_path, sizeof(rom_path), "ROM"); - android_get_char_argv(libretro_path, sizeof(libretro_path), "LIBRETRO"); - - RARCH_LOG("Checking arguments passed...\n"); - RARCH_LOG("ROM Filename: [%s].\n", rom_path); - RARCH_LOG("Libretro path: [%s].\n", libretro_path); - - /* ugly hack for now - hardcode libretro path to 'allowed' dir */ - snprintf(libretro_path, sizeof(libretro_path), "/data/data/com.retroarch/lib/libretro.so"); - - int argc = 0; - char *argv[MAX_ARGS] = {NULL}; - - argv[argc++] = strdup("retroarch"); - argv[argc++] = strdup(rom_path); - argv[argc++] = strdup("-L"); - argv[argc++] = strdup(libretro_path); - argv[argc++] = strdup("-v"); - - - if (android_app->savedState != NULL) - { - // We are starting with a previous saved state; restore from it. - RARCH_LOG("Restoring reentrant savestate.\n"); - g_android.state = *(struct saved_state*)android_app->savedState; - g_android.input_state = g_android.state.input_state; - } - - bool rarch_reentrant = (g_android.input_state & (1ULL << RARCH_REENTRANT)); - - if(rarch_reentrant) - { - RARCH_LOG("Native Activity started (reentrant).\n"); - } - else - { - RARCH_LOG("Native Activity started.\n"); - rarch_main_clear_state(); - } - - - g_extern.verbose = true; - - while(!(g_android.input_state & (1ULL << RARCH_WINDOW_READY))) - { - // Read all pending events. - int id; - - // Block forever waiting for events. - while ((id = ALooper_pollOnce(0, NULL, 0, NULL)) >= 0) - { - // Process this event. - if (id) - { - int8_t cmd; - - if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) - { - if(cmd == APP_CMD_SAVE_STATE) - free_saved_state(android_app); - } - else - cmd = -1; - - engine_handle_cmd(android_app, cmd); - } - - // Check if we are exiting. - if (android_app->destroyRequested != 0) - goto exit; - } - } - - int init_ret; - - if (rarch_reentrant) - { - init_ret = 0; - - /* We've done everything state-wise needed for RARCH_REENTRANT, - * get rid of it now */ - g_android.input_state |= ~(1ULL << RARCH_REENTRANT); - } - else if ((init_ret = rarch_main_init(argc, argv)) != 0) - { - RARCH_LOG("Initialization failed.\n"); - g_android.input_state |= (1ULL << RARCH_QUIT_KEY); - g_android.input_state |= (1ULL << RARCH_KILL); - } - - if (init_ret == 0) - { - RARCH_LOG("Initializing succeeded.\n"); - RARCH_LOG("RetroArch started.\n"); - rarch_init_msg_queue(); - while (rarch_main_iterate()); - RARCH_LOG("RetroArch stopped.\n"); - } - -exit: - if(g_android.input_state & (1ULL << RARCH_QUIT_KEY)) - { - RARCH_LOG("Deinitializing RetroArch...\n"); - rarch_main_deinit(); - rarch_deinit_msg_queue(); -#ifdef PERF_TEST - rarch_perf_log(); -#endif - rarch_main_clear_state(); - - /* Make sure to quit RetroArch later on too */ - g_android.input_state |= (1ULL << RARCH_KILL); - } - - if(g_android.input_state & (1ULL << RARCH_KILL)) - { - android_app_destroy(android_app); - exit(0); - } - return NULL; -} - - -static 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(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) -{ - RARCH_LOG("Destroy: %p\n", activity); - android_app_free((struct android_app*)activity->instance); -} - -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; - - RARCH_LOG("SaveInstanceState: %p\n", activity); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 0; - android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); - while (!android_app->stateSaved) - pthread_cond_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; - } - - pthread_mutex_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; - 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; - RARCH_LOG("LowMemory: %p\n", activity); - 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); -} - -// -------------------------------------------------------------------- -// Native activity interaction (called from main thread) -// -------------------------------------------------------------------- - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) -{ - RARCH_LOG("Creating: %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; - - 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); - - if (savedState != NULL) - { - android_app->savedState = malloc(savedStateSize); - android_app->savedStateSize = savedStateSize; - memcpy(android_app->savedState, savedState, savedStateSize); - } - - int msgpipe[2]; - if (pipe(msgpipe)) - { - RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); - activity->instance = NULL; - } - else - { - 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); - - activity->instance = android_app; - } -} - - /** * Process the next main command. */ @@ -647,4 +253,387 @@ void engine_handle_cmd(struct android_app* android_app, int32_t cmd) } } +#define MAX_ARGS 32 +/** + * This is the main entry point of a native application that is using + * android_native_app_glue. It runs in its own thread, with its own + * event loop for receiving input events and doing other things. + */ + +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); + + ALooper* looper = 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; + + pthread_mutex_lock(&android_app->mutex); + android_app->running = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + + memset(&g_android, 0, sizeof(g_android)); + g_android.app = android_app; + + char rom_path[512]; + char libretro_path[512]; + + // Get arguments */ + android_get_char_argv(rom_path, sizeof(rom_path), "ROM"); + android_get_char_argv(libretro_path, sizeof(libretro_path), "LIBRETRO"); + + RARCH_LOG("Checking arguments passed...\n"); + RARCH_LOG("ROM Filename: [%s].\n", rom_path); + RARCH_LOG("Libretro path: [%s].\n", libretro_path); + + /* ugly hack for now - hardcode libretro path to 'allowed' dir */ + snprintf(libretro_path, sizeof(libretro_path), "/data/data/com.retroarch/lib/libretro.so"); + + int argc = 0; + char *argv[MAX_ARGS] = {NULL}; + + argv[argc++] = strdup("retroarch"); + argv[argc++] = strdup(rom_path); + argv[argc++] = strdup("-L"); + argv[argc++] = strdup(libretro_path); + argv[argc++] = strdup("-v"); + + + if (android_app->savedState != NULL) + { + // We are starting with a previous saved state; restore from it. + RARCH_LOG("Restoring reentrant savestate.\n"); + g_android.state = *(struct saved_state*)android_app->savedState; + g_android.input_state = g_android.state.input_state; + } + + bool rarch_reentrant = (g_android.input_state & (1ULL << RARCH_REENTRANT)); + + if(rarch_reentrant) + { + RARCH_LOG("Native Activity started (reentrant).\n"); + } + else + { + RARCH_LOG("Native Activity started.\n"); + rarch_main_clear_state(); + } + + + g_extern.verbose = true; + + while(!(g_android.input_state & (1ULL << RARCH_WINDOW_READY))) + { + // Read all pending events. + int id; + + // Block forever waiting for events. + while ((id = ALooper_pollOnce(0, NULL, 0, NULL)) >= 0) + { + // Process this event. + if (id) + { + int8_t cmd; + + if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) + { + if(cmd == APP_CMD_SAVE_STATE) + free_saved_state(android_app); + } + else + cmd = -1; + + engine_handle_cmd(android_app, cmd); + } + + // Check if we are exiting. + if (android_app->destroyRequested != 0) + goto exit; + } + } + + int init_ret; + + if (rarch_reentrant) + { + init_ret = 0; + + /* We've done everything state-wise needed for RARCH_REENTRANT, + * get rid of it now */ + g_android.input_state |= ~(1ULL << RARCH_REENTRANT); + } + else if ((init_ret = rarch_main_init(argc, argv)) != 0) + { + RARCH_LOG("Initialization failed.\n"); + g_android.input_state |= (1ULL << RARCH_QUIT_KEY); + g_android.input_state |= (1ULL << RARCH_KILL); + } + + if (init_ret == 0) + { + RARCH_LOG("Initializing succeeded.\n"); + RARCH_LOG("RetroArch started.\n"); + rarch_init_msg_queue(); + while (rarch_main_iterate()); + RARCH_LOG("RetroArch stopped.\n"); + } + +exit: + if(g_android.input_state & (1ULL << RARCH_QUIT_KEY)) + { + RARCH_LOG("Deinitializing RetroArch...\n"); + rarch_main_deinit(); + rarch_deinit_msg_queue(); +#ifdef PERF_TEST + rarch_perf_log(); +#endif + rarch_main_clear_state(); + + /* Make sure to quit RetroArch later on too */ + g_android.input_state |= (1ULL << RARCH_KILL); + } + + if(g_android.input_state & (1ULL << RARCH_KILL)) + { + RARCH_LOG("android_app_destroy!"); + free_saved_state(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. + exit(0); + } + return NULL; +} + + +static 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(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 onDestroy(ANativeActivity* activity) +{ + RARCH_LOG("Destroy: %p\n", activity); + struct android_app* android_app = (struct android_app*)activity->instance; + + 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 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; + + RARCH_LOG("SaveInstanceState: %p\n", activity); + pthread_mutex_lock(&android_app->mutex); + android_app->stateSaved = 0; + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); + while (!android_app->stateSaved) + pthread_cond_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; + } + + pthread_mutex_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; + 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; + RARCH_LOG("LowMemory: %p\n", activity); + 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); +} + +// -------------------------------------------------------------------- +// 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; + + 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); + + if (savedState != NULL) + { + android_app->savedState = malloc(savedStateSize); + android_app->savedStateSize = savedStateSize; + memcpy(android_app->savedState, savedState, savedStateSize); + } + + int msgpipe[2]; + if (pipe(msgpipe)) + { + RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); + activity->instance = NULL; + } + else + { + 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); + + activity->instance = android_app; + } +}