Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PendingIntent from second action overwrites the first action and the contentIntent for Notification

The code:

int id = 0;
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
  .setContentTitle(context.getString(R.string.notification_on_the_move_gps_title))
  .setContentText(context.getString(R.string.notification_on_the_move_text));

builder.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_on_the_move_gps_big_text)));

Intent mainIntent = new Intent(context, MainActivity.class);

Intent turnOffIntent = new Intent(context, MainActivity.class);
turnOffIntent.putExtra(MainApp.KEY_TURN_OFF_NOTIFICATION_ID, id);

TaskStackBuilder mainBuilder = TaskStackBuilder.create(context);
mainBuilder.addParentStack(MainActivity.class);
mainBuilder.addNextIntent(mainIntent);
PendingIntent mainPendingIntent = mainBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(mainPendingIntent);

TaskStackBuilder turnOffBuilder = TaskStackBuilder.create(context);
turnOffBuilder.addParentStack(MainActivity.class);
turnOffBuilder.addNextIntent(turnOffIntent);
PendingIntent turnOffPendingIntent = turnOffBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

builder
  .setSmallIcon(R.drawable.ic_stat_notification)
  .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher))
  .setAutoCancel(true)
  .setLights(Color.BLUE, 500, 500)
  .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
  .addAction(R.drawable.ic_stat_notification, "Open", mainPendingIntent)
  .addAction(R.drawable.ic_stat_notification_off, "Turn off", turnOffPendingIntent);

NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(id, builder.build());

The problem:

Clicking on the unexpanded or expanded notification body or on the Open action button always transfers the intent with (KEY_TURN_OFF_NOTIFICATION_ID) extra.

I've tried ditching the TaskStackBuilder and creating PendingIntents simply:

Intent mainIntent = new Intent(context, MainActivity.class);
PendingIntent piMain = PendingIntent.getActivity(context, 0, mainIntent, 0);

Intent turnOffIntent = new Intent(context, MainActivity.class);
turnOffIntent.putExtra(MainApp.KEY_TURN_OFF_NOTIFICATION_ID, id);
PendingIntent piTurnOff = PendingIntent.getActivity(context, 0, turnOffIntent, 0);

but, to same effect :(

If I ommit setContentIntent(), naturally, tapping on the notification body does nothing.

If I set setContentIntent() after setting actions, then the extra is never received in the MainActivity.

like image 244
Saran Avatar asked Feb 08 '14 23:02

Saran


People also ask

What is a PendingIntent?

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it.

How do I get intent from PendingIntent?

It seems you can get the Intent (retrieve the Extras originally stored with it) if it is currently held by AlarmManager if you call PendingIntent. getService (or maybe . getBroadcast ) with the same requestCode as the original and no flags, and then immediately immediately send() the intent to oneself.

What is requestCode in PendingIntent?

1- requestCode is used to get the same pending intent later on (for cancelling etc) 2- Yes, they will get override as long as your specify the same Receiver to your Intent that you specify on your PendingIntent.


3 Answers

From the doc:

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.

So you have to make those intents different as in Intent.filterEquals method:

That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.

As a side note, I had the same problem while working on the download notifications of firefox for android here

like image 164
fedepaol Avatar answered Oct 24 '22 06:10

fedepaol


Hence PendingIntent.FLAG_UPDATE_CURRENT flag will just overwrite the extras if you are creating new intent where only the extras change.

Try adding distinct

  • action like intent.setAction("DISTINCT.ACTION.HERE") or
  • category like intent.addCategory("DISTINCT.CATEGORY.HERE")

for each intents.

cheers :-)

like image 4
Mohan Avatar answered Oct 24 '22 07:10

Mohan


The proper way to differentiate between the two requests is to set a unique requestCode for each one.

Taking the above code as an example, assign unique requestCodes like so:

int mainRequestCode = 1;
int turnOffRequestCode = 2;

Intent mainIntent = new Intent(context, MainActivity.class);
PendingIntent piMain = PendingIntent.getActivity(context, mainRequestCode, mainIntent, 0);

Intent turnOffIntent = new Intent(context, MainActivity.class);
turnOffIntent.putExtra(MainApp.KEY_TURN_OFF_NOTIFICATION_ID, id);
PendingIntent piTurnOff = PendingIntent.getActivity(context, turnOffRequestCode, turnOffIntent, 0);
like image 1
farmerbb Avatar answered Oct 24 '22 07:10

farmerbb