Marcin Adamczewski
Marcin Adamczewski

Reputation: 191

How to make notification dismissible when playing music in background like in Spotify and Google Music

Spotify and Google Music allows a user to play music in background allowing also the media notification to be dismissible. When you move one of these apps to background, then pause the playback, you are able to dismiss the media notification. However if you don't dismiss the notification, so it is left in paused state for long time, the System won't kill the "audio service" as the notification is always visible and immediately react to play/pause.

As far as I know it is not possible using foreground services as in order to dismiss the notification, we'd need to call stopForeground(false), which would let system to kill the service.

Here is how we do it right now, in our app:

When playback is started, we run MusicService as a foreground service with following code:

startForeground(mediaNotification)

Then, when user leave the app, he is able to control the playback via media notification. As the notification is tightly coupled with the MusicService, user won't be able to dismiss it until we call:

stopForeground(false)

That's why we call this method when user press pause button. However this makes a Service background, so system will kill it in short period of time.

How Spotify and Google Music could workaround it? What is the way to achieve it?

Upvotes: 3

Views: 2889

Answers (5)

Mayb3Not
Mayb3Not

Reputation: 480

I have tried using flag STOP_FOREGROUND_DETACH for stopForeground() and it seems to work, allowing the notification to be swiped while not clearing the notification by OS after a while.

Upvotes: 0

Victor Cold
Victor Cold

Reputation: 653

Did you tried to use

NotificationCompat.Builder()
...
.setOngoing(true)
...
.build()

?

Should do the trick.

Actually, you don't need to stop your foreground. Just use this setting. When you want to change this - just build new Notification with ongoing == false and then call it like:

notificationManager.notify( id, yourNotification )

Upvotes: 1

Christian Boler
Christian Boler

Reputation: 161

Using a combination of Pouya's answer and some independent research, I have a code snippet that behaves fairly close to apps like Spotify using the OOTB MediaPlayer. There is probably a more elegant solution, but this is the quick and dirty version - I have too much code scattered about to post, so have an overview instead:

When the mediaplayer is paused, I run two pieces of code. First, after updating the notification bar I demote it from a foreground service to a background one with:

public void demoteNotifyBar() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            stopForeground(STOP_FOREGROUND_DETACH);
        else
            stopForeground(false);
    }

and then I start a new timer, that remakes the notification bar once a second:

// Put this in the onCreate method
pauseRefresh = new Runnable() {
            @Override
            public void run() {
                // Check if media is playing to prevent race conditions
                if (!isPlaying()) {
                    startForeground(FOREGROUND_SERVICE, notification);
                    demoteNotifyBar();
                    handler.postDelayed(pauseRefresh, 1000);
                }
            }
        };

// Call this wherever you're handling the pause button
pauseRefresh.run();

To cancel the auto-refresh, you'll need to call this bit of code before you remake the notification bar and toggle the media from pause to playing (yes, you can ignore this for toggling audio, but read below for why this is needed):

handler.removeCallbacks(pauseRefresh);

You will also need to listen for the swipe dismiss with a delete intent, to prevent the notification from remaking itself when the user dismisses it; simply use the same code to cancel the timer that is used when the user clicks play.

Upvotes: 3

Pouya Danesh
Pouya Danesh

Reputation: 1627

I think you can have a timer in your service that restarts your service after a while if the user stopped the music your timer will keep it from dying and if the user clicked play button do as what you already do before.

Upvotes: 2

Jigar Fumakiya
Jigar Fumakiya

Reputation: 2319

so you want when another application is playing their music you want your notification dismissable Right. you need to do is when you create notification (I guess in Mediaprepare() or click or something else), when you create the notification you set builder.setOngoing(true), and when you user pauses music or other application use media service you set builder.setOngoing(false) so user can easily dismiss your notification.

Happy Coding

Upvotes: 0

Related Questions