Fix android termination bug (#1354)

* move hook additions to onCreateView

* Updated license header

* Formatting nitpick

* Added prefix to log messages

---------

Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
David Griswold 2025-09-04 18:35:10 -03:00 committed by GitHub
parent b63d7841dd
commit 70f9379eef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 21 deletions

View File

@ -85,7 +85,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
private val preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
private lateinit var emulationState: EmulationState
private var emulationState: EmulationState? = null
private var perfStatsUpdater: Runnable? = null
private lateinit var emulationActivity: EmulationActivity
@ -106,6 +106,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
if (context is EmulationActivity) {
emulationActivity = context
NativeLibrary.setEmulationActivity(context)
EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() })
if (emulationState != null) {
EmulationLifecycleUtil.addShutdownHook(hook = { emulationState!!.stop() })
}
} else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
}
@ -156,8 +160,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
emulationState = EmulationState(game.path)
emulationActivity = requireActivity() as EmulationActivity
screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settingsViewModel.settings)
EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() })
EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() })
EmulationLifecycleUtil.addShutdownHook(hook = { emulationState!!.stop() })
}
override fun onCreateView(
@ -256,8 +259,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
binding.inGameMenu.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.menu_emulation_pause -> {
if (emulationState.isPaused) {
emulationState.unpause()
if (emulationState!!.isPaused) {
emulationState!!.unpause()
it.title = resources.getString(R.string.pause_emulation)
it.icon = ResourcesCompat.getDrawable(
resources,
@ -265,7 +268,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
requireContext().theme
)
} else {
emulationState.pause()
emulationState!!.pause()
it.title = resources.getString(R.string.resume_emulation)
it.icon = ResourcesCompat.getDrawable(
resources,
@ -355,7 +358,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}
R.id.menu_exit -> {
emulationState.pause()
emulationState!!.pause()
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_close_game)
.setMessage(R.string.emulation_close_game_message)
@ -363,9 +366,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
EmulationLifecycleUtil.closeGame()
}
.setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int ->
emulationState.unpause()
emulationState!!.unpause()
}
.setOnCancelListener { emulationState.unpause() }
.setOnCancelListener { emulationState!!.unpause() }
.show()
true
}
@ -459,10 +462,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}
private fun togglePause() {
if (emulationState.isPaused) {
emulationState.unpause()
if (emulationState!!.isPaused) {
emulationState!!.unpause()
} else {
emulationState.pause()
emulationState!!.pause()
}
}
@ -470,7 +473,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
super.onResume()
Choreographer.getInstance().postFrameCallback(this)
if (NativeLibrary.isRunning()) {
emulationState.pause()
emulationState!!.pause()
// If the overlay is enabled, we need to update the position if changed
val position = IntSetting.PERFORMANCE_OVERLAY_POSITION.int
@ -488,7 +491,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}
if (DirectoryInitialization.areCitraDirectoriesReady()) {
emulationState.run(emulationActivity.isActivityRecreated)
emulationState!!.run(emulationActivity.isActivityRecreated)
} else {
setupCitraDirectoriesThenStartEmulation()
}
@ -496,7 +499,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
override fun onPause() {
if (NativeLibrary.isRunning()) {
emulationState.pause()
emulationState!!.pause()
}
Choreographer.getInstance().removeFrameCallback(this)
super.onPause()
@ -512,7 +515,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
if (directoryInitializationState ===
DirectoryInitializationState.CITRA_DIRECTORIES_INITIALIZED
) {
emulationState.run(emulationActivity.isActivityRecreated)
emulationState!!.run(emulationActivity.isActivityRecreated)
} else if (directoryInitializationState ===
DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED
) {
@ -1348,11 +1351,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height)
emulationState.newSurface(holder.surface)
emulationState!!.newSurface(holder.surface)
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
emulationState.clearSurface()
emulationState!!.clearSurface()
}
override fun doFrame(frameTimeNanos: Long) {

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -18,11 +18,19 @@ object EmulationLifecycleUtil {
}
fun addShutdownHook(hook: Runnable) {
shutdownHooks.add(hook)
if (shutdownHooks.contains(hook)) {
Log.warning("[EmulationLifecycleUtil] Tried to add shutdown hook that already existed. Skipping.")
} else {
shutdownHooks.add(hook)
}
}
fun addPauseResumeHook(hook: Runnable) {
pauseResumeHooks.add(hook)
if (pauseResumeHooks.contains(hook)) {
Log.warning("[EmulationLifecycleUtil] Tried to add pause resume hook that already existed. Skipping.")
} else {
pauseResumeHooks.add(hook)
}
}
fun clear() {