diff --git a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt index d4066d182..5d009774e 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt @@ -27,6 +27,7 @@ import androidx.core.os.BundleCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat +import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment import androidx.preference.PreferenceManager import org.citra.citra_emu.CitraApplication @@ -184,6 +185,11 @@ class EmulationActivity : AppCompatActivity() { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) + val launchUri = getLaunchUri(intent) + if (launchUri != null && launchUri != Uri.EMPTY && launchUri == getLaunchUri(this.intent)) { + Log.info("[EmulationActivity] Ignoring relaunch of the running game") + return + } setIntent(intent) NativeLibrary.stopEmulation() @@ -203,7 +209,24 @@ class EmulationActivity : AppCompatActivity() { val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment - navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras) + navHostFragment.navController.navigate( + R.id.emulationFragment, + intent.extras, + NavOptions.Builder().setPopUpTo(R.id.emulationFragment, true).build() + ) + } + + private fun getLaunchUri(intent: Intent): Uri? = try { + val game = intent.extras?.let { extras -> + BundleCompat.getParcelable(extras, "game", Game::class.java) + } + if (game != null) { + game.launchIntent.data + } else { + intent.data ?: intent.getStringExtra("SelectedGame")?.toUri() + } + } catch (e: Exception) { + null } // On some devices, the system bars will not disappear on first boot or after some diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt index 5401b9b43..ab7c7e2e3 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt @@ -564,8 +564,16 @@ class EmulationFragment : super.onPause() } + override fun onDestroyView() { + perfStatsUpdater?.let { perfStatsUpdateHandler.removeCallbacks(it) } + perfStatsUpdater = null + super.onDestroyView() + } + override fun onDetach() { - NativeLibrary.clearEmulationActivity() + if (!isRemoving) { + NativeLibrary.clearEmulationActivity() + } super.onDetach() } diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index b6fe5ddd5..8a38de52c 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -3,6 +3,7 @@ // Refer to the LICENSE.txt file included. #include +#include #include #include #include @@ -196,6 +197,12 @@ static bool CheckMicPermission() { IDCache::GetRequestMicPermission()); } +static void WaitForEmulationSurfaces(std::unique_lock& surface_lock) { + surface_cv.wait_for(surface_lock, std::chrono::seconds(2), + [] { return s_secondary_surface != nullptr; }); + surface_cv.wait(surface_lock, [] { return s_surface != nullptr; }); +} + static Core::System::ResultStatus RunCitra(const std::string& filepath) { // Citra core only supports a single running instance std::scoped_lock lock(running_mutex); @@ -221,6 +228,8 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) { // s_surface/s_secondary_surface while they're still being used. std::unique_lock surface_lock(surface_mutex); + WaitForEmulationSurfaces(surface_lock); + // We also need to lock the surface mutex when System::Init() is called. // This is because save state saving and loading may call System::Init // on its own which does GPU reinitialization. @@ -467,6 +476,7 @@ void Java_org_citra_citra_1emu_NativeLibrary_secondarySurfaceChanged(JNIEnv* env if (!s_secondary_surface) { return; } + surface_cv.notify_all(); bool notify = false; if (secondary_window) {