(Android) Reimplement native glue code

This commit is contained in:
twinaphex 2012-11-01 05:48:20 +01:00
parent 01399a2295
commit 3837a503b7
9 changed files with 398 additions and 487 deletions

View file

@ -52,8 +52,6 @@ LOCAL_SRC_FILES = $(RARCH_PATH)/retroarch.c \
$(RARCH_PATH)/gfx/state_tracker.c \
$(RARCH_PATH)/input/null.c \
input_android.c \
android_native_app_glue.c \
$(RARCH_PATH)/screenshot.c \
$(RARCH_PATH)/conf/config_file.c \
$(RARCH_PATH)/autosave.c \
$(RARCH_PATH)/thread.c \

View file

@ -1,16 +0,0 @@
#ifndef _ANDROID_GENERAL_H
#define _ANDROID_GENERAL_H
#include <android_native_app_glue.h>
#include "../../../boolean.h"
struct droid
{
struct android_app* app;
bool init_quit;
bool window_inited;
};
extern struct droid g_android;
#endif

View file

@ -0,0 +1,32 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2012 - Hans-Kristian Arntzen
* Copyright (C) 2011-2012 - 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _ANDROID_GENERAL_H
#define _ANDROID_GENERAL_H
#include "android_glue.h"
#include "../../../boolean.h"
struct droid
{
struct android_app* app;
bool init_quit;
bool window_inited;
};
extern struct droid g_android;
#endif

View file

@ -1,22 +1,5 @@
/*
* 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
#ifndef _ANDROID_GLUE_H
#define _ANDROID_GLUE_H
#include <poll.h>
#include <pthread.h>
@ -97,15 +80,6 @@ extern "C" {
* Java objects.
*/
struct android_app {
// 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;
@ -283,26 +257,6 @@ extern "C" {
APP_CMD_DESTROY,
};
/**
* 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);
/**
* Dummy function you can call to ensure glue code isn't stripped.
*/
@ -314,11 +268,10 @@ extern "C" {
*/
extern void android_main(struct android_app* app);
extern void process_input(void);
extern void process_cmd(void);
extern void engine_handle_cmd(struct android_app* android_app, int32_t cmd);
#ifdef __cplusplus
}
#endif
#endif /* _ANDROID_NATIVE_APP_GLUE_H */
#endif

View file

@ -1,401 +0,0 @@
/*
* 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.
*
*/
#include <jni.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include "android-general.h"
#include "android_native_app_glue.h"
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:
break;
}
return cmd;
}
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);
/*
LOGV("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",
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:
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)
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:
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:
pthread_cond_broadcast(&android_app->cond);
break;
case APP_CMD_RESUME:
case APP_CMD_START:
case APP_CMD_PAUSE:
case APP_CMD_STOP:
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:
AConfiguration_fromAssetManager(android_app->config,
android_app->activity->assetManager);
print_cur_config(android_app);
break;
case APP_CMD_DESTROY:
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:
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:
break;
case APP_CMD_RESUME:
break;
}
}
void app_dummy()
{
}
static void android_app_destroy(struct android_app* 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.
}
void process_input(void)
{
struct android_app* app = g_android.app;
AInputEvent* event = NULL;
if (AInputQueue_getEvent(app->inputQueue, &event) >= 0)
{
if (AInputQueue_preDispatchEvent(app->inputQueue, event))
return;
int32_t handled = 0;
if (app->onInputEvent != NULL)
handled = app->onInputEvent(app, event);
AInputQueue_finishEvent(app->inputQueue, event, handled);
}
}
void process_cmd(void)
{
struct android_app* app = g_android.app;
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)
{
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 = LOOPER_ID_MAIN;
android_app->inputPollSource = LOOPER_ID_INPUT;
ALooper* looper = 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)
{
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
memset(android_app, 0, sizeof(struct android_app));
android_app->activity = activity;
pthread_mutex_init(&android_app->mutex, NULL);
pthread_cond_init(&android_app->cond, NULL);
int msgpipe[2];
if (pipe(msgpipe))
return 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;
}
static void android_app_write_cmd(struct android_app* android_app, int8_t cmd)
{
write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd);
}
static void android_app_set_input(struct android_app* android_app,
AInputQueue* inputQueue)
{
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(struct android_app* android_app, ANativeWindow* window)
{
pthread_mutex_lock(&android_app->mutex);
if (android_app->pendingWindow != NULL)
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
android_app->pendingWindow = window;
if (window != NULL)
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)
{
android_app_free((struct android_app*)activity->instance);
}
static void onStart(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
}
static void onResume(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
}
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
{
return NULL;
}
static void onPause(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
}
static void onStop(ANativeActivity* 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;
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)
{
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)
{
android_app_set_window((struct android_app*)activity->instance, window);
}
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
{
android_app_set_window((struct android_app*)activity->instance, NULL);
}
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
{
android_app_set_input((struct android_app*)activity->instance, queue);
}
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
{
android_app_set_input((struct android_app*)activity->instance, NULL);
}
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
size_t savedStateSize)
{
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
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);
}

View file

@ -15,7 +15,8 @@
*/
#include <android/keycodes.h>
#include "android-general.h"
#include <unistd.h>
#include "android_general.h"
#include "../../../benchmark.h"
#include "../../../general.h"
#include "../../../driver.h"
@ -278,7 +279,6 @@ static void setup_state_ids(void)
static void *android_input_init(void)
{
g_android.app->onInputEvent = engine_handle_input;
pads_connected = 0;
@ -321,15 +321,35 @@ static void android_input_poll(void *data)
// Read all pending events.
int event;
struct android_app* android_app = g_android.app;
int id = ALooper_pollOnce(0, NULL, &event, NULL);
// Process this event.
if(event)
{
if(id == LOOPER_ID_INPUT)
process_input();
{
AInputEvent* event = NULL;
if (AInputQueue_getEvent(android_app->inputQueue, &event) >= 0)
{
if (AInputQueue_preDispatchEvent(android_app->inputQueue, event))
return;
int32_t handled = engine_handle_input(android_app, event);
AInputQueue_finishEvent(android_app->inputQueue, event, handled);
}
}
else
process_cmd();
{
int8_t cmd;
if (!read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
cmd = -1;
engine_handle_cmd(android_app, cmd);
}
}
}

View file

@ -17,10 +17,18 @@
#include <stdio.h>
#include <jni.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/resource.h>
#include "android-general.h"
#include "android_general.h"
#include "../../../general.h"
static inline void android_app_write_cmd(struct android_app* android_app, int8_t cmd)
{
write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd);
}
JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt)
{
return JNI_VERSION_1_2;
@ -28,13 +36,55 @@ JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt)
JNIEXPORT void JNICALL JNI_OnUnLoad( JavaVM *vm, void *pvt) { }
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);
/*
LOGV("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",
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));
*/
}
/**
* Process the next main command.
*/
static void engine_handle_cmd(struct android_app* app, int32_t cmd)
void engine_handle_cmd(struct android_app* android_app, int32_t cmd)
{
switch (cmd)
{
case APP_CMD_INPUT_CHANGED:
RARCH_LOG("engine_handle_cmd: 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)
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_SAVE_STATE:
RARCH_LOG("engine_handle_cmd: APP_CMD_SAVE_STATE.\n");
// The system has asked us to save our current state. Do so.
@ -42,25 +92,52 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
case APP_CMD_INIT_WINDOW:
RARCH_LOG("engine_handle_cmd: APP_CMD_INIT_WINDOW.\n");
// The window is being shown, get it ready.
if (g_android.app->window != NULL)
pthread_mutex_lock(&android_app->mutex);
android_app->window = android_app->pendingWindow;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
if (android_app->window != NULL)
g_android.window_inited = true;
break;
case APP_CMD_START:
RARCH_LOG("engine_handle_cmd: APP_CMD_START.\n");
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_RESUME:
RARCH_LOG("engine_handle_cmd: APP_CMD_RESUME.\n");
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_STOP:
RARCH_LOG("engine_handle_cmd: APP_CMD_STOP.\n");
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_PAUSE:
RARCH_LOG("engine_handle_cmd: APP_CMD_PAUSE.\n");
pthread_mutex_lock(&android_app->mutex);
android_app->activityState = cmd;
pthread_cond_broadcast(&android_app->cond);
pthread_mutex_unlock(&android_app->mutex);
g_android.init_quit = true;
break;
case APP_CMD_TERM_WINDOW:
RARCH_LOG("engine_handle_cmd: APP_CMD_TERM_WINDOW.\n");
// The window is being hidden or closed, clean it up.
pthread_cond_broadcast(&android_app->cond);
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_GAINED_FOCUS:
RARCH_LOG("engine_handle_cmd: APP_CMD_GAINED_FOCUS.\n");
@ -68,9 +145,21 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
break;
case APP_CMD_LOST_FOCUS:
RARCH_LOG("engine_handle_cmd: APP_CMD_LOST_FOCUS.\n");
if (!g_android.window_inited)
{
}
/*
if (!g_android.window_inited)
{
}
*/
break;
case APP_CMD_CONFIG_CHANGED:
RARCH_LOG("engine_handle_cmd: 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("engine_handle_cmd: APP_CMD_DESTROY.\n");
android_app->destroyRequested = 1;
break;
}
}
@ -119,6 +208,8 @@ void android_main(struct android_app* state)
g_android.app = state;
struct android_app* android_app = g_android.app;
char rom_path[512];
char libretro_path[512];
@ -133,8 +224,6 @@ void android_main(struct android_app* state)
/* ugly hack for now - hardcode libretro path to 'allowed' dir */
snprintf(libretro_path, sizeof(libretro_path), "/data/data/com.retroarch/lib/libretro.so");
g_android.app->onAppCmd = engine_handle_cmd;
int argc = 0;
char *argv[MAX_ARGS] = {NULL};
@ -156,10 +245,17 @@ void android_main(struct android_app* state)
{
// Process this event.
if (id)
process_cmd();
{
int8_t cmd;
if (!read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd))
cmd = -1;
engine_handle_cmd(android_app, cmd);
}
// Check if we are exiting.
if (g_android.app->destroyRequested != 0)
if (android_app->destroyRequested != 0)
return;
}
}
@ -167,5 +263,234 @@ void android_main(struct android_app* state)
RARCH_LOG("Starting RetroArch...\n");
rarch_main(argc, argv);
exit(0);
}
void app_dummy()
{
}
static void* android_app_entry(void* param)
{
struct android_app* android_app = (struct android_app*)param;
/* Init */
android_app->config = AConfiguration_new();
AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
print_cur_config(android_app);
android_app->cmdPollSource = LOOPER_ID_MAIN;
android_app->inputPollSource = LOOPER_ID_INPUT;
ALooper* looper = 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);
/* Main function */
android_main(android_app);
/* Destroy */
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.
return NULL;
}
// --------------------------------------------------------------------
// Native activity interaction (called from main thread)
// --------------------------------------------------------------------
static struct android_app* android_app_create(ANativeActivity* activity,
void* savedState, size_t savedStateSize)
{
struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
memset(android_app, 0, sizeof(struct android_app));
android_app->activity = activity;
pthread_mutex_init(&android_app->mutex, NULL);
pthread_cond_init(&android_app->cond, NULL);
int msgpipe[2];
if (pipe(msgpipe))
return 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;
}
static void android_app_set_input(struct android_app* android_app,
AInputQueue* inputQueue)
{
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(struct android_app* android_app, ANativeWindow* window)
{
pthread_mutex_lock(&android_app->mutex);
if (android_app->pendingWindow != NULL)
android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
android_app->pendingWindow = window;
if (window != NULL)
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)
{
android_app_free((struct android_app*)activity->instance);
}
static void onStart(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
}
static void onResume(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
}
static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen)
{
return NULL;
}
static void onPause(ANativeActivity* activity)
{
android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
}
static void onStop(ANativeActivity* 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;
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)
{
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)
{
android_app_set_window((struct android_app*)activity->instance, window);
}
static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window)
{
android_app_set_window((struct android_app*)activity->instance, NULL);
}
static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
{
android_app_set_input((struct android_app*)activity->instance, queue);
}
static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue)
{
android_app_set_input((struct android_app*)activity->instance, NULL);
}
void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState,
size_t savedStateSize)
{
activity->callbacks->onDestroy = onDestroy;
activity->callbacks->onStart = onStart;
activity->callbacks->onResume = onResume;
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);
}

View file

@ -42,7 +42,7 @@
#endif
#ifdef ANDROID
#include "android/native/jni/android-general.h"
#include "android/native/jni/android_general.h"
#endif
#if defined(XENON) || defined(__CELLOS_LV2__)

View file

@ -21,7 +21,7 @@
#include <EGL/egl.h> /* Requires NDK r5 or newer */
#include <GLES/gl.h>
#include "../../android/native/jni/android-general.h"
#include "../../android/native/jni/android_general.h"
#include <stdint.h>