From 206dd67d98e20cec0f71f38d0b9f94ea72d7f4cd Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Wed, 4 Nov 2026 22:15:39 -0800 Subject: [PATCH] Music started again after the car left is paused again Deezer sometimes carried on out of the phone's speaker after the car was turned off. Apps that are buffering are paused too, and two seconds later any that started by themselves are paused again. --- .../seb3thehacker/gearslip/car/CarServices.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) 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 502fdae..7f83dc2 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/CarServices.kt @@ -31,6 +31,11 @@ object CarServices { private var context: Context? = null + /** Buffering counts as playing: an app between songs is about to make sound again. */ + private val PLAYING_STATES = setOf(PlaybackState.STATE_PLAYING, PlaybackState.STATE_BUFFERING) + /** How long after pausing for the car leaving to look again for an app that started by itself. */ + private const val REPAUSE_MS = 2_000L + val nav: CarAppConnection by lazy { CarAppConnection(requireNotNull(context)) } val media: CarMedia by lazy { CarMedia(requireNotNull(context)) } @@ -253,11 +258,22 @@ object CarServices { * 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. + * An app can start again on its own once the speaker is given back a moment later, which a + * Deezer driver heard after turning the car off (issue #39), so the ones it paused are + * looked at once more and paused again if they're playing. */ fun pausePhoneMedia(why: String = "the car left") { pausedForNow = null pausedOwnForNow = false - pause(why) + val paused = pause(why) + if (paused.isEmpty()) return + android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({ + val again = paused.filter { it.playbackState?.state in PLAYING_STATES } + again.forEach { runCatching { it.transportControls.pause() } } + if (again.isNotEmpty()) { + app.seb3thehacker.gearslip.GearslipLog.i("media: paused ${again.joinToString { it.packageName }} again: it started by itself after $why") + } + }, REPAUSE_MS) } /** What [pausePhoneMediaForNow] paused, for [resumePhoneMedia] to play again. */ @@ -293,7 +309,7 @@ object CarServices { 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 } + manager.getActiveSessions(listener).filter { it.playbackState?.state in PLAYING_STATES } } catch (e: SecurityException) { null }