From cdbb469b1fa98683200540544977e9291c03cdf6 Mon Sep 17 00:00:00 2001 From: papi <20916260+papi-ux@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:07:30 -0400 Subject: [PATCH] fix(ui): exit stream activity on terminal events --- app/src/main/java/com/papi/nova/Game.kt | 20 ++++++++++++++++ .../com/papi/nova/api/PolarisSessionEvents.kt | 19 +++++++++++++++ .../papi/nova/api/PolarisSessionEventsTest.kt | 23 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 app/src/main/java/com/papi/nova/api/PolarisSessionEvents.kt create mode 100644 app/src/test/java/com/papi/nova/api/PolarisSessionEventsTest.kt diff --git a/app/src/main/java/com/papi/nova/Game.kt b/app/src/main/java/com/papi/nova/Game.kt index aece4e2c..dd62b5a4 100644 --- a/app/src/main/java/com/papi/nova/Game.kt +++ b/app/src/main/java/com/papi/nova/Game.kt @@ -5233,6 +5233,10 @@ object : com.papi.nova.api.PolarisEventSource.EventListener { override fun onSessionEvent(event:String, state:String, message:String) { LimeLog.info("Nova SSE: " + event + " [" + state + "] " + message) novaProgressOverlay!!.updateState(state, message) + if (com.papi.nova.api.PolarisSessionEvents.shouldFinishGameActivity(event, state)) { + LimeLog.info("Nova SSE: terminal session event received; ending local stream activity") + runOnUiThread { finishAfterRemotePolarisSessionEnd() } + } } override fun onStateUpdate(sessionState:String, cageRunning:Boolean, screenLocked:Boolean) { novaProgressOverlay!!.updateState(sessionState, "") @@ -5821,6 +5825,22 @@ host ?: this@Game.getIntent().getStringExtra(EXTRA_HOST) ) } +private fun finishAfterRemotePolarisSessionEnd() { + if (isFinishing || isDestroyed) { + return + } + markLocalSessionEnd() + stopBackgroundResumeWindow() + stopPolarisLiveSessionStatusRefresh() + if (novaReconnectOverlay != null) { + novaReconnectOverlay!!.dismiss() + } + if (novaProgressOverlay != null) { + novaProgressOverlay!!.dismiss() + } + finish() + } + fun disconnect() { prepareBackgroundResumeWindow() if (prefConfig!!.smartClipboardSync) diff --git a/app/src/main/java/com/papi/nova/api/PolarisSessionEvents.kt b/app/src/main/java/com/papi/nova/api/PolarisSessionEvents.kt new file mode 100644 index 00000000..3b7abaa0 --- /dev/null +++ b/app/src/main/java/com/papi/nova/api/PolarisSessionEvents.kt @@ -0,0 +1,19 @@ +package com.papi.nova.api + +object PolarisSessionEvents { + private val terminalEvents = setOf( + "stream_ended", + "session_ended", + "stream_resume_timeout", + ) + + @JvmStatic + fun shouldFinishGameActivity(event: String?, state: String?): Boolean { + val normalizedEvent = event?.trim()?.lowercase().orEmpty() + val normalizedState = state?.trim()?.lowercase().orEmpty() + if (terminalEvents.contains(normalizedEvent)) { + return true + } + return normalizedState == "idle" && normalizedEvent == "stream_ended" + } +} diff --git a/app/src/test/java/com/papi/nova/api/PolarisSessionEventsTest.kt b/app/src/test/java/com/papi/nova/api/PolarisSessionEventsTest.kt new file mode 100644 index 00000000..d93eb5e9 --- /dev/null +++ b/app/src/test/java/com/papi/nova/api/PolarisSessionEventsTest.kt @@ -0,0 +1,23 @@ +package com.papi.nova.api + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class PolarisSessionEventsTest { + @Test + fun terminalStreamEndedFinishesGameActivity() { + assertTrue(PolarisSessionEvents.shouldFinishGameActivity("stream_ended", "idle")) + } + + @Test + fun streamResumeTimeoutFinishesGameActivity() { + assertTrue(PolarisSessionEvents.shouldFinishGameActivity("stream_resume_timeout", "idle")) + } + + @Test + fun activeStreamingEventsDoNotFinishGameActivity() { + assertFalse(PolarisSessionEvents.shouldFinishGameActivity("stream_active", "streaming")) + assertFalse(PolarisSessionEvents.shouldFinishGameActivity("cage_starting", "cage_starting")) + } +}