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