• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import com.android.internal.R;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.res.Resources;
24 import android.graphics.Bitmap;
25 import android.media.AudioManager;
26 import android.net.Uri;
27 import android.os.BadParcelableException;
28 import android.os.Bundle;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.os.SystemClock;
32 import android.os.UserHandle;
33 import android.text.TextUtils;
34 import android.util.Log;
35 import android.util.TypedValue;
36 import android.view.View;
37 import android.widget.ProgressBar;
38 import android.widget.RemoteViews;
39 
40 import java.text.NumberFormat;
41 import java.util.ArrayList;
42 
43 /**
44  * A class that represents how a persistent notification is to be presented to
45  * the user using the {@link android.app.NotificationManager}.
46  *
47  * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
48  * easier to construct Notifications.</p>
49  *
50  * <div class="special reference">
51  * <h3>Developer Guides</h3>
52  * <p>For a guide to creating notifications, read the
53  * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
54  * developer guide.</p>
55  * </div>
56  */
57 public class Notification implements Parcelable
58 {
59     private static final String TAG = "Notification";
60 
61     /**
62      * Use all default values (where applicable).
63      */
64     public static final int DEFAULT_ALL = ~0;
65 
66     /**
67      * Use the default notification sound. This will ignore any given
68      * {@link #sound}.
69      *
70 
71      * @see #defaults
72      */
73 
74     public static final int DEFAULT_SOUND = 1;
75 
76     /**
77      * Use the default notification vibrate. This will ignore any given
78      * {@link #vibrate}. Using phone vibration requires the
79      * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
80      *
81      * @see #defaults
82      */
83 
84     public static final int DEFAULT_VIBRATE = 2;
85 
86     /**
87      * Use the default notification lights. This will ignore the
88      * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
89      * {@link #ledOnMS}.
90      *
91      * @see #defaults
92      */
93 
94     public static final int DEFAULT_LIGHTS = 4;
95 
96     /**
97      * A timestamp related to this notification, in milliseconds since the epoch.
98      *
99      * Default value: {@link System#currentTimeMillis() Now}.
100      *
101      * Choose a timestamp that will be most relevant to the user. For most finite events, this
102      * corresponds to the time the event happened (or will happen, in the case of events that have
103      * yet to occur but about which the user is being informed). Indefinite events should be
104      * timestamped according to when the activity began.
105      *
106      * Some examples:
107      *
108      * <ul>
109      *   <li>Notification of a new chat message should be stamped when the message was received.</li>
110      *   <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li>
111      *   <li>Notification of a completed file download should be stamped when the download finished.</li>
112      *   <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li>
113      *   <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time.
114      *   <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.
115      * </ul>
116      *
117      */
118     public long when;
119 
120     /**
121      * The resource id of a drawable to use as the icon in the status bar.
122      * This is required; notifications with an invalid icon resource will not be shown.
123      */
124     public int icon;
125 
126     /**
127      * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
128      * leave it at its default value of 0.
129      *
130      * @see android.widget.ImageView#setImageLevel
131      * @see android.graphics.drawable#setLevel
132      */
133     public int iconLevel;
134 
135     /**
136      * The number of events that this notification represents. For example, in a new mail
137      * notification, this could be the number of unread messages.
138      *
139      * The system may or may not use this field to modify the appearance of the notification. For
140      * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was
141      * superimposed over the icon in the status bar. Starting with
142      * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
143      * {@link Notification.Builder} has displayed the number in the expanded notification view.
144      *
145      * If the number is 0 or negative, it is never shown.
146      */
147     public int number;
148 
149     /**
150      * The intent to execute when the expanded status entry is clicked.  If
151      * this is an activity, it must include the
152      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
153      * that you take care of task management as described in the
154      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
155      * Stack</a> document.  In particular, make sure to read the notification section
156      * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
157      * Notifications</a> for the correct ways to launch an application from a
158      * notification.
159      */
160     public PendingIntent contentIntent;
161 
162     /**
163      * The intent to execute when the notification is explicitly dismissed by the user, either with
164      * the "Clear All" button or by swiping it away individually.
165      *
166      * This probably shouldn't be launching an activity since several of those will be sent
167      * at the same time.
168      */
169     public PendingIntent deleteIntent;
170 
171     /**
172      * An intent to launch instead of posting the notification to the status bar.
173      *
174      * @see Notification.Builder#setFullScreenIntent
175      */
176     public PendingIntent fullScreenIntent;
177 
178     /**
179      * Text to scroll across the screen when this item is added to
180      * the status bar on large and smaller devices.
181      *
182      * @see #tickerView
183      */
184     public CharSequence tickerText;
185 
186     /**
187      * The view to show as the ticker in the status bar when the notification
188      * is posted.
189      */
190     public RemoteViews tickerView;
191 
192     /**
193      * The view that will represent this notification in the expanded status bar.
194      */
195     public RemoteViews contentView;
196 
197     /**
198      * A large-format version of {@link #contentView}, giving the Notification an
199      * opportunity to show more detail. The system UI may choose to show this
200      * instead of the normal content view at its discretion.
201      */
202     public RemoteViews bigContentView;
203 
204     /**
205      * The bitmap that may escape the bounds of the panel and bar.
206      */
207     public Bitmap largeIcon;
208 
209     /**
210      * The sound to play.
211      *
212      * <p>
213      * To play the default notification sound, see {@link #defaults}.
214      * </p>
215      */
216     public Uri sound;
217 
218     /**
219      * Use this constant as the value for audioStreamType to request that
220      * the default stream type for notifications be used.  Currently the
221      * default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
222      */
223     public static final int STREAM_DEFAULT = -1;
224 
225     /**
226      * The audio stream type to use when playing the sound.
227      * Should be one of the STREAM_ constants from
228      * {@link android.media.AudioManager}.
229      */
230     public int audioStreamType = STREAM_DEFAULT;
231 
232     /**
233      * The pattern with which to vibrate.
234      *
235      * <p>
236      * To vibrate the default pattern, see {@link #defaults}.
237      * </p>
238      *
239      * @see android.os.Vibrator#vibrate(long[],int)
240      */
241     public long[] vibrate;
242 
243     /**
244      * The color of the led.  The hardware will do its best approximation.
245      *
246      * @see #FLAG_SHOW_LIGHTS
247      * @see #flags
248      */
249     public int ledARGB;
250 
251     /**
252      * The number of milliseconds for the LED to be on while it's flashing.
253      * The hardware will do its best approximation.
254      *
255      * @see #FLAG_SHOW_LIGHTS
256      * @see #flags
257      */
258     public int ledOnMS;
259 
260     /**
261      * The number of milliseconds for the LED to be off while it's flashing.
262      * The hardware will do its best approximation.
263      *
264      * @see #FLAG_SHOW_LIGHTS
265      * @see #flags
266      */
267     public int ledOffMS;
268 
269     /**
270      * Specifies which values should be taken from the defaults.
271      * <p>
272      * To set, OR the desired from {@link #DEFAULT_SOUND},
273      * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
274      * values, use {@link #DEFAULT_ALL}.
275      * </p>
276      */
277     public int defaults;
278 
279     /**
280      * Bit to be bitwise-ored into the {@link #flags} field that should be
281      * set if you want the LED on for this notification.
282      * <ul>
283      * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
284      *      or 0 for both ledOnMS and ledOffMS.</li>
285      * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
286      * <li>To flash the LED, pass the number of milliseconds that it should
287      *      be on and off to ledOnMS and ledOffMS.</li>
288      * </ul>
289      * <p>
290      * Since hardware varies, you are not guaranteed that any of the values
291      * you pass are honored exactly.  Use the system defaults (TODO) if possible
292      * because they will be set to values that work on any given hardware.
293      * <p>
294      * The alpha channel must be set for forward compatibility.
295      *
296      */
297     public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
298 
299     /**
300      * Bit to be bitwise-ored into the {@link #flags} field that should be
301      * set if this notification is in reference to something that is ongoing,
302      * like a phone call.  It should not be set if this notification is in
303      * reference to something that happened at a particular point in time,
304      * like a missed phone call.
305      */
306     public static final int FLAG_ONGOING_EVENT      = 0x00000002;
307 
308     /**
309      * Bit to be bitwise-ored into the {@link #flags} field that if set,
310      * the audio will be repeated until the notification is
311      * cancelled or the notification window is opened.
312      */
313     public static final int FLAG_INSISTENT          = 0x00000004;
314 
315     /**
316      * Bit to be bitwise-ored into the {@link #flags} field that should be
317      * set if you want the sound and/or vibration play each time the
318      * notification is sent, even if it has not been canceled before that.
319      */
320     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
321 
322     /**
323      * Bit to be bitwise-ored into the {@link #flags} field that should be
324      * set if the notification should be canceled when it is clicked by the
325      * user.
326 
327      */
328     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
329 
330     /**
331      * Bit to be bitwise-ored into the {@link #flags} field that should be
332      * set if the notification should not be canceled when the user clicks
333      * the Clear all button.
334      */
335     public static final int FLAG_NO_CLEAR           = 0x00000020;
336 
337     /**
338      * Bit to be bitwise-ored into the {@link #flags} field that should be
339      * set if this notification represents a currently running service.  This
340      * will normally be set for you by {@link Service#startForeground}.
341      */
342     public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
343 
344     /**
345      * Obsolete flag indicating high-priority notifications; use the priority field instead.
346      *
347      * @deprecated Use {@link #priority} with a positive value.
348      */
349     public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
350 
351     public int flags;
352 
353     /**
354      * Default notification {@link #priority}. If your application does not prioritize its own
355      * notifications, use this value for all notifications.
356      */
357     public static final int PRIORITY_DEFAULT = 0;
358 
359     /**
360      * Lower {@link #priority}, for items that are less important. The UI may choose to show these
361      * items smaller, or at a different position in the list, compared with your app's
362      * {@link #PRIORITY_DEFAULT} items.
363      */
364     public static final int PRIORITY_LOW = -1;
365 
366     /**
367      * Lowest {@link #priority}; these items might not be shown to the user except under special
368      * circumstances, such as detailed notification logs.
369      */
370     public static final int PRIORITY_MIN = -2;
371 
372     /**
373      * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to
374      * show these items larger, or at a different position in notification lists, compared with
375      * your app's {@link #PRIORITY_DEFAULT} items.
376      */
377     public static final int PRIORITY_HIGH = 1;
378 
379     /**
380      * Highest {@link #priority}, for your application's most important items that require the
381      * user's prompt attention or input.
382      */
383     public static final int PRIORITY_MAX = 2;
384 
385     /**
386      * Relative priority for this notification.
387      *
388      * Priority is an indication of how much of the user's valuable attention should be consumed by
389      * this notification. Low-priority notifications may be hidden from the user in certain
390      * situations, while the user might be interrupted for a higher-priority notification. The
391      * system will make a determination about how to interpret this priority when presenting
392      * the notification.
393      */
394     public int priority;
395 
396     /**
397      * @hide
398      * Notification type: incoming call (voice or video) or similar synchronous communication request.
399      */
400     public static final String KIND_CALL = "android.call";
401 
402     /**
403      * @hide
404      * Notification type: incoming direct message (SMS, instant message, etc.).
405      */
406     public static final String KIND_MESSAGE = "android.message";
407 
408     /**
409      * @hide
410      * Notification type: asynchronous bulk message (email).
411      */
412     public static final String KIND_EMAIL = "android.email";
413 
414     /**
415      * @hide
416      * Notification type: calendar event.
417      */
418     public static final String KIND_EVENT = "android.event";
419 
420     /**
421      * @hide
422      * Notification type: promotion or advertisement.
423      */
424     public static final String KIND_PROMO = "android.promo";
425 
426     /**
427      * @hide
428      * If this notification matches of one or more special types (see the <code>KIND_*</code>
429      * constants), add them here, best match first.
430      */
431     public String[] kind;
432 
433     /**
434      * Additional semantic data to be carried around with this Notification.
435      * <p>
436      * The extras keys defined here are intended to capture the original inputs to {@link Builder}
437      * APIs, and are intended to be used by
438      * {@link android.service.notification.NotificationListenerService} implementations to extract
439      * detailed information from notification objects.
440      */
441     public Bundle extras = new Bundle();
442 
443     /**
444      * {@link #extras} key: this is the title of the notification,
445      * as supplied to {@link Builder#setContentTitle(CharSequence)}.
446      */
447     public static final String EXTRA_TITLE = "android.title";
448 
449     /**
450      * {@link #extras} key: this is the title of the notification when shown in expanded form,
451      * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
452      */
453     public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
454 
455     /**
456      * {@link #extras} key: this is the main text payload, as supplied to
457      * {@link Builder#setContentText(CharSequence)}.
458      */
459     public static final String EXTRA_TEXT = "android.text";
460 
461     /**
462      * {@link #extras} key: this is a third line of text, as supplied to
463      * {@link Builder#setSubText(CharSequence)}.
464      */
465     public static final String EXTRA_SUB_TEXT = "android.subText";
466 
467     /**
468      * {@link #extras} key: this is a small piece of additional text as supplied to
469      * {@link Builder#setContentInfo(CharSequence)}.
470      */
471     public static final String EXTRA_INFO_TEXT = "android.infoText";
472 
473     /**
474      * {@link #extras} key: this is a line of summary information intended to be shown
475      * alongside expanded notifications, as supplied to (e.g.)
476      * {@link BigTextStyle#setSummaryText(CharSequence)}.
477      */
478     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
479 
480     /**
481      * {@link #extras} key: this is the resource ID of the notification's main small icon, as
482      * supplied to {@link Builder#setSmallIcon(int)}.
483      */
484     public static final String EXTRA_SMALL_ICON = "android.icon";
485 
486     /**
487      * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the
488      * notification payload, as
489      * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
490      */
491     public static final String EXTRA_LARGE_ICON = "android.largeIcon";
492 
493     /**
494      * {@link #extras} key: this is a bitmap to be used instead of the one from
495      * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
496      * shown in its expanded form, as supplied to
497      * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
498      */
499     public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
500 
501     /**
502      * {@link #extras} key: this is the progress value supplied to
503      * {@link Builder#setProgress(int, int, boolean)}.
504      */
505     public static final String EXTRA_PROGRESS = "android.progress";
506 
507     /**
508      * {@link #extras} key: this is the maximum value supplied to
509      * {@link Builder#setProgress(int, int, boolean)}.
510      */
511     public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
512 
513     /**
514      * {@link #extras} key: whether the progress bar is indeterminate, supplied to
515      * {@link Builder#setProgress(int, int, boolean)}.
516      */
517     public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
518 
519     /**
520      * {@link #extras} key: whether {@link #when} should be shown as a count-up timer (specifically
521      * a {@link android.widget.Chronometer}) instead of a timestamp, as supplied to
522      * {@link Builder#setUsesChronometer(boolean)}.
523      */
524     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
525 
526     /**
527      * {@link #extras} key: whether {@link #when} should be shown,
528      * as supplied to {@link Builder#setShowWhen(boolean)}.
529      */
530     public static final String EXTRA_SHOW_WHEN = "android.showWhen";
531 
532     /**
533      * {@link #extras} key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
534      * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
535      */
536     public static final String EXTRA_PICTURE = "android.picture";
537 
538     /**
539      * {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
540      * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
541      */
542     public static final String EXTRA_TEXT_LINES = "android.textLines";
543 
544     /**
545      * {@link #extras} key: An array of people that this notification relates to, specified
546      * by contacts provider contact URI.
547      */
548     public static final String EXTRA_PEOPLE = "android.people";
549 
550     /**
551      * @hide
552      * Extra added by NotificationManagerService to indicate whether a NotificationScorer
553      * modified the Notifications's score.
554      */
555     public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
556 
557     /**
558      * Not used.
559      * @hide
560      */
561     public static final String EXTRA_AS_HEADS_UP = "headsup";
562 
563     /**
564      * Value for {@link #EXTRA_AS_HEADS_UP}.
565      * @hide
566      */
567     public static final int HEADS_UP_NEVER = 0;
568 
569     /**
570      * Default value for {@link #EXTRA_AS_HEADS_UP}.
571      * @hide
572      */
573     public static final int HEADS_UP_ALLOWED = 1;
574 
575     /**
576      * Value for {@link #EXTRA_AS_HEADS_UP}.
577      * @hide
578      */
579     public static final int HEADS_UP_REQUESTED = 2;
580 
581     /**
582      * Structure to encapsulate a named action that can be shown as part of this notification.
583      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
584      * selected by the user.
585      * <p>
586      * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
587      * attach actions.
588      */
589     public static class Action implements Parcelable {
590         /**
591          * Small icon representing the action.
592          */
593         public int icon;
594         /**
595          * Title of the action.
596          */
597         public CharSequence title;
598         /**
599          * Intent to send when the user invokes this action. May be null, in which case the action
600          * may be rendered in a disabled presentation by the system UI.
601          */
602         public PendingIntent actionIntent;
603 
Action()604         private Action() { }
Action(Parcel in)605         private Action(Parcel in) {
606             icon = in.readInt();
607             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
608             if (in.readInt() == 1) {
609                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
610             }
611         }
612         /**
613          * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
614          */
Action(int icon, CharSequence title, PendingIntent intent)615         public Action(int icon, CharSequence title, PendingIntent intent) {
616             this.icon = icon;
617             this.title = title;
618             this.actionIntent = intent;
619         }
620 
621         @Override
clone()622         public Action clone() {
623             return new Action(
624                 this.icon,
625                 this.title,
626                 this.actionIntent // safe to alias
627             );
628         }
629         @Override
describeContents()630         public int describeContents() {
631             return 0;
632         }
633         @Override
writeToParcel(Parcel out, int flags)634         public void writeToParcel(Parcel out, int flags) {
635             out.writeInt(icon);
636             TextUtils.writeToParcel(title, out, flags);
637             if (actionIntent != null) {
638                 out.writeInt(1);
639                 actionIntent.writeToParcel(out, flags);
640             } else {
641                 out.writeInt(0);
642             }
643         }
644         public static final Parcelable.Creator<Action> CREATOR
645         = new Parcelable.Creator<Action>() {
646             public Action createFromParcel(Parcel in) {
647                 return new Action(in);
648             }
649             public Action[] newArray(int size) {
650                 return new Action[size];
651             }
652         };
653     }
654 
655     /**
656      * Array of all {@link Action} structures attached to this notification by
657      * {@link Builder#addAction(int, CharSequence, PendingIntent)}. Mostly useful for instances of
658      * {@link android.service.notification.NotificationListenerService} that provide an alternative
659      * interface for invoking actions.
660      */
661     public Action[] actions;
662 
663     /**
664      * Constructs a Notification object with default values.
665      * You might want to consider using {@link Builder} instead.
666      */
Notification()667     public Notification()
668     {
669         this.when = System.currentTimeMillis();
670         this.priority = PRIORITY_DEFAULT;
671     }
672 
673     /**
674      * @hide
675      */
Notification(Context context, int icon, CharSequence tickerText, long when, CharSequence contentTitle, CharSequence contentText, Intent contentIntent)676     public Notification(Context context, int icon, CharSequence tickerText, long when,
677             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
678     {
679         this.when = when;
680         this.icon = icon;
681         this.tickerText = tickerText;
682         setLatestEventInfo(context, contentTitle, contentText,
683                 PendingIntent.getActivity(context, 0, contentIntent, 0));
684     }
685 
686     /**
687      * Constructs a Notification object with the information needed to
688      * have a status bar icon without the standard expanded view.
689      *
690      * @param icon          The resource id of the icon to put in the status bar.
691      * @param tickerText    The text that flows by in the status bar when the notification first
692      *                      activates.
693      * @param when          The time to show in the time field.  In the System.currentTimeMillis
694      *                      timebase.
695      *
696      * @deprecated Use {@link Builder} instead.
697      */
698     @Deprecated
Notification(int icon, CharSequence tickerText, long when)699     public Notification(int icon, CharSequence tickerText, long when)
700     {
701         this.icon = icon;
702         this.tickerText = tickerText;
703         this.when = when;
704     }
705 
706     /**
707      * Unflatten the notification from a parcel.
708      */
Notification(Parcel parcel)709     public Notification(Parcel parcel)
710     {
711         int version = parcel.readInt();
712 
713         when = parcel.readLong();
714         icon = parcel.readInt();
715         number = parcel.readInt();
716         if (parcel.readInt() != 0) {
717             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
718         }
719         if (parcel.readInt() != 0) {
720             deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
721         }
722         if (parcel.readInt() != 0) {
723             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
724         }
725         if (parcel.readInt() != 0) {
726             tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
727         }
728         if (parcel.readInt() != 0) {
729             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
730         }
731         if (parcel.readInt() != 0) {
732             largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
733         }
734         defaults = parcel.readInt();
735         flags = parcel.readInt();
736         if (parcel.readInt() != 0) {
737             sound = Uri.CREATOR.createFromParcel(parcel);
738         }
739 
740         audioStreamType = parcel.readInt();
741         vibrate = parcel.createLongArray();
742         ledARGB = parcel.readInt();
743         ledOnMS = parcel.readInt();
744         ledOffMS = parcel.readInt();
745         iconLevel = parcel.readInt();
746 
747         if (parcel.readInt() != 0) {
748             fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
749         }
750 
751         priority = parcel.readInt();
752 
753         kind = parcel.createStringArray(); // may set kind to null
754 
755         extras = parcel.readBundle(); // may be null
756 
757         actions = parcel.createTypedArray(Action.CREATOR); // may be null
758 
759         if (parcel.readInt() != 0) {
760             bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
761         }
762     }
763 
764     @Override
clone()765     public Notification clone() {
766         Notification that = new Notification();
767         cloneInto(that, true);
768         return that;
769     }
770 
771     /**
772      * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
773      * of this into that.
774      * @hide
775      */
cloneInto(Notification that, boolean heavy)776     public void cloneInto(Notification that, boolean heavy) {
777         that.when = this.when;
778         that.icon = this.icon;
779         that.number = this.number;
780 
781         // PendingIntents are global, so there's no reason (or way) to clone them.
782         that.contentIntent = this.contentIntent;
783         that.deleteIntent = this.deleteIntent;
784         that.fullScreenIntent = this.fullScreenIntent;
785 
786         if (this.tickerText != null) {
787             that.tickerText = this.tickerText.toString();
788         }
789         if (heavy && this.tickerView != null) {
790             that.tickerView = this.tickerView.clone();
791         }
792         if (heavy && this.contentView != null) {
793             that.contentView = this.contentView.clone();
794         }
795         if (heavy && this.largeIcon != null) {
796             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
797         }
798         that.iconLevel = this.iconLevel;
799         that.sound = this.sound; // android.net.Uri is immutable
800         that.audioStreamType = this.audioStreamType;
801 
802         final long[] vibrate = this.vibrate;
803         if (vibrate != null) {
804             final int N = vibrate.length;
805             final long[] vib = that.vibrate = new long[N];
806             System.arraycopy(vibrate, 0, vib, 0, N);
807         }
808 
809         that.ledARGB = this.ledARGB;
810         that.ledOnMS = this.ledOnMS;
811         that.ledOffMS = this.ledOffMS;
812         that.defaults = this.defaults;
813 
814         that.flags = this.flags;
815 
816         that.priority = this.priority;
817 
818         final String[] thiskind = this.kind;
819         if (thiskind != null) {
820             final int N = thiskind.length;
821             final String[] thatkind = that.kind = new String[N];
822             System.arraycopy(thiskind, 0, thatkind, 0, N);
823         }
824 
825         if (this.extras != null) {
826             try {
827                 that.extras = new Bundle(this.extras);
828                 // will unparcel
829                 that.extras.size();
830             } catch (BadParcelableException e) {
831                 Log.e(TAG, "could not unparcel extras from notification: " + this, e);
832                 that.extras = null;
833             }
834         }
835 
836         if (this.actions != null) {
837             that.actions = new Action[this.actions.length];
838             for(int i=0; i<this.actions.length; i++) {
839                 that.actions[i] = this.actions[i].clone();
840             }
841         }
842 
843         if (heavy && this.bigContentView != null) {
844             that.bigContentView = this.bigContentView.clone();
845         }
846 
847         if (!heavy) {
848             that.lightenPayload(); // will clean out extras
849         }
850     }
851 
852     /**
853      * Removes heavyweight parts of the Notification object for archival or for sending to
854      * listeners when the full contents are not necessary.
855      * @hide
856      */
lightenPayload()857     public final void lightenPayload() {
858         tickerView = null;
859         contentView = null;
860         bigContentView = null;
861         largeIcon = null;
862         if (extras != null) {
863             extras.remove(Notification.EXTRA_LARGE_ICON);
864             extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
865             extras.remove(Notification.EXTRA_PICTURE);
866         }
867     }
868 
869     /**
870      * Make sure this CharSequence is safe to put into a bundle, which basically
871      * means it had better not be some custom Parcelable implementation.
872      * @hide
873      */
safeCharSequence(CharSequence cs)874     public static CharSequence safeCharSequence(CharSequence cs) {
875         if (cs instanceof Parcelable) {
876             Log.e(TAG, "warning: " + cs.getClass().getCanonicalName()
877                     + " instance is a custom Parcelable and not allowed in Notification");
878             return cs.toString();
879         }
880 
881         return cs;
882     }
883 
describeContents()884     public int describeContents() {
885         return 0;
886     }
887 
888     /**
889      * Flatten this notification from a parcel.
890      */
writeToParcel(Parcel parcel, int flags)891     public void writeToParcel(Parcel parcel, int flags)
892     {
893         parcel.writeInt(1);
894 
895         parcel.writeLong(when);
896         parcel.writeInt(icon);
897         parcel.writeInt(number);
898         if (contentIntent != null) {
899             parcel.writeInt(1);
900             contentIntent.writeToParcel(parcel, 0);
901         } else {
902             parcel.writeInt(0);
903         }
904         if (deleteIntent != null) {
905             parcel.writeInt(1);
906             deleteIntent.writeToParcel(parcel, 0);
907         } else {
908             parcel.writeInt(0);
909         }
910         if (tickerText != null) {
911             parcel.writeInt(1);
912             TextUtils.writeToParcel(tickerText, parcel, flags);
913         } else {
914             parcel.writeInt(0);
915         }
916         if (tickerView != null) {
917             parcel.writeInt(1);
918             tickerView.writeToParcel(parcel, 0);
919         } else {
920             parcel.writeInt(0);
921         }
922         if (contentView != null) {
923             parcel.writeInt(1);
924             contentView.writeToParcel(parcel, 0);
925         } else {
926             parcel.writeInt(0);
927         }
928         if (largeIcon != null) {
929             parcel.writeInt(1);
930             largeIcon.writeToParcel(parcel, 0);
931         } else {
932             parcel.writeInt(0);
933         }
934 
935         parcel.writeInt(defaults);
936         parcel.writeInt(this.flags);
937 
938         if (sound != null) {
939             parcel.writeInt(1);
940             sound.writeToParcel(parcel, 0);
941         } else {
942             parcel.writeInt(0);
943         }
944         parcel.writeInt(audioStreamType);
945         parcel.writeLongArray(vibrate);
946         parcel.writeInt(ledARGB);
947         parcel.writeInt(ledOnMS);
948         parcel.writeInt(ledOffMS);
949         parcel.writeInt(iconLevel);
950 
951         if (fullScreenIntent != null) {
952             parcel.writeInt(1);
953             fullScreenIntent.writeToParcel(parcel, 0);
954         } else {
955             parcel.writeInt(0);
956         }
957 
958         parcel.writeInt(priority);
959 
960         parcel.writeStringArray(kind); // ok for null
961 
962         parcel.writeBundle(extras); // null ok
963 
964         parcel.writeTypedArray(actions, 0); // null ok
965 
966         if (bigContentView != null) {
967             parcel.writeInt(1);
968             bigContentView.writeToParcel(parcel, 0);
969         } else {
970             parcel.writeInt(0);
971         }
972     }
973 
974     /**
975      * Parcelable.Creator that instantiates Notification objects
976      */
977     public static final Parcelable.Creator<Notification> CREATOR
978             = new Parcelable.Creator<Notification>()
979     {
980         public Notification createFromParcel(Parcel parcel)
981         {
982             return new Notification(parcel);
983         }
984 
985         public Notification[] newArray(int size)
986         {
987             return new Notification[size];
988         }
989     };
990 
991     /**
992      * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
993      * layout.
994      *
995      * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
996      * in the view.</p>
997      * @param context       The context for your application / activity.
998      * @param contentTitle The title that goes in the expanded entry.
999      * @param contentText  The text that goes in the expanded entry.
1000      * @param contentIntent The intent to launch when the user clicks the expanded notification.
1001      * If this is an activity, it must include the
1002      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
1003      * that you take care of task management as described in the
1004      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
1005      * Stack</a> document.
1006      *
1007      * @deprecated Use {@link Builder} instead.
1008      */
1009     @Deprecated
setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)1010     public void setLatestEventInfo(Context context,
1011             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
1012         Notification.Builder builder = new Notification.Builder(context);
1013 
1014         // First, ensure that key pieces of information that may have been set directly
1015         // are preserved
1016         builder.setWhen(this.when);
1017         builder.setSmallIcon(this.icon);
1018         builder.setPriority(this.priority);
1019         builder.setTicker(this.tickerText);
1020         builder.setNumber(this.number);
1021         builder.mFlags = this.flags;
1022         builder.setSound(this.sound, this.audioStreamType);
1023         builder.setDefaults(this.defaults);
1024         builder.setVibrate(this.vibrate);
1025 
1026         // now apply the latestEventInfo fields
1027         if (contentTitle != null) {
1028             builder.setContentTitle(contentTitle);
1029         }
1030         if (contentText != null) {
1031             builder.setContentText(contentText);
1032         }
1033         builder.setContentIntent(contentIntent);
1034         builder.buildInto(this);
1035     }
1036 
1037     @Override
toString()1038     public String toString() {
1039         StringBuilder sb = new StringBuilder();
1040         sb.append("Notification(pri=");
1041         sb.append(priority);
1042         sb.append(" contentView=");
1043         if (contentView != null) {
1044             sb.append(contentView.getPackage());
1045             sb.append("/0x");
1046             sb.append(Integer.toHexString(contentView.getLayoutId()));
1047         } else {
1048             sb.append("null");
1049         }
1050         // TODO(dsandler): defaults take precedence over local values, so reorder the branches below
1051         sb.append(" vibrate=");
1052         if ((this.defaults & DEFAULT_VIBRATE) != 0) {
1053             sb.append("default");
1054         } else if (this.vibrate != null) {
1055             int N = this.vibrate.length-1;
1056             sb.append("[");
1057             for (int i=0; i<N; i++) {
1058                 sb.append(this.vibrate[i]);
1059                 sb.append(',');
1060             }
1061             if (N != -1) {
1062                 sb.append(this.vibrate[N]);
1063             }
1064             sb.append("]");
1065         } else {
1066             sb.append("null");
1067         }
1068         sb.append(" sound=");
1069         if ((this.defaults & DEFAULT_SOUND) != 0) {
1070             sb.append("default");
1071         } else if (this.sound != null) {
1072             sb.append(this.sound.toString());
1073         } else {
1074             sb.append("null");
1075         }
1076         sb.append(" defaults=0x");
1077         sb.append(Integer.toHexString(this.defaults));
1078         sb.append(" flags=0x");
1079         sb.append(Integer.toHexString(this.flags));
1080         sb.append(" kind=[");
1081         if (this.kind == null) {
1082             sb.append("null");
1083         } else {
1084             for (int i=0; i<this.kind.length; i++) {
1085                 if (i>0) sb.append(",");
1086                 sb.append(this.kind[i]);
1087             }
1088         }
1089         sb.append("]");
1090         if (actions != null) {
1091             sb.append(" ");
1092             sb.append(actions.length);
1093             sb.append(" action");
1094             if (actions.length > 1) sb.append("s");
1095         }
1096         sb.append(")");
1097         return sb.toString();
1098     }
1099 
1100     /** {@hide} */
setUser(UserHandle user)1101     public void setUser(UserHandle user) {
1102         if (user.getIdentifier() == UserHandle.USER_ALL) {
1103             user = UserHandle.OWNER;
1104         }
1105         if (tickerView != null) {
1106             tickerView.setUser(user);
1107         }
1108         if (contentView != null) {
1109             contentView.setUser(user);
1110         }
1111         if (bigContentView != null) {
1112             bigContentView.setUser(user);
1113         }
1114     }
1115 
1116     /**
1117      * Builder class for {@link Notification} objects.
1118      *
1119      * Provides a convenient way to set the various fields of a {@link Notification} and generate
1120      * content views using the platform's notification layout template. If your app supports
1121      * versions of Android as old as API level 4, you can instead use
1122      * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
1123      * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
1124      * library</a>.
1125      *
1126      * <p>Example:
1127      *
1128      * <pre class="prettyprint">
1129      * Notification noti = new Notification.Builder(mContext)
1130      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
1131      *         .setContentText(subject)
1132      *         .setSmallIcon(R.drawable.new_mail)
1133      *         .setLargeIcon(aBitmap)
1134      *         .build();
1135      * </pre>
1136      */
1137     public static class Builder {
1138         private static final int MAX_ACTION_BUTTONS = 3;
1139 
1140         private Context mContext;
1141 
1142         private long mWhen;
1143         private int mSmallIcon;
1144         private int mSmallIconLevel;
1145         private int mNumber;
1146         private CharSequence mContentTitle;
1147         private CharSequence mContentText;
1148         private CharSequence mContentInfo;
1149         private CharSequence mSubText;
1150         private PendingIntent mContentIntent;
1151         private RemoteViews mContentView;
1152         private PendingIntent mDeleteIntent;
1153         private PendingIntent mFullScreenIntent;
1154         private CharSequence mTickerText;
1155         private RemoteViews mTickerView;
1156         private Bitmap mLargeIcon;
1157         private Uri mSound;
1158         private int mAudioStreamType;
1159         private long[] mVibrate;
1160         private int mLedArgb;
1161         private int mLedOnMs;
1162         private int mLedOffMs;
1163         private int mDefaults;
1164         private int mFlags;
1165         private int mProgressMax;
1166         private int mProgress;
1167         private boolean mProgressIndeterminate;
1168         private ArrayList<String> mKindList = new ArrayList<String>(1);
1169         private Bundle mExtras;
1170         private int mPriority;
1171         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
1172         private boolean mUseChronometer;
1173         private Style mStyle;
1174         private boolean mShowWhen = true;
1175 
1176         /**
1177          * Constructs a new Builder with the defaults:
1178          *
1179 
1180          * <table>
1181          * <tr><th align=right>priority</th>
1182          *     <td>{@link #PRIORITY_DEFAULT}</td></tr>
1183          * <tr><th align=right>when</th>
1184          *     <td>now ({@link System#currentTimeMillis()})</td></tr>
1185          * <tr><th align=right>audio stream</th>
1186          *     <td>{@link #STREAM_DEFAULT}</td></tr>
1187          * </table>
1188          *
1189 
1190          * @param context
1191          *            A {@link Context} that will be used by the Builder to construct the
1192          *            RemoteViews. The Context will not be held past the lifetime of this Builder
1193          *            object.
1194          */
Builder(Context context)1195         public Builder(Context context) {
1196             mContext = context;
1197 
1198             // Set defaults to match the defaults of a Notification
1199             mWhen = System.currentTimeMillis();
1200             mAudioStreamType = STREAM_DEFAULT;
1201             mPriority = PRIORITY_DEFAULT;
1202         }
1203 
1204         /**
1205          * Add a timestamp pertaining to the notification (usually the time the event occurred).
1206          * It will be shown in the notification content view by default; use
1207          * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
1208          *
1209          * @see Notification#when
1210          */
setWhen(long when)1211         public Builder setWhen(long when) {
1212             mWhen = when;
1213             return this;
1214         }
1215 
1216         /**
1217          * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
1218          * in the content view.
1219          */
setShowWhen(boolean show)1220         public Builder setShowWhen(boolean show) {
1221             mShowWhen = show;
1222             return this;
1223         }
1224 
1225         /**
1226          * Show the {@link Notification#when} field as a stopwatch.
1227          *
1228          * Instead of presenting <code>when</code> as a timestamp, the notification will show an
1229          * automatically updating display of the minutes and seconds since <code>when</code>.
1230          *
1231          * Useful when showing an elapsed time (like an ongoing phone call).
1232          *
1233          * @see android.widget.Chronometer
1234          * @see Notification#when
1235          */
setUsesChronometer(boolean b)1236         public Builder setUsesChronometer(boolean b) {
1237             mUseChronometer = b;
1238             return this;
1239         }
1240 
1241         /**
1242          * Set the small icon resource, which will be used to represent the notification in the
1243          * status bar.
1244          *
1245 
1246          * The platform template for the expanded view will draw this icon in the left, unless a
1247          * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
1248          * icon will be moved to the right-hand side.
1249          *
1250 
1251          * @param icon
1252          *            A resource ID in the application's package of the drawable to use.
1253          * @see Notification#icon
1254          */
setSmallIcon(int icon)1255         public Builder setSmallIcon(int icon) {
1256             mSmallIcon = icon;
1257             return this;
1258         }
1259 
1260         /**
1261          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
1262          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
1263          * LevelListDrawable}.
1264          *
1265          * @param icon A resource ID in the application's package of the drawable to use.
1266          * @param level The level to use for the icon.
1267          *
1268          * @see Notification#icon
1269          * @see Notification#iconLevel
1270          */
setSmallIcon(int icon, int level)1271         public Builder setSmallIcon(int icon, int level) {
1272             mSmallIcon = icon;
1273             mSmallIconLevel = level;
1274             return this;
1275         }
1276 
1277         /**
1278          * Set the first line of text in the platform notification template.
1279          */
setContentTitle(CharSequence title)1280         public Builder setContentTitle(CharSequence title) {
1281             mContentTitle = safeCharSequence(title);
1282             return this;
1283         }
1284 
1285         /**
1286          * Set the second line of text in the platform notification template.
1287          */
setContentText(CharSequence text)1288         public Builder setContentText(CharSequence text) {
1289             mContentText = safeCharSequence(text);
1290             return this;
1291         }
1292 
1293         /**
1294          * Set the third line of text in the platform notification template.
1295          * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the
1296          * same location in the standard template.
1297          */
setSubText(CharSequence text)1298         public Builder setSubText(CharSequence text) {
1299             mSubText = safeCharSequence(text);
1300             return this;
1301         }
1302 
1303         /**
1304          * Set the large number at the right-hand side of the notification.  This is
1305          * equivalent to setContentInfo, although it might show the number in a different
1306          * font size for readability.
1307          */
setNumber(int number)1308         public Builder setNumber(int number) {
1309             mNumber = number;
1310             return this;
1311         }
1312 
1313         /**
1314          * A small piece of additional information pertaining to this notification.
1315          *
1316          * The platform template will draw this on the last line of the notification, at the far
1317          * right (to the right of a smallIcon if it has been placed there).
1318          */
setContentInfo(CharSequence info)1319         public Builder setContentInfo(CharSequence info) {
1320             mContentInfo = safeCharSequence(info);
1321             return this;
1322         }
1323 
1324         /**
1325          * Set the progress this notification represents.
1326          *
1327          * The platform template will represent this using a {@link ProgressBar}.
1328          */
setProgress(int max, int progress, boolean indeterminate)1329         public Builder setProgress(int max, int progress, boolean indeterminate) {
1330             mProgressMax = max;
1331             mProgress = progress;
1332             mProgressIndeterminate = indeterminate;
1333             return this;
1334         }
1335 
1336         /**
1337          * Supply a custom RemoteViews to use instead of the platform template.
1338          *
1339          * @see Notification#contentView
1340          */
setContent(RemoteViews views)1341         public Builder setContent(RemoteViews views) {
1342             mContentView = views;
1343             return this;
1344         }
1345 
1346         /**
1347          * Supply a {@link PendingIntent} to be sent when the notification is clicked.
1348          *
1349          * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
1350          * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
1351          * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
1352          * to assign PendingIntents to individual views in that custom layout (i.e., to create
1353          * clickable buttons inside the notification view).
1354          *
1355          * @see Notification#contentIntent Notification.contentIntent
1356          */
setContentIntent(PendingIntent intent)1357         public Builder setContentIntent(PendingIntent intent) {
1358             mContentIntent = intent;
1359             return this;
1360         }
1361 
1362         /**
1363          * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
1364          *
1365          * @see Notification#deleteIntent
1366          */
setDeleteIntent(PendingIntent intent)1367         public Builder setDeleteIntent(PendingIntent intent) {
1368             mDeleteIntent = intent;
1369             return this;
1370         }
1371 
1372         /**
1373          * An intent to launch instead of posting the notification to the status bar.
1374          * Only for use with extremely high-priority notifications demanding the user's
1375          * <strong>immediate</strong> attention, such as an incoming phone call or
1376          * alarm clock that the user has explicitly set to a particular time.
1377          * If this facility is used for something else, please give the user an option
1378          * to turn it off and use a normal notification, as this can be extremely
1379          * disruptive.
1380          *
1381          * @param intent The pending intent to launch.
1382          * @param highPriority Passing true will cause this notification to be sent
1383          *          even if other notifications are suppressed.
1384          *
1385          * @see Notification#fullScreenIntent
1386          */
setFullScreenIntent(PendingIntent intent, boolean highPriority)1387         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
1388             mFullScreenIntent = intent;
1389             setFlag(FLAG_HIGH_PRIORITY, highPriority);
1390             return this;
1391         }
1392 
1393         /**
1394          * Set the "ticker" text which is displayed in the status bar when the notification first
1395          * arrives.
1396          *
1397          * @see Notification#tickerText
1398          */
setTicker(CharSequence tickerText)1399         public Builder setTicker(CharSequence tickerText) {
1400             mTickerText = safeCharSequence(tickerText);
1401             return this;
1402         }
1403 
1404         /**
1405          * Set the text that is displayed in the status bar when the notification first
1406          * arrives, and also a RemoteViews object that may be displayed instead on some
1407          * devices.
1408          *
1409          * @see Notification#tickerText
1410          * @see Notification#tickerView
1411          */
setTicker(CharSequence tickerText, RemoteViews views)1412         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
1413             mTickerText = safeCharSequence(tickerText);
1414             mTickerView = views;
1415             return this;
1416         }
1417 
1418         /**
1419          * Add a large icon to the notification (and the ticker on some devices).
1420          *
1421          * In the platform template, this image will be shown on the left of the notification view
1422          * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side).
1423          *
1424          * @see Notification#largeIcon
1425          */
setLargeIcon(Bitmap icon)1426         public Builder setLargeIcon(Bitmap icon) {
1427             mLargeIcon = icon;
1428             return this;
1429         }
1430 
1431         /**
1432          * Set the sound to play.
1433          *
1434          * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications.
1435          *
1436          * @see Notification#sound
1437          */
setSound(Uri sound)1438         public Builder setSound(Uri sound) {
1439             mSound = sound;
1440             mAudioStreamType = STREAM_DEFAULT;
1441             return this;
1442         }
1443 
1444         /**
1445          * Set the sound to play, along with a specific stream on which to play it.
1446          *
1447          * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
1448          *
1449          * @see Notification#sound
1450          */
setSound(Uri sound, int streamType)1451         public Builder setSound(Uri sound, int streamType) {
1452             mSound = sound;
1453             mAudioStreamType = streamType;
1454             return this;
1455         }
1456 
1457         /**
1458          * Set the vibration pattern to use.
1459          *
1460 
1461          * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
1462          * <code>pattern</code> parameter.
1463          *
1464 
1465          * @see Notification#vibrate
1466          */
setVibrate(long[] pattern)1467         public Builder setVibrate(long[] pattern) {
1468             mVibrate = pattern;
1469             return this;
1470         }
1471 
1472         /**
1473          * Set the desired color for the indicator LED on the device, as well as the
1474          * blink duty cycle (specified in milliseconds).
1475          *
1476 
1477          * Not all devices will honor all (or even any) of these values.
1478          *
1479 
1480          * @see Notification#ledARGB
1481          * @see Notification#ledOnMS
1482          * @see Notification#ledOffMS
1483          */
setLights(int argb, int onMs, int offMs)1484         public Builder setLights(int argb, int onMs, int offMs) {
1485             mLedArgb = argb;
1486             mLedOnMs = onMs;
1487             mLedOffMs = offMs;
1488             return this;
1489         }
1490 
1491         /**
1492          * Set whether this is an "ongoing" notification.
1493          *
1494 
1495          * Ongoing notifications cannot be dismissed by the user, so your application or service
1496          * must take care of canceling them.
1497          *
1498 
1499          * They are typically used to indicate a background task that the user is actively engaged
1500          * with (e.g., playing music) or is pending in some way and therefore occupying the device
1501          * (e.g., a file download, sync operation, active network connection).
1502          *
1503 
1504          * @see Notification#FLAG_ONGOING_EVENT
1505          * @see Service#setForeground(boolean)
1506          */
setOngoing(boolean ongoing)1507         public Builder setOngoing(boolean ongoing) {
1508             setFlag(FLAG_ONGOING_EVENT, ongoing);
1509             return this;
1510         }
1511 
1512         /**
1513          * Set this flag if you would only like the sound, vibrate
1514          * and ticker to be played if the notification is not already showing.
1515          *
1516          * @see Notification#FLAG_ONLY_ALERT_ONCE
1517          */
setOnlyAlertOnce(boolean onlyAlertOnce)1518         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
1519             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
1520             return this;
1521         }
1522 
1523         /**
1524          * Make this notification automatically dismissed when the user touches it. The
1525          * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
1526          *
1527          * @see Notification#FLAG_AUTO_CANCEL
1528          */
setAutoCancel(boolean autoCancel)1529         public Builder setAutoCancel(boolean autoCancel) {
1530             setFlag(FLAG_AUTO_CANCEL, autoCancel);
1531             return this;
1532         }
1533 
1534         /**
1535          * Set which notification properties will be inherited from system defaults.
1536          * <p>
1537          * The value should be one or more of the following fields combined with
1538          * bitwise-or:
1539          * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
1540          * <p>
1541          * For all default values, use {@link #DEFAULT_ALL}.
1542          */
setDefaults(int defaults)1543         public Builder setDefaults(int defaults) {
1544             mDefaults = defaults;
1545             return this;
1546         }
1547 
1548         /**
1549          * Set the priority of this notification.
1550          *
1551          * @see Notification#priority
1552          */
setPriority(int pri)1553         public Builder setPriority(int pri) {
1554             mPriority = pri;
1555             return this;
1556         }
1557 
1558         /**
1559          * @hide
1560          *
1561          * Add a kind (category) to this notification. Optional.
1562          *
1563          * @see Notification#kind
1564          */
addKind(String k)1565         public Builder addKind(String k) {
1566             mKindList.add(k);
1567             return this;
1568         }
1569 
1570         /**
1571          * Add metadata to this notification.
1572          *
1573          * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
1574          * current contents are copied into the Notification each time {@link #build()} is
1575          * called.
1576          *
1577          * @see Notification#extras
1578          */
setExtras(Bundle bag)1579         public Builder setExtras(Bundle bag) {
1580             mExtras = bag;
1581             return this;
1582         }
1583 
1584         /**
1585          * Add an action to this notification. Actions are typically displayed by
1586          * the system as a button adjacent to the notification content.
1587          * <p>
1588          * Every action must have an icon (32dp square and matching the
1589          * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
1590          * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
1591          * <p>
1592          * A notification in its expanded form can display up to 3 actions, from left to right in
1593          * the order they were added. Actions will not be displayed when the notification is
1594          * collapsed, however, so be sure that any essential functions may be accessed by the user
1595          * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
1596          *
1597          * @param icon Resource ID of a drawable that represents the action.
1598          * @param title Text describing the action.
1599          * @param intent PendingIntent to be fired when the action is invoked.
1600          */
addAction(int icon, CharSequence title, PendingIntent intent)1601         public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
1602             mActions.add(new Action(icon, safeCharSequence(title), intent));
1603             return this;
1604         }
1605 
1606         /**
1607          * Add a rich notification style to be applied at build time.
1608          *
1609          * @param style Object responsible for modifying the notification style.
1610          */
setStyle(Style style)1611         public Builder setStyle(Style style) {
1612             if (mStyle != style) {
1613                 mStyle = style;
1614                 if (mStyle != null) {
1615                     mStyle.setBuilder(this);
1616                 }
1617             }
1618             return this;
1619         }
1620 
setFlag(int mask, boolean value)1621         private void setFlag(int mask, boolean value) {
1622             if (value) {
1623                 mFlags |= mask;
1624             } else {
1625                 mFlags &= ~mask;
1626             }
1627         }
1628 
applyStandardTemplate(int resId, boolean fitIn1U)1629         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
1630             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
1631             boolean showLine3 = false;
1632             boolean showLine2 = false;
1633             int smallIconImageViewId = R.id.icon;
1634             if (mLargeIcon != null) {
1635                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
1636                 smallIconImageViewId = R.id.right_icon;
1637             }
1638             if (mPriority < PRIORITY_LOW) {
1639                 contentView.setInt(R.id.icon,
1640                         "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
1641                 contentView.setInt(R.id.status_bar_latest_event_content,
1642                         "setBackgroundResource", R.drawable.notification_bg_low);
1643             }
1644             if (mSmallIcon != 0) {
1645                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
1646                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
1647             } else {
1648                 contentView.setViewVisibility(smallIconImageViewId, View.GONE);
1649             }
1650             if (mContentTitle != null) {
1651                 contentView.setTextViewText(R.id.title, mContentTitle);
1652             }
1653             if (mContentText != null) {
1654                 contentView.setTextViewText(R.id.text, mContentText);
1655                 showLine3 = true;
1656             }
1657             if (mContentInfo != null) {
1658                 contentView.setTextViewText(R.id.info, mContentInfo);
1659                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
1660                 showLine3 = true;
1661             } else if (mNumber > 0) {
1662                 final int tooBig = mContext.getResources().getInteger(
1663                         R.integer.status_bar_notification_info_maxnum);
1664                 if (mNumber > tooBig) {
1665                     contentView.setTextViewText(R.id.info, mContext.getResources().getString(
1666                                 R.string.status_bar_notification_info_overflow));
1667                 } else {
1668                     NumberFormat f = NumberFormat.getIntegerInstance();
1669                     contentView.setTextViewText(R.id.info, f.format(mNumber));
1670                 }
1671                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
1672                 showLine3 = true;
1673             } else {
1674                 contentView.setViewVisibility(R.id.info, View.GONE);
1675             }
1676 
1677             // Need to show three lines?
1678             if (mSubText != null) {
1679                 contentView.setTextViewText(R.id.text, mSubText);
1680                 if (mContentText != null) {
1681                     contentView.setTextViewText(R.id.text2, mContentText);
1682                     contentView.setViewVisibility(R.id.text2, View.VISIBLE);
1683                     showLine2 = true;
1684                 } else {
1685                     contentView.setViewVisibility(R.id.text2, View.GONE);
1686                 }
1687             } else {
1688                 contentView.setViewVisibility(R.id.text2, View.GONE);
1689                 if (mProgressMax != 0 || mProgressIndeterminate) {
1690                     contentView.setProgressBar(
1691                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
1692                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
1693                     showLine2 = true;
1694                 } else {
1695                     contentView.setViewVisibility(R.id.progress, View.GONE);
1696                 }
1697             }
1698             if (showLine2) {
1699                 if (fitIn1U) {
1700                     // need to shrink all the type to make sure everything fits
1701                     final Resources res = mContext.getResources();
1702                     final float subTextSize = res.getDimensionPixelSize(
1703                             R.dimen.notification_subtext_size);
1704                     contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
1705                 }
1706                 // vertical centering
1707                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
1708             }
1709 
1710             if (mWhen != 0 && mShowWhen) {
1711                 if (mUseChronometer) {
1712                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
1713                     contentView.setLong(R.id.chronometer, "setBase",
1714                             mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
1715                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
1716                 } else {
1717                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
1718                     contentView.setLong(R.id.time, "setTime", mWhen);
1719                 }
1720             } else {
1721                 contentView.setViewVisibility(R.id.time, View.GONE);
1722             }
1723 
1724             contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
1725             contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
1726             return contentView;
1727         }
1728 
applyStandardTemplateWithActions(int layoutId)1729         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
1730             RemoteViews big = applyStandardTemplate(layoutId, false);
1731 
1732             int N = mActions.size();
1733             if (N > 0) {
1734                 // Log.d("Notification", "has actions: " + mContentText);
1735                 big.setViewVisibility(R.id.actions, View.VISIBLE);
1736                 big.setViewVisibility(R.id.action_divider, View.VISIBLE);
1737                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
1738                 big.removeAllViews(R.id.actions);
1739                 for (int i=0; i<N; i++) {
1740                     final RemoteViews button = generateActionButton(mActions.get(i));
1741                     //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
1742                     big.addView(R.id.actions, button);
1743                 }
1744             }
1745             return big;
1746         }
1747 
makeContentView()1748         private RemoteViews makeContentView() {
1749             if (mContentView != null) {
1750                 return mContentView;
1751             } else {
1752                 return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor
1753             }
1754         }
1755 
makeTickerView()1756         private RemoteViews makeTickerView() {
1757             if (mTickerView != null) {
1758                 return mTickerView;
1759             } else {
1760                 if (mContentView == null) {
1761                     return applyStandardTemplate(mLargeIcon == null
1762                             ? R.layout.status_bar_latest_event_ticker
1763                             : R.layout.status_bar_latest_event_ticker_large_icon, true);
1764                 } else {
1765                     return null;
1766                 }
1767             }
1768         }
1769 
makeBigContentView()1770         private RemoteViews makeBigContentView() {
1771             if (mActions.size() == 0) return null;
1772 
1773             return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
1774         }
1775 
generateActionButton(Action action)1776         private RemoteViews generateActionButton(Action action) {
1777             final boolean tombstone = (action.actionIntent == null);
1778             RemoteViews button = new RemoteViews(mContext.getPackageName(),
1779                     tombstone ? R.layout.notification_action_tombstone
1780                               : R.layout.notification_action);
1781             button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
1782             button.setTextViewText(R.id.action0, action.title);
1783             if (!tombstone) {
1784                 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
1785             }
1786             button.setContentDescription(R.id.action0, action.title);
1787             return button;
1788         }
1789 
1790         /**
1791          * Apply the unstyled operations and return a new {@link Notification} object.
1792          * @hide
1793          */
buildUnstyled()1794         public Notification buildUnstyled() {
1795             Notification n = new Notification();
1796             n.when = mWhen;
1797             n.icon = mSmallIcon;
1798             n.iconLevel = mSmallIconLevel;
1799             n.number = mNumber;
1800             n.contentView = makeContentView();
1801             n.contentIntent = mContentIntent;
1802             n.deleteIntent = mDeleteIntent;
1803             n.fullScreenIntent = mFullScreenIntent;
1804             n.tickerText = mTickerText;
1805             n.tickerView = makeTickerView();
1806             n.largeIcon = mLargeIcon;
1807             n.sound = mSound;
1808             n.audioStreamType = mAudioStreamType;
1809             n.vibrate = mVibrate;
1810             n.ledARGB = mLedArgb;
1811             n.ledOnMS = mLedOnMs;
1812             n.ledOffMS = mLedOffMs;
1813             n.defaults = mDefaults;
1814             n.flags = mFlags;
1815             n.bigContentView = makeBigContentView();
1816             if (mLedOnMs != 0 || mLedOffMs != 0) {
1817                 n.flags |= FLAG_SHOW_LIGHTS;
1818             }
1819             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
1820                 n.flags |= FLAG_SHOW_LIGHTS;
1821             }
1822             if (mKindList.size() > 0) {
1823                 n.kind = new String[mKindList.size()];
1824                 mKindList.toArray(n.kind);
1825             } else {
1826                 n.kind = null;
1827             }
1828             n.priority = mPriority;
1829             if (mActions.size() > 0) {
1830                 n.actions = new Action[mActions.size()];
1831                 mActions.toArray(n.actions);
1832             }
1833 
1834             return n;
1835         }
1836 
1837         /**
1838          * Capture, in the provided bundle, semantic information used in the construction of
1839          * this Notification object.
1840          * @hide
1841          */
addExtras(Bundle extras)1842         public void addExtras(Bundle extras) {
1843             // Store original information used in the construction of this object
1844             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
1845             extras.putCharSequence(EXTRA_TEXT, mContentText);
1846             extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
1847             extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
1848             extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
1849             extras.putInt(EXTRA_PROGRESS, mProgress);
1850             extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
1851             extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
1852             extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
1853             extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
1854             if (mLargeIcon != null) {
1855                 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
1856             }
1857         }
1858 
1859         /**
1860          * @deprecated Use {@link #build()} instead.
1861          */
1862         @Deprecated
getNotification()1863         public Notification getNotification() {
1864             return build();
1865         }
1866 
1867         /**
1868          * Combine all of the options that have been set and return a new {@link Notification}
1869          * object.
1870          */
build()1871         public Notification build() {
1872             Notification n = buildUnstyled();
1873 
1874             if (mStyle != null) {
1875                 n = mStyle.buildStyled(n);
1876             }
1877 
1878             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
1879 
1880             addExtras(n.extras);
1881             if (mStyle != null) {
1882                 mStyle.addExtras(n.extras);
1883             }
1884 
1885             return n;
1886         }
1887 
1888         /**
1889          * Apply this Builder to an existing {@link Notification} object.
1890          *
1891          * @hide
1892          */
buildInto(Notification n)1893         public Notification buildInto(Notification n) {
1894             build().cloneInto(n, true);
1895             return n;
1896         }
1897     }
1898 
1899     /**
1900      * An object that can apply a rich notification style to a {@link Notification.Builder}
1901      * object.
1902      */
1903     public static abstract class Style
1904     {
1905         private CharSequence mBigContentTitle;
1906         private CharSequence mSummaryText = null;
1907         private boolean mSummaryTextSet = false;
1908 
1909         protected Builder mBuilder;
1910 
1911         /**
1912          * Overrides ContentTitle in the big form of the template.
1913          * This defaults to the value passed to setContentTitle().
1914          */
internalSetBigContentTitle(CharSequence title)1915         protected void internalSetBigContentTitle(CharSequence title) {
1916             mBigContentTitle = title;
1917         }
1918 
1919         /**
1920          * Set the first line of text after the detail section in the big form of the template.
1921          */
internalSetSummaryText(CharSequence cs)1922         protected void internalSetSummaryText(CharSequence cs) {
1923             mSummaryText = cs;
1924             mSummaryTextSet = true;
1925         }
1926 
setBuilder(Builder builder)1927         public void setBuilder(Builder builder) {
1928             if (mBuilder != builder) {
1929                 mBuilder = builder;
1930                 if (mBuilder != null) {
1931                     mBuilder.setStyle(this);
1932                 }
1933             }
1934         }
1935 
checkBuilder()1936         protected void checkBuilder() {
1937             if (mBuilder == null) {
1938                 throw new IllegalArgumentException("Style requires a valid Builder object");
1939             }
1940         }
1941 
getStandardView(int layoutId)1942         protected RemoteViews getStandardView(int layoutId) {
1943             checkBuilder();
1944 
1945             if (mBigContentTitle != null) {
1946                 mBuilder.setContentTitle(mBigContentTitle);
1947             }
1948 
1949             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
1950 
1951             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
1952                 contentView.setViewVisibility(R.id.line1, View.GONE);
1953             } else {
1954                 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
1955             }
1956 
1957             // The last line defaults to the subtext, but can be replaced by mSummaryText
1958             final CharSequence overflowText =
1959                     mSummaryTextSet ? mSummaryText
1960                                     : mBuilder.mSubText;
1961             if (overflowText != null) {
1962                 contentView.setTextViewText(R.id.text, overflowText);
1963                 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
1964                 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
1965             } else {
1966                 contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
1967                 contentView.setViewVisibility(R.id.line3, View.GONE);
1968             }
1969 
1970             return contentView;
1971         }
1972 
1973         /**
1974          * @hide
1975          */
addExtras(Bundle extras)1976         public void addExtras(Bundle extras) {
1977             if (mSummaryTextSet) {
1978                 extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
1979             }
1980             if (mBigContentTitle != null) {
1981                 extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
1982             }
1983         }
1984 
1985         /**
1986          * @hide
1987          */
buildStyled(Notification wip)1988         public abstract Notification buildStyled(Notification wip);
1989 
1990         /**
1991          * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
1992          * attached to.
1993          *
1994          * @return the fully constructed Notification.
1995          */
build()1996         public Notification build() {
1997             checkBuilder();
1998             return mBuilder.build();
1999         }
2000     }
2001 
2002     /**
2003      * Helper class for generating large-format notifications that include a large image attachment.
2004      *
2005      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
2006      * <pre class="prettyprint">
2007      * Notification noti = new Notification.BigPictureStyle(
2008      *      new Notification.Builder()
2009      *         .setContentTitle(&quot;New photo from &quot; + sender.toString())
2010      *         .setContentText(subject)
2011      *         .setSmallIcon(R.drawable.new_post)
2012      *         .setLargeIcon(aBitmap))
2013      *      .bigPicture(aBigBitmap)
2014      *      .build();
2015      * </pre>
2016      *
2017      * @see Notification#bigContentView
2018      */
2019     public static class BigPictureStyle extends Style {
2020         private Bitmap mPicture;
2021         private Bitmap mBigLargeIcon;
2022         private boolean mBigLargeIconSet = false;
2023 
BigPictureStyle()2024         public BigPictureStyle() {
2025         }
2026 
BigPictureStyle(Builder builder)2027         public BigPictureStyle(Builder builder) {
2028             setBuilder(builder);
2029         }
2030 
2031         /**
2032          * Overrides ContentTitle in the big form of the template.
2033          * This defaults to the value passed to setContentTitle().
2034          */
setBigContentTitle(CharSequence title)2035         public BigPictureStyle setBigContentTitle(CharSequence title) {
2036             internalSetBigContentTitle(safeCharSequence(title));
2037             return this;
2038         }
2039 
2040         /**
2041          * Set the first line of text after the detail section in the big form of the template.
2042          */
setSummaryText(CharSequence cs)2043         public BigPictureStyle setSummaryText(CharSequence cs) {
2044             internalSetSummaryText(safeCharSequence(cs));
2045             return this;
2046         }
2047 
2048         /**
2049          * Provide the bitmap to be used as the payload for the BigPicture notification.
2050          */
bigPicture(Bitmap b)2051         public BigPictureStyle bigPicture(Bitmap b) {
2052             mPicture = b;
2053             return this;
2054         }
2055 
2056         /**
2057          * Override the large icon when the big notification is shown.
2058          */
bigLargeIcon(Bitmap b)2059         public BigPictureStyle bigLargeIcon(Bitmap b) {
2060             mBigLargeIconSet = true;
2061             mBigLargeIcon = b;
2062             return this;
2063         }
2064 
makeBigContentView()2065         private RemoteViews makeBigContentView() {
2066             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
2067 
2068             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
2069 
2070             return contentView;
2071         }
2072 
2073         /**
2074          * @hide
2075          */
addExtras(Bundle extras)2076         public void addExtras(Bundle extras) {
2077             super.addExtras(extras);
2078 
2079             if (mBigLargeIconSet) {
2080                 extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
2081             }
2082             extras.putParcelable(EXTRA_PICTURE, mPicture);
2083         }
2084 
2085         /**
2086          * @hide
2087          */
2088         @Override
buildStyled(Notification wip)2089         public Notification buildStyled(Notification wip) {
2090             if (mBigLargeIconSet ) {
2091                 mBuilder.mLargeIcon = mBigLargeIcon;
2092             }
2093             wip.bigContentView = makeBigContentView();
2094             return wip;
2095         }
2096     }
2097 
2098     /**
2099      * Helper class for generating large-format notifications that include a lot of text.
2100      *
2101      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
2102      * <pre class="prettyprint">
2103      * Notification noti = new Notification.BigTextStyle(
2104      *      new Notification.Builder()
2105      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
2106      *         .setContentText(subject)
2107      *         .setSmallIcon(R.drawable.new_mail)
2108      *         .setLargeIcon(aBitmap))
2109      *      .bigText(aVeryLongString)
2110      *      .build();
2111      * </pre>
2112      *
2113      * @see Notification#bigContentView
2114      */
2115     public static class BigTextStyle extends Style {
2116         private CharSequence mBigText;
2117 
BigTextStyle()2118         public BigTextStyle() {
2119         }
2120 
BigTextStyle(Builder builder)2121         public BigTextStyle(Builder builder) {
2122             setBuilder(builder);
2123         }
2124 
2125         /**
2126          * Overrides ContentTitle in the big form of the template.
2127          * This defaults to the value passed to setContentTitle().
2128          */
setBigContentTitle(CharSequence title)2129         public BigTextStyle setBigContentTitle(CharSequence title) {
2130             internalSetBigContentTitle(safeCharSequence(title));
2131             return this;
2132         }
2133 
2134         /**
2135          * Set the first line of text after the detail section in the big form of the template.
2136          */
setSummaryText(CharSequence cs)2137         public BigTextStyle setSummaryText(CharSequence cs) {
2138             internalSetSummaryText(safeCharSequence(cs));
2139             return this;
2140         }
2141 
2142         /**
2143          * Provide the longer text to be displayed in the big form of the
2144          * template in place of the content text.
2145          */
bigText(CharSequence cs)2146         public BigTextStyle bigText(CharSequence cs) {
2147             mBigText = safeCharSequence(cs);
2148             return this;
2149         }
2150 
2151         /**
2152          * @hide
2153          */
addExtras(Bundle extras)2154         public void addExtras(Bundle extras) {
2155             super.addExtras(extras);
2156 
2157             extras.putCharSequence(EXTRA_TEXT, mBigText);
2158         }
2159 
makeBigContentView()2160         private RemoteViews makeBigContentView() {
2161             // Remove the content text so line3 only shows if you have a summary
2162             final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
2163             mBuilder.mContentText = null;
2164 
2165             RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
2166 
2167             if (hadThreeLines) {
2168                 // vertical centering
2169                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
2170             }
2171 
2172             contentView.setTextViewText(R.id.big_text, mBigText);
2173             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
2174             contentView.setViewVisibility(R.id.text2, View.GONE);
2175 
2176             return contentView;
2177         }
2178 
2179         /**
2180          * @hide
2181          */
2182         @Override
buildStyled(Notification wip)2183         public Notification buildStyled(Notification wip) {
2184             wip.bigContentView = makeBigContentView();
2185 
2186             wip.extras.putCharSequence(EXTRA_TEXT, mBigText);
2187 
2188             return wip;
2189         }
2190     }
2191 
2192     /**
2193      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
2194      *
2195      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
2196      * <pre class="prettyprint">
2197      * Notification noti = new Notification.InboxStyle(
2198      *      new Notification.Builder()
2199      *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
2200      *         .setContentText(subject)
2201      *         .setSmallIcon(R.drawable.new_mail)
2202      *         .setLargeIcon(aBitmap))
2203      *      .addLine(str1)
2204      *      .addLine(str2)
2205      *      .setContentTitle("")
2206      *      .setSummaryText(&quot;+3 more&quot;)
2207      *      .build();
2208      * </pre>
2209      *
2210      * @see Notification#bigContentView
2211      */
2212     public static class InboxStyle extends Style {
2213         private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
2214 
InboxStyle()2215         public InboxStyle() {
2216         }
2217 
InboxStyle(Builder builder)2218         public InboxStyle(Builder builder) {
2219             setBuilder(builder);
2220         }
2221 
2222         /**
2223          * Overrides ContentTitle in the big form of the template.
2224          * This defaults to the value passed to setContentTitle().
2225          */
setBigContentTitle(CharSequence title)2226         public InboxStyle setBigContentTitle(CharSequence title) {
2227             internalSetBigContentTitle(safeCharSequence(title));
2228             return this;
2229         }
2230 
2231         /**
2232          * Set the first line of text after the detail section in the big form of the template.
2233          */
setSummaryText(CharSequence cs)2234         public InboxStyle setSummaryText(CharSequence cs) {
2235             internalSetSummaryText(safeCharSequence(cs));
2236             return this;
2237         }
2238 
2239         /**
2240          * Append a line to the digest section of the Inbox notification.
2241          */
addLine(CharSequence cs)2242         public InboxStyle addLine(CharSequence cs) {
2243             mTexts.add(safeCharSequence(cs));
2244             return this;
2245         }
2246 
2247         /**
2248          * @hide
2249          */
addExtras(Bundle extras)2250         public void addExtras(Bundle extras) {
2251             super.addExtras(extras);
2252             CharSequence[] a = new CharSequence[mTexts.size()];
2253             extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
2254         }
2255 
makeBigContentView()2256         private RemoteViews makeBigContentView() {
2257             // Remove the content text so line3 disappears unless you have a summary
2258             mBuilder.mContentText = null;
2259             RemoteViews contentView = getStandardView(R.layout.notification_template_inbox);
2260 
2261             contentView.setViewVisibility(R.id.text2, View.GONE);
2262 
2263             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
2264                     R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
2265 
2266             // Make sure all rows are gone in case we reuse a view.
2267             for (int rowId : rowIds) {
2268                 contentView.setViewVisibility(rowId, View.GONE);
2269             }
2270 
2271 
2272             int i=0;
2273             while (i < mTexts.size() && i < rowIds.length) {
2274                 CharSequence str = mTexts.get(i);
2275                 if (str != null && !str.equals("")) {
2276                     contentView.setViewVisibility(rowIds[i], View.VISIBLE);
2277                     contentView.setTextViewText(rowIds[i], str);
2278                 }
2279                 i++;
2280             }
2281 
2282             contentView.setViewVisibility(R.id.inbox_end_pad,
2283                     mTexts.size() > 0 ? View.VISIBLE : View.GONE);
2284 
2285             contentView.setViewVisibility(R.id.inbox_more,
2286                     mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE);
2287 
2288             return contentView;
2289         }
2290 
2291         /**
2292          * @hide
2293          */
2294         @Override
buildStyled(Notification wip)2295         public Notification buildStyled(Notification wip) {
2296             wip.bigContentView = makeBigContentView();
2297 
2298             return wip;
2299         }
2300     }
2301 }
2302