From 673fb26d6e76d626d12e6d8dca5056c8526b4c0b Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Wed, 11 Jan 2023 11:44:28 +0100 Subject: [PATCH] android: threading fix. stop vibrator thread. allow screen saver If the android activity is destroyed and the game unloaded, the gui's game state wasn't updated, leading to a crash if resuming. Same for the android game state if pausing, destroying then resuming. tentative fix for MINIDUMP-27, MINIDUMP-25, MINIDUMP-23 Wait until emu is stopped in single-threaded. Stop vibrator thread when view is detached Allow the screen saver when a game isn't running. --- core/rend/gui.cpp | 4 +- .../flycast/src/main/AndroidManifest.xml | 1 - .../com/reicast/emulator/BaseGLActivity.java | 13 ++++- .../reicast/emulator/emu/NativeGLView.java | 14 +++++- .../emulator/emu/VirtualJoystickDelegate.java | 9 +++- .../flycast/src/main/jni/src/Android.cpp | 47 ++++++++++++------- 6 files changed, 65 insertions(+), 23 deletions(-) diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 6f8374172..80ea497a9 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -88,8 +88,11 @@ static void emuEventCallback(Event event, void *) game_started = true; break; case Event::Start: + GamepadDevice::load_system_mappings(); + break; case Event::Terminate: GamepadDevice::load_system_mappings(); + game_started = false; break; default: break; @@ -490,7 +493,6 @@ void gui_stop_game(const std::string& message) // Exit to main menu emu.unloadGame(); gui_state = GuiState::Main; - game_started = false; reset_vmus(); if (!message.empty()) gui_error("Flycast has stopped.\n\n" + message); diff --git a/shell/android-studio/flycast/src/main/AndroidManifest.xml b/shell/android-studio/flycast/src/main/AndroidManifest.xml index dfcdee46d..c782dc2fc 100644 --- a/shell/android-studio/flycast/src/main/AndroidManifest.xml +++ b/shell/android-studio/flycast/src/main/AndroidManifest.xml @@ -15,7 +15,6 @@ - diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java index 12a4cd9b2..bb2390ab7 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/BaseGLActivity.java @@ -79,7 +79,6 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat. getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; } - if (!getFilesDir().exists()) { getFilesDir().mkdir(); } @@ -406,5 +405,17 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat. } } + // Called from native code + public void onGameStateChange(boolean started) { + runOnUiThread(new Runnable() { + public void run() { + if (started) + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + else + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + }); + } + private static native void register(BaseGLActivity activity); } diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java index 756a63479..42cb41717 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/NativeGLView.java @@ -35,7 +35,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback public NativeGLView(final Context context, AttributeSet attrs) { super(context, attrs); getHolder().addCallback(this); - setKeepScreenOn(true); setFocusable(true); setFocusableInTouchMode(true); requestFocus(); @@ -53,13 +52,24 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback } }); } - vjoyDelegate = new VirtualJoystickDelegate(this); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); this.setLayerType(LAYER_TYPE_HARDWARE, null); } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + vjoyDelegate = new VirtualJoystickDelegate(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + vjoyDelegate.stop(); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { diff --git a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java index ea821f294..1e9dce529 100644 --- a/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java +++ b/shell/android-studio/flycast/src/main/java/com/reicast/emulator/emu/VirtualJoystickDelegate.java @@ -46,6 +46,14 @@ public class VirtualJoystickDelegate { scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener()); } + public void stop() { + vibratorThread.stopVibrator(); + try { + vibratorThread.join(); + } catch (InterruptedException e) { + } + } + public void readCustomVjoyValues() { vjoy_d_custom = VJoy.readCustomVjoyValues(context); } @@ -58,7 +66,6 @@ public class VirtualJoystickDelegate { view.requestLayout(); } - private void reset_analog() { diff --git a/shell/android-studio/flycast/src/main/jni/src/Android.cpp b/shell/android-studio/flycast/src/main/jni/src/Android.cpp index a71f4113a..1ad839e18 100644 --- a/shell/android-studio/flycast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/flycast/src/main/jni/src/Android.cpp @@ -102,15 +102,29 @@ jobject g_emulator; jmethodID saveAndroidSettingsMid; static ANativeWindow *g_window = 0; +// Activity +static jobject g_activity; +static jmethodID VJoyStartEditingMID; +static jmethodID VJoyStopEditingMID; +static jmethodID VJoyResetEditingMID; +static jmethodID showTextInputMid; +static jmethodID hideTextInputMid; +static jmethodID isScreenKeyboardShownMid; +static jmethodID onGameStateChangeMid; + static void emuEventCallback(Event event, void *) { switch (event) { case Event::Pause: game_started = false; + if (g_activity != nullptr) + jvm_attacher.getEnv()->CallVoidMethod(g_activity, onGameStateChangeMid, false); break; case Event::Resume: game_started = true; + if (g_activity != nullptr) + jvm_attacher.getEnv()->CallVoidMethod(g_activity, onGameStateChangeMid, true); break; default: break; @@ -302,15 +316,6 @@ jmethodID audioInitMid; jmethodID audioTermMid; static jobject g_audioBackend; -// Activity -static jobject g_activity; -static jmethodID VJoyStartEditingMID; -static jmethodID VJoyStopEditingMID; -static jmethodID VJoyResetEditingMID; -static jmethodID showTextInputMid; -static jmethodID hideTextInputMid; -static jmethodID isScreenKeyboardShownMid; - extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) { sipemu = env->NewGlobalRef(sip); @@ -319,11 +324,22 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(J stopRecordingMid = env->GetMethodID(env->GetObjectClass(sipemu),"stopRecording","()V"); } +static void stopEmu() +{ + if (!emu.running()) + game_started = false; + else + emu.stop(); + // in single-threaded mode, stopping is delayed + while (game_started) + std::this_thread::sleep_for(std::chrono::milliseconds(1)); +} + extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,jobject obj) { - if (game_started) + if (emu.running()) { - emu.stop(); + stopEmu(); game_started = true; // restart when resumed if (config::AutoSaveState) dc_savestate(config::SavestateSlot); @@ -339,14 +355,10 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNI extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) { - if (emu.running()) { - emu.stop(); - if (config::AutoSaveState) - dc_savestate(config::SavestateSlot); - } + stopEmu(); emu.unloadGame(); gui_state = GuiState::Main; - settings.content.path.clear(); + game_started = false; } static void *render_thread_func(void *) @@ -652,6 +664,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_reicast_emulator_BaseGLActivity_regis showTextInputMid = env->GetMethodID(env->GetObjectClass(activity), "showTextInput", "(IIII)V"); hideTextInputMid = env->GetMethodID(env->GetObjectClass(activity), "hideTextInput", "()V"); isScreenKeyboardShownMid = env->GetMethodID(env->GetObjectClass(activity), "isScreenKeyboardShown", "()Z"); + onGameStateChangeMid = env->GetMethodID(env->GetObjectClass(activity), "onGameStateChange", "(Z)V"); } }