Back to main activity from notification-created activity

I'm trying to implement the behaviour described here, where a notification (or whatever) starts an "internal" activity in your app, and then when the user pressed back it goes to my "home" activity.

The Android docs say

In the case of the Back button, you should make navigation more predictable by inserting into the task's back stack the complete upward navigation path to the app's topmost screen. This allows users who've forgotten how they entered your app to navigate to the app's topmost screen before exiting.

Is there a good way to actually do that? Other questions on Stackoverflow suggest starting the main activity with an intent that tells it to start the internal activity, but that seems like a huge hack, that I somewhat doubt Google would have used in Gmail, and I assume there is a decent method, given that they are advocating the behaviour.

So is there a non-hacky way to do this?


Aha, I simply need to use PendingIntent.getActivities() instead of getActivity(). Also worth mentioning is TaskStackBuilder

Here is some code:

    Intent backIntent = new Intent(ctx, MainActivity.class);
    backIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    Intent intent = new Intent(ctx, ConversationActivity.class);
    intent.putExtra("whatever", whatever);
    final PendingIntent pendingIntent = PendingIntent.getActivities(ctx, UNIQUE_REQUEST_CODE++,
            new Intent[] {backIntent, intent}, PendingIntent.FLAG_ONE_SHOT);

Just tested it. It works like a charm. I initially suspected that there might be a problem if the app is already running, and you go to a notification. I.e. say you activity stack is (topmost on the right):

[MainActivity] [SomeActivity]

and you click a notification for ConversationActivity. Would you get:?

[MainActivity] [SomeActivity] [MainActivity] [ConversationActivity]

Well, it turns out you magically get

[MainActivity] [SomeActivity] [ConversationActivity]

which is what I wanted, but I have no idea how it does that. I haven't set any special options on any of the activities. Oh well!


There is a new guide on how to do this, and it suggest some slightly different practices than the answers above:

https://developer.android.com/guide/topics/ui/notifiers/notifications.html#NotificationResponse

Note, don't actually use 0 for your requestCode in getPendingIntent. For me any number not 0 worked, but 0 resulted in the back button just going to the launcher.


I know 2 ways of achieving this:

  1. Start your home activity from within activity started by notification. This may become quite trick, as you will have to differentiate and keep track of various possible entry points.
  2. You always start with you home activity which checks if is being started by a notification and then starts the notification activity. This ensures a consistent entry point and the back stack will be there when user press Up key.

Regards.


Intent displayIntent = new Intent(getApplicationContext(), TargetActivity.class);

displayIntent.putExtra("extra_id", "extra_key");

TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addParentStack(TargetActivity.class);
stackBuilder.addNextIntent(displayIntent);
stackBuilder.editIntentAt(1).putExtra("extra_id", "extra_key");

PendingIntent contentIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
        getApplicationContext(), "123").setSmallIcon(R.drawable.logo)
        .setContentTitle("GCM Notification")
        .setStyle(new NotificationCompat.BigTextStyle().bigText("Sample")).setContentText("sample text");

mBuilder.setContentIntent(contentIntent);

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(456, mBuilder.build());
stackBuilder.startActivities();

In addition to the above code also provide appropriate parent class names in your AndroidManifest.xml file.


This solution works great exactly for this problem

android:noHistory="true"