mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00:00
fix(session): no endless loading screen after a game exits back to Steam (#2359)
* fix(session): avoid stale relaunch loading overlay * fix(session): keep the loading screen while the runtime installs
This commit is contained in:
1 parent
1b19837fc6
commit
836340f3a2
6 files changed
+112
-5
No files matched your search
@@ -121,6 +121,7 @@ import com.droiddeck.launcher.session.SessionArtifacts
|
||||
import com.droiddeck.launcher.session.SessionLogShare
|
||||
import com.droiddeck.launcher.session.SessionPhase
|
||||
import com.droiddeck.launcher.session.SessionPaths
|
||||
import com.droiddeck.launcher.session.SessionLoadingDecision
|
||||
import com.droiddeck.launcher.wayland.HdrSupport
|
||||
import com.droiddeck.launcher.session.SessionService
|
||||
import com.droiddeck.launcher.session.SessionState
|
||||
@@ -2435,6 +2436,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
private fun watchSession() {
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
var ticks = 0
|
||||
val loadingStartedAt = SystemClock.elapsedRealtime()
|
||||
val poll = object : Runnable {
|
||||
override fun run() {
|
||||
if (!watching) return
|
||||
@@ -2447,6 +2449,12 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
if (loading.visible && !loading.ended && !SessionState.running && !installingRuntime &&
|
||||
SessionLoadingDecision.shouldReturnToLauncher(
|
||||
loadingStartedAt, SystemClock.elapsedRealtime(), SessionState.running, SessionState.phase)) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
if (loading.visible && !loading.ended) {
|
||||
if (!installingRuntime) loading.update(this@SessionActivity, SessionState.logFile)
|
||||
if (ticks++ % 2 == 0) loading.tick()
|
||||
@@ -2471,8 +2479,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
val hint = sessionExitHint(status)
|
||||
runOnUiThread {
|
||||
if (isFinishing || isDestroyed) return@runOnUiThread
|
||||
if (status == 0) SessionState.relaunch?.let { next ->
|
||||
SessionState.relaunch = null
|
||||
if (status == 0) SessionState.takeRelaunch()?.let { next ->
|
||||
next.putExtra(EXTRA_RETURN_HOME, intent.getBooleanExtra(EXTRA_RETURN_HOME, false))
|
||||
next.putExtra(EXTRA_LINK_TASK, intent.getIntExtra(EXTRA_LINK_TASK, -1))
|
||||
setIntent(next)
|
||||
|
||||
@@ -14,6 +14,7 @@ object SessionEvents {
|
||||
SessionPaths.take()
|
||||
val dir = SessionPaths.beginOrCurrent(context, label ?: SessionPaths.label(mode, null))
|
||||
synchronized(SessionState) {
|
||||
SessionState.clearRelaunch()
|
||||
SessionState.phase = SessionPhase.PREPARING
|
||||
SessionState.mode = mode
|
||||
SessionState.sessionId = dir.name
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
internal object SessionLoadingDecision {
|
||||
const val TIMEOUT_MS = 10_000L
|
||||
|
||||
fun shouldReturnToLauncher(startedAt: Long, now: Long, running: Boolean, phase: SessionPhase): Boolean =
|
||||
!running && phase in setOf(SessionPhase.IDLE, SessionPhase.FAILED) && now - startedAt >= TIMEOUT_MS
|
||||
}
|
||||
@@ -1697,8 +1697,8 @@ class SessionService : Service() {
|
||||
.putExtra(EXTRA_STEAM_UI, ui)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
if (url.isNotEmpty()) next.putExtra(EXTRA_STEAM_URL, url)
|
||||
SessionState.relaunch = next
|
||||
android.os.Handler(android.os.Looper.getMainLooper()).post { stopSession(0) }
|
||||
SessionState.queueRelaunch(next)
|
||||
android.os.Handler(android.os.Looper.getMainLooper()).post { stopSession(0, relaunch = true) }
|
||||
}
|
||||
}
|
||||
watcher.startWatching()
|
||||
@@ -2013,7 +2013,7 @@ class SessionService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopSession(status: Int, gen: Int? = null) {
|
||||
private fun stopSession(status: Int, gen: Int? = null, relaunch: Boolean = false) {
|
||||
if (gen != null && gen != sessionGen) {
|
||||
Log.i(TAG, "ignoring a stop from session $gen; session $sessionGen is current")
|
||||
return
|
||||
@@ -2024,6 +2024,7 @@ class SessionService : Service() {
|
||||
cancelQueuedSteamGame()
|
||||
gameExitWatchToken++
|
||||
if (!SessionState.running) return
|
||||
if (relaunch) SessionState.confirmRelaunchStop()
|
||||
SessionEvents.record("guest.exited", mapOf("status" to status))
|
||||
SessionEvents.transition(SessionPhase.STOPPING, "session.stopping", mapOf("status" to status))
|
||||
SessionState.running = false
|
||||
|
||||
@@ -73,7 +73,44 @@ object SessionState {
|
||||
@Volatile
|
||||
var steamClientArch: String? = null
|
||||
var steamVr by mutableStateOf(false)
|
||||
@Volatile
|
||||
var relaunch: android.content.Intent? = null
|
||||
@Volatile
|
||||
private var relaunchSessionId: String? = null
|
||||
@Volatile
|
||||
private var relaunchStopRequested = false
|
||||
|
||||
fun queueRelaunch(intent: android.content.Intent) {
|
||||
synchronized(this) {
|
||||
relaunch = intent
|
||||
relaunchSessionId = sessionId
|
||||
relaunchStopRequested = false
|
||||
}
|
||||
}
|
||||
|
||||
fun confirmRelaunchStop() {
|
||||
synchronized(this) {
|
||||
relaunchStopRequested = relaunch != null && relaunchSessionId == sessionId
|
||||
}
|
||||
}
|
||||
|
||||
fun takeRelaunch(): android.content.Intent? = synchronized(this) {
|
||||
val next = relaunch
|
||||
val valid = relaunchStopRequested && relaunchSessionId == sessionId
|
||||
relaunch = null
|
||||
relaunchSessionId = null
|
||||
relaunchStopRequested = false
|
||||
next.takeIf { valid }
|
||||
}
|
||||
|
||||
fun clearRelaunch() {
|
||||
synchronized(this) {
|
||||
relaunch = null
|
||||
relaunchSessionId = null
|
||||
relaunchStopRequested = false
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic var hdr = false
|
||||
|
||||
@Volatile private var deckPadValue = false
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
import android.content.Intent
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class SessionLoadingDecisionTest {
|
||||
private var previousSessionId: String? = null
|
||||
private var previousRelaunch: Intent? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
previousSessionId = SessionState.sessionId
|
||||
previousRelaunch = SessionState.relaunch
|
||||
SessionState.clearRelaunch()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
SessionState.sessionId = previousSessionId
|
||||
SessionState.relaunch = previousRelaunch
|
||||
SessionState.clearRelaunch()
|
||||
if (previousRelaunch != null) SessionState.queueRelaunch(previousRelaunch!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadingTimesOutOnlyWhenNoSessionStarted() {
|
||||
assertEquals(false, SessionLoadingDecision.shouldReturnToLauncher(100L, 10_099L, false, SessionPhase.IDLE))
|
||||
assertEquals(true, SessionLoadingDecision.shouldReturnToLauncher(100L, 10_100L, false, SessionPhase.IDLE))
|
||||
assertEquals(false, SessionLoadingDecision.shouldReturnToLauncher(100L, 10_100L, true, SessionPhase.IDLE))
|
||||
assertEquals(false, SessionLoadingDecision.shouldReturnToLauncher(100L, 10_100L, false, SessionPhase.PREPARING))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun relaunchRequiresTheCurrentSessionToHaveRequestedTheStop() {
|
||||
SessionState.sessionId = "session-a"
|
||||
val next = Intent().apply { action = "next" }
|
||||
SessionState.queueRelaunch(next)
|
||||
assertNull(SessionState.takeRelaunch())
|
||||
SessionState.queueRelaunch(next)
|
||||
SessionState.confirmRelaunchStop()
|
||||
assertEquals(next, SessionState.takeRelaunch())
|
||||
assertNull(SessionState.takeRelaunch())
|
||||
|
||||
SessionState.queueRelaunch(next)
|
||||
SessionState.confirmRelaunchStop()
|
||||
SessionState.sessionId = "session-b"
|
||||
assertNull(SessionState.takeRelaunch())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user