Merge pull request #2558 from sigmabeta/android-panic-alerts

Android: Display Panic Alerts on-screen as a Toast message.
This commit is contained in:
Ryan Houdek
2015-06-07 23:14:34 -04:00
3 changed files with 88 additions and 23 deletions

View File

@ -8,6 +8,9 @@ package org.dolphinemu.dolphinemu;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
/** /**
* Class which contains methods that interact * Class which contains methods that interact
@ -15,6 +18,8 @@ import android.view.Surface;
*/ */
public final class NativeLibrary public final class NativeLibrary
{ {
private static EmulationActivity mEmulationActivity;
/** /**
* Button type for use in onTouchEvent * Button type for use in onTouchEvent
*/ */
@ -235,6 +240,13 @@ public final class NativeLibrary
/** Native EGL functions not exposed by Java bindings **/ /** Native EGL functions not exposed by Java bindings **/
public static native void eglBindAPI(int api); 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 static
{ {
try try
@ -245,5 +257,26 @@ public final class NativeLibrary
{ {
Log.e("NativeLibrary", ex.toString()); 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;
} }
} }

View File

@ -7,6 +7,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.util.Log;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
@ -91,6 +92,23 @@ public final class EmulationActivity extends Activity
.commit(); .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 @Override
protected void onPostCreate(Bundle savedInstanceState) protected void onPostCreate(Bundle savedInstanceState)
{ {

View File

@ -37,13 +37,22 @@ ANativeWindow* surf;
std::string g_filename; std::string g_filename;
std::string g_set_userpath = ""; std::string g_set_userpath = "";
// PanicAlert JavaVM* g_java_vm;
static bool g_alert_available = false; jclass g_jni_class;
static std::string g_alert_message = ""; jmethodID g_jni_method_alert;
static Common::Event g_alert_event;
#define DOLPHIN_TAG "DolphinEmuNative" #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_NotifyMapLoaded() {}
void Host_RefreshDSPDebuggerWindow() {} void Host_RefreshDSPDebuggerWindow() {}
@ -99,11 +108,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*/) static bool MsgAlert(const char* caption, const char* text, bool yes_no, int /*Style*/)
{ {
g_alert_message = std::string(text); __android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "%s:%s", caption, text);
g_alert_available = true;
// XXX: Uncomment next line when the Android UI actually handles messages // Associate the current Thread with the Java VM.
// g_alert_event.Wait() JNIEnv* env;
g_alert_available = false; 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();
return false; return false;
} }
@ -363,12 +379,9 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetUserDirec
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv *env, jobject obj); JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetUserDirectory(JNIEnv *env, jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv *env, jobject obj, jboolean enable); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetProfiling(JNIEnv *env, jobject obj, jboolean enable);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(JNIEnv *env, jobject obj); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfileResults(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_Run(JNIEnv *env, jobject obj, jobject _surf); JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf);
// MsgAlert
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_UnPauseEmulation(JNIEnv *env, jobject obj) JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_UnPauseEmulation(JNIEnv *env, jobject obj)
{ {
@ -564,19 +577,20 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_WriteProfile
JitInterface::WriteProfileResults(filename); JitInterface::WriteProfileResults(filename);
} }
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_HasAlertMsg(JNIEnv *env, jobject obj) JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_CacheClassesAndMethods(JNIEnv *env, jobject obj)
{ {
return g_alert_available; // This class reference is only valid for the lifetime of this method.
} jclass localClass = env->FindClass("org/dolphinemu/dolphinemu/NativeLibrary");
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetAlertMsg(JNIEnv *env, jobject obj) // This reference, however, is valid until we delete it.
{ g_jni_class = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));
return env->NewStringUTF(g_alert_message.c_str());
}
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ClearAlertMsg(JNIEnv *env, jobject obj) // TODO Find a place for this.
{ // So we don't leak a reference to NativeLibrary.class.
g_alert_event.Set(); // Kick the alert // 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) JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf)