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