I build simple app with used GCM and notification, I already success implement that, but I have question about notification, in my case:
I got more than one notification,
Example
Notif_1 -> Title : test_1 , Message : test_message_1
Notif_2 -> Title : test_2 , Message : test_message_2
Notif_3 -> Title : test_3 , Message : test_message_3
Notif_4 -> Title : test_4 , Message : test_message_4
The problem I just always got last notification bundle when I tap notification.
So when I tap notif_1, I got bundle from notif_4
when I tap notif_2, I got bundle from notif_4
What I want is when I tap notif_1, must have bundle from notif_1 not from other notif
how to make like that?
private void sendNotification(String title, String msg) {
mNotificationManager =
(NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
Intent resultIntent = new Intent(ctx, BuyLevel.class);
Bundle bundle = new Bundle();
bundle.putString("title", title);
bundle.putString("message", msg);
resultIntent.putExtras(bundle);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(ctx);
stackBuilder.addParentStack(BuyLevel.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ctx);
mBuilder.setSmallIcon(R.drawable.icon_mini);
mBuilder.setContentTitle(title);
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(msg));
mBuilder.setContentText(msg);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setAutoCancel(true);
Notification notification = mBuilder.build();
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
int initialNotification = CommonUtilities.msgId.incrementAndGet();
mNotificationManager.notify(initialNotification, notification);
}
Flag must be required with unique values. So we can set flag as random number.
Change this line:
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
to
Random random = new Random();
int m = random.nextInt(9999 - 1000) + 1000;
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, m);
According to the documentation of PendingIntent:
If the creating application later re-retrieves the same kind of
PendingIntent (same operation, same Intent action, data, categories,
and components, and same flags), it will receive a PendingIntent
representing the same token if that is still valid.
[...]
A common mistake people make is to create multiple PendingIntent
objects with Intents that only vary in their "extra" contents,
expecting to get a different PendingIntent each time. This does not
happen. The parts of the Intent that are used for matching are the
same ones defined by Intent.filterEquals. If you use two Intent
objects that are equivalent as per Intent.filterEquals, then you will
get the same PendingIntent for both of them.
If you truly need multiple distinct PendingIntent objects active at
the same time (such as to use as two notifications that are both shown
at the same time), then you will need to ensure there is something
that is different about them to associate them with different
PendingIntents.
[...]
This may be any of the Intent attributes considered by
Intent.filterEquals, or different request code integers supplied to
getActivity(Context, int, Intent, int), getActivities(Context, int,
Intent[], int), getBroadcast(Context, int, Intent, int), or
getService(Context, int, Intent, int).
So your code when requesting the PendingIntent should be something like:
int m=0;
private void sendNotification(String title, String msg) {
mNotificationManager = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
[...]
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(m++,
PendingIntent.FLAG_UPDATE_CURRENT);
[...]
}
Related
I am developing an app with a minimum SDK of 15 and target SDK of 29. The app has a series of activities (a list, a detail, a list, a detail, etc.) that the user can navigate through as they deep-dive into their database of information. In the fourth activity, the user has the option of setting an alarm as a reminder.
Currently, the alarm is set and fires off on the given day. However, when you click on the notification, the taskStack is not formed correctly because the extras are not included for the top level of the intent.
To create the notification, I have the following code in CourseDetailActivity:
if(canSetAlarm(when)) {
String notificationIdString = notificationIdPrefix + courseId;
int notificationId = Integer.parseInt(notificationIdString);
long notificationWhen = getNotificationTime(when);
PendingIntent pendingIntentForContent = createPendingIntentForThisCourse(courseId);
Intent intent = new Intent(CourseDetailActivity.this, MyReceiver.class);
intent.putExtra(NOTIFICATION_CHANNEL_ID_KEY, getString(R.string.course_tracker_notification_channel_id));
intent.putExtra(NOTIFICATION_ID, notificationId);
intent.putExtra(NOTIFICATION_TITLE_KEY, title);
intent.putExtra(NOTIFICATION_TEXT_KEY, message);
intent.putExtra(NOTIFICATION_PENDING_INTENT_KEY, pendingIntentForContent);
PendingIntent pendingIntentForBroadcast = PendingIntent
.getBroadcast(this, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, notificationWhen, pendingIntentForBroadcast);
} else {
showToast("Alarms cannot be set for today or dates in the past.");
}
}```
This utilizes the helper method below, also in CourseDetailActivity:
``` private PendingIntent createPendingIntentForThisCourse(int courseId) {
int termId = getIntent().getExtras().getInt(TERM_ID_KEY);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
Intent mainIntent = new Intent(getApplicationContext(), MainActivity.class);
stackBuilder.addNextIntent(mainIntent);
Intent termDetailIntent = new Intent(getApplicationContext(), TermDetailActivity.class);
termDetailIntent.putExtra(TERM_ID_KEY, termId);
stackBuilder.addNextIntent(termDetailIntent);
Intent courseListIntent = new Intent(getApplicationContext(), CourseListActivity.class);
courseListIntent.putExtra(TERM_ID_KEY, termId);
stackBuilder.addNextIntent(courseListIntent);
Intent courseDetailIntent = new Intent(getApplicationContext(), CourseDetailActivity.class);
courseDetailIntent.putExtra(TERM_ID_KEY, termId);
courseDetailIntent.putExtra(COURSE_ID_KEY, courseId);
courseDetailIntent.setAction("foo_action");
stackBuilder.addNextIntent(courseDetailIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(courseId, PendingIntent.FLAG_UPDATE_CURRENT);
return resultPendingIntent;
}
MyReceiver class has the following onReceive method:
Log.i(LOG_TAG, "onReceive: ");
String channel_id = intent.getStringExtra(NOTIFICATION_CHANNEL_ID_KEY);
int notificationId = intent.getIntExtra(NOTIFICATION_ID, 0);
String title = intent.getStringExtra(NOTIFICATION_TITLE_KEY);
String text = intent.getStringExtra(NOTIFICATION_TEXT_KEY);
PendingIntent pendingIntent = intent.getParcelableExtra(NOTIFICATION_PENDING_INTENT_KEY);
Toast.makeText(context, text + " (Notification ID " + notificationId + ")", Toast.LENGTH_LONG).show();
Notification notification = new NotificationCompat.Builder(context, channel_id)
.setSmallIcon(R.drawable.ic_alarm_notification)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle(title)
.setContentText(text)
.setStyle(new NotificationCompat.BigTextStyle().bigText(text))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
}
Quite by accident, I discovered that the extras for all other intents in the stack are being passed. It is ONLY the extras for the TOP stack that are not being passed (and therefore, the viewModel for the activity doesn't know which data to pull from the database to display.
I have scoured stackOverflow for hours and now days to now avail. I have tried to change the flags on the pendingIntent and on the Intent themselves. I tried to add a dummy action as suggested in another post. I've added a unique identifier as the request code for the intentToBroadcast. Nothing seems to have worked.
This code works on newer APIs; however, I am struggling to get it to work on API level 15.
I would very much appreciate any guidance you could give.
I'm having trouble in figuring out the Intent, PendingIntent Filters and Flags for notifications.
Notification are working and are getting generated as they should, but the problem is only the last notification created keeps the Bundle Data.
I want all notification to keep the Bundle Data of each notification in it until a user click on them.
Consider an application for a moment when different user send you a message a new notification gets created and when you click on any notification the app launches and takes you to some specific Activity. I want the same thing but when there are more than one notification the last notification keeps the Data where as previous notification loose their Bundle Data and Intent.
There is another thing which Filters to use to restrict the app from launching a new instance of MainActivity everytime a notification is clicked at.
The Notification_ID are different for each notification.
public class AlarmSchedulingService extends IntentService {
private NotificationManager mNotificationManager;
public AlarmSchedulingService() {
super("SchedulingService");
}
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
sendNotification(extras.getInt(KEY_EXTRAS_NOTIFICATION_ID));
}
public void sendNotification(int NOTIFICATION_ID) {
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(keyName, extraData);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// use the right class it should be called from the where alarms are set
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(titleString)
.setStyle(
new NotificationCompat.BigTextStyle()
.bigText(messageString))
.setDefaults(
Notification.DEFAULT_SOUND
| Notification.DEFAULT_LIGHTS)
.setContentText(messageString);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
This is Showing that :
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
You are giving request code 0 to all notifications.
0 should be replaced by each unique number, otherwise, each new notification will override the old one.
My notification Show Method:
public static void ShowNotification(int id, String NotifFirstText,
String NotifTitle, String NotifeText, int notificon, long when) {
try {
Context context = ApplicationClass.context;
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(context.NOTIFICATION_SERVICE);
int icon = notificon;
CharSequence notiText = NotifFirstText;
long meow = when;
Notification notification = new Notification(icon, notiText, meow);
CharSequence contentTitle = NotifTitle;
CharSequence contentText = NotifeText;
Intent notificationIntent = new Intent();
String mPackage = "mypackage";
String mClass = ".ActivityShow";
notificationIntent.setComponent(new ComponentName(mPackage,
mPackage + mClass));
notificationIntent.putExtra("id", id);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.flags = Notification.DEFAULT_LIGHTS
| Notification.FLAG_AUTO_CANCEL
| Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND;
PendingIntent contentIntent = PendingIntent.getActivity(G.context,
0, notificationIntent,0);
notification.setLatestEventInfo(context, contentTitle, contentText,
contentIntent);
int SERVER_DATA_RECEIVED = id;
notificationManager.notify(SERVER_DATA_RECEIVED, notification);
} catch (Exception e) {
e.printStackTrace();
}
}
and this my activity code:
if (getIntent().getExtras() != null) {
Toast.makeText(getBaseContext(),
getIntent().getExtras().getInt("id") + "", Toast.LENGTH_LONG).show();
}
i create more than one notification and set different id for All of them but when i click on each notification i give same id ...
how solve this problem?
When you use PendingIntent.getActivity(G.context, 0, notificationIntent,0), extras do not get replaced per the PendingIntent overview:
Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.
While in most cases you'd replace the last 0 with FLAG_UPDATE_CURRENT to update the extras, this doesn't help the problem of having multiple notifications simultaneously, instead they say:
If you truly need multiple distinct PendingIntent objects active at the same time (such as to use as two notifications that are both shown at the same time), then you will need to ensure there is something that is different about them to associate them with different PendingIntents.
The easiest way to do this is to pass in your id as the request code (the second parameter). This ensures that each PendingIntent is managed separately:
PendingIntent.getActivity(G.context, id, notificationIntent, 0)
I send different notifications. But when you click on any one of them I get the data that have been sent to the last notification. how to fix it? I need to notice every store their data, and a new notice does not replace them.I use a flag PendingIntent.FLAG_UPDATE_CURRENT but I use the left all the offers of flags too.
private void generateNotification(Context context, String title, String message,int groupid,Intent data) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Intent intent = new Intent(context,MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (groupid==1){
intent.putExtra("guest",data.getStringExtra("guest"));
intent.putExtra("hotel",data.getStringExtra("hotel"));
intent.putExtra("room",data.getStringExtra("room"));
}
if (groupid==5){
intent.putExtra("hotel",data.getStringExtra("hotel"));
}
if (groupid==4){
intent.putExtra("hotel",data.getStringExtra("hotel"));
intent.putExtra("guest",data.getStringExtra("guest"));
}
intent.putExtra("group_id",groupid);
Log.d("mylogout","group_id: "+groupid);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(context)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_stat_gcm)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_stat_gcm))
.setTicker("Новое сообщение")
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentTitle(title)
.setContentText(message)
.build();
notificationManager.notify(ID_NITIF++, notification);
}
The trick is to add a different requestCode on the PendingIntent for each different notification.
Documentation is:
public static PendingIntent getActivity (Context context, int requestCode, Intent intent, int flags)
The system uses it to compare PendingIntents, and if you pass the same code to different requests, it thinks its the same, and won't update it. To fix it, add a different requestCode for each different notification.
What I ussually do to make sure ALL notifications are well updated:
//Use the hashcode of current timestamp mixed with some string to make it unique
int requestCode = ("someString" + System.currentTimeMillis()).hashCode();
//Also add it to the intent, to make sure system sees it as different/modified
intent.putExtra("randomRequestCode", requestCode);
//Add the requestCode to the PendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode , intent, PendingIntent.FLAG_UPDATE_CURRENT);
I'm trying to send an android notification but it keeps failing at the mbuilder.build() part. I do have an alert dialog right after in the same method. I'm posting my code below
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.noteiconcon)
.setContentTitle("Finished search")
.setContentText("We found your account");
System.out.println("failed after setText");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
System.out.println("failed after result intent");
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
System.out.println("taskstackbuilder passed");
stackBuilder.addParentStack(MainActivity.class);
System.out.println("stackbuilder.appParentstack passed");
stackbuilder.addNextIntent(resultIntent);
System.out.println("stackbuilder.addnextintent passed");
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
System.out.println("pending intent passed");
mBuilder.setContentIntent(resultPendingIntent);
System.out.println("mbuilder.setcontentintent passed");
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
System.out.println("notification manager passed");
// mId allows you to update the notification later on.
mNotificationManager.notify(mId,mBuilder.build());
System.out.println("notificationManager.notify passed"+ mId);
I already added the meta data task but the log cat says.
Bogus static initialization, type 4 in field type Landroid/support/v4/app/NotificationCompat$NotificationCompatImpl; for Landroid/support/v4/app/NotificationCompat; at index 1
Like I said I added the meta data tag and this is being called in an asychtask after an alert dialog. Ive commented out the alert dialog but it still works.
If I drop the last line .notify it doesn't crash but obviously doesn't send a notification.
I had to use a different notification method which it accepted the notification then.
// Set the icon, scrolling text and timestamp
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String MyText = "Finished searching";
Notification mNotification = new Notification(R.drawable.passicon, MyText, System.currentTimeMillis() );
//The three parameters are: 1. an icon, 2. a title, 3. time when the notification appears
String MyNotificationTitle = "Finished Searching";
String MyNotificationText = "We can't find your password.";
Intent MyIntent = new Intent(this, MainActivity.class);
PendingIntent StartIntent = PendingIntent.getActivity(getApplicationContext(),0,MyIntent, PendingIntent.FLAG_CANCEL_CURRENT);
//A PendingIntent will be fired when the notification is clicked. The FLAG_CANCEL_CURRENT flag cancels the pendingintent
mNotification.setLatestEventInfo(getApplicationContext(), MyNotificationTitle, MyNotificationText, StartIntent);
int NOTIFICATION_ID = 1;
notificationManager.notify(NOTIFICATION_ID , mNotification);
//We are passing the notification to the NotificationManager with a unique id.