How to dismiss notification after action has been clicked
Asked Answered
W

10

182

Since API level 16 (Jelly Bean), there is the possibility to add actions to a notification with

builder.addAction(iconId, title, intent);

But when I add an action to a notification and the action is pressed, the notification is not going to be dismissed. When the notification itself is being clicked, it can be dismissed with

notification.flags = Notification.FLAG_AUTO_CANCEL;

or

builder.setAutoCancel(true);

But obviously, this has nothing to with the actions associated to the notification.

Any hints? Or is this not part of the API yet? I did not find anything.

Wingfield answered 9/8, 2012 at 12:32 Comment(0)
F
189

When you called notify on the notification manager you gave it an id - that is the unique id you can use to access it later (this is from the notification manager:

notify(int id, Notification notification)

To cancel, you would call:

cancel(int id)

with the same id. So, basically, you need to keep track of the id or possibly put the id into a Bundle you add to the Intent inside the PendingIntent?

Fribble answered 9/8, 2012 at 13:15 Comment(9)
Thanks, that solved my issue. However, I still think it is a little bit over-complicated. Instead of just providing an API to auto-dismiss the notification when an action is pressed, you have to work with intent and notification id passing to achieve the same.Wingfield
If you think this is complicated, don't look into updating a notification (don't lose track of that id), or checking whether it's displayed or not (the api doesn't track it, you have to)... :PPushed
How did you do that @FleshWound ? Can you please supply me with your code? thanks!Celestinacelestine
@Daksh: Basically, you add the notification tag and id to your intent which gets started when your action is pressed. With that extra information, you can check in the starting activity whether it was started via a notifcation action.Wingfield
Code sample from onCreate(): Bundle extras = getIntent().getExtras(); if (extras != null) { String tag = extras.getString(NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt(NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); if (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals(tag)) { // activity has been started via notification action, dismiss // notification NotificationManager manager = (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE); manager.cancel(tag, id); } }Wingfield
my action is to Call a specific number. thus it opens up the Phone app and dials the number. so then how do i do it? is there a way to set up a listener for the call intent Intent.ACTION_DIAL and then check the data in the intent extras? if i'm on some sort of right path, then i would really appreciate code for that too!Celestinacelestine
@Celestinacelestine I would open up a new question for what you want to do. Tell people what you have tried and add other info like sample code they can correct.Fribble
This no longer works if setGroup is set to true and there is a group summary. In this case, the cancel somehow has no effect despite using correct idWilbanks
In new API you have notify(String tag, int id, Notification notification) and correspondingly cancel(String tag, int id)Subscribe
B
71

Found this to be an issue when using Lollipop's Heads Up Display notification. See design guidelines. Here's the complete(ish) code to implement.

Until now, having a 'Dismiss' button was less important, but now it's more in your face.

heads up notification

Building the Notification

int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
        .setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
        .setSmallIcon(R.drawable.ic_action_refresh) // Required!
        .setContentTitle("Message from test")
        .setContentText("message")
        .setAutoCancel(true)
        .addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
        .addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);

// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());

NotificationActivity

public class NotificationActivity extends Activity {

    public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
        finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
    }

    public static PendingIntent getDismissIntent(int notificationId, Context context) {
        Intent intent = new Intent(context, NotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.putExtra(NOTIFICATION_ID, notificationId);
        PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return dismissIntent;
    }

}

AndroidManifest.xml (attributes required to prevent SystemUI from focusing to a back stack)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>
Blockade answered 22/11, 2014 at 23:38 Comment(5)
i have multiple notifications from one application and the notifaaction are set to ongoing notification. I want to clear the notification when addaction performs on perticular notificationHaymo
Would it not be more effective to use a BroadcastReceiver here to dismiss the notification instead? Here is a good example that shows the implementation, but it can be even further reduced: https://mcmap.net/q/137730/-dismiss-ongoing-android-notification-via-action-button-without-opening-appIla
Solutions works, except the extras set are forwarded with the intent. They are not forwarded to onCreate. One way is to use static variables. Does anybody know, why the intent extras are not forwarded?Soiree
Why does getDismissIntent only work when placed in the NotificationActivity? The dismiss Intent does not work if the PendingIntent creation code is placed in the notification builder class. I just spent 2 hours on this issue and I cannot figure out why the Pending Intent MUST be created in the Activity. Can anyone explain why this is the case?Tattoo
getDismissIntent() is a static "helper" function that builds the correct Intent to use to communicate with the NotificationActivity. As such, these are usually bundled with the Activity. But I don't see why this static function could not be placed in the notification builder class, as long as you are careful to set the NOTIFICATION_ID and context correctly.Strainer
B
20

I found that when you use the action buttons in expanded notifications, you have to write extra code and you are more constrained.

You have to manually cancel your notification when the user clicks an action button. The notification is only cancelled automatically for the default action.

Also if you start a broadcast receiver from the button, the notification drawer doesn't close.

I ended up creating a new NotificationActivity to address these issues. This intermediary activity without any UI cancels the notification and then starts the activity I really wanted to start from the notification.

I've posted sample code in a related post Clicking Android Notification Actions does not close Notification drawer.

Benedikt answered 14/2, 2014 at 15:36 Comment(2)
Too bad they still haven't baked this into the API... It's pretty hackish to do it like this. But still the only way, especially if you don't have any control over the destination intent, like viewing a URL.Fragile
Thanks for the info, you're correct. However I would use an intentservice rather than an intermediary activityBertine
S
10

In new APIs don't forget about TAG:

notify(String tag, int id, Notification notification)

and correspondingly

cancel(String tag, int id) 

instead of:

cancel(int id)

https://developer.android.com/reference/android/app/NotificationManager

Subscribe answered 14/11, 2018 at 11:2 Comment(1)
You were right! although cancel() function has 2 implementations; one with TAG and one without. But we have to provide a TAG. Here is cancel function from docs public void cancel(@Nullable String tag, int id). Last checked on Android QMalinowski
U
10

You will need to run the following code after your intent is fired to remove the notification.

NotificationManagerCompat.from(this).cancel(null, notificationId);

NB: notificationId is the same id passed to run your notification

Unwearied answered 28/4, 2020 at 15:0 Comment(0)
M
9

In my opinion using a BroadcastReceiver is a cleaner way to cancel a Notification:

In AndroidManifest.xml:

<receiver 
    android:name=.NotificationCancelReceiver" >
    <intent-filter android:priority="999" >
         <action android:name="com.example.cancel" />
    </intent-filter>
</receiver>

In java File:

Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);

NotificationCompat.Action actions[] = new NotificationCompat.Action[1];

NotificationCancelReceiver

public class NotificationCancelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Cancel your ongoing Notification
    };
}
Mutton answered 2/8, 2015 at 14:24 Comment(6)
That's what I do but how do you get the notification ID (in this example, 0) from the onReceive method? It's not in the Intent, since it's not been added to it. I tried adding it as an extra but it seems like the real notification ID is not the one I was adding as an extra in the creating activity... :-/Fard
I really like this approach of using Broadcast services instead of Activities, it is much lighter approach imho.Anthonyanthophore
But I had to use <intent.setAction(Integer.toString(notificationId));> in adidition to be able to dismiss any of the notification shown.Anthonyanthophore
@MarcoZanetti you need to generate a notification id that you pass to the pending intent and also to the notify method when sending the notification. If you do that, then when user clicks the action to cancel it will call the broadcast receiver and then you can get the notification id from the extras.Washburn
@ChristopheMoine you can put id via intent.putExtra() and get it in BroadcastReceiverSutphin
This sucks - it means every action in a notification needs to be captured by my app when the user wants to do something, i.e. [SHARE]Undergird
A
7

You can always cancel() the Notification from whatever is being invoked by the action (e.g., in onCreate() of the activity tied to the PendingIntent you supply to addAction()).

Alcaraz answered 9/8, 2012 at 12:44 Comment(6)
But how do I get access to the notification in the activity which has been called?Wingfield
@FleshWound: cancel() takes the ID of the Notification, which you used when you called notify(). You do not need the Notification object.Alcaraz
@Alcaraz cancel(id) has stopped working if the setGroup is set and there is a Group summary notification. In this case, the cancel does not do anything for some reason. Without the group summary, cancel works fine thoughWilbanks
if my pending intent is ACTION_VIEW and the type is image/jpeg (to share an image with another app) then how is that cancel supposed to be triggered ? IMO Android should auto-cancel, I'm puzzled as to why Android doesn't just take care of it ?!Undergird
@SomeoneSomewhere: "then how is that cancel supposed to be triggered ?" -- it can't. While there is nothing stopping you from pointing to a third-party app in a Notification-related PendingIntent, that's not really how it was designed to work, and so you will run into issues like this one. "IMO Android should auto-cancel" -- I could see offering a flag for that on the action, but it should not be an all-the-time thing. If it were, skipping a track in a music player notification would close the notification.Alcaraz
What I've ended up implementing is: notification Action triggers IntentService, that IntentService cancels the notification and either 1) creates a new intent and triggers the intent chooser or 2) performs a specific action within the appUndergird
W
7

Just put this line :

 builder.setAutoCancel(true);

And the full code is :

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
    builder.setContentTitle("Notifications Title");
    builder.setContentText("Your notification content here.");
    builder.setSubText("Tap to view the website.");
    Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    builder.setAutoCancel(true);
    // Will display the notification in the notification bar
    notificationManager.notify(1, builder.build());
Womanize answered 13/3, 2018 at 13:14 Comment(4)
AutoCancel seems to have no effect when targetting Android 9 (worked fine when targetting Android 8.1)Valine
the distinction here is with action'sUndergird
Tested on API 24, 27, 30, 31 and the notification does indeed close after clicking on it.Coadjutrix
The weird thing is that in some project I work on, the action does get to dismiss the notification in some place in code, and doesn't do it in another place.Apology
A
3

Just for conclusion:

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

Intent intent = new Intent(context, MyNotificationReceiver.class);
intent.putExtra("Notification_ID", 2022);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            intent,
            ...);

Notification notification = new NotificationCompat.Builder(...)
...    
.addAction(0, "Button", pendingIntent)
.build();

notificationManager.notify(2022, notification);

and for dismiss the notification, you have two options:

approach 1: (in MyNotificationReceiver)

NotificationManager manager = (NotificationManager)
            context.getSystemService(NOTIFICATION_SERVICE);
    manager.cancel(intent.getIntExtra("Notification_ID", -1));

approach 2: (in MyNotificationReceiver)

NotificationManagerCompat manager = NotificationManagerCompat.from(context);
manager.cancel(intent.getIntExtra("Notification_ID", -1));

and finally in manifest:

<receiver android:name=".MyNotificationReceiver" />
Adust answered 8/4, 2022 at 10:45 Comment(0)
U
-3

builder.setAutoCancel(true);

Tested on Android 9 also.

Unprintable answered 9/4, 2020 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.