Repository navigation
Enforce using foreground service during playback - #5563
Conversation
|
Claude finished @sztomek's task in 4m 25s —— View job PR Review: Enforce using foreground service during playbackSolid, well-scoped change — the suspend gate + shared 🔴 Correctness
🟡 Worth verifying / polish
🟢 Minor notes
✅ Looks good
|
| val mediaSession = playbackManager.mediaSessionManager.mediaSession ?: return | ||
| try { | ||
| val notification = notificationDrawer.buildPreparingNotification(mediaSession.sessionToken) | ||
| ServiceCompat.startForeground(this, Settings.NotificationId.PLAYING.value, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) |
|
Version |
|
Version |
|
Version |
|
Version |
|
Version |
0d70013 to
3c25184
Compare
|
Claude finished @sztomek's task in 1m 0s —— View job Re-review (rebase push)This push is a rebase onto current Blocking
Non-blocking
|
|
Claude finished @sztomek's task in 1m 24s —— View job Re-review (new commit since 21 Sep)One new commit since my last pass: Blocking
Non-blocking
|
2e738c9 to
187d8b3
Compare
|
Claude finished @sztomek's task in 2m 40s —— View job Re-review (rebase onto current
|
| val session = playbackManager.mediaSessionManager.getMedia3Session() | ||
| try { | ||
| val title = playbackManager.getCurrentEpisode()?.title ?: getString(LR.string.loading) | ||
| val builder = NotificationCompat.Builder(this, Settings.NotificationChannel.NOTIFICATION_CHANNEL_ID_PLAYBACK.id) |
There was a problem hiding this comment.
Could this notification be built in NotificationDrawer instead of inline? This PR already adds NotificationDrawer.buildPreparingNotification() for LegacyPlaybackService, so the two services currently build their preparing notification in different ways. An overload that takes the Media3 MediaSession and a title would keep them together, and it could use notificationHelper.playbackChannelBuilder() rather than hard-coding the channel ID.
There was a problem hiding this comment.
valid, addressed it!
|
Version |
|
Claude finished @sztomek's task in 1m 4s —— View job Re-review (1 new commit)The one new commit,
Still not plumbed: a refusal thrown inside the service doesn't reach the check in |
|
Version |
2b4e2c1 to
622b242
Compare
|
Claude finished @sztomek's task in 29s —— View job Re-review (rebase + 1 new commit)I found nothing new to flag, and none of the earlier findings are still open. This push is a rebase onto current |
|
Claude finished @sztomek's task in 28s —— View job Re-review (1 new commit)The one new commit since my last pass, |
| val session = playbackManager.mediaSessionManager.getMedia3Session() | ||
| try { | ||
| val notification = notificationDrawer.buildPreparingNotification(session, playbackManager.getCurrentEpisode()?.title) | ||
| ServiceCompat.startForeground(this, Settings.NotificationId.PLAYING.value, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) |
Description
Android 17 blocks background audio unless a foreground service is already running. We did it the other way round: we asked for audio focus and started the player first, and the service only went foreground after that. So background plays got their focus request denied, and we stopped playback.
This PR starts the foreground service before we ask for focus. It sits behind the
FOREGROUND_BEFORE_PLAYBACKflag.What's in here:
PlaybackManager.play(). It starts the service, waits for it to reach foreground, and only then do we ask for focus.isServiceForegroundsignal.Testing Instructions
Tested on a Pixel 9 Pro on Android 17 (API 37). Hardening is already on by default there, so there's no setup.
One gotcha:
adb shell cmd audio set-enable-hardeningdoes nothing on a production build. It exits 0 but never changes anything. To test the stricter targetSdk 37 rules, build withtargetSdkVersion = 37instead.MEDIA3_SESSIONoff and repeat. This path matters more, because it drops the foreground service on pause.adb shell dumpsys audioand look for AudioHardening lines with our package. There should be none.What I checked:
Still not covered: Automotive, Wear, TV, and Chromecast on a real device.
One thing this can't fix: if the app process is cached, the system refuses the foreground service outright. We can't start one. We now fail cleanly instead of killing playback, but the audio still won't play.
Screenshots or Screencast
n/a, no UI changes.
Checklist
./gradlew spotlessApplyautomatically applies formatting/linting)modules/services/localization/src/main/res/values/strings.xmlI tested any UI changes...