From 5d52aaf3a32c33bbf5ef9001d29638aaac7c9b6f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 3 Nov 2013 16:38:56 +0100 Subject: [PATCH] (Android) Rewrite frontend_android --- frontend/frontend.c | 45 +++- frontend/frontend_android.c | 346 ++++++++++++++------------- frontend/frontend_context.c | 3 + frontend/frontend_context.h | 7 +- frontend/platform/platform_android.c | 203 ++++++++++++++++ frontend/platform/platform_apple.c | 3 +- frontend/platform/platform_gx.c | 6 +- frontend/platform/platform_ps3.c | 6 +- frontend/platform/platform_psp.c | 6 +- frontend/platform/platform_qnx.c | 3 +- frontend/platform/platform_xdk.c | 3 +- griffin/griffin.c | 2 + 12 files changed, 438 insertions(+), 195 deletions(-) create mode 100644 frontend/platform/platform_android.c diff --git a/frontend/frontend.c b/frontend/frontend.c index a1dd6535cf..1380f638f5 100644 --- a/frontend/frontend.c +++ b/frontend/frontend.c @@ -96,22 +96,37 @@ static void rarch_get_environment_console(void) #define returntype void* #define signature() void* data #define returnfunc() exit(0) -#define return_negative() return NULL +#define return_negative() return +#define return_var(var) return +#define declare_argc() int argc = 0; +#define declare_argv() char *argv[1] +#define args_type() struct android_app* +#define args_initial_ptr() data #elif defined(IOS) || defined(OSX) || defined(HAVE_BB10) #define main_entry rarch_main #define returntype int #define signature() int argc, char *argv[] #define returnfunc() return 0 #define return_negative() return 1 +#define return_var(var) return var +#define declare_argc() +#define declare_argv() +#define args_type() void* +#define args_initial_ptr() NULL #else #define main_entry main #define returntype int #define signature() int argc, char *argv[] #define returnfunc() return 0 #define return_negative() return 1 +#define return_var(var) return var +#define declare_argc() +#define declare_argv() +#define args_type() void* +#define args_initial_ptr() NULL #endif -#if defined(HAVE_BB10) +#if defined(HAVE_BB10) || defined(ANDROID) #define ra_preinited true #else #define ra_preinited false @@ -123,13 +138,13 @@ static void rarch_get_environment_console(void) #define attempt_load_game true #endif -#if defined(RARCH_CONSOLE) || defined(HAVE_BB10) +#if defined(RARCH_CONSOLE) || defined(HAVE_BB10) || defined(ANDROID) #define initial_menu_lifecycle_state (1ULL << MODE_LOAD_GAME) #else #define initial_menu_lifecycle_state (1ULL << MODE_GAME) #endif -#if !defined(RARCH_CONSOLE) && !defined(HAVE_BB10) +#if !defined(RARCH_CONSOLE) && !defined(HAVE_BB10) && !defined(ANDROID) #define attempt_load_game_push_history false #else #define attempt_load_game_push_history true @@ -139,7 +154,7 @@ static void rarch_get_environment_console(void) #define rarch_get_environment_console() (void)0 #endif -#if defined(RARCH_CONSOLE) || defined(__QNX__) +#if defined(RARCH_CONSOLE) || defined(__QNX__) || defined(ANDROID) #define attempt_load_game_fails (1ULL << MODE_MENU) #else #define attempt_load_game_fails (1ULL << MODE_EXIT) @@ -147,15 +162,20 @@ static void rarch_get_environment_console(void) returntype main_entry(signature()) { - void *args = NULL; + declare_argc(); + declare_argv(); + args_type() args = (args_type())args_initial_ptr(); unsigned i; frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first(); if (frontend_ctx && frontend_ctx->init) - frontend_ctx->init(); + frontend_ctx->init(args); if (!ra_preinited) + { rarch_main_clear_state(); + rarch_init_msg_queue(); + } if (frontend_ctx && frontend_ctx->environment_get) { @@ -165,9 +185,8 @@ returntype main_entry(signature()) if (attempt_load_game) { - rarch_init_msg_queue(); int init_ret; - if ((init_ret = rarch_main_init(argc, argv))) return init_ret; + if ((init_ret = rarch_main_init(argc, argv))) return_var(init_ret); } #if defined(HAVE_MENU) || defined(HAVE_BB10) @@ -220,7 +239,7 @@ returntype main_entry(signature()) while ((g_extern.is_paused && !g_extern.is_oneshot) ? rarch_main_idle_iterate() : rarch_main_iterate()) { if (frontend_ctx && frontend_ctx->process_events) - frontend_ctx->process_events(); + frontend_ctx->process_events(args); if (!(g_extern.lifecycle_mode_state & (1ULL << MODE_GAME))) break; @@ -251,7 +270,7 @@ returntype main_entry(signature()) while (!g_extern.system.shutdown && menu_iterate()) { if (frontend_ctx && frontend_ctx->process_events) - frontend_ctx->process_events(); + frontend_ctx->process_events(args); if (!(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))) break; @@ -291,7 +310,7 @@ returntype main_entry(signature()) rarch_perf_log(); #endif -#if defined(HAVE_LOGGER) +#if defined(HAVE_LOGGER) && !defined(ANDROID) logger_shutdown(); #elif defined(HAVE_FILE_LOGGER) if (g_extern.log_file) @@ -300,7 +319,7 @@ returntype main_entry(signature()) #endif if (frontend_ctx && frontend_ctx->deinit) - frontend_ctx->deinit(); + frontend_ctx->deinit(args); if (g_extern.lifecycle_mode_state & (1ULL << MODE_EXITSPAWN) && frontend_ctx && frontend_ctx->exitspawn) diff --git a/frontend/frontend_android.c b/frontend/frontend_android.c index 9bb8f693e2..b5a69cd8fa 100644 --- a/frontend/frontend_android.c +++ b/frontend/frontend_android.c @@ -22,161 +22,129 @@ #include #include "frontend_android.h" -#include "../android/native/jni/jni_macros.h" #include "../general.h" #include "../performance.h" #include "../driver.h" #include "menu/rmenu.h" #include "../config.def.h" +#include "frontend_context.h" -struct android_app *g_android; +frontend_ctx_driver_t *frontend_ctx; -static bool android_run_events (void *data) -{ - int id = ALooper_pollOnce(-1, NULL, NULL, NULL); +#if defined(ANDROID) +#define main_entry android_app_entry +#define returntype void* +#define signature() void* data +#define returnfunc() exit(0) +#define return_negative() return +#define return_var(var) return +#define declare_argc() int argc = 0 +#define declare_argv() char *argv[1] +#define args_type() struct android_app* +#define args_initial_ptr() data +#elif defined(IOS) || defined(OSX) || defined(HAVE_BB10) +#define main_entry rarch_main +#define returntype int +#define signature() int argc, char *argv[] +#define returnfunc() return 0 +#define return_negative() return 1 +#define return_var(var) return var +#define declare_argc() +#define declare_argv() +#define args_type() void* +#define args_initial_ptr() NULL +#else +#define main_entry main +#define returntype int +#define signature() int argc, char *argv[] +#define returnfunc() return 0 +#define return_negative() return 1 +#define return_var(var) return var +#define declare_argc() +#define declare_argv() +#define args_type() void* +#define args_initial_ptr() NULL +#endif - if (id == LOOPER_ID_MAIN) - engine_handle_cmd(); +#if defined(HAVE_BB10) || defined(ANDROID) +#define ra_preinited true +#else +#define ra_preinited false +#endif - // Check if we are exiting. - if (g_extern.lifecycle_state & (1ULL << RARCH_QUIT_KEY)) - return false; +#if defined(HAVE_BB10) || defined(RARCH_CONSOLE) +#define attempt_load_game false +#else +#define attempt_load_game true +#endif - return true; -} +#if defined(RARCH_CONSOLE) || defined(HAVE_BB10) || defined(ANDROID) +#define initial_menu_lifecycle_state (1ULL << MODE_LOAD_GAME) +#else +#define initial_menu_lifecycle_state (1ULL << MODE_GAME) +#endif -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], obj_method_signature[128]; - jclass class_ptr = NULL; - jobject obj = NULL; - jmethodID giid = NULL; - jstring ret_char; +#if !defined(RARCH_CONSOLE) && !defined(HAVE_BB10) && !defined(ANDROID) +#define attempt_load_game_push_history false +#else +#define attempt_load_game_push_history true +#endif - strlcpy(obj_method_name, "getStringExtra", sizeof(obj_method_name)); - strlcpy(obj_method_signature, "(Ljava/lang/String;)Ljava/lang/String;", sizeof(obj_method_signature)); +#ifndef RARCH_CONSOLE +#define rarch_get_environment_console() (void)0 +#endif - 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); - strlcpy(out_args->out, test_argv, out_args->out_sizeof); - (*in_params->env)->ReleaseStringUTFChars(in_params->env, ret_char, test_argv); - } -} - -static bool android_app_start_main(struct android_app *android_app) -{ - struct jni_params in_params; - struct jni_out_params_char out_args; - bool ret = false; - - in_params.java_vm = android_app->activity->vm; - in_params.class_obj = android_app->activity->clazz; - - strlcpy(in_params.method_name, "getIntent", sizeof(in_params.method_name)); - strlcpy(in_params.method_signature, "()Landroid/content/Intent;", sizeof(in_params.method_signature)); - - (*in_params.java_vm)->AttachCurrentThread(in_params.java_vm, &in_params.env, 0); - - // ROM - out_args.out = g_extern.fullpath; - out_args.out_sizeof = sizeof(g_extern.fullpath); - strlcpy(out_args.in, "ROM", sizeof(out_args.in)); - jni_get(&in_params, &out_args); - - // Config file - out_args.out = g_extern.config_path; - out_args.out_sizeof = sizeof(g_extern.config_path); - strlcpy(out_args.in, "CONFIGFILE", sizeof(out_args.in)); - jni_get(&in_params, &out_args); - - // Current IME - out_args.out = android_app->current_ime; - out_args.out_sizeof = sizeof(android_app->current_ime); - strlcpy(out_args.in, "IME", sizeof(out_args.in)); - jni_get(&in_params, &out_args); - - RARCH_LOG("Checking arguments passed ...\n"); - RARCH_LOG("ROM Filename: [%s].\n", g_extern.fullpath); - RARCH_LOG("Config file: [%s].\n", g_extern.config_path); - RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); - - config_load(); - - // libretro - out_args.out = g_settings.libretro; - out_args.out_sizeof = sizeof(g_settings.libretro); - strlcpy(out_args.in, "LIBRETRO", sizeof(out_args.in)); - jni_get(&in_params, &out_args); - - RARCH_LOG("Checking arguments passed ...\n"); - RARCH_LOG("Libretro path: [%s].\n", g_settings.libretro); - - (*in_params.java_vm)->DetachCurrentThread(in_params.java_vm); - - menu_init(); - - - ret = load_menu_game(); - if (ret) - g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME); - - return ret; -} +#if defined(RARCH_CONSOLE) || defined(__QNX__) || defined(ANDROID) +#define attempt_load_game_fails (1ULL << MODE_MENU) +#else +#define attempt_load_game_fails (1ULL << MODE_EXIT) +#endif static void android_app_entry(void *data) { - struct android_app* android_app = (struct android_app*)data; + declare_argc(); + declare_argv(); + args_type() args = (args_type())args_initial_ptr(); + unsigned i; + frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first(); - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL); - android_app->looper = looper; + if (frontend_ctx && frontend_ctx->init) + frontend_ctx->init(args); - 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 = android_app; - - RARCH_LOG("Native Activity started.\n"); - rarch_main_clear_state(); - - while (!android_app->window) + if (!ra_preinited) { - if (!android_run_events(android_app)) - goto exit; + rarch_main_clear_state(); + rarch_init_msg_queue(); } - rarch_init_msg_queue(); - - if (!android_app_start_main(android_app)) + if (frontend_ctx && frontend_ctx->environment_get) { - g_settings.input.overlay[0] = 0; - // threaded video doesn't work right for just displaying one frame - g_settings.video.threaded = false; - init_drivers(); - driver.video_poke->set_aspect_ratio(driver.video_data, ASPECT_RATIO_SQUARE); - rarch_render_cached_frame(); - sleep(2); - goto exit; + frontend_ctx->environment_get(argc, argv, args); + rarch_get_environment_console(); } - if (!g_extern.libretro_dummy) - menu_rom_history_push_current(); + if (attempt_load_game) + { + int init_ret; + if ((init_ret = rarch_main_init(argc, argv))) return_var(init_ret); + } + +#if defined(HAVE_MENU) || defined(HAVE_BB10) + menu_init(); + + if (frontend_ctx && frontend_ctx->process_args) + frontend_ctx->process_args(argc, argv, args); + + g_extern.lifecycle_mode_state |= initial_menu_lifecycle_state; + + if (attempt_load_game_push_history) + { + // If we started a ROM directly from command line, + // push it to ROM history. + if (!g_extern.libretro_dummy) + menu_rom_history_push_current(); + } for (;;) { @@ -191,11 +159,15 @@ static void android_app_entry(void *data) g_extern.lifecycle_mode_state |= (1ULL << MODE_GAME); else { -#ifdef RARCH_CONSOLE - g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU); -#else - return; -#endif + g_extern.lifecycle_mode_state = attempt_load_game_fails; + + if (g_extern.lifecycle_mode_state & (1ULL << MODE_EXIT)) + { + if (frontend_ctx && frontend_ctx->shutdown) + frontend_ctx->shutdown(true); + + return_negative(); + } } g_extern.lifecycle_mode_state &= ~(1ULL << MODE_LOAD_GAME); @@ -205,64 +177,101 @@ static void android_app_entry(void *data) if (driver.video_poke->set_aspect_ratio) driver.video_poke->set_aspect_ratio(driver.video_data, g_settings.video.aspect_ratio_idx); - // Main loop - while (rarch_main_iterate()); + while ((g_extern.is_paused && !g_extern.is_oneshot) ? rarch_main_idle_iterate() : rarch_main_iterate()) + { + if (frontend_ctx && frontend_ctx->process_events) + frontend_ctx->process_events(args); + if (!(g_extern.lifecycle_mode_state & (1ULL << MODE_GAME))) + break; + } g_extern.lifecycle_mode_state &= ~(1ULL << MODE_GAME); } - else if(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) + else if (g_extern.lifecycle_mode_state & (1ULL << MODE_MENU)) { - g_extern.lifecycle_mode_state |= (1ULL << MODE_MENU_PREINIT); - - // Menu should always run with vsync on + g_extern.lifecycle_mode_state |= 1ULL << MODE_MENU_PREINIT; + // Menu should always run with vsync on. video_set_nonblock_state_func(false); + // Stop all rumbling when entering RGUI. + for (i = 0; i < MAX_PLAYERS; i++) + { + driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); + driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); + } + + // Override keyboard callback to redirect to menu instead. + // We'll use this later for something ... + // FIXME: This should probably be moved to menu_common somehow. + retro_keyboard_event_t key_event = g_extern.system.key_event; + g_extern.system.key_event = menu_key_event; if (driver.audio_data) audio_stop_func(); - while((input_key_pressed_func(RARCH_PAUSE_TOGGLE)) ? - android_run_events(android_app) : menu_iterate()); + while (!g_extern.system.shutdown && menu_iterate()) + { + if (frontend_ctx && frontend_ctx->process_events) + frontend_ctx->process_events(args); + + if (!(g_extern.lifecycle_mode_state & (1ULL << MODE_MENU))) + break; + } driver_set_nonblock_state(driver.nonblock_state); - if (driver.audio_data && !audio_start_func()) + if (driver.audio_data && !g_extern.audio_data.mute && !audio_start_func()) { RARCH_ERR("Failed to resume audio driver. Will continue without audio.\n"); g_extern.audio_active = false; } g_extern.lifecycle_mode_state &= ~(1ULL << MODE_MENU); + + // Restore libretro keyboard callback. + g_extern.system.key_event = key_event; } else break; } -exit: - android_app->activityState = APP_CMD_DEAD; - RARCH_LOG("Deinitializing RetroArch...\n"); - + g_extern.system.shutdown = false; menu_free(); if (g_extern.config_save_on_exit && *g_extern.config_path) config_save_file(g_extern.config_path); +#else + while ((g_extern.is_paused && !g_extern.is_oneshot) ? rarch_main_idle_iterate() : rarch_main_iterate()); +#endif - if (g_extern.main_is_init) - rarch_main_deinit(); - + rarch_main_deinit(); rarch_deinit_msg_queue(); + global_uninit_drivers(); + #ifdef PERF_TEST rarch_perf_log(); #endif + +#if defined(HAVE_LOGGER) && !defined(ANDROID) + logger_shutdown(); +#elif defined(HAVE_FILE_LOGGER) + if (g_extern.log_file) + fclose(g_extern.log_file); + g_extern.log_file = NULL; +#endif + + if (frontend_ctx && frontend_ctx->deinit) + frontend_ctx->deinit(args); + + if (g_extern.lifecycle_mode_state & (1ULL << MODE_EXITSPAWN) && frontend_ctx + && frontend_ctx->exitspawn) + frontend_ctx->exitspawn(); + rarch_main_clear_state(); - RARCH_LOG("android_app_destroy!"); - if (android_app->inputQueue != NULL) - AInputQueue_detachLooper(android_app->inputQueue); + if (frontend_ctx && frontend_ctx->shutdown) + frontend_ctx->shutdown(false); - // exit() here is nasty. - // pthread_exit(NULL) or return NULL; causes hanging ... - // Should probably call ANativeActivity_finish(), but it's bugged, it will hang our app. - exit(0); + returnfunc(); } static inline void android_app_write_cmd (void *data, int8_t cmd) @@ -432,19 +441,16 @@ void ANativeActivity_onCreate(ANativeActivity* activity, RARCH_ERR("could not create pipe: %s.\n", strerror(errno)); activity->instance = NULL; } - else - { - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; + android_app->msgread = msgpipe[0]; + android_app->msgwrite = msgpipe[1]; - android_app->thread = (sthread_t*)sthread_create(android_app_entry, android_app); + android_app->thread = (sthread_t*)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); + // 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; - } + activity->instance = android_app; } diff --git a/frontend/frontend_context.c b/frontend/frontend_context.c index 61c3a885d3..0e77de2dde 100644 --- a/frontend/frontend_context.c +++ b/frontend/frontend_context.c @@ -35,6 +35,9 @@ static const frontend_ctx_driver_t *frontend_ctx_drivers[] = { #endif #if defined(IOS) || defined(OSX) &frontend_ctx_apple, +#endif +#if defined(ANDROID) + &frontend_ctx_android, #endif NULL // zero length array is not valid }; diff --git a/frontend/frontend_context.h b/frontend/frontend_context.h index 04dd6736ee..fc013d1f57 100644 --- a/frontend/frontend_context.h +++ b/frontend/frontend_context.h @@ -34,12 +34,12 @@ typedef struct frontend_ctx_driver { void (*environment_get)(int argc, char *argv[], void *args); - void (*init)(void); - void (*deinit)(void); + void (*init)(void *data); + void (*deinit)(void *data); void (*exitspawn)(void); int (*process_args)(int argc, char *argv[], void *args); - int (*process_events)(void); + int (*process_events)(void *data); void (*exec)(const char *, bool); void (*shutdown)(bool); @@ -52,6 +52,7 @@ extern const frontend_ctx_driver_t frontend_ctx_ps3; extern const frontend_ctx_driver_t frontend_ctx_xdk; extern const frontend_ctx_driver_t frontend_ctx_qnx; extern const frontend_ctx_driver_t frontend_ctx_apple; +extern const frontend_ctx_driver_t frontend_ctx_android; const frontend_ctx_driver_t *frontend_ctx_find_driver(const char *ident); // Finds driver with ident. Does not initialize. const frontend_ctx_driver_t *frontend_ctx_init_first(void); // Finds first suitable driver and initializes. diff --git a/frontend/platform/platform_android.c b/frontend/platform/platform_android.c new file mode 100644 index 0000000000..c235c3bab5 --- /dev/null +++ b/frontend/platform/platform_android.c @@ -0,0 +1,203 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2013 - Hans-Kristian Arntzen + * Copyright (C) 2011-2013 - Daniel De Matteis + * + * 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 "../frontend_android.h" +#include "../../android/native/jni/jni_macros.h" + +#include "../../conf/config_file.h" +#include "../../general.h" +#include "../../file.h" + +struct android_app *g_android; + +//forward decls +static void system_deinit(void *data); +static void system_shutdown(bool unused); + +static bool android_run_events (void *data) +{ + int id = ALooper_pollOnce(-1, NULL, NULL, NULL); + + if (id == LOOPER_ID_MAIN) + engine_handle_cmd(); + + // Check if we are exiting. + if (g_extern.lifecycle_state & (1ULL << RARCH_QUIT_KEY)) + return false; + + return true; +} + +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], obj_method_signature[128]; + jclass class_ptr = NULL; + jobject obj = NULL; + jmethodID giid = NULL; + jstring ret_char; + + strlcpy(obj_method_name, "getStringExtra", sizeof(obj_method_name)); + strlcpy(obj_method_signature, "(Ljava/lang/String;)Ljava/lang/String;", sizeof(obj_method_signature)); + + 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); + strlcpy(out_args->out, test_argv, out_args->out_sizeof); + (*in_params->env)->ReleaseStringUTFChars(in_params->env, ret_char, test_argv); + } +} + +static void get_environment_settings(int argc, char *argv[], void *data) +{ + struct android_app* android_app = (struct android_app*)data; + + struct jni_params in_params; + struct jni_out_params_char out_args; + + in_params.java_vm = android_app->activity->vm; + in_params.class_obj = android_app->activity->clazz; + + strlcpy(in_params.method_name, "getIntent", sizeof(in_params.method_name)); + strlcpy(in_params.method_signature, "()Landroid/content/Intent;", sizeof(in_params.method_signature)); + + (*in_params.java_vm)->AttachCurrentThread(in_params.java_vm, &in_params.env, 0); + + // ROM + out_args.out = g_extern.fullpath; + out_args.out_sizeof = sizeof(g_extern.fullpath); + strlcpy(out_args.in, "ROM", sizeof(out_args.in)); + jni_get(&in_params, &out_args); + + // Config file + out_args.out = g_extern.config_path; + out_args.out_sizeof = sizeof(g_extern.config_path); + strlcpy(out_args.in, "CONFIGFILE", sizeof(out_args.in)); + jni_get(&in_params, &out_args); + + // Current IME + out_args.out = android_app->current_ime; + out_args.out_sizeof = sizeof(android_app->current_ime); + strlcpy(out_args.in, "IME", sizeof(out_args.in)); + jni_get(&in_params, &out_args); + + RARCH_LOG("Checking arguments passed ...\n"); + RARCH_LOG("ROM Filename: [%s].\n", g_extern.fullpath); + RARCH_LOG("Config file: [%s].\n", g_extern.config_path); + RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); + + config_load(); + + // libretro + out_args.out = g_settings.libretro; + out_args.out_sizeof = sizeof(g_settings.libretro); + strlcpy(out_args.in, "LIBRETRO", sizeof(out_args.in)); + jni_get(&in_params, &out_args); + + RARCH_LOG("Checking arguments passed ...\n"); + RARCH_LOG("Libretro path: [%s].\n", g_settings.libretro); + + (*in_params.java_vm)->DetachCurrentThread(in_params.java_vm); +} + +static int process_events(void *data) +{ + struct android_app* android_app = (struct android_app*)data; + + if (input_key_pressed_func(RARCH_PAUSE_TOGGLE)) + android_run_events(android_app); + + return 0; +} + +static void system_init(void *data) +{ + struct android_app* android_app = (struct android_app*)data; + + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, NULL); + android_app->looper = looper; + + 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 = android_app; + + RARCH_LOG("Native Activity started.\n"); + rarch_main_clear_state(); + rarch_init_msg_queue(); + + while (!android_app->window) + { + if (!android_run_events(android_app)) + { + system_deinit(android_app); + system_shutdown(android_app); + } + } +} + +static void system_deinit(void *data) +{ + struct android_app* android_app = (struct android_app*)data; + + RARCH_LOG("Deinitializing RetroArch...\n"); + android_app->activityState = APP_CMD_DEAD; + + RARCH_LOG("android_app_destroy!"); + if (android_app->inputQueue != NULL) + AInputQueue_detachLooper(android_app->inputQueue); +} + +static void system_shutdown(bool unused) +{ + (void)unused; + // exit() here is nasty. + // pthread_exit(NULL) or return NULL; causes hanging ... + // Should probably call ANativeActivity_finish(), but it's bugged, it will hang our app. + exit(0); +} + +const frontend_ctx_driver_t frontend_ctx_android = { + get_environment_settings, /* get_environment_settings */ + system_init, /* init */ + system_deinit, /* deinit */ + NULL, /* exitspawn */ + NULL, /* process_args */ + process_events, /* process_events */ + NULL, /* exec */ + system_shutdown, /* shutdown */ + "android", +}; diff --git a/frontend/platform/platform_apple.c b/frontend/platform/platform_apple.c index a35ec8a1f2..4b6a3a5df9 100644 --- a/frontend/platform/platform_apple.c +++ b/frontend/platform/platform_apple.c @@ -48,8 +48,9 @@ void apple_frontend_post_event(void (*fn)(void*), void* userdata) pthread_mutex_unlock(&apple_event_queue_lock); } -static void process_events(void) +static void process_events(void *data) { + (void)data; pthread_mutex_lock(&apple_event_queue_lock); for (int i = 0; i < apple_event_queue_size; i ++) diff --git a/frontend/platform/platform_gx.c b/frontend/platform/platform_gx.c index 6b8dbf7f08..3cf9cb01f7 100644 --- a/frontend/platform/platform_gx.c +++ b/frontend/platform/platform_gx.c @@ -262,8 +262,9 @@ static void get_environment_settings(int argc, char *argv[], void *args) extern void __exception_setreload(int t); -static void system_init(void) +static void system_init(void *data) { + (void)data; #ifdef HW_RVL IOS_ReloadIOS(IOS_GetVersion()); L2Enhance(); @@ -320,8 +321,9 @@ static void system_exitspawn(void) #endif } -static void system_deinit(void) +static void system_deinit(void *data) { + (void)data; #ifndef IS_SALAMANDER // we never init GX/VIDEO subsystems in salamander GX_DrawDone(); diff --git a/frontend/platform/platform_ps3.c b/frontend/platform/platform_ps3.c index 446d2b5280..c14561fbde 100644 --- a/frontend/platform/platform_ps3.c +++ b/frontend/platform/platform_ps3.c @@ -288,8 +288,9 @@ static void get_environment_settings(int argc, char *argv[], void *args) } } -static void system_init(void) +static void system_init(void *data) { + (void)data; #ifdef HAVE_SYSUTILS RARCH_LOG("Registering system utility callback...\n"); cellSysutilRegisterCallback(0, callback_sysutil_exit, NULL); @@ -359,8 +360,9 @@ static int system_process_args(int argc, char *argv[], void *args) return 0; } -static void system_deinit(void) +static void system_deinit(void *data) { + (void)data; #ifndef IS_SALAMANDER #if defined(HAVE_SYSMODULES) diff --git a/frontend/platform/platform_psp.c b/frontend/platform/platform_psp.c index 1702cf3cbb..0b0ef25c75 100644 --- a/frontend/platform/platform_psp.c +++ b/frontend/platform/platform_psp.c @@ -90,8 +90,9 @@ static int setup_callback(void) return thread_id; } -static void system_init(void) +static void system_init(void *data) { + (void)data; //initialize debug screen pspDebugScreenInit(); pspDebugScreenClear(); @@ -99,8 +100,9 @@ static void system_init(void) setup_callback(); } -static void system_deinit(void) +static void system_deinit(void *data) { + (void)data; sceKernelExitGame(); } diff --git a/frontend/platform/platform_qnx.c b/frontend/platform/platform_qnx.c index a531f616c9..46ffade0f7 100644 --- a/frontend/platform/platform_qnx.c +++ b/frontend/platform/platform_qnx.c @@ -36,8 +36,9 @@ static void get_environment_settings(int argc, char *argv[], void *args) config_load(); } -static void system_init(void) +static void system_init(void *data) { + (void)data; /* FIXME - should this apply for both BB10 and PB? */ #if defined(__QNX__) && !defined(HAVE_BB10) bps_initialize(); diff --git a/frontend/platform/platform_xdk.c b/frontend/platform/platform_xdk.c index e6b80a08b7..0b67850328 100644 --- a/frontend/platform/platform_xdk.c +++ b/frontend/platform/platform_xdk.c @@ -253,8 +253,9 @@ static void get_environment_settings(int argc, char *argv[], void *args) #endif } -static void system_init(void) +static void system_init(void *data) { + (void)data; #if defined(_XBOX1) && !defined(IS_SALAMANDER) // Mount drives xbox_io_mount("A:", "cdrom0"); diff --git a/griffin/griffin.c b/griffin/griffin.c index e893a15035..8f0c967b45 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -468,6 +468,8 @@ FRONTEND #include "../frontend/platform/platform_qnx.c" #elif defined(OSX) || defined(IOS) #include "../frontend/platform/platform_apple.c" +#elif defined(ANDROID) +#include "../frontend/platform/platform_android.c" #endif /*============================================================