From a0ca20a821c357e396ac53c2aa106f1069d9a55b Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 21 Jan 2021 01:23:07 +1000 Subject: [PATCH] Android: Defer rotation request until after start Fixes messed-up state when orientation is set. --- .../app/src/cpp/android_host_interface.cpp | 33 +++++++++---------- android/app/src/cpp/android_host_interface.h | 4 +-- .../duckstation/AndroidHostInterface.java | 2 +- .../duckstation/EmulationActivity.java | 14 ++++---- .../stenzek/duckstation/EmulationThread.java | 10 +++--- 5 files changed, 29 insertions(+), 34 deletions(-) diff --git a/android/app/src/cpp/android_host_interface.cpp b/android/app/src/cpp/android_host_interface.cpp index 04f690c47..252b13b56 100644 --- a/android/app/src/cpp/android_host_interface.cpp +++ b/android/app/src/cpp/android_host_interface.cpp @@ -227,13 +227,14 @@ std::unique_ptr AndroidHostInterface::OpenPackageFile(const char* pa void AndroidHostInterface::RegisterHotkeys() { - RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenPauseMenu"), - StaticString(TRANSLATABLE("Hotkeys", "Open Pause Menu")), [this](bool pressed) { - if (pressed) { - AndroidHelpers::GetJNIEnv()->CallVoidMethod(m_emulation_activity_object, - s_EmulationActivity_method_openPauseMenu); - } - }); + RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("OpenPauseMenu"), + StaticString(TRANSLATABLE("Hotkeys", "Open Pause Menu")), [this](bool pressed) { + if (pressed) + { + AndroidHelpers::GetJNIEnv()->CallVoidMethod(m_emulation_activity_object, + s_EmulationActivity_method_openPauseMenu); + } + }); CommonHostInterface::RegisterHotkeys(); } @@ -339,19 +340,17 @@ void AndroidHostInterface::RunOnEmulationThread(std::function function, m_mutex.unlock(); } -void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, jobject surface, +void AndroidHostInterface::EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, SystemBootParameters boot_params, bool resume_state) { - ANativeWindow* native_surface = ANativeWindow_fromSurface(env, surface); - if (!native_surface) + if (!m_surface) { - Log_ErrorPrint("ANativeWindow_fromSurface() returned null"); + Log_ErrorPrint("Emulation thread started without surface set."); env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped); return; } CreateImGuiContext(); - m_surface = native_surface; m_emulation_activity_object = emulation_activity; ApplySettings(true); @@ -912,8 +911,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) nullptr || (s_EmulationActivity_method_getRefreshRate = env->GetMethodID(emulation_activity_class, "getRefreshRate", "()F")) == nullptr || - (s_EmulationActivity_method_openPauseMenu = - env->GetMethodID(emulation_activity_class, "openPauseMenu", "()V")) == nullptr || + (s_EmulationActivity_method_openPauseMenu = env->GetMethodID(emulation_activity_class, "openPauseMenu", "()V")) == + nullptr || (s_PatchCode_constructor = env->GetMethodID(s_PatchCode_class, "", "(ILjava/lang/String;Z)V")) == nullptr || (s_GameListEntry_constructor = env->GetMethodID( s_GameListEntry_class, "", @@ -985,15 +984,15 @@ DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_isEmulationThreadRunning, } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_runEmulationThread, jobject obj, jobject emulationActivity, - jobject surface, jstring filename, jboolean resume_state, jstring state_filename) + jstring filename, jboolean resume_state, jstring state_filename) { std::string state_filename_str = AndroidHelpers::JStringToString(env, state_filename); SystemBootParameters boot_params; boot_params.filename = AndroidHelpers::JStringToString(env, filename); - AndroidHelpers::GetNativeClass(env, obj)->EmulationThreadEntryPoint(env, emulationActivity, surface, - std::move(boot_params), resume_state); + AndroidHelpers::GetNativeClass(env, obj)->EmulationThreadEntryPoint(env, emulationActivity, std::move(boot_params), + resume_state); } DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThreadLoop, jobject obj) diff --git a/android/app/src/cpp/android_host_interface.h b/android/app/src/cpp/android_host_interface.h index b4a79677d..20c32979c 100644 --- a/android/app/src/cpp/android_host_interface.h +++ b/android/app/src/cpp/android_host_interface.h @@ -46,8 +46,8 @@ public: void PauseEmulationThread(bool paused); void StopEmulationThreadLoop(); - void EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, jobject initial_surface, - SystemBootParameters boot_params, bool resume_state); + void EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, SystemBootParameters boot_params, + bool resume_state); void SurfaceChanged(ANativeWindow* surface, int format, int width, int height); void SetDisplayAlignment(HostDisplay::Alignment alignment); diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java index 5caad48d3..a2ec884c4 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/AndroidHostInterface.java @@ -49,7 +49,7 @@ public class AndroidHostInterface { public native boolean isEmulationThreadRunning(); - public native boolean runEmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String state_filename); + public native boolean runEmulationThread(EmulationActivity emulationActivity, String filename, boolean resumeState, String state_filename); public native boolean isEmulationThreadPaused(); diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java index eb5cdf55d..d84cc3d49 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationActivity.java @@ -123,6 +123,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde public void onEmulationStarted() { runOnUiThread(() -> { + updateRequestedOrientation(); updateOrientation(); }); } @@ -196,8 +197,9 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // Once we get a surface, we can boot. + AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height); + if (mEmulationThread != null) { - AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height); updateOrientation(); if (mApplySettingsOnSurfaceRestored) { @@ -212,18 +214,15 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde final boolean resumeState = getIntent().getBooleanExtra("resumeState", false); final String bootSaveStatePath = getIntent().getStringExtra("saveStatePath"); - mEmulationThread = EmulationThread.create(this, holder.getSurface(), bootPath, resumeState, bootSaveStatePath); + mEmulationThread = EmulationThread.create(this, bootPath, resumeState, bootSaveStatePath); } @Override public void surfaceDestroyed(SurfaceHolder holder) { - if (!AndroidHostInterface.getInstance().isEmulationThreadRunning()) - return; - Log.i("EmulationActivity", "Surface destroyed"); // Save the resume state in case we never get back again... - if (!mStopRequested) + if (AndroidHostInterface.getInstance().isEmulationThreadRunning() && !mStopRequested) AndroidHostInterface.getInstance().saveResumeState(true); AndroidHostInterface.getInstance().surfaceChanged(null, 0, 0, 0); @@ -231,9 +230,9 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde @Override protected void onCreate(Bundle savedInstanceState) { + mPreferences = PreferenceManager.getDefaultSharedPreferences(this); super.onCreate(savedInstanceState); - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); Log.i("EmulationActivity", "OnCreate"); // we might be coming from a third-party launcher if the host interface isn't setup @@ -255,7 +254,6 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde mContentView.requestFocus(); // Sort out rotation. - updateRequestedOrientation(); updateOrientation(); updateSustainedPerformanceMode(); diff --git a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java index 8cd95b3a9..7210d8f8a 100644 --- a/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java +++ b/android/app/src/main/java/com/github/stenzek/duckstation/EmulationThread.java @@ -8,24 +8,22 @@ import androidx.annotation.NonNull; public class EmulationThread extends Thread { private EmulationActivity emulationActivity; - private Surface surface; private String filename; private boolean resumeState; private String stateFilename; - private EmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String stateFilename) { + private EmulationThread(EmulationActivity emulationActivity, String filename, boolean resumeState, String stateFilename) { super("EmulationThread"); this.emulationActivity = emulationActivity; - this.surface = surface; this.filename = filename; this.resumeState = resumeState; this.stateFilename = stateFilename; } - public static EmulationThread create(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String stateFilename) { + public static EmulationThread create(EmulationActivity emulationActivity, String filename, boolean resumeState, String stateFilename) { Log.i("EmulationThread", String.format("Starting emulation thread (%s)...", filename)); - EmulationThread thread = new EmulationThread(emulationActivity, surface, filename, resumeState, stateFilename); + EmulationThread thread = new EmulationThread(emulationActivity, filename, resumeState, stateFilename); thread.start(); return thread; } @@ -38,7 +36,7 @@ public class EmulationThread extends Thread { Log.i("EmulationThread", "Failed to set priority for emulation thread: " + e.getMessage()); } - AndroidHostInterface.getInstance().runEmulationThread(emulationActivity, surface, filename, resumeState, stateFilename); + AndroidHostInterface.getInstance().runEmulationThread(emulationActivity, filename, resumeState, stateFilename); Log.i("EmulationThread", "Emulation thread exiting."); }