mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 00:12:24 +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(
|
AndroidView(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.pointerInput(connection) {
|
.pointerInput(connection) {
|
||||||
@@ -114,20 +136,20 @@ private fun AppSurface(
|
|||||||
height: Int,
|
height: Int,
|
||||||
) {
|
) {
|
||||||
GearslipLog.i("stage: surface ready at ${width}x$height")
|
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)
|
connection.attachSurface(holder.surface, width, height, frame.densityDpi)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
GearslipLog.i("stage: surface destroyed")
|
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
|
@Composable
|
||||||
|
|||||||
@@ -139,8 +139,19 @@ class CarAppConnection(private val context: Context) {
|
|||||||
// Replaced by another connect (or a disconnect) while waiting on the location service.
|
// Replaced by another connect (or a disconnect) while waiting on the location service.
|
||||||
if (binding !== connection) return@bind
|
if (binding !== connection) return@bind
|
||||||
var bindError: Throwable? = null
|
var bindError: Throwable? = null
|
||||||
|
val flags = Context.BIND_AUTO_CREATE or LocationKeepAlive.BIND_INCLUDE_CAPABILITIES
|
||||||
val bound = runCatching {
|
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 {
|
}.getOrElse {
|
||||||
GearslipLog.e("bindService threw for ${app.component}", it)
|
GearslipLog.e("bindService threw for ${app.component}", it)
|
||||||
bindError = 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 {
|
main.post {
|
||||||
val current = lent ?: return@post
|
val current = lent ?: return@post
|
||||||
|
if (surface != null && current.surface !== surface) return@post
|
||||||
lent = null
|
lent = null
|
||||||
sendSurfaceDestroyed(current)
|
sendSurfaceDestroyed(current)
|
||||||
update { it.copy(surfaceAttached = false) }
|
update { it.copy(surfaceAttached = false) }
|
||||||
@@ -714,5 +729,8 @@ class CarAppConnection(private val context: Context) {
|
|||||||
private companion object {
|
private companion object {
|
||||||
/** The newest template API this host claims to understand. */
|
/** The newest template API this host claims to understand. */
|
||||||
const val HOST_API_LEVEL = CarAppApiLevels.LEVEL_8
|
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