mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
Merge branch 'pr-5' into try-pr-5
Fix map loading by drawing a virtual display.
This commit is contained in:
commit
473c12ad8f
2 files changed
+47
-7
No files matched your search
@@ -89,6 +89,28 @@ private fun AppSurface(
|
||||
}
|
||||
}
|
||||
|
||||
// A fresh SurfaceView - and so a fresh Surface - for every size, the way Android Auto hands an
|
||||
// app a new surface rather than resizing the old one. A resized SurfaceView keeps the same
|
||||
// BufferQueue, and apps that draw through their own VirtualDisplay build the
|
||||
// new one on it before releasing the old: the old display's disconnect then takes the new one's
|
||||
// connection with it and the map freezes for good. The nav bar hiding for the search keyboard
|
||||
// and the lyrics pane opening both resize this area.
|
||||
androidx.compose.foundation.layout.BoxWithConstraints(modifier) {
|
||||
androidx.compose.runtime.key(constraints.maxWidth, constraints.maxHeight) {
|
||||
SurfaceHost(connection, frame, onSize = { size = it }, Modifier.fillMaxSize())
|
||||
}
|
||||
}
|
||||
|
||||
DisposableEffect(connection) { onDispose { connection.detachSurface() } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SurfaceHost(
|
||||
connection: CarAppConnection,
|
||||
frame: CarEnvironment.Frame,
|
||||
onSize: (Pair<Int, Int>) -> Unit,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
AndroidView(
|
||||
modifier = modifier
|
||||
.pointerInput(connection) {
|
||||
@@ -114,20 +136,20 @@ private fun AppSurface(
|
||||
height: Int,
|
||||
) {
|
||||
GearslipLog.i("stage: surface ready at ${width}x$height")
|
||||
size = width to height
|
||||
onSize(width to height)
|
||||
connection.attachSurface(holder.surface, width, height, frame.densityDpi)
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
GearslipLog.i("stage: surface destroyed")
|
||||
connection.detachSurface()
|
||||
// Only this view's own surface: a replaced view's teardown can land after
|
||||
// its successor has already lent the app a new one.
|
||||
connection.detachSurface(holder.surface)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
DisposableEffect(connection) { onDispose { connection.detachSurface() } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -139,8 +139,19 @@ class CarAppConnection(private val context: Context) {
|
||||
// Replaced by another connect (or a disconnect) while waiting on the location service.
|
||||
if (binding !== connection) return@bind
|
||||
var bindError: Throwable? = null
|
||||
val flags = Context.BIND_AUTO_CREATE or LocationKeepAlive.BIND_INCLUDE_CAPABILITIES
|
||||
val bound = runCatching {
|
||||
context.bindService(intent, connection, Context.BIND_AUTO_CREATE or LocationKeepAlive.BIND_INCLUDE_CAPABILITIES)
|
||||
// Without BIND_FOREGROUND_SERVICE, an app bound by a foreground service (which is
|
||||
// all Gearslip is once the phone screen leaves it) only reaches "important
|
||||
// foreground", and that state loses network under Doze and background network
|
||||
// restrictions: the map and GPS keep working while search and routing go dead.
|
||||
// In the preview Gearslip is the top app, which hides this. Retried without the
|
||||
// flag in case a build of Android refuses it from an unprivileged caller.
|
||||
runCatching { context.bindService(intent, connection, flags or BIND_FOREGROUND_SERVICE) }
|
||||
.getOrElse {
|
||||
GearslipLog.w("host: foreground binding refused (${it.message}); binding without it")
|
||||
context.bindService(intent, connection, flags)
|
||||
}
|
||||
}.getOrElse {
|
||||
GearslipLog.e("bindService threw for ${app.component}", it)
|
||||
bindError = it
|
||||
@@ -428,10 +439,14 @@ class CarAppConnection(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Takes the Surface back, e.g. when the SurfaceView goes away. */
|
||||
fun detachSurface() {
|
||||
/**
|
||||
* Takes the Surface back, e.g. when the SurfaceView goes away. With [surface], only if that is
|
||||
* still the one lent - a replaced view's teardown must not take back its successor's.
|
||||
*/
|
||||
fun detachSurface(surface: Surface? = null) {
|
||||
main.post {
|
||||
val current = lent ?: return@post
|
||||
if (surface != null && current.surface !== surface) return@post
|
||||
lent = null
|
||||
sendSurfaceDestroyed(current)
|
||||
update { it.copy(surfaceAttached = false) }
|
||||
@@ -714,5 +729,8 @@ class CarAppConnection(private val context: Context) {
|
||||
private companion object {
|
||||
/** The newest template API this host claims to understand. */
|
||||
const val HOST_API_LEVEL = CarAppApiLevels.LEVEL_8
|
||||
|
||||
/** Context.BIND_FOREGROUND_SERVICE; the constant itself is hidden from the SDK. */
|
||||
const val BIND_FOREGROUND_SERVICE = 0x04000000
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user