Home | History | Annotate | Download | only in app
      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 
     17 package android.support.v4.app;
     18 
     19 import android.app.Notification;
     20 import android.app.PendingIntent;
     21 import android.content.Context;
     22 import android.graphics.Bitmap;
     23 import android.graphics.Color;
     24 import android.media.AudioManager;
     25 import android.net.Uri;
     26 import android.os.Build;
     27 import android.os.Bundle;
     28 import android.os.Parcelable;
     29 import android.support.annotation.ColorInt;
     30 import android.support.v4.view.GravityCompat;
     31 import android.view.Gravity;
     32 import android.widget.RemoteViews;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Collections;
     36 import java.util.List;
     37 
     38 /**
     39  * Helper for accessing features in {@link android.app.Notification}
     40  * introduced after API level 4 in a backwards compatible fashion.
     41  */
     42 public class NotificationCompat {
     43 
     44     /**
     45      * Use all default values (where applicable).
     46      */
     47     public static final int DEFAULT_ALL = ~0;
     48 
     49     /**
     50      * Use the default notification sound. This will ignore any sound set using
     51      * {@link Builder#setSound}
     52      *
     53      * <p>
     54      * A notification that is noisy is more likely to be presented as a heads-up notification,
     55      * on some platforms.
     56      * </p>
     57      *
     58      * @see Builder#setDefaults
     59      */
     60     public static final int DEFAULT_SOUND = 1;
     61 
     62     /**
     63      * Use the default notification vibrate. This will ignore any vibrate set using
     64      * {@link Builder#setVibrate}. Using phone vibration requires the
     65      * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
     66      *
     67      * <p>
     68      * A notification that vibrates is more likely to be presented as a heads-up notification,
     69      * on some platforms.
     70      * </p>
     71      *
     72      * @see Builder#setDefaults
     73      */
     74     public static final int DEFAULT_VIBRATE = 2;
     75 
     76     /**
     77      * Use the default notification lights. This will ignore the
     78      * {@link #FLAG_SHOW_LIGHTS} bit, and values set with {@link Builder#setLights}.
     79      *
     80      * @see Builder#setDefaults
     81      */
     82     public static final int DEFAULT_LIGHTS = 4;
     83 
     84     /**
     85      * Use this constant as the value for audioStreamType to request that
     86      * the default stream type for notifications be used.  Currently the
     87      * default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
     88      */
     89     public static final int STREAM_DEFAULT = -1;
     90 
     91     /**
     92      * Bit set in the Notification flags field when LEDs should be turned on
     93      * for this notification.
     94      */
     95     public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
     96 
     97     /**
     98      * Bit set in the Notification flags field if this notification is in
     99      * reference to something that is ongoing, like a phone call.  It should
    100      * not be set if this notification is in reference to something that
    101      * happened at a particular point in time, like a missed phone call.
    102      */
    103     public static final int FLAG_ONGOING_EVENT      = 0x00000002;
    104 
    105     /**
    106      * Bit set in the Notification flags field if
    107      * the audio will be repeated until the notification is
    108      * cancelled or the notification window is opened.
    109      */
    110     public static final int FLAG_INSISTENT          = 0x00000004;
    111 
    112     /**
    113      * Bit set in the Notification flags field if the notification's sound,
    114      * vibrate and ticker should only be played if the notification is not already showing.
    115      */
    116     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
    117 
    118     /**
    119      * Bit set in the Notification flags field if the notification should be canceled when
    120      * it is clicked by the user.
    121      */
    122     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
    123 
    124     /**
    125      * Bit set in the Notification flags field if the notification should not be canceled
    126      * when the user clicks the Clear all button.
    127      */
    128     public static final int FLAG_NO_CLEAR           = 0x00000020;
    129 
    130     /**
    131      * Bit set in the Notification flags field if this notification represents a currently
    132      * running service.  This will normally be set for you by
    133      * {@link android.app.Service#startForeground}.
    134      */
    135     public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
    136 
    137     /**
    138      * Obsolete flag indicating high-priority notifications; use the priority field instead.
    139      *
    140      * @deprecated Use {@link NotificationCompat.Builder#setPriority(int)} with a positive value.
    141      */
    142     public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
    143 
    144     /**
    145      * Bit set in the Notification flags field if this notification is relevant to the current
    146      * device only and it is not recommended that it bridge to other devices.
    147      */
    148     public static final int FLAG_LOCAL_ONLY         = 0x00000100;
    149 
    150     /**
    151      * Bit set in the Notification flags field if this notification is the group summary for a
    152      * group of notifications. Grouped notifications may display in a cluster or stack on devices
    153      * which support such rendering. Requires a group key also be set using
    154      * {@link Builder#setGroup}.
    155      */
    156     public static final int FLAG_GROUP_SUMMARY      = 0x00000200;
    157 
    158     /**
    159      * Default notification priority for {@link NotificationCompat.Builder#setPriority(int)}.
    160      * If your application does not prioritize its own notifications,
    161      * use this value for all notifications.
    162      */
    163     public static final int PRIORITY_DEFAULT = 0;
    164 
    165     /**
    166      * Lower notification priority for {@link NotificationCompat.Builder#setPriority(int)},
    167      * for items that are less important. The UI may choose to show
    168      * these items smaller, or at a different position in the list,
    169      * compared with your app's {@link #PRIORITY_DEFAULT} items.
    170      */
    171     public static final int PRIORITY_LOW = -1;
    172 
    173     /**
    174      * Lowest notification priority for {@link NotificationCompat.Builder#setPriority(int)};
    175      * these items might not be shown to the user except under
    176      * special circumstances, such as detailed notification logs.
    177      */
    178     public static final int PRIORITY_MIN = -2;
    179 
    180     /**
    181      * Higher notification priority for {@link NotificationCompat.Builder#setPriority(int)},
    182      * for more important notifications or alerts. The UI may choose
    183      * to show these items larger, or at a different position in
    184      * notification lists, compared with your app's {@link #PRIORITY_DEFAULT} items.
    185      */
    186     public static final int PRIORITY_HIGH = 1;
    187 
    188     /**
    189      * Highest notification priority for {@link NotificationCompat.Builder#setPriority(int)},
    190      * for your application's most important items that require the user's
    191      * prompt attention or input.
    192      */
    193     public static final int PRIORITY_MAX = 2;
    194 
    195     /**
    196      * Notification extras key: this is the title of the notification,
    197      * as supplied to {@link Builder#setContentTitle(CharSequence)}.
    198      */
    199     public static final String EXTRA_TITLE = "android.title";
    200 
    201     /**
    202      * Notification extras key: this is the title of the notification when shown in expanded form,
    203      * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
    204      */
    205     public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
    206 
    207     /**
    208      * Notification extras key: this is the main text payload, as supplied to
    209      * {@link Builder#setContentText(CharSequence)}.
    210      */
    211     public static final String EXTRA_TEXT = "android.text";
    212 
    213     /**
    214      * Notification extras key: this is a third line of text, as supplied to
    215      * {@link Builder#setSubText(CharSequence)}.
    216      */
    217     public static final String EXTRA_SUB_TEXT = "android.subText";
    218 
    219     /**
    220      * Notification extras key: this is a small piece of additional text as supplied to
    221      * {@link Builder#setContentInfo(CharSequence)}.
    222      */
    223     public static final String EXTRA_INFO_TEXT = "android.infoText";
    224 
    225     /**
    226      * Notification extras key: this is a line of summary information intended to be shown
    227      * alongside expanded notifications, as supplied to (e.g.)
    228      * {@link BigTextStyle#setSummaryText(CharSequence)}.
    229      */
    230     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
    231 
    232     /**
    233      * Notification extras key: this is the longer text shown in the big form of a
    234      * {@link BigTextStyle} notification, as supplied to
    235      * {@link BigTextStyle#bigText(CharSequence)}.
    236      */
    237     public static final String EXTRA_BIG_TEXT = "android.bigText";
    238 
    239     /**
    240      * Notification extras key: this is the resource ID of the notification's main small icon, as
    241      * supplied to {@link Builder#setSmallIcon(int)}.
    242      */
    243     public static final String EXTRA_SMALL_ICON = "android.icon";
    244 
    245     /**
    246      * Notification extras key: this is a bitmap to be used instead of the small icon when showing the
    247      * notification payload, as
    248      * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
    249      */
    250     public static final String EXTRA_LARGE_ICON = "android.largeIcon";
    251 
    252     /**
    253      * Notification extras key: this is a bitmap to be used instead of the one from
    254      * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
    255      * shown in its expanded form, as supplied to
    256      * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
    257      */
    258     public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
    259 
    260     /**
    261      * Notification extras key: this is the progress value supplied to
    262      * {@link Builder#setProgress(int, int, boolean)}.
    263      */
    264     public static final String EXTRA_PROGRESS = "android.progress";
    265 
    266     /**
    267      * Notification extras key: this is the maximum value supplied to
    268      * {@link Builder#setProgress(int, int, boolean)}.
    269      */
    270     public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
    271 
    272     /**
    273      * Notification extras key: whether the progress bar is indeterminate, supplied to
    274      * {@link Builder#setProgress(int, int, boolean)}.
    275      */
    276     public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
    277 
    278     /**
    279      * Notification extras key: whether the when field set using {@link Builder#setWhen} should
    280      * be shown as a count-up timer (specifically a {@link android.widget.Chronometer}) instead
    281      * of a timestamp, as supplied to {@link Builder#setUsesChronometer(boolean)}.
    282      */
    283     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
    284 
    285     /**
    286      * Notification extras key: whether the when field set using {@link Builder#setWhen} should
    287      * be shown, as supplied to {@link Builder#setShowWhen(boolean)}.
    288      */
    289     public static final String EXTRA_SHOW_WHEN = "android.showWhen";
    290 
    291     /**
    292      * Notification extras key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
    293      * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
    294      */
    295     public static final String EXTRA_PICTURE = "android.picture";
    296 
    297     /**
    298      * Notification extras key: An array of CharSequences to show in {@link InboxStyle} expanded
    299      * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
    300      */
    301     public static final String EXTRA_TEXT_LINES = "android.textLines";
    302 
    303     /**
    304      * Notification extras key: A string representing the name of the specific
    305      * {@link android.app.Notification.Style} used to create this notification.
    306      */
    307     public static final String EXTRA_TEMPLATE = "android.template";
    308 
    309     /**
    310      * Notification extras key: A String array containing the people that this
    311      * notification relates to, each of which was supplied to
    312      * {@link Builder#addPerson(String)}.
    313      */
    314     public static final String EXTRA_PEOPLE = "android.people";
    315 
    316     /**
    317      * Notification extras key: A
    318      * {@link android.content.ContentUris content URI} pointing to an image that can be displayed
    319      * in the background when the notification is selected. The URI must point to an image stream
    320      * suitable for passing into
    321      * {@link android.graphics.BitmapFactory#decodeStream(java.io.InputStream)
    322      * BitmapFactory.decodeStream}; all other content types will be ignored. The content provider
    323      * URI used for this purpose must require no permissions to read the image data.
    324      */
    325     public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
    326 
    327     /**
    328      * Notification key: A
    329      * {@link android.media.session.MediaSession.Token} associated with a
    330      * {@link android.app.Notification.MediaStyle} notification.
    331      */
    332     public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
    333 
    334     /**
    335      * Notification extras key: the indices of actions to be shown in the compact view,
    336      * as supplied to (e.g.) {@link Notification.MediaStyle#setShowActionsInCompactView(int...)}.
    337      */
    338     public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
    339 
    340     /**
    341      * Value of {@link Notification#color} equal to 0 (also known as
    342      * {@link android.graphics.Color#TRANSPARENT Color.TRANSPARENT}),
    343      * telling the system not to decorate this notification with any special color but instead use
    344      * default colors when presenting this notification.
    345      */
    346     @ColorInt
    347     public static final int COLOR_DEFAULT = Color.TRANSPARENT;
    348 
    349     /**
    350      * Notification visibility: Show this notification in its entirety on all lockscreens.
    351      *
    352      * {@see android.app.Notification#visibility}
    353      */
    354     public static final int VISIBILITY_PUBLIC = 1;
    355 
    356     /**
    357      * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or
    358      * private information on secure lockscreens.
    359      *
    360      * {@see android.app.Notification#visibility}
    361      */
    362     public static final int VISIBILITY_PRIVATE = 0;
    363 
    364     /**
    365      * Notification visibility: Do not reveal any part of this notification on a secure lockscreen.
    366      *
    367      * {@see android.app.Notification#visibility}
    368      */
    369     public static final int VISIBILITY_SECRET = -1;
    370 
    371     /**
    372      * Notification category: incoming call (voice or video) or similar synchronous communication request.
    373      */
    374     public static final String CATEGORY_CALL = NotificationCompatApi21.CATEGORY_CALL;
    375 
    376     /**
    377      * Notification category: incoming direct message (SMS, instant message, etc.).
    378      */
    379     public static final String CATEGORY_MESSAGE = NotificationCompatApi21.CATEGORY_MESSAGE;
    380 
    381     /**
    382      * Notification category: asynchronous bulk message (email).
    383      */
    384     public static final String CATEGORY_EMAIL = NotificationCompatApi21.CATEGORY_EMAIL;
    385 
    386     /**
    387      * Notification category: calendar event.
    388      */
    389     public static final String CATEGORY_EVENT = NotificationCompatApi21.CATEGORY_EVENT;
    390 
    391     /**
    392      * Notification category: promotion or advertisement.
    393      */
    394     public static final String CATEGORY_PROMO = NotificationCompatApi21.CATEGORY_PROMO;
    395 
    396     /**
    397      * Notification category: alarm or timer.
    398      */
    399     public static final String CATEGORY_ALARM = NotificationCompatApi21.CATEGORY_ALARM;
    400 
    401     /**
    402      * Notification category: progress of a long-running background operation.
    403      */
    404     public static final String CATEGORY_PROGRESS = NotificationCompatApi21.CATEGORY_PROGRESS;
    405 
    406     /**
    407      * Notification category: social network or sharing update.
    408      */
    409     public static final String CATEGORY_SOCIAL = NotificationCompatApi21.CATEGORY_SOCIAL;
    410 
    411     /**
    412      * Notification category: error in background operation or authentication status.
    413      */
    414     public static final String CATEGORY_ERROR = NotificationCompatApi21.CATEGORY_ERROR;
    415 
    416     /**
    417      * Notification category: media transport control for playback.
    418      */
    419     public static final String CATEGORY_TRANSPORT = NotificationCompatApi21.CATEGORY_TRANSPORT;
    420 
    421     /**
    422      * Notification category: system or device status update.  Reserved for system use.
    423      */
    424     public static final String CATEGORY_SYSTEM = NotificationCompatApi21.CATEGORY_SYSTEM;
    425 
    426     /**
    427      * Notification category: indication of running background service.
    428      */
    429     public static final String CATEGORY_SERVICE = NotificationCompatApi21.CATEGORY_SERVICE;
    430 
    431     /**
    432      * Notification category: a specific, timely recommendation for a single thing.
    433      * For example, a news app might want to recommend a news story it believes the user will
    434      * want to read next.
    435      */
    436     public static final String CATEGORY_RECOMMENDATION =
    437             NotificationCompatApi21.CATEGORY_RECOMMENDATION;
    438 
    439     /**
    440      * Notification category: ongoing information about device or contextual status.
    441      */
    442     public static final String CATEGORY_STATUS = NotificationCompatApi21.CATEGORY_STATUS;
    443 
    444     private static final NotificationCompatImpl IMPL;
    445 
    446     interface NotificationCompatImpl {
    447         public Notification build(Builder b, BuilderExtender extender);
    448         public Bundle getExtras(Notification n);
    449         public int getActionCount(Notification n);
    450         public Action getAction(Notification n, int actionIndex);
    451         public Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables);
    452         public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions);
    453         public String getCategory(Notification n);
    454         public boolean getLocalOnly(Notification n);
    455         public String getGroup(Notification n);
    456         public boolean isGroupSummary(Notification n);
    457         public String getSortKey(Notification n);
    458         Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc);
    459         NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle(
    460                 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory,
    461                 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory);
    462     }
    463 
    464     /**
    465      * Interface for appcompat to extend v4 builder with media style.
    466      *
    467      * @hide
    468      */
    469     protected static class BuilderExtender {
    470         public Notification build(Builder b, NotificationBuilderWithBuilderAccessor builder) {
    471             return builder.build();
    472         }
    473     }
    474 
    475     static class NotificationCompatImplBase implements NotificationCompatImpl {
    476         @Override
    477         public Notification build(Builder b, BuilderExtender extender) {
    478             Notification result = b.mNotification;
    479             result.setLatestEventInfo(b.mContext, b.mContentTitle,
    480                     b.mContentText, b.mContentIntent);
    481             // translate high priority requests into legacy flag
    482             if (b.mPriority > PRIORITY_DEFAULT) {
    483                 result.flags |= FLAG_HIGH_PRIORITY;
    484             }
    485             return result;
    486         }
    487 
    488         @Override
    489         public Bundle getExtras(Notification n) {
    490             return null;
    491         }
    492 
    493         @Override
    494         public int getActionCount(Notification n) {
    495             return 0;
    496         }
    497 
    498         @Override
    499         public Action getAction(Notification n, int actionIndex) {
    500             return null;
    501         }
    502 
    503         @Override
    504         public Action[] getActionsFromParcelableArrayList(
    505                 ArrayList<Parcelable> parcelables) {
    506             return null;
    507         }
    508 
    509         @Override
    510         public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions) {
    511             return null;
    512         }
    513 
    514         @Override
    515         public String getCategory(Notification n) {
    516             return null;
    517         }
    518 
    519         @Override
    520         public boolean getLocalOnly(Notification n) {
    521             return false;
    522         }
    523 
    524         @Override
    525         public String getGroup(Notification n) {
    526             return null;
    527         }
    528 
    529         @Override
    530         public boolean isGroupSummary(Notification n) {
    531             return false;
    532         }
    533 
    534         @Override
    535         public String getSortKey(Notification n) {
    536             return null;
    537         }
    538 
    539         @Override
    540         public Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) {
    541             return null;
    542         }
    543 
    544         @Override
    545         public NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle(
    546                 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory,
    547                 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) {
    548             return null;
    549         }
    550     }
    551 
    552     static class NotificationCompatImplGingerbread extends NotificationCompatImplBase {
    553         @Override
    554         public Notification build(Builder b, BuilderExtender extender) {
    555             Notification result = b.mNotification;
    556             result.setLatestEventInfo(b.mContext, b.mContentTitle,
    557                     b.mContentText, b.mContentIntent);
    558             result = NotificationCompatGingerbread.add(result, b.mContext,
    559                     b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent);
    560             // translate high priority requests into legacy flag
    561             if (b.mPriority > PRIORITY_DEFAULT) {
    562                 result.flags |= FLAG_HIGH_PRIORITY;
    563             }
    564             return result;
    565         }
    566     }
    567 
    568     static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase {
    569         @Override
    570         public Notification build(Builder b, BuilderExtender extender) {
    571             return NotificationCompatHoneycomb.add(b.mContext, b.mNotification,
    572                     b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView,
    573                     b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon);
    574         }
    575     }
    576 
    577     static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase {
    578         @Override
    579         public Notification build(Builder b, BuilderExtender extender) {
    580             NotificationCompatIceCreamSandwich.Builder builder =
    581                     new NotificationCompatIceCreamSandwich.Builder(
    582                     b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
    583                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
    584                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate);
    585             return extender.build(b, builder);
    586         }
    587     }
    588 
    589     static class NotificationCompatImplJellybean extends NotificationCompatImplBase {
    590         @Override
    591         public Notification build(Builder b, BuilderExtender extender) {
    592             NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder(
    593                     b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
    594                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
    595                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate,
    596                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras,
    597                     b.mGroupKey, b.mGroupSummary, b.mSortKey);
    598             addActionsToBuilder(builder, b.mActions);
    599             addStyleToBuilderJellybean(builder, b.mStyle);
    600             return extender.build(b, builder);
    601         }
    602 
    603         @Override
    604         public Bundle getExtras(Notification n) {
    605             return NotificationCompatJellybean.getExtras(n);
    606         }
    607 
    608         @Override
    609         public int getActionCount(Notification n) {
    610             return NotificationCompatJellybean.getActionCount(n);
    611         }
    612 
    613         @Override
    614         public Action getAction(Notification n, int actionIndex) {
    615             return (Action) NotificationCompatJellybean.getAction(n, actionIndex, Action.FACTORY,
    616                     RemoteInput.FACTORY);
    617         }
    618 
    619         @Override
    620         public Action[] getActionsFromParcelableArrayList(
    621                 ArrayList<Parcelable> parcelables) {
    622             return (Action[]) NotificationCompatJellybean.getActionsFromParcelableArrayList(
    623                     parcelables, Action.FACTORY, RemoteInput.FACTORY);
    624         }
    625 
    626         @Override
    627         public ArrayList<Parcelable> getParcelableArrayListForActions(
    628                 Action[] actions) {
    629             return NotificationCompatJellybean.getParcelableArrayListForActions(actions);
    630         }
    631 
    632         @Override
    633         public boolean getLocalOnly(Notification n) {
    634             return NotificationCompatJellybean.getLocalOnly(n);
    635         }
    636 
    637         @Override
    638         public String getGroup(Notification n) {
    639             return NotificationCompatJellybean.getGroup(n);
    640         }
    641 
    642         @Override
    643         public boolean isGroupSummary(Notification n) {
    644             return NotificationCompatJellybean.isGroupSummary(n);
    645         }
    646 
    647         @Override
    648         public String getSortKey(Notification n) {
    649             return NotificationCompatJellybean.getSortKey(n);
    650         }
    651     }
    652 
    653     static class NotificationCompatImplKitKat extends NotificationCompatImplJellybean {
    654         @Override
    655         public Notification build(Builder b, BuilderExtender extender) {
    656             NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder(
    657                     b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
    658                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
    659                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
    660                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly,
    661                     b.mPeople, b.mExtras, b.mGroupKey, b.mGroupSummary, b.mSortKey);
    662             addActionsToBuilder(builder, b.mActions);
    663             addStyleToBuilderJellybean(builder, b.mStyle);
    664             return extender.build(b, builder);
    665         }
    666 
    667         @Override
    668         public Bundle getExtras(Notification n) {
    669             return NotificationCompatKitKat.getExtras(n);
    670         }
    671 
    672         @Override
    673         public int getActionCount(Notification n) {
    674             return NotificationCompatKitKat.getActionCount(n);
    675         }
    676 
    677         @Override
    678         public Action getAction(Notification n, int actionIndex) {
    679             return (Action) NotificationCompatKitKat.getAction(n, actionIndex, Action.FACTORY,
    680                     RemoteInput.FACTORY);
    681         }
    682 
    683         @Override
    684         public boolean getLocalOnly(Notification n) {
    685             return NotificationCompatKitKat.getLocalOnly(n);
    686         }
    687 
    688         @Override
    689         public String getGroup(Notification n) {
    690             return NotificationCompatKitKat.getGroup(n);
    691         }
    692 
    693         @Override
    694         public boolean isGroupSummary(Notification n) {
    695             return NotificationCompatKitKat.isGroupSummary(n);
    696         }
    697 
    698         @Override
    699         public String getSortKey(Notification n) {
    700             return NotificationCompatKitKat.getSortKey(n);
    701         }
    702     }
    703 
    704     static class NotificationCompatImplApi20 extends NotificationCompatImplKitKat {
    705         @Override
    706         public Notification build(Builder b, BuilderExtender extender) {
    707             NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder(
    708                     b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
    709                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
    710                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
    711                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras,
    712                     b.mGroupKey, b.mGroupSummary, b.mSortKey);
    713             addActionsToBuilder(builder, b.mActions);
    714             addStyleToBuilderJellybean(builder, b.mStyle);
    715             return extender.build(b, builder);
    716         }
    717 
    718         @Override
    719         public Action getAction(Notification n, int actionIndex) {
    720             return (Action) NotificationCompatApi20.getAction(n, actionIndex, Action.FACTORY,
    721                     RemoteInput.FACTORY);
    722         }
    723 
    724         @Override
    725         public Action[] getActionsFromParcelableArrayList(
    726                 ArrayList<Parcelable> parcelables) {
    727             return (Action[]) NotificationCompatApi20.getActionsFromParcelableArrayList(
    728                     parcelables, Action.FACTORY, RemoteInput.FACTORY);
    729         }
    730 
    731         @Override
    732         public ArrayList<Parcelable> getParcelableArrayListForActions(
    733                 Action[] actions) {
    734             return NotificationCompatApi20.getParcelableArrayListForActions(actions);
    735         }
    736 
    737         @Override
    738         public boolean getLocalOnly(Notification n) {
    739             return NotificationCompatApi20.getLocalOnly(n);
    740         }
    741 
    742         @Override
    743         public String getGroup(Notification n) {
    744             return NotificationCompatApi20.getGroup(n);
    745         }
    746 
    747         @Override
    748         public boolean isGroupSummary(Notification n) {
    749             return NotificationCompatApi20.isGroupSummary(n);
    750         }
    751 
    752         @Override
    753         public String getSortKey(Notification n) {
    754             return NotificationCompatApi20.getSortKey(n);
    755         }
    756     }
    757 
    758     static class NotificationCompatImplApi21 extends NotificationCompatImplApi20 {
    759         @Override
    760         public Notification build(Builder b, BuilderExtender extender) {
    761             NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder(
    762                     b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo,
    763                     b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon,
    764                     b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen,
    765                     b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory,
    766                     b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion,
    767                     b.mGroupKey, b.mGroupSummary, b.mSortKey);
    768             addActionsToBuilder(builder, b.mActions);
    769             addStyleToBuilderJellybean(builder, b.mStyle);
    770             return extender.build(b, builder);
    771         }
    772 
    773         @Override
    774         public String getCategory(Notification notif) {
    775             return NotificationCompatApi21.getCategory(notif);
    776         }
    777 
    778         @Override
    779         public Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) {
    780             return NotificationCompatApi21.getBundleForUnreadConversation(uc);
    781         }
    782 
    783         @Override
    784         public NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle(
    785                 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory,
    786                 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) {
    787             return NotificationCompatApi21.getUnreadConversationFromBundle(
    788                     b, factory, remoteInputFactory);
    789         }
    790     }
    791 
    792     private static void addActionsToBuilder(NotificationBuilderWithActions builder,
    793             ArrayList<Action> actions) {
    794         for (Action action : actions) {
    795             builder.addAction(action);
    796         }
    797     }
    798 
    799     private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder,
    800             Style style) {
    801         if (style != null) {
    802             if (style instanceof BigTextStyle) {
    803                 BigTextStyle bigTextStyle = (BigTextStyle) style;
    804                 NotificationCompatJellybean.addBigTextStyle(builder,
    805                         bigTextStyle.mBigContentTitle,
    806                         bigTextStyle.mSummaryTextSet,
    807                         bigTextStyle.mSummaryText,
    808                         bigTextStyle.mBigText);
    809             } else if (style instanceof InboxStyle) {
    810                 InboxStyle inboxStyle = (InboxStyle) style;
    811                 NotificationCompatJellybean.addInboxStyle(builder,
    812                         inboxStyle.mBigContentTitle,
    813                         inboxStyle.mSummaryTextSet,
    814                         inboxStyle.mSummaryText,
    815                         inboxStyle.mTexts);
    816             } else if (style instanceof BigPictureStyle) {
    817                 BigPictureStyle bigPictureStyle = (BigPictureStyle) style;
    818                 NotificationCompatJellybean.addBigPictureStyle(builder,
    819                         bigPictureStyle.mBigContentTitle,
    820                         bigPictureStyle.mSummaryTextSet,
    821                         bigPictureStyle.mSummaryText,
    822                         bigPictureStyle.mPicture,
    823                         bigPictureStyle.mBigLargeIcon,
    824                         bigPictureStyle.mBigLargeIconSet);
    825             }
    826         }
    827     }
    828 
    829     static {
    830         if (Build.VERSION.SDK_INT >= 21) {
    831             IMPL = new NotificationCompatImplApi21();
    832         } else if (Build.VERSION.SDK_INT >= 20) {
    833             IMPL = new NotificationCompatImplApi20();
    834         } else if (Build.VERSION.SDK_INT >= 19) {
    835             IMPL = new NotificationCompatImplKitKat();
    836         } else if (Build.VERSION.SDK_INT >= 16) {
    837             IMPL = new NotificationCompatImplJellybean();
    838         } else if (Build.VERSION.SDK_INT >= 14) {
    839             IMPL = new NotificationCompatImplIceCreamSandwich();
    840         } else if (Build.VERSION.SDK_INT >= 11) {
    841             IMPL = new NotificationCompatImplHoneycomb();
    842         } else if (Build.VERSION.SDK_INT >= 9) {
    843             IMPL = new NotificationCompatImplGingerbread();
    844         } else {
    845             IMPL = new NotificationCompatImplBase();
    846         }
    847     }
    848 
    849     /**
    850      * Builder class for {@link NotificationCompat} objects.  Allows easier control over
    851      * all the flags, as well as help constructing the typical notification layouts.
    852      * <p>
    853      * On platform versions that don't offer expanded notifications, methods that depend on
    854      * expanded notifications have no effect.
    855      * </p>
    856      * <p>
    857      * For example, action buttons won't appear on platforms prior to Android 4.1. Action
    858      * buttons depend on expanded notifications, which are only available in Android 4.1
    859      * and later.
    860      * <p>
    861      * For this reason, you should always ensure that UI controls in a notification are also
    862      * available in an {@link android.app.Activity} in your app, and you should always start that
    863      * {@link android.app.Activity} when users click the notification. To do this, use the
    864      * {@link NotificationCompat.Builder#setContentIntent setContentIntent()}
    865      * method.
    866      * </p>
    867      *
    868      */
    869     public static class Builder {
    870         /**
    871          * Maximum length of CharSequences accepted by Builder and friends.
    872          *
    873          * <p>
    874          * Avoids spamming the system with overly large strings such as full e-mails.
    875          */
    876         private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
    877 
    878         // All these variables are declared public/hidden so they can be accessed by a builder
    879         // extender.
    880 
    881         /** @hide */
    882         public Context mContext;
    883 
    884         /** @hide */
    885         public CharSequence mContentTitle;
    886         /** @hide */
    887         public CharSequence mContentText;
    888         PendingIntent mContentIntent;
    889         PendingIntent mFullScreenIntent;
    890         RemoteViews mTickerView;
    891         /** @hide */
    892         public Bitmap mLargeIcon;
    893         /** @hide */
    894         public CharSequence mContentInfo;
    895         /** @hide */
    896         public int mNumber;
    897         int mPriority;
    898         boolean mShowWhen = true;
    899         /** @hide */
    900         public boolean mUseChronometer;
    901         /** @hide */
    902         public Style mStyle;
    903         /** @hide */
    904         public CharSequence mSubText;
    905         int mProgressMax;
    906         int mProgress;
    907         boolean mProgressIndeterminate;
    908         String mGroupKey;
    909         boolean mGroupSummary;
    910         String mSortKey;
    911         /** @hide */
    912         public ArrayList<Action> mActions = new ArrayList<Action>();
    913         boolean mLocalOnly = false;
    914         String mCategory;
    915         Bundle mExtras;
    916         int mColor = COLOR_DEFAULT;
    917         int mVisibility = VISIBILITY_PRIVATE;
    918         Notification mPublicVersion;
    919 
    920         /** @hide */
    921         public Notification mNotification = new Notification();
    922         public ArrayList<String> mPeople;
    923 
    924         /**
    925          * Constructor.
    926          *
    927          * Automatically sets the when field to {@link System#currentTimeMillis()
    928          * System.currentTimeMillis()} and the audio stream to the
    929          * {@link Notification#STREAM_DEFAULT}.
    930          *
    931          * @param context A {@link Context} that will be used to construct the
    932          *      RemoteViews. The Context will not be held past the lifetime of this
    933          *      Builder object.
    934          */
    935         public Builder(Context context) {
    936             mContext = context;
    937 
    938             // Set defaults to match the defaults of a Notification
    939             mNotification.when = System.currentTimeMillis();
    940             mNotification.audioStreamType = Notification.STREAM_DEFAULT;
    941             mPriority = PRIORITY_DEFAULT;
    942             mPeople = new ArrayList<String>();
    943         }
    944 
    945         /**
    946          * Set the time that the event occurred.  Notifications in the panel are
    947          * sorted by this time.
    948          */
    949         public Builder setWhen(long when) {
    950             mNotification.when = when;
    951             return this;
    952         }
    953 
    954         /**
    955          * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
    956          * in the content view.
    957          */
    958         public Builder setShowWhen(boolean show) {
    959             mShowWhen = show;
    960             return this;
    961         }
    962 
    963         /**
    964          * Show the {@link Notification#when} field as a stopwatch.
    965          *
    966          * Instead of presenting <code>when</code> as a timestamp, the notification will show an
    967          * automatically updating display of the minutes and seconds since <code>when</code>.
    968          *
    969          * Useful when showing an elapsed time (like an ongoing phone call).
    970          *
    971          * @see android.widget.Chronometer
    972          * @see Notification#when
    973          */
    974         public Builder setUsesChronometer(boolean b) {
    975             mUseChronometer = b;
    976             return this;
    977         }
    978 
    979         /**
    980          * Set the small icon to use in the notification layouts.  Different classes of devices
    981          * may return different sizes.  See the UX guidelines for more information on how to
    982          * design these icons.
    983          *
    984          * @param icon A resource ID in the application's package of the drawble to use.
    985          */
    986         public Builder setSmallIcon(int icon) {
    987             mNotification.icon = icon;
    988             return this;
    989         }
    990 
    991         /**
    992          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
    993          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
    994          * LevelListDrawable}.
    995          *
    996          * @param icon A resource ID in the application's package of the drawble to use.
    997          * @param level The level to use for the icon.
    998          *
    999          * @see android.graphics.drawable.LevelListDrawable
   1000          */
   1001         public Builder setSmallIcon(int icon, int level) {
   1002             mNotification.icon = icon;
   1003             mNotification.iconLevel = level;
   1004             return this;
   1005         }
   1006 
   1007         /**
   1008          * Set the title (first row) of the notification, in a standard notification.
   1009          */
   1010         public Builder setContentTitle(CharSequence title) {
   1011             mContentTitle = limitCharSequenceLength(title);
   1012             return this;
   1013         }
   1014 
   1015         /**
   1016          * Set the text (second row) of the notification, in a standard notification.
   1017          */
   1018         public Builder setContentText(CharSequence text) {
   1019             mContentText = limitCharSequenceLength(text);
   1020             return this;
   1021         }
   1022 
   1023         /**
   1024          * Set the third line of text in the platform notification template.
   1025          * Don't use if you're also using {@link #setProgress(int, int, boolean)};
   1026          * they occupy the same location in the standard template.
   1027          * <br>
   1028          * If the platform does not provide large-format notifications, this method has no effect.
   1029          * The third line of text only appears in expanded view.
   1030          * <br>
   1031          */
   1032         public Builder setSubText(CharSequence text) {
   1033             mSubText = limitCharSequenceLength(text);
   1034             return this;
   1035         }
   1036 
   1037         /**
   1038          * Set the large number at the right-hand side of the notification.  This is
   1039          * equivalent to setContentInfo, although it might show the number in a different
   1040          * font size for readability.
   1041          */
   1042         public Builder setNumber(int number) {
   1043             mNumber = number;
   1044             return this;
   1045         }
   1046 
   1047         /**
   1048          * Set the large text at the right-hand side of the notification.
   1049          */
   1050         public Builder setContentInfo(CharSequence info) {
   1051             mContentInfo = limitCharSequenceLength(info);
   1052             return this;
   1053         }
   1054 
   1055         /**
   1056          * Set the progress this notification represents, which may be
   1057          * represented as a {@link android.widget.ProgressBar}.
   1058          */
   1059         public Builder setProgress(int max, int progress, boolean indeterminate) {
   1060             mProgressMax = max;
   1061             mProgress = progress;
   1062             mProgressIndeterminate = indeterminate;
   1063             return this;
   1064         }
   1065 
   1066         /**
   1067          * Supply a custom RemoteViews to use instead of the standard one.
   1068          */
   1069         public Builder setContent(RemoteViews views) {
   1070             mNotification.contentView = views;
   1071             return this;
   1072         }
   1073 
   1074         /**
   1075          * Supply a {@link PendingIntent} to send when the notification is clicked.
   1076          * If you do not supply an intent, you can now add PendingIntents to individual
   1077          * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent
   1078          * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}.  Be sure to
   1079          * read {@link Notification#contentIntent Notification.contentIntent} for
   1080          * how to correctly use this.
   1081          */
   1082         public Builder setContentIntent(PendingIntent intent) {
   1083             mContentIntent = intent;
   1084             return this;
   1085         }
   1086 
   1087         /**
   1088          * Supply a {@link PendingIntent} to send when the notification is cleared by the user
   1089          * directly from the notification panel.  For example, this intent is sent when the user
   1090          * clicks the "Clear all" button, or the individual "X" buttons on notifications.  This
   1091          * intent is not sent when the application calls
   1092          * {@link android.app.NotificationManager#cancel NotificationManager.cancel(int)}.
   1093          */
   1094         public Builder setDeleteIntent(PendingIntent intent) {
   1095             mNotification.deleteIntent = intent;
   1096             return this;
   1097         }
   1098 
   1099         /**
   1100          * An intent to launch instead of posting the notification to the status bar.
   1101          * Only for use with extremely high-priority notifications demanding the user's
   1102          * <strong>immediate</strong> attention, such as an incoming phone call or
   1103          * alarm clock that the user has explicitly set to a particular time.
   1104          * If this facility is used for something else, please give the user an option
   1105          * to turn it off and use a normal notification, as this can be extremely
   1106          * disruptive.
   1107          *
   1108          * <p>
   1109          * On some platforms, the system UI may choose to display a heads-up notification,
   1110          * instead of launching this intent, while the user is using the device.
   1111          * </p>
   1112          *
   1113          * @param intent The pending intent to launch.
   1114          * @param highPriority Passing true will cause this notification to be sent
   1115          *          even if other notifications are suppressed.
   1116          */
   1117         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
   1118             mFullScreenIntent = intent;
   1119             setFlag(FLAG_HIGH_PRIORITY, highPriority);
   1120             return this;
   1121         }
   1122 
   1123         /**
   1124          * Set the text that is displayed in the status bar when the notification first
   1125          * arrives.
   1126          */
   1127         public Builder setTicker(CharSequence tickerText) {
   1128             mNotification.tickerText = limitCharSequenceLength(tickerText);
   1129             return this;
   1130         }
   1131 
   1132         /**
   1133          * Set the text that is displayed in the status bar when the notification first
   1134          * arrives, and also a RemoteViews object that may be displayed instead on some
   1135          * devices.
   1136          */
   1137         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
   1138             mNotification.tickerText = limitCharSequenceLength(tickerText);
   1139             mTickerView = views;
   1140             return this;
   1141         }
   1142 
   1143         /**
   1144          * Set the large icon that is shown in the ticker and notification.
   1145          */
   1146         public Builder setLargeIcon(Bitmap icon) {
   1147             mLargeIcon = icon;
   1148             return this;
   1149         }
   1150 
   1151         /**
   1152          * Set the sound to play.  It will play on the default stream.
   1153          *
   1154          * <p>
   1155          * On some platforms, a notification that is noisy is more likely to be presented
   1156          * as a heads-up notification.
   1157          * </p>
   1158          */
   1159         public Builder setSound(Uri sound) {
   1160             mNotification.sound = sound;
   1161             mNotification.audioStreamType = Notification.STREAM_DEFAULT;
   1162             return this;
   1163         }
   1164 
   1165         /**
   1166          * Set the sound to play.  It will play on the stream you supply.
   1167          *
   1168          * <p>
   1169          * On some platforms, a notification that is noisy is more likely to be presented
   1170          * as a heads-up notification.
   1171          * </p>
   1172          *
   1173          * @see Notification#STREAM_DEFAULT
   1174          * @see AudioManager for the <code>STREAM_</code> constants.
   1175          */
   1176         public Builder setSound(Uri sound, int streamType) {
   1177             mNotification.sound = sound;
   1178             mNotification.audioStreamType = streamType;
   1179             return this;
   1180         }
   1181 
   1182         /**
   1183          * Set the vibration pattern to use.
   1184          *
   1185          * <p>
   1186          * On some platforms, a notification that vibrates is more likely to be presented
   1187          * as a heads-up notification.
   1188          * </p>
   1189          *
   1190          * @see android.os.Vibrator for a discussion of the <code>pattern</code>
   1191          * parameter.
   1192          */
   1193         public Builder setVibrate(long[] pattern) {
   1194             mNotification.vibrate = pattern;
   1195             return this;
   1196         }
   1197 
   1198         /**
   1199          * Set the argb value that you would like the LED on the device to blnk, as well as the
   1200          * rate.  The rate is specified in terms of the number of milliseconds to be on
   1201          * and then the number of milliseconds to be off.
   1202          */
   1203         public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
   1204             mNotification.ledARGB = argb;
   1205             mNotification.ledOnMS = onMs;
   1206             mNotification.ledOffMS = offMs;
   1207             boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0;
   1208             mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) |
   1209                     (showLights ? Notification.FLAG_SHOW_LIGHTS : 0);
   1210             return this;
   1211         }
   1212 
   1213         /**
   1214          * Set whether this is an ongoing notification.
   1215          *
   1216          * <p>Ongoing notifications differ from regular notifications in the following ways:
   1217          * <ul>
   1218          *   <li>Ongoing notifications are sorted above the regular notifications in the
   1219          *   notification panel.</li>
   1220          *   <li>Ongoing notifications do not have an 'X' close button, and are not affected
   1221          *   by the "Clear all" button.
   1222          * </ul>
   1223          */
   1224         public Builder setOngoing(boolean ongoing) {
   1225             setFlag(Notification.FLAG_ONGOING_EVENT, ongoing);
   1226             return this;
   1227         }
   1228 
   1229         /**
   1230          * Set this flag if you would only like the sound, vibrate
   1231          * and ticker to be played if the notification is not already showing.
   1232          */
   1233         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
   1234             setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
   1235             return this;
   1236         }
   1237 
   1238         /**
   1239          * Setting this flag will make it so the notification is automatically
   1240          * canceled when the user clicks it in the panel.  The PendingIntent
   1241          * set with {@link #setDeleteIntent} will be broadcast when the notification
   1242          * is canceled.
   1243          */
   1244         public Builder setAutoCancel(boolean autoCancel) {
   1245             setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel);
   1246             return this;
   1247         }
   1248 
   1249         /**
   1250          * Set whether or not this notification is only relevant to the current device.
   1251          *
   1252          * <p>Some notifications can be bridged to other devices for remote display.
   1253          * This hint can be set to recommend this notification not be bridged.
   1254          */
   1255         public Builder setLocalOnly(boolean b) {
   1256             mLocalOnly = b;
   1257             return this;
   1258         }
   1259 
   1260         /**
   1261          * Set the notification category.
   1262          *
   1263          * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code>
   1264          * constants in {@link Notification}) that best describes this notification.
   1265          * May be used by the system for ranking and filtering.
   1266          */
   1267         public Builder setCategory(String category) {
   1268             mCategory = category;
   1269             return this;
   1270         }
   1271 
   1272         /**
   1273          * Set the default notification options that will be used.
   1274          * <p>
   1275          * The value should be one or more of the following fields combined with
   1276          * bitwise-or:
   1277          * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE},
   1278          * {@link Notification#DEFAULT_LIGHTS}.
   1279          * <p>
   1280          * For all default values, use {@link Notification#DEFAULT_ALL}.
   1281          */
   1282         public Builder setDefaults(int defaults) {
   1283             mNotification.defaults = defaults;
   1284             if ((defaults & Notification.DEFAULT_LIGHTS) != 0) {
   1285                 mNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
   1286             }
   1287             return this;
   1288         }
   1289 
   1290         private void setFlag(int mask, boolean value) {
   1291             if (value) {
   1292                 mNotification.flags |= mask;
   1293             } else {
   1294                 mNotification.flags &= ~mask;
   1295             }
   1296         }
   1297 
   1298         /**
   1299          * Set the relative priority for this notification.
   1300          *
   1301          * Priority is an indication of how much of the user's
   1302          * valuable attention should be consumed by this
   1303          * notification. Low-priority notifications may be hidden from
   1304          * the user in certain situations, while the user might be
   1305          * interrupted for a higher-priority notification.
   1306          * The system sets a notification's priority based on various factors including the
   1307          * setPriority value. The effect may differ slightly on different platforms.
   1308          *
   1309          * @param pri Relative priority for this notification. Must be one of
   1310          *     the priority constants defined by {@link NotificationCompat}.
   1311          *     Acceptable values range from {@link
   1312          *     NotificationCompat#PRIORITY_MIN} (-2) to {@link
   1313          *     NotificationCompat#PRIORITY_MAX} (2).
   1314          */
   1315         public Builder setPriority(int pri) {
   1316             mPriority = pri;
   1317             return this;
   1318         }
   1319 
   1320         /**
   1321          * Add a person that is relevant to this notification.
   1322          *
   1323          * <P>
   1324          * Depending on user preferences, this annotation may allow the notification to pass
   1325          * through interruption filters, and to appear more prominently in the user interface.
   1326          * </P>
   1327          *
   1328          * <P>
   1329          * The person should be specified by the {@code String} representation of a
   1330          * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
   1331          * </P>
   1332          *
   1333          * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema
   1334          * URIs.  The path part of these URIs must exist in the contacts database, in the
   1335          * appropriate column, or the reference will be discarded as invalid. Telephone schema
   1336          * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}.
   1337          * </P>
   1338          *
   1339          * @param uri A URI for the person.
   1340          * @see Notification#EXTRA_PEOPLE
   1341          */
   1342         public Builder addPerson(String uri) {
   1343             mPeople.add(uri);
   1344             return this;
   1345         }
   1346 
   1347         /**
   1348          * Set this notification to be part of a group of notifications sharing the same key.
   1349          * Grouped notifications may display in a cluster or stack on devices which
   1350          * support such rendering.
   1351          *
   1352          * <p>To make this notification the summary for its group, also call
   1353          * {@link #setGroupSummary}. A sort order can be specified for group members by using
   1354          * {@link #setSortKey}.
   1355          * @param groupKey The group key of the group.
   1356          * @return this object for method chaining
   1357          */
   1358         public Builder setGroup(String groupKey) {
   1359             mGroupKey = groupKey;
   1360             return this;
   1361         }
   1362 
   1363         /**
   1364          * Set this notification to be the group summary for a group of notifications.
   1365          * Grouped notifications may display in a cluster or stack on devices which
   1366          * support such rendering. Requires a group key also be set using {@link #setGroup}.
   1367          * @param isGroupSummary Whether this notification should be a group summary.
   1368          * @return this object for method chaining
   1369          */
   1370         public Builder setGroupSummary(boolean isGroupSummary) {
   1371             mGroupSummary = isGroupSummary;
   1372             return this;
   1373         }
   1374 
   1375         /**
   1376          * Set a sort key that orders this notification among other notifications from the
   1377          * same package. This can be useful if an external sort was already applied and an app
   1378          * would like to preserve this. Notifications will be sorted lexicographically using this
   1379          * value, although providing different priorities in addition to providing sort key may
   1380          * cause this value to be ignored.
   1381          *
   1382          * <p>This sort key can also be used to order members of a notification group. See
   1383          * {@link Builder#setGroup}.
   1384          *
   1385          * @see String#compareTo(String)
   1386          */
   1387         public Builder setSortKey(String sortKey) {
   1388             mSortKey = sortKey;
   1389             return this;
   1390         }
   1391 
   1392         /**
   1393          * Merge additional metadata into this notification.
   1394          *
   1395          * <p>Values within the Bundle will replace existing extras values in this Builder.
   1396          *
   1397          * @see Notification#extras
   1398          */
   1399         public Builder addExtras(Bundle extras) {
   1400             if (extras != null) {
   1401                 if (mExtras == null) {
   1402                     mExtras = new Bundle(extras);
   1403                 } else {
   1404                     mExtras.putAll(extras);
   1405                 }
   1406             }
   1407             return this;
   1408         }
   1409 
   1410         /**
   1411          * Set metadata for this notification.
   1412          *
   1413          * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
   1414          * current contents are copied into the Notification each time {@link #build()} is
   1415          * called.
   1416          *
   1417          * <p>Replaces any existing extras values with those from the provided Bundle.
   1418          * Use {@link #addExtras} to merge in metadata instead.
   1419          *
   1420          * @see Notification#extras
   1421          */
   1422         public Builder setExtras(Bundle extras) {
   1423             mExtras = extras;
   1424             return this;
   1425         }
   1426 
   1427         /**
   1428          * Get the current metadata Bundle used by this notification Builder.
   1429          *
   1430          * <p>The returned Bundle is shared with this Builder.
   1431          *
   1432          * <p>The current contents of this Bundle are copied into the Notification each time
   1433          * {@link #build()} is called.
   1434          *
   1435          * @see Notification#extras
   1436          */
   1437         public Bundle getExtras() {
   1438             if (mExtras == null) {
   1439                 mExtras = new Bundle();
   1440             }
   1441             return mExtras;
   1442         }
   1443 
   1444         /**
   1445          * Add an action to this notification. Actions are typically displayed by
   1446          * the system as a button adjacent to the notification content.
   1447          * <br>
   1448          * Action buttons won't appear on platforms prior to Android 4.1. Action
   1449          * buttons depend on expanded notifications, which are only available in Android 4.1
   1450          * and later. To ensure that an action button's functionality is always available, first
   1451          * implement the functionality in the {@link android.app.Activity} that starts when a user
   1452          * clicks the  notification (see {@link #setContentIntent setContentIntent()}), and then
   1453          * enhance the notification by implementing the same functionality with
   1454          * {@link #addAction addAction()}.
   1455          *
   1456          * @param icon Resource ID of a drawable that represents the action.
   1457          * @param title Text describing the action.
   1458          * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked.
   1459          */
   1460         public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
   1461             mActions.add(new Action(icon, title, intent));
   1462             return this;
   1463         }
   1464 
   1465         /**
   1466          * Add an action to this notification. Actions are typically displayed by
   1467          * the system as a button adjacent to the notification content.
   1468          * <br>
   1469          * Action buttons won't appear on platforms prior to Android 4.1. Action
   1470          * buttons depend on expanded notifications, which are only available in Android 4.1
   1471          * and later. To ensure that an action button's functionality is always available, first
   1472          * implement the functionality in the {@link android.app.Activity} that starts when a user
   1473          * clicks the  notification (see {@link #setContentIntent setContentIntent()}), and then
   1474          * enhance the notification by implementing the same functionality with
   1475          * {@link #addAction addAction()}.
   1476          *
   1477          * @param action The action to add.
   1478          */
   1479         public Builder addAction(Action action) {
   1480             mActions.add(action);
   1481             return this;
   1482         }
   1483 
   1484         /**
   1485          * Add a rich notification style to be applied at build time.
   1486          * <br>
   1487          * If the platform does not provide rich notification styles, this method has no effect. The
   1488          * user will always see the normal notification style.
   1489          *
   1490          * @param style Object responsible for modifying the notification style.
   1491          */
   1492         public Builder setStyle(Style style) {
   1493             if (mStyle != style) {
   1494                 mStyle = style;
   1495                 if (mStyle != null) {
   1496                     mStyle.setBuilder(this);
   1497                 }
   1498             }
   1499             return this;
   1500         }
   1501 
   1502         /**
   1503          * Sets {@link Notification#color}.
   1504          *
   1505          * @param argb The accent color to use
   1506          *
   1507          * @return The same Builder.
   1508          */
   1509         public Builder setColor(@ColorInt int argb) {
   1510             mColor = argb;
   1511             return this;
   1512         }
   1513 
   1514         /**
   1515          * Sets {@link Notification#visibility}.
   1516          *
   1517          * @param visibility One of {@link Notification#VISIBILITY_PRIVATE} (the default),
   1518          *                   {@link Notification#VISIBILITY_PUBLIC}, or
   1519          *                   {@link Notification#VISIBILITY_SECRET}.
   1520          */
   1521         public Builder setVisibility(int visibility) {
   1522             mVisibility = visibility;
   1523             return this;
   1524         }
   1525 
   1526         /**
   1527          * Supply a replacement Notification whose contents should be shown in insecure contexts
   1528          * (i.e. atop the secure lockscreen). See {@link Notification#visibility} and
   1529          * {@link #VISIBILITY_PUBLIC}.
   1530          *
   1531          * @param n A replacement notification, presumably with some or all info redacted.
   1532          * @return The same Builder.
   1533          */
   1534         public Builder setPublicVersion(Notification n) {
   1535             mPublicVersion = n;
   1536             return this;
   1537         }
   1538 
   1539         /**
   1540          * Apply an extender to this notification builder. Extenders may be used to add
   1541          * metadata or change options on this builder.
   1542          */
   1543         public Builder extend(Extender extender) {
   1544             extender.extend(this);
   1545             return this;
   1546         }
   1547 
   1548         /**
   1549          * @deprecated Use {@link #build()} instead.
   1550          */
   1551         @Deprecated
   1552         public Notification getNotification() {
   1553             return build();
   1554         }
   1555 
   1556         /**
   1557          * Combine all of the options that have been set and return a new {@link Notification}
   1558          * object.
   1559          */
   1560         public Notification build() {
   1561             return IMPL.build(this, getExtender());
   1562         }
   1563 
   1564         /**
   1565          * @hide
   1566          */
   1567         protected BuilderExtender getExtender() {
   1568             return new BuilderExtender();
   1569         }
   1570 
   1571         protected static CharSequence limitCharSequenceLength(CharSequence cs) {
   1572             if (cs == null) return cs;
   1573             if (cs.length() > MAX_CHARSEQUENCE_LENGTH) {
   1574                 cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH);
   1575             }
   1576             return cs;
   1577         }
   1578     }
   1579 
   1580     /**
   1581      * An object that can apply a rich notification style to a {@link Notification.Builder}
   1582      * object.
   1583      * <br>
   1584      * If the platform does not provide rich notification styles, methods in this class have no
   1585      * effect.
   1586      */
   1587     public static abstract class Style {
   1588         Builder mBuilder;
   1589         CharSequence mBigContentTitle;
   1590         CharSequence mSummaryText;
   1591         boolean mSummaryTextSet = false;
   1592 
   1593         public void setBuilder(Builder builder) {
   1594             if (mBuilder != builder) {
   1595                 mBuilder = builder;
   1596                 if (mBuilder != null) {
   1597                     mBuilder.setStyle(this);
   1598                 }
   1599             }
   1600         }
   1601 
   1602         public Notification build() {
   1603             Notification notification = null;
   1604             if (mBuilder != null) {
   1605                 notification = mBuilder.build();
   1606             }
   1607             return notification;
   1608         }
   1609     }
   1610 
   1611     /**
   1612      * Helper class for generating large-format notifications that include a large image attachment.
   1613      * <br>
   1614      * If the platform does not provide large-format notifications, this method has no effect. The
   1615      * user will always see the normal notification view.
   1616      * <br>
   1617      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
   1618      * <pre class="prettyprint">
   1619      * Notification notif = new Notification.Builder(mContext)
   1620      *     .setContentTitle(&quot;New photo from &quot; + sender.toString())
   1621      *     .setContentText(subject)
   1622      *     .setSmallIcon(R.drawable.new_post)
   1623      *     .setLargeIcon(aBitmap)
   1624      *     .setStyle(new Notification.BigPictureStyle()
   1625      *         .bigPicture(aBigBitmap))
   1626      *     .build();
   1627      * </pre>
   1628      *
   1629      * @see Notification#bigContentView
   1630      */
   1631     public static class BigPictureStyle extends Style {
   1632         Bitmap mPicture;
   1633         Bitmap mBigLargeIcon;
   1634         boolean mBigLargeIconSet;
   1635 
   1636         public BigPictureStyle() {
   1637         }
   1638 
   1639         public BigPictureStyle(Builder builder) {
   1640             setBuilder(builder);
   1641         }
   1642 
   1643         /**
   1644          * Overrides ContentTitle in the big form of the template.
   1645          * This defaults to the value passed to setContentTitle().
   1646          */
   1647         public BigPictureStyle setBigContentTitle(CharSequence title) {
   1648             mBigContentTitle = Builder.limitCharSequenceLength(title);
   1649             return this;
   1650         }
   1651 
   1652         /**
   1653          * Set the first line of text after the detail section in the big form of the template.
   1654          */
   1655         public BigPictureStyle setSummaryText(CharSequence cs) {
   1656             mSummaryText = Builder.limitCharSequenceLength(cs);
   1657             mSummaryTextSet = true;
   1658             return this;
   1659         }
   1660 
   1661         /**
   1662          * Provide the bitmap to be used as the payload for the BigPicture notification.
   1663          */
   1664         public BigPictureStyle bigPicture(Bitmap b) {
   1665             mPicture = b;
   1666             return this;
   1667         }
   1668 
   1669         /**
   1670          * Override the large icon when the big notification is shown.
   1671          */
   1672         public BigPictureStyle bigLargeIcon(Bitmap b) {
   1673             mBigLargeIcon = b;
   1674             mBigLargeIconSet = true;
   1675             return this;
   1676         }
   1677     }
   1678 
   1679     /**
   1680      * Helper class for generating large-format notifications that include a lot of text.
   1681      *
   1682      * <br>
   1683      * If the platform does not provide large-format notifications, this method has no effect. The
   1684      * user will always see the normal notification view.
   1685      * <br>
   1686      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
   1687      * <pre class="prettyprint">
   1688      * Notification notif = new Notification.Builder(mContext)
   1689      *     .setContentTitle(&quot;New mail from &quot; + sender.toString())
   1690      *     .setContentText(subject)
   1691      *     .setSmallIcon(R.drawable.new_mail)
   1692      *     .setLargeIcon(aBitmap)
   1693      *     .setStyle(new Notification.BigTextStyle()
   1694      *         .bigText(aVeryLongString))
   1695      *     .build();
   1696      * </pre>
   1697      *
   1698      * @see Notification#bigContentView
   1699      */
   1700     public static class BigTextStyle extends Style {
   1701         CharSequence mBigText;
   1702 
   1703         public BigTextStyle() {
   1704         }
   1705 
   1706         public BigTextStyle(Builder builder) {
   1707             setBuilder(builder);
   1708         }
   1709 
   1710         /**
   1711          * Overrides ContentTitle in the big form of the template.
   1712          * This defaults to the value passed to setContentTitle().
   1713          */
   1714         public BigTextStyle setBigContentTitle(CharSequence title) {
   1715             mBigContentTitle = Builder.limitCharSequenceLength(title);
   1716             return this;
   1717         }
   1718 
   1719         /**
   1720          * Set the first line of text after the detail section in the big form of the template.
   1721          */
   1722         public BigTextStyle setSummaryText(CharSequence cs) {
   1723             mSummaryText = Builder.limitCharSequenceLength(cs);
   1724             mSummaryTextSet = true;
   1725             return this;
   1726         }
   1727 
   1728         /**
   1729          * Provide the longer text to be displayed in the big form of the
   1730          * template in place of the content text.
   1731          */
   1732         public BigTextStyle bigText(CharSequence cs) {
   1733             mBigText = Builder.limitCharSequenceLength(cs);
   1734             return this;
   1735         }
   1736     }
   1737 
   1738     /**
   1739      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
   1740      *
   1741      * <br>
   1742      * If the platform does not provide large-format notifications, this method has no effect. The
   1743      * user will always see the normal notification view.
   1744      * <br>
   1745      * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so:
   1746      * <pre class="prettyprint">
   1747      * Notification noti = new Notification.Builder()
   1748      *     .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
   1749      *     .setContentText(subject)
   1750      *     .setSmallIcon(R.drawable.new_mail)
   1751      *     .setLargeIcon(aBitmap)
   1752      *     .setStyle(new Notification.InboxStyle()
   1753      *         .addLine(str1)
   1754      *         .addLine(str2)
   1755      *         .setContentTitle(&quot;&quot;)
   1756      *         .setSummaryText(&quot;+3 more&quot;))
   1757      *     .build();
   1758      * </pre>
   1759      *
   1760      * @see Notification#bigContentView
   1761      */
   1762     public static class InboxStyle extends Style {
   1763         ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
   1764 
   1765         public InboxStyle() {
   1766         }
   1767 
   1768         public InboxStyle(Builder builder) {
   1769             setBuilder(builder);
   1770         }
   1771 
   1772         /**
   1773          * Overrides ContentTitle in the big form of the template.
   1774          * This defaults to the value passed to setContentTitle().
   1775          */
   1776         public InboxStyle setBigContentTitle(CharSequence title) {
   1777             mBigContentTitle = Builder.limitCharSequenceLength(title);
   1778             return this;
   1779         }
   1780 
   1781         /**
   1782          * Set the first line of text after the detail section in the big form of the template.
   1783          */
   1784         public InboxStyle setSummaryText(CharSequence cs) {
   1785             mSummaryText = Builder.limitCharSequenceLength(cs);
   1786             mSummaryTextSet = true;
   1787             return this;
   1788         }
   1789 
   1790         /**
   1791          * Append a line to the digest section of the Inbox notification.
   1792          */
   1793         public InboxStyle addLine(CharSequence cs) {
   1794             mTexts.add(Builder.limitCharSequenceLength(cs));
   1795             return this;
   1796         }
   1797     }
   1798 
   1799     /**
   1800      * Structure to encapsulate a named action that can be shown as part of this notification.
   1801      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
   1802      * selected by the user. Action buttons won't appear on platforms prior to Android 4.1.
   1803      * <p>
   1804      * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)}
   1805      * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)}
   1806      * to attach actions.
   1807      */
   1808     public static class Action extends NotificationCompatBase.Action {
   1809         private final Bundle mExtras;
   1810         private final RemoteInput[] mRemoteInputs;
   1811 
   1812         /**
   1813          * Small icon representing the action.
   1814          */
   1815         public int icon;
   1816         /**
   1817          * Title of the action.
   1818          */
   1819         public CharSequence title;
   1820         /**
   1821          * Intent to send when the user invokes this action. May be null, in which case the action
   1822          * may be rendered in a disabled presentation.
   1823          */
   1824         public PendingIntent actionIntent;
   1825 
   1826         public Action(int icon, CharSequence title, PendingIntent intent) {
   1827             this(icon, title, intent, new Bundle(), null);
   1828         }
   1829 
   1830         private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras,
   1831                 RemoteInput[] remoteInputs) {
   1832             this.icon = icon;
   1833             this.title = NotificationCompat.Builder.limitCharSequenceLength(title);
   1834             this.actionIntent = intent;
   1835             this.mExtras = extras != null ? extras : new Bundle();
   1836             this.mRemoteInputs = remoteInputs;
   1837         }
   1838 
   1839         @Override
   1840         public int getIcon() {
   1841             return icon;
   1842         }
   1843 
   1844         @Override
   1845         public CharSequence getTitle() {
   1846             return title;
   1847         }
   1848 
   1849         @Override
   1850         public PendingIntent getActionIntent() {
   1851             return actionIntent;
   1852         }
   1853 
   1854         /**
   1855          * Get additional metadata carried around with this Action.
   1856          */
   1857         @Override
   1858         public Bundle getExtras() {
   1859             return mExtras;
   1860         }
   1861 
   1862         /**
   1863          * Get the list of inputs to be collected from the user when this action is sent.
   1864          * May return null if no remote inputs were added.
   1865          */
   1866         @Override
   1867         public RemoteInput[] getRemoteInputs() {
   1868             return mRemoteInputs;
   1869         }
   1870 
   1871         /**
   1872          * Builder class for {@link Action} objects.
   1873          */
   1874         public static final class Builder {
   1875             private final int mIcon;
   1876             private final CharSequence mTitle;
   1877             private final PendingIntent mIntent;
   1878             private final Bundle mExtras;
   1879             private ArrayList<RemoteInput> mRemoteInputs;
   1880 
   1881             /**
   1882              * Construct a new builder for {@link Action} object.
   1883              * @param icon icon to show for this action
   1884              * @param title the title of the action
   1885              * @param intent the {@link PendingIntent} to fire when users trigger this action
   1886              */
   1887             public Builder(int icon, CharSequence title, PendingIntent intent) {
   1888                 this(icon, title, intent, new Bundle());
   1889             }
   1890 
   1891             /**
   1892              * Construct a new builder for {@link Action} object using the fields from an
   1893              * {@link Action}.
   1894              * @param action the action to read fields from.
   1895              */
   1896             public Builder(Action action) {
   1897                 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
   1898             }
   1899 
   1900             private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
   1901                 mIcon = icon;
   1902                 mTitle = NotificationCompat.Builder.limitCharSequenceLength(title);
   1903                 mIntent = intent;
   1904                 mExtras = extras;
   1905             }
   1906 
   1907             /**
   1908              * Merge additional metadata into this builder.
   1909              *
   1910              * <p>Values within the Bundle will replace existing extras values in this Builder.
   1911              *
   1912              * @see NotificationCompat.Action#getExtras
   1913              */
   1914             public Builder addExtras(Bundle extras) {
   1915                 if (extras != null) {
   1916                     mExtras.putAll(extras);
   1917                 }
   1918                 return this;
   1919             }
   1920 
   1921             /**
   1922              * Get the metadata Bundle used by this Builder.
   1923              *
   1924              * <p>The returned Bundle is shared with this Builder.
   1925              */
   1926             public Bundle getExtras() {
   1927                 return mExtras;
   1928             }
   1929 
   1930             /**
   1931              * Add an input to be collected from the user when this action is sent.
   1932              * Response values can be retrieved from the fired intent by using the
   1933              * {@link RemoteInput#getResultsFromIntent} function.
   1934              * @param remoteInput a {@link RemoteInput} to add to the action
   1935              * @return this object for method chaining
   1936              */
   1937             public Builder addRemoteInput(RemoteInput remoteInput) {
   1938                 if (mRemoteInputs == null) {
   1939                     mRemoteInputs = new ArrayList<RemoteInput>();
   1940                 }
   1941                 mRemoteInputs.add(remoteInput);
   1942                 return this;
   1943             }
   1944 
   1945             /**
   1946              * Apply an extender to this action builder. Extenders may be used to add
   1947              * metadata or change options on this builder.
   1948              */
   1949             public Builder extend(Extender extender) {
   1950                 extender.extend(this);
   1951                 return this;
   1952             }
   1953 
   1954             /**
   1955              * Combine all of the options that have been set and return a new {@link Action}
   1956              * object.
   1957              * @return the built action
   1958              */
   1959             public Action build() {
   1960                 RemoteInput[] remoteInputs = mRemoteInputs != null
   1961                         ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
   1962                 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs);
   1963             }
   1964         }
   1965 
   1966 
   1967         /**
   1968          * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
   1969          * metadata or change options on an action builder.
   1970          */
   1971         public interface Extender {
   1972             /**
   1973              * Apply this extender to a notification action builder.
   1974              * @param builder the builder to be modified.
   1975              * @return the build object for chaining.
   1976              */
   1977             public Builder extend(Builder builder);
   1978         }
   1979 
   1980         /**
   1981          * Wearable extender for notification actions. To add extensions to an action,
   1982          * create a new {@link NotificationCompat.Action.WearableExtender} object using
   1983          * the {@code WearableExtender()} constructor and apply it to a
   1984          * {@link NotificationCompat.Action.Builder} using
   1985          * {@link NotificationCompat.Action.Builder#extend}.
   1986          *
   1987          * <pre class="prettyprint">
   1988          * NotificationCompat.Action action = new NotificationCompat.Action.Builder(
   1989          *         R.drawable.archive_all, "Archive all", actionIntent)
   1990          *         .extend(new NotificationCompat.Action.WearableExtender()
   1991          *                 .setAvailableOffline(false))
   1992          *         .build();</pre>
   1993          */
   1994         public static final class WearableExtender implements Extender {
   1995             /** Notification action extra which contains wearable extensions */
   1996             private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
   1997 
   1998             // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
   1999             private static final String KEY_FLAGS = "flags";
   2000             private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel";
   2001             private static final String KEY_CONFIRM_LABEL = "confirmLabel";
   2002             private static final String KEY_CANCEL_LABEL = "cancelLabel";
   2003 
   2004             // Flags bitwise-ored to mFlags
   2005             private static final int FLAG_AVAILABLE_OFFLINE = 0x1;
   2006 
   2007             // Default value for flags integer
   2008             private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE;
   2009 
   2010             private int mFlags = DEFAULT_FLAGS;
   2011 
   2012             private CharSequence mInProgressLabel;
   2013             private CharSequence mConfirmLabel;
   2014             private CharSequence mCancelLabel;
   2015 
   2016             /**
   2017              * Create a {@link NotificationCompat.Action.WearableExtender} with default
   2018              * options.
   2019              */
   2020             public WearableExtender() {
   2021             }
   2022 
   2023             /**
   2024              * Create a {@link NotificationCompat.Action.WearableExtender} by reading
   2025              * wearable options present in an existing notification action.
   2026              * @param action the notification action to inspect.
   2027              */
   2028             public WearableExtender(Action action) {
   2029                 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS);
   2030                 if (wearableBundle != null) {
   2031                     mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
   2032                     mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL);
   2033                     mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL);
   2034                     mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL);
   2035                 }
   2036             }
   2037 
   2038             /**
   2039              * Apply wearable extensions to a notification action that is being built. This is
   2040              * typically called by the {@link NotificationCompat.Action.Builder#extend}
   2041              * method of {@link NotificationCompat.Action.Builder}.
   2042              */
   2043             @Override
   2044             public Action.Builder extend(Action.Builder builder) {
   2045                 Bundle wearableBundle = new Bundle();
   2046 
   2047                 if (mFlags != DEFAULT_FLAGS) {
   2048                     wearableBundle.putInt(KEY_FLAGS, mFlags);
   2049                 }
   2050                 if (mInProgressLabel != null) {
   2051                     wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel);
   2052                 }
   2053                 if (mConfirmLabel != null) {
   2054                     wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel);
   2055                 }
   2056                 if (mCancelLabel != null) {
   2057                     wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel);
   2058                 }
   2059 
   2060                 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
   2061                 return builder;
   2062             }
   2063 
   2064             @Override
   2065             public WearableExtender clone() {
   2066                 WearableExtender that = new WearableExtender();
   2067                 that.mFlags = this.mFlags;
   2068                 that.mInProgressLabel = this.mInProgressLabel;
   2069                 that.mConfirmLabel = this.mConfirmLabel;
   2070                 that.mCancelLabel = this.mCancelLabel;
   2071                 return that;
   2072             }
   2073 
   2074             /**
   2075              * Set whether this action is available when the wearable device is not connected to
   2076              * a companion device. The user can still trigger this action when the wearable device
   2077              * is offline, but a visual hint will indicate that the action may not be available.
   2078              * Defaults to true.
   2079              */
   2080             public WearableExtender setAvailableOffline(boolean availableOffline) {
   2081                 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline);
   2082                 return this;
   2083             }
   2084 
   2085             /**
   2086              * Get whether this action is available when the wearable device is not connected to
   2087              * a companion device. The user can still trigger this action when the wearable device
   2088              * is offline, but a visual hint will indicate that the action may not be available.
   2089              * Defaults to true.
   2090              */
   2091             public boolean isAvailableOffline() {
   2092                 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0;
   2093             }
   2094 
   2095             private void setFlag(int mask, boolean value) {
   2096                 if (value) {
   2097                     mFlags |= mask;
   2098                 } else {
   2099                     mFlags &= ~mask;
   2100                 }
   2101             }
   2102 
   2103             /**
   2104              * Set a label to display while the wearable is preparing to automatically execute the
   2105              * action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
   2106              *
   2107              * @param label the label to display while the action is being prepared to execute
   2108              * @return this object for method chaining
   2109              */
   2110             public WearableExtender setInProgressLabel(CharSequence label) {
   2111                 mInProgressLabel = label;
   2112                 return this;
   2113             }
   2114 
   2115             /**
   2116              * Get the label to display while the wearable is preparing to automatically execute
   2117              * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
   2118              *
   2119              * @return the label to display while the action is being prepared to execute
   2120              */
   2121             public CharSequence getInProgressLabel() {
   2122                 return mInProgressLabel;
   2123             }
   2124 
   2125             /**
   2126              * Set a label to display to confirm that the action should be executed.
   2127              * This is usually an imperative verb like "Send".
   2128              *
   2129              * @param label the label to confirm the action should be executed
   2130              * @return this object for method chaining
   2131              */
   2132             public WearableExtender setConfirmLabel(CharSequence label) {
   2133                 mConfirmLabel = label;
   2134                 return this;
   2135             }
   2136 
   2137             /**
   2138              * Get the label to display to confirm that the action should be executed.
   2139              * This is usually an imperative verb like "Send".
   2140              *
   2141              * @return the label to confirm the action should be executed
   2142              */
   2143             public CharSequence getConfirmLabel() {
   2144                 return mConfirmLabel;
   2145             }
   2146 
   2147             /**
   2148              * Set a label to display to cancel the action.
   2149              * This is usually an imperative verb, like "Cancel".
   2150              *
   2151              * @param label the label to display to cancel the action
   2152              * @return this object for method chaining
   2153              */
   2154             public WearableExtender setCancelLabel(CharSequence label) {
   2155                 mCancelLabel = label;
   2156                 return this;
   2157             }
   2158 
   2159             /**
   2160              * Get the label to display to cancel the action.
   2161              * This is usually an imperative verb like "Cancel".
   2162              *
   2163              * @return the label to display to cancel the action
   2164              */
   2165             public CharSequence getCancelLabel() {
   2166                 return mCancelLabel;
   2167             }
   2168         }
   2169 
   2170         /** @hide */
   2171         public static final Factory FACTORY = new Factory() {
   2172             @Override
   2173             public Action build(int icon, CharSequence title,
   2174                     PendingIntent actionIntent, Bundle extras,
   2175                     RemoteInputCompatBase.RemoteInput[] remoteInputs) {
   2176                 return new Action(icon, title, actionIntent, extras,
   2177                         (RemoteInput[]) remoteInputs);
   2178             }
   2179 
   2180             @Override
   2181             public Action[] newArray(int length) {
   2182                 return new Action[length];
   2183             }
   2184         };
   2185     }
   2186 
   2187 
   2188     /**
   2189      * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
   2190      * metadata or change options on a notification builder.
   2191      */
   2192     public interface Extender {
   2193         /**
   2194          * Apply this extender to a notification builder.
   2195          * @param builder the builder to be modified.
   2196          * @return the build object for chaining.
   2197          */
   2198         public Builder extend(Builder builder);
   2199     }
   2200 
   2201     /**
   2202      * Helper class to add wearable extensions to notifications.
   2203      * <p class="note"> See
   2204      * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications
   2205      * for Android Wear</a> for more information on how to use this class.
   2206      * <p>
   2207      * To create a notification with wearable extensions:
   2208      * <ol>
   2209      *   <li>Create a {@link NotificationCompat.Builder}, setting any desired
   2210      *   properties.
   2211      *   <li>Create a {@link NotificationCompat.WearableExtender}.
   2212      *   <li>Set wearable-specific properties using the
   2213      *   {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}.
   2214      *   <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a
   2215      *   notification.
   2216      *   <li>Post the notification to the notification
   2217      *   system with the {@code NotificationManagerCompat.notify(...)} methods
   2218      *   and not the {@code NotificationManager.notify(...)} methods.
   2219      * </ol>
   2220      *
   2221      * <pre class="prettyprint">
   2222      * Notification notif = new NotificationCompat.Builder(mContext)
   2223      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
   2224      *         .setContentText(subject)
   2225      *         .setSmallIcon(R.drawable.new_mail)
   2226      *         .extend(new NotificationCompat.WearableExtender()
   2227      *                 .setContentIcon(R.drawable.new_mail))
   2228      *         .build();
   2229      * NotificationManagerCompat.from(mContext).notify(0, notif);</pre>
   2230      *
   2231      * <p>Wearable extensions can be accessed on an existing notification by using the
   2232      * {@code WearableExtender(Notification)} constructor,
   2233      * and then using the {@code get} methods to access values.
   2234      *
   2235      * <pre class="prettyprint">
   2236      * NotificationCompat.WearableExtender wearableExtender =
   2237      *         new NotificationCompat.WearableExtender(notification);
   2238      * List&lt;Notification&gt; pages = wearableExtender.getPages();</pre>
   2239      */
   2240     public static final class WearableExtender implements Extender {
   2241         /**
   2242          * Sentinel value for an action index that is unset.
   2243          */
   2244         public static final int UNSET_ACTION_INDEX = -1;
   2245 
   2246         /**
   2247          * Size value for use with {@link #setCustomSizePreset} to show this notification with
   2248          * default sizing.
   2249          * <p>For custom display notifications created using {@link #setDisplayIntent},
   2250          * the default is {@link #SIZE_LARGE}. All other notifications size automatically based
   2251          * on their content.
   2252          */
   2253         public static final int SIZE_DEFAULT = 0;
   2254 
   2255         /**
   2256          * Size value for use with {@link #setCustomSizePreset} to show this notification
   2257          * with an extra small size.
   2258          * <p>This value is only applicable for custom display notifications created using
   2259          * {@link #setDisplayIntent}.
   2260          */
   2261         public static final int SIZE_XSMALL = 1;
   2262 
   2263         /**
   2264          * Size value for use with {@link #setCustomSizePreset} to show this notification
   2265          * with a small size.
   2266          * <p>This value is only applicable for custom display notifications created using
   2267          * {@link #setDisplayIntent}.
   2268          */
   2269         public static final int SIZE_SMALL = 2;
   2270 
   2271         /**
   2272          * Size value for use with {@link #setCustomSizePreset} to show this notification
   2273          * with a medium size.
   2274          * <p>This value is only applicable for custom display notifications created using
   2275          * {@link #setDisplayIntent}.
   2276          */
   2277         public static final int SIZE_MEDIUM = 3;
   2278 
   2279         /**
   2280          * Size value for use with {@link #setCustomSizePreset} to show this notification
   2281          * with a large size.
   2282          * <p>This value is only applicable for custom display notifications created using
   2283          * {@link #setDisplayIntent}.
   2284          */
   2285         public static final int SIZE_LARGE = 4;
   2286 
   2287         /**
   2288          * Size value for use with {@link #setCustomSizePreset} to show this notification
   2289          * full screen.
   2290          * <p>This value is only applicable for custom display notifications created using
   2291          * {@link #setDisplayIntent}.
   2292          */
   2293         public static final int SIZE_FULL_SCREEN = 5;
   2294 
   2295         /**
   2296          * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
   2297          * short amount of time when this notification is displayed on the screen. This
   2298          * is the default value.
   2299          */
   2300         public static final int SCREEN_TIMEOUT_SHORT = 0;
   2301 
   2302         /**
   2303          * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
   2304          * for a longer amount of time when this notification is displayed on the screen.
   2305          */
   2306         public static final int SCREEN_TIMEOUT_LONG = -1;
   2307 
   2308         /** Notification extra which contains wearable extensions */
   2309         private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
   2310 
   2311         // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
   2312         private static final String KEY_ACTIONS = "actions";
   2313         private static final String KEY_FLAGS = "flags";
   2314         private static final String KEY_DISPLAY_INTENT = "displayIntent";
   2315         private static final String KEY_PAGES = "pages";
   2316         private static final String KEY_BACKGROUND = "background";
   2317         private static final String KEY_CONTENT_ICON = "contentIcon";
   2318         private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity";
   2319         private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex";
   2320         private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset";
   2321         private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
   2322         private static final String KEY_GRAVITY = "gravity";
   2323         private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
   2324 
   2325         // Flags bitwise-ored to mFlags
   2326         private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
   2327         private static final int FLAG_HINT_HIDE_ICON = 1 << 1;
   2328         private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
   2329         private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
   2330         private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4;
   2331 
   2332         // Default value for flags integer
   2333         private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
   2334 
   2335         private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END;
   2336         private static final int DEFAULT_GRAVITY = Gravity.BOTTOM;
   2337 
   2338         private ArrayList<Action> mActions = new ArrayList<Action>();
   2339         private int mFlags = DEFAULT_FLAGS;
   2340         private PendingIntent mDisplayIntent;
   2341         private ArrayList<Notification> mPages = new ArrayList<Notification>();
   2342         private Bitmap mBackground;
   2343         private int mContentIcon;
   2344         private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY;
   2345         private int mContentActionIndex = UNSET_ACTION_INDEX;
   2346         private int mCustomSizePreset = SIZE_DEFAULT;
   2347         private int mCustomContentHeight;
   2348         private int mGravity = DEFAULT_GRAVITY;
   2349         private int mHintScreenTimeout;
   2350 
   2351         /**
   2352          * Create a {@link NotificationCompat.WearableExtender} with default
   2353          * options.
   2354          */
   2355         public WearableExtender() {
   2356         }
   2357 
   2358         public WearableExtender(Notification notif) {
   2359             Bundle extras = getExtras(notif);
   2360             Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS)
   2361                     : null;
   2362             if (wearableBundle != null) {
   2363                 Action[] actions = IMPL.getActionsFromParcelableArrayList(
   2364                         wearableBundle.getParcelableArrayList(KEY_ACTIONS));
   2365                 if (actions != null) {
   2366                     Collections.addAll(mActions, actions);
   2367                 }
   2368 
   2369                 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
   2370                 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT);
   2371 
   2372                 Notification[] pages = getNotificationArrayFromBundle(
   2373                         wearableBundle, KEY_PAGES);
   2374                 if (pages != null) {
   2375                     Collections.addAll(mPages, pages);
   2376                 }
   2377 
   2378                 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND);
   2379                 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON);
   2380                 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY,
   2381                         DEFAULT_CONTENT_ICON_GRAVITY);
   2382                 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX,
   2383                         UNSET_ACTION_INDEX);
   2384                 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET,
   2385                         SIZE_DEFAULT);
   2386                 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
   2387                 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
   2388                 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
   2389             }
   2390         }
   2391 
   2392         /**
   2393          * Apply wearable extensions to a notification that is being built. This is typically
   2394          * called by the {@link NotificationCompat.Builder#extend} method of
   2395          * {@link NotificationCompat.Builder}.
   2396          */
   2397         @Override
   2398         public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
   2399             Bundle wearableBundle = new Bundle();
   2400 
   2401             if (!mActions.isEmpty()) {
   2402                 wearableBundle.putParcelableArrayList(KEY_ACTIONS,
   2403                         IMPL.getParcelableArrayListForActions(mActions.toArray(
   2404                                 new Action[mActions.size()])));
   2405             }
   2406             if (mFlags != DEFAULT_FLAGS) {
   2407                 wearableBundle.putInt(KEY_FLAGS, mFlags);
   2408             }
   2409             if (mDisplayIntent != null) {
   2410                 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent);
   2411             }
   2412             if (!mPages.isEmpty()) {
   2413                 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray(
   2414                         new Notification[mPages.size()]));
   2415             }
   2416             if (mBackground != null) {
   2417                 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
   2418             }
   2419             if (mContentIcon != 0) {
   2420                 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon);
   2421             }
   2422             if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) {
   2423                 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity);
   2424             }
   2425             if (mContentActionIndex != UNSET_ACTION_INDEX) {
   2426                 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX,
   2427                         mContentActionIndex);
   2428             }
   2429             if (mCustomSizePreset != SIZE_DEFAULT) {
   2430                 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset);
   2431             }
   2432             if (mCustomContentHeight != 0) {
   2433                 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight);
   2434             }
   2435             if (mGravity != DEFAULT_GRAVITY) {
   2436                 wearableBundle.putInt(KEY_GRAVITY, mGravity);
   2437             }
   2438             if (mHintScreenTimeout != 0) {
   2439                 wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout);
   2440             }
   2441 
   2442             builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
   2443             return builder;
   2444         }
   2445 
   2446         @Override
   2447         public WearableExtender clone() {
   2448             WearableExtender that = new WearableExtender();
   2449             that.mActions = new ArrayList<Action>(this.mActions);
   2450             that.mFlags = this.mFlags;
   2451             that.mDisplayIntent = this.mDisplayIntent;
   2452             that.mPages = new ArrayList<Notification>(this.mPages);
   2453             that.mBackground = this.mBackground;
   2454             that.mContentIcon = this.mContentIcon;
   2455             that.mContentIconGravity = this.mContentIconGravity;
   2456             that.mContentActionIndex = this.mContentActionIndex;
   2457             that.mCustomSizePreset = this.mCustomSizePreset;
   2458             that.mCustomContentHeight = this.mCustomContentHeight;
   2459             that.mGravity = this.mGravity;
   2460             that.mHintScreenTimeout = this.mHintScreenTimeout;
   2461             return that;
   2462         }
   2463 
   2464         /**
   2465          * Add a wearable action to this notification.
   2466          *
   2467          * <p>When wearable actions are added using this method, the set of actions that
   2468          * show on a wearable device splits from devices that only show actions added
   2469          * using {@link NotificationCompat.Builder#addAction}. This allows for customization
   2470          * of which actions display on different devices.
   2471          *
   2472          * @param action the action to add to this notification
   2473          * @return this object for method chaining
   2474          * @see NotificationCompat.Action
   2475          */
   2476         public WearableExtender addAction(Action action) {
   2477             mActions.add(action);
   2478             return this;
   2479         }
   2480 
   2481         /**
   2482          * Adds wearable actions to this notification.
   2483          *
   2484          * <p>When wearable actions are added using this method, the set of actions that
   2485          * show on a wearable device splits from devices that only show actions added
   2486          * using {@link NotificationCompat.Builder#addAction}. This allows for customization
   2487          * of which actions display on different devices.
   2488          *
   2489          * @param actions the actions to add to this notification
   2490          * @return this object for method chaining
   2491          * @see NotificationCompat.Action
   2492          */
   2493         public WearableExtender addActions(List<Action> actions) {
   2494             mActions.addAll(actions);
   2495             return this;
   2496         }
   2497 
   2498         /**
   2499          * Clear all wearable actions present on this builder.
   2500          * @return this object for method chaining.
   2501          * @see #addAction
   2502          */
   2503         public WearableExtender clearActions() {
   2504             mActions.clear();
   2505             return this;
   2506         }
   2507 
   2508         /**
   2509          * Get the wearable actions present on this notification.
   2510          */
   2511         public List<Action> getActions() {
   2512             return mActions;
   2513         }
   2514 
   2515         /**
   2516          * Set an intent to launch inside of an activity view when displaying
   2517          * this notification. The {@link PendingIntent} provided should be for an activity.
   2518          *
   2519          * <pre class="prettyprint">
   2520          * Intent displayIntent = new Intent(context, MyDisplayActivity.class);
   2521          * PendingIntent displayPendingIntent = PendingIntent.getActivity(context,
   2522          *         0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT);
   2523          * Notification notif = new NotificationCompat.Builder(context)
   2524          *         .extend(new NotificationCompat.WearableExtender()
   2525          *                 .setDisplayIntent(displayPendingIntent)
   2526          *                 .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM))
   2527          *         .build();</pre>
   2528          *
   2529          * <p>The activity to launch needs to allow embedding, must be exported, and
   2530          * should have an empty task affinity. It is also recommended to use the device
   2531          * default light theme.
   2532          *
   2533          * <p>Example AndroidManifest.xml entry:
   2534          * <pre class="prettyprint">
   2535          * &lt;activity android:name=&quot;com.example.MyDisplayActivity&quot;
   2536          *     android:exported=&quot;true&quot;
   2537          *     android:allowEmbedded=&quot;true&quot;
   2538          *     android:taskAffinity=&quot;&quot;
   2539          *     android:theme=&quot;@android:style/Theme.DeviceDefault.Light&quot; /&gt;</pre>
   2540          *
   2541          * @param intent the {@link PendingIntent} for an activity
   2542          * @return this object for method chaining
   2543          * @see NotificationCompat.WearableExtender#getDisplayIntent
   2544          */
   2545         public WearableExtender setDisplayIntent(PendingIntent intent) {
   2546             mDisplayIntent = intent;
   2547             return this;
   2548         }
   2549 
   2550         /**
   2551          * Get the intent to launch inside of an activity view when displaying this
   2552          * notification. This {@code PendingIntent} should be for an activity.
   2553          */
   2554         public PendingIntent getDisplayIntent() {
   2555             return mDisplayIntent;
   2556         }
   2557 
   2558         /**
   2559          * Add an additional page of content to display with this notification. The current
   2560          * notification forms the first page, and pages added using this function form
   2561          * subsequent pages. This field can be used to separate a notification into multiple
   2562          * sections.
   2563          *
   2564          * @param page the notification to add as another page
   2565          * @return this object for method chaining
   2566          * @see NotificationCompat.WearableExtender#getPages
   2567          */
   2568         public WearableExtender addPage(Notification page) {
   2569             mPages.add(page);
   2570             return this;
   2571         }
   2572 
   2573         /**
   2574          * Add additional pages of content to display with this notification. The current
   2575          * notification forms the first page, and pages added using this function form
   2576          * subsequent pages. This field can be used to separate a notification into multiple
   2577          * sections.
   2578          *
   2579          * @param pages a list of notifications
   2580          * @return this object for method chaining
   2581          * @see NotificationCompat.WearableExtender#getPages
   2582          */
   2583         public WearableExtender addPages(List<Notification> pages) {
   2584             mPages.addAll(pages);
   2585             return this;
   2586         }
   2587 
   2588         /**
   2589          * Clear all additional pages present on this builder.
   2590          * @return this object for method chaining.
   2591          * @see #addPage
   2592          */
   2593         public WearableExtender clearPages() {
   2594             mPages.clear();
   2595             return this;
   2596         }
   2597 
   2598         /**
   2599          * Get the array of additional pages of content for displaying this notification. The
   2600          * current notification forms the first page, and elements within this array form
   2601          * subsequent pages. This field can be used to separate a notification into multiple
   2602          * sections.
   2603          * @return the pages for this notification
   2604          */
   2605         public List<Notification> getPages() {
   2606             return mPages;
   2607         }
   2608 
   2609         /**
   2610          * Set a background image to be displayed behind the notification content.
   2611          * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background
   2612          * will work with any notification style.
   2613          *
   2614          * @param background the background bitmap
   2615          * @return this object for method chaining
   2616          * @see NotificationCompat.WearableExtender#getBackground
   2617          */
   2618         public WearableExtender setBackground(Bitmap background) {
   2619             mBackground = background;
   2620             return this;
   2621         }
   2622 
   2623         /**
   2624          * Get a background image to be displayed behind the notification content.
   2625          * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background
   2626          * will work with any notification style.
   2627          *
   2628          * @return the background image
   2629          * @see NotificationCompat.WearableExtender#setBackground
   2630          */
   2631         public Bitmap getBackground() {
   2632             return mBackground;
   2633         }
   2634 
   2635         /**
   2636          * Set an icon that goes with the content of this notification.
   2637          */
   2638         public WearableExtender setContentIcon(int icon) {
   2639             mContentIcon = icon;
   2640             return this;
   2641         }
   2642 
   2643         /**
   2644          * Get an icon that goes with the content of this notification.
   2645          */
   2646         public int getContentIcon() {
   2647             return mContentIcon;
   2648         }
   2649 
   2650         /**
   2651          * Set the gravity that the content icon should have within the notification display.
   2652          * Supported values include {@link android.view.Gravity#START} and
   2653          * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
   2654          * @see #setContentIcon
   2655          */
   2656         public WearableExtender setContentIconGravity(int contentIconGravity) {
   2657             mContentIconGravity = contentIconGravity;
   2658             return this;
   2659         }
   2660 
   2661         /**
   2662          * Get the gravity that the content icon should have within the notification display.
   2663          * Supported values include {@link android.view.Gravity#START} and
   2664          * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
   2665          * @see #getContentIcon
   2666          */
   2667         public int getContentIconGravity() {
   2668             return mContentIconGravity;
   2669         }
   2670 
   2671         /**
   2672          * Set an action from this notification's actions to be clickable with the content of
   2673          * this notification. This action will no longer display separately from the
   2674          * notification's content.
   2675          *
   2676          * <p>For notifications with multiple pages, child pages can also have content actions
   2677          * set, although the list of available actions comes from the main notification and not
   2678          * from the child page's notification.
   2679          *
   2680          * @param actionIndex The index of the action to hoist onto the current notification page.
   2681          *                    If wearable actions were added to the main notification, this index
   2682          *                    will apply to that list, otherwise it will apply to the regular
   2683          *                    actions list.
   2684          */
   2685         public WearableExtender setContentAction(int actionIndex) {
   2686             mContentActionIndex = actionIndex;
   2687             return this;
   2688         }
   2689 
   2690         /**
   2691          * Get the index of the notification action, if any, that was specified as being clickable
   2692          * with the content of this notification. This action will no longer display separately
   2693          * from the notification's content.
   2694          *
   2695          * <p>For notifications with multiple pages, child pages can also have content actions
   2696          * set, although the list of available actions comes from the main notification and not
   2697          * from the child page's notification.
   2698          *
   2699          * <p>If wearable specific actions were added to the main notification, this index will
   2700          * apply to that list, otherwise it will apply to the regular actions list.
   2701          *
   2702          * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected.
   2703          */
   2704         public int getContentAction() {
   2705             return mContentActionIndex;
   2706         }
   2707 
   2708         /**
   2709          * Set the gravity that this notification should have within the available viewport space.
   2710          * Supported values include {@link android.view.Gravity#TOP},
   2711          * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
   2712          * The default value is {@link android.view.Gravity#BOTTOM}.
   2713          */
   2714         public WearableExtender setGravity(int gravity) {
   2715             mGravity = gravity;
   2716             return this;
   2717         }
   2718 
   2719         /**
   2720          * Get the gravity that this notification should have within the available viewport space.
   2721          * Supported values include {@link android.view.Gravity#TOP},
   2722          * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
   2723          * The default value is {@link android.view.Gravity#BOTTOM}.
   2724          */
   2725         public int getGravity() {
   2726             return mGravity;
   2727         }
   2728 
   2729         /**
   2730          * Set the custom size preset for the display of this notification out of the available
   2731          * presets found in {@link NotificationCompat.WearableExtender}, e.g.
   2732          * {@link #SIZE_LARGE}.
   2733          * <p>Some custom size presets are only applicable for custom display notifications created
   2734          * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the
   2735          * documentation for the preset in question. See also
   2736          * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}.
   2737          */
   2738         public WearableExtender setCustomSizePreset(int sizePreset) {
   2739             mCustomSizePreset = sizePreset;
   2740             return this;
   2741         }
   2742 
   2743         /**
   2744          * Get the custom size preset for the display of this notification out of the available
   2745          * presets found in {@link NotificationCompat.WearableExtender}, e.g.
   2746          * {@link #SIZE_LARGE}.
   2747          * <p>Some custom size presets are only applicable for custom display notifications created
   2748          * using {@link #setDisplayIntent}. Check the documentation for the preset in question.
   2749          * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}.
   2750          */
   2751         public int getCustomSizePreset() {
   2752             return mCustomSizePreset;
   2753         }
   2754 
   2755         /**
   2756          * Set the custom height in pixels for the display of this notification's content.
   2757          * <p>This option is only available for custom display notifications created
   2758          * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also
   2759          * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and
   2760          * {@link #getCustomContentHeight}.
   2761          */
   2762         public WearableExtender setCustomContentHeight(int height) {
   2763             mCustomContentHeight = height;
   2764             return this;
   2765         }
   2766 
   2767         /**
   2768          * Get the custom height in pixels for the display of this notification's content.
   2769          * <p>This option is only available for custom display notifications created
   2770          * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and
   2771          * {@link #setCustomContentHeight}.
   2772          */
   2773         public int getCustomContentHeight() {
   2774             return mCustomContentHeight;
   2775         }
   2776 
   2777         /**
   2778          * Set whether the scrolling position for the contents of this notification should start
   2779          * at the bottom of the contents instead of the top when the contents are too long to
   2780          * display within the screen.  Default is false (start scroll at the top).
   2781          */
   2782         public WearableExtender setStartScrollBottom(boolean startScrollBottom) {
   2783             setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom);
   2784             return this;
   2785         }
   2786 
   2787         /**
   2788          * Get whether the scrolling position for the contents of this notification should start
   2789          * at the bottom of the contents instead of the top when the contents are too long to
   2790          * display within the screen. Default is false (start scroll at the top).
   2791          */
   2792         public boolean getStartScrollBottom() {
   2793             return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0;
   2794         }
   2795 
   2796         /**
   2797          * Set whether the content intent is available when the wearable device is not connected
   2798          * to a companion device.  The user can still trigger this intent when the wearable device
   2799          * is offline, but a visual hint will indicate that the content intent may not be available.
   2800          * Defaults to true.
   2801          */
   2802         public WearableExtender setContentIntentAvailableOffline(
   2803                 boolean contentIntentAvailableOffline) {
   2804             setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline);
   2805             return this;
   2806         }
   2807 
   2808         /**
   2809          * Get whether the content intent is available when the wearable device is not connected
   2810          * to a companion device.  The user can still trigger this intent when the wearable device
   2811          * is offline, but a visual hint will indicate that the content intent may not be available.
   2812          * Defaults to true.
   2813          */
   2814         public boolean getContentIntentAvailableOffline() {
   2815             return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0;
   2816         }
   2817 
   2818         /**
   2819          * Set a hint that this notification's icon should not be displayed.
   2820          * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise.
   2821          * @return this object for method chaining
   2822          */
   2823         public WearableExtender setHintHideIcon(boolean hintHideIcon) {
   2824             setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon);
   2825             return this;
   2826         }
   2827 
   2828         /**
   2829          * Get a hint that this notification's icon should not be displayed.
   2830          * @return {@code true} if this icon should not be displayed, false otherwise.
   2831          * The default value is {@code false} if this was never set.
   2832          */
   2833         public boolean getHintHideIcon() {
   2834             return (mFlags & FLAG_HINT_HIDE_ICON) != 0;
   2835         }
   2836 
   2837         /**
   2838          * Set a visual hint that only the background image of this notification should be
   2839          * displayed, and other semantic content should be hidden. This hint is only applicable
   2840          * to sub-pages added using {@link #addPage}.
   2841          */
   2842         public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) {
   2843             setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly);
   2844             return this;
   2845         }
   2846 
   2847         /**
   2848          * Get a visual hint that only the background image of this notification should be
   2849          * displayed, and other semantic content should be hidden. This hint is only applicable
   2850          * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}.
   2851          */
   2852         public boolean getHintShowBackgroundOnly() {
   2853             return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
   2854         }
   2855 
   2856         /**
   2857          * Set a hint that this notification's background should not be clipped if possible,
   2858          * and should instead be resized to fully display on the screen, retaining the aspect
   2859          * ratio of the image. This can be useful for images like barcodes or qr codes.
   2860          * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible.
   2861          * @return this object for method chaining
   2862          */
   2863         public WearableExtender setHintAvoidBackgroundClipping(
   2864                 boolean hintAvoidBackgroundClipping) {
   2865             setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping);
   2866             return this;
   2867         }
   2868 
   2869         /**
   2870          * Get a hint that this notification's background should not be clipped if possible,
   2871          * and should instead be resized to fully display on the screen, retaining the aspect
   2872          * ratio of the image. This can be useful for images like barcodes or qr codes.
   2873          * @return {@code true} if it's ok if the background is clipped on the screen, false
   2874          * otherwise. The default value is {@code false} if this was never set.
   2875          */
   2876         public boolean getHintAvoidBackgroundClipping() {
   2877             return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0;
   2878         }
   2879 
   2880         /**
   2881          * Set a hint that the screen should remain on for at least this duration when
   2882          * this notification is displayed on the screen.
   2883          * @param timeout The requested screen timeout in milliseconds. Can also be either
   2884          *     {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
   2885          * @return this object for method chaining
   2886          */
   2887         public WearableExtender setHintScreenTimeout(int timeout) {
   2888             mHintScreenTimeout = timeout;
   2889             return this;
   2890         }
   2891 
   2892         /**
   2893          * Get the duration, in milliseconds, that the screen should remain on for
   2894          * when this notification is displayed.
   2895          * @return the duration in milliseconds if > 0, or either one of the sentinel values
   2896          *     {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
   2897          */
   2898         public int getHintScreenTimeout() {
   2899             return mHintScreenTimeout;
   2900         }
   2901 
   2902         private void setFlag(int mask, boolean value) {
   2903             if (value) {
   2904                 mFlags |= mask;
   2905             } else {
   2906                 mFlags &= ~mask;
   2907             }
   2908         }
   2909     }
   2910 
   2911     /**
   2912      * <p>Helper class to add Android Auto extensions to notifications. To create a notification
   2913      * with car extensions:
   2914      *
   2915      * <ol>
   2916      *  <li>Create an {@link NotificationCompat.Builder}, setting any desired
   2917      *  properties.
   2918      *  <li>Create a {@link CarExtender}.
   2919      *  <li>Set car-specific properties using the {@code add} and {@code set} methods of
   2920      *  {@link CarExtender}.
   2921      *  <li>Call {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)}
   2922      *  to apply the extensions to a notification.
   2923      *  <li>Post the notification to the notification system with the
   2924      *  {@code NotificationManagerCompat.notify(...)} methods and not the
   2925      *  {@code NotificationManager.notify(...)} methods.
   2926      * </ol>
   2927      *
   2928      * <pre class="prettyprint">
   2929      * Notification notification = new NotificationCompat.Builder(context)
   2930      *         ...
   2931      *         .extend(new CarExtender()
   2932      *                 .set*(...))
   2933      *         .build();
   2934      * </pre>
   2935      *
   2936      * <p>Car extensions can be accessed on an existing notification by using the
   2937      * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods
   2938      * to access values.
   2939      */
   2940     public static final class CarExtender implements Extender {
   2941         private static final String TAG = "CarExtender";
   2942 
   2943         private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
   2944         private static final String EXTRA_LARGE_ICON = "large_icon";
   2945         private static final String EXTRA_CONVERSATION = "car_conversation";
   2946         private static final String EXTRA_COLOR = "app_color";
   2947 
   2948         private Bitmap mLargeIcon;
   2949         private UnreadConversation mUnreadConversation;
   2950         private int mColor = NotificationCompat.COLOR_DEFAULT;
   2951 
   2952         /**
   2953          * Create a {@link CarExtender} with default options.
   2954          */
   2955         public CarExtender() {
   2956         }
   2957 
   2958         /**
   2959          * Create a {@link CarExtender} from the CarExtender options of an existing Notification.
   2960          *
   2961          * @param notif The notification from which to copy options.
   2962          */
   2963         public CarExtender(Notification notif) {
   2964             if (Build.VERSION.SDK_INT < 21) {
   2965                 return;
   2966             }
   2967 
   2968             Bundle carBundle = getExtras(notif)==null ?
   2969                     null : getExtras(notif).getBundle(EXTRA_CAR_EXTENDER);
   2970             if (carBundle != null) {
   2971                 mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
   2972                 mColor = carBundle.getInt(EXTRA_COLOR, NotificationCompat.COLOR_DEFAULT);
   2973 
   2974                 Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
   2975                 mUnreadConversation = (UnreadConversation) IMPL.getUnreadConversationFromBundle(
   2976                         b, UnreadConversation.FACTORY, RemoteInput.FACTORY);
   2977             }
   2978         }
   2979 
   2980         /**
   2981          * Apply car extensions to a notification that is being built. This is typically called by
   2982          * the {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)}
   2983          * method of {@link NotificationCompat.Builder}.
   2984          */
   2985         @Override
   2986         public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
   2987             if (Build.VERSION.SDK_INT < 21) {
   2988                 return builder;
   2989             }
   2990 
   2991             Bundle carExtensions = new Bundle();
   2992 
   2993             if (mLargeIcon != null) {
   2994                 carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
   2995             }
   2996             if (mColor != NotificationCompat.COLOR_DEFAULT) {
   2997                 carExtensions.putInt(EXTRA_COLOR, mColor);
   2998             }
   2999 
   3000             if (mUnreadConversation != null) {
   3001                 Bundle b = IMPL.getBundleForUnreadConversation(mUnreadConversation);
   3002                 carExtensions.putBundle(EXTRA_CONVERSATION, b);
   3003             }
   3004 
   3005             builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions);
   3006             return builder;
   3007         }
   3008 
   3009         /**
   3010          * Sets the accent color to use when Android Auto presents the notification.
   3011          *
   3012          * Android Auto uses the color set with {@link android.support.v4.app.NotificationCompat.Builder#setColor(int)}
   3013          * to accent the displayed notification. However, not all colors are acceptable in an
   3014          * automotive setting. This method can be used to override the color provided in the
   3015          * notification in such a situation.
   3016          */
   3017         public CarExtender setColor(@ColorInt int color) {
   3018             mColor = color;
   3019             return this;
   3020         }
   3021 
   3022         /**
   3023          * Gets the accent color.
   3024          *
   3025          * @see setColor
   3026          */
   3027         @ColorInt
   3028         public int getColor() {
   3029             return mColor;
   3030         }
   3031 
   3032         /**
   3033          * Sets the large icon of the car notification.
   3034          *
   3035          * If no large icon is set in the extender, Android Auto will display the icon
   3036          * specified by {@link android.support.v4.app.NotificationCompat.Builder#setLargeIcon(android.graphics.Bitmap)}
   3037          *
   3038          * @param largeIcon The large icon to use in the car notification.
   3039          * @return This object for method chaining.
   3040          */
   3041         public CarExtender setLargeIcon(Bitmap largeIcon) {
   3042             mLargeIcon = largeIcon;
   3043             return this;
   3044         }
   3045 
   3046         /**
   3047          * Gets the large icon used in this car notification, or null if no icon has been set.
   3048          *
   3049          * @return The large icon for the car notification.
   3050          * @see CarExtender#setLargeIcon
   3051          */
   3052         public Bitmap getLargeIcon() {
   3053             return mLargeIcon;
   3054         }
   3055 
   3056         /**
   3057          * Sets the unread conversation in a message notification.
   3058          *
   3059          * @param unreadConversation The unread part of the conversation this notification conveys.
   3060          * @return This object for method chaining.
   3061          */
   3062         public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
   3063             mUnreadConversation = unreadConversation;
   3064             return this;
   3065         }
   3066 
   3067         /**
   3068          * Returns the unread conversation conveyed by this notification.
   3069          * @see #setUnreadConversation(UnreadConversation)
   3070          */
   3071         public UnreadConversation getUnreadConversation() {
   3072             return mUnreadConversation;
   3073         }
   3074 
   3075         /**
   3076          * A class which holds the unread messages from a conversation.
   3077          */
   3078         public static class UnreadConversation extends NotificationCompatBase.UnreadConversation {
   3079             private final String[] mMessages;
   3080             private final RemoteInput mRemoteInput;
   3081             private final PendingIntent mReplyPendingIntent;
   3082             private final PendingIntent mReadPendingIntent;
   3083             private final String[] mParticipants;
   3084             private final long mLatestTimestamp;
   3085 
   3086             UnreadConversation(String[] messages, RemoteInput remoteInput,
   3087                     PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
   3088                     String[] participants, long latestTimestamp) {
   3089                 mMessages = messages;
   3090                 mRemoteInput = remoteInput;
   3091                 mReadPendingIntent = readPendingIntent;
   3092                 mReplyPendingIntent = replyPendingIntent;
   3093                 mParticipants = participants;
   3094                 mLatestTimestamp = latestTimestamp;
   3095             }
   3096 
   3097             /**
   3098              * Gets the list of messages conveyed by this notification.
   3099              */
   3100             @Override
   3101             public String[] getMessages() {
   3102                 return mMessages;
   3103             }
   3104 
   3105             /**
   3106              * Gets the remote input that will be used to convey the response to a message list, or
   3107              * null if no such remote input exists.
   3108              */
   3109             @Override
   3110             public RemoteInput getRemoteInput() {
   3111                 return mRemoteInput;
   3112             }
   3113 
   3114             /**
   3115              * Gets the pending intent that will be triggered when the user replies to this
   3116              * notification.
   3117              */
   3118             @Override
   3119             public PendingIntent getReplyPendingIntent() {
   3120                 return mReplyPendingIntent;
   3121             }
   3122 
   3123             /**
   3124              * Gets the pending intent that Android Auto will send after it reads aloud all messages
   3125              * in this object's message list.
   3126              */
   3127             @Override
   3128             public PendingIntent getReadPendingIntent() {
   3129                 return mReadPendingIntent;
   3130             }
   3131 
   3132             /**
   3133              * Gets the participants in the conversation.
   3134              */
   3135             @Override
   3136             public String[] getParticipants() {
   3137                 return mParticipants;
   3138             }
   3139 
   3140             /**
   3141              * Gets the firs participant in the conversation.
   3142              */
   3143             @Override
   3144             public String getParticipant() {
   3145                 return mParticipants.length > 0 ? mParticipants[0] : null;
   3146             }
   3147 
   3148             /**
   3149              * Gets the timestamp of the conversation.
   3150              */
   3151             @Override
   3152             public long getLatestTimestamp() {
   3153                 return mLatestTimestamp;
   3154             }
   3155 
   3156             /** @hide */
   3157             static final Factory FACTORY = new Factory() {
   3158                 @Override
   3159                 public UnreadConversation build(
   3160                         String[] messages, RemoteInputCompatBase.RemoteInput remoteInput,
   3161                         PendingIntent replyPendingIntent, PendingIntent readPendingIntent,
   3162                         String[] participants, long latestTimestamp) {
   3163                     return new UnreadConversation(
   3164                             messages, (RemoteInput) remoteInput, replyPendingIntent,
   3165                             readPendingIntent,
   3166                             participants, latestTimestamp);
   3167                 }
   3168             };
   3169 
   3170             /**
   3171              * Builder class for {@link CarExtender.UnreadConversation} objects.
   3172              */
   3173             public static class Builder {
   3174                 private final List<String> mMessages = new ArrayList<String>();
   3175                 private final String mParticipant;
   3176                 private RemoteInput mRemoteInput;
   3177                 private PendingIntent mReadPendingIntent;
   3178                 private PendingIntent mReplyPendingIntent;
   3179                 private long mLatestTimestamp;
   3180 
   3181                 /**
   3182                  * Constructs a new builder for {@link CarExtender.UnreadConversation}.
   3183                  *
   3184                  * @param name The name of the other participant in the conversation.
   3185                  */
   3186                 public Builder(String name) {
   3187                     mParticipant = name;
   3188                 }
   3189 
   3190                 /**
   3191                  * Appends a new unread message to the list of messages for this conversation.
   3192                  *
   3193                  * The messages should be added from oldest to newest.
   3194                  *
   3195                  * @param message The text of the new unread message.
   3196                  * @return This object for method chaining.
   3197                  */
   3198                 public Builder addMessage(String message) {
   3199                     mMessages.add(message);
   3200                     return this;
   3201                 }
   3202 
   3203                 /**
   3204                  * Sets the pending intent and remote input which will convey the reply to this
   3205                  * notification.
   3206                  *
   3207                  * @param pendingIntent The pending intent which will be triggered on a reply.
   3208                  * @param remoteInput The remote input parcelable which will carry the reply.
   3209                  * @return This object for method chaining.
   3210                  *
   3211                  * @see CarExtender.UnreadConversation#getRemoteInput
   3212                  * @see CarExtender.UnreadConversation#getReplyPendingIntent
   3213                  */
   3214                 public Builder setReplyAction(
   3215                         PendingIntent pendingIntent, RemoteInput remoteInput) {
   3216                     mRemoteInput = remoteInput;
   3217                     mReplyPendingIntent = pendingIntent;
   3218 
   3219                     return this;
   3220                 }
   3221 
   3222                 /**
   3223                  * Sets the pending intent that will be sent once the messages in this notification
   3224                  * are read.
   3225                  *
   3226                  * @param pendingIntent The pending intent to use.
   3227                  * @return This object for method chaining.
   3228                  */
   3229                 public Builder setReadPendingIntent(PendingIntent pendingIntent) {
   3230                     mReadPendingIntent = pendingIntent;
   3231                     return this;
   3232                 }
   3233 
   3234                 /**
   3235                  * Sets the timestamp of the most recent message in an unread conversation.
   3236                  *
   3237                  * If a messaging notification has been posted by your application and has not
   3238                  * yet been cancelled, posting a later notification with the same id and tag
   3239                  * but without a newer timestamp may result in Android Auto not displaying a
   3240                  * heads up notification for the later notification.
   3241                  *
   3242                  * @param timestamp The timestamp of the most recent message in the conversation.
   3243                  * @return This object for method chaining.
   3244                  */
   3245                 public Builder setLatestTimestamp(long timestamp) {
   3246                     mLatestTimestamp = timestamp;
   3247                     return this;
   3248                 }
   3249 
   3250                 /**
   3251                  * Builds a new unread conversation object.
   3252                  *
   3253                  * @return The new unread conversation object.
   3254                  */
   3255                 public UnreadConversation build() {
   3256                     String[] messages = mMessages.toArray(new String[mMessages.size()]);
   3257                     String[] participants = { mParticipant };
   3258                     return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent,
   3259                             mReadPendingIntent, participants, mLatestTimestamp);
   3260                 }
   3261             }
   3262         }
   3263     }
   3264 
   3265 
   3266     /**
   3267      * Get an array of Notification objects from a parcelable array bundle field.
   3268      * Update the bundle to have a typed array so fetches in the future don't need
   3269      * to do an array copy.
   3270      */
   3271     private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) {
   3272         Parcelable[] array = bundle.getParcelableArray(key);
   3273         if (array instanceof Notification[] || array == null) {
   3274             return (Notification[]) array;
   3275         }
   3276         Notification[] typedArray = new Notification[array.length];
   3277         for (int i = 0; i < array.length; i++) {
   3278             typedArray[i] = (Notification) array[i];
   3279         }
   3280         bundle.putParcelableArray(key, typedArray);
   3281         return typedArray;
   3282     }
   3283 
   3284     /**
   3285      * Gets the {@link Notification#extras} field from a notification in a backwards
   3286      * compatible manner. Extras field was supported from JellyBean (Api level 16)
   3287      * forwards. This function will return null on older api levels.
   3288      */
   3289     public static Bundle getExtras(Notification notif) {
   3290         return IMPL.getExtras(notif);
   3291     }
   3292 
   3293     /**
   3294      * Get the number of actions in this notification in a backwards compatible
   3295      * manner. Actions were supported from JellyBean (Api level 16) forwards.
   3296      */
   3297     public static int getActionCount(Notification notif) {
   3298         return IMPL.getActionCount(notif);
   3299     }
   3300 
   3301     /**
   3302      * Get an action on this notification in a backwards compatible
   3303      * manner. Actions were supported from JellyBean (Api level 16) forwards.
   3304      * @param notif The notification to inspect.
   3305      * @param actionIndex The index of the action to retrieve.
   3306      */
   3307     public static Action getAction(Notification notif, int actionIndex) {
   3308         return IMPL.getAction(notif, actionIndex);
   3309     }
   3310 
   3311     /**
   3312     * Get the category of this notification in a backwards compatible
   3313     * manner.
   3314     * @param notif The notification to inspect.
   3315     */
   3316     public static String getCategory(Notification notif) {
   3317         return IMPL.getCategory(notif);
   3318     }
   3319 
   3320     /**
   3321      * Get whether or not this notification is only relevant to the current device.
   3322      *
   3323      * <p>Some notifications can be bridged to other devices for remote display.
   3324      * If this hint is set, it is recommend that this notification not be bridged.
   3325      */
   3326     public static boolean getLocalOnly(Notification notif) {
   3327         return IMPL.getLocalOnly(notif);
   3328     }
   3329 
   3330     /**
   3331      * Get the key used to group this notification into a cluster or stack
   3332      * with other notifications on devices which support such rendering.
   3333      */
   3334     public static String getGroup(Notification notif) {
   3335         return IMPL.getGroup(notif);
   3336     }
   3337 
   3338     /**
   3339      * Get whether this notification to be the group summary for a group of notifications.
   3340      * Grouped notifications may display in a cluster or stack on devices which
   3341      * support such rendering. Requires a group key also be set using {@link Builder#setGroup}.
   3342      * @return Whether this notification is a group summary.
   3343      */
   3344     public static boolean isGroupSummary(Notification notif) {
   3345         return IMPL.isGroupSummary(notif);
   3346     }
   3347 
   3348     /**
   3349      * Get a sort key that orders this notification among other notifications from the
   3350      * same package. This can be useful if an external sort was already applied and an app
   3351      * would like to preserve this. Notifications will be sorted lexicographically using this
   3352      * value, although providing different priorities in addition to providing sort key may
   3353      * cause this value to be ignored.
   3354      *
   3355      * <p>This sort key can also be used to order members of a notification group. See
   3356      * {@link Builder#setGroup}.
   3357      *
   3358      * @see String#compareTo(String)
   3359      */
   3360     public static String getSortKey(Notification notif) {
   3361         return IMPL.getSortKey(notif);
   3362     }
   3363 }
   3364