static void frontend_android_init(void *data)
{
   JNIEnv *env;
   ALooper *looper;
   jclass class = NULL;
   jobject obj = NULL;
   struct android_app* android_app = (struct android_app*)data;

   if (!android_app)
      return;

   looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
   ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL);
   android_app->looper = looper;

   slock_lock(android_app->mutex);
   android_app->running = 1;
   scond_broadcast(android_app->cond);
   slock_unlock(android_app->mutex);

   memset(&g_android, 0, sizeof(g_android));
   g_android = (struct android_app*)android_app;

   RARCH_LOG("Waiting for Android Native Window to be initialized ...\n");

   while (!android_app->window)
   {
      if (!android_run_events(android_app))
      {
         frontend_android_deinit(android_app);
         frontend_android_shutdown(android_app);
         return;
      }
   }

   RARCH_LOG("Android Native Window initialized.\n");

   env = jni_thread_getenv();
   if (!env)
      return;

   GET_OBJECT_CLASS(env, class, android_app->activity->clazz);
   GET_METHOD_ID(env, android_app->getIntent, class, "getIntent", "()Landroid/content/Intent;");
   CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, android_app->getIntent);
#if 0
   GET_METHOD_ID(env, android_app->hasPendingIntent, class, "hasPendingIntent", "()Z");
   GET_METHOD_ID(env, android_app->clearPendingIntent, class, "clearPendingIntent", "()V");
   GET_METHOD_ID(env, android_app->getPendingIntentConfigPath, class, "getPendingIntentConfigPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentLibretroPath, class, "getPendingIntentLibretroPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentFullPath, class, "getPendingIntentFullPath",
         "()Ljava/lang/String;");
   GET_METHOD_ID(env, android_app->getPendingIntentIME, class, "getPendingIntentIME",
         "()Ljava/lang/String;");
#endif

   GET_OBJECT_CLASS(env, class, obj);
   GET_METHOD_ID(env, android_app->getStringExtra, class, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
}
static void jni_get (void *data_in, void *data_out)
{
   struct jni_params *in_params = (struct jni_params*)data_in;
   struct jni_out_params_char *out_args = (struct jni_out_params_char*)data_out;
   char obj_method_name[128];
   char obj_method_signature[128];
   jclass class_ptr = NULL;
   jobject obj = NULL;
   jmethodID giid = NULL;
   jstring ret_char;

   snprintf(obj_method_name, sizeof(obj_method_name), "getStringExtra");
   snprintf(obj_method_signature, sizeof(obj_method_signature), "(Ljava/lang/String;)Ljava/lang/String;");

   GET_OBJECT_CLASS(in_params->env, class_ptr, in_params->class_obj);
   GET_METHOD_ID(in_params->env, giid, class_ptr, in_params->method_name, in_params->method_signature);
   CALL_OBJ_METHOD(in_params->env, obj, in_params->class_obj, giid);

   GET_OBJECT_CLASS(in_params->env, class_ptr, obj);
   GET_METHOD_ID(in_params->env, giid, class_ptr, obj_method_name, obj_method_signature);

   CALL_OBJ_METHOD_PARAM(in_params->env, ret_char, obj, giid, (*in_params->env)->NewStringUTF(in_params->env, out_args->in));

   if (giid != NULL && ret_char)
   {
      const char *test_argv = (*in_params->env)->GetStringUTFChars(in_params->env, ret_char, 0);
      strncpy(out_args->out, test_argv, out_args->out_sizeof);
      (*in_params->env)->ReleaseStringUTFChars(in_params->env, ret_char, test_argv);
   }
}
static void input_autodetect_get_device_name(void *data, char *buf, size_t size, int id)
{
   struct android_app *android_app = (struct android_app*)data;
   buf[0] = '\0';

   JavaVM *vm = android_app->activity->vm;
   JNIEnv *env = NULL;
   (*vm)->AttachCurrentThread(vm, &env, 0);

   jclass input_device_class = NULL;
   FIND_CLASS(env, input_device_class, "android/view/InputDevice");
   if (!input_device_class)
      goto end;

   jmethodID method = NULL;
   GET_STATIC_METHOD_ID(env, method, input_device_class, "getDevice", "(I)Landroid/view/InputDevice;");
   if (!method)
      goto end;

   jobject device = NULL;
   CALL_OBJ_STATIC_METHOD_PARAM(env, device, input_device_class, method, (jint)id);
   if (!device)
   {
      RARCH_ERR("Failed to find device for ID: %d\n", id);
      goto end;
   }

   jmethodID getName = NULL;
   GET_METHOD_ID(env, getName, input_device_class, "getName", "()Ljava/lang/String;");
   if (!getName)
      goto end;

   jobject name = NULL;
   CALL_OBJ_METHOD(env, name, device, getName);
   if (!name)
   {
      RARCH_ERR("Failed to find name for device ID: %d\n", id);
      goto end;
   }

   const char *str = (*env)->GetStringUTFChars(env, name, 0);
   if (str)
      strlcpy(buf, str, size);
   (*env)->ReleaseStringUTFChars(env, name, str);

end:
   (*vm)->DetachCurrentThread(vm);
}
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 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;
}