Notification.java revision 7aee61f5a96e94e158bf5ad3d8e192c4d4f7eff6
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     */
86    public int icon;
87
88    /**
89     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
90     * leave it at its default value of 0.
91     *
92     * @see android.widget.ImageView#setImageLevel
93     * @see android.graphics.drawable#setLevel
94     */
95    public int iconLevel;
96
97    /**
98     * The number of events that this notification represents.  For example, in a new mail
99     * notification, this could be the number of unread messages.  This number is superimposed over
100     * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status
101     * bar.
102     */
103    public int number;
104
105    /**
106     * The intent to execute when the expanded status entry is clicked.  If
107     * this is an activity, it must include the
108     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
109     * that you take care of task management as described in the
110     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
111     * Stack</a> document.
112     */
113    public PendingIntent contentIntent;
114
115    /**
116     * The intent to execute when the status entry is deleted by the user
117     * with the "Clear All Notifications" button. This probably shouldn't
118     * be launching an activity since several of those will be sent at the
119     * same time.
120     */
121    public PendingIntent deleteIntent;
122
123    /**
124     * An intent to launch instead of posting the notification to the status bar.
125     *
126     * @see Notification.Builder#setFullScreenIntent
127     */
128    public PendingIntent fullScreenIntent;
129
130    /**
131     * Text to scroll across the screen when this item is added to
132     * the status bar on large and smaller devices.
133     *
134     * <p>This field is provided separately from the other ticker fields
135     * both for compatibility and to allow an application to choose different
136     * text for when the text scrolls in and when it is displayed all at once
137     * in conjunction with one or more icons.
138     *
139     * @see #tickerView
140     */
141    public CharSequence tickerText;
142
143    /**
144     * The view to show as the ticker in the status bar when the notification
145     * is posted.
146     */
147    public RemoteViews tickerView;
148
149    /**
150     * The view that will represent this notification in the expanded status bar.
151     */
152    public RemoteViews contentView;
153
154    /**
155     * The bitmap that may escape the bounds of the panel and bar.
156     */
157    public Bitmap largeIcon;
158
159    /**
160     * The sound to play.
161     *
162     * <p>
163     * To play the default notification sound, see {@link #defaults}.
164     * </p>
165     */
166    public Uri sound;
167
168    /**
169     * Use this constant as the value for audioStreamType to request that
170     * the default stream type for notifications be used.  Currently the
171     * default stream type is STREAM_RING.
172     */
173    public static final int STREAM_DEFAULT = -1;
174
175    /**
176     * The audio stream type to use when playing the sound.
177     * Should be one of the STREAM_ constants from
178     * {@link android.media.AudioManager}.
179     */
180    public int audioStreamType = STREAM_DEFAULT;
181
182
183    /**
184     * The pattern with which to vibrate.
185     *
186     * <p>
187     * To vibrate the default pattern, see {@link #defaults}.
188     * </p>
189     *
190     * @see android.os.Vibrator#vibrate(long[],int)
191     */
192    public long[] vibrate;
193
194    /**
195     * The color of the led.  The hardware will do its best approximation.
196     *
197     * @see #FLAG_SHOW_LIGHTS
198     * @see #flags
199     */
200    public int ledARGB;
201
202    /**
203     * The number of milliseconds for the LED to be on while it's flashing.
204     * The hardware will do its best approximation.
205     *
206     * @see #FLAG_SHOW_LIGHTS
207     * @see #flags
208     */
209    public int ledOnMS;
210
211    /**
212     * The number of milliseconds for the LED to be off while it's flashing.
213     * The hardware will do its best approximation.
214     *
215     * @see #FLAG_SHOW_LIGHTS
216     * @see #flags
217     */
218    public int ledOffMS;
219
220    /**
221     * Specifies which values should be taken from the defaults.
222     * <p>
223     * To set, OR the desired from {@link #DEFAULT_SOUND},
224     * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
225     * values, use {@link #DEFAULT_ALL}.
226     * </p>
227     */
228    public int defaults;
229
230
231    /**
232     * Bit to be bitwise-ored into the {@link #flags} field that should be
233     * set if you want the LED on for this notification.
234     * <ul>
235     * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
236     *      or 0 for both ledOnMS and ledOffMS.</li>
237     * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
238     * <li>To flash the LED, pass the number of milliseconds that it should
239     *      be on and off to ledOnMS and ledOffMS.</li>
240     * </ul>
241     * <p>
242     * Since hardware varies, you are not guaranteed that any of the values
243     * you pass are honored exactly.  Use the system defaults (TODO) if possible
244     * because they will be set to values that work on any given hardware.
245     * <p>
246     * The alpha channel must be set for forward compatibility.
247     *
248     */
249    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
250
251    /**
252     * Bit to be bitwise-ored into the {@link #flags} field that should be
253     * set if this notification is in reference to something that is ongoing,
254     * like a phone call.  It should not be set if this notification is in
255     * reference to something that happened at a particular point in time,
256     * like a missed phone call.
257     */
258    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
259
260    /**
261     * Bit to be bitwise-ored into the {@link #flags} field that if set,
262     * the audio will be repeated until the notification is
263     * cancelled or the notification window is opened.
264     */
265    public static final int FLAG_INSISTENT          = 0x00000004;
266
267    /**
268     * Bit to be bitwise-ored into the {@link #flags} field that should be
269     * set if you want the sound and/or vibration play each time the
270     * notification is sent, even if it has not been canceled before that.
271     */
272    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
273
274    /**
275     * Bit to be bitwise-ored into the {@link #flags} field that should be
276     * set if the notification should be canceled when it is clicked by the
277     * user.  On tablets, the
278     */
279    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
280
281    /**
282     * Bit to be bitwise-ored into the {@link #flags} field that should be
283     * set if the notification should not be canceled when the user clicks
284     * the Clear all button.
285     */
286    public static final int FLAG_NO_CLEAR           = 0x00000020;
287
288    /**
289     * Bit to be bitwise-ored into the {@link #flags} field that should be
290     * set if this notification represents a currently running service.  This
291     * will normally be set for you by {@link Service#startForeground}.
292     */
293    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
294
295    /**
296     * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification
297     * represents a high-priority event that may be shown to the user even if notifications are
298     * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used
299     * in conjunction with {@link #fullScreenIntent}.
300     */
301    public static final int FLAG_HIGH_PRIORITY = 0x00000080;
302
303    public int flags;
304
305    /**
306     * Constructs a Notification object with everything set to 0.
307     * You might want to consider using {@link Builder} instead.
308     */
309    public Notification()
310    {
311        this.when = System.currentTimeMillis();
312    }
313
314    /**
315     * @hide
316     */
317    public Notification(Context context, int icon, CharSequence tickerText, long when,
318            CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
319    {
320        this.when = when;
321        this.icon = icon;
322        this.tickerText = tickerText;
323        setLatestEventInfo(context, contentTitle, contentText,
324                PendingIntent.getActivity(context, 0, contentIntent, 0));
325    }
326
327    /**
328     * Constructs a Notification object with the information needed to
329     * have a status bar icon without the standard expanded view.
330     *
331     * @param icon          The resource id of the icon to put in the status bar.
332     * @param tickerText    The text that flows by in the status bar when the notification first
333     *                      activates.
334     * @param when          The time to show in the time field.  In the System.currentTimeMillis
335     *                      timebase.
336     *
337     * @deprecated Use {@link Builder} instead.
338     */
339    @Deprecated
340    public Notification(int icon, CharSequence tickerText, long when)
341    {
342        this.icon = icon;
343        this.tickerText = tickerText;
344        this.when = when;
345    }
346
347    /**
348     * Unflatten the notification from a parcel.
349     */
350    public Notification(Parcel parcel)
351    {
352        int version = parcel.readInt();
353
354        when = parcel.readLong();
355        icon = parcel.readInt();
356        number = parcel.readInt();
357        if (parcel.readInt() != 0) {
358            contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
359        }
360        if (parcel.readInt() != 0) {
361            deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
362        }
363        if (parcel.readInt() != 0) {
364            tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
365        }
366        if (parcel.readInt() != 0) {
367            tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
368        }
369        if (parcel.readInt() != 0) {
370            contentView = RemoteViews.CREATOR.createFromParcel(parcel);
371        }
372        if (parcel.readInt() != 0) {
373            largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
374        }
375        defaults = parcel.readInt();
376        flags = parcel.readInt();
377        if (parcel.readInt() != 0) {
378            sound = Uri.CREATOR.createFromParcel(parcel);
379        }
380
381        audioStreamType = parcel.readInt();
382        vibrate = parcel.createLongArray();
383        ledARGB = parcel.readInt();
384        ledOnMS = parcel.readInt();
385        ledOffMS = parcel.readInt();
386        iconLevel = parcel.readInt();
387
388        if (parcel.readInt() != 0) {
389            fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
390        }
391    }
392
393    @Override
394    public Notification clone() {
395        Notification that = new Notification();
396
397        that.when = this.when;
398        that.icon = this.icon;
399        that.number = this.number;
400
401        // PendingIntents are global, so there's no reason (or way) to clone them.
402        that.contentIntent = this.contentIntent;
403        that.deleteIntent = this.deleteIntent;
404        that.fullScreenIntent = this.fullScreenIntent;
405
406        if (this.tickerText != null) {
407            that.tickerText = this.tickerText.toString();
408        }
409        if (this.tickerView != null) {
410            that.tickerView = this.tickerView.clone();
411        }
412        if (this.contentView != null) {
413            that.contentView = this.contentView.clone();
414        }
415        if (this.largeIcon != null) {
416            that.largeIcon = Bitmap.createBitmap(this.largeIcon);
417        }
418        that.iconLevel = that.iconLevel;
419        that.sound = this.sound; // android.net.Uri is immutable
420        that.audioStreamType = this.audioStreamType;
421
422        final long[] vibrate = this.vibrate;
423        if (vibrate != null) {
424            final int N = vibrate.length;
425            final long[] vib = that.vibrate = new long[N];
426            System.arraycopy(vibrate, 0, vib, 0, N);
427        }
428
429        that.ledARGB = this.ledARGB;
430        that.ledOnMS = this.ledOnMS;
431        that.ledOffMS = this.ledOffMS;
432        that.defaults = this.defaults;
433
434        that.flags = this.flags;
435
436        return that;
437    }
438
439    public int describeContents() {
440        return 0;
441    }
442
443    /**
444     * Flatten this notification from a parcel.
445     */
446    public void writeToParcel(Parcel parcel, int flags)
447    {
448        parcel.writeInt(1);
449
450        parcel.writeLong(when);
451        parcel.writeInt(icon);
452        parcel.writeInt(number);
453        if (contentIntent != null) {
454            parcel.writeInt(1);
455            contentIntent.writeToParcel(parcel, 0);
456        } else {
457            parcel.writeInt(0);
458        }
459        if (deleteIntent != null) {
460            parcel.writeInt(1);
461            deleteIntent.writeToParcel(parcel, 0);
462        } else {
463            parcel.writeInt(0);
464        }
465        if (tickerText != null) {
466            parcel.writeInt(1);
467            TextUtils.writeToParcel(tickerText, parcel, flags);
468        } else {
469            parcel.writeInt(0);
470        }
471        if (tickerView != null) {
472            parcel.writeInt(1);
473            tickerView.writeToParcel(parcel, 0);
474        } else {
475            parcel.writeInt(0);
476        }
477        if (contentView != null) {
478            parcel.writeInt(1);
479            contentView.writeToParcel(parcel, 0);
480        } else {
481            parcel.writeInt(0);
482        }
483        if (largeIcon != null) {
484            parcel.writeInt(1);
485            largeIcon.writeToParcel(parcel, 0);
486        } else {
487            parcel.writeInt(0);
488        }
489
490        parcel.writeInt(defaults);
491        parcel.writeInt(this.flags);
492
493        if (sound != null) {
494            parcel.writeInt(1);
495            sound.writeToParcel(parcel, 0);
496        } else {
497            parcel.writeInt(0);
498        }
499        parcel.writeInt(audioStreamType);
500        parcel.writeLongArray(vibrate);
501        parcel.writeInt(ledARGB);
502        parcel.writeInt(ledOnMS);
503        parcel.writeInt(ledOffMS);
504        parcel.writeInt(iconLevel);
505
506        if (fullScreenIntent != null) {
507            parcel.writeInt(1);
508            fullScreenIntent.writeToParcel(parcel, 0);
509        } else {
510            parcel.writeInt(0);
511        }
512    }
513
514    /**
515     * Parcelable.Creator that instantiates Notification objects
516     */
517    public static final Parcelable.Creator<Notification> CREATOR
518            = new Parcelable.Creator<Notification>()
519    {
520        public Notification createFromParcel(Parcel parcel)
521        {
522            return new Notification(parcel);
523        }
524
525        public Notification[] newArray(int size)
526        {
527            return new Notification[size];
528        }
529    };
530
531    /**
532     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
533     * layout.
534     *
535     * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
536     * in the view.</p>
537     * @param context       The context for your application / activity.
538     * @param contentTitle The title that goes in the expanded entry.
539     * @param contentText  The text that goes in the expanded entry.
540     * @param contentIntent The intent to launch when the user clicks the expanded notification.
541     * If this is an activity, it must include the
542     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
543     * that you take care of task management as described in the
544     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
545     * Stack</a> document.
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