android: Fix black screen when relaunching a game from a shortcut (#2656)

* android: Fix black screen when relaunching a game from a shortcut

onNewIntent stopped emulation and then called setGraph with an equal
graph, which keeps the old emulation fragment, so nothing restarted.

A shortcut for the game that is already running now just brings it
back. A shortcut for a different game replaces the emulation fragment
so the new game boots. The old fragment no longer clears the activity
registration the new one already set, and its stats overlay updater
stops with its view instead of resetting the new game's stats.

After HOME the second screen surface comes back after the main one,
so the emulation thread waits briefly for it instead of crashing.

Fixes #2329

* android: Update EmulationFragment.kt license header to GPLv3
This commit is contained in:
Ygor Dreyer authored and GitHub committed 2026-10-12 19:10:59 +02:00
1 parent f718556525
commit 7ea9cee479
3 files changed
+43 -2

No files matched your search

@@ -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
@@ -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()
}
+10
View File
@@ -3,6 +3,7 @@
// Refer to the LICENSE.txt file included.
#include <algorithm>
#include <chrono>
#include <codecvt>
#include <thread>
#include <dlfcn.h>
@@ -196,6 +197,12 @@ static bool CheckMicPermission() {
IDCache::GetRequestMicPermission());
}
static void WaitForEmulationSurfaces(std::unique_lock<std::recursive_mutex>& 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<std::recursive_mutex> 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) {