static void frontend_android_init(void *data) { JNIEnv *env = NULL; ALooper *looper = NULL; 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;"); GET_METHOD_ID(env, android_app->onRetroArchExit, class, "onRetroArchExit", "()V"); CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); GET_OBJECT_CLASS(env, class, obj); GET_METHOD_ID(env, android_app->getStringExtra, class, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); }
static void android_display_server_set_screen_orientation(enum rotation rotation) { JNIEnv *env = jni_thread_getenv(); if (!env || !g_android) return; if (g_android->setScreenOrientation) CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz, g_android->setScreenOrientation, rotation); }
static void frontend_android_deinit(void *data) { struct android_app *android_app = (struct android_app*)data; if (!android_app) return; RARCH_LOG("Deinitializing RetroArch ...\n"); android_app->activityState = APP_CMD_DEAD; JNIEnv *env = jni_thread_getenv(); if (env && android_app->onRetroArchExit) CALL_VOID_METHOD(env, android_app->activity->clazz, android_app->onRetroArchExit); if (android_app->inputQueue) { RARCH_LOG("Detaching Android input queue looper ...\n"); AInputQueue_detachLooper(android_app->inputQueue); } }
static int frontend_android_process_events(void *data) { //jboolean hasPendingIntent; //JNIEnv *env; 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 process_pending_intent(void *data) { RARCH_LOG("process_pending_intent.\n"); JNIEnv *env; struct android_app* android_app = (struct android_app*)data; jstring jstr = NULL; bool startgame = false; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; // ROM jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentFullPath); JNI_EXCEPTION(env); RARCH_LOG("Checking arguments passed from intent ...\n"); if (android_app->getPendingIntentFullPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(g_extern.fullpath, argv, sizeof(g_extern.fullpath)); (*env)->ReleaseStringUTFChars(env, jstr, argv); startgame = true; RARCH_LOG("ROM Filename: [%s].\n", g_extern.fullpath); } // Config file jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentConfigPath); JNI_EXCEPTION(env); if (android_app->getPendingIntentConfigPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(default_paths.config_path, argv, sizeof(default_paths.config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", g_extern.config_path); } // Current IME jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentIME); JNI_EXCEPTION(env); if (android_app->getPendingIntentIME && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } //LIBRETRO jstr = (*env)->CallObjectMethod(env, android_app->activity->clazz, android_app->getPendingIntentLibretroPath); JNI_EXCEPTION(env); if (android_app->getPendingIntentLibretroPath && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(default_paths.core_path, argv, sizeof(default_paths.core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); } RARCH_LOG("Libretro path: [%s].\n", default_paths.core_path); if (startgame) { RARCH_LOG("Starting new game %s ...\n", g_extern.fullpath); g_extern.lifecycle_state &= ~(1ULL << MODE_MENU_PREINIT); g_extern.lifecycle_state &= ~(1ULL << MODE_GAME); load_menu_game_new_core(); } CALL_VOID_METHOD(env, android_app->activity->clazz, android_app->clearPendingIntent); }
static void frontend_android_get_environment_settings(int *argc, char *argv[], void *data, void *params_data) { static char config_path[PATH_MAX]; static char core_path[PATH_MAX]; static char path[PATH_MAX]; JNIEnv *env; jobject obj = NULL; jstring jstr = NULL; struct android_app* android_app = (struct android_app*)data; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; struct rarch_main_wrap *args = (struct rarch_main_wrap*)params_data; if (args) { args->touched = true; args->no_rom = false; args->verbose = false; args->sram_path = NULL; args->state_path = NULL; } CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); RARCH_LOG("Checking arguments passed from intent ...\n"); // Config file CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "CONFIGFILE")); *config_path = '\0'; if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (*argv && *argv) strlcpy(config_path, argv, sizeof(config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", config_path); if (args && *config_path) args->config_path = config_path; } // Current IME CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "IME")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "USED")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); bool used = (strcmp(argv, "false") == 0) ? false : true; (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("USED: [%s].\n", used ? "true" : "false"); } // LIBRETRO CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "LIBRETRO")); *core_path = '\0'; if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (*argv && *argv) strlcpy(core_path, argv, sizeof(core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Libretro path: [%s].\n", core_path); if (args && *core_path) args->libretro_path = core_path; } // Content CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "ROM")); *path = '\0'; if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (*argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Auto-start game %s.\n", path); if (args && *path) args->rom_path = path; } } }
static void frontend_android_get_environment_settings(int *argc, char *argv[], void *data, void *params_data) { int32_t major, minor, rel; int perms = 0; char device_model[PROP_VALUE_MAX] = {0}; char device_id[PROP_VALUE_MAX] = {0}; struct rarch_main_wrap *args = NULL; JNIEnv *env = NULL; jobject obj = NULL; jstring jstr = NULL; struct android_app *android_app = (struct android_app*)data; char buf[PATH_MAX_LENGTH] = {0}; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; args = (struct rarch_main_wrap*)params_data; if (args) { args->touched = true; args->no_content = false; args->verbose = false; args->sram_path = NULL; args->state_path = NULL; } frontend_android_get_version(&major, &minor, &rel); RARCH_LOG("Android OS version (major : %d, minor : %d, rel : %d)\n", major, minor, rel); CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); RARCH_LOG("Checking arguments passed from intent ...\n"); /* Config file. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "CONFIGFILE")); if (android_app->getStringExtra && jstr) { static char config_path[PATH_MAX_LENGTH] = {0}; const char *argv = NULL; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(config_path, argv, sizeof(config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", config_path); if (args && *config_path) args->config_path = config_path; } /* Current IME. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "IME")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "USED")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); bool used = (!strcmp(argv, "false")) ? false : true; (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("USED: [%s].\n", used ? "true" : "false"); } /* LIBRETRO. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "LIBRETRO")); if (android_app->getStringExtra && jstr) { static char core_path[PATH_MAX_LENGTH]; const char *argv = NULL; *core_path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(core_path, argv, sizeof(core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Libretro path: [%s]\n", core_path); if (args && *core_path) args->libretro_path = core_path; } /* Content. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "ROM")); if (android_app->getStringExtra && jstr) { static char path[PATH_MAX_LENGTH]; const char *argv = NULL; *path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Auto-start game %s.\n", path); if (args && *path) args->content_path = path; } } /* External Storage */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "SDCARD")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *sdcard_dir = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(sdcard_dir, argv, sizeof(sdcard_dir)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*sdcard_dir) { RARCH_LOG("External storage location [%s]\n", sdcard_dir); /* TODO base dir handler */ } } /* Screenshots */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "SCREENSHOTS")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *screenshot_dir = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(screenshot_dir, argv, sizeof(screenshot_dir)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*screenshot_dir) { RARCH_LOG("Picture folder location [%s]\n", screenshot_dir); /* TODO: screenshot handler */ } } /* Downloads */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "DOWNLOADS")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *downloads_dir = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(downloads_dir, argv, sizeof(downloads_dir)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*downloads_dir) { RARCH_LOG("Download folder location [%s].\n", downloads_dir); /* TODO: downloads handler */ } } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "APK")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *apk_path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(apk_path, argv, sizeof(apk_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*apk_path) { RARCH_LOG("APK location [%s].\n", apk_path); } } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "EXTERNAL")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *ext_dir = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(ext_dir, argv, sizeof(ext_dir)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*ext_dir) { RARCH_LOG("External files location [%s]\n", ext_dir); } } /* Content. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "DATADIR")); if (android_app->getStringExtra && jstr) { const char *argv = NULL; *app_dir = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(app_dir, argv, sizeof(app_dir)); (*env)->ReleaseStringUTFChars(env, jstr, argv); //set paths depending on the ability to write to sdcard_dir if(*sdcard_dir) { if(test_permissions(sdcard_dir)) perms = SDCARD_ROOT_WRITABLE; } else if(*ext_dir) { if(test_permissions(ext_dir)) perms = SDCARD_EXT_DIR_WRITABLE; } else perms = SDCARD_NOT_WRITABLE; RARCH_LOG("SD permissions: %d",perms); if (*app_dir) { RARCH_LOG("Application location: [%s].\n", app_dir); if (args && *app_dir) { fill_pathname_join(g_defaults.dir.assets, app_dir, "assets", sizeof(g_defaults.dir.assets)); fill_pathname_join(g_defaults.dir.extraction, app_dir, "tmp", sizeof(g_defaults.dir.extraction)); fill_pathname_join(g_defaults.dir.shader, app_dir, "shaders", sizeof(g_defaults.dir.shader)); fill_pathname_join(g_defaults.dir.overlay, app_dir, "overlays", sizeof(g_defaults.dir.overlay)); fill_pathname_join(g_defaults.dir.core, app_dir, "cores", sizeof(g_defaults.dir.core)); fill_pathname_join(g_defaults.dir.core_info, app_dir, "info", sizeof(g_defaults.dir.core_info)); fill_pathname_join(g_defaults.dir.autoconfig, app_dir, "autoconfig", sizeof(g_defaults.dir.autoconfig)); fill_pathname_join(g_defaults.dir.audio_filter, app_dir, "audio_filters", sizeof(g_defaults.dir.audio_filter)); fill_pathname_join(g_defaults.dir.video_filter, app_dir, "video_filters", sizeof(g_defaults.dir.video_filter)); strlcpy(g_defaults.dir.content_history, app_dir, sizeof(g_defaults.dir.content_history)); fill_pathname_join(g_defaults.dir.database, app_dir, "database/rdb", sizeof(g_defaults.dir.database)); fill_pathname_join(g_defaults.dir.cursor, app_dir, "database/cursors", sizeof(g_defaults.dir.cursor)); fill_pathname_join(g_defaults.dir.cheats, app_dir, "cheats", sizeof(g_defaults.dir.cheats)); fill_pathname_join(g_defaults.dir.playlist, app_dir, "playlists", sizeof(g_defaults.dir.playlist)); fill_pathname_join(g_defaults.dir.remap, app_dir, "remaps", sizeof(g_defaults.dir.remap)); fill_pathname_join(g_defaults.dir.wallpapers, app_dir, "wallpapers", sizeof(g_defaults.dir.wallpapers)); if(*downloads_dir && test_permissions(downloads_dir)) { fill_pathname_join(g_defaults.dir.core_assets, downloads_dir, "", sizeof(g_defaults.dir.core_assets)); } else { fill_pathname_join(g_defaults.dir.core_assets, app_dir, "downloads", sizeof(g_defaults.dir.core_assets)); path_mkdir(g_defaults.dir.core_assets); } RARCH_LOG("Default download folder: [%s]", g_defaults.dir.core_assets); if(*screenshot_dir && test_permissions(screenshot_dir)) { fill_pathname_join(g_defaults.dir.screenshot, screenshot_dir, "", sizeof(g_defaults.dir.screenshot)); } else { fill_pathname_join(g_defaults.dir.screenshot, app_dir, "screenshots", sizeof(g_defaults.dir.screenshot)); path_mkdir(g_defaults.dir.screenshot); } RARCH_LOG("Default screenshot folder: [%s]", g_defaults.dir.screenshot); switch (perms) { case SDCARD_EXT_DIR_WRITABLE: fill_pathname_join(g_defaults.dir.sram, ext_dir, "saves", sizeof(g_defaults.dir.sram)); path_mkdir(g_defaults.dir.sram); fill_pathname_join(g_defaults.dir.savestate, ext_dir, "states", sizeof(g_defaults.dir.savestate)); path_mkdir(g_defaults.dir.savestate); fill_pathname_join(g_defaults.dir.system, ext_dir, "system", sizeof(g_defaults.dir.system)); path_mkdir(g_defaults.dir.system); break; case SDCARD_NOT_WRITABLE: fill_pathname_join(g_defaults.dir.sram, app_dir, "saves", sizeof(g_defaults.dir.sram)); path_mkdir(g_defaults.dir.sram); fill_pathname_join(g_defaults.dir.savestate, app_dir, "states", sizeof(g_defaults.dir.savestate)); path_mkdir(g_defaults.dir.savestate); fill_pathname_join(g_defaults.dir.system, app_dir, "system", sizeof(g_defaults.dir.system)); path_mkdir(g_defaults.dir.system); break; case SDCARD_ROOT_WRITABLE: default: break; } /* create save and system directories in the internal dir too */ fill_pathname_join(buf, app_dir, "saves", sizeof(buf)); path_mkdir(buf); fill_pathname_join(buf, app_dir, "states", sizeof(buf)); path_mkdir(buf); fill_pathname_join(buf, app_dir, "system", sizeof(buf)); path_mkdir(buf); /* create save and system directories in the internal sd too */ fill_pathname_join(buf, ext_dir, "saves", sizeof(buf)); path_mkdir(buf); fill_pathname_join(buf, ext_dir, "states", sizeof(buf)); path_mkdir(buf); fill_pathname_join(buf, ext_dir, "system", sizeof(buf)); path_mkdir(buf); RARCH_LOG("Default savefile folder: [%s]", g_defaults.dir.sram); RARCH_LOG("Default savestate folder: [%s]", g_defaults.dir.savestate); RARCH_LOG("Default system folder: [%s]", g_defaults.dir.system); } } } frontend_android_get_name(device_model, sizeof(device_model)); system_property_get("ro.product.id", device_id); g_defaults.settings.video_threaded_enable = true; /* Set automatic default values per device */ if (device_is_xperia_play(device_model)) { g_defaults.settings.out_latency = 128; g_defaults.settings.video_refresh_rate = 59.19132938771038; g_defaults.settings.video_threaded_enable = false; } else if (!strcmp(device_model, "GAMEMID_BT")) g_defaults.settings.out_latency = 160; else if (!strcmp(device_model, "SHIELD")) g_defaults.settings.video_refresh_rate = 60.0; else if (!strcmp(device_model, "JSS15J")) g_defaults.settings.video_refresh_rate = 59.65; #if 0 /* Explicitly disable input overlay by default * for gamepad-like/console devices. */ if (device_is_game_console(device_model)) g_defaults.settings.input_overlay_enable = false; #endif }
static void frontend_android_get_environment_settings(int *argc, char *argv[], void *data, void *params_data) { int32_t major, minor, rel; char device_model[PROP_VALUE_MAX] = {0}; char device_id[PROP_VALUE_MAX] = {0}; struct rarch_main_wrap *args = NULL; JNIEnv *env = NULL; jobject obj = NULL; jstring jstr = NULL; struct android_app *android_app = (struct android_app*)data; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; args = (struct rarch_main_wrap*)params_data; if (args) { args->touched = true; args->no_content = false; args->verbose = false; args->sram_path = NULL; args->state_path = NULL; } frontend_android_get_version(&major, &minor, &rel); RARCH_LOG("Android OS version (major : %d, minor : %d, rel : %d)\n", major, minor, rel); CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); RARCH_LOG("Checking arguments passed from intent ...\n"); /* Config file. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "CONFIGFILE")); if (android_app->getStringExtra && jstr) { static char config_path[PATH_MAX_LENGTH] = {0}; const char *argv = NULL; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(config_path, argv, sizeof(config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", config_path); if (args && *config_path) args->config_path = config_path; } /* Current IME. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "IME")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "USED")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); bool used = (!strcmp(argv, "false")) ? false : true; (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("USED: [%s].\n", used ? "true" : "false"); } /* LIBRETRO. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "LIBRETRO")); if (android_app->getStringExtra && jstr) { static char core_path[PATH_MAX_LENGTH]; const char *argv = NULL; *core_path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(core_path, argv, sizeof(core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Libretro path: [%s].\n", core_path); if (args && *core_path) args->libretro_path = core_path; } /* Content. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "ROM")); if (android_app->getStringExtra && jstr) { static char path[PATH_MAX_LENGTH]; const char *argv = NULL; *path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Auto-start game %s.\n", path); if (args && *path) args->content_path = path; } } /* Content. */ CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "DATADIR")); if (android_app->getStringExtra && jstr) { static char path[PATH_MAX_LENGTH]; const char *argv = NULL; *path = '\0'; argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Data path: [%s].\n", path); if (args && *path) { fill_pathname_join(g_defaults.assets_dir, path, "assets", sizeof(g_defaults.savestate_dir)); fill_pathname_join(g_defaults.extraction_dir, path, "tmp", sizeof(g_defaults.extraction_dir)); fill_pathname_join(g_defaults.shader_dir, path, "shaders_glsl", sizeof(g_defaults.shader_dir)); fill_pathname_join(g_defaults.overlay_dir, path, "overlays", sizeof(g_defaults.overlay_dir)); fill_pathname_join(g_defaults.core_dir, path, "cores", sizeof(g_defaults.core_dir)); fill_pathname_join(g_defaults.core_info_dir, path, "info", sizeof(g_defaults.core_info_dir)); fill_pathname_join(g_defaults.autoconfig_dir, path, "autoconfig", sizeof(g_defaults.autoconfig_dir)); fill_pathname_join(g_defaults.audio_filter_dir, path, "audio_filters", sizeof(g_defaults.audio_filter_dir)); fill_pathname_join(g_defaults.video_filter_dir, path, "video_filters", sizeof(g_defaults.video_filter_dir)); strlcpy(g_defaults.content_history_dir, path, sizeof(g_defaults.content_history_dir)); fill_pathname_join(g_defaults.database_dir, path, "database/rdb", sizeof(g_defaults.database_dir)); fill_pathname_join(g_defaults.cursor_dir, path, "database/cursors", sizeof(g_defaults.cursor_dir)); fill_pathname_join(g_defaults.cheats_dir, path, "cheats", sizeof(g_defaults.cheats_dir)); fill_pathname_join(g_defaults.playlist_dir, path, "playlists", sizeof(g_defaults.playlist_dir)); fill_pathname_join(g_defaults.remap_dir, path, "remaps", sizeof(g_defaults.remap_dir)); fill_pathname_join(g_defaults.wallpapers_dir, path, "wallpapers", sizeof(g_defaults.wallpapers_dir)); fill_pathname_join(g_defaults.core_assets_dir, path, "downloads", sizeof(g_defaults.core_assets_dir)); } } } frontend_android_get_name(device_model, sizeof(device_model)); system_property_get("ro.product.id", device_id); g_defaults.settings.video_threaded_enable = true; // Set automatic default values per device if (device_is_xperia_play(device_model)) { g_defaults.settings.out_latency = 128; g_defaults.settings.video_refresh_rate = 59.19132938771038; g_defaults.settings.video_threaded_enable = false; } else if (!strcmp(device_model, "GAMEMID_BT")) g_defaults.settings.out_latency = 160; else if (!strcmp(device_model, "SHIELD")) g_defaults.settings.video_refresh_rate = 60.0; else if (!strcmp(device_model, "JSS15J")) g_defaults.settings.video_refresh_rate = 59.65; /* FIXME - needs to be refactored */ #if 0 /* Explicitly disable input overlay by default * for gamepad-like/console devices. */ if (device_is_game_console(device_model)) g_defaults.settings.input_overlay_enable = false; #endif }
static bool android_gfx_ctx_get_metrics(void *data, enum display_metric_types type, float *value) { jclass metrics_class; jobject metrics; jmethodID getMetrics; struct android_app *android_app = (struct android_app*)g_android; JNIEnv *env = (JNIEnv*)jni_thread_getenv(); GET_METHOD_ID(env, getMetrics, android_app->activity, "getMetrics", "()Landroid/util/DisplayMetrics;"); if (!getMetrics) goto error; CALL_OBJ_STATIC_METHOD(env, metrics, android_app->activity, getMetrics); GET_OBJECT_CLASS(env, metrics_class, metrics); /* Density */ float density = (*env)->GetFloatField(env, metrics, (*env)->GetFieldID(env, metrics_class, "density", "F")); float scaled_density = (*env)->GetFloatField(env, metrics, (*env)->GetFieldID(env, metrics_class, "scaledDensity", "F")); int density_dpi = (*env)->GetIntField(env, metrics, (*env)->GetFieldID(env, metrics_class, "densityDpi", "I")); /* Size */ int width_pixels = (*env)->GetIntField(env, metrics, (*env)->GetFieldID(env, metrics_class, "widthPixels", "I")); int height_pixels = (*env)->GetIntField(env, metrics, (*env)->GetFieldID(env, metrics_class, "heightPixels", "I")); /* DPI */ /* Apparently xdpi and ydpi can't be trusted to be implemented correctly, so don't try to rely on it... * * https://groups.google.com/forum/#!topic/android-developers/QjUlaRohRPI * * "The xdpi and ydpi are supposed to be the real DPI of the screen... though as you've seen, * many devices don't set it correctly. :( This is our fault, it isn't actually used anywhere * in the platform, so people don't realize they have a bad value, and we haven't had a CTS * test to try to make sure it is sane (it's not clear how that test should work). Worse, we * shipping the original Droid with a graphics driver that reports the wrong value here... * in fact that reported that same damnable 96." * * Unfortunately, I don't have a good solution if you want to get the real exactly screen dots per inch. * One thing you could do is compare xdpi/ydpi with densityDpi and if they are significantly * far apart, assume the values are bad and just fall back on densityDpi as an approximation. * * Be careful on this, because a correctly working device may have densityDpi fairly different * than the real dpi -- for example the Samsung TAB uses high density even though its screen's * really density is a fair amount lower than 240." */ float xdpi = (*env)->GetFloatField(env, metrics, (*env)->GetFieldID(env, metrics_class, "xdpi", "F")); float ydpi = (*env)->GetFloatField(env, metrics, (*env)->GetFieldID(env, metrics_class, "ydpi", "F")); (void)width_pixels; (void)height_pixels; (void)scaled_density; (void)density; (void)density_dpi; switch (type) { case DISPLAY_METRIC_MM_WIDTH: /* can't guarantee this to be accurate - so return false anyway. */ *value = xdpi; return false; case DISPLAY_METRIC_MM_HEIGHT: /* can't guarantee this to be accurate - so return false anyway. */ *value = ydpi; return false; case DISPLAY_METRIC_DPI: /* just go with quantized DPI. */ *value = density_dpi; break; case DISPLAY_METRIC_NONE: default: *value = 0; return false; } return true; error: return false; }
static void frontend_android_get_environment_settings(int *argc, char *argv[], void *data, void *params_data) { char device_model[PROP_VALUE_MAX], device_id[PROP_VALUE_MAX]; JNIEnv *env; jobject obj = NULL; jstring jstr = NULL; struct android_app* android_app = (struct android_app*)data; if (!android_app) return; env = jni_thread_getenv(); if (!env) return; struct rarch_main_wrap *args = (struct rarch_main_wrap*)params_data; if (args) { args->touched = true; args->no_rom = false; args->verbose = false; args->sram_path = NULL; args->state_path = NULL; } CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent); RARCH_LOG("Checking arguments passed from intent ...\n"); // Config file CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "CONFIGFILE")); if (android_app->getStringExtra && jstr) { static char config_path[PATH_MAX]; *config_path = '\0'; const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(config_path, argv, sizeof(config_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Config file: [%s].\n", config_path); if (args && *config_path) args->config_path = config_path; } // Current IME CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "IME")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); strlcpy(android_app->current_ime, argv, sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "USED")); if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); bool used = (strcmp(argv, "false") == 0) ? false : true; (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("USED: [%s].\n", used ? "true" : "false"); } // LIBRETRO CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "LIBRETRO")); if (android_app->getStringExtra && jstr) { static char core_path[PATH_MAX]; *core_path = '\0'; const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(core_path, argv, sizeof(core_path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); RARCH_LOG("Libretro path: [%s].\n", core_path); if (args && *core_path) args->libretro_path = core_path; } // Content CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "ROM")); if (android_app->getStringExtra && jstr) { static char path[PATH_MAX]; *path = '\0'; const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Auto-start game %s.\n", path); if (args && *path) args->rom_path = path; } } // Content CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "DATADIR")); if (android_app->getStringExtra && jstr) { static char path[PATH_MAX]; *path = '\0'; const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); if (argv && *argv) strlcpy(path, argv, sizeof(path)); (*env)->ReleaseStringUTFChars(env, jstr, argv); if (*path) { RARCH_LOG("Data path: [%s].\n", path); if (args && *path) { fill_pathname_join(g_defaults.savestate_dir, path, "savestates", sizeof(g_defaults.savestate_dir)); fill_pathname_join(g_defaults.sram_dir, path, "savefiles", sizeof(g_defaults.sram_dir)); fill_pathname_join(g_defaults.system_dir, path, "system", sizeof(g_defaults.system_dir)); } } } frontend_android_get_name(device_model, sizeof(device_model)); __system_property_get("ro.product.id", device_id); g_defaults.settings.video_threaded_enable = true; g_defaults.settings.input_overlay_enable = true; // Enable input overlay by default // Set automatic default values per device if (device_is_xperia_play(device_model)) { g_defaults.settings.out_latency = 128; g_defaults.settings.video_refresh_rate = 59.19132938771038; g_defaults.settings.video_threaded_enable = false; } else if (!strcmp(device_model, "GAMEMID_BT")) g_defaults.settings.out_latency = 160; else if (!strcmp(device_model, "SHIELD")) g_defaults.settings.video_refresh_rate = 60.0; else if (!strcmp(device_model, "JSS15J")) g_defaults.settings.video_refresh_rate = 59.65; // Explicitly disable input overlay by default for gamepad-like/console devices if (device_is_game_console(device_model)) g_defaults.settings.input_overlay_enable = false; }