I am working on a media app. I wonder how I can keep some old behavior my app has prior to Oreo, for example, have the notification and the service (for playback) hang in there even if the service is no longer set to foreground.
We call startService(MediaPlaybackService.class) to start the service when playback starts, then create a notification and call startForeground() with it on the service. So far so good - if user exits the app, user will still have media play in the background and can control the playback from the notification.
When user pauses playback, we call stopForeground(false) to make the notification dismissible. Here comes the problem, since Android Oreo, the system prevents starting non-foreground services and stops the running ones. In my case, on pausing playback, service becomes non-foreground and is subject to be stopped by system. And since it's like a proper stopSelf() call, setting onStartCommand() to return "START_STICKY" doesn't seem to help deliver another start call to the service, and most likely won't work even if it does because the app is still in background.
It looks like it's working for Spotify - their notification stays indefinitely when playback is paused; and the notification is dismissible so I figured it's not set to foreground. Wonder how it works for Spotify?
Here is some sample code:
class MyService extends MediaBrowserServiceCompat implements PlayerStateListener {
public int onStartCommand(...) {
//....
return START_STICKY;
}
void onPlaybackStarts() {
makeServiceStart(); // handles before and after 26
Notification notif = buildNotif();
startForeground(NOTIF_ID, notif); // non-zero value
}
void onPlaybackStops() {
// if app is in background at this point, system will stop the service short after the line below.
stopForeground(false);
if (state == Player.IDLE) {
stopSelf();
}
}
}
onPlaybackStarts()
/onPlaybackStops()
is called fromonPlay()
/onStop()
as per the callbacks guide. – CownNotification
can then start the service via agetForegroundService()
PendingIntent
, if the user taps the action (or whatever) you have in thatNotification
to resume playback. – RemaremainonDestroy()
you should still be releasing yourMediaSessionCompat
). See the source of MediaButtonReceiver - it connects viaMediaBrowserCompat
, binding to yourMediaBrowserServiceCompat
. That temporarily will create your Service if it isn't already running, allowing you to handle the media button. – Cown