Files
minecraft-pe-0.6.1/src/main_android.cpp

204 lines
6.3 KiB
C++
Executable File

#include "App.h"
#include "AppPlatform_android.h"
#include <android_native_app_glue.h>
// Horrible, I know. / A
#ifndef MAIN_CLASS
#include "main.cpp"
#endif
#include <pthread.h>
// References for JNI
static pthread_mutex_t g_activityMutex = PTHREAD_MUTEX_INITIALIZER;
static jobject g_pActivity = 0;
static AppPlatform_android appPlatform;
static void setupExternalPath(struct android_app* state, MAIN_CLASS* app)
{
LOGI("setupExternalPath");
JNIEnv* env = state->activity->env;
state->activity->vm->AttachCurrentThread(&env, NULL);
if (env)
{
LOGI("Environment exists");
}
jclass clazz = env->FindClass("android/os/Environment");
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
jobject file = env->CallStaticObjectMethod(clazz, method);
jclass fileClass = env->GetObjectClass(file);
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
jobject pathString = env->CallObjectMethod(file, fileMethod);
const char* str = env->GetStringUTFChars((jstring) pathString, NULL);
app->externalStoragePath = str;
app->externalCacheStoragePath = str;
LOGI("%s", str);
// ensure the process working directory is set to a writable location
// on Android the default cwd may be '/' which isn't writable. By chdir'ing
// to the external storage path we make relative fopen calls (e.g. "options.txt")
// succeed and persist across launches, fixing the "options never save" bug.
if (chdir(str) != 0) {
LOGI("chdir to %s failed: %s", str, strerror(errno));
}
env->ReleaseStringUTFChars((jstring)pathString, str);
// We're done, detach!
state->activity->vm->DetachCurrentThread();
}
extern "C" {
JNIEXPORT jint JNICALL
JNI_OnLoad( JavaVM * vm, void * reserved )
{
pthread_mutex_init(&g_activityMutex, 0);
pthread_mutex_lock(&g_activityMutex);
LOGI("Entering OnLoad %d\n", pthread_self());
return appPlatform.init(vm);
}
// Register/save a reference to the java main activity instance
JNIEXPORT void JNICALL
Java_com_mojang_minecraftpe_MainActivity_nativeRegisterThis(JNIEnv* env, jobject clazz) {
LOGI("@RegisterThis %d\n", pthread_self());
g_pActivity = (jobject)env->NewGlobalRef( clazz );
pthread_mutex_unlock(&g_activityMutex);
}
// Unregister/delete the reference to the java main activity instance
JNIEXPORT void JNICALL
Java_com_mojang_minecraftpe_MainActivity_nativeUnregisterThis(JNIEnv* env, jobject clazz) {
LOGI("@UnregisterThis %d\n", pthread_self());
env->DeleteGlobalRef( g_pActivity );
g_pActivity = 0;
pthread_mutex_destroy(&g_activityMutex);
}
JNIEXPORT void JNICALL
Java_com_mojang_minecraftpe_MainActivity_nativeStopThis(JNIEnv* env, jobject clazz) {
LOGI("Lost Focus!");
}
}
static void internal_process_input(struct android_app* app, struct android_poll_source* source) {
AInputEvent* event = NULL;
if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
LOGV("New input event: type=%d\n", AInputEvent_getType(event));
bool isBackButtonDown = AKeyEvent_getKeyCode(event) == AKEYCODE_BACK && AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN;
if(!(appPlatform.isKeyboardVisible() && isBackButtonDown)) {
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);
} else {
LOGE("Failure reading next input event: %s\n", strerror(errno));
}
}
void
android_main( struct android_app* state )
{
struct ENGINE engine;
// Make sure glue isn't stripped.
app_dummy();
memset( (void*)&engine, 0, sizeof(engine) );
state->userData = (void*)&engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
state->destroyRequested = 0;
pthread_mutex_lock(&g_activityMutex);
appPlatform.instance = g_pActivity;
pthread_mutex_unlock(&g_activityMutex);
appPlatform.initConsts();
//LOGI("socket-stuff\n");
//socketDesc = initSocket(1999);
App* app = new MAIN_CLASS();
engine.userApp = app;
engine.app = state;
engine.is_inited = false;
engine.appContext.doRender = true;
engine.appContext.platform = &appPlatform;
setupExternalPath(state, (MAIN_CLASS*)app);
if( state->savedState != NULL )
{
// We are starting with a previous saved state; restore from it.
app->loadState(state->savedState, state->savedStateSize);
}
bool inited = false;
bool teardownPhase = false;
appPlatform._nativeActivity = state->activity;
// our 'main loop'
while( 1 )
{
// Read all pending events.
int ident;
int events;
struct android_poll_source* source;
while( (ident = ALooper_pollAll( 0, NULL, &events, (void**)&source) ) >= 0 )
{
// Process this event.
// This will call the function pointer android_app::onInputEvent() which in our case is
// engine_handle_input()
if( source != NULL ) {
if(source->id == 2) {
// Back button is intercepted by the ime on android 4.1/4.2 resulting in the application stopping to respond.
internal_process_input( state, source );
} else {
source->process( state, source );
}
}
}
// Check if we are exiting.
if( state->destroyRequested )
{
//engine_term_display( &engine );
delete app;
return;
}
if (!inited && engine.is_inited) {
app->init(engine.appContext);
app->setSize(engine.width, engine.height);
inited = true;
}
if (inited && engine.is_inited && engine.has_focus) {
app->update();
} else {
sleepMs(50);
}
if (!teardownPhase && app->wantToQuit()) {
teardownPhase = true;
LOGI("tearing down!");
ANativeActivity_finish(state->activity);
}
}
}