I have an app which associates some entities with a unique ID and notifies about the entities to the user, which I'm gonna use notificationID to be the same as entity ID.
I have built a notification with a dismiss action based on the following sample solution exactly without any modification.
So far things are going well until I try to create 2 notifications with different ID using the sample.
A problem arises in that the dismiss button only receives the notificationID of the first notification:
The first notification behaves normally as expected.
But the second notification's getExtra() in BroadcastReceiver takes the notificationID of the FIRST notification instead and cancelling the notification just keeps cancelling the first notification.
My create Notification function, I just call this function twice with different IDs:
void createNoti(int NOTIFICATION_ID){
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());
}
BroadcastReceiver class:
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
I believe the issue is in passing in 0 into PendingIntent:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
I had the same issue until I started passing in the notification id as the 2nd argument; so instead of passing in 0, pass in the id of the notification:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), NOTIFICATION_ID, buttonIntent, 0);
After I made that change, I noticed that when clicking on individual notifications (especially notifications in a group) everything worked as intended.
Related
Hello currently I have setup a application which allows the user to set an alarm. When this alarms reaches it designated time it will then send a notification to the user. Now currently each time this notification is activated it sends a static message e.g. "You have a notification". I want to be able to change this notifications title to the alarms name which I have stored inside of SQLOPENHELPER when the user made the alarm.
I have also given each alarm a specific ID which is the current time in milliseconds and then also stored this inside of my SQL. Now I know you require a new ID for each notification but how would I do this and relate it back to my SQL?
I have included a small diagram just to clarify what I'm doing and my current alarm and broadcast receiver...
Diagram................
Set alarm.....
// id - relates to the custom id given to that alarm
// receiver - is our intent
pendingIntent = PendingIntent.getBroadcast(v.getContext(), id, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, myCalendar.getTimeInMillis(), pendingIntent);
// Intent array list is used to store multiple alarms
intentArrayList.add(pendingIntent);
Broadcast receiver...
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
Intent moveActivity = new Intent(context, AlarmActivity.class);
moveActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Works with moveActivity to move the user back to main application.
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, moveActivity, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentIntent(pendingIntent)
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true);
notificationManager.notify(0, builder.build());
// Notification ID has been left at 0 because I don't know what to do as this point and after trying to figure it out for 2 days I thought I should ask.
//// UPDATE
Main Activity
I have implemented a put extra just under my intent Array List
receiver.putExtra("title", id);
Broadcast
Bundle bundle = intent.getExtras();
if (bundle != null) {
pass = bundle.getString("title");
//I have put my notification in this section
}
I tested it by putting "pass" which is the String for retrieving the put extra into the title of my notification and it comes up blank?
Update your receiver intent as below to pass the ALARM_ID:
Intent receiver = new Intent(getApplicationContext(), Receiver.class);
receiver.putExtra("KEY_ALARM_ID", ALARM_ID); // ALARM_ID = id
In PendingIntent.getBroadcast(), Use ALARM_ID as requestCode.
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, receiver, PendingIntent.FLAG_UPDATE_CURRENT );
Always use different requestCode for different notification to get
correct result.
In notify() method, use ALARM_ID as id:
notificationManager.notify(ALARM_ID, builder.build());
Notification id should be unique within your application. If a
notification with the same id has already been posted by your
application and has not yet been canceled, it will be replaced by the
updated information.
In your BroadcastReceiver class onReceive() method get the ALARM_ID:
#Override
public void onReceive(Context context, Intent intent)
{
int alarmId= intent.getExtras().getInt("KEY_ALARM_ID");
// Do something with alarmId
}
Hope this will solve your problem.
// Main activity
receiver.putExtra("title", id);
pendingIntent = PendingIntent.getBroadcast(v.getContext(), id, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, myCalendar.getTimeInMillis(), pendingIntent);
intentArrayList.add(pendingIntent);
Broadcast
Bundle bundle = intent.getExtras();
int pass = bundle.getInt("title" , 1);
Thanks psKink you gave me the kick I needed
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);
I have a background Service that triggers events and builds notifications for my app. If clicked, a notification should open the MainActivity, and depending on the info sent, open one of my Fragments within this Activity. For that, the Notification contains a PendingIntent that saves data into the Intent's Bundle.
There are three scenarios for this triggered event:
App in foreground: my service sends a Broadcast and my BroadcastReceiver in the Activity gets the event and handles it. No Notification needed. It works well.
App killed: the PendindIntent reopens my app, and my Activity accesses my info through the Bundle using getIntent().getExtras(). Everything works well.
App in background: the Activity was created already, so the BroadcastReceiver is registered. I click on my Notification, but nothing happens. Neither I receive a broadcast message, nor I can access my Bundle (checking it in onResume with getIntent().getExtras() and it's null).
Any thoughts on how to solve the third case?
Code that creates the Notification:
private void createNotification() {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.my_icon);
mBuilder.setContentTitle("My App");
mBuilder.setContentText("Notification message");
Bundle bundle = new Bundle();
bundle.putString(MainActivity.OPEN_FRAGMENT, "myFragment");
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("myInfo","myInfo");
resultIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
resultIntent.putExtras(bundle);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
Have you tried to change
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
Finally, I found the solution!
What happened is that on my cases:
App foreground: Service sends a Broadcast. Activity receives it and handles the event.
App killed: Notification clicked, PendingIntent launched. App reopens and handles the event with the info from Bundle.
App in background: Notification clicked, it sends a PendingIntent, however the Activity is already running so it doesn't override it, which is why nothing happened.
Solution: override the onNewIntent method:
#Override
protected void onNewIntent(Intent intent) { // Receives the PendingIntent
super.onNewIntent(intent);
if (intent.getExtras() != null && intent.getExtras().getString(OPEN_MY_FRAGMENT) != null) {
// TODO something with intent.getExtras().getString("myInfo");
}
}
I want to be able to have a button that copies the text from a notification to the clipboard. The notification is sent through the google's GCM service.
The first time the notification arrives when I press the "copy" button everything is fine and the text goes into the clipboard by the service that the button sends an intent to. The second time a notification arrives with different text when I press the "copy" button the content of the first notification goes into the clipboard instead of the new one. When I debug the code, it seems that the intent that's calling the service has the new content, but the service that puts it into the clipboard runs with the parameters of the old notification, as if the same session of the service is awaken with the old intent.
Any clue why this is happening?
// Called by the GCM notification handler
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, MainActivity.class), 0);
Intent notificationIntent = new Intent(this, clipboardService.class);
notificationIntent.putExtra("tool",msg);
PendingIntent serviceIntent = PendingIntent.getService(this, 0, notificationIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_gcm)
.setContentTitle("Here's your text!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg)
.addAction(R.drawable.ic_stat_gcm, "Copy", serviceIntent); // <--- The intent will have the right (new) value on the second run
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
This is the service that the notification actions calls to:
public class clipboardService extends IntentService {
public clipboardService() {
super("clipboardService");
}
#Override
protected void onHandleIntent(Intent intent) { //This intent will have the values of the first intent to fire, instead of the updated one.
String msg = (String) intent.getExtras().get("tool");
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("2android",msg);
clipboard.setPrimaryClip(clip);
}
Although it is very late to answer your question, but recently I faced the same issue and Google led to me this unanswered question. So here is my understanding if in future someone dig this up.
This is because PendingIntent uses cached intent extras from previous instance of the intent unless you explicitly tell it not to. There are two ways to do that...
Use FLAG_CANCEL_CURRENT or FLAG_UPDATE_CURRENT (best in your case) as flag while constructing the PendingIntent. The first flag will automatically dismiss the previous PendingIntent and create a completely new one and the second one will only update the extras for the PendingIntent and save the overhead of creating a completely new one.
PendingIntent.getService(this, 0, notificationIntent,
FLAG_CANCEL_CURRENT | FLAG_UPDATE_CURRENT);
Pass an unique requestCode to the PendingIntent constructor everytime. This will generate unique pending intents for everytime so that you can access the extras associated with a particular intent later. I believe this is not required in your case.
PendingIntent.getService(this, UNIQUE_ID, pi, 0);
I'm building an app that shows a notification with two options "Dim" and "Full" when a BroadcastReceiver is called. Each of this buttons broadcasts an action.
So far everything is possible to do, right?
The problem is that the buttons shown on the notification do not respond to the tap but the whole notification does (if I click on the icon or text instead of the button).
I have this function to build the notification:
private Notification buildReleaseNotification(NotificationManager nManager, Context context) {
Notification.Builder builder = new Builder(context);
builder.addAction(R.drawable.rate_star_big_half_holo_dark, "Dim", buildPendingIntent(context, DIM));
builder.addAction(R.drawable.rate_star_big_on_holo_dark, "Full", buildPendingIntent(context, FULL));
builder.setContentTitle("Car notification");
builder.setContentText("Freed");
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setOngoing(true);
Notification notification = builder.build();
return notification;
}
and it is called when receiving a broadcast:
public void onReceive(Context context, Intent intent) {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification noty = null;
noty = buildReleaseNotification(context);
startService(context, RELEASE);
if (noty != null) {
nManager.notify(ChangeLockService.GLOBAL_TAG, ID, noty);
}
}
------ edit
Just noticed that the following function returns null... So, how can I build a pending intent to perform a broadcast?
private PendingIntent buildPendingIntent(Context context, String action) {
Intent i = new Intent(action);
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, Intent.FLAG_RECEIVER_REPLACE_PENDING);
return pi;
}
When creating the intent through
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, Intent.FLAG_RECEIVER_REPLACE_PENDING);
caused it to return null.
According to the documentation, I understood that the flag Intent.FLAG_RECEIVER_REPLACE_PENDING would replace any pending intent that already existed for that button. If I send no flags then everything works fine:
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, 0);