From 7242693e6978d9df16c1450430feec9849748987 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 9 May 2015 09:38:45 +0200 Subject: [PATCH] (Android) Go back to old input code --- frontend/drivers/android_native_app_glue.c | 487 ---------------- frontend/drivers/android_native_app_glue.h | 364 ------------ frontend/drivers/platform_android.c | 528 +++++++++++------- frontend/drivers/platform_android.h | 191 ++++--- griffin/griffin.c | 1 - input/drivers/android_input.c | 621 ++++++++++++++------- input/drivers_joypad/android_joypad.c | 14 +- 7 files changed, 858 insertions(+), 1348 deletions(-) delete mode 100644 frontend/drivers/android_native_app_glue.c delete mode 100644 frontend/drivers/android_native_app_glue.h diff --git a/frontend/drivers/android_native_app_glue.c b/frontend/drivers/android_native_app_glue.c deleted file mode 100644 index db48377154..0000000000 --- a/frontend/drivers/android_native_app_glue.c +++ /dev/null @@ -1,487 +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 "platform_android.h" - -static void free_saved_state(struct android_app* android_app) -{ - pthread_mutex_lock(&android_app->mutex); - if (android_app->savedState != NULL) - { - free(android_app->savedState); - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - pthread_mutex_unlock(&android_app->mutex); -} - - -int8_t android_app_read_cmd(struct android_app *android_app) -{ - int8_t cmd; - if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) - { - switch (cmd) - { - case APP_CMD_SAVE_STATE: - free_saved_state(android_app); - break; - } - return cmd; - } - else - { - RARCH_ERR("No data on command pipe.\n"); - } - return 1; -} - -static void print_cur_config(struct android_app* android_app) -{ - char lang[2], country[2]; - AConfiguration_getLanguage(android_app->config, lang); - AConfiguration_getCountry(android_app->config, country); - - RARCH_LOG("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " - "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " - "modetype=%d modenight=%d\n", - AConfiguration_getMcc(android_app->config), - AConfiguration_getMnc(android_app->config), - lang[0], lang[1], country[0], country[1], - AConfiguration_getOrientation(android_app->config), - AConfiguration_getTouchscreen(android_app->config), - AConfiguration_getDensity(android_app->config), - AConfiguration_getKeyboard(android_app->config), - AConfiguration_getNavigation(android_app->config), - AConfiguration_getKeysHidden(android_app->config), - AConfiguration_getNavHidden(android_app->config), - AConfiguration_getSdkVersion(android_app->config), - AConfiguration_getScreenSize(android_app->config), - AConfiguration_getScreenLong(android_app->config), - AConfiguration_getUiModeType(android_app->config), - AConfiguration_getUiModeNight(android_app->config)); -} - -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) -{ - switch (cmd) - { - case APP_CMD_INPUT_CHANGED: - RARCH_LOG("APP_CMD_INPUT_CHANGED\n"); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) - AInputQueue_detachLooper(android_app->inputQueue); - android_app->inputQueue = android_app->pendingInputQueue; - if (android_app->inputQueue != NULL) - { - RARCH_LOG("Attaching input queue to looper"); - AInputQueue_attachLooper(android_app->inputQueue, - android_app->looper, LOOPER_ID_INPUT, NULL, - &android_app->inputPollSource); - } - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_INIT_WINDOW: - RARCH_LOG("APP_CMD_INIT_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_TERM_WINDOW: - RARCH_LOG("APP_CMD_TERM_WINDOW\n"); - pthread_cond_broadcast(&android_app->cond); - break; - - case APP_CMD_RESUME: - case APP_CMD_START: - case APP_CMD_PAUSE: - case APP_CMD_STOP: - RARCH_LOG("activityState=%d\n", cmd); - pthread_mutex_lock(&android_app->mutex); - android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_CONFIG_CHANGED: - RARCH_LOG("APP_CMD_CONFIG_CHANGED\n"); - AConfiguration_fromAssetManager(android_app->config, - android_app->activity->assetManager); - print_cur_config(android_app); - break; - - case APP_CMD_DESTROY: - RARCH_LOG("APP_CMD_DESTROY\n"); - android_app->destroyRequested = 1; - break; - } -} - -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) -{ - switch (cmd) - { - case APP_CMD_TERM_WINDOW: - RARCH_LOG("APP_CMD_TERM_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = NULL; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_SAVE_STATE: - RARCH_LOG("APP_CMD_SAVE_STATE\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_RESUME: - free_saved_state(android_app); - break; - } -} - -void app_dummy(void) -{ - -} - -static void android_app_destroy(struct android_app* android_app) -{ - RARCH_LOG("android_app_destroy!"); - free_saved_state(android_app); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) - AInputQueue_detachLooper(android_app->inputQueue); - AConfiguration_delete(android_app->config); - android_app->destroyed = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - /* Can't touch android_app object after this. */ -} - -static void process_input(struct android_app* app, struct android_poll_source* source) -{ - AInputEvent* event = NULL; - int processed = 0; - - while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) - { - int32_t handled = 0; - RARCH_LOG("New input event: type=%d\n", AInputEvent_getType(event)); - if (AInputQueue_preDispatchEvent(app->inputQueue, event)) - continue; - if (app->onInputEvent != NULL) - handled = app->onInputEvent(app, event); - AInputQueue_finishEvent(app->inputQueue, event, handled); - processed = 1; - } - if (processed == 0) - RARCH_ERR("Failure reading next input event: %s\n", strerror(errno)); -} - -static void process_cmd(struct android_app* app, struct android_poll_source* source) -{ - int8_t cmd = android_app_read_cmd(app); - android_app_pre_exec_cmd(app, cmd); - if (app->onAppCmd != NULL) - app->onAppCmd(app, cmd); - android_app_post_exec_cmd(app, cmd); -} - -static void *android_app_entry(void *param) -{ - ALooper *looper; - struct android_app* android_app = (struct android_app*)param; - - android_app->config = AConfiguration_new(); - AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); - - print_cur_config(android_app); - - android_app->cmdPollSource.id = LOOPER_ID_MAIN; - android_app->cmdPollSource.app = android_app; - android_app->cmdPollSource.process = process_cmd; - android_app->inputPollSource.id = LOOPER_ID_INPUT; - android_app->inputPollSource.app = android_app; - android_app->inputPollSource.process = process_input; - - looper = (ALooper*)ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, - ALOOPER_EVENT_INPUT, NULL, &android_app->cmdPollSource); - android_app->looper = looper; - - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - - android_main(android_app); - - android_app_destroy(android_app); - return NULL; -} - -/* -------------------------------------------------------------------- - * Native activity interaction (called from main thread) - * -------------------------------------------------------------------- - */ - -static struct android_app* android_app_create(ANativeActivity* activity, - void* savedState, size_t savedStateSize) -{ - int msgpipe[2]; - struct android_app* android_app = (struct android_app*) - calloc(1, sizeof(*android_app)); - android_app->activity = activity; - - pthread_mutex_init(&android_app->mutex, NULL); - pthread_cond_init(&android_app->cond, NULL); - - if (savedState != NULL) - { - android_app->savedState = malloc(savedStateSize); - android_app->savedStateSize = savedStateSize; - memcpy(android_app->savedState, savedState, savedStateSize); - } - - 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]; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&android_app->thread, &attr, android_app_entry, android_app); - - /* Wait for thread to start. */ - pthread_mutex_lock(&android_app->mutex); - while (!android_app->running) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - pthread_mutex_unlock(&android_app->mutex); - - return android_app; -} - -void android_app_write_cmd(struct android_app *android_app, int8_t cmd) -{ - 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; - - pthread_mutex_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) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - - pthread_mutex_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; - - pthread_mutex_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) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_activity_state(struct android_app *android_app, int8_t cmd) -{ - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_free(struct android_app* android_app) -{ - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, APP_CMD_DESTROY); - while (!android_app->destroyed) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - pthread_mutex_unlock(&android_app->mutex); - - close(android_app->msgread); - close(android_app->msgwrite); - pthread_cond_destroy(&android_app->cond); - pthread_mutex_destroy(&android_app->mutex); - free(android_app); -} - -static void onDestroy(ANativeActivity* activity) -{ - RARCH_LOG("Destroy: %p\n", activity); - android_app_free((struct android_app*)activity->instance); -} - -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* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) -{ - struct android_app* android_app = (struct android_app*)activity->instance; - void* savedState = NULL; - - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 0; - android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); - while (!android_app->stateSaved) - pthread_cond_wait(&android_app->cond, &android_app->mutex); - - if (android_app->savedState != NULL) - { - savedState = android_app->savedState; - *outLen = android_app->savedStateSize; - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - - pthread_mutex_unlock(&android_app->mutex); - - return savedState; -} - -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 onLowMemory(ANativeActivity* activity) -{ - struct android_app* android_app = (struct android_app*)activity->instance; - android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); -} - -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); -} - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) -{ - RARCH_LOG("Creating Native Activity: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = onSaveInstanceState; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onLowMemory = onLowMemory; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - - activity->instance = android_app_create(activity, savedState, savedStateSize); -} diff --git a/frontend/drivers/android_native_app_glue.h b/frontend/drivers/android_native_app_glue.h deleted file mode 100644 index b3beaa49b0..0000000000 --- a/frontend/drivers/android_native_app_glue.h +++ /dev/null @@ -1,364 +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 . - */ - -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef _ANDROID_NATIVE_APP_GLUE_H -#define _ANDROID_NATIVE_APP_GLUE_H - -#include -#include -#include - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The native activity interface provided by - * is based on a set of application-provided callbacks that will be called - * by the Activity's main thread when certain events occur. - * - * This means that each one of this callbacks _should_ _not_ block, or they - * risk having the system force-close the application. This programming - * model is direct, lightweight, but constraining. - * - * The 'threaded_native_app' static library is used to provide a different - * execution model where the application can implement its own main event - * loop in a different thread instead. Here's how it works: - * - * 1/ The application must provide a function named "android_main()" that - * will be called when the activity is created, in a new thread that is - * distinct from the activity's main thread. - * - * 2/ android_main() receives a pointer to a valid "android_app" structure - * that contains references to other important objects, e.g. the - * ANativeActivity obejct instance the application is running in. - * - * 3/ the "android_app" object holds an ALooper instance that already - * listens to two important things: - * - * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX - * declarations below. - * - * - input events coming from the AInputQueue attached to the activity. - * - * Each of these correspond to an ALooper identifier returned by - * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, - * respectively. - * - * Your application can use the same ALooper to listen to additional - * file-descriptors. They can either be callback based, or with return - * identifiers starting with LOOPER_ID_USER. - * - * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event, - * the returned data will point to an android_poll_source structure. You - * can call the process() function on it, and fill in android_app->onAppCmd - * and android_app->onInputEvent to be called for your own processing - * of the event. - * - * Alternatively, you can call the low-level functions to read and process - * the data directly... look at the process_cmd() and process_input() - * implementations in the glue to see how to do this. - * - * See the sample named "native-activity" that comes with the NDK with a - * full usage example. Also look at the JavaDoc of NativeActivity. - */ - -struct android_app; - -/** - * Data associated with an ALooper fd that will be returned as the "outData" - * when that source has data ready. - */ -struct android_poll_source -{ - /* The identifier of this source. May be LOOPER_ID_MAIN or - * LOOPER_ID_INPUT. */ - int32_t id; - - /* The android_app this ident is associated with. */ - struct android_app *app; - - /* Function to call to perform the standard processing of data from - * this source. */ - void (*process)(struct android_app *app, struct android_poll_source *source); -}; - -/** - * This is the interface for the standard glue code of a threaded - * application. In this model, the application's code is running - * in its own thread separate from the main thread of the process. - * It is not required that this thread be associated with the Java - * VM, although it will need to be in order to make JNI calls any - * Java objects. - */ -struct android_app -{ - /* The application can place a pointer to its own state object - * here if it likes. */ - void *userData; - - /* Fill this in with the function to process main app commands (APP_CMD_*) */ - void (*onAppCmd)(struct android_app *app, int32_t cmd); - - /* Fill this in with the function to process input events. At this point - * the event has already been pre-dispatched, and it will be finished upon - * return. Return 1 if you have handled the event, 0 for any default - * dispatching. */ - int32_t (*onInputEvent)(struct android_app *app, AInputEvent *event); - - - /* The ANativeActivity object instance that this app is running in. */ - ANativeActivity* activity; - - /* The current configuration the app is running in. */ - AConfiguration *config; - - /* This is the last instance's saved state, as provided at creation time. - * It is NULL if there was no state. You can use this as you need; the - * memory will remain around until you call android_app_exec_cmd() for - * APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. - * These variables should only be changed when processing a APP_CMD_SAVE_STATE, - * at which point they will be initialized to NULL and you can malloc your - * state and place the information here. In that case the memory will be - * freed for you later. */ - void* savedState; - size_t savedStateSize; - - /* The ALooper associated with the app's thread. */ - ALooper* looper; - - /* When non-NULL, this is the input queue from which the app will - * receive user input events. */ - AInputQueue* inputQueue; - - /* When non-NULL, this is the window surface that the app can draw in. */ - ANativeWindow* window; - - /* Current content rectangle of the window; this is the area where the - * window's content should be placed to be seen by the user. */ - ARect contentRect; - - /* Current state of the app's activity. May be either APP_CMD_START, - * APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. */ - int activityState; - - /* This is non-zero when the application's NativeActivity is being - * destroyed and waiting for the app thread to complete. */ - int destroyRequested; - - /* Below are "private" implementation variables of the glue code. */ - - pthread_mutex_t mutex; - pthread_cond_t cond; - - int msgread; - int msgwrite; - - pthread_t thread; - - struct android_poll_source cmdPollSource; - struct android_poll_source inputPollSource; - - int running; - int stateSaved; - int destroyed; - int redrawNeeded; - AInputQueue* pendingInputQueue; - ANativeWindow* pendingWindow; - ARect pendingContentRect; -}; - -enum -{ - /** - * Looper data ID of commands coming from the app's main thread, which - * is returned as an identifier from ALooper_pollOnce(). The data for this - * identifier is a pointer to an android_poll_source structure. - * These can be retrieved and processed with android_app_read_cmd() - * and android_app_exec_cmd(). - */ - LOOPER_ID_MAIN = 1, - - /** - * Looper data ID of events coming from the AInputQueue of the - * application's window, which is returned as an identifier from - * ALooper_pollOnce(). The data for this identifier is a pointer to an - * android_poll_source structure. These can be read via the inputQueue - * object of android_app. - */ - LOOPER_ID_INPUT = 2, - - /** - * Start of user-defined ALooper identifiers. - */ - LOOPER_ID_USER = 3, -}; - -enum -{ - /** - * Command from main thread: the AInputQueue has changed. Upon processing - * this command, android_app->inputQueue will be updated to the new queue - * (or NULL). - */ - APP_CMD_INPUT_CHANGED, - - /** - * Command from main thread: a new ANativeWindow is ready for use. Upon - * receiving this command, android_app->window will contain the new window - * surface. - */ - APP_CMD_INIT_WINDOW, - - /** - * Command from main thread: the existing ANativeWindow needs to be - * terminated. Upon receiving this command, android_app->window still - * contains the existing window; after calling android_app_exec_cmd - * it will be set to NULL. - */ - APP_CMD_TERM_WINDOW, - - /** - * Command from main thread: the current ANativeWindow has been resized. - * Please redraw with its new size. - */ - APP_CMD_WINDOW_RESIZED, - - /** - * Command from main thread: the system needs that the current ANativeWindow - * be redrawn. You should redraw the window before handing this to - * android_app_exec_cmd() in order to avoid transient drawing glitches. - */ - APP_CMD_WINDOW_REDRAW_NEEDED, - - /** - * Command from main thread: the content area of the window has changed, - * such as from the soft input window being shown or hidden. You can - * find the new content rect in android_app::contentRect. - */ - APP_CMD_CONTENT_RECT_CHANGED, - - /** - * Command from main thread: the app's activity window has gained - * input focus. - */ - APP_CMD_GAINED_FOCUS, - - /** - * Command from main thread: the app's activity window has lost - * input focus. - */ - APP_CMD_LOST_FOCUS, - - /** - * Command from main thread: the current device configuration has changed. - */ - APP_CMD_CONFIG_CHANGED, - - /** - * Command from main thread: the system is running low on memory. - * Try to reduce your memory use. - */ - APP_CMD_LOW_MEMORY, - - /** - * Command from main thread: the app's activity has been started. - */ - APP_CMD_START, - - /** - * Command from main thread: the app's activity has been resumed. - */ - APP_CMD_RESUME, - - /** - * Command from main thread: the app should generate a new saved state - * for itself, to restore from later if needed. - */ - APP_CMD_SAVE_STATE, - - /** - * Command from main thread: the app's activity has been paused. - */ - APP_CMD_PAUSE, - - /** - * Command from main thread: the app's activity has been stopped. - */ - APP_CMD_STOP, - - /** - * Command from main thread: the app's activity is being destroyed, - * and waiting for the app thread to clean up and exit before proceeding. - */ - APP_CMD_DESTROY, -}; - -void android_app_write_cmd(struct android_app *android_app, int8_t cmd); - -/** - * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next - * app command message. - */ -int8_t android_app_read_cmd(struct android_app *android_app); - -/** - * Call with the command returned by android_app_read_cmd() to do the - * initial pre-processing of the given command. You can perform your own - * actions for the command after calling this function. - */ -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * Call with the command returned by android_app_read_cmd() to do the - * final post-processing of the given command. You must have done your own - * actions for the command before calling this function. - */ -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * This is the function that application code must implement, representing - * the main entry to the app. - */ -void android_main(struct android_app* app); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/frontend/drivers/platform_android.c b/frontend/drivers/platform_android.c index 9a5e5073ee..3f44560c25 100644 --- a/frontend/drivers/platform_android.c +++ b/frontend/drivers/platform_android.c @@ -27,10 +27,169 @@ #include "../../general.h" #include +struct android_app *g_android; static pthread_key_t thread_key; -struct android_app *g_android; -struct android_app_userdata *g_android_userdata; +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) { @@ -64,37 +223,92 @@ static void jni_thread_destruct(void *value) pthread_setspecific(thread_key, NULL); } -void android_main(struct android_app *state) +static void android_app_entry(void *data) { char *argv[1]; int argc = 0; - int ret_iterate, ret_poll; - g_android = state; - g_android_userdata = (struct android_app_userdata*)calloc(1, sizeof(*g_android_userdata)); - - state->userData = g_android_userdata; - state->onAppCmd = engine_handle_cmd; - state->onInputEvent = engine_handle_input; - - if (rarch_main(argc, argv, state) != 0) + if (rarch_main(argc, argv, data) != 0) goto end; +#ifndef HAVE_MAIN + while (rarch_main_iterate() != -1); - do{ - ret_poll = 0; - ret_iterate = rarch_main_iterate(); - }while(ret_iterate != -1 && ret_poll != -1); + main_exit(data); +#endif end: - main_exit(state); - - if (g_android_userdata) - free(g_android_userdata); - g_android_userdata = NULL; - 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; @@ -228,8 +442,6 @@ static void frontend_android_get_environment_settings(int *argc, jobject obj = NULL; jstring jstr = NULL; struct android_app* android_app = (struct android_app*)data; - struct android_app_userdata *userdata = - (struct android_app_userdata*)g_android_userdata; if (!android_app) return; @@ -253,14 +465,14 @@ static void frontend_android_get_environment_settings(int *argc, RARCH_LOG("Android OS version (major : %d, minor : %d, rel : %d)\n", major, minor, rel); CALL_OBJ_METHOD(env, obj, android_app->activity->clazz, - userdata->getIntent); + android_app->getIntent); RARCH_LOG("Checking arguments passed from intent ...\n"); /* Config file. */ - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "CONFIGFILE")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { static char config_path[PATH_MAX_LENGTH]; const char *argv = NULL; @@ -278,23 +490,23 @@ static void frontend_android_get_environment_settings(int *argc, } /* Current IME. */ - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "IME")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); - strlcpy(userdata->current_ime, argv, - sizeof(userdata->current_ime)); + strlcpy(android_app->current_ime, argv, + sizeof(android_app->current_ime)); (*env)->ReleaseStringUTFChars(env, jstr, argv); - RARCH_LOG("Current IME: [%s].\n", userdata->current_ime); + RARCH_LOG("Current IME: [%s].\n", android_app->current_ime); } - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "USED")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { const char *argv = (*env)->GetStringUTFChars(env, jstr, 0); bool used = (strcmp(argv, "false") == 0) ? false : true; @@ -304,10 +516,10 @@ static void frontend_android_get_environment_settings(int *argc, } /* LIBRETRO. */ - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "LIBRETRO")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { static char core_path[PATH_MAX_LENGTH]; const char *argv = NULL; @@ -324,10 +536,10 @@ static void frontend_android_get_environment_settings(int *argc, } /* Content. */ - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "ROM")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { static char path[PATH_MAX_LENGTH]; const char *argv = NULL; @@ -348,10 +560,10 @@ static void frontend_android_get_environment_settings(int *argc, } /* Content. */ - CALL_OBJ_METHOD_PARAM(env, jstr, obj, userdata->getStringExtra, + CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra, (*env)->NewStringUTF(env, "DATADIR")); - if (userdata->getStringExtra && jstr) + if (android_app->getStringExtra && jstr) { static char path[PATH_MAX_LENGTH]; const char *argv = NULL; @@ -426,182 +638,73 @@ static void frontend_android_get_environment_settings(int *argc, #endif } -int android_main_poll(void *data); - -static bool android_input_lookup_name_prekitkat(char *buf, - int *vendorId, int *productId, size_t size, int id) +static void frontend_android_deinit(void *data) { - RARCH_LOG("Using old lookup"); - - jclass class; - jmethodID method, getName; - jobject device, name; - const char *str = NULL; - JNIEnv *env = (JNIEnv*)jni_thread_getenv(); - - if (!env) - goto error; - - class = NULL; - FIND_CLASS(env, class, "android/view/InputDevice"); - if (!class) - goto error; - - method = NULL; - GET_STATIC_METHOD_ID(env, method, class, "getDevice", - "(I)Landroid/view/InputDevice;"); - if (!method) - goto error; - - device = NULL; - CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id); - if (!device) - { - RARCH_ERR("Failed to find device for ID: %d\n", id); - goto error; - } - - getName = NULL; - GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;"); - if (!getName) - goto error; - - name = NULL; - CALL_OBJ_METHOD(env, name, device, getName); - if (!name) - { - RARCH_ERR("Failed to find name for device ID: %d\n", id); - goto error; - } - - buf[0] = '\0'; - - str = (*env)->GetStringUTFChars(env, name, 0); - if (str) - strlcpy(buf, str, size); - (*env)->ReleaseStringUTFChars(env, name, str); - - RARCH_LOG("device name: %s\n", buf); - - return true; -error: - return false; -} - -static bool android_input_lookup_name(char *buf, - int *vendorId, int *productId, size_t size, int id) -{ - RARCH_LOG("Using new lookup"); - - jclass class; - jmethodID method, getName, getVendorId, getProductId; - jobject device, name; - const char *str = NULL; - JNIEnv *env = (JNIEnv*)jni_thread_getenv(); - - if (!env) - goto error; - - class = NULL; - FIND_CLASS(env, class, "android/view/InputDevice"); - if (!class) - goto error; - - method = NULL; - GET_STATIC_METHOD_ID(env, method, class, "getDevice", - "(I)Landroid/view/InputDevice;"); - if (!method) - goto error; - - device = NULL; - CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id); - if (!device) - { - RARCH_ERR("Failed to find device for ID: %d\n", id); - goto error; - } - - getName = NULL; - GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;"); - if (!getName) - goto error; - - name = NULL; - CALL_OBJ_METHOD(env, name, device, getName); - if (!name) - { - RARCH_ERR("Failed to find name for device ID: %d\n", id); - goto error; - } - - buf[0] = '\0'; - - str = (*env)->GetStringUTFChars(env, name, 0); - if (str) - strlcpy(buf, str, size); - (*env)->ReleaseStringUTFChars(env, name, str); - - RARCH_LOG("device name: %s\n", buf); - - getVendorId = NULL; - GET_METHOD_ID(env, getVendorId, class, "getVendorId", "()I"); - if (!getVendorId) - goto error; - - CALL_INT_METHOD(env, *vendorId, device, getVendorId); - if (!*vendorId) - { - RARCH_ERR("Failed to find vendor id for device ID: %d\n", id); - goto error; - } - RARCH_LOG("device vendor id: %d\n", *vendorId); - - getProductId = NULL; - GET_METHOD_ID(env, getProductId, class, "getProductId", "()I"); - if (!getProductId) - goto error; - - *productId = 0; - CALL_INT_METHOD(env, *productId, device, getProductId); - if (!*productId) - { - RARCH_ERR("Failed to find product id for device ID: %d\n", id); - goto error; - } - RARCH_LOG("device product id: %d\n", *productId); - - return true; -error: - return false; -} - -static void frontend_android_init(void *data) -{ - int32_t sdk; JNIEnv *env; - jclass class = NULL; - jobject obj = NULL; - struct android_app* android_app = (struct android_app*)data; - struct android_app_userdata *userdata = - (struct android_app_userdata*)g_android_userdata; + struct android_app *android_app = (struct android_app*)data; if (!android_app) return; - if (pthread_key_create(&thread_key, jni_thread_destruct)) - RARCH_ERR("Error initializing pthread_key\n"); + RARCH_LOG("Deinitializing RetroArch ...\n"); + android_app->activityState = APP_CMD_DEAD; - /* These are set only for the native activity, - * and are reset when it ends. */ - ANativeActivity_setWindowFlags(android_app->activity, - AWINDOW_FLAG_KEEP_SCREEN_ON | AWINDOW_FLAG_FULLSCREEN, 0); + 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; + 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_main_poll(NULL) == -1) + if (!android_run_events(android_app)) + { + frontend_android_deinit(android_app); + frontend_android_shutdown(android_app); return; + } } RARCH_LOG("Android Native Window initialized.\n"); @@ -611,21 +714,16 @@ static void frontend_android_init(void *data) return; GET_OBJECT_CLASS(env, class, android_app->activity->clazz); - GET_METHOD_ID(env, userdata->getIntent, class, + 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, - userdata->getIntent); + android_app->getIntent); GET_OBJECT_CLASS(env, class, obj); - GET_METHOD_ID(env, userdata->getStringExtra, class, + GET_METHOD_ID(env, android_app->getStringExtra, class, "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;"); - - frontend_android_get_version_sdk(&sdk); - - if (sdk >= 19) - engine_lookup_name = android_input_lookup_name; - else - engine_lookup_name = android_input_lookup_name_prekitkat; } static int frontend_android_get_rating(void) @@ -664,12 +762,12 @@ static enum frontend_architecture frontend_android_get_architecture(void) const frontend_ctx_driver_t frontend_ctx_android = { frontend_android_get_environment_settings, frontend_android_init, - NULL, /* deinit */ + frontend_android_deinit, NULL, /* exitspawn */ NULL, /* process_args */ NULL, /* exec */ NULL, /* set_fork */ - NULL, /* shutdown */ + frontend_android_shutdown, frontend_android_get_name, frontend_android_get_os, frontend_android_get_rating, diff --git a/frontend/drivers/platform_android.h b/frontend/drivers/platform_android.h index 7cdf3f9429..64e9003bcd 100644 --- a/frontend/drivers/platform_android.h +++ b/frontend/drivers/platform_android.h @@ -19,68 +19,37 @@ #define _PLATFORM_ANDROID_H #include +#include +#include -#include "android_native_app_glue.h" +#include +#include #include #include -#ifndef MAX_AXIS -#define MAX_AXIS 10 -#endif +#include -#ifndef MAX_PADS -#define MAX_PADS 8 -#endif - -#ifndef MAX_TOUCH -#define MAX_TOUCH 16 -#endif - -#ifndef AKEYCODE_ASSIST -#define AKEYCODE_ASSIST 219 -#endif - -#define LAST_KEYCODE AKEYCODE_ASSIST - -typedef struct state_device -{ - int id; - int port; - char name[256]; -} state_device_t; - -struct input_pointer -{ - int16_t x, y; - int16_t full_x, full_y; -}; - -typedef struct -{ - float x; - float y; - float z; -} sensor_t; - -typedef struct android_input_state -{ - int16_t analog_state[MAX_PADS][MAX_AXIS]; - int8_t hat_state[MAX_PADS][2]; - uint8_t pad_state[MAX_PADS][(LAST_KEYCODE + 7) / 8]; - unsigned pads_connected; - state_device_t pad_states[MAX_PADS]; - struct input_pointer pointer[MAX_TOUCH]; - sensor_t accelerometer_state; - unsigned pointer_count; -} android_input_state_t; - -struct android_app_userdata +struct android_app { + ANativeActivity* activity; + ALooper* looper; + AInputQueue* inputQueue; + AInputQueue* pendingInputQueue; + ANativeWindow* window; + ANativeWindow* pendingWindow; + slock_t *mutex; + scond_t *cond; + int activityState; + int msgread; + int msgwrite; + int running; unsigned accelerometer_event_rate; const ASensor* accelerometerSensor; uint64_t sensor_state_mask; + sthread_t *thread; char current_ime[PATH_MAX_LENGTH]; jmethodID getIntent; + jmethodID onRetroArchExit; jmethodID getStringExtra; jmethodID clearPendingIntent; jmethodID hasPendingIntent; @@ -88,9 +57,111 @@ struct android_app_userdata jmethodID getPendingIntentLibretroPath; jmethodID getPendingIntentFullPath; jmethodID getPendingIntentIME; - android_input_state_t thread_state; - ASensorManager *sensorManager; - ASensorEventQueue *sensorEventQueue; +}; + +enum +{ + LOOPER_ID_MAIN = 1, + LOOPER_ID_INPUT, + LOOPER_ID_USER, + LOOPER_ID_INPUT_MSG, +}; + +enum +{ + APP_CMD_INPUT_CHANGED, + /** + * Command from main thread: a new ANativeWindow is ready for use. Upon + * receiving this command, android_app->window will contain the new window + * surface. + */ + APP_CMD_INIT_WINDOW, + + /** + * Command from main thread: the existing ANativeWindow needs to be + * terminated. Upon receiving this command, android_app->window still + * contains the existing window; after calling android_app_exec_cmd + * it will be set to NULL. + */ + APP_CMD_TERM_WINDOW, + + /** + * Command from main thread: the current ANativeWindow has been resized. + * Please redraw with its new size. + */ + APP_CMD_WINDOW_RESIZED, + + /** + * Command from main thread: the system needs that the current ANativeWindow + * be redrawn. You should redraw the window before handing this to + * android_app_exec_cmd() in order to avoid transient drawing glitches. + */ + APP_CMD_WINDOW_REDRAW_NEEDED, + + /** + * Command from main thread: the content area of the window has changed, + * such as from the soft input window being shown or hidden. You can + * find the new content rect in android_app::contentRect. + */ + APP_CMD_CONTENT_RECT_CHANGED, + + /** + * Command from main thread: the app's activity window has gained + * input focus. + */ + APP_CMD_GAINED_FOCUS, + + /** + * Command from main thread: the app's activity window has lost + * input focus. + */ + APP_CMD_LOST_FOCUS, + + /** + * Command from main thread: the current device configuration has changed. + */ + APP_CMD_CONFIG_CHANGED, + + /** + * Command from main thread: the system is running low on memory. + * Try to reduce your memory use. + */ + APP_CMD_LOW_MEMORY, + + /** + * Command from main thread: the app's activity has been started. + */ + APP_CMD_START, + + /** + * Command from main thread: the app's activity has been resumed. + */ + APP_CMD_RESUME, + + /** + * Command from main thread: the app should generate a new saved state + * for itself, to restore from later if needed. + */ + APP_CMD_SAVE_STATE, + + /** + * Command from main thread: the app's activity has been paused. + */ + APP_CMD_PAUSE, + + /** + * Command from main thread: the app's activity has been stopped. + */ + APP_CMD_STOP, + + /** + * Command from main thread: the app's activity is being destroyed, + * and waiting for the app thread to clean up and exit before proceeding. + */ + APP_CMD_DESTROY, + + // Set by thread when it will no longer reply to commands. + APP_CMD_DEAD, }; #define JNI_EXCEPTION(env) \ @@ -156,18 +227,8 @@ struct android_app_userdata var = (*env)->CallIntMethod(env, clazz_obj, methodId); \ JNI_EXCEPTION(env) -bool (*engine_lookup_name)(char *buf, - int *vendorId, int *productId, size_t size, int id); - -JNIEnv *jni_thread_getenv(void); - -void android_app_write_cmd(struct android_app *android_app, int8_t cmd); +extern JNIEnv *jni_thread_getenv(void); extern struct android_app *g_android; -extern struct android_app_userdata *g_android_userdata; - -void android_main(struct android_app *android_app); - -int android_main_poll(void *data); #endif /* _PLATFORM_ANDROID_H */ diff --git a/griffin/griffin.c b/griffin/griffin.c index 465a666d7e..e23cff65dd 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -613,7 +613,6 @@ FRONTEND #elif defined(__QNX__) #include "../frontend/drivers/platform_qnx.c" #elif defined(ANDROID) -#include "../frontend/drivers/android_native_app_glue.c" #include "../frontend/drivers/platform_android.c" #elif defined(__linux__) && !defined(ANDROID) #include "../frontend/drivers/platform_linux.c" diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index a2e48e3d70..d6813df4d6 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -30,8 +30,31 @@ #include "../../general.h" #include "../../driver.h" + +#define MAX_TOUCH 16 +#define MAX_PADS 8 + #define AKEY_EVENT_NO_ACTION 255 +#ifndef AKEYCODE_ASSIST +#define AKEYCODE_ASSIST 219 +#endif + +#define LAST_KEYCODE AKEYCODE_ASSIST + +typedef struct +{ + float x; + float y; + float z; +} sensor_t; + +struct input_pointer +{ + int16_t x, y; + int16_t full_x, full_y; +}; + enum { AXIS_X = 0, @@ -46,18 +69,37 @@ enum AXIS_BRAKE = 23, }; +#define MAX_AXIS 10 + +typedef struct state_device +{ + int id; + int port; + char name[256]; +} state_device_t; typedef struct android_input { - android_input_state_t copy; + unsigned pads_connected; + state_device_t pad_states[MAX_PADS]; + uint8_t pad_state[MAX_PADS][(LAST_KEYCODE + 7) / 8]; + int8_t hat_state[MAX_PADS][2]; + + int16_t analog_state[MAX_PADS][MAX_AXIS]; + sensor_t accelerometer_state; + struct input_pointer pointer[MAX_TOUCH]; + unsigned pointer_count; + ASensorManager *sensorManager; + ASensorEventQueue *sensorEventQueue; const input_device_driver_t *joypad; } android_input_t; static void frontend_android_get_version_sdk(int32_t *sdk); -void (*engine_handle_dpad)(android_input_state_t *state, - AInputEvent*, int, int); +bool (*engine_lookup_name)(char *buf, + int *vendorId, int *productId, size_t size, int id); +void (*engine_handle_dpad)(android_input_t *android, AInputEvent*, int, int); static bool android_input_set_sensor_state(void *data, unsigned port, enum retro_sensor_action action, unsigned event_rate); @@ -68,62 +110,214 @@ static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue; #define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue) -static void engine_handle_dpad_default( - android_input_state_t *state, AInputEvent *event, int port, int source) +static void engine_handle_dpad_default(android_input_t *android, + AInputEvent *event, int port, int source) { size_t motion_pointer = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; float x = AMotionEvent_getX(event, motion_pointer); float y = AMotionEvent_getY(event, motion_pointer); - state->analog_state[port][0] = (int16_t)(x * 32767.0f); - state->analog_state[port][1] = (int16_t)(y * 32767.0f); + android->analog_state[port][0] = (int16_t)(x * 32767.0f); + android->analog_state[port][1] = (int16_t)(y * 32767.0f); } -static void engine_handle_dpad_getaxisvalue( - android_input_state_t *state, +static void engine_handle_dpad_getaxisvalue(android_input_t *android, AInputEvent *event, int port, int source) { size_t motion_pointer = AMotionEvent_getAction(event) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_pointer); - float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_pointer); - float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_pointer); - float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_pointer); - float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_pointer); - float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_pointer); - float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_pointer); - float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_pointer); - float brake = AMotionEvent_getAxisValue(event, AXIS_BRAKE, motion_pointer); - float gas = AMotionEvent_getAxisValue(event, AXIS_GAS, motion_pointer); + float x = AMotionEvent_getAxisValue(event, AXIS_X, motion_pointer); + float y = AMotionEvent_getAxisValue(event, AXIS_Y, motion_pointer); + float z = AMotionEvent_getAxisValue(event, AXIS_Z, motion_pointer); + float rz = AMotionEvent_getAxisValue(event, AXIS_RZ, motion_pointer); + float hatx = AMotionEvent_getAxisValue(event, AXIS_HAT_X, motion_pointer); + float haty = AMotionEvent_getAxisValue(event, AXIS_HAT_Y, motion_pointer); + float ltrig = AMotionEvent_getAxisValue(event, AXIS_LTRIGGER, motion_pointer); + float rtrig = AMotionEvent_getAxisValue(event, AXIS_RTRIGGER, motion_pointer); + float brake = AMotionEvent_getAxisValue(event, AXIS_BRAKE, motion_pointer); + float gas = AMotionEvent_getAxisValue(event, AXIS_GAS, motion_pointer); - state->hat_state[port][0] = (int)hatx; - state->hat_state[port][1] = (int)haty; + android->hat_state[port][0] = (int)hatx; + android->hat_state[port][1] = (int)haty; /* XXX: this could be a loop instead, but do we really want to * loop through every axis? */ - state->analog_state[port][0] = (int16_t)(x * 32767.0f); - state->analog_state[port][1] = (int16_t)(y * 32767.0f); - state->analog_state[port][2] = (int16_t)(z * 32767.0f); - state->analog_state[port][3] = (int16_t)(rz * 32767.0f); - state->analog_state[port][6] = (int16_t)(ltrig * 32767.0f); - state->analog_state[port][7] = (int16_t)(rtrig * 32767.0f); - state->analog_state[port][8] = (int16_t)(brake * 32767.0f); - state->analog_state[port][9] = (int16_t)(gas * 32767.0f); + android->analog_state[port][0] = (int16_t)(x * 32767.0f); + android->analog_state[port][1] = (int16_t)(y * 32767.0f); + android->analog_state[port][2] = (int16_t)(z * 32767.0f); + android->analog_state[port][3] = (int16_t)(rz * 32767.0f); + //android->analog_state[port][4] = (int16_t)(hatx * 32767.0f); + //android->analog_state[port][5] = (int16_t)(haty * 32767.0f); + android->analog_state[port][6] = (int16_t)(ltrig * 32767.0f); + android->analog_state[port][7] = (int16_t)(rtrig * 32767.0f); + android->analog_state[port][8] = (int16_t)(brake * 32767.0f); + android->analog_state[port][9] = (int16_t)(gas * 32767.0f); } -void engine_handle_cmd(struct android_app *android_app, int32_t cmd) +static bool android_input_lookup_name_prekitkat(char *buf, + int *vendorId, int *productId, size_t size, int id) { - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; + RARCH_LOG("Using old lookup"); + + jclass class; + jmethodID method, getName; + jobject device, name; + const char *str = NULL; + JNIEnv *env = (JNIEnv*)jni_thread_getenv(); + + if (!env) + goto error; + + class = NULL; + FIND_CLASS(env, class, "android/view/InputDevice"); + if (!class) + goto error; + + method = NULL; + GET_STATIC_METHOD_ID(env, method, class, "getDevice", + "(I)Landroid/view/InputDevice;"); + if (!method) + goto error; + + device = NULL; + CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id); + if (!device) + { + RARCH_ERR("Failed to find device for ID: %d\n", id); + goto error; + } + + getName = NULL; + GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;"); + if (!getName) + goto error; + + name = NULL; + CALL_OBJ_METHOD(env, name, device, getName); + if (!name) + { + RARCH_ERR("Failed to find name for device ID: %d\n", id); + goto error; + } + + buf[0] = '\0'; + + str = (*env)->GetStringUTFChars(env, name, 0); + if (str) + strlcpy(buf, str, size); + (*env)->ReleaseStringUTFChars(env, name, str); + + RARCH_LOG("device name: %s\n", buf); + + return true; +error: + return false; +} + +static bool android_input_lookup_name(char *buf, + int *vendorId, int *productId, size_t size, int id) +{ + RARCH_LOG("Using new lookup"); + + jclass class; + jmethodID method, getName, getVendorId, getProductId; + jobject device, name; + const char *str = NULL; + JNIEnv *env = (JNIEnv*)jni_thread_getenv(); + + if (!env) + goto error; + + class = NULL; + FIND_CLASS(env, class, "android/view/InputDevice"); + if (!class) + goto error; + + method = NULL; + GET_STATIC_METHOD_ID(env, method, class, "getDevice", + "(I)Landroid/view/InputDevice;"); + if (!method) + goto error; + + device = NULL; + CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id); + if (!device) + { + RARCH_ERR("Failed to find device for ID: %d\n", id); + goto error; + } + + getName = NULL; + GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;"); + if (!getName) + goto error; + + name = NULL; + CALL_OBJ_METHOD(env, name, device, getName); + if (!name) + { + RARCH_ERR("Failed to find name for device ID: %d\n", id); + goto error; + } + + buf[0] = '\0'; + + str = (*env)->GetStringUTFChars(env, name, 0); + if (str) + strlcpy(buf, str, size); + (*env)->ReleaseStringUTFChars(env, name, str); + + RARCH_LOG("device name: %s\n", buf); + + getVendorId = NULL; + GET_METHOD_ID(env, getVendorId, class, "getVendorId", "()I"); + if (!getVendorId) + goto error; + + CALL_INT_METHOD(env, *vendorId, device, getVendorId); + if (!*vendorId) + { + RARCH_ERR("Failed to find vendor id for device ID: %d\n", id); + goto error; + } + RARCH_LOG("device vendor id: %d\n", *vendorId); + + getProductId = NULL; + GET_METHOD_ID(env, getProductId, class, "getProductId", "()I"); + if (!getProductId) + goto error; + + *productId = 0; + CALL_INT_METHOD(env, *productId, device, getProductId); + if (!*productId) + { + RARCH_ERR("Failed to find product id for device ID: %d\n", id); + goto error; + } + RARCH_LOG("device product id: %d\n", *productId); + + return true; +error: + return false; +} + +static void engine_handle_cmd(void) +{ + int8_t cmd; + struct android_app *android_app = (struct android_app*)g_android; runloop_t *runloop = rarch_main_get_ptr(); global_t *global = global_get_ptr(); driver_t *driver = driver_get_ptr(); + if (read(android_app->msgread, &cmd, sizeof(cmd)) != sizeof(cmd)) + cmd = -1; + switch (cmd) { case APP_CMD_INPUT_CHANGED: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); if (android_app->inputQueue) AInputQueue_detachLooper(android_app->inputQueue); @@ -138,40 +332,40 @@ void engine_handle_cmd(struct android_app *android_app, int32_t cmd) NULL); } - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); break; case APP_CMD_INIT_WINDOW: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); if (runloop->is_paused) event_command(EVENT_CMD_REINIT); break; case APP_CMD_RESUME: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); break; case APP_CMD_START: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); break; case APP_CMD_PAUSE: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); if (!global->system.shutdown) { @@ -182,16 +376,16 @@ void engine_handle_cmd(struct android_app *android_app, int32_t cmd) break; case APP_CMD_STOP: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); break; case APP_CMD_CONFIG_CHANGED: break; case APP_CMD_TERM_WINDOW: - pthread_mutex_lock(&android_app->mutex); + slock_lock(android_app->mutex); /* The window is being hidden or closed, clean it up. */ /* terminate display/EGL context here */ @@ -201,31 +395,31 @@ void engine_handle_cmd(struct android_app *android_app, int32_t cmd) #endif android_app->window = NULL; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); + scond_broadcast(android_app->cond); + slock_unlock(android_app->mutex); break; case APP_CMD_GAINED_FOCUS: runloop->is_paused = false; runloop->is_idle = false; - if ((userdata->sensor_state_mask + if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE)) - && userdata->accelerometerSensor == NULL + && android_app->accelerometerSensor == NULL && driver->input_data) android_input_set_sensor_state(driver->input_data, 0, RETRO_SENSOR_ACCELEROMETER_ENABLE, - userdata->accelerometer_event_rate); + android_app->accelerometer_event_rate); break; case APP_CMD_LOST_FOCUS: /* Avoid draining battery while app is not being used. */ - if ((userdata->sensor_state_mask + if ((android_app->sensor_state_mask & (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE)) - && userdata->accelerometerSensor != NULL + && android_app->accelerometerSensor != NULL && driver->input_data) android_input_set_sensor_state(driver->input_data, 0, RETRO_SENSOR_ACCELEROMETER_DISABLE, - userdata->accelerometer_event_rate); + android_app->accelerometer_event_rate); break; case APP_CMD_DESTROY: @@ -236,15 +430,25 @@ void engine_handle_cmd(struct android_app *android_app, int32_t cmd) static void *android_input_init(void) { + int32_t sdk; settings_t *settings = config_get_ptr(); android_input_t *android = (android_input_t*)calloc(1, sizeof(*android)); if (!android) return NULL; - android->copy.pads_connected = 0; + android->pads_connected = 0; android->joypad = input_joypad_init_driver(settings->input.joypad_driver); + frontend_android_get_version_sdk(&sdk); + + RARCH_LOG("sdk version: %d\n", sdk); + + if (sdk >= 19) + engine_lookup_name = android_input_lookup_name; + else + engine_lookup_name = android_input_lookup_name_prekitkat; + return android; } @@ -252,7 +456,7 @@ static int zeus_id = -1; static int zeus_second_id = -1; static INLINE int android_input_poll_event_type_motion( - android_input_state_t *android, AInputEvent *event, + android_input_t *android, AInputEvent *event, int port, int source) { int getaction, action; @@ -262,10 +466,10 @@ static INLINE int android_input_poll_event_type_motion( if (source & ~(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE)) return 1; - getaction = AMotionEvent_getAction(event); - action = getaction & AMOTION_EVENT_ACTION_MASK; + getaction = AMotionEvent_getAction(event); + action = getaction & AMOTION_EVENT_ACTION_MASK; motion_pointer = getaction >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - keyup = ( + keyup = ( action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL || action == AMOTION_EVENT_ACTION_POINTER_UP) || @@ -306,7 +510,7 @@ static INLINE int android_input_poll_event_type_motion( } static INLINE void android_input_poll_event_type_key( - android_input_state_t *android, struct android_app *android_app, + android_input_t *android, struct android_app *android_app, AInputEvent *event, int port, int keycode, int source, int type_event, int *handled) { @@ -327,7 +531,7 @@ static INLINE void android_input_poll_event_type_key( *handled = 0; } -static int android_input_get_id_port(android_input_state_t *android, int id, +static int android_input_get_id_port(android_input_t *android, int id, int source) { unsigned i; @@ -342,8 +546,10 @@ static int android_input_get_id_port(android_input_state_t *android, int id, return -1; } + + /* Returns the index inside android->pad_state */ -static int android_input_get_id_index_from_name(android_input_state_t *android, +static int android_input_get_id_index_from_name(android_input_t *android, const char *name) { int i; @@ -356,8 +562,8 @@ static int android_input_get_id_index_from_name(android_input_state_t *android, return -1; } -static void handle_hotplug(android_input_state_t *android, - struct android_app_userdata *userdata, unsigned *port, unsigned id, +static void handle_hotplug(android_input_t *android, + struct android_app *android_app, unsigned *port, unsigned id, int source) { char device_name[256], name_buf[256]; @@ -423,11 +629,15 @@ static void handle_hotplug(android_input_state_t *android, } else if (strstr(device_name, "Sun4i-keypad")) strlcpy(name_buf, "iDroid x360", sizeof(name_buf)); + else if (strstr(device_name, "mtk-kpd")) + strlcpy(name_buf, "MUCH iReadyGo i5", sizeof(name_buf)); else if (strstr(device_name, "360 Wireless")) strlcpy(name_buf, "XBox 360 Wireless", sizeof(name_buf)); else if (strstr(device_name, "Microsoft")) { - if (strstr(device_name, "SideWinder")) + if (strstr(device_name, "Dual Strike")) + strlcpy(device_name, "SideWinder Dual Strike", sizeof(device_name)); + else if (strstr(device_name, "SideWinder")) strlcpy(name_buf, "SideWinder Classic", sizeof(name_buf)); else if (strstr(device_name, "X-Box 360") || strstr(device_name, "X-Box")) @@ -484,6 +694,11 @@ static void handle_hotplug(android_input_state_t *android, strlcpy(name_buf, "JXD S7800B", sizeof(name_buf)); else if (strstr(device_name, "2Axes 11Keys Game Pad")) strlcpy(name_buf, "Tomee NES USB", sizeof(name_buf)); + else if ( + strstr(device_name, "rk29-keypad") || + strstr(device_name, "GAMEMID") + ) + strlcpy(name_buf, "GameMID", sizeof(name_buf)); else if (strstr(device_name, "USB Gamepad")) strlcpy(name_buf, "Defender Game Racer Classic", sizeof(name_buf)); else if (strstr(device_name, "NVIDIA Controller")) @@ -498,12 +713,12 @@ static void handle_hotplug(android_input_state_t *android, else if (device_name[0] != '\0') strlcpy(name_buf, device_name, sizeof(name_buf)); - if (strstr(userdata->current_ime, "net.obsidianx.android.mogaime")) - strlcpy(name_buf, userdata->current_ime, sizeof(name_buf)); - else if (strstr(userdata->current_ime, "com.ccpcreations.android.WiiUseAndroid")) - strlcpy(name_buf, userdata->current_ime, sizeof(name_buf)); - else if (strstr(userdata->current_ime, "com.hexad.bluezime")) - strlcpy(name_buf, userdata->current_ime, sizeof(name_buf)); + if (strstr(android_app->current_ime, "net.obsidianx.android.mogaime")) + strlcpy(name_buf, android_app->current_ime, sizeof(name_buf)); + else if (strstr(android_app->current_ime, "com.ccpcreations.android.WiiUseAndroid")) + strlcpy(name_buf, android_app->current_ime, sizeof(name_buf)); + else if (strstr(android_app->current_ime, "com.hexad.bluezime")) + strlcpy(name_buf, android_app->current_ime, sizeof(name_buf)); if (source == AINPUT_SOURCE_KEYBOARD && strcmp(name_buf, "Xperia Play")) strlcpy(name_buf, "RetroKeyboard", sizeof(name_buf)); @@ -514,11 +729,11 @@ static void handle_hotplug(android_input_state_t *android, name_buf, sizeof(settings->input.device_names[*port])); RARCH_LOG("Port %d: %s.\n", *port, name_buf); - strlcpy(params.name, name_buf, sizeof(params.name)); params.idx = *port; + strlcpy(params.name, name_buf, sizeof(params.name)); params.vid = vendorId; params.pid = productId; - strlcpy(params.driver, "android", sizeof(params.driver)); + strlcpy(params.driver, android_joypad.ident, sizeof(params.driver)); input_config_autoconfigure_joypad(¶ms); } @@ -531,7 +746,7 @@ static void handle_hotplug(android_input_state_t *android, android->pads_connected++; } -static int android_input_get_id(AInputEvent *event) +static int android_input_get_id(android_input_t *android, AInputEvent *event) { int id = AInputEvent_getDeviceId(event); @@ -542,124 +757,110 @@ static int android_input_get_id(AInputEvent *event) return id; } -static int32_t engine_handle_input(struct android_app *android_app, AInputEvent *event) +static void android_input_handle_input(void *data) { - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; - android_input_state_t *android = &userdata->thread_state; + AInputEvent *event = NULL; + android_input_t *android = (android_input_t*)data; + struct android_app *android_app = (struct android_app*)g_android; /* Read all pending events. */ - int32_t handled = 1; - int predispatched = AInputQueue_preDispatchEvent(android_app->inputQueue, event); - int source = AInputEvent_getSource(event); - int type_event = AInputEvent_getType(event); - int id = android_input_get_id(event); - int port = android_input_get_id_port(android, id, source); - - if (port < 0) - handle_hotplug(android, userdata, - &android->pads_connected, id, source); - - switch (type_event) + while (AInputQueue_hasEvents(android_app->inputQueue)) { - case AINPUT_EVENT_TYPE_MOTION: - if (android_input_poll_event_type_motion(android, event, - port, source)) - { - engine_handle_dpad(android, event, port, source); - handled = 0; - } - break; - case AINPUT_EVENT_TYPE_KEY: - { - int keycode = AKeyEvent_getKeyCode(event); - android_input_poll_event_type_key(android, android_app, - event, port, keycode, source, type_event, &handled); - handled = 0; - } - break; - } - - if (!predispatched) - AInputQueue_finishEvent(android_app->inputQueue, event, - handled); - - return handled; -} - -void android_input_handle_user(android_input_state_t *state) -{ - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; - - if ((userdata->sensor_state_mask & (1ULL << - RETRO_SENSOR_ACCELEROMETER_ENABLE)) - && userdata->accelerometerSensor) - { - ASensorEvent event; - while (ASensorEventQueue_getEvents(userdata->sensorEventQueue, &event, 1) > 0) + while (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0) { - state->accelerometer_state.x = event.acceleration.x; - state->accelerometer_state.y = event.acceleration.y; - state->accelerometer_state.z = event.acceleration.z; + int32_t handled = 1; + int predispatched = AInputQueue_preDispatchEvent(android_app->inputQueue, event); + int source = AInputEvent_getSource(event); + int type_event = AInputEvent_getType(event); + int id = android_input_get_id(android, event); + int port = android_input_get_id_port(android, id, source); + + if (port < 0) + handle_hotplug(android, android_app, + &android->pads_connected, id, source); + + switch (type_event) + { + case AINPUT_EVENT_TYPE_MOTION: + if (android_input_poll_event_type_motion(android, event, + port, source)) + engine_handle_dpad(android, event, port, source); + break; + case AINPUT_EVENT_TYPE_KEY: + { + int keycode = AKeyEvent_getKeyCode(event); + android_input_poll_event_type_key(android, android_app, + event, port, keycode, source, type_event, &handled); + } + break; + } + + if (!predispatched) + AInputQueue_finishEvent(android_app->inputQueue, event, + handled); } } } -int android_main_poll(void *data) +static void android_input_handle_user(void *data) { - global_t *global = global_get_ptr(); - int ident, events; - AInputEvent *event; - struct android_poll_source *source; - bool copy_state = false; android_input_t *android = (android_input_t*)data; struct android_app *android_app = (struct android_app*)g_android; - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; - /* Handle all events. If our activity is in pause state, - * block until we're unpaused. */ + if ((android_app->sensor_state_mask & (1ULL << + RETRO_SENSOR_ACCELEROMETER_ENABLE)) + && android_app->accelerometerSensor) + { + ASensorEvent event; + while (ASensorEventQueue_getEvents(android->sensorEventQueue, &event, 1) > 0) + { + android->accelerometer_state.x = event.acceleration.x; + android->accelerometer_state.y = event.acceleration.y; + android->accelerometer_state.z = event.acceleration.z; + } + } +} + +/* Handle all events. If our activity is in pause state, + * block until we're unpaused. + */ +static void android_input_poll(void *data) +{ + int ident; + while ((ident = - ALooper_pollAll( - input_driver_key_pressed(RARCH_PAUSE_TOGGLE) ? -1 : 0, - NULL, &events, (void**)&source)) >= 0) + ALooper_pollAll((input_driver_key_pressed(RARCH_PAUSE_TOGGLE)) + ? -1 : 0, + NULL, NULL, NULL)) >= 0) { switch (ident) { case LOOPER_ID_INPUT: - while (AInputQueue_hasEvents(android_app->inputQueue)) - { - if (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0) - { - engine_handle_input(android_app, event); - copy_state = true; - } - } + android_input_handle_input(data); break; case LOOPER_ID_USER: - android_input_handle_user(&userdata->thread_state); - copy_state = true; + android_input_handle_user(data); break; case LOOPER_ID_MAIN: - { - int32_t cmd = android_app_read_cmd(android_app); - engine_handle_cmd(android_app, cmd); - } + engine_handle_cmd(); break; } } - - /* Check if we are exiting. */ - if (global && global->system.shutdown) - return -1; - - if (copy_state && android) - memcpy(&android->copy, &userdata->thread_state, sizeof(android->copy)); - - return 0; } -static void android_input_poll(void *data) +bool android_run_events(void *data) { - android_main_poll(data); + global_t *global = global_get_ptr(); + int id = ALooper_pollOnce(-1, NULL, NULL, NULL); + + if (id == LOOPER_ID_MAIN) + engine_handle_cmd(); + + /* Check if we are exiting. */ + if (global->system.shutdown) + return false; + + return true; } static int16_t android_input_state(void *data, @@ -679,30 +880,30 @@ static int16_t android_input_state(void *data, switch (id) { case RETRO_DEVICE_ID_POINTER_X: - return android->copy.pointer[idx].x; + return android->pointer[idx].x; case RETRO_DEVICE_ID_POINTER_Y: - return android->copy.pointer[idx].y; + return android->pointer[idx].y; case RETRO_DEVICE_ID_POINTER_PRESSED: - return (idx < android->copy.pointer_count) && - (android->copy.pointer[idx].x != -0x8000) && - (android->copy.pointer[idx].y != -0x8000); + return (idx < android->pointer_count) && + (android->pointer[idx].x != -0x8000) && + (android->pointer[idx].y != -0x8000); case RARCH_DEVICE_ID_POINTER_BACK: - return BIT_GET(android->copy.pad_state[0], AKEYCODE_BACK); + return BIT_GET(android->pad_state[0], AKEYCODE_BACK); } break; case RARCH_DEVICE_POINTER_SCREEN: switch (id) { case RETRO_DEVICE_ID_POINTER_X: - return android->copy.pointer[idx].full_x; + return android->pointer[idx].full_x; case RETRO_DEVICE_ID_POINTER_Y: - return android->copy.pointer[idx].full_y; + return android->pointer[idx].full_y; case RETRO_DEVICE_ID_POINTER_PRESSED: - return (idx < android->copy.pointer_count) && - (android->copy.pointer[idx].full_x != -0x8000) && - (android->copy.pointer[idx].full_y != -0x8000); + return (idx < android->pointer_count) && + (android->pointer[idx].full_x != -0x8000) && + (android->pointer[idx].full_y != -0x8000); case RARCH_DEVICE_ID_POINTER_BACK: - return BIT_GET(android->copy.pad_state[0], AKEYCODE_BACK); + return BIT_GET(android->pad_state[0], AKEYCODE_BACK); } break; } @@ -727,11 +928,13 @@ static bool android_input_key_pressed(void *data, int key) static void android_input_free_input(void *data) { - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; + android_input_t *android = (android_input_t*)data; + if (!android) + return; - if (userdata->sensorManager) - ASensorManager_destroyEventQueue(userdata->sensorManager, - userdata->sensorEventQueue); + if (android->sensorManager) + ASensorManager_destroyEventQueue(android->sensorManager, + android->sensorEventQueue); free(data); } @@ -748,15 +951,15 @@ static uint64_t android_input_get_capabilities(void *data) static void android_input_enable_sensor_manager(void *data) { + android_input_t *android = (android_input_t*)data; struct android_app *android_app = (struct android_app*)g_android; - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; - userdata->sensorManager = ASensorManager_getInstance(); - userdata->accelerometerSensor = - ASensorManager_getDefaultSensor(userdata->sensorManager, + android->sensorManager = ASensorManager_getInstance(); + android_app->accelerometerSensor = + ASensorManager_getDefaultSensor(android->sensorManager, ASENSOR_TYPE_ACCELEROMETER); - userdata->sensorEventQueue = - ASensorManager_createEventQueue(userdata->sensorManager, + android->sensorEventQueue = + ASensorManager_createEventQueue(android->sensorManager, android_app->looper, LOOPER_ID_USER, NULL, NULL); } @@ -764,7 +967,7 @@ static bool android_input_set_sensor_state(void *data, unsigned port, enum retro_sensor_action action, unsigned event_rate) { android_input_t *android = (android_input_t*)data; - struct android_app_userdata *userdata = (struct android_app_userdata*)g_android_userdata; + struct android_app *android_app = (struct android_app*)g_android; if (event_rate == 0) event_rate = 60; @@ -772,33 +975,33 @@ static bool android_input_set_sensor_state(void *data, unsigned port, switch (action) { case RETRO_SENSOR_ACCELEROMETER_ENABLE: - if (!userdata->accelerometerSensor) + if (!android_app->accelerometerSensor) android_input_enable_sensor_manager(android); - if (userdata->accelerometerSensor) - ASensorEventQueue_enableSensor(userdata->sensorEventQueue, - userdata->accelerometerSensor); + if (android_app->accelerometerSensor) + ASensorEventQueue_enableSensor(android->sensorEventQueue, + android_app->accelerometerSensor); // events per second (in us). - if (userdata->accelerometerSensor) - ASensorEventQueue_setEventRate(userdata->sensorEventQueue, - userdata->accelerometerSensor, (1000L / event_rate) + if (android_app->accelerometerSensor) + ASensorEventQueue_setEventRate(android->sensorEventQueue, + android_app->accelerometerSensor, (1000L / event_rate) * 1000); - userdata->sensor_state_mask &= ~(1ULL << RETRO_SENSOR_ACCELEROMETER_DISABLE); - userdata->sensor_state_mask |= (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE); + android_app->sensor_state_mask &= ~(1ULL << RETRO_SENSOR_ACCELEROMETER_DISABLE); + android_app->sensor_state_mask |= (1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE); return true; case RETRO_SENSOR_ACCELEROMETER_DISABLE: - if (userdata->accelerometerSensor) - ASensorEventQueue_disableSensor(userdata->sensorEventQueue, - userdata->accelerometerSensor); + if (android_app->accelerometerSensor) + ASensorEventQueue_disableSensor(android->sensorEventQueue, + android_app->accelerometerSensor); - userdata->sensor_state_mask &= ~(1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE); - userdata->sensor_state_mask |= (1ULL << RETRO_SENSOR_ACCELEROMETER_DISABLE); + android_app->sensor_state_mask &= ~(1ULL << RETRO_SENSOR_ACCELEROMETER_ENABLE); + android_app->sensor_state_mask |= (1ULL << RETRO_SENSOR_ACCELEROMETER_DISABLE); return true; default: - break; + return false; } return false; @@ -812,11 +1015,11 @@ static float android_input_get_sensor_input(void *data, switch (id) { case RETRO_SENSOR_ACCELEROMETER_X: - return android->copy.accelerometer_state.x; + return android->accelerometer_state.x; case RETRO_SENSOR_ACCELEROMETER_Y: - return android->copy.accelerometer_state.y; + return android->accelerometer_state.y; case RETRO_SENSOR_ACCELEROMETER_Z: - return android->copy.accelerometer_state.z; + return android->accelerometer_state.z; } return 0; diff --git a/input/drivers_joypad/android_joypad.c b/input/drivers_joypad/android_joypad.c index d8f93e29af..bc28266b2f 100644 --- a/input/drivers_joypad/android_joypad.c +++ b/input/drivers_joypad/android_joypad.c @@ -67,7 +67,7 @@ static bool android_joypad_button(unsigned port, uint16_t joykey) if (!android || port >= MAX_PADS) return false; - buf = android->copy.pad_state[port]; + buf = android->pad_state[port]; if (GET_HAT_DIR(joykey)) { @@ -78,13 +78,13 @@ static bool android_joypad_button(unsigned port, uint16_t joykey) switch (GET_HAT_DIR(joykey)) { case HAT_LEFT_MASK: - return android->copy.hat_state[port][0] == -1; + return android->hat_state[port][0] == -1; case HAT_RIGHT_MASK: - return android->copy.hat_state[port][0] == 1; + return android->hat_state[port][0] == 1; case HAT_UP_MASK: - return android->copy.hat_state[port][1] == -1; + return android->hat_state[port][1] == -1; case HAT_DOWN_MASK: - return android->copy.hat_state[port][1] == 1; + return android->hat_state[port][1] == 1; default: return false; } @@ -116,7 +116,7 @@ static int16_t android_joypad_axis(unsigned port, uint32_t joyaxis) is_pos = true; } - val = android->copy.analog_state[port][axis]; + val = android->analog_state[port][axis]; if (is_neg && val > 0) val = 0; @@ -134,7 +134,7 @@ static bool android_joypad_query_pad(unsigned pad) { driver_t *driver = driver_get_ptr(); android_input_t *android = (android_input_t*)driver->input_data; - return (pad < MAX_USERS && pad < android->copy.pads_connected); + return (pad < MAX_USERS && pad < android->pads_connected); }