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