androidandroid-activityandroid-notificationsandroid-pendingintentandroid-task

Android Task Created by PendingInent cannot start another activity with pendingIntent again


I have 2 activities: Main (will schedule notification with alarm manager), and Message (to handle user navigation or notification). No launch mode and flags are set on Message. Message is opened by user navigation or notification.

The normal flow of control that is working fine:

(Home Screen) -> (user) -> new task of Main -> (user) -> new Message -> (notification) -> new Message -> (notification) -> new Message -> (user) -> new Message

When the app is not loaded and a new task is started by notification for Message. The flow is ok:

(Home Screen) -> (notification) -> new task of Message -> (user) -> new Message

The problem comes in when a second notification is clicked, it is not handled properly. A new Message is expected for the second notification.

(Home Screen) -> (notification) -> new task of Message -> (notification) -> X nothing now but expect new Message

The last notification pending intent cannot start Message (no OnCreate, no OnNewIntent). No new task is started to handle it too. If the task is in background, notification pending intent will bring the task to foreground (but no new activity). The result is that with a task that was started by pending intent, any further pending Intent will not create new activity. Not sure if it is about pending intent security concerns or something else.

How can I start new activity Message with notification pending intent when the task is started by pending intent? Any help will be appreciated.

Thanks,

Nick

Code is written in Xamarin for reference:

Code for setting alarm, context is the Activity context.

    Intent intentScheduleReminder = new Intent(context, typeof(BroadcastReceiver));
    intentScheduleReminder.SetAction(PlatformConstants.NotificationActionShow);
    intentScheduleReminder.PutExtra(PlatformConstants.ScheduleReminderId, scheduleReminder.Id);
    PendingIntent intentAlarm = PendingIntent.GetBroadcast(context, scheduleReminder.Id, intentScheduleReminder, PendingIntentFlags.CancelCurrent);

    Java.Util.Calendar calendar = DroidUtility.ConvertDateTimeToCalendar(scheduleReminder.ScheduleDateTime);
    AlarmManager alarmManager = (AlarmManager)Application.Context.GetSystemService(Context.AlarmService);
    alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, calendar.TimeInMillis, intentAlarm);

Code for sending Notification. Pending Intent is created with context from BroadcastReceiver.OnReceive

    var builder = new NotificationCompat.Builder(Application.Context,  PlatformConstants.NotificationChannelIdBillReminder)
        .SetContentTitle(appNotification.Title)
        .SetContentText(appNotification.Message)
        .SetSmallIcon(Resource.Drawable.ic_appicon_24dp)
        .SetLargeIcon(largeIconBitmap)
        .SetAutoCancel(true)
        .SetOnlyAlertOnce(true);
    Intent intent = new Intent((Context)BroadcastContext, typeof(InfiniteScrollingParentFsActivity));
    intent.PutExtra(……
    PendingIntent pendingIntent = PendingIntent.GetActivity((Context)BroadcastContext, notificationId, intent, 0);
    builder.SetContentIntent(pendingIntent);
    Notification notification = builder.Build();
    NotificationManager notificationManager = (NotificationManager)Application.Context.GetSystemService(Context.NotificationService);
    notificationManager.Notify(notificationId, notification);

Solution

  • Read the documentation for PendingIntent carefully. Especially this part:

    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.

    Your notification is always firing the same Intent:

    Intent intent = new Intent((Context)BroadcastContext, typeof(InfiniteScrollingParentFsActivity));
    intent.PutExtra(……
    PendingIntent pendingIntent = PendingIntent.GetActivity((Context)BroadcastContext, notificationId, intent, 0);
    

    So it's always going to re-open the same Activity if it exists.

    You probably want to make your intent unique so each one represents exactly one message. You can do this by setting a unique value for the intent's data field:

    Intent intent = new Intent((Context)BroadcastContext, typeof(InfiniteScrollingParentFsActivity));
    intent.PutExtra(……
    
    intent.SetData(something that uniquely ids this message here) <----
    
    PendingIntent pendingIntent = PendingIntent.GetActivity((Context)BroadcastContext, notificationId, intent, 0);