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