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.id = LOOPER_ID_MAIN; android_app->cmdPollSource.app = android_app; android_app->cmdPollSource.process = process_cmd; android_app->inputPollSource.id = LOOPER_ID_INPUT; android_app->inputPollSource.app = android_app; android_app->inputPollSource.process = process_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; }
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { switch (cmd) { case APP_CMD_INPUT_CHANGED: LOGV("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) { LOGV("Attaching input queue to looper"); 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: LOGV("APP_CMD_INIT_WINDOW\n"); 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: LOGV("APP_CMD_TERM_WINDOW\n"); pthread_cond_broadcast(&android_app->cond); break; case APP_CMD_RESUME: case APP_CMD_START: case APP_CMD_PAUSE: case APP_CMD_STOP: LOGV("activityState=%d\n", cmd); 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: LOGV("APP_CMD_CONFIG_CHANGED\n"); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); break; case APP_CMD_DESTROY: LOGV("APP_CMD_DESTROY\n"); android_app->destroyRequested = 1; break; } }
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { switch (cmd) { case APP_CMD_INPUT_CHANGED: LOGI("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) { LOGI("Attaching input queue to looper"); 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: LOGI("APP_CMD_INIT_WINDOW\n"); pthread_mutex_lock(&android_app->mutex); android_app->window = android_app->pendingWindow; if (android_app->window && ANativeWindow_getWidth(android_app->window) && ANativeWindow_getHeight(android_app->window)) { android_app->lifecycleFlags |= NV_APP_STATUS_HAS_REAL_SURFACE; } else { android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE; } pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_TERM_WINDOW: LOGI("APP_CMD_TERM_WINDOW\n"); android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE; pthread_cond_broadcast(&android_app->cond); break; case APP_CMD_WINDOW_RESIZED: LOGI("APP_CMD_WINDOW_RESIZED\n"); pthread_mutex_lock(&android_app->mutex); if (android_app->window && ANativeWindow_getWidth(android_app->window) && ANativeWindow_getHeight(android_app->window)) { android_app->lifecycleFlags |= NV_APP_STATUS_HAS_REAL_SURFACE; } else { android_app->lifecycleFlags &= ~NV_APP_STATUS_HAS_REAL_SURFACE; } pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_GAINED_FOCUS: LOGI("APP_CMD_GAINED_FOCUS\n"); pthread_mutex_lock(&android_app->mutex); android_app->lifecycleFlags |= NV_APP_STATUS_FOCUSED; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_LOST_FOCUS: LOGI("APP_CMD_LOST_FOCUS\n"); pthread_mutex_lock(&android_app->mutex); android_app->lifecycleFlags &= ~NV_APP_STATUS_FOCUSED; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_RESUME: LOGI("activityState=%d\n", cmd); pthread_mutex_lock(&android_app->mutex); android_app->lifecycleFlags |= NV_APP_STATUS_ACTIVE; android_app->activityState = cmd; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_START: LOGI("activityState=%d\n", cmd); 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: LOGI("activityState=%d\n", cmd); pthread_mutex_lock(&android_app->mutex); android_app->lifecycleFlags &= ~NV_APP_STATUS_ACTIVE; android_app->activityState = cmd; pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); break; case APP_CMD_STOP: LOGI("activityState=%d\n", cmd); 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: LOGI("APP_CMD_CONFIG_CHANGED\n"); AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); print_cur_config(android_app); break; case APP_CMD_DESTROY: LOGI("APP_CMD_DESTROY\n"); android_app->lifecycleFlags &= ~NV_APP_STATUS_RUNNING; break; } }
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); }
static void* android_app_entry(void* param) { LOGV("+android_app_entry"); 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.id = LOOPER_ID_MAIN; android_app->cmdPollSource.app = android_app; android_app->cmdPollSource.process = process_cmd; android_app->inputPollSource.id = LOOPER_ID_INPUT; android_app->inputPollSource.app = android_app; android_app->inputPollSource.process = process_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); std::string sargv; // Load command line from ARGV parameter JNIEnv *env = GetEnvAttachThread(android_app->activity->vm); if(env) { jobject me = android_app->activity->clazz; jclass acl = env->GetObjectClass(me); //class pointer of NativeActivity jmethodID giid = env->GetMethodID(acl, "getIntent", "()Landroid/content/Intent;"); jobject intent = env->CallObjectMethod(me, giid); //Got our intent jclass icl = env->GetObjectClass(intent); //class pointer of Intent jmethodID gseid = env->GetMethodID(icl, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); jstring jsARGV = (jstring)env->CallObjectMethod(intent, gseid, env->NewStringUTF("ARGV")); if(jsARGV) { const char *chARGV = env->GetStringUTFChars(jsARGV, 0); if(chARGV) { sargv = std::string(chARGV); LOGI("ARGV: pango %s", chARGV); } env->ReleaseStringUTFChars(jsARGV, chARGV); } android_app->activity->vm->DetachCurrentThread(); } // Set up argv/argc to pass to users main std::vector<std::string> vargv; vargv.push_back("pango"); // Parse parameters from ARGV android intent parameter std::istringstream iss(sargv); std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter<std::vector<std::string> >(vargv)); char* argv[vargv.size()+1]; for(size_t ac = 0; ac < vargv.size(); ++ac) { argv[ac] = new char[vargv[ac].size()]; strcpy( argv[ac], vargv[ac].c_str() ); } argv[vargv.size()] = NULL; // Call users standard main entry point. main(vargv.size(), argv); // Clean up parameters for(size_t ac = 0; ac < vargv.size(); ++ac) { delete[] argv[ac]; } android_app_destroy(android_app); LOGV("-android_app_entry"); return NULL; }