Notification.java revision cde8aae955f2c1074a840074a9f586f95c3f61f7
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.Bundle;
26import android.os.IBinder;
27import android.os.Parcel;
28import android.os.Parcelable;
29import android.os.SystemClock;
30import android.text.TextUtils;
31import android.util.IntProperty;
32import android.util.Log;
33import android.view.View;
34import android.widget.ProgressBar;
35import android.widget.RemoteViews;
36
37import java.text.NumberFormat;
38import java.util.ArrayList;
39
40/**
41 * A class that represents how a persistent notification is to be presented to
42 * the user using the {@link android.app.NotificationManager}.
43 *
44 * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
45 * easier to construct Notifications.</p>
46 *
47 * <div class="special reference">
48 * <h3>Developer Guides</h3>
49 * <p>For a guide to creating notifications, read the
50 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
51 * developer guide.</p>
52 * </div>
53 */
54public class Notification implements Parcelable
55{
56    /**
57     * Use all default values (where applicable).
58     */
59    public static final int DEFAULT_ALL = ~0;
60
61    /**
62     * Use the default notification sound. This will ignore any given
63     * {@link #sound}.
64     *
65
66     * @see #defaults
67     */
68
69    public static final int DEFAULT_SOUND = 1;
70
71    /**
72     * Use the default notification vibrate. This will ignore any given
73     * {@link #vibrate}. Using phone vibration requires the
74     * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
75     *
76     * @see #defaults
77     */
78
79    public static final int DEFAULT_VIBRATE = 2;
80
81    /**
82     * Use the default notification lights. This will ignore the
83     * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
84     * {@link #ledOnMS}.
85     *
86     * @see #defaults
87     */
88
89    public static final int DEFAULT_LIGHTS = 4;
90
91    /**
92     * A timestamp related to this notification, in milliseconds since the epoch.
93     *
94     * Default value: {@link System#currentTimeMillis() Now}.
95     *
96     * Choose a timestamp that will be most relevant to the user. For most finite events, this
97     * corresponds to the time the event happened (or will happen, in the case of events that have
98     * yet to occur but about which the user is being informed). Indefinite events should be
99     * timestamped according to when the activity began.
100     *
101     * Some examples:
102     *
103     * <ul>
104     *   <li>Notification of a new chat message should be stamped when the message was received.</li>
105     *   <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li>
106     *   <li>Notification of a completed file download should be stamped when the download finished.</li>
107     *   <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li>
108     *   <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time.
109     *   <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.
110     * </ul>
111     *
112     */
113    public long when;
114
115    /**
116     * The resource id of a drawable to use as the icon in the status bar.
117     * This is required; notifications with an invalid icon resource will not be shown.
118     */
119    public int icon;
120
121    /**
122     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
123     * leave it at its default value of 0.
124     *
125     * @see android.widget.ImageView#setImageLevel
126     * @see android.graphics.drawable#setLevel
127     */
128    public int iconLevel;
129
130    /**
131     * The number of events that this notification represents. For example, in a new mail
132     * notification, this could be the number of unread messages.
133     *
134     * The system may or may not use this field to modify the appearance of the notification. For
135     * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was
136     * superimposed over the icon in the status bar. Starting with
137     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
138     * {@link Notification.Builder} has displayed the number in the expanded notification view.
139     *
140     * If the number is 0 or negative, it is never shown.
141     */
142    public int number;
143
144    /**
145     * The intent to execute when the expanded status entry is clicked.  If
146     * this is an activity, it must include the
147     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
148     * that you take care of task management as described in the
149     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
150     * Stack</a> document.  In particular, make sure to read the notification section
151     * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
152     * Notifications</a> for the correct ways to launch an application from a
153     * notification.
154     */
155    public PendingIntent contentIntent;
156
157    /**
158     * The intent to execute when the notification is explicitly dismissed by the user, either with
159     * the "Clear All" button or by swiping it away individually.
160     *
161     * This probably shouldn't be launching an activity since several of those will be sent
162     * at the same time.
163     */
164    public PendingIntent deleteIntent;
165
166    /**
167     * An intent to launch instead of posting the notification to the status bar.
168     *
169     * @see Notification.Builder#setFullScreenIntent
170     */
171    public PendingIntent fullScreenIntent;
172
173    /**
174     * Text to scroll across the screen when this item is added to
175     * the status bar on large and smaller devices.
176     *
177     * @see #tickerView
178     */
179    public CharSequence tickerText;
180
181    /**
182     * The view to show as the ticker in the status bar when the notification
183     * is posted.
184     */
185    public RemoteViews tickerView;
186
187    /**
188     * The view that will represent this notification in the expanded status bar.
189     */
190    public RemoteViews contentView;
191
192    /**
193     * The view that will represent this notification in the pop-up "intruder alert" dialog.
194     * @hide
195     */
196    public RemoteViews intruderView;
197
198    /**
199     * A larger version of {@link #contentView}, giving the Notification an
200     * opportunity to show more detail. The system UI may choose to show this
201     * instead of the normal content view at its discretion.
202     * @hide
203     */
204    public RemoteViews bigContentView;
205
206    /**
207     * The bitmap that may escape the bounds of the panel and bar.
208     */
209    public Bitmap largeIcon;
210
211    /**
212     * The sound to play.
213     *
214     * <p>
215     * To play the default notification sound, see {@link #defaults}.
216     * </p>
217     */
218    public Uri sound;
219
220    /**
221     * Use this constant as the value for audioStreamType to request that
222     * the default stream type for notifications be used.  Currently the
223     * default stream type is STREAM_RING.
224     */
225    public static final int STREAM_DEFAULT = -1;
226
227    /**
228     * The audio stream type to use when playing the sound.
229     * Should be one of the STREAM_ constants from
230     * {@link android.media.AudioManager}.
231     */
232    public int audioStreamType = STREAM_DEFAULT;
233
234    /**
235     * The pattern with which to vibrate.
236     *
237     * <p>
238     * To vibrate the default pattern, see {@link #defaults}.
239     * </p>
240     *
241     * @see android.os.Vibrator#vibrate(long[],int)
242     */
243    public long[] vibrate;
244
245    /**
246     * The color of the led.  The hardware will do its best approximation.
247     *
248     * @see #FLAG_SHOW_LIGHTS
249     * @see #flags
250     */
251    public int ledARGB;
252
253    /**
254     * The number of milliseconds for the LED to be on while it's flashing.
255     * The hardware will do its best approximation.
256     *
257     * @see #FLAG_SHOW_LIGHTS
258     * @see #flags
259     */
260    public int ledOnMS;
261
262    /**
263     * The number of milliseconds for the LED to be off while it's flashing.
264     * The hardware will do its best approximation.
265     *
266     * @see #FLAG_SHOW_LIGHTS
267     * @see #flags
268     */
269    public int ledOffMS;
270
271    /**
272     * Specifies which values should be taken from the defaults.
273     * <p>
274     * To set, OR the desired from {@link #DEFAULT_SOUND},
275     * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
276     * values, use {@link #DEFAULT_ALL}.
277     * </p>
278     */
279    public int defaults;
280
281    /**
282     * Bit to be bitwise-ored into the {@link #flags} field that should be
283     * set if you want the LED on for this notification.
284     * <ul>
285     * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
286     *      or 0 for both ledOnMS and ledOffMS.</li>
287     * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
288     * <li>To flash the LED, pass the number of milliseconds that it should
289     *      be on and off to ledOnMS and ledOffMS.</li>
290     * </ul>
291     * <p>
292     * Since hardware varies, you are not guaranteed that any of the values
293     * you pass are honored exactly.  Use the system defaults (TODO) if possible
294     * because they will be set to values that work on any given hardware.
295     * <p>
296     * The alpha channel must be set for forward compatibility.
297     *
298     */
299    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
300
301    /**
302     * Bit to be bitwise-ored into the {@link #flags} field that should be
303     * set if this notification is in reference to something that is ongoing,
304     * like a phone call.  It should not be set if this notification is in
305     * reference to something that happened at a particular point in time,
306     * like a missed phone call.
307     */
308    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
309
310    /**
311     * Bit to be bitwise-ored into the {@link #flags} field that if set,
312     * the audio will be repeated until the notification is
313     * cancelled or the notification window is opened.
314     */
315    public static final int FLAG_INSISTENT          = 0x00000004;
316
317    /**
318     * Bit to be bitwise-ored into the {@link #flags} field that should be
319     * set if you want the sound and/or vibration play each time the
320     * notification is sent, even if it has not been canceled before that.
321     */
322    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
323
324    /**
325     * Bit to be bitwise-ored into the {@link #flags} field that should be
326     * set if the notification should be canceled when it is clicked by the
327     * user.  On tablets, the
328
329     */
330    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
331
332    /**
333     * Bit to be bitwise-ored into the {@link #flags} field that should be
334     * set if the notification should not be canceled when the user clicks
335     * the Clear all button.
336     */
337    public static final int FLAG_NO_CLEAR           = 0x00000020;
338
339    /**
340     * Bit to be bitwise-ored into the {@link #flags} field that should be
341     * set if this notification represents a currently running service.  This
342     * will normally be set for you by {@link Service#startForeground}.
343     */
344    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
345
346    /**
347     * Obsolete flag indicating high-priority notifications; use the priority field instead.
348     *
349     * @deprecated Use {@link #priority} with a positive value.
350     */
351    public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
352
353    public int flags;
354
355    /**
356     * Default notification {@link #priority}. If your application does not prioritize its own
357     * notifications, use this value for all notifications.
358     */
359    public static final int PRIORITY_DEFAULT = 0;
360
361    /**
362     * Lower {@link #priority}, for items that are less important. The UI may choose to show these
363     * items smaller, or at a different position in the list, compared with your app's
364     * {@link #PRIORITY_DEFAULT} items.
365     */
366    public static final int PRIORITY_LOW = -1;
367
368    /**
369     * Lowest {@link #priority}; these items might not be shown to the user except under special
370     * circumstances, such as detailed notification logs.
371     */
372    public static final int PRIORITY_MIN = -2;
373
374    /**
375     * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to
376     * show these items larger, or at a different position in notification lists, compared with
377     * your app's {@link #PRIORITY_DEFAULT} items.
378     */
379    public static final int PRIORITY_HIGH = 1;
380
381    /**
382     * Highest {@link #priority}, for your application's most important items that require the
383     * user's prompt attention or input.
384     */
385    public static final int PRIORITY_MAX = 2;
386
387    /**
388     * Relative priority for this notification.
389     *
390     * Priority is an indication of how much of the user's valuable attention should be consumed by
391     * this notification. Low-priority notifications may be hidden from the user in certain
392     * situations, while the user might be interrupted for a higher-priority notification. The
393     * system will make a determination about how to interpret notification priority as described in
394     * MUMBLE MUMBLE.
395     */
396    public int priority;
397
398    /**
399     * Notification type: incoming call (voice or video) or similar synchronous communication request.
400     */
401    public static final String KIND_CALL = "android.call";
402
403    /**
404     * Notification type: incoming direct message (SMS, instant message, etc.).
405     */
406    public static final String KIND_MESSAGE = "android.message";
407
408    /**
409     * Notification type: asynchronous bulk message (email).
410     */
411    public static final String KIND_EMAIL = "android.email";
412
413    /**
414     * Notification type: calendar event.
415     */
416    public static final String KIND_EVENT = "android.event";
417
418    /**
419     * Notification type: promotion or advertisement.
420     */
421    public static final String KIND_PROMO = "android.promo";
422
423    /**
424     * If this notification matches of one or more special types (see the <code>KIND_*</code>
425     * constants), add them here, best match first.
426     */
427    public String[] kind;
428
429    /**
430     * Extra key for people values (type TBD).
431     *
432     * @hide
433     */
434    public static final String EXTRA_PEOPLE = "android.people";
435
436    private Bundle extras;
437
438    /**
439     * Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
440     * @hide
441     */
442    private static class Action implements Parcelable {
443        public int icon;
444        public CharSequence title;
445        public PendingIntent actionIntent;
446        @SuppressWarnings("unused")
447        public Action() { }
448        private Action(Parcel in) {
449            icon = in.readInt();
450            title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
451            if (in.readInt() == 1) {
452                actionIntent = PendingIntent.CREATOR.createFromParcel(in);
453            }
454        }
455        public Action(int icon_, CharSequence title_, PendingIntent intent_) {
456            this.icon = icon_;
457            this.title = title_;
458            this.actionIntent = intent_;
459        }
460        @Override
461        public Action clone() {
462            return new Action(
463                this.icon,
464                this.title.toString(),
465                this.actionIntent // safe to alias
466            );
467        }
468        @Override
469        public int describeContents() {
470            return 0;
471        }
472        @Override
473        public void writeToParcel(Parcel out, int flags) {
474            out.writeInt(icon);
475            TextUtils.writeToParcel(title, out, flags);
476            if (actionIntent != null) {
477                out.writeInt(1);
478                actionIntent.writeToParcel(out, flags);
479            } else {
480                out.writeInt(0);
481            }
482        }
483        public static final Parcelable.Creator<Action> CREATOR
484        = new Parcelable.Creator<Action>() {
485            public Action createFromParcel(Parcel in) {
486                return new Action(in);
487            }
488            public Action[] newArray(int size) {
489                return new Action[size];
490            }
491        };
492    }
493
494    private Action[] actions;
495
496    /**
497     * Constructs a Notification object with default values.
498     * You might want to consider using {@link Builder} instead.
499     */
500    public Notification()
501    {
502        this.when = System.currentTimeMillis();
503        this.priority = PRIORITY_DEFAULT;
504    }
505
506    /**
507     * @hide
508     */
509    public Notification(Context context, int icon, CharSequence tickerText, long when,
510            CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
511    {
512        this.when = when;
513        this.icon = icon;
514        this.tickerText = tickerText;
515        setLatestEventInfo(context, contentTitle, contentText,
516                PendingIntent.getActivity(context, 0, contentIntent, 0));
517    }
518
519    /**
520     * Constructs a Notification object with the information needed to
521     * have a status bar icon without the standard expanded view.
522     *
523     * @param icon          The resource id of the icon to put in the status bar.
524     * @param tickerText    The text that flows by in the status bar when the notification first
525     *                      activates.
526     * @param when          The time to show in the time field.  In the System.currentTimeMillis
527     *                      timebase.
528     *
529     * @deprecated Use {@link Builder} instead.
530     */
531    @Deprecated
532    public Notification(int icon, CharSequence tickerText, long when)
533    {
534        this.icon = icon;
535        this.tickerText = tickerText;
536        this.when = when;
537    }
538
539    /**
540     * Unflatten the notification from a parcel.
541     */
542    public Notification(Parcel parcel)
543    {
544        int version = parcel.readInt();
545
546        when = parcel.readLong();
547        icon = parcel.readInt();
548        number = parcel.readInt();
549        if (parcel.readInt() != 0) {
550            contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
551        }
552        if (parcel.readInt() != 0) {
553            deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
554        }
555        if (parcel.readInt() != 0) {
556            tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
557        }
558        if (parcel.readInt() != 0) {
559            tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
560        }
561        if (parcel.readInt() != 0) {
562            contentView = RemoteViews.CREATOR.createFromParcel(parcel);
563        }
564        if (parcel.readInt() != 0) {
565            largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
566        }
567        defaults = parcel.readInt();
568        flags = parcel.readInt();
569        if (parcel.readInt() != 0) {
570            sound = Uri.CREATOR.createFromParcel(parcel);
571        }
572
573        audioStreamType = parcel.readInt();
574        vibrate = parcel.createLongArray();
575        ledARGB = parcel.readInt();
576        ledOnMS = parcel.readInt();
577        ledOffMS = parcel.readInt();
578        iconLevel = parcel.readInt();
579
580        if (parcel.readInt() != 0) {
581            fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
582        }
583
584        priority = parcel.readInt();
585
586        kind = parcel.createStringArray(); // may set kind to null
587
588        if (parcel.readInt() != 0) {
589            extras = parcel.readBundle();
590        }
591
592        actions = parcel.createTypedArray(Action.CREATOR);
593        if (parcel.readInt() != 0) {
594            intruderView = RemoteViews.CREATOR.createFromParcel(parcel);
595        }
596        if (parcel.readInt() != 0) {
597            bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
598        }
599    }
600
601    @Override
602    public Notification clone() {
603        Notification that = new Notification();
604
605        that.when = this.when;
606        that.icon = this.icon;
607        that.number = this.number;
608
609        // PendingIntents are global, so there's no reason (or way) to clone them.
610        that.contentIntent = this.contentIntent;
611        that.deleteIntent = this.deleteIntent;
612        that.fullScreenIntent = this.fullScreenIntent;
613
614        if (this.tickerText != null) {
615            that.tickerText = this.tickerText.toString();
616        }
617        if (this.tickerView != null) {
618            that.tickerView = this.tickerView.clone();
619        }
620        if (this.contentView != null) {
621            that.contentView = this.contentView.clone();
622        }
623        if (this.largeIcon != null) {
624            that.largeIcon = Bitmap.createBitmap(this.largeIcon);
625        }
626        that.iconLevel = this.iconLevel;
627        that.sound = this.sound; // android.net.Uri is immutable
628        that.audioStreamType = this.audioStreamType;
629
630        final long[] vibrate = this.vibrate;
631        if (vibrate != null) {
632            final int N = vibrate.length;
633            final long[] vib = that.vibrate = new long[N];
634            System.arraycopy(vibrate, 0, vib, 0, N);
635        }
636
637        that.ledARGB = this.ledARGB;
638        that.ledOnMS = this.ledOnMS;
639        that.ledOffMS = this.ledOffMS;
640        that.defaults = this.defaults;
641
642        that.flags = this.flags;
643
644        that.priority = this.priority;
645
646        final String[] thiskind = this.kind;
647        if (thiskind != null) {
648            final int N = thiskind.length;
649            final String[] thatkind = that.kind = new String[N];
650            System.arraycopy(thiskind, 0, thatkind, 0, N);
651        }
652
653        if (this.extras != null) {
654            that.extras = new Bundle(this.extras);
655
656        }
657
658        that.actions = new Action[this.actions.length];
659        for(int i=0; i<this.actions.length; i++) {
660            that.actions[i] = this.actions[i].clone();
661        }
662        if (this.intruderView != null) {
663            that.intruderView = this.intruderView.clone();
664        }
665        if (this.bigContentView != null) {
666            that.bigContentView = this.bigContentView.clone();
667        }
668
669        return that;
670    }
671
672    public int describeContents() {
673        return 0;
674    }
675
676    /**
677     * Flatten this notification from a parcel.
678     */
679    public void writeToParcel(Parcel parcel, int flags)
680    {
681        parcel.writeInt(1);
682
683        parcel.writeLong(when);
684        parcel.writeInt(icon);
685        parcel.writeInt(number);
686        if (contentIntent != null) {
687            parcel.writeInt(1);
688            contentIntent.writeToParcel(parcel, 0);
689        } else {
690            parcel.writeInt(0);
691        }
692        if (deleteIntent != null) {
693            parcel.writeInt(1);
694            deleteIntent.writeToParcel(parcel, 0);
695        } else {
696            parcel.writeInt(0);
697        }
698        if (tickerText != null) {
699            parcel.writeInt(1);
700            TextUtils.writeToParcel(tickerText, parcel, flags);
701        } else {
702            parcel.writeInt(0);
703        }
704        if (tickerView != null) {
705            parcel.writeInt(1);
706            tickerView.writeToParcel(parcel, 0);
707        } else {
708            parcel.writeInt(0);
709        }
710        if (contentView != null) {
711            parcel.writeInt(1);
712            contentView.writeToParcel(parcel, 0);
713        } else {
714            parcel.writeInt(0);
715        }
716        if (largeIcon != null) {
717            parcel.writeInt(1);
718            largeIcon.writeToParcel(parcel, 0);
719        } else {
720            parcel.writeInt(0);
721        }
722
723        parcel.writeInt(defaults);
724        parcel.writeInt(this.flags);
725
726        if (sound != null) {
727            parcel.writeInt(1);
728            sound.writeToParcel(parcel, 0);
729        } else {
730            parcel.writeInt(0);
731        }
732        parcel.writeInt(audioStreamType);
733        parcel.writeLongArray(vibrate);
734        parcel.writeInt(ledARGB);
735        parcel.writeInt(ledOnMS);
736        parcel.writeInt(ledOffMS);
737        parcel.writeInt(iconLevel);
738
739        if (fullScreenIntent != null) {
740            parcel.writeInt(1);
741            fullScreenIntent.writeToParcel(parcel, 0);
742        } else {
743            parcel.writeInt(0);
744        }
745
746        parcel.writeInt(priority);
747
748        parcel.writeStringArray(kind); // ok for null
749
750        if (extras != null) {
751            parcel.writeInt(1);
752            extras.writeToParcel(parcel, 0);
753        } else {
754            parcel.writeInt(0);
755        }
756
757        parcel.writeTypedArray(actions, 0);
758
759        if (intruderView != null) {
760            parcel.writeInt(1);
761            intruderView.writeToParcel(parcel, 0);
762        } else {
763            parcel.writeInt(0);
764        }
765
766        if (bigContentView != null) {
767            parcel.writeInt(1);
768            bigContentView.writeToParcel(parcel, 0);
769        } else {
770            parcel.writeInt(0);
771        }
772    }
773
774    /**
775     * Parcelable.Creator that instantiates Notification objects
776     */
777    public static final Parcelable.Creator<Notification> CREATOR
778            = new Parcelable.Creator<Notification>()
779    {
780        public Notification createFromParcel(Parcel parcel)
781        {
782            return new Notification(parcel);
783        }
784
785        public Notification[] newArray(int size)
786        {
787            return new Notification[size];
788        }
789    };
790
791    /**
792     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
793     * layout.
794     *
795     * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
796     * in the view.</p>
797     * @param context       The context for your application / activity.
798     * @param contentTitle The title that goes in the expanded entry.
799     * @param contentText  The text that goes in the expanded entry.
800     * @param contentIntent The intent to launch when the user clicks the expanded notification.
801     * If this is an activity, it must include the
802     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
803     * that you take care of task management as described in the
804     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
805     * Stack</a> document.
806     *
807     * @deprecated Use {@link Builder} instead.
808     */
809    @Deprecated
810    public void setLatestEventInfo(Context context,
811            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
812        // TODO: rewrite this to use Builder
813        RemoteViews contentView = new RemoteViews(context.getPackageName(),
814                R.layout.notification_template_base);
815        if (this.icon != 0) {
816            contentView.setImageViewResource(R.id.icon, this.icon);
817        }
818        if (contentTitle != null) {
819            contentView.setTextViewText(R.id.title, contentTitle);
820        }
821        if (contentText != null) {
822            contentView.setTextViewText(R.id.text, contentText);
823        }
824        if (this.when != 0) {
825            contentView.setViewVisibility(R.id.time, View.VISIBLE);
826            contentView.setLong(R.id.time, "setTime", when);
827        }
828
829        this.contentView = contentView;
830        this.contentIntent = contentIntent;
831    }
832
833    @Override
834    public String toString() {
835        StringBuilder sb = new StringBuilder();
836        sb.append("Notification(pri=");
837        sb.append(priority);
838        sb.append(" contentView=");
839        if (contentView != null) {
840            sb.append(contentView.getPackage());
841            sb.append("/0x");
842            sb.append(Integer.toHexString(contentView.getLayoutId()));
843        } else {
844            sb.append("null");
845        }
846        // TODO(dsandler): defaults take precedence over local values, so reorder the branches below
847        sb.append(" vibrate=");
848        if (this.vibrate != null) {
849            int N = this.vibrate.length-1;
850            sb.append("[");
851            for (int i=0; i<N; i++) {
852                sb.append(this.vibrate[i]);
853                sb.append(',');
854            }
855            if (N != -1) {
856                sb.append(this.vibrate[N]);
857            }
858            sb.append("]");
859        } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
860            sb.append("default");
861        } else {
862            sb.append("null");
863        }
864        sb.append(" sound=");
865        if (this.sound != null) {
866            sb.append(this.sound.toString());
867        } else if ((this.defaults & DEFAULT_SOUND) != 0) {
868            sb.append("default");
869        } else {
870            sb.append("null");
871        }
872        sb.append(" defaults=0x");
873        sb.append(Integer.toHexString(this.defaults));
874        sb.append(" flags=0x");
875        sb.append(Integer.toHexString(this.flags));
876        sb.append(" kind=[");
877        if (this.kind == null) {
878            sb.append("null");
879        } else {
880            for (int i=0; i<this.kind.length; i++) {
881                if (i>0) sb.append(",");
882                sb.append(this.kind[i]);
883            }
884        }
885        sb.append("]");
886        if (actions != null) {
887            sb.append(" ");
888            sb.append(actions.length);
889            sb.append(" action");
890            if (actions.length > 1) sb.append("s");
891        }
892        sb.append(")");
893        return sb.toString();
894    }
895
896    /**
897     * Builder class for {@link Notification} objects.
898     *
899     * Provides a convenient way to set the various fields of a {@link Notification} and generate
900     * content views using the platform's notification layout template.
901     *
902     * Example:
903     *
904     * <pre class="prettyprint">
905     * Notification noti = new Notification.Builder()
906     *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
907     *         .setContentText(subject)
908     *         .setSmallIcon(R.drawable.new_mail)
909     *         .setLargeIcon(aBitmap)
910     *         .getNotification();
911     * </pre>
912     */
913    public static class Builder {
914        private Context mContext;
915
916        private long mWhen;
917        private int mSmallIcon;
918        private int mSmallIconLevel;
919        private int mNumber;
920        private CharSequence mContentTitle;
921        private CharSequence mContentText;
922        private CharSequence mContentInfo;
923        private CharSequence mSubText;
924        private PendingIntent mContentIntent;
925        private RemoteViews mContentView;
926        private PendingIntent mDeleteIntent;
927        private PendingIntent mFullScreenIntent;
928        private CharSequence mTickerText;
929        private RemoteViews mTickerView;
930        private Bitmap mLargeIcon;
931        private Uri mSound;
932        private int mAudioStreamType;
933        private long[] mVibrate;
934        private int mLedArgb;
935        private int mLedOnMs;
936        private int mLedOffMs;
937        private int mDefaults;
938        private int mFlags;
939        private int mProgressMax;
940        private int mProgress;
941        private boolean mProgressIndeterminate;
942        private ArrayList<String> mKindList = new ArrayList<String>(1);
943        private Bundle mExtras;
944        private int mPriority;
945        private ArrayList<Action> mActions = new ArrayList<Action>(3);
946        private boolean mCanHasIntruder;
947        private boolean mIntruderActionsShowText;
948        private boolean mUseChronometer;
949
950        /**
951         * Constructs a new Builder with the defaults:
952         *
953
954         * <table>
955         * <tr><th align=right>priority</th>
956         *     <td>{@link #PRIORITY_DEFAULT}</td></tr>
957         * <tr><th align=right>when</th>
958         *     <td>now ({@link System#currentTimeMillis()})</td></tr>
959         * <tr><th align=right>audio stream</th>
960         *     <td>{@link #STREAM_DEFAULT}</td></tr>
961         * </table>
962         *
963
964         * @param context
965         *            A {@link Context} that will be used by the Builder to construct the
966         *            RemoteViews. The Context will not be held past the lifetime of this Builder
967         *            object.
968         */
969        public Builder(Context context) {
970            mContext = context;
971
972            // Set defaults to match the defaults of a Notification
973            mWhen = System.currentTimeMillis();
974            mAudioStreamType = STREAM_DEFAULT;
975            mPriority = PRIORITY_DEFAULT;
976        }
977
978        /**
979         * Add a timestamp pertaining to the notification (usually the time the event occurred).
980         *
981
982         * @see Notification#when
983         */
984        public Builder setWhen(long when) {
985            mWhen = when;
986            return this;
987        }
988
989        /**
990         * @hide
991         *
992         * Show the {@link Notification#when} field as a countdown (or count-up) timer instead of a timestamp.
993         *
994         * @see Notification#when
995         */
996        public Builder setUsesChronometer(boolean b) {
997            mUseChronometer = b;
998            return this;
999        }
1000
1001        /**
1002         * Set the small icon resource, which will be used to represent the notification in the
1003         * status bar.
1004         *
1005
1006         * The platform template for the expanded view will draw this icon in the left, unless a
1007         * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
1008         * icon will be moved to the right-hand side.
1009         *
1010
1011         * @param icon
1012         *            A resource ID in the application's package of the drawable to use.
1013         * @see Notification#icon
1014         */
1015        public Builder setSmallIcon(int icon) {
1016            mSmallIcon = icon;
1017            return this;
1018        }
1019
1020        /**
1021         * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
1022         * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
1023         * LevelListDrawable}.
1024         *
1025         * @param icon A resource ID in the application's package of the drawable to use.
1026         * @param level The level to use for the icon.
1027         *
1028         * @see Notification#icon
1029         * @see Notification#iconLevel
1030         */
1031        public Builder setSmallIcon(int icon, int level) {
1032            mSmallIcon = icon;
1033            mSmallIconLevel = level;
1034            return this;
1035        }
1036
1037        /**
1038         * Set the first line of text in the platform notification template.
1039         */
1040        public Builder setContentTitle(CharSequence title) {
1041            mContentTitle = title;
1042            return this;
1043        }
1044
1045        /**
1046         * Set the second line of text in the platform notification template.
1047         */
1048        public Builder setContentText(CharSequence text) {
1049            mContentText = text;
1050            return this;
1051        }
1052
1053        /**
1054         * Set the third line of text in the platform notification template.
1055         * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the same location in the standard template.
1056         */
1057        public Builder setSubText(CharSequence text) {
1058            mSubText = text;
1059            return this;
1060        }
1061
1062        /**
1063         * Set the large number at the right-hand side of the notification.  This is
1064         * equivalent to setContentInfo, although it might show the number in a different
1065         * font size for readability.
1066         */
1067        public Builder setNumber(int number) {
1068            mNumber = number;
1069            return this;
1070        }
1071
1072        /**
1073         * A small piece of additional information pertaining to this notification.
1074         *
1075         * The platform template will draw this on the last line of the notification, at the far
1076         * right (to the right of a smallIcon if it has been placed there).
1077         */
1078        public Builder setContentInfo(CharSequence info) {
1079            mContentInfo = info;
1080            return this;
1081        }
1082
1083        /**
1084         * Set the progress this notification represents.
1085         *
1086         * The platform template will represent this using a {@link ProgressBar}.
1087         */
1088        public Builder setProgress(int max, int progress, boolean indeterminate) {
1089            mProgressMax = max;
1090            mProgress = progress;
1091            mProgressIndeterminate = indeterminate;
1092            return this;
1093        }
1094
1095        /**
1096         * Supply a custom RemoteViews to use instead of the platform template.
1097         *
1098         * @see Notification#contentView
1099         */
1100        public Builder setContent(RemoteViews views) {
1101            mContentView = views;
1102            return this;
1103        }
1104
1105        /**
1106         * Supply a {@link PendingIntent} to be sent when the notification is clicked.
1107         *
1108         * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
1109         * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
1110         * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
1111         * to assign PendingIntents to individual views in that custom layout (i.e., to create
1112         * clickable buttons inside the notification view).
1113         *
1114         * @see Notification#contentIntent Notification.contentIntent
1115         */
1116        public Builder setContentIntent(PendingIntent intent) {
1117            mContentIntent = intent;
1118            return this;
1119        }
1120
1121        /**
1122         * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
1123         *
1124         * @see Notification#deleteIntent
1125         */
1126        public Builder setDeleteIntent(PendingIntent intent) {
1127            mDeleteIntent = intent;
1128            return this;
1129        }
1130
1131        /**
1132         * An intent to launch instead of posting the notification to the status bar.
1133         * Only for use with extremely high-priority notifications demanding the user's
1134         * <strong>immediate</strong> attention, such as an incoming phone call or
1135         * alarm clock that the user has explicitly set to a particular time.
1136         * If this facility is used for something else, please give the user an option
1137         * to turn it off and use a normal notification, as this can be extremely
1138         * disruptive.
1139         *
1140         * @param intent The pending intent to launch.
1141         * @param highPriority Passing true will cause this notification to be sent
1142         *          even if other notifications are suppressed.
1143         *
1144         * @see Notification#fullScreenIntent
1145         */
1146        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
1147            mFullScreenIntent = intent;
1148            setFlag(FLAG_HIGH_PRIORITY, highPriority);
1149            return this;
1150        }
1151
1152        /**
1153         * Set the "ticker" text which is displayed in the status bar when the notification first
1154         * arrives.
1155         *
1156         * @see Notification#tickerText
1157         */
1158        public Builder setTicker(CharSequence tickerText) {
1159            mTickerText = tickerText;
1160            return this;
1161        }
1162
1163        /**
1164         * Set the text that is displayed in the status bar when the notification first
1165         * arrives, and also a RemoteViews object that may be displayed instead on some
1166         * devices.
1167         *
1168         * @see Notification#tickerText
1169         * @see Notification#tickerView
1170         */
1171        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
1172            mTickerText = tickerText;
1173            mTickerView = views;
1174            return this;
1175        }
1176
1177        /**
1178         * Add a large icon to the notification (and the ticker on some devices).
1179         *
1180         * In the platform template, this image will be shown on the left of the notification view
1181         * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side).
1182         *
1183         * @see Notification#largeIcon
1184         */
1185        public Builder setLargeIcon(Bitmap icon) {
1186            mLargeIcon = icon;
1187            return this;
1188        }
1189
1190        /**
1191         * Set the sound to play.
1192         *
1193         * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications.
1194         *
1195         * @see Notification#sound
1196         */
1197        public Builder setSound(Uri sound) {
1198            mSound = sound;
1199            mAudioStreamType = STREAM_DEFAULT;
1200            return this;
1201        }
1202
1203        /**
1204         * Set the sound to play, along with a specific stream on which to play it.
1205         *
1206         * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
1207         *
1208         * @see Notification#sound
1209         */
1210        public Builder setSound(Uri sound, int streamType) {
1211            mSound = sound;
1212            mAudioStreamType = streamType;
1213            return this;
1214        }
1215
1216        /**
1217         * Set the vibration pattern to use.
1218         *
1219
1220         * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
1221         * <code>pattern</code> parameter.
1222         *
1223
1224         * @see Notification#vibrate
1225         */
1226        public Builder setVibrate(long[] pattern) {
1227            mVibrate = pattern;
1228            return this;
1229        }
1230
1231        /**
1232         * Set the desired color for the indicator LED on the device, as well as the
1233         * blink duty cycle (specified in milliseconds).
1234         *
1235
1236         * Not all devices will honor all (or even any) of these values.
1237         *
1238
1239         * @see Notification#ledARGB
1240         * @see Notification#ledOnMS
1241         * @see Notification#ledOffMS
1242         */
1243        public Builder setLights(int argb, int onMs, int offMs) {
1244            mLedArgb = argb;
1245            mLedOnMs = onMs;
1246            mLedOffMs = offMs;
1247            return this;
1248        }
1249
1250        /**
1251         * Set whether this is an "ongoing" notification.
1252         *
1253
1254         * Ongoing notifications cannot be dismissed by the user, so your application or service
1255         * must take care of canceling them.
1256         *
1257
1258         * They are typically used to indicate a background task that the user is actively engaged
1259         * with (e.g., playing music) or is pending in some way and therefore occupying the device
1260         * (e.g., a file download, sync operation, active network connection).
1261         *
1262
1263         * @see Notification#FLAG_ONGOING_EVENT
1264         * @see Service#setForeground(boolean)
1265         */
1266        public Builder setOngoing(boolean ongoing) {
1267            setFlag(FLAG_ONGOING_EVENT, ongoing);
1268            return this;
1269        }
1270
1271        /**
1272         * Set this flag if you would only like the sound, vibrate
1273         * and ticker to be played if the notification is not already showing.
1274         *
1275         * @see Notification#FLAG_ONLY_ALERT_ONCE
1276         */
1277        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
1278            setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
1279            return this;
1280        }
1281
1282        /**
1283         * Make this notification automatically dismissed when the user touches it. The
1284         * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
1285         *
1286         * @see Notification#FLAG_AUTO_CANCEL
1287         */
1288        public Builder setAutoCancel(boolean autoCancel) {
1289            setFlag(FLAG_AUTO_CANCEL, autoCancel);
1290            return this;
1291        }
1292
1293        /**
1294         * Set which notification properties will be inherited from system defaults.
1295         * <p>
1296         * The value should be one or more of the following fields combined with
1297         * bitwise-or:
1298         * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
1299         * <p>
1300         * For all default values, use {@link #DEFAULT_ALL}.
1301         */
1302        public Builder setDefaults(int defaults) {
1303            mDefaults = defaults;
1304            return this;
1305        }
1306
1307        /**
1308         * Set the priority of this notification.
1309         *
1310         * @see Notification#priority
1311         */
1312        public Builder setPriority(int pri) {
1313            mPriority = pri;
1314            return this;
1315        }
1316
1317        /**
1318         * Add a kind (category) to this notification. Optional.
1319         *
1320         * @see Notification#kind
1321         */
1322        public Builder addKind(String k) {
1323            mKindList.add(k);
1324            return this;
1325        }
1326
1327        /**
1328         * Add metadata to this notification.
1329         *
1330         * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
1331         * current contents are copied into the Notification each time {@link #getNotification()} is
1332         * called.
1333         *
1334         * @see Notification#extras
1335         * @hide
1336         */
1337        public Builder setExtras(Bundle bag) {
1338            mExtras = bag;
1339            return this;
1340        }
1341
1342        /**
1343         * Add an action to this notification. Actions are typically displayed by
1344         * the system as a button adjacent to the notification content.
1345         *
1346         * @param icon Resource ID of a drawable that represents the action.
1347         * @param title Text describing the action.
1348         * @param intent PendingIntent to be fired when the action is invoked.
1349         */
1350        public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
1351            mActions.add(new Action(icon, title, intent));
1352            return this;
1353        }
1354
1355        /**
1356         * Specify whether this notification should pop up as an
1357         * "intruder alert" (a small window that shares the screen with the
1358         * current activity). This sort of notification is (as the name implies)
1359         * very intrusive, so use it sparingly for notifications that require
1360         * the user's attention.
1361         *
1362         * Notes:
1363         * <ul>
1364         * <li>Intruder alerts only show when the screen is on.</li>
1365         * <li>Intruder alerts take precedence over fullScreenIntents.</li>
1366         * </ul>
1367         *
1368         * @param intrude Whether to pop up an intruder alert (default false).
1369         */
1370        public Builder setUsesIntruderAlert(boolean intrude) {
1371            mCanHasIntruder = intrude;
1372            return this;
1373        }
1374
1375        /**
1376         * Control text on intruder alert action buttons. By default, action
1377         * buttons in intruders do not show textual labels.
1378         *
1379         * @param showActionText Whether to show text labels beneath action
1380         *            icons (default false).
1381         */
1382        public Builder setIntruderActionsShowText(boolean showActionText) {
1383            mIntruderActionsShowText = showActionText;
1384            return this;
1385        }
1386
1387        private void setFlag(int mask, boolean value) {
1388            if (value) {
1389                mFlags |= mask;
1390            } else {
1391                mFlags &= ~mask;
1392            }
1393        }
1394
1395        private RemoteViews applyStandardTemplate(int resId) {
1396            RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
1397            boolean hasLine3 = false;
1398            boolean hasLine2 = false;
1399            int smallIconImageViewId = R.id.icon;
1400            if (mLargeIcon != null) {
1401                contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
1402                smallIconImageViewId = R.id.right_icon;
1403            }
1404            if (mSmallIcon != 0) {
1405                contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
1406                contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
1407            } else {
1408                contentView.setViewVisibility(smallIconImageViewId, View.GONE);
1409            }
1410            if (mContentTitle != null) {
1411                contentView.setTextViewText(R.id.title, mContentTitle);
1412            }
1413            if (mContentText != null) {
1414                contentView.setTextViewText(
1415                        (mSubText != null) ? R.id.text2 : R.id.text,
1416                        mContentText);
1417                hasLine3 = true;
1418            }
1419            if (mContentInfo != null) {
1420                contentView.setTextViewText(R.id.info, mContentInfo);
1421                contentView.setViewVisibility(R.id.info, View.VISIBLE);
1422                hasLine3 = true;
1423            } else if (mNumber > 0) {
1424                final int tooBig = mContext.getResources().getInteger(
1425                        R.integer.status_bar_notification_info_maxnum);
1426                if (mNumber > tooBig) {
1427                    contentView.setTextViewText(R.id.info, mContext.getResources().getString(
1428                                R.string.status_bar_notification_info_overflow));
1429                } else {
1430                    NumberFormat f = NumberFormat.getIntegerInstance();
1431                    contentView.setTextViewText(R.id.info, f.format(mNumber));
1432                }
1433                contentView.setViewVisibility(R.id.info, View.VISIBLE);
1434                hasLine3 = true;
1435            } else {
1436                contentView.setViewVisibility(R.id.info, View.GONE);
1437            }
1438
1439            if (mSubText != null) {
1440                contentView.setTextViewText(R.id.text, mSubText);
1441                contentView.setViewVisibility(R.id.text2, View.VISIBLE);
1442            } else {
1443                contentView.setViewVisibility(R.id.text2, View.GONE);
1444                if (mProgressMax != 0 || mProgressIndeterminate) {
1445                    contentView.setProgressBar(
1446                            R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
1447                    contentView.setViewVisibility(R.id.progress, View.VISIBLE);
1448                } else {
1449                    contentView.setViewVisibility(R.id.progress, View.GONE);
1450                }
1451            }
1452            if (mWhen != 0) {
1453                if (mUseChronometer) {
1454                    contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
1455                    contentView.setLong(R.id.chronometer, "setBase",
1456                            mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
1457                    contentView.setBoolean(R.id.chronometer, "setStarted", true);
1458                } else {
1459                    contentView.setViewVisibility(R.id.time, View.VISIBLE);
1460                    contentView.setLong(R.id.time, "setTime", mWhen);
1461                }
1462            }
1463            contentView.setViewVisibility(R.id.line3, hasLine3 ? View.VISIBLE : View.GONE);
1464            return contentView;
1465        }
1466
1467        private RemoteViews applyStandardTemplateWithActions(int layoutId) {
1468            RemoteViews big = applyStandardTemplate(layoutId);
1469
1470            int N = mActions.size();
1471            if (N > 0) {
1472                Log.d("Notification", "has actions: " + mContentText);
1473                big.setViewVisibility(R.id.actions, View.VISIBLE);
1474                if (N>3) N=3;
1475                for (int i=0; i<N; i++) {
1476                    final RemoteViews button = generateActionButton(mActions.get(i));
1477                    Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
1478                    big.addView(R.id.actions, button);
1479                }
1480            }
1481            return big;
1482        }
1483
1484        private RemoteViews makeContentView() {
1485            if (mContentView != null) {
1486                return mContentView;
1487            } else {
1488                return applyStandardTemplate(R.layout.notification_template_base); // no more special large_icon flavor
1489            }
1490        }
1491
1492        private RemoteViews makeTickerView() {
1493            if (mTickerView != null) {
1494                return mTickerView;
1495            } else {
1496                if (mContentView == null) {
1497                    return applyStandardTemplate(mLargeIcon == null
1498                            ? R.layout.status_bar_latest_event_ticker
1499                            : R.layout.status_bar_latest_event_ticker_large_icon);
1500                } else {
1501                    return null;
1502                }
1503            }
1504        }
1505
1506        private RemoteViews makeBigContentView() {
1507            if (mActions.size() == 0) return null;
1508
1509            return applyStandardTemplateWithActions(R.layout.notification_template_base);
1510        }
1511
1512        private RemoteViews makeIntruderView(boolean showLabels) {
1513            RemoteViews intruderView = new RemoteViews(mContext.getPackageName(),
1514                    R.layout.notification_intruder_content);
1515            if (mLargeIcon != null) {
1516                intruderView.setImageViewBitmap(R.id.icon, mLargeIcon);
1517                intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
1518            } else if (mSmallIcon != 0) {
1519                intruderView.setImageViewResource(R.id.icon, mSmallIcon);
1520                intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
1521            } else {
1522                intruderView.setViewVisibility(R.id.icon, View.GONE);
1523            }
1524            if (mContentTitle != null) {
1525                intruderView.setTextViewText(R.id.title, mContentTitle);
1526            }
1527            if (mContentText != null) {
1528                intruderView.setTextViewText(R.id.text, mContentText);
1529            }
1530            if (mActions.size() > 0) {
1531                intruderView.setViewVisibility(R.id.actions, View.VISIBLE);
1532                int N = mActions.size();
1533                if (N>3) N=3;
1534                final int[] BUTTONS = { R.id.action0, R.id.action1, R.id.action2 };
1535                for (int i=0; i<N; i++) {
1536                    final Action action = mActions.get(i);
1537                    final int buttonId = BUTTONS[i];
1538
1539                    intruderView.setViewVisibility(buttonId, View.VISIBLE);
1540                    intruderView.setTextViewText(buttonId, showLabels ? action.title : null);
1541                    intruderView.setTextViewCompoundDrawables(buttonId, 0, action.icon, 0, 0);
1542                    intruderView.setContentDescription(buttonId, action.title);
1543                    intruderView.setOnClickPendingIntent(buttonId, action.actionIntent);
1544                }
1545            } else {
1546                intruderView.setViewVisibility(R.id.actions, View.GONE);
1547            }
1548            return intruderView;
1549        }
1550
1551        private RemoteViews generateActionButton(Action action) {
1552            RemoteViews button = new RemoteViews(mContext.getPackageName(), R.layout.notification_action);
1553            button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0);
1554            button.setTextViewText(R.id.action0, action.title);
1555            button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
1556            button.setContentDescription(R.id.action0, action.title);
1557            return button;
1558        }
1559
1560        /**
1561         * Combine all of the options that have been set and return a new {@link Notification}
1562         * object.
1563         */
1564        public Notification getNotification() {
1565            Notification n = new Notification();
1566            n.when = mWhen;
1567            n.icon = mSmallIcon;
1568            n.iconLevel = mSmallIconLevel;
1569            n.number = mNumber;
1570            n.contentView = makeContentView();
1571            n.contentIntent = mContentIntent;
1572            n.deleteIntent = mDeleteIntent;
1573            n.fullScreenIntent = mFullScreenIntent;
1574            n.tickerText = mTickerText;
1575            n.tickerView = makeTickerView();
1576            n.largeIcon = mLargeIcon;
1577            n.sound = mSound;
1578            n.audioStreamType = mAudioStreamType;
1579            n.vibrate = mVibrate;
1580            n.ledARGB = mLedArgb;
1581            n.ledOnMS = mLedOnMs;
1582            n.ledOffMS = mLedOffMs;
1583            n.defaults = mDefaults;
1584            n.flags = mFlags;
1585            if (mCanHasIntruder) {
1586                n.intruderView = makeIntruderView(mIntruderActionsShowText);
1587            }
1588            n.bigContentView = makeBigContentView();
1589            if (mLedOnMs != 0 && mLedOffMs != 0) {
1590                n.flags |= FLAG_SHOW_LIGHTS;
1591            }
1592            if ((mDefaults & DEFAULT_LIGHTS) != 0) {
1593                n.flags |= FLAG_SHOW_LIGHTS;
1594            }
1595            if (mKindList.size() > 0) {
1596                n.kind = new String[mKindList.size()];
1597                mKindList.toArray(n.kind);
1598            } else {
1599                n.kind = null;
1600            }
1601            n.priority = mPriority;
1602            n.extras = mExtras != null ? new Bundle(mExtras) : null;
1603            if (mActions.size() > 0) {
1604                n.actions = new Action[mActions.size()];
1605                mActions.toArray(n.actions);
1606            }
1607            return n;
1608        }
1609    }
1610
1611    /**
1612     * @hide because this API is still very rough
1613     *
1614     * This is a "rebuilder": It consumes a Builder object and modifies its output.
1615     *
1616     * This represents the "big picture" style notification, with a large Bitmap atop the usual notification.
1617     *
1618     * Usage:
1619     * <pre class="prettyprint">
1620     * Notification noti = new Notification.BigPictureStyle(
1621     *      new Notification.Builder()
1622     *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
1623     *         .setContentText(subject)
1624     *         .setSmallIcon(R.drawable.new_mail)
1625     *         .setLargeIcon(aBitmap))
1626     *      .bigPicture(aBigBitmap)
1627     *      .build();
1628     * </pre>
1629     */
1630    public static class BigPictureStyle {
1631        private Builder mBuilder;
1632        private Bitmap mPicture;
1633
1634        public BigPictureStyle(Builder builder) {
1635            mBuilder = builder;
1636        }
1637
1638        public BigPictureStyle bigPicture(Bitmap b) {
1639            mPicture = b;
1640            return this;
1641        }
1642
1643        private RemoteViews makeBigContentView() {
1644            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_big_picture);
1645
1646            contentView.setImageViewBitmap(R.id.big_picture, mPicture);
1647
1648            return contentView;
1649        }
1650
1651        public Notification build() {
1652            Notification wip = mBuilder.getNotification();
1653            wip.bigContentView = makeBigContentView();
1654            return wip;
1655        }
1656    }
1657
1658    /**
1659     * @hide because this API is still very rough
1660     *
1661     * This is a "rebuilder": It consumes a Builder object and modifies its output.
1662     *
1663     * This represents the "big text" style notification, with more area for the main content text to be read in its entirety.
1664     *
1665     * Usage:
1666     * <pre class="prettyprint">
1667     * Notification noti = new Notification.BigPictureStyle(
1668     *      new Notification.Builder()
1669     *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
1670     *         .setContentText(subject)
1671     *         .setSmallIcon(R.drawable.new_mail)
1672     *         .setLargeIcon(aBitmap))
1673     *      .bigText(aVeryLongString)
1674     *      .build();
1675     * </pre>
1676     */
1677    public static class BigTextStyle {
1678        private Builder mBuilder;
1679        private CharSequence mBigText;
1680
1681        public BigTextStyle(Builder builder) {
1682            mBuilder = builder;
1683        }
1684
1685        public BigTextStyle bigText(CharSequence cs) {
1686            mBigText = cs;
1687            return this;
1688        }
1689
1690        private RemoteViews makeBigContentView() {
1691            RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_base);
1692
1693            contentView.setTextViewText(R.id.big_text, mBigText);
1694            contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
1695            contentView.setTextViewText(R.id.text, ""); // XXX: what do do with this spot?
1696
1697            return contentView;
1698        }
1699
1700        public Notification build() {
1701            Notification wip = mBuilder.getNotification();
1702            wip.bigContentView = makeBigContentView();
1703            return wip;
1704        }
1705    }
1706}
1707