Notification.java revision d952daec06018fe7064b8cafd31dfc71f9eee383
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 <em>Activities and Tasks</em>
111     * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application
112     * Fundamentals</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 = that.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
545     * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
546     *
547     * @deprecated Use {@link Builder} instead.
548     */
549    @Deprecated
550    public void setLatestEventInfo(Context context,
551            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
552        RemoteViews contentView = new RemoteViews(context.getPackageName(),
553                R.layout.status_bar_latest_event_content);
554        if (this.icon != 0) {
555            contentView.setImageViewResource(R.id.icon, this.icon);
556        }
557        if (contentTitle != null) {
558            contentView.setTextViewText(R.id.title, contentTitle);
559        }
560        if (contentText != null) {
561            contentView.setTextViewText(R.id.text, contentText);
562        }
563        if (this.when != 0) {
564            contentView.setLong(R.id.time, "setTime", when);
565        }
566
567        this.contentView = contentView;
568        this.contentIntent = contentIntent;
569    }
570
571    @Override
572    public String toString() {
573        StringBuilder sb = new StringBuilder();
574        sb.append("Notification(contentView=");
575        if (contentView != null) {
576            sb.append(contentView.getPackage());
577            sb.append("/0x");
578            sb.append(Integer.toHexString(contentView.getLayoutId()));
579        } else {
580            sb.append("null");
581        }
582        sb.append(" vibrate=");
583        if (this.vibrate != null) {
584            int N = this.vibrate.length-1;
585            sb.append("[");
586            for (int i=0; i<N; i++) {
587                sb.append(this.vibrate[i]);
588                sb.append(',');
589            }
590            if (N != -1) {
591                sb.append(this.vibrate[N]);
592            }
593            sb.append("]");
594        } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
595            sb.append("default");
596        } else {
597            sb.append("null");
598        }
599        sb.append(",sound=");
600        if (this.sound != null) {
601            sb.append(this.sound.toString());
602        } else if ((this.defaults & DEFAULT_SOUND) != 0) {
603            sb.append("default");
604        } else {
605            sb.append("null");
606        }
607        sb.append(",defaults=0x");
608        sb.append(Integer.toHexString(this.defaults));
609        sb.append(",flags=0x");
610        sb.append(Integer.toHexString(this.flags));
611        if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
612            sb.append("!!!1!one!");
613        }
614        sb.append(")");
615        return sb.toString();
616    }
617
618    /**
619     * Builder class for {@link Notification} objects.  Allows easier control over
620     * all the flags, as well as help constructing the typical notification layouts.
621     */
622    public static class Builder {
623        private Context mContext;
624
625        private long mWhen;
626        private int mSmallIcon;
627        private int mSmallIconLevel;
628        private int mNumber;
629        private CharSequence mContentTitle;
630        private CharSequence mContentText;
631        private CharSequence mContentInfo;
632        private PendingIntent mContentIntent;
633        private RemoteViews mContentView;
634        private PendingIntent mDeleteIntent;
635        private PendingIntent mFullScreenIntent;
636        private CharSequence mTickerText;
637        private RemoteViews mTickerView;
638        private Bitmap mLargeIcon;
639        private Uri mSound;
640        private int mAudioStreamType;
641        private long[] mVibrate;
642        private int mLedArgb;
643        private int mLedOnMs;
644        private int mLedOffMs;
645        private int mDefaults;
646        private int mFlags;
647
648        /**
649         * Constructor.
650         *
651         * Automatically sets the when field to {@link System#currentTimeMillis()
652         * System.currentTimeMllis()} and the audio stream to the {@link #STREAM_DEFAULT}.
653         *
654         * @param context A {@link Context} that will be used to construct the
655         *      RemoteViews. The Context will not be held past the lifetime of this
656         *      Builder object.
657         */
658        public Builder(Context context) {
659            mContext = context;
660
661            // Set defaults to match the defaults of a Notification
662            mWhen = System.currentTimeMillis();
663            mAudioStreamType = STREAM_DEFAULT;
664        }
665
666        /**
667         * Set the time that the event occurred.  Notifications in the panel are
668         * sorted by this time.
669         */
670        public Builder setWhen(long when) {
671            mWhen = when;
672            return this;
673        }
674
675        /**
676         * Set the small icon to use in the notification layouts.  Different classes of devices
677         * may return different sizes.  See the UX guidelines for more information on how to
678         * design these icons.
679         *
680         * @param icon A resource ID in the application's package of the drawble to use.
681         */
682        public Builder setSmallIcon(int icon) {
683            mSmallIcon = icon;
684            return this;
685        }
686
687        /**
688         * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
689         * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
690         * LevelListDrawable}.
691         *
692         * @param icon A resource ID in the application's package of the drawble to use.
693         * @param level The level to use for the icon.
694         *
695         * @see android.graphics.drawable.LevelListDrawable
696         */
697        public Builder setSmallIcon(int icon, int level) {
698            mSmallIcon = icon;
699            mSmallIconLevel = level;
700            return this;
701        }
702
703        /**
704         * Set the title (first row) of the notification, in a standard notification.
705         */
706        public Builder setContentTitle(CharSequence title) {
707            mContentTitle = title;
708            return this;
709        }
710
711        /**
712         * Set the text (second row) of the notification, in a standard notification.
713         */
714        public Builder setContentText(CharSequence text) {
715            mContentText = text;
716            return this;
717        }
718
719        /**
720         * Set the large number at the right-hand side of the notification.  This is
721         * equivalent to setContentInfo, although it might show the number in a different
722         * font size for readability.
723         */
724        public Builder setNumber(int number) {
725            mNumber = number;
726            return this;
727        }
728
729        /**
730         * Set the large text at the right-hand side of the notification.
731         */
732        public Builder setContentInfo(CharSequence info) {
733            mContentInfo = info;
734            return this;
735        }
736
737        /**
738         * Supply a custom RemoteViews to use instead of the standard one.
739         */
740        public Builder setContent(RemoteViews views) {
741            mContentView = views;
742            return this;
743        }
744
745        /**
746         * Supply a {@link PendingIntent} to send when the notification is clicked.
747         * If you do not supply an intent, you can now add PendingIntents to individual
748         * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
749         * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.
750         */
751        public Builder setContentIntent(PendingIntent intent) {
752            mContentIntent = intent;
753            return this;
754        }
755
756        /**
757         * Supply a {@link PendingIntent} to send when the notification is cleared by the user
758         * directly from the notification panel.  For example, this intent is sent when the user
759         * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
760         * intent is not sent when the application calls {@link NotificationManager#cancel
761         * NotificationManager.cancel(int)}.
762         */
763        public Builder setDeleteIntent(PendingIntent intent) {
764            mDeleteIntent = intent;
765            return this;
766        }
767
768        /**
769         * An intent to launch instead of posting the notification to the status bar.
770         * Only for use with extremely high-priority notifications demanding the user's
771         * <strong>immediate</strong> attention, such as an incoming phone call or
772         * alarm clock that the user has explicitly set to a particular time.
773         * If this facility is used for something else, please give the user an option
774         * to turn it off and use a normal notification, as this can be extremely
775         * disruptive.
776         *
777         * @param intent The pending intent to launch.
778         * @param highPriority Passing true will cause this notification to be sent
779         *          even if other notifications are suppressed.
780         */
781        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
782            mFullScreenIntent = intent;
783            setFlag(FLAG_HIGH_PRIORITY, highPriority);
784            return this;
785        }
786
787        /**
788         * Set the text that is displayed in the status bar when the notification first
789         * arrives.
790         */
791        public Builder setTicker(CharSequence tickerText) {
792            mTickerText = tickerText;
793            return this;
794        }
795
796        /**
797         * Set the text that is displayed in the status bar when the notification first
798         * arrives, and also a RemoteViews object that may be displayed instead on some
799         * devices.
800         */
801        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
802            mTickerText = tickerText;
803            mTickerView = views;
804            return this;
805        }
806
807        /**
808         * Set the large icon that is shown in the ticker and notification.
809         */
810        public Builder setLargeIcon(Bitmap icon) {
811            mLargeIcon = icon;
812            return this;
813        }
814
815        /**
816         * Set the sound to play.  It will play on the default stream.
817         */
818        public Builder setSound(Uri sound) {
819            mSound = sound;
820            mAudioStreamType = STREAM_DEFAULT;
821            return this;
822        }
823
824        /**
825         * Set the sound to play.  It will play on the stream you supply.
826         *
827         * @see #STREAM_DEFAULT
828         * @see AudioManager for the <code>STREAM_</code> constants.
829         */
830        public Builder setSound(Uri sound, int streamType) {
831            mSound = sound;
832            mAudioStreamType = streamType;
833            return this;
834        }
835
836        /**
837         * Set the vibration pattern to use.
838         *
839         * @see android.os.Vibrator for a discussion of the <code>pattern</code>
840         * parameter.
841         */
842        public Builder setVibrate(long[] pattern) {
843            mVibrate = pattern;
844            return this;
845        }
846
847        /**
848         * Set the argb value that you would like the LED on the device to blnk, as well as the
849         * rate.  The rate is specified in terms of the number of milliseconds to be on
850         * and then the number of milliseconds to be off.
851         */
852        public Builder setLights(int argb, int onMs, int offMs) {
853            mLedArgb = argb;
854            mLedOnMs = onMs;
855            mLedOffMs = offMs;
856            return this;
857        }
858
859        /**
860         * Set whether this is an ongoing notification.
861         *
862         * <p>Ongoing notifications differ from regular notifications in the following ways:
863         * <ul>
864         *   <li>Ongoing notifications are sorted above the regular notifications in the
865         *   notification panel.</li>
866         *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
867         *   by the "Clear all" button.
868         * </ul>
869         */
870        public Builder setOngoing(boolean ongoing) {
871            setFlag(FLAG_ONGOING_EVENT, ongoing);
872            return this;
873        }
874
875        /**
876         * Set this flag if you would only like the sound, vibrate
877         * and ticker to be played if the notification is not already showing.
878         */
879        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
880            setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
881            return this;
882        }
883
884        /**
885         * Setting this flag will make it so the notification is automatically
886         * canceled when the user clicks it in the panel.  The PendingIntent
887         * set with {@link #setDeleteIntent} will be broadcast when the notification
888         * is canceled.
889         */
890        public Builder setAutoCancel(boolean autoCancel) {
891            setFlag(FLAG_AUTO_CANCEL, autoCancel);
892            return this;
893        }
894
895        /**
896         * Set the default notification options that will be used.
897         * <p>
898         * The value should be one or more of the following fields combined with
899         * bitwise-or:
900         * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
901         * <p>
902         * For all default values, use {@link #DEFAULT_ALL}.
903         */
904        public Builder setDefaults(int defaults) {
905            mDefaults = defaults;
906            return this;
907        }
908
909        private void setFlag(int mask, boolean value) {
910            if (value) {
911                mFlags |= mask;
912            } else {
913                mFlags &= ~mask;
914            }
915        }
916
917        private RemoteViews makeRemoteViews(int resId) {
918            RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
919            if (mSmallIcon != 0) {
920                contentView.setImageViewResource(R.id.icon, mSmallIcon);
921            }
922            if (mContentTitle != null) {
923                contentView.setTextViewText(R.id.title, mContentTitle);
924            }
925            if (mContentText != null) {
926                contentView.setTextViewText(R.id.text, mContentText);
927            }
928            if (mContentInfo != null) {
929                contentView.setTextViewText(R.id.info, mContentInfo);
930            } else if (mNumber > 0) {
931                if (mNumber > 999) {
932                    contentView.setTextViewText(R.id.info, "999+");
933                } else {
934                    NumberFormat f = NumberFormat.getIntegerInstance();
935                    contentView.setTextViewText(R.id.info, f.format(mNumber));
936                }
937                contentView.setFloat(R.id.info, "setTextSize",
938                        mContext.getResources().getDimensionPixelSize(
939                            R.dimen.status_bar_content_number_size));
940            } else {
941                contentView.setViewVisibility(R.id.info, View.GONE);
942            }
943            if (mWhen != 0) {
944                contentView.setLong(R.id.time, "setTime", mWhen);
945            }
946            return contentView;
947        }
948
949        private RemoteViews makeContentView() {
950            if (mContentView != null) {
951                return mContentView;
952            } else {
953                    return makeRemoteViews(mLargeIcon == null
954                            ? R.layout.status_bar_latest_event_content
955                        : R.layout.status_bar_latest_event_content_large_icon);
956            }
957        }
958
959        private RemoteViews makeTickerView() {
960            if (mTickerView != null) {
961                return mTickerView;
962            } else {
963                if (mContentView == null) {
964                    return makeRemoteViews(mLargeIcon == null
965                            ? R.layout.status_bar_latest_event_ticker
966                            : R.layout.status_bar_latest_event_ticker_large_icon);
967                } else {
968                    return null;
969                }
970            }
971        }
972
973        /**
974         * Combine all of the options that have been set and return a new {@link Notification}
975         * object.
976         */
977        public Notification getNotification() {
978            Notification n = new Notification();
979            n.when = mWhen;
980            n.icon = mSmallIcon;
981            n.iconLevel = mSmallIconLevel;
982            n.number = mNumber;
983            n.contentView = makeContentView();
984            n.contentIntent = mContentIntent;
985            n.deleteIntent = mDeleteIntent;
986            n.fullScreenIntent = mFullScreenIntent;
987            n.tickerText = mTickerText;
988            n.tickerView = makeTickerView();
989            n.largeIcon = mLargeIcon;
990            n.sound = mSound;
991            n.audioStreamType = mAudioStreamType;
992            n.vibrate = mVibrate;
993            n.ledARGB = mLedArgb;
994            n.ledOnMS = mLedOnMs;
995            n.ledOffMS = mLedOffMs;
996            n.defaults = mDefaults;
997            n.flags = mFlags;
998            if (mLedOnMs != 0 && mLedOffMs != 0) {
999                n.flags |= FLAG_SHOW_LIGHTS;
1000            }
1001            if ((mDefaults & DEFAULT_LIGHTS) != 0) {
1002                n.flags |= FLAG_SHOW_LIGHTS;
1003            }
1004            return n;
1005        }
1006    }
1007}
1008