diff --git a/frontend/drivers/platform_android.c b/frontend/drivers/platform_android.c
deleted file mode 100644
index 612a5fbf7e..0000000000
--- a/frontend/drivers/platform_android.c
+++ /dev/null
@@ -1,1063 +0,0 @@
-/* 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
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "platform_android.h"
-
-#include "../frontend.h"
-#include "../../general.h"
-#include "../../msg_hash.h"
-#include "../../runloop_data.h"
-
-#define SDCARD_ROOT_WRITABLE 1
-#define SDCARD_EXT_DIR_WRITABLE 2
-#define SDCARD_NOT_WRITABLE 3
-
-struct android_app *g_android;
-static pthread_key_t thread_key;
-
-char screenshot_dir[PATH_MAX_LENGTH];
-char downloads_dir[PATH_MAX_LENGTH];
-char apk_path[PATH_MAX_LENGTH];
-char sdcard_dir[PATH_MAX_LENGTH];
-char app_dir[PATH_MAX_LENGTH];
-char ext_dir[PATH_MAX_LENGTH];
-
-static INLINE void android_app_write_cmd(void *data, int8_t cmd)
-{
- struct android_app *android_app = (struct android_app*)data;
-
- if (!android_app)
- return;
-
- 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;
- struct android_app* android_app = (struct android_app*)g_android;
- int status = (*android_app->activity->vm)->
- AttachCurrentThread(android_app->activity->vm, &env, 0);
-
- if (status < 0)
- {
- RARCH_ERR("jni_thread_getenv: Failed to attach current thread.\n");
- return NULL;
- }
- pthread_setspecific(thread_key, (void*)env);
-
- return env;
-}
-
-static void jni_thread_destruct(void *value)
-{
- JNIEnv *env = (JNIEnv*)value;
- struct android_app *android_app = (struct android_app*)g_android;
- RARCH_LOG("jni_thread_destruct()\n");
-
- if (!env)
- return;
-
- if (android_app)
- (*android_app->activity->vm)->
- DetachCurrentThread(android_app->activity->vm);
- pthread_setspecific(thread_key, NULL);
-}
-
-static void android_app_entry(void *data)
-{
- char *argv[1];
- int argc = 0;
- int ret = 0;
-
- if (rarch_main(argc, argv, data) != 0)
- goto end;
-#ifndef HAVE_MAIN
- do
- {
- unsigned sleep_ms = 0;
- ret = rarch_main_iterate(&sleep_ms);
-
- if (ret == 1 && sleep_ms > 0)
- rarch_sleep(sleep_ms);
- rarch_main_data_iterate();
- }while (ret != -1);
-
- main_exit(data);
-#endif
-
-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));
- if (!android_app)
- {
- RARCH_ERR("Failed to initialize android_app\n");
- return;
- }
-
- 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] = {0};
- char cmd[PATH_MAX_LENGTH] = {0};
- 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 *s, size_t len)
-{
- system_property_get("ro.product.model", s);
-}
-
-static void frontend_android_get_version(int32_t *major,
- int32_t *minor, int32_t *rel)
-{
- char os_version_str[PROP_VALUE_MAX] = {0};
- system_property_get("ro.build.version.release", os_version_str);
-
- *major = 0;
- *minor = 0;
- *rel = 0;
-
- /* Parse out the OS version numbers from the system properties. */
- if (os_version_str[0])
- {
- /* Try to parse out the version numbers from the string. */
- int num_read = sscanf(os_version_str, "%d.%d.%d", major, minor, rel);
-
- if (num_read > 0)
- {
- if (num_read < 2)
- *minor = 0;
- if (num_read < 3)
- *rel = 0;
- return;
- }
- }
-}
-
-static void frontend_android_get_os(char *s, size_t len, int *major, int *minor)
-{
- int rel;
-
- frontend_android_get_version(major, minor, &rel);
-
- strlcpy(s, "Android", len);
-}
-
-static void frontend_android_get_version_sdk(int32_t *sdk)
-{
- char os_version_str[PROP_VALUE_MAX] = {0};
- system_property_get("ro.build.version.sdk", os_version_str);
-
- *sdk = 0;
- if (os_version_str[0])
- {
- int num_read = sscanf(os_version_str, "%d", sdk);
- (void) num_read;
- }
-}
-
-static bool device_is_xperia_play(const char *name)
-{
- if (
- !strcmp(name, "R800x") ||
- !strcmp(name, "R800at") ||
- !strcmp(name, "R800i") ||
- !strcmp(name, "R800a") ||
- !strcmp(name, "SO-01D")
- )
- return true;
-
- return false;
-}
-
-static bool device_is_game_console(const char *name)
-{
- if (
- !strcmp(name, "OUYA Console") ||
- device_is_xperia_play(name) ||
- !strcmp(name, "GAMEMID_BT") ||
- !strcmp(name, "S7800") ||
- !strcmp(name, "SHIELD")
- )
- return true;
-
- return false;
-}
-
-bool test_permissions(const char *path)
-{
- char buf[PATH_MAX_LENGTH];
- bool ret;
-
- RARCH_LOG("Testing permissions for %s\n",path);
-
- fill_pathname_join(buf, path, ".retroarch", sizeof(buf));
- ret = path_mkdir(buf);
-
- RARCH_LOG("Create %s %s\n", buf, ret ? "true" : "false");
-
- if(ret)
- rmdir(buf);
-
- return ret;
-}
-
-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 = (*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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *core_path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *sdcard_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *screenshot_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *downloads_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *apk_path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *ext_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
-
- *app_dir = '\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.osk_overlay, app_dir,
- "overlays", sizeof(g_defaults.dir.osk_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_deinit(void *data)
-{
- JNIEnv *env = NULL;
- struct android_app *android_app = (struct android_app*)data;
-
- if (!android_app)
- return;
-
- RARCH_LOG("Deinitializing RetroArch ...\n");
- android_app->activityState = APP_CMD_DEAD;
-
- 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 void frontend_android_shutdown(bool unused)
-{
- (void)unused;
- /* Cleaner approaches don't work sadly. */
- exit(0);
-}
-
-bool android_run_events(void *data);
-
-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 int frontend_android_get_rating(void)
-{
- char device_model[PROP_VALUE_MAX] = {0};
- frontend_android_get_name(device_model, sizeof(device_model));
-
- RARCH_LOG("ro.product.model: (%s).\n", device_model);
-
- if (device_is_xperia_play(device_model))
- return 6;
- else if (!strcmp(device_model, "GT-I9505"))
- return 12;
- else if (!strcmp(device_model, "SHIELD"))
- return 13;
- return -1;
-}
-
-#define ANDROID_ARCH_ARMV7 0x26257a91U
-#define ANDROID_ARCH_ARM 0x406a3516U
-#define ANDROID_ARCH_MIPS 0x7c9aa25eU
-#define ANDROID_ARCH_X86 0x0b88b8cbU
-
-static enum frontend_architecture frontend_android_get_architecture(void)
-{
- uint32_t abi_hash;
- char abi[PROP_VALUE_MAX] = {0};
- system_property_get("ro.product.cpu.abi", abi);
-
- abi_hash = msg_hash_calculate(abi);
-
- switch (abi_hash)
- {
- case ANDROID_ARCH_ARMV7:
- return FRONTEND_ARCH_ARM;
- case ANDROID_ARCH_ARM:
- return FRONTEND_ARCH_ARM;
- case ANDROID_ARCH_MIPS:
- return FRONTEND_ARCH_MIPS;
- case ANDROID_ARCH_X86:
- return FRONTEND_ARCH_X86;
- }
-
- return FRONTEND_ARCH_NONE;
-}
-
-static int frontend_android_parse_drive_list(void *data)
-{
- file_list_t *list = (file_list_t*)data;
-
- // MENU_FILE_DIRECTORY is not working with labels, placeholders for now
- menu_list_push(list,
- app_dir, "Application Dir", MENU_FILE_DIRECTORY, 0, 0);
- menu_list_push(list,
- ext_dir, "External Application Dir", MENU_FILE_DIRECTORY, 0, 0);
- menu_list_push(list,
- sdcard_dir, "Internal Memory", MENU_FILE_DIRECTORY, 0, 0);
-
- menu_list_push(list, "/", "",
- MENU_FILE_DIRECTORY, 0, 0);
-
- return 0;
-}
-
-frontend_ctx_driver_t frontend_ctx_android = {
- frontend_android_get_environment_settings,
- frontend_android_init,
- frontend_android_deinit,
- NULL, /* exitspawn */
- NULL, /* process_args */
- NULL, /* exec */
- NULL, /* set_fork */
- frontend_android_shutdown,
- frontend_android_get_name,
- frontend_android_get_os,
- frontend_android_get_rating,
- NULL, /* load_content */
- frontend_android_get_architecture,
- NULL, /* get_powerstate */
- frontend_android_parse_drive_list,
- "android",
-};
diff --git a/frontend/drivers/platform_linux.c b/frontend/drivers/platform_linux.c
index 7f3c82fedf..3005e43e74 100644
--- a/frontend/drivers/platform_linux.c
+++ b/frontend/drivers/platform_linux.c
@@ -2,6 +2,7 @@
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2015 - Daniel De Matteis
* Copyright (C) 2012-2015 - Jason Fetters
+ * 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-
@@ -23,7 +24,7 @@
#include
#include
#include
-#include /* PATH_MAX */
+#include
#include
#include
@@ -31,10 +32,457 @@
#include
#include
+#include "../frontend.h"
#include "../frontend_driver.h"
#include "../../general.h"
-#ifndef ANDROID
+#ifdef ANDROID
+#include "platform_android.h"
+
+#define SDCARD_ROOT_WRITABLE 1
+#define SDCARD_EXT_DIR_WRITABLE 2
+#define SDCARD_NOT_WRITABLE 3
+
+struct android_app *g_android;
+static pthread_key_t thread_key;
+
+char screenshot_dir[PATH_MAX_LENGTH];
+char downloads_dir[PATH_MAX_LENGTH];
+char apk_path[PATH_MAX_LENGTH];
+char sdcard_dir[PATH_MAX_LENGTH];
+char app_dir[PATH_MAX_LENGTH];
+char ext_dir[PATH_MAX_LENGTH];
+
+/* forward declaration */
+bool android_run_events(void *data);
+
+static INLINE void android_app_write_cmd(void *data, int8_t cmd)
+{
+ struct android_app *android_app = (struct android_app*)data;
+
+ if (!android_app)
+ return;
+
+ 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;
+ struct android_app* android_app = (struct android_app*)g_android;
+ int status = (*android_app->activity->vm)->
+ AttachCurrentThread(android_app->activity->vm, &env, 0);
+
+ if (status < 0)
+ {
+ RARCH_ERR("jni_thread_getenv: Failed to attach current thread.\n");
+ return NULL;
+ }
+ pthread_setspecific(thread_key, (void*)env);
+
+ return env;
+}
+
+static void jni_thread_destruct(void *value)
+{
+ JNIEnv *env = (JNIEnv*)value;
+ struct android_app *android_app = (struct android_app*)g_android;
+ RARCH_LOG("jni_thread_destruct()\n");
+
+ if (!env)
+ return;
+
+ if (android_app)
+ (*android_app->activity->vm)->
+ DetachCurrentThread(android_app->activity->vm);
+ pthread_setspecific(thread_key, NULL);
+}
+
+static void android_app_entry(void *data)
+{
+ char *argv[1];
+ int argc = 0;
+ int ret = 0;
+
+ if (rarch_main(argc, argv, data) != 0)
+ goto end;
+#ifndef HAVE_MAIN
+ do
+ {
+ unsigned sleep_ms = 0;
+ ret = rarch_main_iterate(&sleep_ms);
+
+ if (ret == 1 && sleep_ms > 0)
+ rarch_sleep(sleep_ms);
+ rarch_main_data_iterate();
+ }while (ret != -1);
+
+ main_exit(data);
+#endif
+
+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));
+ if (!android_app)
+ {
+ RARCH_ERR("Failed to initialize android_app\n");
+ return;
+ }
+
+ 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] = {0};
+ char cmd[PATH_MAX_LENGTH] = {0};
+ 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 *s, size_t len)
+{
+ system_property_get("ro.product.model", s);
+}
+
+static void frontend_android_get_version(int32_t *major,
+ int32_t *minor, int32_t *rel)
+{
+ char os_version_str[PROP_VALUE_MAX] = {0};
+ system_property_get("ro.build.version.release", os_version_str);
+
+ *major = 0;
+ *minor = 0;
+ *rel = 0;
+
+ /* Parse out the OS version numbers from the system properties. */
+ if (os_version_str[0])
+ {
+ /* Try to parse out the version numbers from the string. */
+ int num_read = sscanf(os_version_str, "%d.%d.%d", major, minor, rel);
+
+ if (num_read > 0)
+ {
+ if (num_read < 2)
+ *minor = 0;
+ if (num_read < 3)
+ *rel = 0;
+ return;
+ }
+ }
+}
+
+static void frontend_android_get_version_sdk(int32_t *sdk)
+{
+ char os_version_str[PROP_VALUE_MAX] = {0};
+ system_property_get("ro.build.version.sdk", os_version_str);
+
+ *sdk = 0;
+ if (os_version_str[0])
+ {
+ int num_read = sscanf(os_version_str, "%d", sdk);
+ (void) num_read;
+ }
+}
+
+static bool device_is_xperia_play(const char *name)
+{
+ if (
+ !strcmp(name, "R800x") ||
+ !strcmp(name, "R800at") ||
+ !strcmp(name, "R800i") ||
+ !strcmp(name, "R800a") ||
+ !strcmp(name, "SO-01D")
+ )
+ return true;
+
+ return false;
+}
+
+static bool device_is_game_console(const char *name)
+{
+ if (
+ !strcmp(name, "OUYA Console") ||
+ device_is_xperia_play(name) ||
+ !strcmp(name, "GAMEMID_BT") ||
+ !strcmp(name, "S7800") ||
+ !strcmp(name, "SHIELD")
+ )
+ return true;
+
+ return false;
+}
+
+bool test_permissions(const char *path)
+{
+ char buf[PATH_MAX_LENGTH];
+ bool ret;
+
+ RARCH_LOG("Testing permissions for %s\n",path);
+
+ fill_pathname_join(buf, path, ".retroarch", sizeof(buf));
+ ret = path_mkdir(buf);
+
+ RARCH_LOG("Create %s %s\n", buf, ret ? "true" : "false");
+
+ if(ret)
+ rmdir(buf);
+
+ return ret;
+}
+
+static void frontend_android_shutdown(bool unused)
+{
+ (void)unused;
+ /* Cleaner approaches don't work sadly. */
+ exit(0);
+}
+
+#else
static const char *proc_apm_path = "/proc/apm";
static const char *proc_acpi_battery_path = "/proc/acpi/battery";
static const char *proc_acpi_sysfs_ac_adapter_path= "/sys/class/power_supply/ACAD";
@@ -499,6 +947,24 @@ error:
}
#endif
+static int frontend_linux_get_rating(void)
+{
+#ifdef ANDROID
+ char device_model[PROP_VALUE_MAX] = {0};
+ frontend_android_get_name(device_model, sizeof(device_model));
+
+ RARCH_LOG("ro.product.model: (%s).\n", device_model);
+
+ if (device_is_xperia_play(device_model))
+ return 6;
+ else if (!strcmp(device_model, "GT-I9505"))
+ return 12;
+ else if (!strcmp(device_model, "SHIELD"))
+ return 13;
+#endif
+ return -1;
+}
+
static enum frontend_powerstate frontend_linux_get_powerstate(int *seconds, int *percent)
{
enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
@@ -514,7 +980,7 @@ static enum frontend_powerstate frontend_linux_get_powerstate(int *seconds, int
return ret;
#endif
- return FRONTEND_POWERSTATE_NONE;
+ return ret;
}
#define LINUX_ARCH_X86_64 0x23dea434U
@@ -524,18 +990,35 @@ static enum frontend_powerstate frontend_linux_get_powerstate(int *seconds, int
#define LINUX_ARCH_MIPS 0x7c9aa25eU
#define LINUX_ARCH_TILE 0x7c9e7873U
+#define ANDROID_ARCH_ARMV7 0x26257a91U
+#define ANDROID_ARCH_ARM 0x406a3516U
+
static enum frontend_architecture frontend_linux_get_architecture(void)
{
uint32_t buffer_hash;
+ const char *val;
+#ifdef ANDROID
+ char abi[PROP_VALUE_MAX] = {0};
+ system_property_get("ro.product.cpu.abi", abi);
+ val = abi;
+#else
struct utsname buffer;
if (uname(&buffer) != 0)
return FRONTEND_ARCH_NONE;
- buffer_hash = djb2_calculate(buffer.machine);
+ val = buffer.machine;
+#endif
+ buffer_hash = djb2_calculate(val);
switch (buffer_hash)
{
+#ifdef ANDROID
+ case ANDROID_ARCH_ARMV7:
+ return FRONTEND_ARCH_ARM;
+ case ANDROID_ARCH_ARM:
+ return FRONTEND_ARCH_ARM;
+#endif
case LINUX_ARCH_X86_64:
return FRONTEND_ARCH_X86_64;
case LINUX_ARCH_X86:
@@ -555,7 +1038,12 @@ static enum frontend_architecture frontend_linux_get_architecture(void)
static void frontend_linux_get_os(char *s, size_t len, int *major, int *minor)
{
-#ifndef ANDROID
+#ifdef ANDROID
+ int rel;
+ frontend_android_get_version(major, minor, &rel);
+
+ strlcpy(s, "Android", len);
+#else
unsigned krel;
struct utsname buffer;
@@ -570,79 +1058,604 @@ static void frontend_linux_get_os(char *s, size_t len, int *major, int *minor)
static void frontend_linux_get_env(int *argc,
char *argv[], void *data, void *params_data)
{
- char base_path[PATH_MAX];
- const char *xdg = getenv("XDG_CONFIG_HOME");
- const char *home = getenv("HOME");
+#ifdef ANDROID
+ 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 (xdg)
- snprintf(base_path, sizeof(base_path), "%s/retroarch", xdg);
- else if (home)
- snprintf(base_path, sizeof(base_path), "%s/.config/retroarch", home);
- else
- snprintf(base_path, sizeof(base_path), "retroarch");
+ if (!android_app)
+ return;
- fill_pathname_join(g_defaults.dir.core, base_path,
- "cores", sizeof(g_defaults.dir.core));
- fill_pathname_join(g_defaults.dir.core_info, base_path,
- "cores", sizeof(g_defaults.dir.core_info));
- fill_pathname_join(g_defaults.dir.autoconfig, base_path,
- "autoconf", sizeof(g_defaults.dir.autoconfig));
- fill_pathname_join(g_defaults.dir.assets, base_path,
- "assets", sizeof(g_defaults.dir.assets));
- fill_pathname_join(g_defaults.dir.remap, base_path,
- "remap", sizeof(g_defaults.dir.remap));
- fill_pathname_join(g_defaults.dir.playlist, base_path,
- "playlists", sizeof(g_defaults.dir.playlist));
- fill_pathname_join(g_defaults.dir.cursor, base_path,
- "database/cursors", sizeof(g_defaults.dir.cursor));
- fill_pathname_join(g_defaults.dir.database, base_path,
- "database/rdb", sizeof(g_defaults.dir.database));
- fill_pathname_join(g_defaults.dir.shader, base_path,
- "shaders", sizeof(g_defaults.dir.shader));
- fill_pathname_join(g_defaults.dir.cheats, base_path,
- "cheats", sizeof(g_defaults.dir.cheats));
- fill_pathname_join(g_defaults.dir.overlay, base_path,
- "overlay", sizeof(g_defaults.dir.overlay));
- fill_pathname_join(g_defaults.dir.osk_overlay, base_path,
- "overlay", sizeof(g_defaults.dir.osk_overlay));
+ env = jni_thread_getenv();
+ if (!env)
+ return;
- if(home)
+ args = (struct rarch_main_wrap*)params_data;
+
+ if (args)
{
- fill_pathname_join(g_defaults.dir.screenshot, home,
- "Pictures", sizeof(g_defaults.dir.screenshot));
- fill_pathname_join(g_defaults.dir.core_assets, home,
- "Downloads", sizeof(g_defaults.dir.core_assets));
- }
- else
- {
- fill_pathname_join(g_defaults.dir.screenshot, home,
- "retroArch/screenshots", sizeof(g_defaults.dir.screenshot));
- fill_pathname_join(g_defaults.dir.core_assets, home,
- "retroarch/downloads", sizeof(g_defaults.dir.core_assets));
+ args->touched = true;
+ args->no_content = false;
+ args->verbose = false;
+ args->sram_path = NULL;
+ args->state_path = NULL;
}
- return;
+ 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 = (*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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *core_path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *sdcard_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *screenshot_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *downloads_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *apk_path = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *ext_dir = '\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 = (*env)->GetStringUTFChars(env, jstr, 0);
+
+ *app_dir = '\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.osk_overlay, app_dir,
+ "overlays", sizeof(g_defaults.dir.osk_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
+#else
+ char base_path[PATH_MAX];
+ const char *xdg = getenv("XDG_CONFIG_HOME");
+ const char *home = getenv("HOME");
+
+ if (xdg)
+ snprintf(base_path, sizeof(base_path), "%s/retroarch", xdg);
+ else if (home)
+ snprintf(base_path, sizeof(base_path), "%s/.config/retroarch", home);
+ else
+ snprintf(base_path, sizeof(base_path), "retroarch");
+
+ fill_pathname_join(g_defaults.dir.core, base_path,
+ "cores", sizeof(g_defaults.dir.core));
+ fill_pathname_join(g_defaults.dir.core_info, base_path,
+ "cores", sizeof(g_defaults.dir.core_info));
+ fill_pathname_join(g_defaults.dir.autoconfig, base_path,
+ "autoconf", sizeof(g_defaults.dir.autoconfig));
+ fill_pathname_join(g_defaults.dir.assets, base_path,
+ "assets", sizeof(g_defaults.dir.assets));
+ fill_pathname_join(g_defaults.dir.remap, base_path,
+ "remap", sizeof(g_defaults.dir.remap));
+ fill_pathname_join(g_defaults.dir.playlist, base_path,
+ "playlists", sizeof(g_defaults.dir.playlist));
+ fill_pathname_join(g_defaults.dir.cursor, base_path,
+ "database/cursors", sizeof(g_defaults.dir.cursor));
+ fill_pathname_join(g_defaults.dir.database, base_path,
+ "database/rdb", sizeof(g_defaults.dir.database));
+ fill_pathname_join(g_defaults.dir.shader, base_path,
+ "shaders", sizeof(g_defaults.dir.shader));
+ fill_pathname_join(g_defaults.dir.cheats, base_path,
+ "cheats", sizeof(g_defaults.dir.cheats));
+ fill_pathname_join(g_defaults.dir.overlay, base_path,
+ "overlay", sizeof(g_defaults.dir.overlay));
+ fill_pathname_join(g_defaults.dir.osk_overlay, base_path,
+ "overlay", sizeof(g_defaults.dir.osk_overlay));
+
+ if(home)
+ {
+ fill_pathname_join(g_defaults.dir.screenshot, home,
+ "Pictures", sizeof(g_defaults.dir.screenshot));
+ fill_pathname_join(g_defaults.dir.core_assets, home,
+ "Downloads", sizeof(g_defaults.dir.core_assets));
+ }
+ else
+ {
+ fill_pathname_join(g_defaults.dir.screenshot, home,
+ "retroArch/screenshots", sizeof(g_defaults.dir.screenshot));
+ fill_pathname_join(g_defaults.dir.core_assets, home,
+ "retroarch/downloads", sizeof(g_defaults.dir.core_assets));
+ }
+#endif
}
+static void frontend_linux_deinit(void *data)
+{
+#ifdef ANDROID
+ JNIEnv *env = NULL;
+ struct android_app *android_app = (struct android_app*)data;
+
+ if (!android_app)
+ return;
+
+ RARCH_LOG("Deinitializing RetroArch ...\n");
+ android_app->activityState = APP_CMD_DEAD;
+
+ 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);
+ }
+#endif
+}
+
+static void frontend_linux_init(void *data)
+{
+#ifdef ANDROID
+ 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_linux_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;");
+#endif
+}
+
+#ifdef ANDROID
+static int frontend_android_parse_drive_list(void *data)
+{
+ file_list_t *list = (file_list_t*)data;
+
+ // MENU_FILE_DIRECTORY is not working with labels, placeholders for now
+ menu_list_push(list,
+ app_dir, "Application Dir", MENU_FILE_DIRECTORY, 0, 0);
+ menu_list_push(list,
+ ext_dir, "External Application Dir", MENU_FILE_DIRECTORY, 0, 0);
+ menu_list_push(list,
+ sdcard_dir, "Internal Memory", MENU_FILE_DIRECTORY, 0, 0);
+
+ menu_list_push(list, "/", "",
+ MENU_FILE_DIRECTORY, 0, 0);
+
+ return 0;
+}
+#endif
+
frontend_ctx_driver_t frontend_ctx_linux = {
frontend_linux_get_env, /* environment_get */
- NULL, /* init */
- NULL, /* deinit */
+ frontend_linux_init, /* init */
+ frontend_linux_deinit, /* deinit */
NULL, /* exitspawn */
NULL, /* process_args */
NULL, /* exec */
NULL, /* set_fork */
+#ifdef ANDROID
+ frontend_android_shutdown, /* shutdown */
+ frontend_android_get_name, /* get_name */
+#else
NULL, /* shutdown */
NULL, /* get_name */
+#endif
frontend_linux_get_os,
- NULL, /* get_rating */
+ frontend_linux_get_rating, /* get_rating */
NULL, /* load_content */
frontend_linux_get_architecture,
frontend_linux_get_powerstate,
- NULL, /* parse_drive_list */
#ifdef ANDROID
+ frontend_android_parse_drive_list, /* parse_drive_list */
"android",
#else
+ NULL, /* parse_drive_list */
"linux",
#endif
};
diff --git a/frontend/frontend_driver.c b/frontend/frontend_driver.c
index 97dd6411e4..508a55a730 100644
--- a/frontend/frontend_driver.c
+++ b/frontend/frontend_driver.c
@@ -38,10 +38,7 @@ static frontend_ctx_driver_t *frontend_ctx_drivers[] = {
#if defined(__APPLE__) && defined(__MACH__)
&frontend_ctx_darwin,
#endif
-#if defined(ANDROID)
- &frontend_ctx_android,
-#endif
-#if defined(__linux__) && !defined(ANDROID)
+#if defined(__linux__)
&frontend_ctx_linux,
#endif
#if defined(PSP) || defined(VITA)
diff --git a/griffin/griffin.c b/griffin/griffin.c
index 0d39b62289..8b1f610538 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -636,9 +636,7 @@ FRONTEND
#include "../frontend/drivers/platform_xenon.c"
#elif defined(__QNX__)
#include "../frontend/drivers/platform_qnx.c"
-#elif defined(ANDROID)
-#include "../frontend/drivers/platform_android.c"
-#elif defined(__linux__) && !defined(ANDROID)
+#elif defined(__linux__)
#include "../frontend/drivers/platform_linux.c"
#endif
#include "../frontend/drivers/platform_null.c"