How to cancel a foreground service from using the notification (swipe dismiss) or clear all notifications?

d.moncada picture d.moncada · Oct 13, 2012 · Viewed 22.2k times · Source

I'm currently creating a foreground service with a notification that appears in the notification bar when the service starts. If the service stops, the notification dismisses. My question is, is there a way to stop the service when "clear all notifications" or a dismiss of the notification (swipe) occurs?

Updated to include implementation of notification:

public int onStartCommand(Intent intent, int flags, int startId)
{   
    Log.d(CLASS, "onStartCommand service started.");

    if (getString(R.string.service_start_action) == intent.getAction())
    {
        Intent intentForeground = new Intent(this, ServiceMain.class)
            .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);    
        PendingIntent pendIntent = PendingIntent.getActivity(getApplicationContext(), 0, intentForeground, 0);      
        Notification notification;
        Notification.Builder builder = new Notification.Builder(getApplicationContext())
            .setSmallIcon(android.R.drawable.btn_star)
            .setTicker("Service started...")
            .setContentIntent(pendIntent)
            .setDefaults(Notification.DEFAULT_ALL)
            .setOnlyAlertOnce(true)
            .setOngoing(false);
        notification = builder.build();
        notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;

        startForeground(SERV_NOTIFY, notification);
        player.start();
    }
    else
    {
        Log.d(CLASS, "onStartCommand unable to identify acition.");
    }

    return START_STICKY;        
}

Answer

Kevin Lee picture Kevin Lee · Mar 1, 2016

The user is not allowed to swipe away a notification generated by an ongoing foreground service.

Hence, stopForeground(false) first, which allows the notification to be swiped away by the user thereafter (at least on Lollipop+). For pre-Lollipop, you may have to stopForeground(true), which stops foreground and removes the notification, then re-issue the notification with notificationManager.notify(yourNotificationID, yourNotificationObject), so that your notification is visible but swipeable.

Crucially, set up the notification object with a delete intent that is triggered when the user swipes it away.

(new NotificationCompat.builder(this).setDeleteIntent(deletePendingIntent)).build()

where deletePendingIntent is something like

Intent deleteIntent = new Intent(this, YourService.class);
deleteIntent.putExtra(someKey, someIntValue);
PendingIntent deletePendingIntent = PendingIntent.getService(this,
someIntValue, 
deleteIntent, 
PendingIntent.FLAG_CANCEL_CURRENT);

When the user swipes it away, the intent with its extra is delivered to the service. Handle the delivered extra within onStartCommand, i.e. check that intent != null, intent.getExtras() != null, then extract the value from the extras bundle given someKey, and if it matches someIntValue, then call stopSelf().