NotificationCompat.java revision aea520f48e382c4e88487785c2cacadb527c6da7
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.media.AudioManager;
25import android.net.Uri;
26import android.os.Build;
27import android.os.Bundle;
28import android.widget.RemoteViews;
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     * Obsolete flag indicating high-priority notifications; use the priority field instead.
38     *
39     * @deprecated Use {@link NotificationCompat.Builder#setPriority(int)} with a positive value.
40     */
41    public static final int FLAG_HIGH_PRIORITY = 0x00000080;
42
43    /**
44     * Default notification priority for {@link NotificationCompat.Builder#setPriority(int)}.
45     * If your application does not prioritize its own notifications,
46     * use this value for all notifications.
47     */
48    public static final int PRIORITY_DEFAULT = 0;
49
50    /**
51     * Lower notification priority for {@link NotificationCompat.Builder#setPriority(int)},
52     * for items that are less important. The UI may choose to show
53     * these items smaller, or at a different position in the list,
54     * compared with your app's {@link #PRIORITY_DEFAULT} items.
55     */
56    public static final int PRIORITY_LOW = -1;
57
58    /**
59     * Lowest notification priority for {@link NotificationCompat.Builder#setPriority(int)};
60     * these items might not be shown to the user except under
61     * special circumstances, such as detailed notification logs.
62     */
63    public static final int PRIORITY_MIN = -2;
64
65    /**
66     * Higher notification priority for {@link NotificationCompat.Builder#setPriority(int)},
67     * for more important notifications or alerts. The UI may choose
68     * to show these items larger, or at a different position in
69     * notification lists, compared with your app's {@link #PRIORITY_DEFAULT} items.
70     */
71    public static final int PRIORITY_HIGH = 1;
72
73    /**
74     * Highest notification priority for {@link NotificationCompat.Builder#setPriority(int)},
75     * for your application's most important items that require the user's
76     * prompt attention or input.
77     */
78    public static final int PRIORITY_MAX = 2;
79
80    private static final NotificationCompatImpl IMPL;
81
82    interface NotificationCompatImpl {
83        public Notification build(Builder b);
84        public Bundle getExtras(Notification n);
85        public boolean getLocalOnly(Notification n);
86    }
87
88    static class NotificationCompatImplBase implements NotificationCompatImpl {
89        @Override
90        public Notification build(Builder b) {
91            Notification result = b.mNotification;
92            result.setLatestEventInfo(b.mContext, b.mContentTitle,
93                    b.mContentText, b.mContentIntent);
94            // translate high priority requests into legacy flag
95            if (b.mPriority > PRIORITY_DEFAULT) {
96                result.flags |= FLAG_HIGH_PRIORITY;
97            }
98            return result;
99        }
100
101        @Override
102        public Bundle getExtras(Notification n) {
103            return null;
104        }
105
106        @Override
107        public boolean getLocalOnly(Notification n) {
108            return false;
109        }
110    }
111
112    static class NotificationCompatImplGingerbread extends NotificationCompatImplBase {
113        @Override
114        public Notification build(Builder b) {
115            Notification result = b.mNotification;
116            result.setLatestEventInfo(b.mContext, b.mContentTitle,
117                    b.mContentText, b.mContentIntent);
118            result = NotificationCompatGingerbread.add(result, b.mContext,
119                    b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent);
120            // translate high priority requests into legacy flag
121            if (b.mPriority > PRIORITY_DEFAULT) {
122                result.flags |= FLAG_HIGH_PRIORITY;
123            }
124            return result;
125        }
126    }
127
128    static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase {
129        @Override
130        public Notification build(Builder b) {
131            return NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
132                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
133                    b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
134        }
135    }
136
137    static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase {
138        @Override
139        public Notification build(Builder b) {
140            return NotificationCompatIceCreamSandwich.add(b.mContext, b.mNotification,
141                    b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
142                    b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
143                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
144        }
145    }
146
147    static class NotificationCompatImplJellybean extends NotificationCompatImplBase {
148        @Override
149        public Notification build(Builder b) {
150            NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
151                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
152                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
153                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
154                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras);
155            addActionsToBuilder(builder, b.mActions);
156            addStyleToBuilderJellybean(builder, b.mStyle);
157            return builder.build();
158        }
159
160        @Override
161        public Bundle getExtras(Notification n) {
162            return NotificationCompatJellybean.getExtras(n);
163        }
164
165        @Override
166        public boolean getLocalOnly(Notification n) {
167            return NotificationCompatJellybean.getLocalOnly(n);
168        }
169    }
170
171    static class NotificationCompatImplKitKat extends NotificationCompatImplBase {
172        @Override
173        public Notification build(Builder b) {
174            NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
175                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
176                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
177                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
178                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras);
179            addActionsToBuilder(builder, b.mActions);
180            addStyleToBuilderJellybean(builder, b.mStyle);
181            return builder.build();
182        }
183
184        @Override
185        public Bundle getExtras(Notification n) {
186            return NotificationCompatKitKat.getExtras(n);
187        }
188
189        @Override
190        public boolean getLocalOnly(Notification n) {
191            return NotificationCompatKitKat.getLocalOnly(n);
192        }
193    }
194
195    static class NotificationCompatImplApi20 extends NotificationCompatImplBase {
196        @Override
197        public Notification build(Builder b) {
198            NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
199                    b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
200                    b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
201                    b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
202                    b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
203                    b.mPeople, b.mExtras);
204            addActionsToBuilder(builder, b.mActions);
205            addStyleToBuilderJellybean(builder, b.mStyle);
206            return builder.build();
207        }
208
209        @Override
210        public Bundle getExtras(Notification n) {
211            return NotificationCompatKitKat.getExtras(n);
212        }
213
214        @Override
215        public boolean getLocalOnly(Notification n) {
216            return NotificationCompatApi20.getLocalOnly(n);
217        }
218    }
219
220    private static void addActionsToBuilder(NotificationBuilderWithActions builder,
221            ArrayList<Action> actions) {
222        for (Action action : actions) {
223            builder.addAction(action.icon, action.title, action.actionIntent);
224        }
225    }
226
227    private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder,
228            Style style) {
229        if (style != null) {
230            if (style instanceof BigTextStyle) {
231                BigTextStyle bigTextStyle = (BigTextStyle) style;
232                NotificationCompatJellybean.addBigTextStyle(builder,
233                        bigTextStyle.mBigContentTitle,
234                        bigTextStyle.mSummaryTextSet,
235                        bigTextStyle.mSummaryText,
236                        bigTextStyle.mBigText);
237            } else if (style instanceof InboxStyle) {
238                InboxStyle inboxStyle = (InboxStyle) style;
239                NotificationCompatJellybean.addInboxStyle(builder,
240                        inboxStyle.mBigContentTitle,
241                        inboxStyle.mSummaryTextSet,
242                        inboxStyle.mSummaryText,
243                        inboxStyle.mTexts);
244            } else if (style instanceof BigPictureStyle) {
245                BigPictureStyle bigPictureStyle = (BigPictureStyle) style;
246                NotificationCompatJellybean.addBigPictureStyle(builder,
247                        bigPictureStyle.mBigContentTitle,
248                        bigPictureStyle.mSummaryTextSet,
249                        bigPictureStyle.mSummaryText,
250                        bigPictureStyle.mPicture,
251                        bigPictureStyle.mBigLargeIcon,
252                        bigPictureStyle.mBigLargeIconSet);
253            }
254        }
255    }
256
257    static {
258        // TODO: Replace this if clause when SDK_INT is incremented to 20.
259        if (Build.VERSION.RELEASE.equals("L")) {
260            IMPL = new NotificationCompatImplApi20();
261        } else if (Build.VERSION.SDK_INT >= 19) {
262            IMPL = new NotificationCompatImplKitKat();
263        } else if (Build.VERSION.SDK_INT >= 16) {
264            IMPL = new NotificationCompatImplJellybean();
265        } else if (Build.VERSION.SDK_INT >= 14) {
266            IMPL = new NotificationCompatImplIceCreamSandwich();
267        } else if (Build.VERSION.SDK_INT >= 11) {
268            IMPL = new NotificationCompatImplHoneycomb();
269        } else if (Build.VERSION.SDK_INT >= 9) {
270            IMPL = new NotificationCompatImplGingerbread();
271        } else {
272            IMPL = new NotificationCompatImplBase();
273        }
274    }
275
276    /**
277     * Builder class for {@link NotificationCompat} objects.  Allows easier control over
278     * all the flags, as well as help constructing the typical notification layouts.
279     * <p>
280     * On platform versions that don't offer expanded notifications, methods that depend on
281     * expanded notifications have no effect.
282     * </p>
283     * <p>
284     * For example, action buttons won't appear on platforms prior to Android 4.1. Action
285     * buttons depend on expanded notifications, which are only available in Android 4.1
286     * and later.
287     * <p>
288     * For this reason, you should always ensure that UI controls in a notification are also
289     * available in an {@link android.app.Activity} in your app, and you should always start that
290     * {@link android.app.Activity} when users click the notification. To do this, use the
291     * {@link NotificationCompat.Builder#setContentIntent setContentIntent()}
292     * method.
293     * </p>
294     *
295     */
296    public static class Builder {
297        Context mContext;
298
299        CharSequence mContentTitle;
300        CharSequence mContentText;
301        PendingIntent mContentIntent;
302        PendingIntent mFullScreenIntent;
303        RemoteViews mTickerView;
304        Bitmap mLargeIcon;
305        CharSequence mContentInfo;
306        int mNumber;
307        int mPriority;
308        boolean mUseChronometer;
309        Style mStyle;
310        CharSequence mSubText;
311        int mProgressMax;
312        int mProgress;
313        boolean mProgressIndeterminate;
314        ArrayList<Action> mActions = new ArrayList<Action>();
315        boolean mLocalOnly = false;
316        String mCategory;
317        Bundle mExtras;
318
319        Notification mNotification = new Notification();
320        public ArrayList<String> mPeople;
321
322        /**
323         * Constructor.
324         *
325         * Automatically sets the when field to {@link System#currentTimeMillis()
326         * System.currentTimeMillis()} and the audio stream to the
327         * {@link Notification#STREAM_DEFAULT}.
328         *
329         * @param context A {@link Context} that will be used to construct the
330         *      RemoteViews. The Context will not be held past the lifetime of this
331         *      Builder object.
332         */
333        public Builder(Context context) {
334            mContext = context;
335
336            // Set defaults to match the defaults of a Notification
337            mNotification.when = System.currentTimeMillis();
338            mNotification.audioStreamType = Notification.STREAM_DEFAULT;
339            mPriority = PRIORITY_DEFAULT;
340            mPeople = new ArrayList<String>();
341        }
342
343        /**
344         * Set the time that the event occurred.  Notifications in the panel are
345         * sorted by this time.
346         */
347        public Builder setWhen(long when) {
348            mNotification.when = when;
349            return this;
350        }
351
352        /**
353         * Show the {@link Notification#when} field as a stopwatch.
354         *
355         * Instead of presenting <code>when</code> as a timestamp, the notification will show an
356         * automatically updating display of the minutes and seconds since <code>when</code>.
357         *
358         * Useful when showing an elapsed time (like an ongoing phone call).
359         *
360         * @see android.widget.Chronometer
361         * @see Notification#when
362         */
363        public Builder setUsesChronometer(boolean b) {
364            mUseChronometer = b;
365            return this;
366        }
367
368        /**
369         * Set the small icon to use in the notification layouts.  Different classes of devices
370         * may return different sizes.  See the UX guidelines for more information on how to
371         * design these icons.
372         *
373         * @param icon A resource ID in the application's package of the drawble to use.
374         */
375        public Builder setSmallIcon(int icon) {
376            mNotification.icon = icon;
377            return this;
378        }
379
380        /**
381         * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
382         * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
383         * LevelListDrawable}.
384         *
385         * @param icon A resource ID in the application's package of the drawble to use.
386         * @param level The level to use for the icon.
387         *
388         * @see android.graphics.drawable.LevelListDrawable
389         */
390        public Builder setSmallIcon(int icon, int level) {
391            mNotification.icon = icon;
392            mNotification.iconLevel = level;
393            return this;
394        }
395
396        /**
397         * Set the title (first row) of the notification, in a standard notification.
398         */
399        public Builder setContentTitle(CharSequence title) {
400            mContentTitle = title;
401            return this;
402        }
403
404        /**
405         * Set the text (second row) of the notification, in a standard notification.
406         */
407        public Builder setContentText(CharSequence text) {
408            mContentText = text;
409            return this;
410        }
411
412        /**
413         * Set the third line of text in the platform notification template.
414         * Don't use if you're also using {@link #setProgress(int, int, boolean)};
415         * they occupy the same location in the standard template.
416         * <br>
417         * If the platform does not provide large-format notifications, this method has no effect.
418         * The third line of text only appears in expanded view.
419         * <br>
420         */
421        public Builder setSubText(CharSequence text) {
422            mSubText = text;
423            return this;
424        }
425
426        /**
427         * Set the large number at the right-hand side of the notification.  This is
428         * equivalent to setContentInfo, although it might show the number in a different
429         * font size for readability.
430         */
431        public Builder setNumber(int number) {
432            mNumber = number;
433            return this;
434        }
435
436        /**
437         * Set the large text at the right-hand side of the notification.
438         */
439        public Builder setContentInfo(CharSequence info) {
440            mContentInfo = info;
441            return this;
442        }
443
444        /**
445         * Set the progress this notification represents, which may be
446         * represented as a {@link android.widget.ProgressBar}.
447         */
448        public Builder setProgress(int max, int progress, boolean indeterminate) {
449            mProgressMax = max;
450            mProgress = progress;
451            mProgressIndeterminate = indeterminate;
452            return this;
453        }
454
455        /**
456         * Supply a custom RemoteViews to use instead of the standard one.
457         */
458        public Builder setContent(RemoteViews views) {
459            mNotification.contentView = views;
460            return this;
461        }
462
463        /**
464         * Supply a {@link PendingIntent} to send when the notification is clicked.
465         * If you do not supply an intent, you can now add PendingIntents to individual
466         * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
467         * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.  Be sure to
468         * read {@link Notification#contentIntent Notification.contentIntent} for
469         * how to correctly use this.
470         */
471        public Builder setContentIntent(PendingIntent intent) {
472            mContentIntent = intent;
473            return this;
474        }
475
476        /**
477         * Supply a {@link PendingIntent} to send when the notification is cleared by the user
478         * directly from the notification panel.  For example, this intent is sent when the user
479         * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
480         * intent is not sent when the application calls {@link NotificationManager#cancel
481         * NotificationManager.cancel(int)}.
482         */
483        public Builder setDeleteIntent(PendingIntent intent) {
484            mNotification.deleteIntent = intent;
485            return this;
486        }
487
488        /**
489         * An intent to launch instead of posting the notification to the status bar.
490         * Only for use with extremely high-priority notifications demanding the user's
491         * <strong>immediate</strong> attention, such as an incoming phone call or
492         * alarm clock that the user has explicitly set to a particular time.
493         * If this facility is used for something else, please give the user an option
494         * to turn it off and use a normal notification, as this can be extremely
495         * disruptive.
496         *
497         * @param intent The pending intent to launch.
498         * @param highPriority Passing true will cause this notification to be sent
499         *          even if other notifications are suppressed.
500         */
501        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
502            mFullScreenIntent = intent;
503            setFlag(FLAG_HIGH_PRIORITY, highPriority);
504            return this;
505        }
506
507        /**
508         * Set the text that is displayed in the status bar when the notification first
509         * arrives.
510         */
511        public Builder setTicker(CharSequence tickerText) {
512            mNotification.tickerText = tickerText;
513            return this;
514        }
515
516        /**
517         * Set the text that is displayed in the status bar when the notification first
518         * arrives, and also a RemoteViews object that may be displayed instead on some
519         * devices.
520         */
521        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
522            mNotification.tickerText = tickerText;
523            mTickerView = views;
524            return this;
525        }
526
527        /**
528         * Set the large icon that is shown in the ticker and notification.
529         */
530        public Builder setLargeIcon(Bitmap icon) {
531            mLargeIcon = icon;
532            return this;
533        }
534
535        /**
536         * Set the sound to play.  It will play on the default stream.
537         */
538        public Builder setSound(Uri sound) {
539            mNotification.sound = sound;
540            mNotification.audioStreamType = Notification.STREAM_DEFAULT;
541            return this;
542        }
543
544        /**
545         * Set the sound to play.  It will play on the stream you supply.
546         *
547         * @see Notification#STREAM_DEFAULT
548         * @see AudioManager for the <code>STREAM_</code> constants.
549         */
550        public Builder setSound(Uri sound, int streamType) {
551            mNotification.sound = sound;
552            mNotification.audioStreamType = streamType;
553            return this;
554        }
555
556        /**
557         * Set the vibration pattern to use.
558         *
559         * @see android.os.Vibrator for a discussion of the <code>pattern</code>
560         * parameter.
561         */
562        public Builder setVibrate(long[] pattern) {
563            mNotification.vibrate = pattern;
564            return this;
565        }
566
567        /**
568         * Set the argb value that you would like the LED on the device to blnk, as well as the
569         * rate.  The rate is specified in terms of the number of milliseconds to be on
570         * and then the number of milliseconds to be off.
571         */
572        public Builder setLights(int argb, int onMs, int offMs) {
573            mNotification.ledARGB = argb;
574            mNotification.ledOnMS = onMs;
575            mNotification.ledOffMS = offMs;
576            boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0;
577            mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) |
578                    (showLights ? Notification.FLAG_SHOW_LIGHTS : 0);
579            return this;
580        }
581
582        /**
583         * Set whether this is an ongoing notification.
584         *
585         * <p>Ongoing notifications differ from regular notifications in the following ways:
586         * <ul>
587         *   <li>Ongoing notifications are sorted above the regular notifications in the
588         *   notification panel.</li>
589         *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
590         *   by the "Clear all" button.
591         * </ul>
592         */
593        public Builder setOngoing(boolean ongoing) {
594            setFlag(Notification.FLAG_ONGOING_EVENT, ongoing);
595            return this;
596        }
597
598        /**
599         * Set this flag if you would only like the sound, vibrate
600         * and ticker to be played if the notification is not already showing.
601         */
602        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
603            setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
604            return this;
605        }
606
607        /**
608         * Setting this flag will make it so the notification is automatically
609         * canceled when the user clicks it in the panel.  The PendingIntent
610         * set with {@link #setDeleteIntent} will be broadcast when the notification
611         * is canceled.
612         */
613        public Builder setAutoCancel(boolean autoCancel) {
614            setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel);
615            return this;
616        }
617
618        /**
619         * Set whether or not this notification is only relevant to the current device.
620         *
621         * <p>Some notifications can be bridged to other devices for remote display.
622         * This hint can be set to recommend this notification not be bridged.
623         */
624        public Builder setLocalOnly(boolean b) {
625            mLocalOnly = b;
626            return this;
627        }
628
629        /**
630         * Set the notification category.
631         *
632         * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code>
633         * constants in {@link Notification}) that best describes this notification.
634         * May be used by the system for ranking and filtering.
635         */
636        public Builder setCategory(String category) {
637            mCategory = category;
638            return this;
639        }
640
641        /**
642         * Set the default notification options that will be used.
643         * <p>
644         * The value should be one or more of the following fields combined with
645         * bitwise-or:
646         * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE},
647         * {@link Notification#DEFAULT_LIGHTS}.
648         * <p>
649         * For all default values, use {@link Notification#DEFAULT_ALL}.
650         */
651        public Builder setDefaults(int defaults) {
652            mNotification.defaults = defaults;
653            if ((defaults & Notification.DEFAULT_LIGHTS) != 0) {
654                mNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
655            }
656            return this;
657        }
658
659        private void setFlag(int mask, boolean value) {
660            if (value) {
661                mNotification.flags |= mask;
662            } else {
663                mNotification.flags &= ~mask;
664            }
665        }
666
667        /**
668         * Set the relative priority for this notification.
669         *
670         * Priority is an indication of how much of the user's
671         * valuable attention should be consumed by this
672         * notification. Low-priority notifications may be hidden from
673         * the user in certain situations, while the user might be
674         * interrupted for a higher-priority notification.
675         * The system sets a notification's priority based on various factors including the
676         * setPriority value. The effect may differ slightly on different platforms.
677         */
678        public Builder setPriority(int pri) {
679            mPriority = pri;
680            return this;
681        }
682
683        /**
684         * Add a person that is relevant to this notification.
685         *
686         * @see Notification#EXTRA_PEOPLE
687         */
688        public Builder addPerson(String handle) {
689            mPeople.add(handle);
690            return this;
691        }
692
693        /**
694         * Merge additional metadata into this notification.
695         *
696         * <p>Values within the Bundle will replace existing extras values in this Builder.
697         *
698         * @see Notification#extras
699         */
700        public Builder addExtras(Bundle bag) {
701            if (mExtras == null) {
702                mExtras = new Bundle(bag);
703            } else {
704                mExtras.putAll(bag);
705            }
706            return this;
707        }
708
709        /**
710         * Set metadata for this notification.
711         *
712         * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
713         * current contents are copied into the Notification each time {@link #build()} is
714         * called.
715         *
716         * <p>Replaces any existing extras values with those from the provided Bundle.
717         * Use {@link #addExtras} to merge in metadata instead.
718         *
719         * @see Notification#extras
720         */
721        public Builder setExtras(Bundle bag) {
722            mExtras = bag;
723            return this;
724        }
725
726        /**
727         * Get the current metadata Bundle used by this notification Builder.
728         *
729         * <p>The returned Bundle is shared with this Builder.
730         *
731         * <p>The current contents of this Bundle are copied into the Notification each time
732         * {@link #build()} is called.
733         *
734         * @see Notification#extras
735         */
736        public Bundle getExtras() {
737            if (mExtras == null) {
738                mExtras = new Bundle();
739            }
740            return mExtras;
741        }
742
743        /**
744         * Add an action to this notification. Actions are typically displayed by
745         * the system as a button adjacent to the notification content.
746         * <br>
747         * Action buttons won't appear on platforms prior to Android 4.1. Action
748         * buttons depend on expanded notifications, which are only available in Android 4.1
749         * and later. To ensure that an action button's functionality is always available, first
750         * implement the functionality in the {@link android.app.Activity} that starts when a user
751         * clicks the  notification (see {@link #setContentIntent setContentIntent()}), and then
752         * enhance the notification by implementing the same functionality with
753         * {@link #addAction addAction()}.
754         *
755         * @param icon Resource ID of a drawable that represents the action.
756         * @param title Text describing the action.
757         * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked.
758         */
759        public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
760            mActions.add(new Action(icon, title, intent));
761            return this;
762        }
763
764        /**
765         * Add a rich notification style to be applied at build time.
766         * <br>
767         * If the platform does not provide rich notification styles, this method has no effect. The
768         * user will always see the normal notification style.
769         *
770         * @param style Object responsible for modifying the notification style.
771         */
772        public Builder setStyle(Style style) {
773            if (mStyle != style) {
774                mStyle = style;
775                if (mStyle != null) {
776                    mStyle.setBuilder(this);
777                }
778            }
779            return this;
780        }
781
782        /**
783         * @deprecated Use {@link #build()} instead.
784         */
785        @Deprecated
786        public Notification getNotification() {
787            return IMPL.build(this);
788        }
789
790        /**
791         * Combine all of the options that have been set and return a new {@link Notification}
792         * object.
793         */
794        public Notification build() {
795            return IMPL.build(this);
796        }
797    }
798
799    /**
800     * An object that can apply a rich notification style to a {@link Notification.Builder}
801     * object.
802     * <br>
803     * If the platform does not provide rich notification styles, methods in this class have no
804     * effect.
805     */
806    public static abstract class Style {
807        Builder mBuilder;
808        CharSequence mBigContentTitle;
809        CharSequence mSummaryText;
810        boolean mSummaryTextSet = false;
811
812        public void setBuilder(Builder builder) {
813            if (mBuilder != builder) {
814                mBuilder = builder;
815                if (mBuilder != null) {
816                    mBuilder.setStyle(this);
817                }
818            }
819        }
820
821        public Notification build() {
822            Notification notification = null;
823            if (mBuilder != null) {
824                notification = mBuilder.build();
825            }
826            return notification;
827        }
828    }
829
830    /**
831     * Helper class for generating large-format notifications that include a large image attachment.
832     * <br>
833     * If the platform does not provide large-format notifications, this method has no effect. The
834     * user will always see the normal notification view.
835     * <br>
836     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
837     * <pre class="prettyprint">
838     * Notification noti = new Notification.Builder()
839     *     .setContentTitle(&quot;New photo from &quot; + sender.toString())
840     *     .setContentText(subject)
841     *     .setSmallIcon(R.drawable.new_post)
842     *     .setLargeIcon(aBitmap)
843     *     .setStyle(new Notification.BigPictureStyle()
844     *         .bigPicture(aBigBitmap))
845     *     .build();
846     * </pre>
847     *
848     * @see Notification#bigContentView
849     */
850    public static class BigPictureStyle extends Style {
851        Bitmap mPicture;
852        Bitmap mBigLargeIcon;
853        boolean mBigLargeIconSet;
854
855        public BigPictureStyle() {
856        }
857
858        public BigPictureStyle(Builder builder) {
859            setBuilder(builder);
860        }
861
862        /**
863         * Overrides ContentTitle in the big form of the template.
864         * This defaults to the value passed to setContentTitle().
865         */
866        public BigPictureStyle setBigContentTitle(CharSequence title) {
867            mBigContentTitle = title;
868            return this;
869        }
870
871        /**
872         * Set the first line of text after the detail section in the big form of the template.
873         */
874        public BigPictureStyle setSummaryText(CharSequence cs) {
875            mSummaryText = cs;
876            mSummaryTextSet = true;
877            return this;
878        }
879
880        /**
881         * Provide the bitmap to be used as the payload for the BigPicture notification.
882         */
883        public BigPictureStyle bigPicture(Bitmap b) {
884            mPicture = b;
885            return this;
886        }
887
888        /**
889         * Override the large icon when the big notification is shown.
890         */
891        public BigPictureStyle bigLargeIcon(Bitmap b) {
892            mBigLargeIcon = b;
893            mBigLargeIconSet = true;
894            return this;
895        }
896    }
897
898    /**
899     * Helper class for generating large-format notifications that include a lot of text.
900     *
901     * <br>
902     * If the platform does not provide large-format notifications, this method has no effect. The
903     * user will always see the normal notification view.
904     * <br>
905     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
906     * <pre class="prettyprint">
907     * Notification noti = new Notification.Builder()
908     *     .setContentTitle(&quot;New mail from &quot; + sender.toString())
909     *     .setContentText(subject)
910     *     .setSmallIcon(R.drawable.new_mail)
911     *     .setLargeIcon(aBitmap)
912     *     .setStyle(new Notification.BigTextStyle()
913     *         .bigText(aVeryLongString))
914     *     .build();
915     * </pre>
916     *
917     * @see Notification#bigContentView
918     */
919    public static class BigTextStyle extends Style {
920        CharSequence mBigText;
921
922        public BigTextStyle() {
923        }
924
925        public BigTextStyle(Builder builder) {
926            setBuilder(builder);
927        }
928
929        /**
930         * Overrides ContentTitle in the big form of the template.
931         * This defaults to the value passed to setContentTitle().
932         */
933        public BigTextStyle setBigContentTitle(CharSequence title) {
934            mBigContentTitle = title;
935            return this;
936        }
937
938        /**
939         * Set the first line of text after the detail section in the big form of the template.
940         */
941        public BigTextStyle setSummaryText(CharSequence cs) {
942            mSummaryText = cs;
943            mSummaryTextSet = true;
944            return this;
945        }
946
947        /**
948         * Provide the longer text to be displayed in the big form of the
949         * template in place of the content text.
950         */
951        public BigTextStyle bigText(CharSequence cs) {
952            mBigText = cs;
953            return this;
954        }
955    }
956
957    /**
958     * Helper class for generating large-format notifications that include a list of (up to 5) strings.
959     *
960     * <br>
961     * If the platform does not provide large-format notifications, this method has no effect. The
962     * user will always see the normal notification view.
963     * <br>
964     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
965     * <pre class="prettyprint">
966     * Notification noti = new Notification.Builder()
967     *     .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
968     *     .setContentText(subject)
969     *     .setSmallIcon(R.drawable.new_mail)
970     *     .setLargeIcon(aBitmap)
971     *     .setStyle(new Notification.InboxStyle()
972     *         .addLine(str1)
973     *         .addLine(str2)
974     *         .setContentTitle(&quot;&quot;)
975     *         .setSummaryText(&quot;+3 more&quot;))
976     *     .build();
977     * </pre>
978     *
979     * @see Notification#bigContentView
980     */
981    public static class InboxStyle extends Style {
982        ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
983
984        public InboxStyle() {
985        }
986
987        public InboxStyle(Builder builder) {
988            setBuilder(builder);
989        }
990
991        /**
992         * Overrides ContentTitle in the big form of the template.
993         * This defaults to the value passed to setContentTitle().
994         */
995        public InboxStyle setBigContentTitle(CharSequence title) {
996            mBigContentTitle = title;
997            return this;
998        }
999
1000        /**
1001         * Set the first line of text after the detail section in the big form of the template.
1002         */
1003        public InboxStyle setSummaryText(CharSequence cs) {
1004            mSummaryText = cs;
1005            mSummaryTextSet = true;
1006            return this;
1007        }
1008
1009        /**
1010         * Append a line to the digest section of the Inbox notification.
1011         */
1012        public InboxStyle addLine(CharSequence cs) {
1013            mTexts.add(cs);
1014            return this;
1015        }
1016    }
1017
1018    public static class Action {
1019        public int icon;
1020        public CharSequence title;
1021        public PendingIntent actionIntent;
1022
1023        public Action(int icon_, CharSequence title_, PendingIntent intent_) {
1024            this.icon = icon_;
1025            this.title = title_;
1026            this.actionIntent = intent_;
1027        }
1028    }
1029
1030    /**
1031     * Gets the {@link Notification#extras} field from a notification in a backwards
1032     * compatible manner. Extras field was supported from JellyBean (Api level 16)
1033     * forwards. This function will return null on older api levels.
1034     */
1035    public static Bundle getExtras(Notification notif) {
1036        return IMPL.getExtras(notif);
1037    }
1038
1039    /**
1040     * Get whether or not this notification is only relevant to the current device.
1041     *
1042     * <p>Some notifications can be bridged to other devices for remote display.
1043     * If this hint is set, it is recommend that this notification not be bridged.
1044     */
1045    public static boolean getLocalOnly(Notification notif) {
1046        return IMPL.getLocalOnly(notif);
1047    }
1048}
1049