• 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.graphics.Bitmap;
24 import android.net.Uri;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.text.TextUtils;
28 import android.view.View;
29 import android.widget.ProgressBar;
30 import android.widget.RemoteViews;
31 
32 import java.text.NumberFormat;
33 
34 /**
35  * A class that represents how a persistent notification is to be presented to
36  * the user using the {@link android.app.NotificationManager}.
37  *
38  * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
39  * easier to construct Notifications.</p>
40  *
41  * <div class="special reference">
42  * <h3>Developer Guides</h3>
43  * <p>For a guide to creating notifications, read the
44  * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
45  * developer guide.</p>
46  * </div>
47  */
48 public class Notification implements Parcelable
49 {
50     /**
51      * Use all default values (where applicable).
52      */
53     public static final int DEFAULT_ALL = ~0;
54 
55     /**
56      * Use the default notification sound. This will ignore any given
57      * {@link #sound}.
58      *
59      * @see #defaults
60      */
61     public static final int DEFAULT_SOUND = 1;
62 
63     /**
64      * Use the default notification vibrate. This will ignore any given
65      * {@link #vibrate}. Using phone vibration requires the
66      * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
67      *
68      * @see #defaults
69      */
70     public static final int DEFAULT_VIBRATE = 2;
71 
72     /**
73      * Use the default notification lights. This will ignore the
74      * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
75      * {@link #ledOnMS}.
76      *
77      * @see #defaults
78      */
79     public static final int DEFAULT_LIGHTS = 4;
80 
81     /**
82      * The timestamp for the notification.  The icons and expanded views
83      * are sorted by this key.
84      */
85     public long when;
86 
87     /**
88      * The resource id of a drawable to use as the icon in the status bar.
89      * This is required; notifications with an invalid icon resource will not be shown.
90      */
91     public int icon;
92 
93     /**
94      * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
95      * leave it at its default value of 0.
96      *
97      * @see android.widget.ImageView#setImageLevel
98      * @see android.graphics.drawable#setLevel
99      */
100     public int iconLevel;
101 
102     /**
103      * The number of events that this notification represents.  For example, in a new mail
104      * notification, this could be the number of unread messages.  This number is superimposed over
105      * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status
106      * bar.
107      */
108     public int number;
109 
110     /**
111      * The intent to execute when the expanded status entry is clicked.  If
112      * this is an activity, it must include the
113      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
114      * that you take care of task management as described in the
115      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
116      * Stack</a> document.
117      */
118     public PendingIntent contentIntent;
119 
120     /**
121      * The intent to execute when the status entry is deleted by the user
122      * with the "Clear All Notifications" button. This probably shouldn't
123      * be launching an activity since several of those will be sent at the
124      * same time.
125      */
126     public PendingIntent deleteIntent;
127 
128     /**
129      * An intent to launch instead of posting the notification to the status bar.
130      *
131      * @see Notification.Builder#setFullScreenIntent
132      */
133     public PendingIntent fullScreenIntent;
134 
135     /**
136      * Text to scroll across the screen when this item is added to
137      * the status bar on large and smaller devices.
138      *
139      * <p>This field is provided separately from the other ticker fields
140      * both for compatibility and to allow an application to choose different
141      * text for when the text scrolls in and when it is displayed all at once
142      * in conjunction with one or more icons.
143      *
144      * @see #tickerView
145      */
146     public CharSequence tickerText;
147 
148     /**
149      * The view to show as the ticker in the status bar when the notification
150      * is posted.
151      */
152     public RemoteViews tickerView;
153 
154     /**
155      * The view that will represent this notification in the expanded status bar.
156      */
157     public RemoteViews contentView;
158 
159     /**
160      * The bitmap that may escape the bounds of the panel and bar.
161      */
162     public Bitmap largeIcon;
163 
164     /**
165      * The sound to play.
166      *
167      * <p>
168      * To play the default notification sound, see {@link #defaults}.
169      * </p>
170      */
171     public Uri sound;
172 
173     /**
174      * Use this constant as the value for audioStreamType to request that
175      * the default stream type for notifications be used.  Currently the
176      * default stream type is STREAM_RING.
177      */
178     public static final int STREAM_DEFAULT = -1;
179 
180     /**
181      * The audio stream type to use when playing the sound.
182      * Should be one of the STREAM_ constants from
183      * {@link android.media.AudioManager}.
184      */
185     public int audioStreamType = STREAM_DEFAULT;
186 
187 
188     /**
189      * The pattern with which to vibrate.
190      *
191      * <p>
192      * To vibrate the default pattern, see {@link #defaults}.
193      * </p>
194      *
195      * @see android.os.Vibrator#vibrate(long[],int)
196      */
197     public long[] vibrate;
198 
199     /**
200      * The color of the led.  The hardware will do its best approximation.
201      *
202      * @see #FLAG_SHOW_LIGHTS
203      * @see #flags
204      */
205     public int ledARGB;
206 
207     /**
208      * The number of milliseconds for the LED to be on while it's flashing.
209      * The hardware will do its best approximation.
210      *
211      * @see #FLAG_SHOW_LIGHTS
212      * @see #flags
213      */
214     public int ledOnMS;
215 
216     /**
217      * The number of milliseconds for the LED to be off while it's flashing.
218      * The hardware will do its best approximation.
219      *
220      * @see #FLAG_SHOW_LIGHTS
221      * @see #flags
222      */
223     public int ledOffMS;
224 
225     /**
226      * Specifies which values should be taken from the defaults.
227      * <p>
228      * To set, OR the desired from {@link #DEFAULT_SOUND},
229      * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
230      * values, use {@link #DEFAULT_ALL}.
231      * </p>
232      */
233     public int defaults;
234 
235 
236     /**
237      * Bit to be bitwise-ored into the {@link #flags} field that should be
238      * set if you want the LED on for this notification.
239      * <ul>
240      * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
241      *      or 0 for both ledOnMS and ledOffMS.</li>
242      * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
243      * <li>To flash the LED, pass the number of milliseconds that it should
244      *      be on and off to ledOnMS and ledOffMS.</li>
245      * </ul>
246      * <p>
247      * Since hardware varies, you are not guaranteed that any of the values
248      * you pass are honored exactly.  Use the system defaults (TODO) if possible
249      * because they will be set to values that work on any given hardware.
250      * <p>
251      * The alpha channel must be set for forward compatibility.
252      *
253      */
254     public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
255 
256     /**
257      * Bit to be bitwise-ored into the {@link #flags} field that should be
258      * set if this notification is in reference to something that is ongoing,
259      * like a phone call.  It should not be set if this notification is in
260      * reference to something that happened at a particular point in time,
261      * like a missed phone call.
262      */
263     public static final int FLAG_ONGOING_EVENT      = 0x00000002;
264 
265     /**
266      * Bit to be bitwise-ored into the {@link #flags} field that if set,
267      * the audio will be repeated until the notification is
268      * cancelled or the notification window is opened.
269      */
270     public static final int FLAG_INSISTENT          = 0x00000004;
271 
272     /**
273      * Bit to be bitwise-ored into the {@link #flags} field that should be
274      * set if you want the sound and/or vibration play each time the
275      * notification is sent, even if it has not been canceled before that.
276      */
277     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
278 
279     /**
280      * Bit to be bitwise-ored into the {@link #flags} field that should be
281      * set if the notification should be canceled when it is clicked by the
282      * user.  On tablets, the
283      */
284     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
285 
286     /**
287      * Bit to be bitwise-ored into the {@link #flags} field that should be
288      * set if the notification should not be canceled when the user clicks
289      * the Clear all button.
290      */
291     public static final int FLAG_NO_CLEAR           = 0x00000020;
292 
293     /**
294      * Bit to be bitwise-ored into the {@link #flags} field that should be
295      * set if this notification represents a currently running service.  This
296      * will normally be set for you by {@link Service#startForeground}.
297      */
298     public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
299 
300     /**
301      * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification
302      * represents a high-priority event that may be shown to the user even if notifications are
303      * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used
304      * in conjunction with {@link #fullScreenIntent}.
305      */
306     public static final int FLAG_HIGH_PRIORITY = 0x00000080;
307 
308     public int flags;
309 
310     /**
311      * Constructs a Notification object with everything set to 0.
312      * You might want to consider using {@link Builder} instead.
313      */
Notification()314     public Notification()
315     {
316         this.when = System.currentTimeMillis();
317     }
318 
319     /**
320      * @hide
321      */
Notification(Context context, int icon, CharSequence tickerText, long when, CharSequence contentTitle, CharSequence contentText, Intent contentIntent)322     public Notification(Context context, int icon, CharSequence tickerText, long when,
323             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
324     {
325         this.when = when;
326         this.icon = icon;
327         this.tickerText = tickerText;
328         setLatestEventInfo(context, contentTitle, contentText,
329                 PendingIntent.getActivity(context, 0, contentIntent, 0));
330     }
331 
332     /**
333      * Constructs a Notification object with the information needed to
334      * have a status bar icon without the standard expanded view.
335      *
336      * @param icon          The resource id of the icon to put in the status bar.
337      * @param tickerText    The text that flows by in the status bar when the notification first
338      *                      activates.
339      * @param when          The time to show in the time field.  In the System.currentTimeMillis
340      *                      timebase.
341      *
342      * @deprecated Use {@link Builder} instead.
343      */
344     @Deprecated
Notification(int icon, CharSequence tickerText, long when)345     public Notification(int icon, CharSequence tickerText, long when)
346     {
347         this.icon = icon;
348         this.tickerText = tickerText;
349         this.when = when;
350     }
351 
352     /**
353      * Unflatten the notification from a parcel.
354      */
Notification(Parcel parcel)355     public Notification(Parcel parcel)
356     {
357         int version = parcel.readInt();
358 
359         when = parcel.readLong();
360         icon = parcel.readInt();
361         number = parcel.readInt();
362         if (parcel.readInt() != 0) {
363             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
364         }
365         if (parcel.readInt() != 0) {
366             deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
367         }
368         if (parcel.readInt() != 0) {
369             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
370         }
371         if (parcel.readInt() != 0) {
372             tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
373         }
374         if (parcel.readInt() != 0) {
375             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
376         }
377         if (parcel.readInt() != 0) {
378             largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
379         }
380         defaults = parcel.readInt();
381         flags = parcel.readInt();
382         if (parcel.readInt() != 0) {
383             sound = Uri.CREATOR.createFromParcel(parcel);
384         }
385 
386         audioStreamType = parcel.readInt();
387         vibrate = parcel.createLongArray();
388         ledARGB = parcel.readInt();
389         ledOnMS = parcel.readInt();
390         ledOffMS = parcel.readInt();
391         iconLevel = parcel.readInt();
392 
393         if (parcel.readInt() != 0) {
394             fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
395         }
396     }
397 
398     @Override
clone()399     public Notification clone() {
400         Notification that = new Notification();
401 
402         that.when = this.when;
403         that.icon = this.icon;
404         that.number = this.number;
405 
406         // PendingIntents are global, so there's no reason (or way) to clone them.
407         that.contentIntent = this.contentIntent;
408         that.deleteIntent = this.deleteIntent;
409         that.fullScreenIntent = this.fullScreenIntent;
410 
411         if (this.tickerText != null) {
412             that.tickerText = this.tickerText.toString();
413         }
414         if (this.tickerView != null) {
415             that.tickerView = this.tickerView.clone();
416         }
417         if (this.contentView != null) {
418             that.contentView = this.contentView.clone();
419         }
420         if (this.largeIcon != null) {
421             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
422         }
423         that.iconLevel = this.iconLevel;
424         that.sound = this.sound; // android.net.Uri is immutable
425         that.audioStreamType = this.audioStreamType;
426 
427         final long[] vibrate = this.vibrate;
428         if (vibrate != null) {
429             final int N = vibrate.length;
430             final long[] vib = that.vibrate = new long[N];
431             System.arraycopy(vibrate, 0, vib, 0, N);
432         }
433 
434         that.ledARGB = this.ledARGB;
435         that.ledOnMS = this.ledOnMS;
436         that.ledOffMS = this.ledOffMS;
437         that.defaults = this.defaults;
438 
439         that.flags = this.flags;
440 
441         return that;
442     }
443 
describeContents()444     public int describeContents() {
445         return 0;
446     }
447 
448     /**
449      * Flatten this notification from a parcel.
450      */
writeToParcel(Parcel parcel, int flags)451     public void writeToParcel(Parcel parcel, int flags)
452     {
453         parcel.writeInt(1);
454 
455         parcel.writeLong(when);
456         parcel.writeInt(icon);
457         parcel.writeInt(number);
458         if (contentIntent != null) {
459             parcel.writeInt(1);
460             contentIntent.writeToParcel(parcel, 0);
461         } else {
462             parcel.writeInt(0);
463         }
464         if (deleteIntent != null) {
465             parcel.writeInt(1);
466             deleteIntent.writeToParcel(parcel, 0);
467         } else {
468             parcel.writeInt(0);
469         }
470         if (tickerText != null) {
471             parcel.writeInt(1);
472             TextUtils.writeToParcel(tickerText, parcel, flags);
473         } else {
474             parcel.writeInt(0);
475         }
476         if (tickerView != null) {
477             parcel.writeInt(1);
478             tickerView.writeToParcel(parcel, 0);
479         } else {
480             parcel.writeInt(0);
481         }
482         if (contentView != null) {
483             parcel.writeInt(1);
484             contentView.writeToParcel(parcel, 0);
485         } else {
486             parcel.writeInt(0);
487         }
488         if (largeIcon != null) {
489             parcel.writeInt(1);
490             largeIcon.writeToParcel(parcel, 0);
491         } else {
492             parcel.writeInt(0);
493         }
494 
495         parcel.writeInt(defaults);
496         parcel.writeInt(this.flags);
497 
498         if (sound != null) {
499             parcel.writeInt(1);
500             sound.writeToParcel(parcel, 0);
501         } else {
502             parcel.writeInt(0);
503         }
504         parcel.writeInt(audioStreamType);
505         parcel.writeLongArray(vibrate);
506         parcel.writeInt(ledARGB);
507         parcel.writeInt(ledOnMS);
508         parcel.writeInt(ledOffMS);
509         parcel.writeInt(iconLevel);
510 
511         if (fullScreenIntent != null) {
512             parcel.writeInt(1);
513             fullScreenIntent.writeToParcel(parcel, 0);
514         } else {
515             parcel.writeInt(0);
516         }
517     }
518 
519     /**
520      * Parcelable.Creator that instantiates Notification objects
521      */
522     public static final Parcelable.Creator<Notification> CREATOR
523             = new Parcelable.Creator<Notification>()
524     {
525         public Notification createFromParcel(Parcel parcel)
526         {
527             return new Notification(parcel);
528         }
529 
530         public Notification[] newArray(int size)
531         {
532             return new Notification[size];
533         }
534     };
535 
536     /**
537      * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
538      * layout.
539      *
540      * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
541      * in the view.</p>
542      * @param context       The context for your application / activity.
543      * @param contentTitle The title that goes in the expanded entry.
544      * @param contentText  The text that goes in the expanded entry.
545      * @param contentIntent The intent to launch when the user clicks the expanded notification.
546      * If this is an activity, it must include the
547      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
548      * that you take care of task management as described in the
549      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
550      * Stack</a> document.
551      *
552      * @deprecated Use {@link Builder} instead.
553      */
554     @Deprecated
setLatestEventInfo(Context context, CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent)555     public void setLatestEventInfo(Context context,
556             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
557         RemoteViews contentView = new RemoteViews(context.getPackageName(),
558                 R.layout.status_bar_latest_event_content);
559         if (this.icon != 0) {
560             contentView.setImageViewResource(R.id.icon, this.icon);
561         }
562         if (contentTitle != null) {
563             contentView.setTextViewText(R.id.title, contentTitle);
564         }
565         if (contentText != null) {
566             contentView.setTextViewText(R.id.text, contentText);
567         }
568         if (this.when != 0) {
569             contentView.setLong(R.id.time, "setTime", when);
570         }
571 
572         this.contentView = contentView;
573         this.contentIntent = contentIntent;
574     }
575 
576     @Override
toString()577     public String toString() {
578         StringBuilder sb = new StringBuilder();
579         sb.append("Notification(contentView=");
580         if (contentView != null) {
581             sb.append(contentView.getPackage());
582             sb.append("/0x");
583             sb.append(Integer.toHexString(contentView.getLayoutId()));
584         } else {
585             sb.append("null");
586         }
587         sb.append(" vibrate=");
588         if (this.vibrate != null) {
589             int N = this.vibrate.length-1;
590             sb.append("[");
591             for (int i=0; i<N; i++) {
592                 sb.append(this.vibrate[i]);
593                 sb.append(',');
594             }
595             if (N != -1) {
596                 sb.append(this.vibrate[N]);
597             }
598             sb.append("]");
599         } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
600             sb.append("default");
601         } else {
602             sb.append("null");
603         }
604         sb.append(",sound=");
605         if (this.sound != null) {
606             sb.append(this.sound.toString());
607         } else if ((this.defaults & DEFAULT_SOUND) != 0) {
608             sb.append("default");
609         } else {
610             sb.append("null");
611         }
612         sb.append(",defaults=0x");
613         sb.append(Integer.toHexString(this.defaults));
614         sb.append(",flags=0x");
615         sb.append(Integer.toHexString(this.flags));
616         if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
617             sb.append("!!!1!one!");
618         }
619         sb.append(")");
620         return sb.toString();
621     }
622 
623     /**
624      * Builder class for {@link Notification} objects.  Allows easier control over
625      * all the flags, as well as help constructing the typical notification layouts.
626      */
627     public static class Builder {
628         private Context mContext;
629 
630         private long mWhen;
631         private int mSmallIcon;
632         private int mSmallIconLevel;
633         private int mNumber;
634         private CharSequence mContentTitle;
635         private CharSequence mContentText;
636         private CharSequence mContentInfo;
637         private PendingIntent mContentIntent;
638         private RemoteViews mContentView;
639         private PendingIntent mDeleteIntent;
640         private PendingIntent mFullScreenIntent;
641         private CharSequence mTickerText;
642         private RemoteViews mTickerView;
643         private Bitmap mLargeIcon;
644         private Uri mSound;
645         private int mAudioStreamType;
646         private long[] mVibrate;
647         private int mLedArgb;
648         private int mLedOnMs;
649         private int mLedOffMs;
650         private int mDefaults;
651         private int mFlags;
652         private int mProgressMax;
653         private int mProgress;
654         private boolean mProgressIndeterminate;
655 
656         /**
657          * Constructor.
658          *
659          * Automatically sets the when field to {@link System#currentTimeMillis()
660          * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}.
661          *
662          * @param context A {@link Context} that will be used to construct the
663          *      RemoteViews. The Context will not be held past the lifetime of this
664          *      Builder object.
665          */
Builder(Context context)666         public Builder(Context context) {
667             mContext = context;
668 
669             // Set defaults to match the defaults of a Notification
670             mWhen = System.currentTimeMillis();
671             mAudioStreamType = STREAM_DEFAULT;
672         }
673 
674         /**
675          * Set the time that the event occurred.  Notifications in the panel are
676          * sorted by this time.
677          */
setWhen(long when)678         public Builder setWhen(long when) {
679             mWhen = when;
680             return this;
681         }
682 
683         /**
684          * Set the small icon to use in the notification layouts.  Different classes of devices
685          * may return different sizes.  See the UX guidelines for more information on how to
686          * design these icons.
687          *
688          * @param icon A resource ID in the application's package of the drawble to use.
689          */
setSmallIcon(int icon)690         public Builder setSmallIcon(int icon) {
691             mSmallIcon = icon;
692             return this;
693         }
694 
695         /**
696          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
697          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
698          * LevelListDrawable}.
699          *
700          * @param icon A resource ID in the application's package of the drawble to use.
701          * @param level The level to use for the icon.
702          *
703          * @see android.graphics.drawable.LevelListDrawable
704          */
setSmallIcon(int icon, int level)705         public Builder setSmallIcon(int icon, int level) {
706             mSmallIcon = icon;
707             mSmallIconLevel = level;
708             return this;
709         }
710 
711         /**
712          * Set the title (first row) of the notification, in a standard notification.
713          */
setContentTitle(CharSequence title)714         public Builder setContentTitle(CharSequence title) {
715             mContentTitle = title;
716             return this;
717         }
718 
719         /**
720          * Set the text (second row) of the notification, in a standard notification.
721          */
setContentText(CharSequence text)722         public Builder setContentText(CharSequence text) {
723             mContentText = text;
724             return this;
725         }
726 
727         /**
728          * Set the large number at the right-hand side of the notification.  This is
729          * equivalent to setContentInfo, although it might show the number in a different
730          * font size for readability.
731          */
setNumber(int number)732         public Builder setNumber(int number) {
733             mNumber = number;
734             return this;
735         }
736 
737         /**
738          * Set the large text at the right-hand side of the notification.
739          */
setContentInfo(CharSequence info)740         public Builder setContentInfo(CharSequence info) {
741             mContentInfo = info;
742             return this;
743         }
744 
745         /**
746          * Set the progress this notification represents, which may be
747          * represented as a {@link ProgressBar}.
748          */
setProgress(int max, int progress, boolean indeterminate)749         public Builder setProgress(int max, int progress, boolean indeterminate) {
750             mProgressMax = max;
751             mProgress = progress;
752             mProgressIndeterminate = indeterminate;
753             return this;
754         }
755 
756         /**
757          * Supply a custom RemoteViews to use instead of the standard one.
758          */
setContent(RemoteViews views)759         public Builder setContent(RemoteViews views) {
760             mContentView = views;
761             return this;
762         }
763 
764         /**
765          * Supply a {@link PendingIntent} to send when the notification is clicked.
766          * If you do not supply an intent, you can now add PendingIntents to individual
767          * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
768          * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
769          */
setContentIntent(PendingIntent intent)770         public Builder setContentIntent(PendingIntent intent) {
771             mContentIntent = intent;
772             return this;
773         }
774 
775         /**
776          * Supply a {@link PendingIntent} to send when the notification is cleared by the user
777          * directly from the notification panel.  For example, this intent is sent when the user
778          * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
779          * intent is not sent when the application calls {@link NotificationManager#cancel
780          * NotificationManager.cancel(int)}.
781          */
setDeleteIntent(PendingIntent intent)782         public Builder setDeleteIntent(PendingIntent intent) {
783             mDeleteIntent = intent;
784             return this;
785         }
786 
787         /**
788          * An intent to launch instead of posting the notification to the status bar.
789          * Only for use with extremely high-priority notifications demanding the user's
790          * <strong>immediate</strong> attention, such as an incoming phone call or
791          * alarm clock that the user has explicitly set to a particular time.
792          * If this facility is used for something else, please give the user an option
793          * to turn it off and use a normal notification, as this can be extremely
794          * disruptive.
795          *
796          * @param intent The pending intent to launch.
797          * @param highPriority Passing true will cause this notification to be sent
798          *          even if other notifications are suppressed.
799          */
setFullScreenIntent(PendingIntent intent, boolean highPriority)800         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
801             mFullScreenIntent = intent;
802             setFlag(FLAG_HIGH_PRIORITY, highPriority);
803             return this;
804         }
805 
806         /**
807          * Set the text that is displayed in the status bar when the notification first
808          * arrives.
809          */
setTicker(CharSequence tickerText)810         public Builder setTicker(CharSequence tickerText) {
811             mTickerText = tickerText;
812             return this;
813         }
814 
815         /**
816          * Set the text that is displayed in the status bar when the notification first
817          * arrives, and also a RemoteViews object that may be displayed instead on some
818          * devices.
819          */
setTicker(CharSequence tickerText, RemoteViews views)820         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
821             mTickerText = tickerText;
822             mTickerView = views;
823             return this;
824         }
825 
826         /**
827          * Set the large icon that is shown in the ticker and notification.
828          */
setLargeIcon(Bitmap icon)829         public Builder setLargeIcon(Bitmap icon) {
830             mLargeIcon = icon;
831             return this;
832         }
833 
834         /**
835          * Set the sound to play.  It will play on the default stream.
836          */
setSound(Uri sound)837         public Builder setSound(Uri sound) {
838             mSound = sound;
839             mAudioStreamType = STREAM_DEFAULT;
840             return this;
841         }
842 
843         /**
844          * Set the sound to play.  It will play on the stream you supply.
845          *
846          * @see #STREAM_DEFAULT
847          * @see AudioManager for the <code>STREAM_</code> constants.
848          */
setSound(Uri sound, int streamType)849         public Builder setSound(Uri sound, int streamType) {
850             mSound = sound;
851             mAudioStreamType = streamType;
852             return this;
853         }
854 
855         /**
856          * Set the vibration pattern to use.
857          *
858          * @see android.os.Vibrator for a discussion of the <code>pattern</code>
859          * parameter.
860          */
setVibrate(long[] pattern)861         public Builder setVibrate(long[] pattern) {
862             mVibrate = pattern;
863             return this;
864         }
865 
866         /**
867          * Set the argb value that you would like the LED on the device to blnk, as well as the
868          * rate.  The rate is specified in terms of the number of milliseconds to be on
869          * and then the number of milliseconds to be off.
870          */
setLights(int argb, int onMs, int offMs)871         public Builder setLights(int argb, int onMs, int offMs) {
872             mLedArgb = argb;
873             mLedOnMs = onMs;
874             mLedOffMs = offMs;
875             return this;
876         }
877 
878         /**
879          * Set whether this is an ongoing notification.
880          *
881          * <p>Ongoing notifications differ from regular notifications in the following ways:
882          * <ul>
883          *   <li>Ongoing notifications are sorted above the regular notifications in the
884          *   notification panel.</li>
885          *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
886          *   by the "Clear all" button.
887          * </ul>
888          */
setOngoing(boolean ongoing)889         public Builder setOngoing(boolean ongoing) {
890             setFlag(FLAG_ONGOING_EVENT, ongoing);
891             return this;
892         }
893 
894         /**
895          * Set this flag if you would only like the sound, vibrate
896          * and ticker to be played if the notification is not already showing.
897          */
setOnlyAlertOnce(boolean onlyAlertOnce)898         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
899             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
900             return this;
901         }
902 
903         /**
904          * Setting this flag will make it so the notification is automatically
905          * canceled when the user clicks it in the panel.  The PendingIntent
906          * set with {@link #setDeleteIntent} will be broadcast when the notification
907          * is canceled.
908          */
setAutoCancel(boolean autoCancel)909         public Builder setAutoCancel(boolean autoCancel) {
910             setFlag(FLAG_AUTO_CANCEL, autoCancel);
911             return this;
912         }
913 
914         /**
915          * Set the default notification options that will be used.
916          * <p>
917          * The value should be one or more of the following fields combined with
918          * bitwise-or:
919          * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
920          * <p>
921          * For all default values, use {@link #DEFAULT_ALL}.
922          */
setDefaults(int defaults)923         public Builder setDefaults(int defaults) {
924             mDefaults = defaults;
925             return this;
926         }
927 
setFlag(int mask, boolean value)928         private void setFlag(int mask, boolean value) {
929             if (value) {
930                 mFlags |= mask;
931             } else {
932                 mFlags &= ~mask;
933             }
934         }
935 
makeRemoteViews(int resId)936         private RemoteViews makeRemoteViews(int resId) {
937             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
938             boolean hasLine3 = false;
939             if (mSmallIcon != 0) {
940                 contentView.setImageViewResource(R.id.icon, mSmallIcon);
941                 contentView.setViewVisibility(R.id.icon, View.VISIBLE);
942             } else {
943                 contentView.setViewVisibility(R.id.icon, View.GONE);
944             }
945             if (mContentTitle != null) {
946                 contentView.setTextViewText(R.id.title, mContentTitle);
947             }
948             if (mContentText != null) {
949                 contentView.setTextViewText(R.id.text, mContentText);
950                 hasLine3 = true;
951             }
952             if (mContentInfo != null) {
953                 contentView.setTextViewText(R.id.info, mContentInfo);
954                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
955                 hasLine3 = true;
956             } else if (mNumber > 0) {
957                 final int tooBig = mContext.getResources().getInteger(
958                         R.integer.status_bar_notification_info_maxnum);
959                 if (mNumber > tooBig) {
960                     contentView.setTextViewText(R.id.info, mContext.getResources().getString(
961                                 R.string.status_bar_notification_info_overflow));
962                 } else {
963                     NumberFormat f = NumberFormat.getIntegerInstance();
964                     contentView.setTextViewText(R.id.info, f.format(mNumber));
965                 }
966                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
967                 hasLine3 = true;
968             } else {
969                 contentView.setViewVisibility(R.id.info, View.GONE);
970             }
971             if (mProgressMax != 0 || mProgressIndeterminate) {
972                 contentView.setProgressBar(
973                         R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
974                 contentView.setViewVisibility(R.id.progress, View.VISIBLE);
975             } else {
976                 contentView.setViewVisibility(R.id.progress, View.GONE);
977             }
978             if (mWhen != 0) {
979                 contentView.setLong(R.id.time, "setTime", mWhen);
980             }
981             contentView.setViewVisibility(R.id.line3, hasLine3 ? View.VISIBLE : View.GONE);
982             return contentView;
983         }
984 
makeContentView()985         private RemoteViews makeContentView() {
986             if (mContentView != null) {
987                 return mContentView;
988             } else {
989                     return makeRemoteViews(mLargeIcon == null
990                             ? R.layout.status_bar_latest_event_content
991                         : R.layout.status_bar_latest_event_content_large_icon);
992             }
993         }
994 
makeTickerView()995         private RemoteViews makeTickerView() {
996             if (mTickerView != null) {
997                 return mTickerView;
998             } else {
999                 if (mContentView == null) {
1000                     return makeRemoteViews(mLargeIcon == null
1001                             ? R.layout.status_bar_latest_event_ticker
1002                             : R.layout.status_bar_latest_event_ticker_large_icon);
1003                 } else {
1004                     return null;
1005                 }
1006             }
1007         }
1008 
1009         /**
1010          * Combine all of the options that have been set and return a new {@link Notification}
1011          * object.
1012          */
getNotification()1013         public Notification getNotification() {
1014             Notification n = new Notification();
1015             n.when = mWhen;
1016             n.icon = mSmallIcon;
1017             n.iconLevel = mSmallIconLevel;
1018             n.number = mNumber;
1019             n.contentView = makeContentView();
1020             n.contentIntent = mContentIntent;
1021             n.deleteIntent = mDeleteIntent;
1022             n.fullScreenIntent = mFullScreenIntent;
1023             n.tickerText = mTickerText;
1024             n.tickerView = makeTickerView();
1025             n.largeIcon = mLargeIcon;
1026             n.sound = mSound;
1027             n.audioStreamType = mAudioStreamType;
1028             n.vibrate = mVibrate;
1029             n.ledARGB = mLedArgb;
1030             n.ledOnMS = mLedOnMs;
1031             n.ledOffMS = mLedOffMs;
1032             n.defaults = mDefaults;
1033             n.flags = mFlags;
1034             if (mLedOnMs != 0 && mLedOffMs != 0) {
1035                 n.flags |= FLAG_SHOW_LIGHTS;
1036             }
1037             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
1038                 n.flags |= FLAG_SHOW_LIGHTS;
1039             }
1040             return n;
1041         }
1042     }
1043 }
1044