How to dismiss notification after action has been clicked

125,376

Solution 1

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?

Solution 2

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>

Solution 3

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.

Solution 4

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

Solution 5

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
    };
}
Share:
125,376

Related videos on Youtube

endowzoner
Author by

endowzoner

I'm curious about any kind of innovation in the area of mobile computing as well as great products using web and mobile technologies. As the mobile world cannot be reduced to one platform and there is not one kind of mobile technology at all, I'm open-minded for new and alternative evolutions and do not focus on only one specific technology. Therefore, I'm also highly interested in the international technology start-up scene. I admire everyone who comes up with a great new idea and product and brings it to the market successfully. Currently, in my rare spare time I'm trying to get into great presentation techniques and improve my presentation skills. I think having a great idea is one part, but presenting it accordingly and to the right people is even more important than the ideal itself.

Updated on April 09, 2022

Comments

  • endowzoner
    endowzoner about 2 years

    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.

  • endowzoner
    endowzoner almost 12 years
    But how do I get access to the notification in the activity which has been called?
  • endowzoner
    endowzoner almost 12 years
    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.
  • CommonsWare
    CommonsWare almost 12 years
    @FleshWound: cancel() takes the ID of the Notification, which you used when you called notify(). You do not need the Notification object.
  • Travis
    Travis over 11 years
    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)... :P
  • Daksh
    Daksh over 11 years
    How did you do that @FleshWound ? Can you please supply me with your code? thanks!
  • endowzoner
    endowzoner over 11 years
    @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.
  • endowzoner
    endowzoner over 11 years
    Code sample from onCreate(): Bundle extras = getIntent().getExtras(); if (extras != null) { String tag = extras.getString(NotificationReceiver.INTENT_EXTRA_NOTIFICAT‌​ION_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); } }
  • Daksh
    Daksh over 11 years
    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!
  • Kaediil
    Kaediil over 11 years
    @Daksh 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.
  • Prasad
    Prasad about 9 years
    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 notification
  • Bogdan Zurac
    Bogdan Zurac about 9 years
    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.
  • alice.harrison
    alice.harrison about 9 years
    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: stackoverflow.com/a/19745745/793150
  • Baschi
    Baschi over 8 years
    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?
  • Tim
    Tim about 8 years
    Thanks for the info, you're correct. However I would use an intentservice rather than an intermediary activity
  • Marco Zanetti
    Marco Zanetti about 8 years
    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... :-/
  • Christophe Moine
    Christophe Moine over 7 years
    I really like this approach of using Broadcast services instead of Activities, it is much lighter approach imho.
  • Christophe Moine
    Christophe Moine over 7 years
    But I had to use <intent.setAction(Integer.toString(notificationId));> in adidition to be able to dismiss any of the notification shown.
  • Ray Li
    Ray Li about 7 years
    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?
  • Ray Hunter
    Ray Hunter almost 7 years
    @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.
  • Kushan
    Kushan over 6 years
    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 id
  • Kushan
    Kushan over 6 years
    @CommonsWare 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 though
  • Mike
    Mike about 6 years
    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.
  • Malachiasz
    Malachiasz over 5 years
    In new API you have notify(String tag, int id, Notification notification) and correspondingly cancel(String tag, int id)
  • Alix
    Alix about 5 years
    AutoCancel seems to have no effect when targetting Android 9 (worked fine when targetting Android 8.1)
  • Vadim Kotov
    Vadim Kotov almost 5 years
    @ChristopheMoine you can put id via intent.putExtra() and get it in BroadcastReceiver
  • sud007
    sud007 about 4 years
    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 Q
  • Someone Somewhere
    Someone Somewhere almost 4 years
    the distinction here is with action's
  • Someone Somewhere
    Someone Somewhere almost 4 years
    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]
  • Someone Somewhere
    Someone Somewhere almost 4 years
    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 ?!
  • CommonsWare
    CommonsWare almost 4 years
    @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.
  • Someone Somewhere
    Someone Somewhere almost 4 years
    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 app
  • DIRTY DAVE
    DIRTY DAVE over 2 years
    Tested on API 24, 27, 30, 31 and the notification does indeed close after clicking on it.