Notification setAutoCancel(true) doesn't work if clicking on Action
I have a notification with an action within it. When I tap on the notification it gets removed from the list. However, when I click on the Action it successfully completes the Action (namely makes a call), but when I return to the list of notifications, it remains there.
Relative code of the AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver {
Meeting meeting;
/**
* Handle received notifications about meetings that are going to start
*/
#Override
public void onReceive(Context context, Intent intent) {
// Get extras from the notification intent
Bundle extras = intent.getExtras();
this.meeting = extras.getParcelable("MeetingParcel");
// build notification pending intent to go to the details page when click on the body of the notification
Intent notificationIntent = new Intent(context, MeetingDetails.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
notificationIntent.putExtra("MeetingParcel", meeting); // send meeting that we received to the MeetingDetails class
notificationIntent.putExtra("notificationIntent", true); // flag to know where the details screen is opening from
PendingIntent pIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
// build intents for the call now button
Intent phoneCall = Call._callIntent(meeting);
if (phoneCall != null) {
PendingIntent phoneCallIntent = PendingIntent.getActivity(context, 0, phoneCall, PendingIntent.FLAG_CANCEL_CURRENT);
int flags = Notification.FLAG_AUTO_CANCEL;
// build notification object
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Notification notification = builder.setContentTitle("Call In")
.setContentText(intent.getStringExtra("contextText"))
.setTicker("Call In Notification")
.setColor(ContextCompat.getColor(context, R.color.colorBluePrimary))
.setAutoCancel(true) // will remove notification from the status bar once is clicked
.setDefaults(Notification.DEFAULT_ALL) // Default vibration, default sound, default LED: requires VIBRATE permission
.setSmallIcon(R.drawable.icon_notifications)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(meeting.description))
.addAction(R.drawable.icon_device, "Call Now", phoneCallIntent)
.setCategory(Notification.CATEGORY_EVENT) // handle notification as a calendar event
.setPriority(Notification.PRIORITY_HIGH) // this will show the notification floating. Priority is high because it is a time sensitive notification
.setContentIntent(pIntent).build();
notification.flags = flags;
// tell the notification manager to notify the user with our custom notification
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
}
}
use this flag:
Notification.FLAG_AUTO_CANCEL
inside this:
int flags = Notification.FLAG_AUTO_CANCEL;
Notification notification = builder.build();
notification.flags = flags;
Documentation
Ok turns out it's a known problem already, and it needs extra code to be done (keeping reference to notification through id). Have no clue why API does not provide this, as it seems very logical to do. But anyways,
see this answer in stackoverflow:
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?
I faced this problem today, and found that FLAG_AUTO_CANCEL and setAutoCanel(true), both work when click on notification,
but not work for action click
so simply, in the target service or activity of action, cancel the notification
NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancelAll();
or if have more notification
manager.cancel(notificationId);
You have created two pending intent use in boths and change Flag too.
PendingIntent pIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), notificationIntent, 0);
PendingIntent phoneCallIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), phoneCall, PendingIntent.FLAG_UPDATE_CURRENT);
// CHANGE TO THIS LINE
PendingIntent pIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
PendingIntent phoneCallIntent = PendingIntent.getActivity(context, 0, phoneCall, PendingIntent.FLAG_CANCEL_CURRENT);
Related
I wrote the following method to check if a notification is active (visible on the status bar):
public static boolean isNotificationActive(Context context, int id) {
Intent intentPopup = new Intent(context, PopupActivity.class);
PendingIntent test = PendingIntent.getActivity(context, id, intentPopup, PendingIntent.FLAG_NO_CREATE);
return test != null;
}
I create a PendingIntent exactly like the one I want to be checked (the same 'intentPopup' and 'id' are passed to this PendingIntent) and, because of FLAG_NO_CREATE, I expect this PendingIntent to be null if it doesn't exist yet. I read about this method in a thread posted years ago here.
If the notification has not yet been issued, the method returns the expected value (false). When the notification is issued and is in the status bar, the method returns true.
However, after I dismiss the notification, the method still returns true, as if the PendingIntent is still there.
What am I missing here? Is the PendingIntent still available or am I misunderstanding something?
Is there a better way to check if a specific notification is active (being displayed in the status bar)?
EDIT: here's the code that creates the notification:
Intent intentPopup = new Intent(context, PopupActivity.class);
intentPopup.putExtra("id", id);
intentPopup.putExtra("timeQ", timeQ);
PendingIntent pendingIntentPopup = PendingIntent.getActivity(context, id, intentPopup, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setContentIntent(pendingIntentPopup)
.setSmallIcon(R.drawable.q_notification_icon)
.setContent(contentView)
.setSound(Uri.parse("android.resource://" + context.getPackageName() + "/raw/notification_sound"))
.setVibrate(vibrate_pattern);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_NO_CLEAR;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, notification);
Unfortunately PendingIntents that you embed in a Notification do not automatically disappear when the Notification is dismissed, viewed, or canceled. You can't use the presence or absence of a PendingIntent (using PendingIntent.FLAG_NO_CREATE like you've done) to determine whether or not a Notification is active.
To determine if a Notification is active, you can call NotificationManager.getActiveNotifications(). This will return all active Notifications that your app has posted.
I can use the following code to display a notification icon of missed calls, I hope to click the icon to open system Missed Calls UI, how can I do ? Thanks!
At present, I can open ui.CallerMain.class UI if I remove the comment.
BTW, in system Missed Calls UI, missed calls are listed in there.
private void ShowMissCallNotification(Context myContext,String myContentText) {
NotificationManager notificationManager = (NotificationManager) myContext.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(android.R.drawable.sym_call_missed,
myContext.getString(R.string.app_name),
System.currentTimeMillis());
notification.flags |= Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_NO_CLEAR;
CharSequence contentTitle= "Title";
CharSequence contentText =myContentText;
//Intent notificationIntent = new Intent(myContext, ui.CallerMain.class);
//PendingIntent contentItent = PendingIntent.getActivity(myContext, 0, notificationIntent, 0);
//notification.setLatestEventInfo(myContext, contentTitle, contentText,contentItent);
notificationManager.notify(NotificationID, notification);
}
Set a Pending Intent to the notification which will trigger the Call History.
First create an intent with Call Log
Intent resultIntent = new Intent();
resultIntent.setAction(Intent.ACTION_VIEW);
resultIntent.setType(CallLog.Calls.CONTENT_TYPE);
Then obtain the PendingIntent
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
Then set the PendingIntent to your notification builder
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon()
.setContentTitle()
.setContentText()
.setContentIntent(resultPendingIntent);
notificationManager.notify(id, builder.build());
Now clicking the notification will open the Call Log.
Update: The code commented out in your snippet will work if you create the Intent as mentioned above in this answer. But please be aware that the method by which you are creating notification has been deprecated. Use NotificationCompat class from the support library in future.
I have a notification that have 2 actions. One intent open an Activity, the other open browser web.
my code:
Intent intent1 = new Intent(context, NotificationClickActivity.class);
PendingIntent pIntent1 = PendingIntent.getActivity(context, 0, intent1, PendingIntent.FLAG_CANCEL_CURRENT);
String url = "http://www.google.com";
Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.setData(Uri.parse(url));
PendingIntent pBrowserIntent = PendingIntent.getActivity(context, 1, browserIntent, PendingIntent.FLAG_CANCEL_CURRENT);
// Build notification
Notification noti = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(shortDescription)
.setStyle(new Notification.BigTextStyle().bigText(longDescription))
.setSmallIcon(R.drawable.small_defaulticon)
.setAutoCancel(true)
.setContentIntent(pIntent1)
.addAction(R.drawable.playstore_icon_32, "Dettagli", pIntent1)
.setContentIntent(pBrowserIntent)
.addAction(R.drawable.small_defaulticon, "Vai al sito", pBrowserIntent).build();
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
// Hide the notification after its selected
noti.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, noti);
If i click on the notification it goes away, but if I click on one of the 2 Actions it open the right intent but notification doesn't cleared.
I try also .setDeleteIntent(myPendingIntent) but nothing... I wonder where I am going wrong...
A screen of my notification...
Thank you!
A notification is never dismissed when an action button is pressed. It just sends you associated intent. If you want it to dismiss, you need to call NoficationManager.cancel(int id) to cancel it yourself. You will normally do it in the same method, which handles action button intent.
Notification.FLAG_AUTO_CANCEL flag you tried to use is only applied to notification body and not to action buttons.
use cancel() in the activity that started by your action to dismiss the notification
try this
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setDefaults(Notification.DEFAULT_ALL);
and try to send uniqueId in notificationManager.notify(uniqueId, noti);
I have a method for creating notification. I want to clear notification number as soon as a user clicks on status notification.
public void createNotification(){
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification=null;
notification = new Notification(R.drawable.ic_launcher, "You have a new message", System.currentTimeMillis());
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.number = **count**++;
Intent intent = new Intent();
intent.setClass(TabInterfaceActivity.this, TabInterfaceActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent activity = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.contentIntent = activity;
notification.setLatestEventInfo(this, " New Message", message, notification.contentIntent);
}
If by "I want to clear notification number" you mean you want to keep the notification itself still displayed, but you want just to update/remove counter, then you should set your notification PendingIntent to point to your code that would handle this scenario for you, and when it completes it shall redirect to your target TabInterfaceActivity (or you can make it more flexible and pass target in PendingIntent's Bundle).
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.
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?
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.
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>
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.
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
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
};
}
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
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()).
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());
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" />
builder.setAutoCancel(true);
Tested on Android 9 also.