When you start an Activity
from a notification, you must preserve the user's
expected navigation experience. Clicking Back should take the user back through the application's normal work flow to the Home screen, and clicking Recents should show the Activity
as
a separate task. To preserve the navigation experience, you should start the Activity
in
a fresh task. How you set up the PendingIntent
to give you a fresh
task depends on the nature of the Activity
you're starting. There
are two general situations:
- Regular activity
- You're starting an
Activity
that's part of the application's normal workflow. In this situation, set up thePendingIntent
to start a fresh task, and provide thePendingIntent
with a back stack that reproduces the application's normal Back behavior.Notifications from the Gmail app demonstrate this. When you click a notification for a single email message, you see the message itself. Touching Back takes you backwards through Gmail to the Home screen, just as if you had entered Gmail from the Home screen rather than entering it from a notification.
This happens regardless of the application you were in when you touched the notification. For example, if you're in Gmail composing a message, and you click a notification for a single email, you go immediately to that email. Touching Back takes you to the inbox and then the Home screen, rather than taking you to the message you were composing.
- Special activity
- The user only sees this
Activity
if it's started from a notification. In a sense, theActivity
extends the notification by providing information that would be hard to display in the notification itself. For this situation, set up thePendingIntent
to start in a fresh task. There's no need to create a back stack, though, because the startedActivity
isn't part of the application's activity flow. Clicking Back will still take the user to the Home screen.
Setting up a regular activity PendingIntent
To set up a PendingIntent
that starts a direct entry Activity
,
follow these steps:
- Define your application's
Activity
hierarchy in the manifest.- Add support for Android 4.0.3 and earlier. To do this, specify the parent of the
Activity
you're starting by adding a<meta-data>
element as the child of the<activity>
.For this element, set
android:name="android.support.PARENT_ACTIVITY"
. Setandroid:value="<parent_activity_name>"
where<parent_activity_name>
is the value ofandroid:name
for the parent<activity>
element. See the following XML for an example. - Also add support for Android 4.1 and later. To do this, add the
android:parentActivityName
attribute to the<activity>
element of theActivity
you're starting.
The final XML should look like this:
<activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ResultActivity" android:parentActivityName=".MainActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"/> </activity>
- Add support for Android 4.0.3 and earlier. To do this, specify the parent of the
- Create a back stack based on the
Intent
that starts theActivity
:- Create the
Intent
to start theActivity
. - Create a stack builder by calling
TaskStackBuilder.create()
. - Add the back stack to the stack builder by calling
addParentStack()
. For eachActivity
in the hierarchy you've defined in the manifest, the back stack contains anIntent
object that starts theActivity
. This method also adds flags that start the stack in a fresh task.Note: Although the argument to
addParentStack()
is a reference to the startedActivity
, the method call doesn't add theIntent
that starts theActivity
. Instead, that's taken care of in the next step. - Add the
Intent
that starts theActivity
from the notification, by callingaddNextIntent()
. Pass theIntent
you created in the first step as the argument toaddNextIntent()
. - If you need to, add arguments to
Intent
objects on the stack by callingTaskStackBuilder.editIntentAt()
. This is sometimes necessary to ensure that the targetActivity
displays meaningful data when the user navigates to it using Back. - Get a
PendingIntent
for this back stack by callinggetPendingIntent()
. You can then use thisPendingIntent
as the argument tosetContentIntent()
.
- Create the
The following code snippet demonstrates the process:
...
Intent resultIntent = new Intent(this, ResultActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent to the top of the stack
stackBuilder.addNextIntent(resultIntent);
// Gets a PendingIntent containing the entire back stack
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
...
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, builder.build());
Setting up a special activity PendingIntent
The following section describes how to set up a special activity PendingIntent
.
A special Activity
doesn't need a back stack, so you don't have to define
its Activity
hierarchy in the manifest, and you don't have to calladdParentStack()
to
build a back stack. Instead, use the manifest to set up the Activity
task
options, and create the PendingIntent
by callinggetActivity()
:
- In your manifest, add the following attributes to the
<activity>
element for theActivity
android:name="activityclass"
- The activity's fully-qualified class name.
android:taskAffinity=""
- Combined with the
FLAG_ACTIVITY_NEW_TASK
flag that you set in code, this ensures that thisActivity
doesn't go into the application's default task. Any existing tasks that have the application's default affinity are not affected. android:excludeFromRecents="true"
- Excludes the new task from Recents, so that the user can't accidentally navigate back to it.
This snippet shows the element:
<activity android:name=".ResultActivity" ... android:launchMode="singleTask" android:taskAffinity="" android:excludeFromRecents="true"> </activity> ...
- Build and issue the notification:
- Create an
Intent
that starts theActivity
. - Set the
Activity
to start in a new, empty task by callingsetFlags()
with the flagsFLAG_ACTIVITY_NEW_TASK
andFLAG_ACTIVITY_CLEAR_TASK
. - Set any other options you need for the
Intent
. - Create a
PendingIntent
from theIntent
by callinggetActivity()
. You can then use thisPendingIntent
as the argument tosetContentIntent()
.
The following code snippet demonstrates the process:
// Instantiate a Builder object. NotificationCompat.Builder builder = new NotificationCompat.Builder(this); // Creates an Intent for the Activity Intent notifyIntent = new Intent(this, ResultActivity.class); // Sets the Activity to start in a new, empty task notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // Creates the PendingIntent PendingIntent notifyPendingIntent = PendingIntent.getActivity( this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT ); // Puts the PendingIntent into the notification builder builder.setContentIntent(notifyPendingIntent); // Notifications are issued by sending them to the // NotificationManager system service. NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Builds an anonymous Notification object from the builder, and // passes it to the NotificationManager mNotificationManager.notify(id, builder.build());
- Create an