4

I have a music control notification that allows the user to start/stop the music. I want exactly the same behavior than the Google Play Music app notification: when music is playing, the service is in foreground and the notification not cancelable, and when the music is not playing the service is not in the foreground anymore and the notification can be removed. It works fine but when I cancel the foreground of my service, the notification is quickly removed before reappearing just after.

Here's my code, first how I build the notification:

NotificationCompat.Builder notifBuilder =
            new android.support.v7.app.NotificationCompat.Builder(getApplicationContext())
                    .setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
                            .setShowActionsInCompactView(1, 2, 3)
                            .setShowCancelButton(true)
                            .setCancelButtonIntent(deletePendingIntent)))
                    .setSmallIcon(R.drawable.notif_logo)
                    .setColor(ResourcesCompat.getColor(getResources(), R.color.blue, getTheme()))
                    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                    .setShowWhen(false);

    notifBuilder.setContentIntent(pendingIntent);
    notifBuilder.setDeleteIntent(deletePendingIntent);

And here is how I start and update my notification:

private void showNotification(NotificationCompat.Builder notifBuilder, boolean foreground) {
    if (foreground) {
        startForeground(NOTIFICATION_ID, notifBuilder.build());
    } else {
        stopForeground(false);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICATION_ID, notifBuilder.build());
    }
}

If I use stopForeground(false), the notification is still not cancelable after running it. If I use stopForeground(true), the notification is quickly removed then added again which give a weird blinking.

How can I have a notification that is cancelable after a service quit being in foreground, without having to remove then add again the notification?

MickaelG
  • 326
  • 3
  • 16

1 Answers1

8

Per the Using MediaStyle notifications with a foreground service documentation:

In Android 5.0 (API level 21) and later you can swipe away a notification to stop the player once the service is no longer running in the foreground. You can't do this in earlier versions. To allow users to remove the notification and stop playback before Android 5.0 (API level 21), you can add a cancel button in the upper-right corner of the notification by calling setShowCancelButton(true) and setCancelButtonIntent().

You never need to call setOngoing(false)/setOngoing(true) as that is controlled by whether your service is currently in the foreground.

As per the Media Session Callbacks docs, you should be called stopForeground(false) when your music gets paused - this remove the foreground priority and allows users to swipe the notification away on API 21+ devices.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Hi, thanks for your response. stopForeground(false) is the first thing I tried but it doesn't work, the notification is still not cancelable/cannot be swiped after running it. I'm testing on a API 25 device. I updated the code and last part of my question. – MickaelG Apr 25 '17 at 09:39
  • Do you see the same behavior on an emulator or Nexus/Pixel device? – ianhanniballake Apr 25 '17 at 21:43
  • Finally found the bug! For stopForeground(false) to works as intended, I need to target version 21 or more. I was targeting version 20. I created a minimalist project that reproduce the bug: https://github.com/MickaelGuilbeaud/AndroidForegroundNotification I was not expecting targetSdkVersion 21 to be mandatory when I use NotificationCompat. – MickaelG May 04 '17 at 07:53
  • Once stopForeground(false) is called, the service seems to get cleaned up by the OS within a minute or two and the notification disappears. That sounds reasonable enough as it is no longer in the foreground and nothing is bound to it, however other music streaming apps are able to keep the notification alive and cancellable indefinitely - what are they doing differently? – user888867 Feb 21 '20 at 21:10
  • 2
    @user888867 - they're probably using [ServiceCompat.stopForeground](https://developer.android.com/reference/androidx/core/app/ServiceCompat.html#stopForeground(android.app.Service,%20int)) with [STOP_FOREGROUND_DETACH](https://developer.android.com/reference/androidx/core/app/ServiceCompat.html#STOP_FOREGROUND_DETACH) which allows the notification to remain even when the service is destroyed. – ianhanniballake Feb 21 '20 at 21:13