From 3038368128696e3aa924da7f6ff08c0f7cb5323f Mon Sep 17 00:00:00 2001 From: sigmabeta Date: Sun, 7 Jun 2015 20:13:52 -0400 Subject: [PATCH] Android: Display Panic Alerts on-screen as an Android Toast message. --- .../dolphinemu/dolphinemu/NativeLibrary.java | 33 ++++++++++++++ .../activities/EmulationActivity.java | 18 ++++++++ Source/Core/DolphinWX/MainAndroid.cpp | 45 ++++++++++++++++++- 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java index 12259de37b..d8b1b6c112 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java @@ -8,6 +8,9 @@ package org.dolphinemu.dolphinemu; import android.util.Log; import android.view.Surface; +import android.widget.Toast; + +import org.dolphinemu.dolphinemu.activities.EmulationActivity; /** * Class which contains methods that interact @@ -15,6 +18,8 @@ import android.view.Surface; */ public final class NativeLibrary { + private static EmulationActivity mEmulationActivity; + /** * Button type for use in onTouchEvent */ @@ -235,6 +240,13 @@ public final class NativeLibrary /** Native EGL functions not exposed by Java bindings **/ public static native void eglBindAPI(int api); + /** + * The methods C++ uses to find references to Java classes and methods + * are really expensive. Rather than calling them every time we want to + * run them, do it once when we load the native library. + */ + private static native void CacheClassesAndMethods(); + static { try @@ -245,5 +257,26 @@ public final class NativeLibrary { Log.e("NativeLibrary", ex.toString()); } + + CacheClassesAndMethods(); + } + + public static void displayAlertMsg(final String alert) + { + Log.e("DolphinEmu", "Alert: " + alert); + mEmulationActivity.runOnUiThread(new Runnable() + { + @Override + public void run() + { + Toast.makeText(mEmulationActivity, "Panic Alert: " + alert, Toast.LENGTH_LONG).show(); + } + }); + } + + public static void setEmulationActivity(EmulationActivity emulationActivity) + { + Log.v("DolphinEmu", "Registering EmulationActivity."); + mEmulationActivity = emulationActivity; } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index de7ebb17d3..b4c61bea0e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.util.Log; import android.view.InputDevice; import android.view.KeyEvent; import android.view.Menu; @@ -91,6 +92,23 @@ public final class EmulationActivity extends Activity .commit(); } + @Override + protected void onStart() + { + super.onStart(); + Log.d("DolphinEmu", "EmulationActivity starting."); + NativeLibrary.setEmulationActivity(this); + } + + @Override + protected void onStop() + { + super.onStop(); + Log.d("DolphinEmu", "EmulationActivity stopping."); + + NativeLibrary.setEmulationActivity(null); + } + @Override protected void onPostCreate(Bundle savedInstanceState) { diff --git a/Source/Core/DolphinWX/MainAndroid.cpp b/Source/Core/DolphinWX/MainAndroid.cpp index 07532be838..11e8d01df1 100644 --- a/Source/Core/DolphinWX/MainAndroid.cpp +++ b/Source/Core/DolphinWX/MainAndroid.cpp @@ -37,6 +37,10 @@ ANativeWindow* surf; std::string g_filename; std::string g_set_userpath = ""; +JavaVM* g_java_vm; +jclass g_jni_class; +jmethodID g_jni_method_alert; + // PanicAlert static bool g_alert_available = false; static std::string g_alert_message = ""; @@ -44,6 +48,16 @@ static Common::Event g_alert_event; #define DOLPHIN_TAG "DolphinEmuNative" +/* + * Cache the JavaVM so that we can call into it later. + */ +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + g_java_vm = vm; + + return JNI_VERSION_1_6; +} + void Host_NotifyMapLoaded() {} void Host_RefreshDSPDebuggerWindow() {} @@ -99,6 +113,18 @@ void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {} static bool MsgAlert(const char* caption, const char* text, bool yes_no, int /*Style*/) { + __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "%s:%s", caption, text); + + // Associate the current Thread with the Java VM. + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + + // Execute the Java method. + env->CallStaticVoidMethod(g_jni_class, g_jni_method_alert, env->NewStringUTF(text)); + + // Must be called before the current thread exits; might as well do it here. + g_java_vm->DetachCurrentThread(); + g_alert_message = std::string(text); g_alert_available = true; // XXX: Uncomment next line when the Android UI actually handles messages @@ -365,10 +391,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf); -// MsgAlert +// Msg JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_HasAlertMsg(JNIEnv *env, jobject obj); JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetAlertMsg(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ClearAlertMsg(JNIEnv *env, jobject obj); +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv *env, jobject obj) { @@ -579,6 +606,22 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ClearAlertMs g_alert_event.Set(); // Kick the alert } +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv *env, jobject obj) +{ + // This class reference is only valid for the lifetime of this method. + jclass localClass = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary"); + + // This reference, however, is valid until we delete it. + g_jni_class = reinterpret_cast(env->NewGlobalRef(localClass)); + + // TODO Find a place for this. + // So we don't leak a reference to NativeLibrary.class. + // env->DeleteGlobalRef(g_jni_class); + + // Method signature taken from javap -s Source/Android/app/build/intermediates/classes/arm/debug/org/dolphinemu/dolphinemu/NativeLibrary.class + g_jni_method_alert = env->GetStaticMethodID(g_jni_class, "displayAlertMsg", "(Ljava/lang/String;)V"); +} + JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf) { surf = ANativeWindow_fromSurface(env, _surf);