Skip to content

Commit cc7bd5a

Browse files
Dianne HackbornAndroid (Google) Code Review
authored andcommitted
Merge "Update notification documentation to follow current guidelines." into ics-mr1
2 parents bd9d9d3 + 6ceca58 commit cc7bd5a

File tree

3 files changed

+154
-103
lines changed

3 files changed

+154
-103
lines changed

core/java/android/app/Notification.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ public class Notification implements Parcelable
113113
* {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
114114
* that you take care of task management as described in the
115115
* <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
116-
* Stack</a> document.
116+
* Stack</a> document. In particular, make sure to read the notification section
117+
* <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
118+
* Notifications</a> for the correct ways to launch an application from a
119+
* notification.
117120
*/
118121
public PendingIntent contentIntent;
119122

@@ -765,7 +768,9 @@ public Builder setContent(RemoteViews views) {
765768
* Supply a {@link PendingIntent} to send when the notification is clicked.
766769
* If you do not supply an intent, you can now add PendingIntents to individual
767770
* views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
768-
* RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
771+
* RemoteViews.setOnClickPendingIntent(int,PendingIntent)}. Be sure to
772+
* read {@link Notification#contentIntent Notification.contentIntent} for
773+
* how to correctly use this.
769774
*/
770775
public Builder setContentIntent(PendingIntent intent) {
771776
mContentIntent = intent;

docs/html/guide/practices/ui_guidelines/activity_task_design.jd

Lines changed: 14 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ parent.link=index.html
4040
<li><a href=#reusing_tip>Handle case where no activity matches</a></li>
4141
<li><a href=#activity_launching_tip>Consider how to launch your activities</a></li>
4242
<li><a href=#activities_added_to_task_tip>Allow activities to add to current task</a></li>
43-
<li><a href=#notifications_get_back_tip>Notifications should let user easily get back</li>
43+
<li><a href=#notifications_get_back_tip>Notifications and App Widgets should provide consistent back behavior</li>
4444
<li><a href=#use_notification_tip>Use the notification system</a></li>
4545
<li><a href=#taking_over_back_key>Don't take over BACK key unless you absolutely need to</a></li>
4646
</ol>
@@ -1063,110 +1063,23 @@ MAIN and
10631063
</p>
10641064

10651065

1066-
<h3 id="notifications_get_back_tip">Notifications should let the user easily get back to the previous activity</h3>
1066+
<h3 id="notifications_get_back_tip">Notifications and App Widgets should provide consistent back behavior</h3>
10671067
<p>
1068-
Applications that are in the background or not running can have
1069-
services that send out notifications to the user letting them know about
1070-
events of interest. Two examples are Calendar, which can send out notifications of
1071-
upcoming events, and Email, which can send out notifications when new
1072-
messages arrive. One of the user interface guidelines is that when the
1073-
user is in activity A, gets a notification for activity B and
1074-
picks that notification, when they press the BACK key, they should
1075-
go back to activity A.&nbsp;
1068+
Notifications and app widgets are two common ways that a user can launch
1069+
your app through something besides its main icon in Launcher. You must
1070+
take care when implementing these so that the user has a consistent experience
1071+
with the back button, not causing surprises in where they return to or the
1072+
state the application ends up in.
10761073
</p>
10771074

10781075
<p>
1079-
The following scenario shows how the activity stack should work
1080-
when the user responds to a notification.
1081-
</p>
1082-
1083-
<ol>
1084-
<li>
1085-
User is creating a new event in Calendar. They realize they
1086-
need to copy part of an email message into this event
1087-
</li>
1088-
<li>
1089-
The user chooses Home &gt; Gmail
1090-
</li>
1091-
<li>
1092-
While in Gmail, they receive a notification from Calendar for an upcoming meeting
1093-
</li>
1094-
<li>
1095-
So they choose that notification, which takes them to a
1096-
dedicated Calendar activity that displays brief details of the
1097-
upcoming meeting
1098-
</li>
1099-
<li>
1100-
The user chooses this short notice to view further details
1101-
</li>
1102-
<li>
1103-
When done viewing the event, the user presses the BACK
1104-
key. They should be taken to Gmail, which is where they were
1105-
when they took the notification
1106-
</li>
1107-
</ol>
1108-
1109-
<p>
1110-
This behavior doesn't necessarily happen by default.
1111-
</p>
1112-
1113-
<p>
1114-
Notifications generally happen primarily in one of two ways:
1115-
</p>
1116-
1117-
<ul>
1118-
<li>
1119-
<b>The chosen activity is dedicated for notification only</b> -
1120-
For example, when the user receives a
1121-
Calendar notification, choosing that
1122-
notification starts a special activity that displays a list
1123-
of upcoming calendar events &mdash; this view is available only
1124-
from the notification, not through the Calendar's own user
1125-
interface. After viewing this upcoming event, to ensure that
1126-
the user pressing the BACK key will return to the activity
1127-
the user was in when they picked the notification, you would
1128-
make sure this dedicated activity does not have the same
1129-
task affinity as the Calendar or any other activity. (You do
1130-
this by setting task affinity to the empty string, which
1131-
means it has no affinity to anything.) The explanation for
1132-
this follows.
1133-
1134-
<p>
1135-
Because of the way tasks work, if the taskAffinity of the
1136-
dedicated activity is kept as its default, then pressing the
1137-
BACK key (in step 6, above) would go to Calendar, rather
1138-
than Gmail. The reason is that, by default, all activities
1139-
in a given application have the same task
1140-
affinity. Therefore, the task affinity of the dedicated
1141-
activity matches the Calendar task, which is already running
1142-
in step 1. This means in step 4, choosing the notification
1143-
brings the existing Calendar event (in step 1) forward and
1144-
starts the dedicated activity on top of it. This is not
1145-
what you want to have happen. Setting the dedicated
1146-
activity's taskAffinity to empty string fixes this.
1147-
</p>
1148-
</li>
1149-
1150-
<li>
1151-
<b>The chosen activity is not dedicated, but always comes to
1152-
the foreground in its initial state</b> - For example, in
1153-
response to a notification, when the Gmail application comes
1154-
to the foreground, it always presents the list of conversations.
1155-
You can ensure this happens by setting a "clear top" flag in the
1156-
intent that the notification triggers. This ensures that when the
1157-
activity is launched, it displays its initial activity, preventing
1158-
Gmail from coming to the foreground in whatever state the user last
1159-
happened to be viewing it. (To do this, you put {@link
1160-
android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP
1161-
FLAG_ACTIVITY_CLEAR_TOP} in the intent you pass to startActivity()).
1162-
</li>
1163-
</ul>
1164-
1165-
<p>
1166-
There are other ways to handle notifications, such as bringing the
1167-
activity to the foreground, set to display specific data, such as
1168-
displaying the text message thread for the person who just sent a
1169-
new text message.
1076+
The
1077+
<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
1078+
Notifications</a> section of the developer guide's
1079+
<a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
1080+
documentation provides an overview of how to write code to correctly handle
1081+
notification. This dicussion applies equally to handling interactions with
1082+
app widgets.
11701083
</p>
11711084

11721085
<p>

docs/html/guide/topics/ui/notifiers/notifications.jd

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ user clicks it</li>
1616
<h2>In this document</h2>
1717
<ol>
1818
<li><a href="#Basics">The Basics</a></li>
19+
<li><a href="#HandlingNotifications">Responding to Notifications</a></li>
1920
<li><a href="#ManageYourNotifications">Managing your Notifications</a></li>
2021
<li><a href="#CreateANotification">Creating a Notification</a>
2122
<ol>
@@ -137,6 +138,138 @@ mNotificationManager.notify(HELLO_ID, notification);
137138
</ol>
138139

139140

141+
<h2 id="HandlingNotifications">Responding to Notifications</h2>
142+
143+
<p>A central part of the user's experience with a notification revolves around
144+
how it interacts with the application's UI flow. You must implement
145+
this correctly to provide a consistent user experience within your app.</p>
146+
147+
<p>Two typical examples of notifications are provided by Calendar, which can send out
148+
notifications of upcoming events, and Email, which can send out notifications
149+
when new messages arrive. These represent the two recommended patterns for handling
150+
notifications: either launching into an activity that is separate from the
151+
main application, or launching an entirely new instance of the application
152+
showing the appropriate point for the notification.</p>
153+
154+
<p>The following scenario shows how the activity stack should work
155+
in these two typical notification flows, first handling a Calendar notification:
156+
</p>
157+
158+
<ol>
159+
<li>User is creating a new event in Calendar. They realize they
160+
need to copy part of an email message into this event.
161+
</li>
162+
<li>
163+
The user chooses Home &gt; Email.
164+
</li>
165+
<li>
166+
While in Email, they receive a notification from Calendar for an upcoming
167+
meeting.
168+
</li>
169+
<li>
170+
So they choose that notification, which takes them to a
171+
dedicated Calendar activity that displays brief details of the
172+
upcoming meeting.
173+
</li>
174+
<li>
175+
The user has seen enough to know they have a meeting coming up,
176+
so they press the BACK button. They are now returned to Email, which
177+
is where they were when they took the notification.
178+
</li>
179+
</ol>
180+
181+
<p>Handling an Email notification:</p>
182+
183+
<ol>
184+
<li>
185+
The user is currently in Email composing a message, and needs to
186+
check a date in their calendar.
187+
</li>
188+
<li>
189+
The user chooses Home &gt; Calendar.
190+
</li>
191+
<li>
192+
While in Calendar, they receive a notification from Email about a new
193+
message.
194+
</li>
195+
<li>
196+
They select the notification, which brings them to Email with the message
197+
details displayed. This has replaced what they were previously doing
198+
(writing an e-mail), but that message is still saved in their drafts.
199+
</li>
200+
<li>
201+
The user presses BACK once to go to the message list (the typical flow in the
202+
Email app), and press BACK again to return to Calendar as they left it.
203+
</li>
204+
</ol>
205+
206+
<p>In an Email style of notification, the UI launched by the notification
207+
shows the main application in a state representing that notification.
208+
For example, when the Email application comes to the foreground from its
209+
notification, it displays either the conversion list or a specific
210+
conversation depending on whether there are multiple or only one new
211+
email. To achieve this, we want to completely replace whatever current
212+
state the application is in with a new activity stack representing the
213+
new notification state.</p>
214+
215+
<p>The following code illustrates how to show this kind of notification. Of
216+
most interest is the <code>makeMessageIntentStack()</code> method, which constructs
217+
an array of intents representing the app's new activity stack for this state.
218+
(If you are using fragments, you may need to initialize your fragment and
219+
app state so that pressing BACK will switch the UI back to its parent state.)
220+
The core of this is the {@link android.content.Intent#makeRestartActivityTask
221+
Intent.makeRestartActivityTask()} method, which constructs the root activity
222+
of the stack with the appropriate flags, such as
223+
{@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TASK Intent.FLAG_ACTIVITY_CLEAR_TASK}.</p>
224+
225+
{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java
226+
app_notification}
227+
228+
<p>In a Calendar style of notification, the UI launched by the notification
229+
is a dedicated activity that is not part of the normal application flow.
230+
For example, when the user receives a Calendar notification, choosing that
231+
notification starts a special activity that displays a list
232+
of upcoming calendar events &mdash; this view is available only
233+
from the notification, not through the Calendar's normal user
234+
interface.</p>
235+
236+
<p>The code for posting this type of notification is very straight-forward; it
237+
is like the above, but the {@link android.app.PendingIntent} is for just a single
238+
activity, our dedicated notification activity.</p>
239+
240+
{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessage.java
241+
interstitial_notification}
242+
243+
<p>This is not enough, however. Normally Android considers all activities within
244+
an application to be part of that application's UI flow, so simply launching the
245+
activity like this can cause it to be mixed with your normal application back stack
246+
in undesired ways. To make it behave correctly, in the manifest declaration
247+
for the activity the attributes
248+
<code>android:launchMode="singleInstance"</code> and
249+
<code>android:excludeFromRecents="true"</code>
250+
must be set. The full activity declaration for this sample is:</p>
251+
252+
{@sample development/samples/ApiDemos/AndroidManifest.xml interstitial_affinity}
253+
254+
<p>Because of the use of <code>singleInstance</code>, you must be careful about launching
255+
any other activities from this one. These activities will be launched
256+
in their own task, and care must be taken to make sure this interacts
257+
well with the current state of your application's task. This is essentially
258+
the same as switching to the main application as described for the Email style
259+
notification shown before. Given the <code>makeMessageIntentStack()</code>
260+
method previously shown, handling a click here would look something like this:</p>
261+
262+
{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageInterstitial.java
263+
app_launch}
264+
265+
<p>If you don't want to use the <code>singleInstance</code> launch mode for
266+
this activity, an alternative approach is to use <code>android:taskAffinity=""</code>.
267+
This tells Android that the activity should not be treated as part of the
268+
main application flow, so it will not get mixed together with that. All of the
269+
other issues discussed here do still apply, though this would allow you to start
270+
additional activities that are part of this notification task instead of switching
271+
to and replacing the main application task.</p>
272+
140273
<h2 id="ManageYourNotifications">Managing your Notifications</h2>
141274

142275
<p>The {@link android.app.NotificationManager} is a system service that manages all

0 commit comments

Comments
 (0)