static void frontend_android_init(void *data) { JNIEnv *env; ALooper *looper; jclass class = NULL; jobject obj = NULL; struct android_app* android_app = (struct android_app*)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; slock_lock(android_app->mutex); android_app->running = 1; scond_broadcast(android_app->cond); slock_unlock(android_app->mutex); memset(&g_android, 0, sizeof(g_android)); g_android = (struct android_app*)android_app; RARCH_LOG("Waiting for Android Native Window to be initialized ...\n"); while (!android_app->window) { if (!android_run_events(android_app)) { frontend_android_deinit(android_app); frontend_android_shutdown(android_app); return; } } RARCH_LOG("Android Native Window initialized.\n"); env = jni_thread_getenv(); if (!env) return; GET_OBJECT_CLASS(env, class, android_app->activity->clazz); GET_METHOD_ID(env, android_app->getIntent, class, "getIntent", "()Landroid/content/Intent;"); CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); #if 0 GET_METHOD_ID(env, android_app->hasPendingIntent, class, "hasPendingIntent", "()Z"); GET_METHOD_ID(env, android_app->clearPendingIntent, class, "clearPendingIntent", "()V"); GET_METHOD_ID(env, android_app->getPendingIntentConfigPath, class, "getPendingIntentConfigPath", "()Ljava/lang/String;"); GET_METHOD_ID(env, android_app->getPendingIntentLibretroPath, class, "getPendingIntentLibretroPath", "()Ljava/lang/String;"); GET_METHOD_ID(env, android_app->getPendingIntentFullPath, class, "getPendingIntentFullPath", "()Ljava/lang/String;"); GET_METHOD_ID(env, android_app->getPendingIntentIME, class, "getPendingIntentIME", "()Ljava/lang/String;"); #endif GET_OBJECT_CLASS(env, class, obj); GET_METHOD_ID(env, android_app->getStringExtra, class, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); }
static int frontend_android_process_events(void *data) { #if 0 jboolean hasPendingIntent; JNIEnv *env; #endif struct android_app* android_app = (struct android_app*)data; if (g_extern.is_paused) android_run_events(android_app); #if 0 env = jni_thread_getenv(); if (!env) return -1; CALL_BOOLEAN_METHOD(env, hasPendingIntent, android_app->activity->clazz, android_app->hasPendingIntent); if (hasPendingIntent) process_pending_intent(android_app); #endif return 0; }
static void *android_app_entry(void *data) { struct android_app* android_app = (struct android_app*)data; 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 = android_app; RARCH_LOG("Native Activity started.\n"); rarch_main_clear_state(); while (!android_app->window) { if (!android_run_events(android_app)) goto exit; } rarch_init_msg_queue(); if (!android_app_start_main(android_app)) { g_settings.input.overlay[0] = 0; // threaded video doesn't work right for just displaying one frame g_settings.video.threaded = false; init_drivers(); driver.video_poke->set_aspect_ratio(driver.video_data, ASPECT_RATIO_SQUARE); rarch_render_cached_frame(); sleep(2); goto exit; } if (!g_extern.libretro_dummy) menu_rom_history_push_current(); for (;;) { if (g_extern.system.shutdown) break; else if (g_extern.lifecycle_mode_state & (1ULL << MODE_LOAD_GAME)) { load_menu_game_prepare(); // If ROM load fails, we exit RetroArch. On console it might make more sense to go back to menu though ... if (load_menu_game()) g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME); else { #ifdef RARCH_CONSOLE g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU); #else return NULL; #endif } g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME); } else if (g_extern.lifecycle_mode_state & (1ULL << MODE_GAME)) { driver.input->poll(NULL); if (driver.video_poke->set_aspect_ratio) driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx); if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE)) audio_start_func(); // Main loop while (rarch_main_iterate()); if (g_extern.lifecycle_mode_state & (1ULL << MODE_VIDEO_THROTTLE_ENABLE)) audio_stop_func(); g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME); } else if(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) { g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU_PREINIT); while((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ? android_run_events(android_app) : menu_iterate()); g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU); } else break; } exit: android_app->activityState = APP_CMD_DEAD; RARCH_LOG("Deinitializing RetroArch...\n"); menu_free(); if (g_extern.config_save_on_exit && *g_extern.config_path) config_save_file(g_extern.config_path); if (g_extern.main_is_init) rarch_main_deinit(); rarch_deinit_msg_queue(); #ifdef PERF_TEST rarch_perf_log(); #endif rarch_main_clear_state(); RARCH_LOG("android_app_destroy!"); if (android_app->inputQueue != NULL) AInputQueue_detachLooper(android_app->inputQueue); AConfiguration_delete(android_app->config); // exit() here is nasty. // pthread_exit(NULL) or return NULL; causes hanging ... // Should probably called ANativeActivity_finsih(), but it's bugged, it will hang our app. exit(0); }