I have an alarm receiver that does some checks and then creates a Notification for each check. This means it can create more than one Notification. This all works fine. However, I have an Intent connected to the notification to start an activity when the notification is tapped.
This is the notification code:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, CHANNEL_OUTPUT_LEVELS)
.setSmallIcon(icon)
.setContentTitle(title)
.setContentText(message)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(longmessage))
.setContentIntent(getPendingIntent(solarEdge, reason))
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
// notificationId is a unique int for each notification that you must define
// we use the installation's ID to make sure all notifications get sent
notificationManager.notify(solarEdge.getInfo().getId(), mBuilder.build());
The method that creates the PendingIntent is:
private PendingIntent getPendingIntent(SolarEdge solarEdge, int reason) {
String apikey = solarEdge.getApikey();
int installationId = solarEdge.getInfo().getId();
Intent intent = new Intent(context, InstallationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(EXTRA_API_KEY, apikey);
intent.putExtra(EXTRA_INSTALLATION_ID, installationId);
intent.putExtra(EXTRA_REASON, reason);
return PendingIntent.getActivity(context, 0, intent, 0);
}
Problem I have, is that even I create a different intent, it still always calls the Activity with the same extras (apikey and installid). It always takes the first one created.
It seems that the problem is caused by the arguments you passed to the getActivity method.
Try the following code
PendingIntent.getActivity(context, <unique_value_per_every_call>, intent, 0);
The second argument is requestCode so it should be unique.
The accepted answer is one way to solve the problem, but it isn't the only way.
To get a unique PendingIntent on every call, the call to PendingIntent.getActivity() needs to provide either a unique requestCode or a unique Intent. To make the Intent unique it is necessary to provide either a unique ACTION, DATA, or COMPONENT. There are therefore several ways to solve this problem.
Known "problem"/quirk/design and we programmers keep running into it.
The request code parameter must be something other than 0 if the intent is the same (action, data or component the same, not only extra data differs).
int requestCode = 1;
PendingIntent.getActivity(context, requestCode, intent, 0);
Additionally:
If you want to update a notification/pending intent later on you can use the same requestCode.
If you add multiple pending intents they must all be different. Example: A stop and a pause action.
I usually follow this pattern:
requestCode = 1 for the content intent.
requestCode = 2 for first action
requestCode = 3 for second action
etc
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
I am seriously confused now, I have been reading several SE examples and they all seem to be doing slightly different things.
What i want to do: Is have a single Activity called NotificationActivity, when I click on a notification it must open that activity and provide the activity with a DeviceId. I don't want to override or update any pending activities. Each activity should be its own intent.
There should only be once instance of NotificationActivity.
here is the code I have so far:
MyGcmListenerService:
Intent intent = new Intent(this, NotificationActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
//ADD My Extras
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_ID, content.DeviceId);
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_TYPE_ID, content.DeviceTypeId);
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_NAME, content.DeviceName);
//
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(content.DeviceName)
.setContentText("Notification")
.setAutoCancel(true)
.setSound(ingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setGroup("Mi:" + content.DeviceId)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NotificationID++, notificationBuilder.build());
and my NotificationActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification);
deviceId = getIntent().getExtras().getLong(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_ID, -1);
deviceName = getIntent().getExtras().getString(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_NAME, "");
deviceTypeId = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_TYPE_ID, 0);
What am I missing here/ I think I am getting mixed up with all the different flags and launcher types.
If there is already an NotificationActivty in memory, I want to close it and open a new one with the latest intent. If there are 3 notifications on the users phones, and they click on all three. it must open the NotificationActivty for the last clicked Notification.
There must be an issue with my pending intent?
In NotificationActivity, you collect int or long value using following code i.e.
notificationID = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, 0);
then please pass a proper value with putExtra() i.e. if collect int then pass Integer.parseInt(content.DeviceId) or collect long then pass Long.parseLong(content.DeviceId)
hope it's helpful to you
In Notification class add this line
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, NotificationID);
In NotificationActivity
notificationID = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, 0);
I'm having issues with mutiple notification while putExtra using PendingIntent. In Activity getStringExtra fom Intent is returning last putExtra while generating Notification.
Let me explain complete scenario first and make me correct if i'm wrong.
First of all my Activity's (let's say its MainActivity) launchMode is singleTop. i'm setting it into manifest.i.e.
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
... />
Now i'm generating notifaction using this code,
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent notifyIntent = new Intent(context,
MainActivity.class);
notifyIntent.putExtra("message", msg);
Log.i(TAG, msg);
notifyIntent.putExtra("title", notification_title);
Log.i(TAG, notification_title);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(
BeaconService.this, 0, notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new Notification.Builder(
context).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(notification_title).setContentText(msg)
.setAutoCancel(true).setContentIntent(pendingIntent).build();
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_LIGHTS;
notificationManager.notify(NOTIFICATION_ID, notification);
NOTIFICATION_ID++;
I'm also using flag PendingIntent.FLAG_UPDATE_CURRENT. but, while clicking on any Notification (let's say we've 5 notifactions) it just returns the fifth extra put while generating Notification all top four notification extra are just like lost somewhere.
In my MainActivity i've also override onNewIntent like,
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// getIntent() should always return the most recent
setIntent(intent);
if (intent.hasExtra("message")) {
String message = intent.getStringExtra("message");
}
if (intent.hasExtra("title")) {
String title = intent.getStringExtra("title");
}
}
this extras returned are always from last notification's extra. I don't know where am i going wrong?
I've also tried some links but didn't find helpful solution.
Intent extras being lost when sending with PendingIntent for GCM
Please help.
You aren't creating unique PendingIntents. There must be a thousand answers to exactly this question on Stackoverflow.
When you call this:
PendingIntent pendingIntent = PendingIntent.getActivity(
BeaconService.this, 0, notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
The second time, it will find the first PendingIntent and return you a reference to it (Android will not create another one). Also, since you set FLAG_UPDATE_CURRENT, Android will modify the underlying Intent by overwriting the extras in the old Intent with the extras you provided in the new Intent. That's why it always only delivers one Intent and that Intent always has the last set of extras.
You need to make each PendingIntent unique. There are many ways to do this (setting different extras is NOT one of the ways). Try providing a unique number as the requestCode parameter to PendingIntent.getActivity().
#David Wasser thanks for your answer!
I just wanted to share a piece of code which i've used and solved my issue.
providing a unique number as the requestCode parameter to PendingIntent.getActivity() is the right solution with Multiple Notifications while launchmode="singleTop".
To provide unique code as the requestCode what i've done is, placed NOTIFICATION_ID as requestCode i.e,
PendingIntent pendingIntent = PendingIntent.getActivity(
BeaconService.this, NOTIFICATION_ID, notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
I've also found same solution at here.
That's the perfect unique requestCode in my case. I hope it will be helpful to others is well who are facing issue.
I want to pass a long value using a PendingIntent something like this
Intent intentForPending = new Intent(context, NewBlaBlaActivity.class);
long courseId = 15252;
intentForPending.putExtra("courseId", courseId);
intentForPending.putExtra("isFromPushNotification", true);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intentForPending, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
context).setSmallIcon(R.drawable.appicon)
.setContentTitle("BlaBla")
.setStyle(new NotificationCompat.BigTextStyle().bigText(message))
.setContentText(message)
.setAutoCancel(true);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
And get the value as below
Intent intent = getIntent();
if(intent.getBooleanExtra("isFromPushNotification", false)) {
long courseId = intent.getLongExtra("courseId", 0);
}
But I always get 0 from the intent. The weird thing is while I can get the boolean value with 'isFromPushNotification' key from the intent, I cannot get the long value from the same intent.
This drives me crazy. As you can see, it is a PushNotification and this code runs when I tap on the notification.
I tried all the way I can get from the forums and questions in stackoverflow, adding L suffix on def and original value on long objects. But I think PendingIntent is wet blanket.
I am waiting for your godlike advices. Thanks!
If you are going to use extras with a PendingIntent, always use a flag in the last parameter of the PendingIntent factory method (getActivity() in your case). Probably you want FLAG_UPDATE_CURRENT, to indicate to replace any existing PendingIntent contents with the new extras.
I'm currently doing some notifications for my app. Now I've successfully created a notification but problem is that each of my notification doesn't pass different extras on click.
Well what happen is that I only have a loop that calls the createNotification method per loop and also I assign different ID's for those for the notification to appear in different stack.
here's my code:
private void createNotification(String record_name, String file_path, String status, int id) {
/*must pass:
* record_name, (get the record name in DB using the id create a new query method)
* record_status, (simple part just match if equivalent to ready to download for the JSON data then show notif if true)
* record_path *full path* (this one can be get using the record name itself add the path and extension name)*/
/*this will jump from the current activity into the target activity class just do some workarounds here*/
Intent intent = new Intent(this, RecordEditActivity.class);
intent.putExtra("record_name", record_name);
intent.putExtra("record_path", file_path);
intent.putExtra("record_status", status);
PendingIntent pIntent = PendingIntent.getActivity(this,0, intent, 0);
/*build the notification here this is only supported for API 11. Since we've targeted API 11 there will be no problem on this*/
NotificationCompat.Builder notify = new NotificationCompat.Builder(this)
.setContentTitle(record_name + " is ready for download")
.setContentText("Click to view or download recording")
.setAutoCancel(true)
.setSmallIcon(R.drawable.notif_icon)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_launcher))
.setTicker("Echo: your file is ready for download")
.setContentIntent(pIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT<16){
/*build notification for HoneyComb to ICS*/
notificationManager.notify(id, notify.getNotification());
}if(Build.VERSION.SDK_INT>15){
/*Notification for Jellybean and above*/
notificationManager.notify(id, notify.build());
}
}
I think the problem is in the PendingIntent part since I don't know which flags should I use for this but I'm not that sure about it.
Got it! what needed is for me to assign an ID for my pendingIntent requestCode what I did is assign the same ID I used for my notificationManager.
More info here.
Just use this one line of code-
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
And for more detail see this answer:
GCM android Push Notification shows old message always. Intent received incorrect