1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
|
page.title=Notifications
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li>
<a href="#NotificationUI">Notification Display Elements</a>
</li>
<li>
<a href="#CreateNotification">Creating a Notification</a>
</li>
<li>
<a href="#Managing">Managing Notifications</a>
</li>
<li>
<a href="#NotificationResponse">Preserving Navigation when Starting an Activity</a>
</li>
<li>
<a href="#Progress">Displaying Progress in a Notification</a>
</li>
<li>
<a href="#CustomNotification">Custom Notification Layouts</a>
</li>
</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.app.NotificationManager}</li>
<li>{@link android.support.v4.app.NotificationCompat}</li>
</ol>
<h2>Videos</h2>
<ol>
<li>
<a href="http://www.youtube.com/watch?v=Yc8YrVc47TI&feature=player_detailpage#t=1672s">
Notifications in 4.1</a>
</li>
</ol>
<h2>See also</h2>
<ol>
<li>
<a href="{@docRoot}design/patterns/notifications.html">Android Design: Notifications</a>
</li>
</ol>
</div>
</div>
<p>
A notification is a message you can display to the user outside of your application's
normal UI. When you tell the system to issue a notification, it first appears as an icon in the
<strong>notification area</strong>. To see the details of the notification, the user opens the
<strong>notification drawer</strong>. Both the notification area and the notification drawer
are system-controlled areas that the user can view at any time.
</p>
<img
id="figure1"
src="{@docRoot}images/ui/notifications/iconic_notification.png"
height="32"
alt="" />
<p class="img-caption">
<strong>Figure 1.</strong> Notifications in the notification area.
</p>
<img id="figure2" src="{@docRoot}images/ui/notifications/normal_notification.png"
height="240" alt="" />
<p class="img-caption">
<strong>Figure 2.</strong> Notifications in the notification drawer.
</p>
<div class="note design">
<p>
<strong>Notification Design</strong>
</p>
<p>
Notifications, as an important part of the Android UI, have their own design guidelines. To
learn how to design notifications and their interactions, read the Android Design Guide
<a href="{@docRoot}design/patterns/notifications.html">Notifications</a> topic.
</p>
</div>
<p class="note">
<strong>Note:</strong> This guide refers to the
{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} class
in the version 4 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.
The class {@link android.app.Notification.Builder Notification.Builder} was added in API
level 11.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="NotificationUI">Notification Display Elements</h2>
<p>
Notifications in the notification drawer appear in two main visual styles, normal view and
big view.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="NormalNotify">Normal view</h3>
<p>
A notification in normal view appears in an area that's up to 64 dp tall. Even if you create a
notification with a big view style, it will appear in normal view until it's expanded. This
is an example of a normal view:
</p>
<img
src="{@docRoot}images/ui/notifications/normal_notification_callouts.png"
alt=""
height="204"
id="figure3" />
<p class="img-caption">
<strong>Figure 3.</strong> Notification in normal view.
</p>
<p>
The callouts in the illustration refer to the following:
</p>
<ol>
<li>Content title</li>
<li>Large icon</li>
<li>Content text</li>
<li>Content info</li>
<li>Small icon</li>
<li>
Time that the notification was issued. You can set an explicit value with
{@link android.support.v4.app.NotificationCompat.Builder#setWhen setWhen()}; if you don't
it defaults to the time that the system received the notification.
</li>
</ol>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="BigNotify">Big view</h3>
<p>
A notification's big view appears only when the notification is expanded, which happens when the
notification is at the top of the notification drawer, or when the user expands the
notification with a gesture.
</p>
<p>
The following screenshot shows an inbox-style notification:
</p>
<img src="{@docRoot}images/ui/notifications/bigpicture_notification_callouts.png"
alt=""
height="240"
id="figure4" />
<p class="img-caption">
<strong>Figure 4.</strong> Big view notification.
</p>
<p>
Notice that the big view shares most of its visual elements with the normal view. The
only difference is callout number 7, the details area. Each big view style sets this area in
a different way. The available styles are:
</p>
<dl>
<dt>
Big picture style
</dt>
<dd>
The details area contains a bitmap up to 256 dp tall in its detail section.
</dd>
<dt>
Big text style
</dt>
<dd>
Displays a large text block in the details section.
</dd>
<dt>
Inbox style
</dt>
<dd>
Displays lines of text in the details section.
</dd>
</dl>
<p>
All of the big view styles also have the following content options that aren't
available in normal view:
</p>
<dl>
<dt>
Big content title
</dt>
<dd>
Allows you to override the normal view's content title with a title that appears only in
the expanded view.
</dd>
<dt>
Summary text
</dt>
<dd>
Allows you to add a line of text below the details area.
</dd>
</dl>
<p>
Applying a big view style to a notification is described in the section
<a href="#ApplyStyle">Applying a big view style to a notification</a>.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="CreateNotification">Creating a Notification</h2>
<p>
You specify the UI information and actions for a notification in a
{@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} object.
To create the notification itself, you call
{@link android.support.v4.app.NotificationCompat.Builder#build
NotificationCompat.Builder.build()}, which returns a {@link android.app.Notification} object
containing your specifications.
To issue the notification, you pass the {@link android.app.Notification} object to the system
by calling {@link android.app.NotificationManager#notify NotificationManager.notify()}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="Required">Required notification contents</h3>
<p>
A {@link android.app.Notification} object <em>must</em> contain the following:
</p>
<ul>
<li>
A small icon, set by
{@link android.support.v4.app.NotificationCompat.Builder#setSmallIcon setSmallIcon()}
</li>
<li>
A title, set by
{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}
</li>
<li>
Detail text, set by
{@link android.support.v4.app.NotificationCompat.Builder#setContentText setContentText()}
</li>
</ul>
<h3 id="Optional">Optional notification contents and settings</h3>
<p>
All other notification settings and contents are optional. To learn more about them,
see the reference documentation for {@link android.support.v4.app.NotificationCompat.Builder}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="Actions">Notification actions</h3>
<p>
Although they're optional, you should add at least one action to your notification.
An action allows users to go directly from the notification to an
{@link android.app.Activity} in your application, where they can look at one or more events
or do further work.
</p>
<p>
A notification can provide multiple actions. You should always define the action that's
triggered when the user touches the notification; usually this action opens an
{@link android.app.Activity} in your application. You can also add buttons to the notification
that perform additional actions such as snoozing an alarm or responding immediately to a text
message.
</p>
<p>
Inside a {@link android.app.Notification}, the action itself is defined by a
{@link android.app.PendingIntent} containing an {@link android.content.Intent} that starts
an {@link android.app.Activity} in your application. To associate the
{@link android.app.PendingIntent} with a gesture, call the appropriate method of
{@link android.support.v4.app.NotificationCompat.Builder}. For example, if you want to start
{@link android.app.Activity} when the user touches the notification text in
the notification drawer, you add the {@link android.app.PendingIntent} by calling
{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
</p>
<p>
Starting an {@link android.app.Activity} when the user touches the notification is the most
common action scenario. You can also start an {@link android.app.Activity} when the user
dismisses an {@link android.app.Activity}, and you can start an {@link android.app.Activity}
from an action button. To learn more, read the reference guide for
{@link android.support.v4.app.NotificationCompat.Builder}.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="SimpleNotification">Creating a simple notification</h3>
<p>
The following snippet illustrates a simple notification that specifies an activity to open when
the user touches the notification. Notice that the code creates a
{@link android.support.v4.app.TaskStackBuilder} object and uses it to create the
{@link android.app.PendingIntent} for the action. This pattern is explained in more detail
in the section <a href="#NotificationResponse">
Preserving Navigation when Starting an Activity</a>:
</p>
<pre>
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, ResultActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
</pre>
<p>That's it. Your user has now been notified.</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="ApplyStyle">Applying a big view style to a notification</h3>
<p>
To have a notification appear in a big view when it's expanded, first create a
{@link android.support.v4.app.NotificationCompat.Builder} object with the normal view options
you want. Next, call {@link android.support.v4.app.NotificationCompat.Builder#setStyle
Builder.setStyle()} with a big view style object as its argument.
</p>
<p>
For example, the following code snippet demonstrates how to alter the notification created
in the previous snippet to use the Inbox big view style:
</p>
<pre>
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Event tracker")
.setContentText("Events received")
NotificationCompat.InboxStyle inboxStyle =
new NotificationCompat.InboxStyle();
String[] events = new String[6];
// Sets a title for the Inbox style big view
inboxStyle.SetBigContentTitle("Event tracker details:");
...
// Moves events into the big view
for (int i=0; i < events.length; i++) {
inboxStyle.addLine(events[i]);
}
// Moves the big view style object into the notification object.
mBuilder.setStyle(inBoxStyle);
...
// Issue the notification here.
</pre>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="Managing">Managing Notifications</h2>
<p>
When you need to issue a notification multiple times for the same type of event, you
should avoid making a completely new notification. Instead, you should consider updating a
previous notification, either by changing some of its values or by adding to it, or both.
</p>
<p>
For example, Gmail notifies the user that new emails have arrived by increasing its count of
unread messages and by adding a summary of each email to the notification. This is called
"stacking" the notification; it's described in more detail in the
<a href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design guide.
</p>
<p>
The following section describes how to update notifications and also how to remove them.
</p>
<h3 id="Updating">Updating notifications</h3>
<p>
To set up a notification so it can be updated, issue it with a notification ID by
calling {@link android.app.NotificationManager#notify(int, Notification)
NotificationManager.notify(ID, notification)}. To update this notification once you've issued
it, update or create a {@link android.support.v4.app.NotificationCompat.Builder} object,
build a {@link android.app.Notification} object from it, and issue the
{@link android.app.Notification} with the same ID you used previously. If
the previous notification is still visible, the system updates it from the contents of
the {@link android.app.Notification} object. If the previous notification has been dismissed, a
new notification is created instead.
</p>
<p>
The following snippet demonstrates a notification that is updated to reflect the
number of events that have occurred. It stacks the notification, showing a summary:
</p>
<pre>
mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated
int notifyID = 1;
mNotifyBuilder = new NotificationCompat.Builder(this)
.setContentTitle("New Message")
.setContentText("You've received new messages.")
.setSmallIcon(R.drawable.ic_notify_status)
numMessages = 0;
// Start of a loop that processes data and then notifies the user
...
mNotifyBuilder.setContentText(currentText)
.setNumber(++numMessages);
// Because the ID remains unchanged, the existing notification is
// updated.
mNotificationManager.notify(
notifyID,
mNotifyBuilder.build());
...
</pre>
<p>
This produces a notification that looks like this:
</p>
<img
id="figure5"
src="{@docRoot}images/ui/notifications/updated_notification.png"
alt=""
height="118"/>
<p class="img-caption">
<strong>Figure 5.</strong> Updated notification displayed in the notification drawer.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="Removing">Removing notifications</h3>
<p>
Notifications remain visible until one of the following happens:
</p>
<ul>
<li>
The user dismisses the notification either individually or by using "Clear All" (if
the notification can be cleared).
</li>
<li>
The user touches the notification, and you called
{@link android.support.v4.app.NotificationCompat.Builder#setAutoCancel setAutoCancel()} when
you created the notification.
</li>
<li>
You call {@link android.app.NotificationManager#cancel(int) cancel()} for a specific
notification ID. This method also deletes ongoing notifications.
</li>
<li>
You call {@link android.app.NotificationManager#cancelAll() cancelAll()}, which removes
all of the notifications you previously issued.
</li>
</ul>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="NotificationResponse">Preserving Navigation when Starting an Activity</h2>
<p>
When you start an {@link android.app.Activity} from a notification, you must preserve the
user's expected navigation experience. Clicking <i>Back</i> should take the user back through
the application's normal work flow to the Home screen, and clicking <i>Recents</i> should show
the {@link android.app.Activity} as a separate task. To preserve the navigation experience, you
should start the {@link android.app.Activity} in a fresh task. How you set up the
{@link android.app.PendingIntent} to give you a fresh task depends on the nature of the
{@link android.app.Activity} you're starting. 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. In this situation, set up the {@link android.app.PendingIntent} to
start a fresh task, and provide the {@link android.app.PendingIntent} with a back stack
that reproduces the application's normal <i>Back</i> behavior.
<p>
Notifications from the Gmail app demonstrate this. When you touch a notification for
a single email message, you see the message itself. Touching <b>Back</b> 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.
</p>
<p>
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 <i>Back</i>
takes you to the inbox and then the Home screen, rather than taking you to the
message you were composing.
</p>
</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. For this situation,
set up the {@link android.app.PendingIntent} to start in a fresh task. There's no need to
create a back stack, though, because the started {@link android.app.Activity} isn't part of
the application's activity flow. Clicking <i>Back</i> will still take the user to the
Home screen.
</dd>
</dl>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="DirectEntry">Setting up a regular activity PendingIntent</h3>
<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.
<ol style="list-style-type: lower-alpha;">
<li>
Add support for API versions 15 and earlier. To do this, specify the parent of the
{@link android.app.Activity} you're starting by adding a
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code>
element as the child of the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>.
<p>
For this element, set
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a>="android.support.PARENT_ACTIVITY"</code>.
Set
<code><a href="{@docRoot}/guide/topics/manifest/meta-data-element.html#val">android:value</a>="<parent_activity_name>"</code>
where <code><parent_activity_name></code> is the value of
<code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html#nm">android:name</a></code>
for the parent
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>
element. See the following XML for an example.
</p>
</li>
<li>
Also add support for API versions 16 and later. To do this, add the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">android:parentActivityName</a></code>
attribute to the
<code><a href="{@docRoot}guide/topics/manifest/activity-element.html"><activity></a></code>
element of the {@link android.app.Activity} you're starting.
</li>
</ol>
<p>
The final XML should look like this:
</p>
<pre>
<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>
</pre>
</li>
<li>
Create a back stack based on the {@link android.content.Intent} that starts the
{@link android.app.Activity}:
<ol style="list-style-type: lower-alpha;">
<li>
Create the {@link android.content.Intent} to start the {@link android.app.Activity}.
</li>
<li>
Create a stack builder by calling {@link android.app.TaskStackBuilder#create
TaskStackBuilder.create()}.
</li>
<li>
Add the back stack to the stack builder by calling
{@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}.
For each {@link android.app.Activity} in the hierarchy you've defined in the
manifest, the back stack contains an {@link android.content.Intent} object that
starts the {@link android.app.Activity}. This method also adds flags that start the
stack in a fresh task.
<p class="note">
<strong>Note:</strong> Although the argument to
{@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()}
is a reference to the started {@link android.app.Activity}, the method call
doesn't add the {@link android.content.Intent} that starts the
{@link android.app.Activity}. Instead, that's taken care of in the next step.
</p>
</li>
<li>
Add the {@link android.content.Intent} that starts the {@link android.app.Activity}
from the notification, by calling
{@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
Pass the {@link android.content.Intent} you created in the first step as the
argument to
{@link android.support.v4.app.TaskStackBuilder#addNextIntent addNextIntent()}.
</li>
<li>
If you need to, add arguments to {@link android.content.Intent} objects on the
stack by calling {@link android.support.v4.app.TaskStackBuilder#editIntentAt
TaskStackBuilder.editIntentAt()}. This is sometimes necessary to ensure that the
target {@link android.app.Activity} displays meaningful data when the user navigates
to it using <i>Back</i>.
</li>
<li>
Get a {@link android.app.PendingIntent} for this back stack by calling
{@link android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.
You can then use this {@link android.app.PendingIntent} as the argument to
{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
setContentIntent()}.
</li>
</ol>
</li>
</ol>
<p>
The following code snippet demonstrates the process:
</p>
<pre>
...
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>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="ExtendedNotification">Setting up a special activity PendingIntent</h3>
<p>
The following section describes how to set up a special activity
{@link android.app.PendingIntent}.
</p>
<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"><activity></a></code>
element for the {@link android.app.Activity}
<dl>
<dt>
<code><a href="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>
<activity
android:name=".ResultActivity"
...
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true">
</activity>
...
</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(FLAG_ACTIVITY_NEW_TASK | 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>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="Progress">Displaying Progress in a Notification</h2>
<p>
Notifications can include an animated progress indicator that shows users the status
of an ongoing operation. If you can estimate how long the operation takes and how much of it
is complete at any time, use the "determinate" form of the indicator
(a progress bar). If you can't estimate the length of the operation, use the
"indeterminate" form of the indicator (an activity indicator).
</p>
<p>
Progress indicators are displayed with the platform's implementation of the
{@link android.widget.ProgressBar} class.
</p>
<p>
To use a progress indicator, call
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. The
determinate and indeterminate forms are described in the following sections.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="FixedProgress">Displaying a fixed-duration progress indicator</h3>
<p>
To display a determinate progress bar, add the bar to your notification by calling
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
setProgress(max, progress, false)} and then issue the notification. As your operation proceeds,
increment <code>progress</code>, and update the notification. At the end of the operation,
<code>progress</code> should equal <code>max</code>. A common way to call
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
is to set <code>max</code> to 100 and then increment <code>progress</code> as a
"percent complete" value for the operation.
</p>
<p>
You can either leave the progress bar showing when the operation is done, or remove it. In
either case, remember to update the notification text to show that the operation is complete.
To remove the progress bar, call
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
setProgress(0, 0, false)}. For example:
</p>
<pre>
...
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle("Picture Download")
.setContentText("Download in progress")
.setSmallIcon(R.drawable.ic_notification);
// Start a lengthy operation in a background thread
new Thread(
new Runnable() {
@Override
public void run() {
int incr;
// Do the "lengthy" operation 20 times
for (incr = 0; incr <= 100; incr+=5) {
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate"
// state
mBuilder.setProgress(100, incr, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(0, mBuilder.build());
// Sleeps the thread, simulating an operation
// that takes time
try {
// Sleep for 5 seconds
Thread.sleep(5*1000);
} catch (InterruptedException e) {
Log.d(TAG, "sleep failure");
}
}
// When the loop is finished, updates the notification
mBuilder.setContentText("Download complete")
// Removes the progress bar
.setProgress(0,0,false);
mNotifyManager.notify(ID, mBuilder.build());
}
}
// Starts the thread by calling the run() method in its Runnable
).start();
</pre>
<p>
The resulting notifications are shown in figure 6. On the left side is a snapshot of the
notification during the operation; on the right side is a snapshot of it after the operation
has finished.
</p>
<img
id="figure6"
src="{@docRoot}images/ui/notifications/progress_bar_summary.png"
height="84"
alt="" />
<p class="img-caption">
<strong>Figure 6.</strong> The progress bar during and after the operation.</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h3 id="ActivityIndicator">Displaying a continuing activity indicator</h3>
<p>
To display an indeterminate activity indicator, add it to your notification with
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)}
(the first two arguments are ignored), and issue the notification. The result is an indicator
that has the same style as a progress bar, except that its animation is ongoing.
</p>
<p>
Issue the notification at the beginning of the operation. The animation will run until you
modify your notification. When the operation is done, call
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()
setProgress(0, 0, false)} and then update the notification to remove the activity indicator.
Always do this; otherwise, the animation will run even when the operation is complete. Also
remember to change the notification text to indicate that the operation is complete.
</p>
<p>
To see how activity indicators work, refer to the preceding snippet. Locate the following lines:
</p>
<pre>
// Sets the progress indicator to a max value, the current completion
// percentage, and "determinate" state
mBuilder.setProgress(100, incr, false);
// Issues the notification
mNotifyManager.notify(0, mBuilder.build());
</pre>
<p>
Replace the lines you've found with the following lines:
</p>
<pre>
// Sets an activity indicator for an operation of indeterminate length
mBuilder.setProgress(0, 0, false);
// Issues the notification
mNotifyManager.notify(0, mBuilder.build());
</pre>
<p>
The resulting indicator is shown in figure 7:
</p>
<img
id="figure7"
src="{@docRoot}images/ui/notifications/activity_indicator.png"
height="99"
alt="" />
<p class="img-caption"><strong>Figure 7.</strong> An ongoing activity indicator.</p>
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<!-- ------------------------------------------------------------------------------------------ -->
<h2 id="CustomNotification">Custom Notification Layouts</h2>
<p>
The notifications framework allows you to define a custom notification layout, which
defines the notification's appearance in a {@link android.widget.RemoteViews} object.
Custom layout notifications are similar to normal notifications, but they're based on a
{@link android.widget.RemoteViews} defined in a XML layout file.
</p>
<p>
To define a custom notification layout, start by instantiating a
{@link android.widget.RemoteViews} object that inflates an XML layout file. Then,
instead of calling methods such as
{@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()},
call {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. To set
content details in the custom notification, use the methods in
{@link android.widget.RemoteViews} to set the values of the view's children:
</p>
<ol>
<li>
Create an XML layout for the notification in a separate file. You can use any file name
you wish, but you must use the extension <code>.xml</code>
</li>
<li>
In your app, use {@link android.widget.RemoteViews} methods to define your notification's
icons and text. Put this {@link android.widget.RemoteViews} object into your
{@link android.support.v4.app.NotificationCompat.Builder} by calling
{@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. Avoid
setting a background {@link android.graphics.drawable.Drawable} on your
{@link android.widget.RemoteViews} object, because your text color may become unreadable.
</li>
</ol>
<p>
The {@link android.widget.RemoteViews} class also includes methods that you can use to easily
add a {@link android.widget.Chronometer} or {@link android.widget.ProgressBar}
to your notification's layout. For more information about creating custom layouts for your
notification, refer to the {@link android.widget.RemoteViews} reference documentation.
</p>
<p class="caution">
<strong>Caution:</strong> When you use a custom notification layout, take special care to
ensure that your custom layout works with different device orientations and resolutions. While
this advice applies to all View layouts, it's especially important for notifications because
the space in the notification drawer is very restricted. Don't make your custom layout too
complex, and be sure to test it in various configurations.
</p>
<!-- ------------------------------------------------------------------------------------------ -->
<h4>Using style resources for custom notification text</h4>
<p>
Always use style resources for the text of a custom notification. The background color of the
notification can vary across different devices and platform versions, and using style resources
helps you account for this. Starting in API level 9, the system defined a style for the
standard notification layout text. If you use the same style in applications that target API
level 9 or higher, you'll ensure that your text is visible against the display background.
</p>
|