blob: b7051ab5f1fabfa5c02c148877b3f6e2b208a40a [file] [log] [blame]
page.title=Preserving Navigation when Starting an Activity
page.tags=notifications
helpoutsWidget=true
trainingnavtop=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#DirectEntry">Set up a regular activity PendingIntent</a></li>
<li><a href="#ExtendedNotification">Set up a special activity PendingIntent</a></li>
</ol>
<!-- other docs (NOT javadocs) -->
<h2>You should also read</h2>
<ul>
<li>
<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Notifications</a> API Guide
</li>
<li>
<a href="{@docRoot}guide/components/intents-filters.html">
Intents and Intent Filters
</a>
</li>
<li>
<a href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design Guide
</li>
</ul>
</div>
</div>
<p>
Part of designing a notification is preserving the user's expected navigation experience.
For a detailed discussion of this topic, see the
<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#NotificationResponse">Notifications</a>
API guide.
There are two general situations:
</p>
<dl>
<dt>
Regular activity
</dt>
<dd>
You're starting an {@link android.app.Activity} that's part of the application's normal
workflow.
</dd>
<dt>
Special activity
</dt>
<dd>
The user only sees this {@link android.app.Activity} if it's started from a notification.
In a sense, the {@link android.app.Activity} extends the notification by providing
information that would be hard to display in the notification itself.
</dd>
</dl>
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="DirectEntry">Set Up a Regular Activity PendingIntent</h2>
<p>
To set up a {@link android.app.PendingIntent} that starts a direct entry
{@link android.app.Activity}, follow these steps:
</p>
<ol>
<li>
Define your application's {@link android.app.Activity} hierarchy in the manifest. The final XML should look like this:
</p>
<pre>
&lt;activity
android:name=".MainActivity"
android:label="&#64;string/app_name" &gt;
&lt;intent-filter&gt;
&lt;action android:name="android.intent.action.MAIN" /&gt;
&lt;category android:name="android.intent.category.LAUNCHER" /&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;
&lt;activity
android:name=".ResultActivity"
android:parentActivityName=".MainActivity"&gt;
&lt;meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity"/&gt;
&lt;/activity&gt;
</pre>
</li>
<li>
Create a back stack based on the {@link android.content.Intent} that starts the
{@link android.app.Activity}. For example:
</p>
<pre>
int id = 1;
...
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());
</pre>
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="ExtendedNotification">Set Up a Special Activity PendingIntent</h2>
<p>
A special {@link android.app.Activity} doesn't need a back stack, so you don't have to
define its {@link android.app.Activity} hierarchy in the manifest, and you don't have
to call
{@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} to build a
back stack. Instead, use the manifest to set up the {@link android.app.Activity} task options,
and create the {@link android.app.PendingIntent} by calling
{@link android.app.PendingIntent#getActivity getActivity()}:
</p>
<ol>
<li>
In your manifest, add the following attributes to the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html">&lt;activity&gt;</a></code>
element for the {@link android.app.Activity}:
<dl>
<dt>
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#nm">android:name</a>="<i>activityclass</i>"</code>
</dt>
<dd>
The activity's fully-qualified class name.
</dd>
<dt>
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#aff">android:taskAffinity</a>=""</code>
</dt>
<dd>
Combined with the
{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} flag
that you set in code, this ensures that this {@link android.app.Activity} doesn't
go into the application's default task. Any existing tasks that have the
application's default affinity are not affected.
</dd>
<dt>
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#exclude">android:excludeFromRecents</a>="true"</code>
</dt>
<dd>
Excludes the new task from <i>Recents</i>, so that the user can't accidentally
navigate back to it.
</dd>
</dl>
<p>
This snippet shows the element:
</p>
<pre>
&lt;activity
android:name=".ResultActivity"
...
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true"&gt;
&lt;/activity&gt;
...
</pre>
</li>
<li>
Build and issue the notification:
<ol style="list-style-type: lower-alpha;">
<li>
Create an {@link android.content.Intent} that starts the
{@link android.app.Activity}.
</li>
<li>
Set the {@link android.app.Activity} to start in a new, empty task by calling
{@link android.content.Intent#setFlags setFlags()} with the flags
{@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK}
and
{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK FLAG_ACTIVITY_CLEAR_TASK}.
</li>
<li>
Set any other options you need for the {@link android.content.Intent}.
</li>
<li>
Create a {@link android.app.PendingIntent} from the {@link android.content.Intent}
by calling {@link android.app.PendingIntent#getActivity getActivity()}.
You can then use this {@link android.app.PendingIntent} as the argument to
{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
setContentIntent()}.
</li>
</ol>
<p>
The following code snippet demonstrates the process:
</p>
<pre>
// Instantiate a Builder object.
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
// Creates an Intent for the Activity
Intent notifyIntent =
new Intent(new ComponentName(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 notifyIntent =
PendingIntent.getActivity(
this,
0,
notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
// Puts the PendingIntent into the notification builder
builder.setContentIntent(notifyIntent);
// 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());
</pre>
</li>
</ol>