From 40086e061b4ccbf63758745e56477e77347e549d Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Thu, 8 Oct 2026 00:06:34 -0700 Subject: [PATCH] audio pause when unplugged, theme tweak --- .../gearslip/GearslipActivity.kt | 2 ++ .../seb3thehacker/gearslip/car/CarServices.kt | 26 +++++++++++++++++++ .../gearslip/car/theme/GsHoldMarker.kt | 5 +++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipActivity.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipActivity.kt index d9a3efe..41010b5 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipActivity.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipActivity.kt @@ -338,6 +338,8 @@ class GearslipActivity : ComponentActivity(), Projection { } override fun onProjectionStopped() { + // Before the car UI goes, while the media connection is still up. + app.seb3thehacker.gearslip.car.CarServices.pausePhoneMedia() runOnUiThread { PhoneMirror.requestStop() app.seb3thehacker.gearslip.car.CarKeys.focusSink = null diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt index cee0059..5f02ea4 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt @@ -200,6 +200,32 @@ object CarServices { return playingPackages.firstNotNullOfOrNull { pkg -> catalog.firstOrNull { it.component.packageName == pkg } } } + /** + * The car went away mid-song: pause it, as Android Auto does, so it doesn't carry on out of + * the phone's speaker. Unplugging a USB accessory isn't "audio becoming noisy" the way + * headphones are, so the apps won't pause themselves. Every playing session is paused, not + * just the one Gearslip opened: anything the car was playing was going through the car. + */ + fun pausePhoneMedia() { + val ctx = context ?: return + val manager = ctx.getSystemService(MediaSessionManager::class.java) + val listener = ComponentName(ctx, GearslipNotificationListener::class.java) + val playing = try { + manager.getActiveSessions(listener).filter { it.playbackState?.state == PlaybackState.STATE_PLAYING } + } catch (e: SecurityException) { + null + } + if (playing == null) { + // No notification access: the app Gearslip itself is driving is all it can reach. + mediaOrNull()?.let { if (it.now.value.playing) it.togglePlay() } + return + } + playing.forEach { runCatching { it.transportControls.pause() } } + if (playing.isNotEmpty()) { + app.seb3thehacker.gearslip.GearslipLog.i("media: paused ${playing.joinToString { it.packageName }} as the car left") + } + } + /** The car went away: nothing should keep running for a screen that no longer exists. */ fun shutdown() { context?.let { app.seb3thehacker.gearslip.notify.CarMotion.stop(it) } diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/theme/GsHoldMarker.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/theme/GsHoldMarker.kt index 44cafd3..7488389 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/theme/GsHoldMarker.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/theme/GsHoldMarker.kt @@ -50,6 +50,8 @@ enum class HoldMarkerStyle { * colour, so the peel's flap matches whatever it sits on. Round and pill-shaped controls get the * dot whatever the theme says: a circle has no corner to peel. */ +private const val SHOW_HOLD_DOT = false + @Composable internal fun BoxScope.GsHoldMarker(style: HoldMarkerStyle, container: Color, shape: Shape, press: InteractionSource) { if (style == HoldMarkerStyle.NONE) return @@ -68,8 +70,9 @@ internal fun BoxScope.GsHoldMarker(style: HoldMarkerStyle, container: Color, sha val side = min(size.width, size.height) val r = (shape as? CornerBasedShape)?.topEnd?.toPx(size, this) ?: 0f val round = r >= side * 0.4f + // The dot is off until it's redesigned: flat themes and round controls show nothing. if (style == HoldMarkerStyle.DOT || round) { - drawHoldDot(r, side, ink) + if (SHOW_HOLD_DOT) drawHoldDot(r, side, ink) } else { // Drawn for the bottom-right corner, then flipped up to the top-right. scale(1f, -1f, pivot = center) {