• 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      * @hide
436      */
437     public Bundle extras = new Bundle();
438 
439     // extras keys for Builder inputs
440     /** @hide */
441     public static final String EXTRA_TITLE = "android.title";
442     /** @hide */
443     public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
444     /** @hide */
445     public static final String EXTRA_TEXT = "android.text";
446     /** @hide */
447     public static final String EXTRA_SUB_TEXT = "android.subText";
448     /** @hide */
449     public static final String EXTRA_INFO_TEXT = "android.infoText";
450     /** @hide */
451     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
452     /** @hide */
453     public static final String EXTRA_SMALL_ICON = "android.icon";
454     /** @hide */
455     public static final String EXTRA_LARGE_ICON = "android.largeIcon";
456     /** @hide */
457     public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
458     /** @hide */
459     public static final String EXTRA_PROGRESS = "android.progress";
460     /** @hide */
461     public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
462     /** @hide */
463     public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
464     /** @hide */
465     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
466     /** @hide */
467     public static final String EXTRA_SHOW_WHEN = "android.showWhen";
468     /** @hide from BigPictureStyle */
469     public static final String EXTRA_PICTURE = "android.picture";
470     /** @hide from InboxStyle */
471     public static final String EXTRA_TEXT_LINES = "android.textLines";
472 
473     // extras keys for other interesting pieces of information
474     /** @hide */
475     public static final String EXTRA_PEOPLE = "android.people";
476 
477     /**
478      * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
479      * @hide
480      */
481     public static class Action implements Parcelable {
482         public int icon;
483         public CharSequence title;
484         public PendingIntent actionIntent;
485         @SuppressWarnings("unused")
Action()486         public Action() { }
Action(Parcel in)487         private Action(Parcel in) {
488             icon = in.readInt();
489             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
490             if (in.readInt() == 1) {
491                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
492             }
493         }
Action(int icon_, CharSequence title_, PendingIntent intent_)494         public Action(int icon_, CharSequence title_, PendingIntent intent_) {
495             this.icon = icon_;
496             this.title = title_;
497             this.actionIntent = intent_;
498         }
499         @Override
clone()500         public Action clone() {
501             return new Action(
502                 this.icon,
503                 this.title.toString(),
504                 this.actionIntent // safe to alias
505             );
506         }
507         @Override
describeContents()508         public int describeContents() {
509             return 0;
510         }
511         @Override
writeToParcel(Parcel out, int flags)512         public void writeToParcel(Parcel out, int flags) {
513             out.writeInt(icon);
514             TextUtils.writeToParcel(title, out, flags);
515             if (actionIntent != null) {
516                 out.writeInt(1);
517                 actionIntent.writeToParcel(out, flags);
518             } else {
519                 out.writeInt(0);
520             }
521         }
522         public static final Parcelable.Creator<Action> CREATOR
523         = new Parcelable.Creator<Action>() {
524             public Action createFromParcel(Parcel in) {
525                 return new Action(in);
526             }
527             public Action[] newArray(int size) {
528                 return new Action[size];
529             }
530         };
531     }
532 
533     /**
534      * @hide
535      */
536     public Action[] actions;
537 
538     /**
539      * Constructs a Notification object with default values.
540      * You might want to consider using {@link Builder} instead.
541      */
Notification()542     public Notification()
543     {
544         this.when = System.currentTimeMillis();
545         this.priority = PRIORITY_DEFAULT;
546     }
547 
548     /**
549      * @hide
550      */
Notification(Context context, int icon, CharSequence tickerText, long when, CharSequence contentTitle, CharSequence contentText, Intent contentIntent)551     public Notification(Context context, int icon, CharSequence tickerText, long when,
552             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
553     {
554         this.when = when;
555         this.icon = icon;
556         this.tickerText = tickerText;
557         setLatestEventInfo(context, contentTitle, contentText,
558                 PendingIntent.getActivity(context, 0, contentIntent, 0));
559     }
560 
561     /**
562      * Constructs a Notification object with the information needed to
563      * have a status bar icon without the standard expanded view.
564      *
565      * @param icon          The resource id of the icon to put in the status bar.
566      * @param tickerText    The text that flows by in the status bar when the notification first
567      *                      activates.
568      * @param when          The time to show in the time field.  In the System.currentTimeMillis
569      *                      timebase.
570      *
571      * @deprecated Use {@link Builder} instead.
572      */
573     @Deprecated
Notification(int icon, CharSequence tickerText, long when)574     public Notification(int icon, CharSequence tickerText, long when)
575     {
576         this.icon = icon;
577         this.tickerText = tickerText;
578         this.when = when;
579     }
580 
581     /**
582      * Unflatten the notification from a parcel.
583      */
Notification(Parcel parcel)584     public Notification(Parcel parcel)
585     {
586         int version = parcel.readInt();
587 
588         when = parcel.readLong();
589         icon = parcel.readInt();
590         number = parcel.readInt();
591         if (parcel.readInt() != 0) {
592             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
593         }
594         if (parcel.readInt() != 0) {
595             deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
596         }
597         if (parcel.readInt() != 0) {
598             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
599         }
600         if (parcel.readInt() != 0) {
601             tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
602         }
603         if (parcel.readInt() != 0) {
604             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
605         }
606         if (parcel.readInt() != 0) {
607             largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
608         }
609         defaults = parcel.readInt();
610         flags = parcel.readInt();
611         if (parcel.readInt() != 0) {
612             sound = Uri.CREATOR.createFromParcel(parcel);
613         }
614 
615         audioStreamType = parcel.readInt();
616         vibrate = parcel.createLongArray();
617         ledARGB = parcel.readInt();
618         ledOnMS = parcel.readInt();
619         ledOffMS = parcel.readInt();
620         iconLevel = parcel.readInt();
621 
622         if (parcel.readInt() != 0) {
623             fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
624         }
625 
626         priority = parcel.readInt();
627 
628         kind = parcel.createStringArray(); // may set kind to null
629 
630         extras = parcel.readBundle(); // may be null
631 
632         actions = parcel.createTypedArray(Action.CREATOR); // may be null
633 
634         if (parcel.readInt() != 0) {
635             bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
636         }
637     }
638 
639     @Override
clone()640     public Notification clone() {
641         Notification that = new Notification();
642         cloneInto(that, true);
643         return that;
644     }
645 
646     /**
647      * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
648      * of this into that.
649      * @hide
650      */
cloneInto(Notification that, boolean heavy)651     public void cloneInto(Notification that, boolean heavy) {
652         that.when = this.when;
653         that.icon = this.icon;
654         that.number = this.number;
655 
656         // PendingIntents are global, so there's no reason (or way) to clone them.
657         that.contentIntent = this.contentIntent;
658         that.deleteIntent = this.deleteIntent;
659         that.fullScreenIntent = this.fullScreenIntent;
660 
661         if (this.tickerText != null) {
662             that.tickerText = this.tickerText.toString();
663         }
664         if (heavy && this.tickerView != null) {
665             that.tickerView = this.tickerView.clone();
666         }
667         if (heavy && this.contentView != null) {
668             that.contentView = this.contentView.clone();
669         }
670         if (heavy && this.largeIcon != null) {
671             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
672         }
673         that.iconLevel = this.iconLevel;
674         that.sound = this.sound; // android.net.Uri is immutable
675         that.audioStreamType = this.audioStreamType;
676 
677         final long[] vibrate = this.vibrate;
678         if (vibrate != null) {
679             final int N = vibrate.length;
680             final long[] vib = that.vibrate = new long[N];
681             System.arraycopy(vibrate, 0, vib, 0, N);
682         }
683 
684         that.ledARGB = this.ledARGB;
685         that.ledOnMS = this.ledOnMS;
686         that.ledOffMS = this.ledOffMS;
687         that.defaults = this.defaults;
688 
689         that.flags = this.flags;
690 
691         that.priority = this.priority;
692 
693         final String[] thiskind = this.kind;
694         if (thiskind != null) {
695             final int N = thiskind.length;
696             final String[] thatkind = that.kind = new String[N];
697             System.arraycopy(thiskind, 0, thatkind, 0, N);
698         }
699 
700         if (this.extras != null) {
701             try {
702                 that.extras = new Bundle(this.extras);
703                 // will unparcel
704                 that.extras.size();
705             } catch (BadParcelableException e) {
706                 Log.e(TAG, "could not unparcel extras from notification: " + this, e);
707                 that.extras = null;
708             }
709         }
710 
711         if (this.actions != null) {
712             that.actions = new Action[this.actions.length];
713             for(int i=0; i<this.actions.length; i++) {
714                 that.actions[i] = this.actions[i].clone();
715             }
716         }
717 
718         if (heavy && this.bigContentView != null) {
719             that.bigContentView = this.bigContentView.clone();
720         }
721 
722         if (!heavy) {
723             that.lightenPayload(); // will clean out extras
724         }
725     }
726 
727     /**
728      * Removes heavyweight parts of the Notification object for archival or for sending to
729      * listeners when the full contents are not necessary.
730      * @hide
731      */
lightenPayload()732     public final void lightenPayload() {
733         tickerView = null;
734         contentView = null;
735         bigContentView = null;
736         largeIcon = null;
737         if (extras != null) {
738             extras.remove(Notification.EXTRA_LARGE_ICON);
739             extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
740             extras.remove(Notification.EXTRA_PICTURE);
741         }
742     }
743 
744     /**
745      * Make sure this CharSequence is safe to put into a bundle, which basically
746      * means it had better not be some custom Parcelable implementation.
747      * @hide
748      */
safeCharSequence(CharSequence cs)749     public static CharSequence safeCharSequence(CharSequence cs) {
750         if (cs instanceof Parcelable) {
751             Log.e(TAG, "warning: " + cs.getClass().getCanonicalName()
752                     + " instance is a custom Parcelable and not allowed in Notification");
753             return cs.toString();
754         }
755 
756         return cs;
757     }
758 
describeContents()759     public int describeContents() {
760         return 0;
761     }
762 
763     /**
764      * Flatten this notification from a parcel.
765      */
writeToParcel(Parcel parcel, int flags)766     public void writeToParcel(Parcel parcel, int flags)
767     {
768         parcel.writeInt(1);
769 
770         parcel.writeLong(when);
771         parcel.writeInt(icon);
772         parcel.writeInt(number);
773         if (contentIntent != null) {
774             parcel.writeInt(1);
775             contentIntent.writeToParcel(parcel, 0);
776         } else {
777             parcel.writeInt(0);
778         }
779         if (deleteIntent != null) {
780             parcel.writeInt(1);
781             deleteIntent.writeToParcel(parcel, 0);
782         } else {
783             parcel.writeInt(0);
784         }
785         if (tickerText != null) {
786             parcel.writeInt(1);
787             TextUtils.writeToParcel(tickerText, parcel, flags);
788         } else {
789             parcel.writeInt(0);
790         }
791         if (tickerView != null) {
792             parcel.writeInt(1);
793             tickerView.writeToParcel(parcel, 0);
794         } else {
795             parcel.writeInt(0);
796         }
797         if (contentView != null) {
798             parcel.writeInt(1);
799             contentView.writeToParcel(parcel, 0);
800         } else {
801             parcel.writeInt(0);
802         }
803         if (largeIcon != null) {
804             parcel.writeInt(1);
805             largeIcon.writeToParcel(parcel, 0);
806         } else {
807             parcel.writeInt(0);
808         }
809 
810         parcel.writeInt(defaults);
811         parcel.writeInt(this.flags);
812 
813         if (sound != null) {
814             parcel.writeInt(1);
815             sound.writeToParcel(parcel, 0);
816         } else {
817             parcel.writeInt(0);
818         }
819         parcel.writeInt(audioStreamType);
820         parcel.writeLongArray(vibrate);
821         parcel.writeInt(ledARGB);
822         parcel.writeInt(ledOnMS);
823         parcel.writeInt(ledOffMS);
824         parcel.writeInt(iconLevel);
825 
826         if (fullScreenIntent != null) {
827             parcel.writeInt(1);
828             fullScreenIntent.writeToParcel(parcel, 0);
829         } else {
830             parcel.writeInt(0);
831         }
832 
833         parcel.writeInt(priority);
834 
835         parcel.writeStringArray(kind); // ok for null
836 
837         parcel.writeBundle(extras); // null ok
838 
839         parcel.writeTypedArray(actions, 0); // null ok
840 
841         if (bigContentView != null) {
842             parcel.writeInt(1);
843             bigContentView.writeToParcel(parcel, 0);
844         } else {
845             parcel.writeInt(0);
846         }
847     }
848 
849     /**
850      * Parcelable.Creator that instantiates Notification objects
851      */
852     public static final Parcelable.Creator<Notification> CREATOR
853             = new Parcelable.Creator<Notification>()
854     {
855         public Notification createFromParcel(Parcel parcel)
856         {
857             return new Notification(parcel);
858         }
859 
860         public Notification[] newArray(int size)
861         {
862             return new Notification[size];
863         }
864     };
865 
866     /**
867      * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
868      * layout.
869      *
870      * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
871      * in the view.</p>
872      * @param context       The context for your application / activity.
873      * @param contentTitle The title that goes in the expanded entry.
874      * @param contentText  The text that goes in the expanded entry.
875      * @param contentIntent The intent to launch when the user clicks the expanded notification.
876      * If this is an activity, it must include the
877      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
878      * that you take care of task management as described in the
879      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
880      * Stack</a> document.
881      *
882      * @deprecated Use {@link Builder} instead.
883      */
884     @Deprecated
setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)885     public void setLatestEventInfo(Context context,
886             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
887         Notification.Builder builder = new Notification.Builder(context);
888 
889         // First, ensure that key pieces of information that may have been set directly
890         // are preserved
891         builder.setWhen(this.when);
892         builder.setSmallIcon(this.icon);
893         builder.setPriority(this.priority);
894         builder.setTicker(this.tickerText);
895         builder.setNumber(this.number);
896         builder.mFlags = this.flags;
897         builder.setSound(this.sound, this.audioStreamType);
898         builder.setDefaults(this.defaults);
899         builder.setVibrate(this.vibrate);
900 
901         // now apply the latestEventInfo fields
902         if (contentTitle != null) {
903             builder.setContentTitle(contentTitle);
904         }
905         if (contentText != null) {
906             builder.setContentText(contentText);
907         }
908         builder.setContentIntent(contentIntent);
909         builder.buildInto(this);
910     }
911 
912     @Override
toString()913     public String toString() {
914         StringBuilder sb = new StringBuilder();
915         sb.append("Notification(pri=");
916         sb.append(priority);
917         sb.append(" contentView=");
918         if (contentView != null) {
919             sb.append(contentView.getPackage());
920             sb.append("/0x");
921             sb.append(Integer.toHexString(contentView.getLayoutId()));
922         } else {
923             sb.append("null");
924         }
925         // TODO(dsandler): defaults take precedence over local values, so reorder the branches below
926         sb.append(" vibrate=");
927         if ((this.defaults & DEFAULT_VIBRATE) != 0) {
928             sb.append("default");
929         } else if (this.vibrate != null) {
930             int N = this.vibrate.length-1;
931             sb.append("[");
932             for (int i=0; i<N; i++) {
933                 sb.append(this.vibrate[i]);
934                 sb.append(',');
935             }
936             if (N != -1) {
937                 sb.append(this.vibrate[N]);
938             }
939             sb.append("]");
940         } else {
941             sb.append("null");
942         }
943         sb.append(" sound=");
944         if ((this.defaults & DEFAULT_SOUND) != 0) {
945             sb.append("default");
946         } else if (this.sound != null) {
947             sb.append(this.sound.toString());
948         } else {
949             sb.append("null");
950         }
951         sb.append(" defaults=0x");
952         sb.append(Integer.toHexString(this.defaults));
953         sb.append(" flags=0x");
954         sb.append(Integer.toHexString(this.flags));
955         sb.append(" kind=[");
956         if (this.kind == null) {
957             sb.append("null");
958         } else {
959             for (int i=0; i<this.kind.length; i++) {
960                 if (i>0) sb.append(",");
961                 sb.append(this.kind[i]);
962             }
963         }
964         sb.append("]");
965         if (actions != null) {
966             sb.append(" ");
967             sb.append(actions.length);
968             sb.append(" action");
969             if (actions.length > 1) sb.append("s");
970         }
971         sb.append(")");
972         return sb.toString();
973     }
974 
975     /** {@hide} */
setUser(UserHandle user)976     public void setUser(UserHandle user) {
977         if (user.getIdentifier() == UserHandle.USER_ALL) {
978             user = UserHandle.OWNER;
979         }
980         if (tickerView != null) {
981             tickerView.setUser(user);
982         }
983         if (contentView != null) {
984             contentView.setUser(user);
985         }
986         if (bigContentView != null) {
987             bigContentView.setUser(user);
988         }
989     }
990 
991     /**
992      * Builder class for {@link Notification} objects.
993      *
994      * Provides a convenient way to set the various fields of a {@link Notification} and generate
995      * content views using the platform's notification layout template. If your app supports
996      * versions of Android as old as API level 4, you can instead use
997      * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
998      * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
999      * library</a>.
1000      *
1001      * <p>Example:
1002      *
1003      * <pre class="prettyprint">
1004      * Notification noti = new Notification.Builder(mContext)
1005      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
1006      *         .setContentText(subject)
1007      *         .setSmallIcon(R.drawable.new_mail)
1008      *         .setLargeIcon(aBitmap)
1009      *         .build();
1010      * </pre>
1011      */
1012     public static class Builder {
1013         private static final int MAX_ACTION_BUTTONS = 3;
1014 
1015         private Context mContext;
1016 
1017         private long mWhen;
1018         private int mSmallIcon;
1019         private int mSmallIconLevel;
1020         private int mNumber;
1021         private CharSequence mContentTitle;
1022         private CharSequence mContentText;
1023         private CharSequence mContentInfo;
1024         private CharSequence mSubText;
1025         private PendingIntent mContentIntent;
1026         private RemoteViews mContentView;
1027         private PendingIntent mDeleteIntent;
1028         private PendingIntent mFullScreenIntent;
1029         private CharSequence mTickerText;
1030         private RemoteViews mTickerView;
1031         private Bitmap mLargeIcon;
1032         private Uri mSound;
1033         private int mAudioStreamType;
1034         private long[] mVibrate;
1035         private int mLedArgb;
1036         private int mLedOnMs;
1037         private int mLedOffMs;
1038         private int mDefaults;
1039         private int mFlags;
1040         private int mProgressMax;
1041         private int mProgress;
1042         private boolean mProgressIndeterminate;
1043         private ArrayList<String> mKindList = new ArrayList<String>(1);
1044         private Bundle mExtras;
1045         private int mPriority;
1046         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
1047         private boolean mUseChronometer;
1048         private Style mStyle;
1049         private boolean mShowWhen = true;
1050 
1051         /**
1052          * Constructs a new Builder with the defaults:
1053          *
1054 
1055          * <table>
1056          * <tr><th align=right>priority</th>
1057          *     <td>{@link #PRIORITY_DEFAULT}</td></tr>
1058          * <tr><th align=right>when</th>
1059          *     <td>now ({@link System#currentTimeMillis()})</td></tr>
1060          * <tr><th align=right>audio stream</th>
1061          *     <td>{@link #STREAM_DEFAULT}</td></tr>
1062          * </table>
1063          *
1064 
1065          * @param context
1066          *            A {@link Context} that will be used by the Builder to construct the
1067          *            RemoteViews. The Context will not be held past the lifetime of this Builder
1068          *            object.
1069          */
Builder(Context context)1070         public Builder(Context context) {
1071             mContext = context;
1072 
1073             // Set defaults to match the defaults of a Notification
1074             mWhen = System.currentTimeMillis();
1075             mAudioStreamType = STREAM_DEFAULT;
1076             mPriority = PRIORITY_DEFAULT;
1077         }
1078 
1079         /**
1080          * Add a timestamp pertaining to the notification (usually the time the event occurred).
1081          * It will be shown in the notification content view by default; use
1082          * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
1083          *
1084          * @see Notification#when
1085          */
setWhen(long when)1086         public Builder setWhen(long when) {
1087             mWhen = when;
1088             return this;
1089         }
1090 
1091         /**
1092          * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
1093          * in the content view.
1094          */
setShowWhen(boolean show)1095         public Builder setShowWhen(boolean show) {
1096             mShowWhen = show;
1097             return this;
1098         }
1099 
1100         /**
1101          * Show the {@link Notification#when} field as a stopwatch.
1102          *
1103          * Instead of presenting <code>when</code> as a timestamp, the notification will show an
1104          * automatically updating display of the minutes and seconds since <code>when</code>.
1105          *
1106          * Useful when showing an elapsed time (like an ongoing phone call).
1107          *
1108          * @see android.widget.Chronometer
1109          * @see Notification#when
1110          */
setUsesChronometer(boolean b)1111         public Builder setUsesChronometer(boolean b) {
1112             mUseChronometer = b;
1113             return this;
1114         }
1115 
1116         /**
1117          * Set the small icon resource, which will be used to represent the notification in the
1118          * status bar.
1119          *
1120 
1121          * The platform template for the expanded view will draw this icon in the left, unless a
1122          * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
1123          * icon will be moved to the right-hand side.
1124          *
1125 
1126          * @param icon
1127          *            A resource ID in the application's package of the drawable to use.
1128          * @see Notification#icon
1129          */
setSmallIcon(int icon)1130         public Builder setSmallIcon(int icon) {
1131             mSmallIcon = icon;
1132             return this;
1133         }
1134 
1135         /**
1136          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
1137          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
1138          * LevelListDrawable}.
1139          *
1140          * @param icon A resource ID in the application's package of the drawable to use.
1141          * @param level The level to use for the icon.
1142          *
1143          * @see Notification#icon
1144          * @see Notification#iconLevel
1145          */
setSmallIcon(int icon, int level)1146         public Builder setSmallIcon(int icon, int level) {
1147             mSmallIcon = icon;
1148             mSmallIconLevel = level;
1149             return this;
1150         }
1151 
1152         /**
1153          * Set the first line of text in the platform notification template.
1154          */
setContentTitle(CharSequence title)1155         public Builder setContentTitle(CharSequence title) {
1156             mContentTitle = safeCharSequence(title);
1157             return this;
1158         }
1159 
1160         /**
1161          * Set the second line of text in the platform notification template.
1162          */
setContentText(CharSequence text)1163         public Builder setContentText(CharSequence text) {
1164             mContentText = safeCharSequence(text);
1165             return this;
1166         }
1167 
1168         /**
1169          * Set the third line of text in the platform notification template.
1170          * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the
1171          * same location in the standard template.
1172          */
setSubText(CharSequence text)1173         public Builder setSubText(CharSequence text) {
1174             mSubText = safeCharSequence(text);
1175             return this;
1176         }
1177 
1178         /**
1179          * Set the large number at the right-hand side of the notification.  This is
1180          * equivalent to setContentInfo, although it might show the number in a different
1181          * font size for readability.
1182          */
setNumber(int number)1183         public Builder setNumber(int number) {
1184             mNumber = number;
1185             return this;
1186         }
1187 
1188         /**
1189          * A small piece of additional information pertaining to this notification.
1190          *
1191          * The platform template will draw this on the last line of the notification, at the far
1192          * right (to the right of a smallIcon if it has been placed there).
1193          */
setContentInfo(CharSequence info)1194         public Builder setContentInfo(CharSequence info) {
1195             mContentInfo = safeCharSequence(info);
1196             return this;
1197         }
1198 
1199         /**
1200          * Set the progress this notification represents.
1201          *
1202          * The platform template will represent this using a {@link ProgressBar}.
1203          */
setProgress(int max, int progress, boolean indeterminate)1204         public Builder setProgress(int max, int progress, boolean indeterminate) {
1205             mProgressMax = max;
1206             mProgress = progress;
1207             mProgressIndeterminate = indeterminate;
1208             return this;
1209         }
1210 
1211         /**
1212          * Supply a custom RemoteViews to use instead of the platform template.
1213          *
1214          * @see Notification#contentView
1215          */
setContent(RemoteViews views)1216         public Builder setContent(RemoteViews views) {
1217             mContentView = views;
1218             return this;
1219         }
1220 
1221         /**
1222          * Supply a {@link PendingIntent} to be sent when the notification is clicked.
1223          *
1224          * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
1225          * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
1226          * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
1227          * to assign PendingIntents to individual views in that custom layout (i.e., to create
1228          * clickable buttons inside the notification view).
1229          *
1230          * @see Notification#contentIntent Notification.contentIntent
1231          */
setContentIntent(PendingIntent intent)1232         public Builder setContentIntent(PendingIntent intent) {
1233             mContentIntent = intent;
1234             return this;
1235         }
1236 
1237         /**
1238          * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
1239          *
1240          * @see Notification#deleteIntent
1241          */
setDeleteIntent(PendingIntent intent)1242         public Builder setDeleteIntent(PendingIntent intent) {
1243             mDeleteIntent = intent;
1244             return this;
1245         }
1246 
1247         /**
1248          * An intent to launch instead of posting the notification to the status bar.
1249          * Only for use with extremely high-priority notifications demanding the user's
1250          * <strong>immediate</strong> attention, such as an incoming phone call or
1251          * alarm clock that the user has explicitly set to a particular time.
1252          * If this facility is used for something else, please give the user an option
1253          * to turn it off and use a normal notification, as this can be extremely
1254          * disruptive.
1255          *
1256          * @param intent The pending intent to launch.
1257          * @param highPriority Passing true will cause this notification to be sent
1258          *          even if other notifications are suppressed.
1259          *
1260          * @see Notification#fullScreenIntent
1261          */
setFullScreenIntent(PendingIntent intent, boolean highPriority)1262         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
1263             mFullScreenIntent = intent;
1264             setFlag(FLAG_HIGH_PRIORITY, highPriority);
1265             return this;
1266         }
1267 
1268         /**
1269          * Set the "ticker" text which is displayed in the status bar when the notification first
1270          * arrives.
1271          *
1272          * @see Notification#tickerText
1273          */
setTicker(CharSequence tickerText)1274         public Builder setTicker(CharSequence tickerText) {
1275             mTickerText = safeCharSequence(tickerText);
1276             return this;
1277         }
1278 
1279         /**
1280          * Set the text that is displayed in the status bar when the notification first
1281          * arrives, and also a RemoteViews object that may be displayed instead on some
1282          * devices.
1283          *
1284          * @see Notification#tickerText
1285          * @see Notification#tickerView
1286          */
setTicker(CharSequence tickerText, RemoteViews views)1287         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
1288             mTickerText = safeCharSequence(tickerText);
1289             mTickerView = views;
1290             return this;
1291         }
1292 
1293         /**
1294          * Add a large icon to the notification (and the ticker on some devices).
1295          *
1296          * In the platform template, this image will be shown on the left of the notification view
1297          * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side).
1298          *
1299          * @see Notification#largeIcon
1300          */
setLargeIcon(Bitmap icon)1301         public Builder setLargeIcon(Bitmap icon) {
1302             mLargeIcon = icon;
1303             return this;
1304         }
1305 
1306         /**
1307          * Set the sound to play.
1308          *
1309          * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications.
1310          *
1311          * @see Notification#sound
1312          */
setSound(Uri sound)1313         public Builder setSound(Uri sound) {
1314             mSound = sound;
1315             mAudioStreamType = STREAM_DEFAULT;
1316             return this;
1317         }
1318 
1319         /**
1320          * Set the sound to play, along with a specific stream on which to play it.
1321          *
1322          * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
1323          *
1324          * @see Notification#sound
1325          */
setSound(Uri sound, int streamType)1326         public Builder setSound(Uri sound, int streamType) {
1327             mSound = sound;
1328             mAudioStreamType = streamType;
1329             return this;
1330         }
1331 
1332         /**
1333          * Set the vibration pattern to use.
1334          *
1335 
1336          * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
1337          * <code>pattern</code> parameter.
1338          *
1339 
1340          * @see Notification#vibrate
1341          */
setVibrate(long[] pattern)1342         public Builder setVibrate(long[] pattern) {
1343             mVibrate = pattern;
1344             return this;
1345         }
1346 
1347         /**
1348          * Set the desired color for the indicator LED on the device, as well as the
1349          * blink duty cycle (specified in milliseconds).
1350          *
1351 
1352          * Not all devices will honor all (or even any) of these values.
1353          *
1354 
1355          * @see Notification#ledARGB
1356          * @see Notification#ledOnMS
1357          * @see Notification#ledOffMS
1358          */
setLights(int argb, int onMs, int offMs)1359         public Builder setLights(int argb, int onMs, int offMs) {
1360             mLedArgb = argb;
1361             mLedOnMs = onMs;
1362             mLedOffMs = offMs;
1363             return this;
1364         }
1365 
1366         /**
1367          * Set whether this is an "ongoing" notification.
1368          *
1369 
1370          * Ongoing notifications cannot be dismissed by the user, so your application or service
1371          * must take care of canceling them.
1372          *
1373 
1374          * They are typically used to indicate a background task that the user is actively engaged
1375          * with (e.g., playing music) or is pending in some way and therefore occupying the device
1376          * (e.g., a file download, sync operation, active network connection).
1377          *
1378 
1379          * @see Notification#FLAG_ONGOING_EVENT
1380          * @see Service#setForeground(boolean)
1381          */
setOngoing(boolean ongoing)1382         public Builder setOngoing(boolean ongoing) {
1383             setFlag(FLAG_ONGOING_EVENT, ongoing);
1384             return this;
1385         }
1386 
1387         /**
1388          * Set this flag if you would only like the sound, vibrate
1389          * and ticker to be played if the notification is not already showing.
1390          *
1391          * @see Notification#FLAG_ONLY_ALERT_ONCE
1392          */
setOnlyAlertOnce(boolean onlyAlertOnce)1393         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
1394             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
1395             return this;
1396         }
1397 
1398         /**
1399          * Make this notification automatically dismissed when the user touches it. The
1400          * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
1401          *
1402          * @see Notification#FLAG_AUTO_CANCEL
1403          */
setAutoCancel(boolean autoCancel)1404         public Builder setAutoCancel(boolean autoCancel) {
1405             setFlag(FLAG_AUTO_CANCEL, autoCancel);
1406             return this;
1407         }
1408 
1409         /**
1410          * Set which notification properties will be inherited from system defaults.
1411          * <p>
1412          * The value should be one or more of the following fields combined with
1413          * bitwise-or:
1414          * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
1415          * <p>
1416          * For all default values, use {@link #DEFAULT_ALL}.
1417          */
setDefaults(int defaults)1418         public Builder setDefaults(int defaults) {
1419             mDefaults = defaults;
1420             return this;
1421         }
1422 
1423         /**
1424          * Set the priority of this notification.
1425          *
1426          * @see Notification#priority
1427          */
setPriority(int pri)1428         public Builder setPriority(int pri) {
1429             mPriority = pri;
1430             return this;
1431         }
1432 
1433         /**
1434          * @hide
1435          *
1436          * Add a kind (category) to this notification. Optional.
1437          *
1438          * @see Notification#kind
1439          */
addKind(String k)1440         public Builder addKind(String k) {
1441             mKindList.add(k);
1442             return this;
1443         }
1444 
1445         /**
1446          * Add metadata to this notification.
1447          *
1448          * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
1449          * current contents are copied into the Notification each time {@link #build()} is
1450          * called.
1451          *
1452          * @see Notification#extras
1453          * @hide
1454          */
setExtras(Bundle bag)1455         public Builder setExtras(Bundle bag) {
1456             mExtras = bag;
1457             return this;
1458         }
1459 
1460         /**
1461          * Add an action to this notification. Actions are typically displayed by
1462          * the system as a button adjacent to the notification content.
1463          * <br>
1464          * A notification displays up to 3 actions, from left to right in the order they were added.
1465          *
1466          * @param icon Resource ID of a drawable that represents the action.
1467          * @param title Text describing the action.
1468          * @param intent PendingIntent to be fired when the action is invoked.
1469          */
addAction(int icon, CharSequence title, PendingIntent intent)1470         public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
1471             mActions.add(new Action(icon, safeCharSequence(title), intent));
1472             return this;
1473         }
1474 
1475         /**
1476          * Add a rich notification style to be applied at build time.
1477          *
1478          * @param style Object responsible for modifying the notification style.
1479          */
setStyle(Style style)1480         public Builder setStyle(Style style) {
1481             if (mStyle != style) {
1482                 mStyle = style;
1483                 if (mStyle != null) {
1484                     mStyle.setBuilder(this);
1485                 }
1486             }
1487             return this;
1488         }
1489 
setFlag(int mask, boolean value)1490         private void setFlag(int mask, boolean value) {
1491             if (value) {
1492                 mFlags |= mask;
1493             } else {
1494                 mFlags &= ~mask;
1495             }
1496         }
1497 
applyStandardTemplate(int resId, boolean fitIn1U)1498         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
1499             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
1500             boolean showLine3 = false;
1501             boolean showLine2 = false;
1502             int smallIconImageViewId = R.id.icon;
1503             if (mLargeIcon != null) {
1504                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
1505                 smallIconImageViewId = R.id.right_icon;
1506             }
1507             if (mPriority < PRIORITY_LOW) {
1508                 contentView.setInt(R.id.icon,
1509                         "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
1510                 contentView.setInt(R.id.status_bar_latest_event_content,
1511                         "setBackgroundResource", R.drawable.notification_bg_low);
1512             }
1513             if (mSmallIcon != 0) {
1514                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
1515                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
1516             } else {
1517                 contentView.setViewVisibility(smallIconImageViewId, View.GONE);
1518             }
1519             if (mContentTitle != null) {
1520                 contentView.setTextViewText(R.id.title, mContentTitle);
1521             }
1522             if (mContentText != null) {
1523                 contentView.setTextViewText(R.id.text, mContentText);
1524                 showLine3 = true;
1525             }
1526             if (mContentInfo != null) {
1527                 contentView.setTextViewText(R.id.info, mContentInfo);
1528                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
1529                 showLine3 = true;
1530             } else if (mNumber > 0) {
1531                 final int tooBig = mContext.getResources().getInteger(
1532                         R.integer.status_bar_notification_info_maxnum);
1533                 if (mNumber > tooBig) {
1534                     contentView.setTextViewText(R.id.info, mContext.getResources().getString(
1535                                 R.string.status_bar_notification_info_overflow));
1536                 } else {
1537                     NumberFormat f = NumberFormat.getIntegerInstance();
1538                     contentView.setTextViewText(R.id.info, f.format(mNumber));
1539                 }
1540                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
1541                 showLine3 = true;
1542             } else {
1543                 contentView.setViewVisibility(R.id.info, View.GONE);
1544             }
1545 
1546             // Need to show three lines?
1547             if (mSubText != null) {
1548                 contentView.setTextViewText(R.id.text, mSubText);
1549                 if (mContentText != null) {
1550                     contentView.setTextViewText(R.id.text2, mContentText);
1551                     contentView.setViewVisibility(R.id.text2, View.VISIBLE);
1552                     showLine2 = true;
1553                 } else {
1554                     contentView.setViewVisibility(R.id.text2, View.GONE);
1555                 }
1556             } else {
1557                 contentView.setViewVisibility(R.id.text2, View.GONE);
1558                 if (mProgressMax != 0 || mProgressIndeterminate) {
1559                     contentView.setProgressBar(
1560                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
1561                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
1562                     showLine2 = true;
1563                 } else {
1564                     contentView.setViewVisibility(R.id.progress, View.GONE);
1565                 }
1566             }
1567             if (showLine2) {
1568                 if (fitIn1U) {
1569                     // need to shrink all the type to make sure everything fits
1570                     final Resources res = mContext.getResources();
1571                     final float subTextSize = res.getDimensionPixelSize(
1572                             R.dimen.notification_subtext_size);
1573                     contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
1574                 }
1575                 // vertical centering
1576                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
1577             }
1578 
1579             if (mWhen != 0 && mShowWhen) {
1580                 if (mUseChronometer) {
1581                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
1582                     contentView.setLong(R.id.chronometer, "setBase",
1583                             mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
1584                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
1585                 } else {
1586                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
1587                     contentView.setLong(R.id.time, "setTime", mWhen);
1588                 }
1589             } else {
1590                 contentView.setViewVisibility(R.id.time, View.GONE);
1591             }
1592 
1593             contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
1594             contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
1595             return contentView;
1596         }
1597 
applyStandardTemplateWithActions(int layoutId)1598         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
1599             RemoteViews big = applyStandardTemplate(layoutId, false);
1600 
1601             int N = mActions.size();
1602             if (N > 0) {
1603                 // Log.d("Notification", "has actions: " + mContentText);
1604                 big.setViewVisibility(R.id.actions, View.VISIBLE);
1605                 big.setViewVisibility(R.id.action_divider, View.VISIBLE);
1606                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
1607                 big.removeAllViews(R.id.actions);
1608                 for (int i=0; i<N; i++) {
1609                     final RemoteViews button = generateActionButton(mActions.get(i));
1610                     //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
1611                     big.addView(R.id.actions, button);
1612                 }
1613             }
1614             return big;
1615         }
1616 
makeContentView()1617         private RemoteViews makeContentView() {
1618             if (mContentView != null) {
1619                 return mContentView;
1620             } else {
1621                 return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor
1622             }
1623         }
1624 
makeTickerView()1625         private RemoteViews makeTickerView() {
1626             if (mTickerView != null) {
1627                 return mTickerView;
1628             } else {
1629                 if (mContentView == null) {
1630                     return applyStandardTemplate(mLargeIcon == null
1631                             ? R.layout.status_bar_latest_event_ticker
1632                             : R.layout.status_bar_latest_event_ticker_large_icon, true);
1633                 } else {
1634                     return null;
1635                 }
1636             }
1637         }
1638 
makeBigContentView()1639         private RemoteViews makeBigContentView() {
1640             if (mActions.size() == 0) return null;
1641 
1642             return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
1643         }
1644 
generateActionButton(Action action)1645         private RemoteViews generateActionButton(Action action) {
1646             final boolean tombstone = (action.actionIntent == null);
1647             RemoteViews button = new RemoteViews(mContext.getPackageName(),
1648                     tombstone ? R.layout.notification_action_tombstone
1649                               : R.layout.notification_action);
1650             button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0);
1651             button.setTextViewText(R.id.action0, action.title);
1652             if (!tombstone) {
1653                 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
1654             }
1655             button.setContentDescription(R.id.action0, action.title);
1656             return button;
1657         }
1658 
1659         /**
1660          * Apply the unstyled operations and return a new {@link Notification} object.
1661          */
buildUnstyled()1662         private Notification buildUnstyled() {
1663             Notification n = new Notification();
1664             n.when = mWhen;
1665             n.icon = mSmallIcon;
1666             n.iconLevel = mSmallIconLevel;
1667             n.number = mNumber;
1668             n.contentView = makeContentView();
1669             n.contentIntent = mContentIntent;
1670             n.deleteIntent = mDeleteIntent;
1671             n.fullScreenIntent = mFullScreenIntent;
1672             n.tickerText = mTickerText;
1673             n.tickerView = makeTickerView();
1674             n.largeIcon = mLargeIcon;
1675             n.sound = mSound;
1676             n.audioStreamType = mAudioStreamType;
1677             n.vibrate = mVibrate;
1678             n.ledARGB = mLedArgb;
1679             n.ledOnMS = mLedOnMs;
1680             n.ledOffMS = mLedOffMs;
1681             n.defaults = mDefaults;
1682             n.flags = mFlags;
1683             n.bigContentView = makeBigContentView();
1684             if (mLedOnMs != 0 || mLedOffMs != 0) {
1685                 n.flags |= FLAG_SHOW_LIGHTS;
1686             }
1687             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
1688                 n.flags |= FLAG_SHOW_LIGHTS;
1689             }
1690             if (mKindList.size() > 0) {
1691                 n.kind = new String[mKindList.size()];
1692                 mKindList.toArray(n.kind);
1693             } else {
1694                 n.kind = null;
1695             }
1696             n.priority = mPriority;
1697             if (mActions.size() > 0) {
1698                 n.actions = new Action[mActions.size()];
1699                 mActions.toArray(n.actions);
1700             }
1701 
1702             return n;
1703         }
1704 
1705         /**
1706          * Capture, in the provided bundle, semantic information used in the construction of
1707          * this Notification object.
1708          * @hide
1709          */
addExtras(Bundle extras)1710         public void addExtras(Bundle extras) {
1711             // Store original information used in the construction of this object
1712             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
1713             extras.putCharSequence(EXTRA_TEXT, mContentText);
1714             extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
1715             extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
1716             extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
1717             extras.putInt(EXTRA_PROGRESS, mProgress);
1718             extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
1719             extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
1720             extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
1721             extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
1722             if (mLargeIcon != null) {
1723                 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
1724             }
1725         }
1726 
1727         /**
1728          * @deprecated Use {@link #build()} instead.
1729          */
1730         @Deprecated
getNotification()1731         public Notification getNotification() {
1732             return build();
1733         }
1734 
1735         /**
1736          * Combine all of the options that have been set and return a new {@link Notification}
1737          * object.
1738          */
build()1739         public Notification build() {
1740             final Notification n;
1741 
1742             if (mStyle != null) {
1743                 n = mStyle.build();
1744             } else {
1745                 n = buildUnstyled();
1746             }
1747 
1748             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
1749 
1750             addExtras(n.extras);
1751             if (mStyle != null) {
1752                 mStyle.addExtras(n.extras);
1753             }
1754 
1755             return n;
1756         }
1757 
1758         /**
1759          * Apply this Builder to an existing {@link Notification} object.
1760          *
1761          * @hide
1762          */
buildInto(Notification n)1763         public Notification buildInto(Notification n) {
1764             build().cloneInto(n, true);
1765             return n;
1766         }
1767     }
1768 
1769     /**
1770      * An object that can apply a rich notification style to a {@link Notification.Builder}
1771      * object.
1772      */
1773     public static abstract class Style
1774     {
1775         private CharSequence mBigContentTitle;
1776         private CharSequence mSummaryText = null;
1777         private boolean mSummaryTextSet = false;
1778 
1779         protected Builder mBuilder;
1780 
1781         /**
1782          * Overrides ContentTitle in the big form of the template.
1783          * This defaults to the value passed to setContentTitle().
1784          */
internalSetBigContentTitle(CharSequence title)1785         protected void internalSetBigContentTitle(CharSequence title) {
1786             mBigContentTitle = title;
1787         }
1788 
1789         /**
1790          * Set the first line of text after the detail section in the big form of the template.
1791          */
internalSetSummaryText(CharSequence cs)1792         protected void internalSetSummaryText(CharSequence cs) {
1793             mSummaryText = cs;
1794             mSummaryTextSet = true;
1795         }
1796 
setBuilder(Builder builder)1797         public void setBuilder(Builder builder) {
1798             if (mBuilder != builder) {
1799                 mBuilder = builder;
1800                 if (mBuilder != null) {
1801                     mBuilder.setStyle(this);
1802                 }
1803             }
1804         }
1805 
checkBuilder()1806         protected void checkBuilder() {
1807             if (mBuilder == null) {
1808                 throw new IllegalArgumentException("Style requires a valid Builder object");
1809             }
1810         }
1811 
getStandardView(int layoutId)1812         protected RemoteViews getStandardView(int layoutId) {
1813             checkBuilder();
1814 
1815             if (mBigContentTitle != null) {
1816                 mBuilder.setContentTitle(mBigContentTitle);
1817             }
1818 
1819             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
1820 
1821             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
1822                 contentView.setViewVisibility(R.id.line1, View.GONE);
1823             } else {
1824                 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
1825             }
1826 
1827             // The last line defaults to the subtext, but can be replaced by mSummaryText
1828             final CharSequence overflowText =
1829                     mSummaryTextSet ? mSummaryText
1830                                     : mBuilder.mSubText;
1831             if (overflowText != null) {
1832                 contentView.setTextViewText(R.id.text, overflowText);
1833                 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
1834                 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
1835             } else {
1836                 contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
1837                 contentView.setViewVisibility(R.id.line3, View.GONE);
1838             }
1839 
1840             return contentView;
1841         }
1842 
1843         /**
1844          * @hide
1845          */
addExtras(Bundle extras)1846         public void addExtras(Bundle extras) {
1847             if (mSummaryTextSet) {
1848                 extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
1849             }
1850             if (mBigContentTitle != null) {
1851                 extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
1852             }
1853         }
1854 
build()1855         public abstract Notification build();
1856     }
1857 
1858     /**
1859      * Helper class for generating large-format notifications that include a large image attachment.
1860      *
1861      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
1862      * <pre class="prettyprint">
1863      * Notification noti = new Notification.BigPictureStyle(
1864      *      new Notification.Builder()
1865      *         .setContentTitle(&quot;New photo from &quot; + sender.toString())
1866      *         .setContentText(subject)
1867      *         .setSmallIcon(R.drawable.new_post)
1868      *         .setLargeIcon(aBitmap))
1869      *      .bigPicture(aBigBitmap)
1870      *      .build();
1871      * </pre>
1872      *
1873      * @see Notification#bigContentView
1874      */
1875     public static class BigPictureStyle extends Style {
1876         private Bitmap mPicture;
1877         private Bitmap mBigLargeIcon;
1878         private boolean mBigLargeIconSet = false;
1879 
BigPictureStyle()1880         public BigPictureStyle() {
1881         }
1882 
BigPictureStyle(Builder builder)1883         public BigPictureStyle(Builder builder) {
1884             setBuilder(builder);
1885         }
1886 
1887         /**
1888          * Overrides ContentTitle in the big form of the template.
1889          * This defaults to the value passed to setContentTitle().
1890          */
setBigContentTitle(CharSequence title)1891         public BigPictureStyle setBigContentTitle(CharSequence title) {
1892             internalSetBigContentTitle(safeCharSequence(title));
1893             return this;
1894         }
1895 
1896         /**
1897          * Set the first line of text after the detail section in the big form of the template.
1898          */
setSummaryText(CharSequence cs)1899         public BigPictureStyle setSummaryText(CharSequence cs) {
1900             internalSetSummaryText(safeCharSequence(cs));
1901             return this;
1902         }
1903 
1904         /**
1905          * Provide the bitmap to be used as the payload for the BigPicture notification.
1906          */
bigPicture(Bitmap b)1907         public BigPictureStyle bigPicture(Bitmap b) {
1908             mPicture = b;
1909             return this;
1910         }
1911 
1912         /**
1913          * Override the large icon when the big notification is shown.
1914          */
bigLargeIcon(Bitmap b)1915         public BigPictureStyle bigLargeIcon(Bitmap b) {
1916             mBigLargeIconSet = true;
1917             mBigLargeIcon = b;
1918             return this;
1919         }
1920 
makeBigContentView()1921         private RemoteViews makeBigContentView() {
1922             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
1923 
1924             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
1925 
1926             return contentView;
1927         }
1928 
1929         /**
1930          * @hide
1931          */
addExtras(Bundle extras)1932         public void addExtras(Bundle extras) {
1933             super.addExtras(extras);
1934 
1935             if (mBigLargeIconSet) {
1936                 extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
1937             }
1938             extras.putParcelable(EXTRA_PICTURE, mPicture);
1939         }
1940 
1941         @Override
build()1942         public Notification build() {
1943             checkBuilder();
1944             Notification wip = mBuilder.buildUnstyled();
1945             if (mBigLargeIconSet ) {
1946                 mBuilder.mLargeIcon = mBigLargeIcon;
1947             }
1948             wip.bigContentView = makeBigContentView();
1949             return wip;
1950         }
1951     }
1952 
1953     /**
1954      * Helper class for generating large-format notifications that include a lot of text.
1955      *
1956      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
1957      * <pre class="prettyprint">
1958      * Notification noti = new Notification.BigTextStyle(
1959      *      new Notification.Builder()
1960      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
1961      *         .setContentText(subject)
1962      *         .setSmallIcon(R.drawable.new_mail)
1963      *         .setLargeIcon(aBitmap))
1964      *      .bigText(aVeryLongString)
1965      *      .build();
1966      * </pre>
1967      *
1968      * @see Notification#bigContentView
1969      */
1970     public static class BigTextStyle extends Style {
1971         private CharSequence mBigText;
1972 
BigTextStyle()1973         public BigTextStyle() {
1974         }
1975 
BigTextStyle(Builder builder)1976         public BigTextStyle(Builder builder) {
1977             setBuilder(builder);
1978         }
1979 
1980         /**
1981          * Overrides ContentTitle in the big form of the template.
1982          * This defaults to the value passed to setContentTitle().
1983          */
setBigContentTitle(CharSequence title)1984         public BigTextStyle setBigContentTitle(CharSequence title) {
1985             internalSetBigContentTitle(safeCharSequence(title));
1986             return this;
1987         }
1988 
1989         /**
1990          * Set the first line of text after the detail section in the big form of the template.
1991          */
setSummaryText(CharSequence cs)1992         public BigTextStyle setSummaryText(CharSequence cs) {
1993             internalSetSummaryText(safeCharSequence(cs));
1994             return this;
1995         }
1996 
1997         /**
1998          * Provide the longer text to be displayed in the big form of the
1999          * template in place of the content text.
2000          */
bigText(CharSequence cs)2001         public BigTextStyle bigText(CharSequence cs) {
2002             mBigText = safeCharSequence(cs);
2003             return this;
2004         }
2005 
2006         /**
2007          * @hide
2008          */
addExtras(Bundle extras)2009         public void addExtras(Bundle extras) {
2010             super.addExtras(extras);
2011 
2012             extras.putCharSequence(EXTRA_TEXT, mBigText);
2013         }
2014 
makeBigContentView()2015         private RemoteViews makeBigContentView() {
2016             // Remove the content text so line3 only shows if you have a summary
2017             final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
2018             mBuilder.mContentText = null;
2019 
2020             RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
2021 
2022             if (hadThreeLines) {
2023                 // vertical centering
2024                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
2025             }
2026 
2027             contentView.setTextViewText(R.id.big_text, mBigText);
2028             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
2029             contentView.setViewVisibility(R.id.text2, View.GONE);
2030 
2031             return contentView;
2032         }
2033 
2034         @Override
build()2035         public Notification build() {
2036             checkBuilder();
2037             Notification wip = mBuilder.buildUnstyled();
2038             wip.bigContentView = makeBigContentView();
2039 
2040             wip.extras.putCharSequence(EXTRA_TEXT, mBigText);
2041 
2042             return wip;
2043         }
2044     }
2045 
2046     /**
2047      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
2048      *
2049      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
2050      * <pre class="prettyprint">
2051      * Notification noti = new Notification.InboxStyle(
2052      *      new Notification.Builder()
2053      *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
2054      *         .setContentText(subject)
2055      *         .setSmallIcon(R.drawable.new_mail)
2056      *         .setLargeIcon(aBitmap))
2057      *      .addLine(str1)
2058      *      .addLine(str2)
2059      *      .setContentTitle("")
2060      *      .setSummaryText(&quot;+3 more&quot;)
2061      *      .build();
2062      * </pre>
2063      *
2064      * @see Notification#bigContentView
2065      */
2066     public static class InboxStyle extends Style {
2067         private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
2068 
InboxStyle()2069         public InboxStyle() {
2070         }
2071 
InboxStyle(Builder builder)2072         public InboxStyle(Builder builder) {
2073             setBuilder(builder);
2074         }
2075 
2076         /**
2077          * Overrides ContentTitle in the big form of the template.
2078          * This defaults to the value passed to setContentTitle().
2079          */
setBigContentTitle(CharSequence title)2080         public InboxStyle setBigContentTitle(CharSequence title) {
2081             internalSetBigContentTitle(safeCharSequence(title));
2082             return this;
2083         }
2084 
2085         /**
2086          * Set the first line of text after the detail section in the big form of the template.
2087          */
setSummaryText(CharSequence cs)2088         public InboxStyle setSummaryText(CharSequence cs) {
2089             internalSetSummaryText(safeCharSequence(cs));
2090             return this;
2091         }
2092 
2093         /**
2094          * Append a line to the digest section of the Inbox notification.
2095          */
addLine(CharSequence cs)2096         public InboxStyle addLine(CharSequence cs) {
2097             mTexts.add(safeCharSequence(cs));
2098             return this;
2099         }
2100 
2101         /**
2102          * @hide
2103          */
addExtras(Bundle extras)2104         public void addExtras(Bundle extras) {
2105             super.addExtras(extras);
2106             CharSequence[] a = new CharSequence[mTexts.size()];
2107             extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
2108         }
2109 
makeBigContentView()2110         private RemoteViews makeBigContentView() {
2111             // Remove the content text so line3 disappears unless you have a summary
2112             mBuilder.mContentText = null;
2113             RemoteViews contentView = getStandardView(R.layout.notification_template_inbox);
2114 
2115             contentView.setViewVisibility(R.id.text2, View.GONE);
2116 
2117             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
2118                     R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
2119 
2120             // Make sure all rows are gone in case we reuse a view.
2121             for (int rowId : rowIds) {
2122                 contentView.setViewVisibility(rowId, View.GONE);
2123             }
2124 
2125 
2126             int i=0;
2127             while (i < mTexts.size() && i < rowIds.length) {
2128                 CharSequence str = mTexts.get(i);
2129                 if (str != null && !str.equals("")) {
2130                     contentView.setViewVisibility(rowIds[i], View.VISIBLE);
2131                     contentView.setTextViewText(rowIds[i], str);
2132                 }
2133                 i++;
2134             }
2135 
2136             contentView.setViewVisibility(R.id.inbox_end_pad,
2137                     mTexts.size() > 0 ? View.VISIBLE : View.GONE);
2138 
2139             contentView.setViewVisibility(R.id.inbox_more,
2140                     mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE);
2141 
2142             return contentView;
2143         }
2144 
2145         @Override
build()2146         public Notification build() {
2147             checkBuilder();
2148             Notification wip = mBuilder.buildUnstyled();
2149             wip.bigContentView = makeBigContentView();
2150 
2151             return wip;
2152         }
2153     }
2154 }
2155