Cancel a notification inside a Bundle created using setGroup - android

I have multiple notifications stacked in a bundle created using the:
setGroup("groupname");
and the
setGroupSummary(true);
methods.
Each notification has an action. The intent inside the action pendingIntent contains the notification id which can be used to cancel the notification.
When the notifications are NOT bundled into a group and displayed inside a summary notification, calling NotificationManager.cancel(id) cancels the notification promptly.
However, If the notifications are grouped and ARE summarized, the NotificationManager.cancel(id) does nothing.
Can anyone tell me how to solve this.
The pending intent for action is as follows:
Intent notificationSettingsIntent = new Intent(context.getApplicationContext(), NotificationSettingsActivity.class);
notificationSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationSettingsIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
notificationSettingsIntent.putExtra("fromNotification",true);
notificationSettingsIntent.putExtra("notif_id",counterOfValidNotifications+6666);
//Log.d("FragmentCreate","Setting notif_id inside action button "+(counterOfValidNotifications+6666)+" for restid "+c.getInt(restidindex));
PendingIntent notificationSettingsActivityPendingIntent = PendingIntent.getActivity(context,(int)(System.currentTimeMillis()%10000),notificationSettingsIntent,PendingIntent.FLAG_ONE_SHOT);
notificationBuilder.addAction(R.drawable.ic_notifications_off_black_24dp,"Notification Options",notificationSettingsActivityPendingIntent);
The notif_id inside this intent is received inside the activity specified and here i basically call cancel(id).

(int)(System.currentTimeMillis()%10000)
This is not enough. If all your notifications are created within the millisecond they'll have just one PendingIntent. You set the flags as oneshot, so after the first one they won't be even delivered.

Related

Android: How to distinguish CLEAR all events from notification bar from user action

According to the specification, .setDeleteIntent(pendingIntent) is associated to both actions (CLEAR all events from notification bar and user action like swiping).
My requirements are that when the user touches the notification that appears on the notification bar, he must be forwarded to the NotificationsList.class. This is done with my pendingInent:
PendingIntent sendPendingIntent = PendingIntent.getActivity(context, reminderId, new Intent(context, NotificationsList.class), PendingIntent.FLAG_UPDATE_CURRENT);
However, on clicking the CLEAR button, the user must not be navigated to the application at all. With the .setDeleteIntent(pendingIndent) I cannot fulfill the 2nd requirement. The user is still navigated to NotificationsList.class.
Is there a way to programmatically distinguish the CLEAR all notifications events fired from the CLEAR button from user actions like touch or swipe on the specific notification on the notification bar?
What you're describing is very obtuse behavior. You need only set the pending intent to your notification and when it is clicked, the intent that is backing it will be executed.
If your code is navigating the user back to the app when the notification is cleared, then you already have a problem with your design. If the user clears your notification you should NOT be trying to navigate them back. Hence the setDeleteIntent() should NOT be associated with starting any activity.
Note that the intent that is backed when you click the notification (setContentIntent()) and clear (setDeleteIntent()) the notification are basically two PendingIntents, they should not be the same, which is what your problem is describing.
You cannot distinguish the two events. As the documentation says:
Notifications remain visible until one of the following happens:
The user dismisses the notification either individually or by using "Clear All" (if the notification can be cleared).
The user clicks the notification, and you called setAutoCancel() when you created the notification.
You call cancel() for a specific notification ID. This method also deletes ongoing notifications.
You call cancelAll(), which removes all of the notifications you previously issued.
So there are basically three different events in the view of a programmer:
You dismisses the notification
The user clicks on the notification
The user dismisses the notification (either by swiping or clearing it)
The first event is fired by yourself by calling cancelAll() or cancel().
You can handle the second like (which you wanna do I think):
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
//....
.setContentIntent(sendPendingIntent);
And you can handle the third event like (as you have described above):
builder.setDeleteIntent(pendingIndent)
I don't recommend to start an activity after the user dismisses your notification, because the user won't expect it and it will be a bad user experience.
I hope I could help.
According to the design guidelines, the user can expect to interact with your notification using higher-level gestures like click, swipe, and pinch zoom. Responding instantly to a lower level event like touch would short circuit these gestures, so your requirements would violate the design guidelines and you should not implement it.
If the requirements are changed so that the user is forwarded when they click on the notification, there is no need to distinguish between swiping and clearing, which is impossible in any case.
So your issue should be resolved by changing one word in the requirements: touch --> click.
I googled deleteIntent to find some info for a problem which led me here.
English is my second language. Sorry for some misuse of words in advance. I'm an android newbie, just downvote the answer if it sucks :)
For your last question, just as #x-code and #bendaf said, it's impossible to
distinguish swiping and clearing.
I am following the codelabs about notifications and encountered the same question(The description in your title). So I decided to offer more detail about how to use .setDeleteIntent in your case. Maybe you had done that.
In your case, the wrapped intent is for starting an activity, so do the pendingIntent.
PendingIntent sendPendingIntent = PendingIntent.getActivity(context, reminderId, new Intent(context, NotificationsList.class), PendingIntent.FLAG_UPDATE_CURRENT);
But for performing a broadcast, e.g. doing some stuff when the notification is cleared, use:
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, NOTIFICATION_ID, new Intent(yourCustomActionString), PendingIntent.FLAG_UPDATE_CURRENT);
builder.setDeleteIntent(pendingIntent); // the pendingIntent will be sent when the notification is cleared
Then we need a custom broadcast receiver receive that custom action contained in the Intent object, in your case, this action relates to the clearing:
// Inside onCreate, register the broadcast receiver;
registerReceiver(new MyReceiver(), new IntentFilter(yourCustomActionString));
.
.
// Create an inner class
public class MyReceiver extends BroadcastReceiver {
public NotificationReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
// code inside will be executed when pendingIntent is sent
Log("taG", "Notification is cleared"); // a message will be logged if the notification is cleared
// for more than one action, using switch...case to decide
}
}

Notification with button that upon click take an action without opening activity

I am trying to create a notification where I add button to it that would basically do some action. I know I can do the following
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, intent)
My questions are:
1) Is adding button supported in API 5.0+ ONLY or also in 4.x? I read different answers about it
2) The action seems to be associated with opening an activity. Is there away I can have it so when you click on a button it takes an action without having to open the activity (Either through broadcast receiver or some other way)? As far as I know Intent opens activities.
Thank you so much
It will work in Android 4.1 and later. See official doc.
If you want to do action with out any UI update(i.e., showing any activity), I suggest send a pending intent(which will trigger a broadcast receiver) as a parameter for notification action
i) Create a BroadcastReceiver named MyBroadcastReceiver
ii) Add your action in BroadcastReceiver's onReceive method
iii) Create a PendingIntent
Intent mIntent = new Intent(this,MyBroadcastReceiver.class);
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, mIntent , 0);
iv) Add it to Notification
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, mPendingIntent)
1) Is adding button supported in API 5.0+ ONLY or also in 4.x?
It will work in Android 4.1 and later. See official doc.
2)...As far as I know Intent opens activities.
Yes, you can use BroadcastReceiver or Service for executing logic that doesn't involve UI. First of all, you can build intent to launch activity, broadcast receiver, or service. Secondly, the third argument of NoticiationCompat.Builder#addAction is PendingIntent, not an Intent. You can use PendingIntent.getService to create an PendingIntent for service, for instance.
http://developer.android.com/reference/android/app/PendingIntent.html#getService(android.content.Context, int, android.content.Intent, int)

How to find that notification view is expanded or not

I am using the following code showing the notification, it works properly. I am look for the listener from which i can come to know whether the notification is expanded or not.
I want to open the app if the notification is expanded or else open the particular activity of the app.
Intent intent= new Intent(context, Activity1.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, getNextRandom(), intent, 0);
Builder newBuilder newBuilder = new Notification.Builder(context);
newBuilder.setContentTitle(title)
.setContentText(subtitle)
.setAutoCancel(true)
.setSmallIcon(R.drawable.icon)
.setTicker(notificationMessage)
.setContentIntent(pendingIntent);
Notificationnotification = new Notification.BigTextStyle(newBuilder)
.setBigContentTitle(notificationTitle)
.bigText(text)
.build();
Let me know if there is way to acheive this?
There is no way to know if the notification is open... What you can do is add buttons to the expanded notification that pressing on them will act differently than pressing on the notification itself.
There maybe no direct way, but maybe the following hack can help!!
You can have a custom notification layout and use RemoteView, Set a setOnClickPendingIntent to launch a service for the entire view so that you get notified when the notification is clicked.
When the user clicks the notification, service is started and show the new expanded custom layout from the service (you replace the old notification with the new one)
Maybe show your initial notification also from the same service using startforeground, so that your app is not killed and the view click can be received faster since service is already running and response time for changing the view is lower.
see this for remoteview and this for launching service from notification click.

Notification Auto-Cancel does not call DeleteIntent

I'm implementing GCM in my app and keeping a hash of notifications to keep track of what is in the notification shade (I have to change intents based on if the user is in or out of app).
I set the deleteIntent PendingIntent for all my notifications. All this does is remove the Notification from my local hash so it won't be updated anymore. The intent is fired fine if I clear all or swipe to delete a notification. However, I also set my notifications to auto cancel. Clicking on a notification does not trigger the deleteIntent for my notification.
My question is, is there any way to be notified when my Notifications are auto-cancelled?
This bug has been reported, but it doesn't look like it has been investigated at all. To work around this here's what I did:
Turn off auto cancel
Use broadcast for both content and delete intents with different actions
Broadcast receiver checks action
Content action: Do both click and delete operations, and cancel notification manually
Delete action: Do delete operation only
For example:
Send Notification
Notification.Builder builder = new Notification.Builder(context)
// Set other properties (not auto-cancel)
.setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(NOTIFICATION_CLICKED_ACTION), 0))
.setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(NOTIFICATION_DELETED_ACTION), 0));
notificationManager.notify(NOTIFICATION_ID, builder.build());
Receive Broadcast
if (intent.getAction().equals(NOTIFICATION_CLICKED_ACTION)) {
startActivity(new Intent(context, MyActivity.class));
notificationManager.cancel(NOTIFICATION_ID);
}
// Do deletion behaviour here (for both click and delete actions)
This is the correct behaviour od the DeleteIntent as described here in the Android SDK documentation:
Supply a PendingIntent to send when the notification is cleared
explicitly by the user.
The DeleteIntent will only get called when the notification is explicitly cleared by the user by swiping it away or by using the "clear all" function of the notification menu. Tapping on the notification will ONLY trigger the ContentIntent EVEN IF the AutoCancel is set to True.
Documentation says here and here, that clicking on notification with FLAG_AUTO_CANCEL cancels it automatically. This behavior means also that regular contentIntent (if set) will fire along with automatic cancellation, because it is fired in response for user's click action.
Use contentIntent field along with deleteIntent to detect cancellation performed by explicit user tap.

Change notification intent in Android

I have a service that shows a notification that I wish that will be able to go to a specific activity of my app each time the user presses on it. Usually it would be the last one that the user has shown, but not always.
If the activity was started before, it should return to it, and if not, it should open it inside of the app's task, adding it to the activities tasks.
In addition, on some cases according to the service's logic, I wish to change the notification's intent so that it will target a different activity.
How do i do that? Is it possible without creating a new notification and dismissing the previous one? Is it also possible without creating a new task or an instance of an activity?
No it wouldn't be possible to change the Activity once you have sent the notification.
You can start an Activity on your task stack that is not a problem, check out the notification service in the tutorial here:
http://blog.blundell-apps.com/notification-for-a-user-chosen-time/
You have to set a pending intent on the notification:
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, SecondActivity.class), 0);
// Set the info for the view that shows in the notification panel.
notification.setLatestEventInfo(this, title, text, contentIntent);
You can see the pending intent takes a normal intent "new Intent(this, SecondActivity.class" so if you want specific behaviour (like bringing to the top instead of starting a new activity. Add the flags like you would normally to this intent. i.e. FLAG_ACTIVITY_REORDER_TO_FRONT (something like that)
Since platform version 11, you can build a notification using Notification.Builder. The v4 support library has an equivalent class NotificationCompat.Builder.
You can't change the Activity once you've sent the notification, but you can update the notification with a new Intent. When you create the PendingIntent, use the flag FLAG_CANCEL_CURRENT. When you send the new notification, use the ID of the existing notification when you call NotificationManager.notify().
Also, you should be careful how you start your app. The Status Bar Notifications guide tells you how to set up the back stack.

Categories

Resources