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