mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
Merge pull request #8 from Brian5647/fix-map-freeze
fix the drawing after coming back from the media menu to navigation app
This commit is contained in:
2 files changed
+40
-19
No files matched your search
@@ -83,12 +83,16 @@ fun CarHome() {
|
|||||||
val navigator = LocalCarNavigator.current
|
val navigator = LocalCarNavigator.current
|
||||||
val panel = navigator.sidePanel
|
val panel = navigator.sidePanel
|
||||||
|
|
||||||
// Coming back to the map from another screen: make sure the nav app is drawing into a live
|
// Leaving the map for another screen: hand the nav app a fresh surface while it's covered, so
|
||||||
// surface. The first composition is skipped, since the surface is only just being lent.
|
// it has redrawn by the time the map comes back - a new surface shows black until the app's
|
||||||
|
// next frame. Coming back only replaces one that died meanwhile. Nothing happens before Home
|
||||||
|
// has first been shown, since the surface is only just being lent.
|
||||||
val onHome = navigator.current == CarScreen.Home
|
val onHome = navigator.current == CarScreen.Home
|
||||||
val seenHome = remember { booleanArrayOf(false) }
|
val seenHome = remember { booleanArrayOf(false) }
|
||||||
LaunchedEffect(onHome) {
|
LaunchedEffect(onHome) {
|
||||||
if (onHome && seenHome[0]) CarServices.nav.refreshSurface()
|
if (seenHome[0]) {
|
||||||
|
if (onHome) CarServices.nav.replaceDeadSurface() else CarServices.nav.renewSurface()
|
||||||
|
}
|
||||||
if (onHome) seenHome[0] = true
|
if (onHome) seenHome[0] = true
|
||||||
}
|
}
|
||||||
val splitScreen = phase == CarMedia.Phase.READY && now.isActive && panel != SidePanel.NONE
|
val splitScreen = phase == CarMedia.Phase.READY && now.isActive && panel != SidePanel.NONE
|
||||||
|
|||||||
@@ -455,31 +455,48 @@ class CarAppConnection(private val context: Context) {
|
|||||||
|
|
||||||
private val _surfaceEpoch = MutableStateFlow(0)
|
private val _surfaceEpoch = MutableStateFlow(0)
|
||||||
|
|
||||||
/** Bumped when the lent surface turns out to be dead, so the stage builds a fresh one. */
|
/** Bumped to throw the lent surface away, so the stage builds a fresh one. */
|
||||||
val surfaceEpoch: StateFlow<Int> = _surfaceEpoch.asStateFlow()
|
val surfaceEpoch: StateFlow<Int> = _surfaceEpoch.asStateFlow()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lends the app its surface again: called when the map comes back into view. An app that
|
* Lends the app a fresh surface: called as the map goes out of view, so the app has redrawn
|
||||||
* draws through its own VirtualDisplay (Organic Maps does) can be left pointing at a surface
|
* on the new one by the time it comes back. An app that draws through its own VirtualDisplay
|
||||||
* that has since died, and draws black until it's told about a live one. Taking the surface
|
* (Organic Maps does) can be left pointing at a surface that has since died, and draws black
|
||||||
* back and lending it again repoints it; a surface that has itself died is replaced.
|
* until it's told about a live one.
|
||||||
|
*
|
||||||
|
* Always a new surface, never the same one lent again: such an app (Flitsmeister does) builds
|
||||||
|
* its new display on the re-lent surface before releasing the old, and the old one's
|
||||||
|
* disconnect then takes the shared BufferQueue's connection with it - the map freezes on its
|
||||||
|
* last frame for good. The stage's key on [surfaceEpoch] swaps in a new SurfaceView, which
|
||||||
|
* lends itself as it comes up.
|
||||||
*/
|
*/
|
||||||
fun refreshSurface() {
|
fun renewSurface() {
|
||||||
main.post {
|
main.post {
|
||||||
val current = lent ?: return@post
|
val current = lent ?: return@post
|
||||||
if (!current.surface.isValid) {
|
GearslipLog.i("host: building a fresh surface as the map goes out of view")
|
||||||
GearslipLog.w("host: the lent surface died; building a new one")
|
replaceSurface(current)
|
||||||
lent = null
|
|
||||||
sendSurfaceDestroyed(current)
|
|
||||||
_surfaceEpoch.value = _surfaceEpoch.value + 1
|
|
||||||
return@post
|
|
||||||
}
|
|
||||||
GearslipLog.i("host: lending the surface again as the map comes back")
|
|
||||||
sendSurfaceDestroyed(current)
|
|
||||||
sendSurfaceAvailable()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called as the map comes back into view: replaces the surface only if it died while the map
|
||||||
|
* was covered, since a new one shows black until the app's next frame.
|
||||||
|
*/
|
||||||
|
fun replaceDeadSurface() {
|
||||||
|
main.post {
|
||||||
|
val current = lent ?: return@post
|
||||||
|
if (current.surface.isValid) return@post
|
||||||
|
GearslipLog.w("host: the lent surface died; building a new one")
|
||||||
|
replaceSurface(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceSurface(current: Lent) {
|
||||||
|
lent = null
|
||||||
|
sendSurfaceDestroyed(current)
|
||||||
|
_surfaceEpoch.value = _surfaceEpoch.value + 1
|
||||||
|
}
|
||||||
|
|
||||||
private fun sendSurfaceAvailable() {
|
private fun sendSurfaceAvailable() {
|
||||||
val callback = surfaceCallback ?: return
|
val callback = surfaceCallback ?: return
|
||||||
val surface = lent ?: return
|
val surface = lent ?: return
|
||||||
|
|||||||
Reference in new issue
Block a user