NotificationCompat.java revision 708b75c6599afe1a215b07458e940fe3ca13622a
1/*
2 * Copyright (C) 2012 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.support.v4.app;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.Context;
23import android.graphics.Bitmap;
24import android.graphics.Color;
25import android.media.AudioManager;
26import android.net.Uri;
27import android.os.Build;
28import android.os.Bundle;
29import android.widget.RemoteViews;
30
31import java.util.ArrayList;
32
33/**
34 * Helper for accessing features in {@link android.app.Notification}
35 * introduced after API level 4 in a backwards compatible fashion.
36 */
37public class NotificationCompat {
38
39    /**
40     * Use all default values (where applicable).
41     */
42    public static final int DEFAULT_ALL = ~0;
43
44    /**
45     * Use the default notification sound. This will ignore any sound set using
46     * {@link Builder#setSound}
47     *
48     * @see Builder#setDefaults
49     */
50    public static final int DEFAULT_SOUND = 1;
51
52    /**
53     * Use the default notification vibrate. This will ignore any vibrate set using
54     * {@link Builder#setVibrate}. Using phone vibration requires the
55     * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
56     *
57     * @see Builder#setDefaults
58     */
59    public static final int DEFAULT_VIBRATE = 2;
60
61    /**
62     * Use the default notification lights. This will ignore the
63     * {@link #FLAG_SHOW_LIGHTS} bit, and values set with {@link Builder#setLights}.
64     *
65     * @see Builder#setDefaults
66     */
67    public static final int DEFAULT_LIGHTS = 4;
68
69    /**
70     * Use this constant as the value for audioStreamType to request that
71     * the default stream type for notifications be used.  Currently the
72     * default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
73     */
74    public static final int STREAM_DEFAULT = -1;
75
76    /**
77     * Bit set in the Notification flags field when LEDs should be turned on
78     * for this notification.
79     */
80    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
81
82    /**
83     * Bit set in the Notification flags field if this notification is in
84     * reference to something that is ongoing, like a phone call.  It should
85     * not be set if this notification is in reference to something that
86     * happened at a particular point in time, like a missed phone call.
87     */
88    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
89
90    /**
91     * Bit set in the Notification flags field if
92     * the audio will be repeated until the notification is
93     * cancelled or the notification window is opened.
94     */
95    public static final int FLAG_INSISTENT          = 0x00000004;
96
97    /**
98     * Bit set in the Notification flags field if the notification's sound,
99     * vibrate and ticker should only be played if the notification is not already showing.
100     */
101    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
102
103    /**
104     * Bit set in the Notification flags field if the notification should be canceled when
105     * it is clicked by the user.
106     */
107    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
108
109    /**
110     * Bit set in the Notification flags field if the notification should not be canceled
111     * when the user clicks the Clear all button.
112     */
113    public static final int FLAG_NO_CLEAR           = 0x00000020;
114
115    /**
116     * Bit set in the Notification flags field if this notification represents a currently
117     * running service.  This will normally be set for you by
118     * {@link android.app.Service#startForeground}.
119     */
120    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
121
122    /**
123     * Obsolete flag indicating high-priority notifications; use the priority field instead.
124     *
125     * @deprecated Use {@link NotificationCompat.Builder#setPriority(int)} with a positive value.
126     */
127    public static final int FLAG_HIGH_PRIORITY = 0x00000080;
128
129    /**
130     * Default notification priority for {@link NotificationCompat.Builder#setPriority(int)}.
131     * If your application does not prioritize its own notifications,
132     * use this value for all notifications.
133     */
134    public static final int PRIORITY_DEFAULT = 0;
135
136    /**
137     * Lower notification priority for {@link NotificationCompat.Builder#setPriority(int)},
138     * for items that are less important. The UI may choose to show
139     * these items smaller, or at a different position in the list,
140     * compared with your app's {@link #PRIORITY_DEFAULT} items.
141     */
142    public static final int PRIORITY_LOW = -1;
143
144    /**
145     * Lowest notification priority for {@link NotificationCompat.Builder#setPriority(int)};
146     * these items might not be shown to the user except under
147     * special circumstances, such as detailed notification logs.
148     */
149    public static final int PRIORITY_MIN = -2;
150
151    /**
152     * Higher notification priority for {@link NotificationCompat.Builder#setPriority(int)},
153     * for more important notifications or alerts. The UI may choose
154     * to show these items larger, or at a different position in
155     * notification lists, compared with your app's {@link #PRIORITY_DEFAULT} items.
156     */
157    public static final int PRIORITY_HIGH = 1;
158
159    /**
160     * Highest notification priority for {@link NotificationCompat.Builder#setPriority(int)},
161     * for your application's most important items that require the user's
162     * prompt attention or input.
163     */
164    public static final int PRIORITY_MAX = 2;
165
166    /**
167     * Notification extras key: this is the title of the notification,
168     * as supplied to {@link Builder#setContentTitle(CharSequence)}.
169     */
170    public static final String EXTRA_TITLE = "android.title";
171
172    /**
173     * Notification extras key: this is the title of the notification when shown in expanded form,
174     * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
175     */
176    public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
177
178    /**
179     * Notification extras key: this is the main text payload, as supplied to
180     * {@link Builder#setContentText(CharSequence)}.
181     */
182    public static final String EXTRA_TEXT = "android.text";
183
184    /**
185     * Notification extras key: this is a third line of text, as supplied to
186     * {@link Builder#setSubText(CharSequence)}.
187     */
188    public static final String EXTRA_SUB_TEXT = "android.subText";
189
190    /**
191     * Notification extras key: this is a small piece of additional text as supplied to
192     * {@link Builder#setContentInfo(CharSequence)}.
193     */
194    public static final String EXTRA_INFO_TEXT = "android.infoText";
195
196    /**
197     * Notification extras key: this is a line of summary information intended to be shown
198     * alongside expanded notifications, as supplied to (e.g.)
199     * {@link BigTextStyle#setSummaryText(CharSequence)}.
200     */
201    public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
202
203    /**
204     * Notification extras key: this is the resource ID of the notification's main small icon, as
205     * supplied to {@link Builder#setSmallIcon(int)}.
206     */
207    public static final String EXTRA_SMALL_ICON = "android.icon";
208
209    /**
210     * Notification extras key: this is a bitmap to be used instead of the small icon when showing the
211     * notification payload, as
212     * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
213     */
214    public static final String EXTRA_LARGE_ICON = "android.largeIcon";
215
216    /**
217     * Notification extras key: this is a bitmap to be used instead of the one from
218     * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
219     * shown in its expanded form, as supplied to
220     * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
221     */
222    public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
223
224    /**
225     * Notification extras key: this is the progress value supplied to
226     * {@link Builder#setProgress(int, int, boolean)}.
227     */
228    public static final String EXTRA_PROGRESS = "android.progress";
229
230    /**
231     * Notification extras key: this is the maximum value supplied to
232     * {@link Builder#setProgress(int, int, boolean)}.
233     */
234    public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
235
236    /**
237     * Notification extras key: whether the progress bar is indeterminate, supplied to
238     * {@link Builder#setProgress(int, int, boolean)}.
239     */
240    public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
241
242    /**
243     * Notification extras key: whether the when field set using {@link Builder#setWhen} should
244     * be shown as a count-up timer (specifically a {@link android.widget.Chronometer}) instead
245     * of a timestamp, as supplied to {@link Builder#setUsesChronometer(boolean)}.
246     */
247    public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
248
249    /**
250     * Notification extras key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
251     * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
252     */
253    public static final String EXTRA_PICTURE = "android.picture";
254
255    /**
256     * Notification extras key: An array of CharSequences to show in {@link InboxStyle} expanded
257     * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
258     */
259    public static final String EXTRA_TEXT_LINES = "android.textLines";
260
261    /**
262     * Notification extras key: An array of people that this notification relates to, specified
263     * by contacts provider contact URI.
264     */
265    public static final String EXTRA_PEOPLE = "android.people";
266
267    /**
268     * Value of {@link Notification#color} equal to 0 (also known as
269     * {@link android.graphics.Color#TRANSPARENT Color.TRANSPARENT}),
270     * telling the system not to decorate this notification with any special color but instead use
271     * default colors when presenting this notification.
272     */
273    public static final int COLOR_DEFAULT = Color.TRANSPARENT;
274
275    /**
276     * Notification visibility: Show this notification in its entirety on all lockscreens.
277     *
278     * {@see android.app.Notification#visibility}
279     */
280    public static final int VISIBILITY_PUBLIC = 1;
281
282    /**
283     * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or
284     * private information on secure lockscreens.
285     *
286     * {@see android.app.Notification#visibility}
287     */
288    public static final int VISIBILITY_PRIVATE = 0;
289
290    /**
291     * Notification visibility: Do not reveal any part of this notification on a secure lockscreen.
292     *
293     * {@see android.app.Notification#visibility}
294     */
295    public static final int VISIBILITY_SECRET = -1;
296
297    private static final NotificationCompatImpl IMPL;
298
299    interface NotificationCompatImpl {
300        public Notification build(Builder b);
301        public Bundle getExtras(Notification n);
302        public int getActionCount(Notification n);
303        public Action getAction(Notification n, int actionIndex);
304        public boolean getLocalOnly(Notification n);
305    }
306
307    static class NotificationCompatImplBase implements NotificationCompatImpl {
308        @Override
309        public Notification build(Builder b) {
310            Notification result = b.mNotification;
311            result.setLatestEventInfo(b.mContext, b.mContentTitle,
312                    b.mContentText, b.mContentIntent);
313            // translate high priority requests into legacy flag
314            if (b.mPriority > PRIORITY_DEFAULT) {
315                result.flags |= FLAG_HIGH_PRIORITY;
316            }
317            return result;
318        }
319
320        @Override
321        public Bundle getExtras(Notification n) {
322            return null;
323        }
324
325        @Override
326        public int getActionCount(Notification n) {
327            return 0;
328        }
329
330        @Override
331        public Action getAction(Notification n, int actionIndex) {
332            return null;
333        }
334
335        @Override
336        public boolean getLocalOnly(Notification n) {
337            return false;
338        }
339    }
340
341    static class NotificationCompatImplGingerbread extends NotificationCompatImplBase {
342        @Override
343        public Notification build(Builder b) {
344            Notification result = b.mNotification;
345            result.setLatestEventInfo(b.mContext, b.mContentTitle,
346                    b.mContentText, b.mContentIntent);
347            result = NotificationCompatGingerbread.add(result, b.mContext,
348                    b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent);
349            // translate high priority requests into legacy flag
350            if (b.mPriority > PRIORITY_DEFAULT) {
351                result.flags |= FLAG_HIGH_PRIORITY;
352            }
353            return result;
354        }
355    }
356
357    static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase {
358        @Override
359        public Notification build(Builder b) {
360            return NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
361                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
362                    b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
363        }
364    }
365
366    static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase {
367        @Override
368        public Notification build(Builder b) {
369            return NotificationCompatIceCreamSandwich.add(b.mContext, b.mNotification,
370                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
371                    b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
372                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
373        }
374    }
375
376    static class NotificationCompatImplJellybean extends NotificationCompatImplBase {
377        @Override
378        public Notification build(Builder b) {
379            NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
380                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
381                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
382                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
383                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras);
384            addActionsToBuilder(builder, b.mActions);
385            addStyleToBuilderJellybean(builder, b.mStyle);
386            return builder.build();
387        }
388
389        @Override
390        public Bundle getExtras(Notification n) {
391            return NotificationCompatJellybean.getExtras(n);
392        }
393
394        @Override
395        public int getActionCount(Notification n) {
396            return NotificationCompatJellybean.getActionCount(n);
397        }
398
399        @Override
400        public Action getAction(Notification n, int actionIndex) {
401            NotificationActionHolderImpl holder = new NotificationActionHolderImpl();
402            NotificationCompatJellybean.getAction(n, actionIndex, holder);
403            return holder.get();
404        }
405
406        @Override
407        public boolean getLocalOnly(Notification n) {
408            return NotificationCompatJellybean.getLocalOnly(n);
409        }
410    }
411
412    static class NotificationCompatImplKitKat extends NotificationCompatImplBase {
413        @Override
414        public Notification build(Builder b) {
415            NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
416                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
417                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
418                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
419                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras);
420            addActionsToBuilder(builder, b.mActions);
421            addStyleToBuilderJellybean(builder, b.mStyle);
422            return builder.build();
423        }
424
425        @Override
426        public Bundle getExtras(Notification n) {
427            return NotificationCompatKitKat.getExtras(n);
428        }
429
430        @Override
431        public int getActionCount(Notification n) {
432            return NotificationCompatKitKat.getActionCount(n);
433        }
434
435        @Override
436        public Action getAction(Notification n, int actionIndex) {
437            NotificationActionHolderImpl holder = new NotificationActionHolderImpl();
438            NotificationCompatKitKat.getAction(n, actionIndex, holder);
439            return holder.get();
440        }
441
442        @Override
443        public boolean getLocalOnly(Notification n) {
444            return NotificationCompatKitKat.getLocalOnly(n);
445        }
446    }
447
448    static class NotificationCompatImplApi20 extends NotificationCompatImplBase {
449        @Override
450        public Notification build(Builder b) {
451            NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
452                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
453                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
454                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
455                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
456                    b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion);
457            addActionsToBuilder(builder, b.mActions);
458            addStyleToBuilderJellybean(builder, b.mStyle);
459            return builder.build();
460        }
461
462        @Override
463        public Bundle getExtras(Notification n) {
464            return NotificationCompatKitKat.getExtras(n);
465        }
466
467        @Override
468        public int getActionCount(Notification n) {
469            return NotificationCompatKitKat.getActionCount(n);
470        }
471
472        @Override
473        public Action getAction(Notification n, int actionIndex) {
474            NotificationActionHolderImpl holder = new NotificationActionHolderImpl();
475            NotificationCompatApi20.getAction(n, actionIndex, holder);
476            return holder.get();
477        }
478
479        @Override
480        public boolean getLocalOnly(Notification n) {
481            return NotificationCompatApi20.getLocalOnly(n);
482        }
483    }
484
485    private static void addActionsToBuilder(NotificationBuilderWithActions builder,
486            ArrayList<Action> actions) {
487        for (Action action : actions) {
488            builder.addAction(action.icon, action.title, action.actionIntent, action.getExtras());
489        }
490    }
491
492    private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder,
493            Style style) {
494        if (style != null) {
495            if (style instanceof BigTextStyle) {
496                BigTextStyle bigTextStyle = (BigTextStyle) style;
497                NotificationCompatJellybean.addBigTextStyle(builder,
498                        bigTextStyle.mBigContentTitle,
499                        bigTextStyle.mSummaryTextSet,
500                        bigTextStyle.mSummaryText,
501                        bigTextStyle.mBigText);
502            } else if (style instanceof InboxStyle) {
503                InboxStyle inboxStyle = (InboxStyle) style;
504                NotificationCompatJellybean.addInboxStyle(builder,
505                        inboxStyle.mBigContentTitle,
506                        inboxStyle.mSummaryTextSet,
507                        inboxStyle.mSummaryText,
508                        inboxStyle.mTexts);
509            } else if (style instanceof BigPictureStyle) {
510                BigPictureStyle bigPictureStyle = (BigPictureStyle) style;
511                NotificationCompatJellybean.addBigPictureStyle(builder,
512                        bigPictureStyle.mBigContentTitle,
513                        bigPictureStyle.mSummaryTextSet,
514                        bigPictureStyle.mSummaryText,
515                        bigPictureStyle.mPicture,
516                        bigPictureStyle.mBigLargeIcon,
517                        bigPictureStyle.mBigLargeIconSet);
518            }
519        }
520    }
521
522    static {
523        // TODO: Replace this if clause when SDK_INT is incremented to 20.
524        if (Build.VERSION.RELEASE.equals("L")) {
525            IMPL = new NotificationCompatImplApi20();
526        } else if (Build.VERSION.SDK_INT >= 19) {
527            IMPL = new NotificationCompatImplKitKat();
528        } else if (Build.VERSION.SDK_INT >= 16) {
529            IMPL = new NotificationCompatImplJellybean();
530        } else if (Build.VERSION.SDK_INT >= 14) {
531            IMPL = new NotificationCompatImplIceCreamSandwich();
532        } else if (Build.VERSION.SDK_INT >= 11) {
533            IMPL = new NotificationCompatImplHoneycomb();
534        } else if (Build.VERSION.SDK_INT >= 9) {
535            IMPL = new NotificationCompatImplGingerbread();
536        } else {
537            IMPL = new NotificationCompatImplBase();
538        }
539    }
540
541    /**
542     * Builder class for {@link NotificationCompat} objects.  Allows easier control over
543     * all the flags, as well as help constructing the typical notification layouts.
544     * <p>
545     * On platform versions that don't offer expanded notifications, methods that depend on
546     * expanded notifications have no effect.
547     * </p>
548     * <p>
549     * For example, action buttons won't appear on platforms prior to Android 4.1. Action
550     * buttons depend on expanded notifications, which are only available in Android 4.1
551     * and later.
552     * <p>
553     * For this reason, you should always ensure that UI controls in a notification are also
554     * available in an {@link android.app.Activity} in your app, and you should always start that
555     * {@link android.app.Activity} when users click the notification. To do this, use the
556     * {@link NotificationCompat.Builder#setContentIntent setContentIntent()}
557     * method.
558     * </p>
559     *
560     */
561    public static class Builder {
562        Context mContext;
563
564        CharSequence mContentTitle;
565        CharSequence mContentText;
566        PendingIntent mContentIntent;
567        PendingIntent mFullScreenIntent;
568        RemoteViews mTickerView;
569        Bitmap mLargeIcon;
570        CharSequence mContentInfo;
571        int mNumber;
572        int mPriority;
573        boolean mUseChronometer;
574        Style mStyle;
575        CharSequence mSubText;
576        int mProgressMax;
577        int mProgress;
578        boolean mProgressIndeterminate;
579        ArrayList<Action> mActions = new ArrayList<Action>();
580        boolean mLocalOnly = false;
581        String mCategory;
582        Bundle mExtras;
583        int mColor = COLOR_DEFAULT;
584        int mVisibility = VISIBILITY_PRIVATE;
585        Notification mPublicVersion;
586
587        Notification mNotification = new Notification();
588        public ArrayList<String> mPeople;
589
590        /**
591         * Constructor.
592         *
593         * Automatically sets the when field to {@link System#currentTimeMillis()
594         * System.currentTimeMillis()} and the audio stream to the
595         * {@link Notification#STREAM_DEFAULT}.
596         *
597         * @param context A {@link Context} that will be used to construct the
598         *      RemoteViews. The Context will not be held past the lifetime of this
599         *      Builder object.
600         */
601        public Builder(Context context) {
602            mContext = context;
603
604            // Set defaults to match the defaults of a Notification
605            mNotification.when = System.currentTimeMillis();
606            mNotification.audioStreamType = Notification.STREAM_DEFAULT;
607            mPriority = PRIORITY_DEFAULT;
608            mPeople = new ArrayList<String>();
609        }
610
611        /**
612         * Set the time that the event occurred.  Notifications in the panel are
613         * sorted by this time.
614         */
615        public Builder setWhen(long when) {
616            mNotification.when = when;
617            return this;
618        }
619
620        /**
621         * Show the {@link Notification#when} field as a stopwatch.
622         *
623         * Instead of presenting <code>when</code> as a timestamp, the notification will show an
624         * automatically updating display of the minutes and seconds since <code>when</code>.
625         *
626         * Useful when showing an elapsed time (like an ongoing phone call).
627         *
628         * @see android.widget.Chronometer
629         * @see Notification#when
630         */
631        public Builder setUsesChronometer(boolean b) {
632            mUseChronometer = b;
633            return this;
634        }
635
636        /**
637         * Set the small icon to use in the notification layouts.  Different classes of devices
638         * may return different sizes.  See the UX guidelines for more information on how to
639         * design these icons.
640         *
641         * @param icon A resource ID in the application's package of the drawble to use.
642         */
643        public Builder setSmallIcon(int icon) {
644            mNotification.icon = icon;
645            return this;
646        }
647
648        /**
649         * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
650         * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
651         * LevelListDrawable}.
652         *
653         * @param icon A resource ID in the application's package of the drawble to use.
654         * @param level The level to use for the icon.
655         *
656         * @see android.graphics.drawable.LevelListDrawable
657         */
658        public Builder setSmallIcon(int icon, int level) {
659            mNotification.icon = icon;
660            mNotification.iconLevel = level;
661            return this;
662        }
663
664        /**
665         * Set the title (first row) of the notification, in a standard notification.
666         */
667        public Builder setContentTitle(CharSequence title) {
668            mContentTitle = title;
669            return this;
670        }
671
672        /**
673         * Set the text (second row) of the notification, in a standard notification.
674         */
675        public Builder setContentText(CharSequence text) {
676            mContentText = text;
677            return this;
678        }
679
680        /**
681         * Set the third line of text in the platform notification template.
682         * Don't use if you're also using {@link #setProgress(int, int, boolean)};
683         * they occupy the same location in the standard template.
684         * <br>
685         * If the platform does not provide large-format notifications, this method has no effect.
686         * The third line of text only appears in expanded view.
687         * <br>
688         */
689        public Builder setSubText(CharSequence text) {
690            mSubText = text;
691            return this;
692        }
693
694        /**
695         * Set the large number at the right-hand side of the notification.  This is
696         * equivalent to setContentInfo, although it might show the number in a different
697         * font size for readability.
698         */
699        public Builder setNumber(int number) {
700            mNumber = number;
701            return this;
702        }
703
704        /**
705         * Set the large text at the right-hand side of the notification.
706         */
707        public Builder setContentInfo(CharSequence info) {
708            mContentInfo = info;
709            return this;
710        }
711
712        /**
713         * Set the progress this notification represents, which may be
714         * represented as a {@link android.widget.ProgressBar}.
715         */
716        public Builder setProgress(int max, int progress, boolean indeterminate) {
717            mProgressMax = max;
718            mProgress = progress;
719            mProgressIndeterminate = indeterminate;
720            return this;
721        }
722
723        /**
724         * Supply a custom RemoteViews to use instead of the standard one.
725         */
726        public Builder setContent(RemoteViews views) {
727            mNotification.contentView = views;
728            return this;
729        }
730
731        /**
732         * Supply a {@link PendingIntent} to send when the notification is clicked.
733         * If you do not supply an intent, you can now add PendingIntents to individual
734         * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
735         * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.  Be sure to
736         * read {@link Notification#contentIntent Notification.contentIntent} for
737         * how to correctly use this.
738         */
739        public Builder setContentIntent(PendingIntent intent) {
740            mContentIntent = intent;
741            return this;
742        }
743
744        /**
745         * Supply a {@link PendingIntent} to send when the notification is cleared by the user
746         * directly from the notification panel.  For example, this intent is sent when the user
747         * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
748         * intent is not sent when the application calls {@link NotificationManager#cancel
749         * NotificationManager.cancel(int)}.
750         */
751        public Builder setDeleteIntent(PendingIntent intent) {
752            mNotification.deleteIntent = intent;
753            return this;
754        }
755
756        /**
757         * An intent to launch instead of posting the notification to the status bar.
758         * Only for use with extremely high-priority notifications demanding the user's
759         * <strong>immediate</strong> attention, such as an incoming phone call or
760         * alarm clock that the user has explicitly set to a particular time.
761         * If this facility is used for something else, please give the user an option
762         * to turn it off and use a normal notification, as this can be extremely
763         * disruptive.
764         *
765         * @param intent The pending intent to launch.
766         * @param highPriority Passing true will cause this notification to be sent
767         *          even if other notifications are suppressed.
768         */
769        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
770            mFullScreenIntent = intent;
771            setFlag(FLAG_HIGH_PRIORITY, highPriority);
772            return this;
773        }
774
775        /**
776         * Set the text that is displayed in the status bar when the notification first
777         * arrives.
778         */
779        public Builder setTicker(CharSequence tickerText) {
780            mNotification.tickerText = tickerText;
781            return this;
782        }
783
784        /**
785         * Set the text that is displayed in the status bar when the notification first
786         * arrives, and also a RemoteViews object that may be displayed instead on some
787         * devices.
788         */
789        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
790            mNotification.tickerText = tickerText;
791            mTickerView = views;
792            return this;
793        }
794
795        /**
796         * Set the large icon that is shown in the ticker and notification.
797         */
798        public Builder setLargeIcon(Bitmap icon) {
799            mLargeIcon = icon;
800            return this;
801        }
802
803        /**
804         * Set the sound to play.  It will play on the default stream.
805         */
806        public Builder setSound(Uri sound) {
807            mNotification.sound = sound;
808            mNotification.audioStreamType = Notification.STREAM_DEFAULT;
809            return this;
810        }
811
812        /**
813         * Set the sound to play.  It will play on the stream you supply.
814         *
815         * @see Notification#STREAM_DEFAULT
816         * @see AudioManager for the <code>STREAM_</code> constants.
817         */
818        public Builder setSound(Uri sound, int streamType) {
819            mNotification.sound = sound;
820            mNotification.audioStreamType = streamType;
821            return this;
822        }
823
824        /**
825         * Set the vibration pattern to use.
826         *
827         * @see android.os.Vibrator for a discussion of the <code>pattern</code>
828         * parameter.
829         */
830        public Builder setVibrate(long[] pattern) {
831            mNotification.vibrate = pattern;
832            return this;
833        }
834
835        /**
836         * Set the argb value that you would like the LED on the device to blnk, as well as the
837         * rate.  The rate is specified in terms of the number of milliseconds to be on
838         * and then the number of milliseconds to be off.
839         */
840        public Builder setLights(int argb, int onMs, int offMs) {
841            mNotification.ledARGB = argb;
842            mNotification.ledOnMS = onMs;
843            mNotification.ledOffMS = offMs;
844            boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0;
845            mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) |
846                    (showLights ? Notification.FLAG_SHOW_LIGHTS : 0);
847            return this;
848        }
849
850        /**
851         * Set whether this is an ongoing notification.
852         *
853         * <p>Ongoing notifications differ from regular notifications in the following ways:
854         * <ul>
855         *   <li>Ongoing notifications are sorted above the regular notifications in the
856         *   notification panel.</li>
857         *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
858         *   by the "Clear all" button.
859         * </ul>
860         */
861        public Builder setOngoing(boolean ongoing) {
862            setFlag(Notification.FLAG_ONGOING_EVENT, ongoing);
863            return this;
864        }
865
866        /**
867         * Set this flag if you would only like the sound, vibrate
868         * and ticker to be played if the notification is not already showing.
869         */
870        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
871            setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
872            return this;
873        }
874
875        /**
876         * Setting this flag will make it so the notification is automatically
877         * canceled when the user clicks it in the panel.  The PendingIntent
878         * set with {@link #setDeleteIntent} will be broadcast when the notification
879         * is canceled.
880         */
881        public Builder setAutoCancel(boolean autoCancel) {
882            setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel);
883            return this;
884        }
885
886        /**
887         * Set whether or not this notification is only relevant to the current device.
888         *
889         * <p>Some notifications can be bridged to other devices for remote display.
890         * This hint can be set to recommend this notification not be bridged.
891         */
892        public Builder setLocalOnly(boolean b) {
893            mLocalOnly = b;
894            return this;
895        }
896
897        /**
898         * Set the notification category.
899         *
900         * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code>
901         * constants in {@link Notification}) that best describes this notification.
902         * May be used by the system for ranking and filtering.
903         */
904        public Builder setCategory(String category) {
905            mCategory = category;
906            return this;
907        }
908
909        /**
910         * Set the default notification options that will be used.
911         * <p>
912         * The value should be one or more of the following fields combined with
913         * bitwise-or:
914         * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE},
915         * {@link Notification#DEFAULT_LIGHTS}.
916         * <p>
917         * For all default values, use {@link Notification#DEFAULT_ALL}.
918         */
919        public Builder setDefaults(int defaults) {
920            mNotification.defaults = defaults;
921            if ((defaults & Notification.DEFAULT_LIGHTS) != 0) {
922                mNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
923            }
924            return this;
925        }
926
927        private void setFlag(int mask, boolean value) {
928            if (value) {
929                mNotification.flags |= mask;
930            } else {
931                mNotification.flags &= ~mask;
932            }
933        }
934
935        /**
936         * Set the relative priority for this notification.
937         *
938         * Priority is an indication of how much of the user's
939         * valuable attention should be consumed by this
940         * notification. Low-priority notifications may be hidden from
941         * the user in certain situations, while the user might be
942         * interrupted for a higher-priority notification.
943         * The system sets a notification's priority based on various factors including the
944         * setPriority value. The effect may differ slightly on different platforms.
945         *
946         * @param pri Relative priority for this notification. Must be one of
947         *     the priority constants defined by {@link NotificationCompat}.
948         *     Acceptable values range from {@link
949         *     NotificationCompat#PRIORITY_MIN} (-2) to {@link
950         *     NotificationCompat#PRIORITY_MAX} (2).
951         */
952        public Builder setPriority(int pri) {
953            mPriority = pri;
954            return this;
955        }
956
957        /**
958         * Add a person that is relevant to this notification.
959         *
960         * @see Notification#EXTRA_PEOPLE
961         */
962        public Builder addPerson(String handle) {
963            mPeople.add(handle);
964            return this;
965        }
966
967        /**
968         * Merge additional metadata into this notification.
969         *
970         * <p>Values within the Bundle will replace existing extras values in this Builder.
971         *
972         * @see Notification#extras
973         */
974        public Builder addExtras(Bundle extras) {
975            if (extras != null) {
976                if (mExtras == null) {
977                    mExtras = new Bundle(extras);
978                } else {
979                    mExtras.putAll(extras);
980                }
981            }
982            return this;
983        }
984
985        /**
986         * Set metadata for this notification.
987         *
988         * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
989         * current contents are copied into the Notification each time {@link #build()} is
990         * called.
991         *
992         * <p>Replaces any existing extras values with those from the provided Bundle.
993         * Use {@link #addExtras} to merge in metadata instead.
994         *
995         * @see Notification#extras
996         */
997        public Builder setExtras(Bundle extras) {
998            mExtras = extras;
999            return this;
1000        }
1001
1002        /**
1003         * Get the current metadata Bundle used by this notification Builder.
1004         *
1005         * <p>The returned Bundle is shared with this Builder.
1006         *
1007         * <p>The current contents of this Bundle are copied into the Notification each time
1008         * {@link #build()} is called.
1009         *
1010         * @see Notification#extras
1011         */
1012        public Bundle getExtras() {
1013            if (mExtras == null) {
1014                mExtras = new Bundle();
1015            }
1016            return mExtras;
1017        }
1018
1019        /**
1020         * Add an action to this notification. Actions are typically displayed by
1021         * the system as a button adjacent to the notification content.
1022         * <br>
1023         * Action buttons won't appear on platforms prior to Android 4.1. Action
1024         * buttons depend on expanded notifications, which are only available in Android 4.1
1025         * and later. To ensure that an action button's functionality is always available, first
1026         * implement the functionality in the {@link android.app.Activity} that starts when a user
1027         * clicks the  notification (see {@link #setContentIntent setContentIntent()}), and then
1028         * enhance the notification by implementing the same functionality with
1029         * {@link #addAction addAction()}.
1030         *
1031         * @param icon Resource ID of a drawable that represents the action.
1032         * @param title Text describing the action.
1033         * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked.
1034         */
1035        public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
1036            mActions.add(new Action(icon, title, intent));
1037            return this;
1038        }
1039
1040        /**
1041         * Add an action to this notification. Actions are typically displayed by
1042         * the system as a button adjacent to the notification content.
1043         * <br>
1044         * Action buttons won't appear on platforms prior to Android 4.1. Action
1045         * buttons depend on expanded notifications, which are only available in Android 4.1
1046         * and later. To ensure that an action button's functionality is always available, first
1047         * implement the functionality in the {@link android.app.Activity} that starts when a user
1048         * clicks the  notification (see {@link #setContentIntent setContentIntent()}), and then
1049         * enhance the notification by implementing the same functionality with
1050         * {@link #addAction addAction()}.
1051         *
1052         * @param action The action to add.
1053         */
1054        public Builder addAction(Action action) {
1055            mActions.add(action);
1056            return this;
1057        }
1058
1059        /**
1060         * Add a rich notification style to be applied at build time.
1061         * <br>
1062         * If the platform does not provide rich notification styles, this method has no effect. The
1063         * user will always see the normal notification style.
1064         *
1065         * @param style Object responsible for modifying the notification style.
1066         */
1067        public Builder setStyle(Style style) {
1068            if (mStyle != style) {
1069                mStyle = style;
1070                if (mStyle != null) {
1071                    mStyle.setBuilder(this);
1072                }
1073            }
1074            return this;
1075        }
1076
1077        /**
1078         * Sets {@link Notification#color}.
1079         *
1080         * @param argb The accent color to use
1081         *
1082         * @return The same Builder.
1083         */
1084        public Builder setColor(int argb) {
1085            mColor = argb;
1086            return this;
1087        }
1088
1089        /**
1090         * Sets {@link Notification#visibility}.
1091         *
1092         * @param visibility One of {@link Notification#VISIBILITY_PRIVATE} (the default),
1093         *                   {@link Notification#VISIBILITY_PUBLIC}, or
1094         *                   {@link Notification#VISIBILITY_SECRET}.
1095         */
1096        public Builder setVisibility(int visibility) {
1097            mVisibility = visibility;
1098            return this;
1099        }
1100
1101        /**
1102         * Supply a replacement Notification whose contents should be shown in insecure contexts
1103         * (i.e. atop the secure lockscreen). See {@link Notification#visibility} and
1104         * {@link #VISIBILITY_PUBLIC}.
1105         *
1106         * @param n A replacement notification, presumably with some or all info redacted.
1107         * @return The same Builder.
1108         */
1109        public Builder setPublicVersion(Notification n) {
1110            mPublicVersion = n;
1111            return this;
1112        }
1113
1114        /**
1115         * @deprecated Use {@link #build()} instead.
1116         */
1117        @Deprecated
1118        public Notification getNotification() {
1119            return IMPL.build(this);
1120        }
1121
1122        /**
1123         * Combine all of the options that have been set and return a new {@link Notification}
1124         * object.
1125         */
1126        public Notification build() {
1127            return IMPL.build(this);
1128        }
1129    }
1130
1131    /**
1132     * An object that can apply a rich notification style to a {@link Notification.Builder}
1133     * object.
1134     * <br>
1135     * If the platform does not provide rich notification styles, methods in this class have no
1136     * effect.
1137     */
1138    public static abstract class Style {
1139        Builder mBuilder;
1140        CharSequence mBigContentTitle;
1141        CharSequence mSummaryText;
1142        boolean mSummaryTextSet = false;
1143
1144        public void setBuilder(Builder builder) {
1145            if (mBuilder != builder) {
1146                mBuilder = builder;
1147                if (mBuilder != null) {
1148                    mBuilder.setStyle(this);
1149                }
1150            }
1151        }
1152
1153        public Notification build() {
1154            Notification notification = null;
1155            if (mBuilder != null) {
1156                notification = mBuilder.build();
1157            }
1158            return notification;
1159        }
1160    }
1161
1162    /**
1163     * Helper class for generating large-format notifications that include a large image attachment.
1164     * <br>
1165     * If the platform does not provide large-format notifications, this method has no effect. The
1166     * user will always see the normal notification view.
1167     * <br>
1168     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
1169     * <pre class="prettyprint">
1170     * Notification noti = new Notification.Builder()
1171     *     .setContentTitle(&quot;New photo from &quot; + sender.toString())
1172     *     .setContentText(subject)
1173     *     .setSmallIcon(R.drawable.new_post)
1174     *     .setLargeIcon(aBitmap)
1175     *     .setStyle(new Notification.BigPictureStyle()
1176     *         .bigPicture(aBigBitmap))
1177     *     .build();
1178     * </pre>
1179     *
1180     * @see Notification#bigContentView
1181     */
1182    public static class BigPictureStyle extends Style {
1183        Bitmap mPicture;
1184        Bitmap mBigLargeIcon;
1185        boolean mBigLargeIconSet;
1186
1187        public BigPictureStyle() {
1188        }
1189
1190        public BigPictureStyle(Builder builder) {
1191            setBuilder(builder);
1192        }
1193
1194        /**
1195         * Overrides ContentTitle in the big form of the template.
1196         * This defaults to the value passed to setContentTitle().
1197         */
1198        public BigPictureStyle setBigContentTitle(CharSequence title) {
1199            mBigContentTitle = title;
1200            return this;
1201        }
1202
1203        /**
1204         * Set the first line of text after the detail section in the big form of the template.
1205         */
1206        public BigPictureStyle setSummaryText(CharSequence cs) {
1207            mSummaryText = cs;
1208            mSummaryTextSet = true;
1209            return this;
1210        }
1211
1212        /**
1213         * Provide the bitmap to be used as the payload for the BigPicture notification.
1214         */
1215        public BigPictureStyle bigPicture(Bitmap b) {
1216            mPicture = b;
1217            return this;
1218        }
1219
1220        /**
1221         * Override the large icon when the big notification is shown.
1222         */
1223        public BigPictureStyle bigLargeIcon(Bitmap b) {
1224            mBigLargeIcon = b;
1225            mBigLargeIconSet = true;
1226            return this;
1227        }
1228    }
1229
1230    /**
1231     * Helper class for generating large-format notifications that include a lot of text.
1232     *
1233     * <br>
1234     * If the platform does not provide large-format notifications, this method has no effect. The
1235     * user will always see the normal notification view.
1236     * <br>
1237     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
1238     * <pre class="prettyprint">
1239     * Notification noti = new Notification.Builder()
1240     *     .setContentTitle(&quot;New mail from &quot; + sender.toString())
1241     *     .setContentText(subject)
1242     *     .setSmallIcon(R.drawable.new_mail)
1243     *     .setLargeIcon(aBitmap)
1244     *     .setStyle(new Notification.BigTextStyle()
1245     *         .bigText(aVeryLongString))
1246     *     .build();
1247     * </pre>
1248     *
1249     * @see Notification#bigContentView
1250     */
1251    public static class BigTextStyle extends Style {
1252        CharSequence mBigText;
1253
1254        public BigTextStyle() {
1255        }
1256
1257        public BigTextStyle(Builder builder) {
1258            setBuilder(builder);
1259        }
1260
1261        /**
1262         * Overrides ContentTitle in the big form of the template.
1263         * This defaults to the value passed to setContentTitle().
1264         */
1265        public BigTextStyle setBigContentTitle(CharSequence title) {
1266            mBigContentTitle = title;
1267            return this;
1268        }
1269
1270        /**
1271         * Set the first line of text after the detail section in the big form of the template.
1272         */
1273        public BigTextStyle setSummaryText(CharSequence cs) {
1274            mSummaryText = cs;
1275            mSummaryTextSet = true;
1276            return this;
1277        }
1278
1279        /**
1280         * Provide the longer text to be displayed in the big form of the
1281         * template in place of the content text.
1282         */
1283        public BigTextStyle bigText(CharSequence cs) {
1284            mBigText = cs;
1285            return this;
1286        }
1287    }
1288
1289    /**
1290     * Helper class for generating large-format notifications that include a list of (up to 5) strings.
1291     *
1292     * <br>
1293     * If the platform does not provide large-format notifications, this method has no effect. The
1294     * user will always see the normal notification view.
1295     * <br>
1296     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
1297     * <pre class="prettyprint">
1298     * Notification noti = new Notification.Builder()
1299     *     .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
1300     *     .setContentText(subject)
1301     *     .setSmallIcon(R.drawable.new_mail)
1302     *     .setLargeIcon(aBitmap)
1303     *     .setStyle(new Notification.InboxStyle()
1304     *         .addLine(str1)
1305     *         .addLine(str2)
1306     *         .setContentTitle(&quot;&quot;)
1307     *         .setSummaryText(&quot;+3 more&quot;))
1308     *     .build();
1309     * </pre>
1310     *
1311     * @see Notification#bigContentView
1312     */
1313    public static class InboxStyle extends Style {
1314        ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
1315
1316        public InboxStyle() {
1317        }
1318
1319        public InboxStyle(Builder builder) {
1320            setBuilder(builder);
1321        }
1322
1323        /**
1324         * Overrides ContentTitle in the big form of the template.
1325         * This defaults to the value passed to setContentTitle().
1326         */
1327        public InboxStyle setBigContentTitle(CharSequence title) {
1328            mBigContentTitle = title;
1329            return this;
1330        }
1331
1332        /**
1333         * Set the first line of text after the detail section in the big form of the template.
1334         */
1335        public InboxStyle setSummaryText(CharSequence cs) {
1336            mSummaryText = cs;
1337            mSummaryTextSet = true;
1338            return this;
1339        }
1340
1341        /**
1342         * Append a line to the digest section of the Inbox notification.
1343         */
1344        public InboxStyle addLine(CharSequence cs) {
1345            mTexts.add(cs);
1346            return this;
1347        }
1348    }
1349
1350    /**
1351     * Structure to encapsulate a named action that can be shown as part of this notification.
1352     * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
1353     * selected by the user. Action buttons won't appear on platforms prior to Android 4.1.
1354     * <p>
1355     * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)}
1356     * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)}
1357     * to attach actions.
1358     */
1359    public static class Action {
1360        private final Bundle mExtras;
1361
1362        /**
1363         * Small icon representing the action.
1364         */
1365        public int icon;
1366        /**
1367         * Title of the action.
1368         */
1369        public CharSequence title;
1370        /**
1371         * Intent to send when the user invokes this action. May be null, in which case the action
1372         * may be rendered in a disabled presentation.
1373         */
1374        public PendingIntent actionIntent;
1375
1376        public Action(int icon, CharSequence title, PendingIntent intent) {
1377            this(icon, title, intent, new Bundle());
1378        }
1379
1380        private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
1381            this.icon = icon;
1382            this.title = title;
1383            this.actionIntent = intent;
1384            this.mExtras = extras != null ? extras : new Bundle();
1385        }
1386
1387        /**
1388         * Get additional metadata carried around with this Action.
1389         */
1390        public Bundle getExtras() {
1391            return mExtras;
1392        }
1393
1394        /**
1395         * Builder class for {@link Action} objects.
1396         */
1397        public static class Builder {
1398            private final int mIcon;
1399            private final CharSequence mTitle;
1400            private final PendingIntent mIntent;
1401            private final Bundle mExtras;
1402
1403            /**
1404             * Construct a new builder for {@link Action} object.
1405             * @param icon icon to show for this action
1406             * @param title the title of the action
1407             * @param intent the {@link PendingIntent} to fire when users trigger this action
1408             */
1409            public Builder(int icon, CharSequence title, PendingIntent intent) {
1410                this(icon, title, intent, new Bundle());
1411            }
1412
1413            /**
1414             * Construct a new builder for {@link Action} object using the fields from an
1415             * {@link Action}.
1416             * @param action the action to read fields from.
1417             */
1418            public Builder(Action action) {
1419                this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
1420            }
1421
1422            private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
1423                mIcon = icon;
1424                mTitle = title;
1425                mIntent = intent;
1426                mExtras = extras;
1427            }
1428
1429            /**
1430             * Merge additional metadata into this builder.
1431             *
1432             * <p>Values within the Bundle will replace existing extras values in this Builder.
1433             *
1434             * @see NotificationCompat.Action#getExtras
1435             */
1436            public Builder addExtras(Bundle extras) {
1437                if (extras != null) {
1438                    mExtras.putAll(extras);
1439                }
1440                return this;
1441            }
1442
1443            /**
1444             * Get the metadata Bundle used by this Builder.
1445             *
1446             * <p>The returned Bundle is shared with this Builder.
1447             */
1448            public Bundle getExtras() {
1449                return mExtras;
1450            }
1451
1452            /**
1453             * Combine all of the options that have been set and return a new {@link Action}
1454             * object.
1455             * @return the built action
1456             */
1457            public Action build() {
1458                return new Action(mIcon, mTitle, mIntent, mExtras);
1459            }
1460        }
1461    }
1462
1463    private static class NotificationActionHolderImpl implements NotificationActionHolder {
1464        private NotificationCompat.Action mAction;
1465
1466        @Override
1467        public void set(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
1468            mAction = new Action(icon, title, intent, extras);
1469        }
1470
1471        public NotificationCompat.Action get() {
1472            return mAction;
1473        }
1474    }
1475
1476    /**
1477     * Gets the {@link Notification#extras} field from a notification in a backwards
1478     * compatible manner. Extras field was supported from JellyBean (Api level 16)
1479     * forwards. This function will return null on older api levels.
1480     */
1481    public static Bundle getExtras(Notification notif) {
1482        return IMPL.getExtras(notif);
1483    }
1484
1485    /**
1486     * Get the number of actions in this notification in a backwards compatible
1487     * manner. Actions were supported from JellyBean (Api level 16) forwards.
1488     */
1489    public static int getActionCount(Notification notif) {
1490        return IMPL.getActionCount(notif);
1491    }
1492
1493    /**
1494     * Get an action on this notification in a backwards compatible
1495     * manner. Actions were supported from JellyBean (Api level 16) forwards.
1496     * @param notif The notification to inspect.
1497     * @param actionIndex The index of the action to retrieve.
1498     */
1499    public static Action getAction(Notification notif, int actionIndex) {
1500        return IMPL.getAction(notif, actionIndex);
1501    }
1502
1503    /**
1504     * Get whether or not this notification is only relevant to the current device.
1505     *
1506     * <p>Some notifications can be bridged to other devices for remote display.
1507     * If this hint is set, it is recommend that this notification not be bridged.
1508     */
1509    public static boolean getLocalOnly(Notification notif) {
1510        return IMPL.getLocalOnly(notif);
1511    }
1512}
1513