Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2007 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.app;
     18 
     19 import com.android.internal.R;
     20 
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.res.Resources;
     24 import android.graphics.Bitmap;
     25 import android.media.AudioManager;
     26 import android.net.Uri;
     27 import android.os.BadParcelableException;
     28 import android.os.Bundle;
     29 import android.os.Parcel;
     30 import android.os.Parcelable;
     31 import android.os.SystemClock;
     32 import android.os.UserHandle;
     33 import android.text.TextUtils;
     34 import android.util.Log;
     35 import android.util.TypedValue;
     36 import android.view.View;
     37 import android.widget.ProgressBar;
     38 import android.widget.RemoteViews;
     39 
     40 import java.text.NumberFormat;
     41 import java.util.ArrayList;
     42 
     43 /**
     44  * A class that represents how a persistent notification is to be presented to
     45  * the user using the {@link android.app.NotificationManager}.
     46  *
     47  * <p>The {@link Notification.Builder Notification.Builder} has been added to make it
     48  * easier to construct Notifications.</p>
     49  *
     50  * <div class="special reference">
     51  * <h3>Developer Guides</h3>
     52  * <p>For a guide to creating notifications, read the
     53  * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a>
     54  * developer guide.</p>
     55  * </div>
     56  */
     57 public class Notification implements Parcelable
     58 {
     59     private static final String TAG = "Notification";
     60 
     61     /**
     62      * Use all default values (where applicable).
     63      */
     64     public static final int DEFAULT_ALL = ~0;
     65 
     66     /**
     67      * Use the default notification sound. This will ignore any given
     68      * {@link #sound}.
     69      *
     70 
     71      * @see #defaults
     72      */
     73 
     74     public static final int DEFAULT_SOUND = 1;
     75 
     76     /**
     77      * Use the default notification vibrate. This will ignore any given
     78      * {@link #vibrate}. Using phone vibration requires the
     79      * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
     80      *
     81      * @see #defaults
     82      */
     83 
     84     public static final int DEFAULT_VIBRATE = 2;
     85 
     86     /**
     87      * Use the default notification lights. This will ignore the
     88      * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
     89      * {@link #ledOnMS}.
     90      *
     91      * @see #defaults
     92      */
     93 
     94     public static final int DEFAULT_LIGHTS = 4;
     95 
     96     /**
     97      * A timestamp related to this notification, in milliseconds since the epoch.
     98      *
     99      * Default value: {@link System#currentTimeMillis() Now}.
    100      *
    101      * Choose a timestamp that will be most relevant to the user. For most finite events, this
    102      * corresponds to the time the event happened (or will happen, in the case of events that have
    103      * yet to occur but about which the user is being informed). Indefinite events should be
    104      * timestamped according to when the activity began.
    105      *
    106      * Some examples:
    107      *
    108      * <ul>
    109      *   <li>Notification of a new chat message should be stamped when the message was received.</li>
    110      *   <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li>
    111      *   <li>Notification of a completed file download should be stamped when the download finished.</li>
    112      *   <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li>
    113      *   <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time.
    114      *   <li>Notification of an ongoing countdown timer should be stamped with the timer's end time.
    115      * </ul>
    116      *
    117      */
    118     public long when;
    119 
    120     /**
    121      * The resource id of a drawable to use as the icon in the status bar.
    122      * This is required; notifications with an invalid icon resource will not be shown.
    123      */
    124     public int icon;
    125 
    126     /**
    127      * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
    128      * leave it at its default value of 0.
    129      *
    130      * @see android.widget.ImageView#setImageLevel
    131      * @see android.graphics.drawable#setLevel
    132      */
    133     public int iconLevel;
    134 
    135     /**
    136      * The number of events that this notification represents. For example, in a new mail
    137      * notification, this could be the number of unread messages.
    138      *
    139      * The system may or may not use this field to modify the appearance of the notification. For
    140      * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was
    141      * superimposed over the icon in the status bar. Starting with
    142      * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by
    143      * {@link Notification.Builder} has displayed the number in the expanded notification view.
    144      *
    145      * If the number is 0 or negative, it is never shown.
    146      */
    147     public int number;
    148 
    149     /**
    150      * The intent to execute when the expanded status entry is clicked.  If
    151      * this is an activity, it must include the
    152      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
    153      * that you take care of task management as described in the
    154      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
    155      * Stack</a> document.  In particular, make sure to read the notification section
    156      * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling
    157      * Notifications</a> for the correct ways to launch an application from a
    158      * notification.
    159      */
    160     public PendingIntent contentIntent;
    161 
    162     /**
    163      * The intent to execute when the notification is explicitly dismissed by the user, either with
    164      * the "Clear All" button or by swiping it away individually.
    165      *
    166      * This probably shouldn't be launching an activity since several of those will be sent
    167      * at the same time.
    168      */
    169     public PendingIntent deleteIntent;
    170 
    171     /**
    172      * An intent to launch instead of posting the notification to the status bar.
    173      *
    174      * @see Notification.Builder#setFullScreenIntent
    175      */
    176     public PendingIntent fullScreenIntent;
    177 
    178     /**
    179      * Text to scroll across the screen when this item is added to
    180      * the status bar on large and smaller devices.
    181      *
    182      * @see #tickerView
    183      */
    184     public CharSequence tickerText;
    185 
    186     /**
    187      * The view to show as the ticker in the status bar when the notification
    188      * is posted.
    189      */
    190     public RemoteViews tickerView;
    191 
    192     /**
    193      * The view that will represent this notification in the expanded status bar.
    194      */
    195     public RemoteViews contentView;
    196 
    197     /**
    198      * A large-format version of {@link #contentView}, giving the Notification an
    199      * opportunity to show more detail. The system UI may choose to show this
    200      * instead of the normal content view at its discretion.
    201      */
    202     public RemoteViews bigContentView;
    203 
    204     /**
    205      * The bitmap that may escape the bounds of the panel and bar.
    206      */
    207     public Bitmap largeIcon;
    208 
    209     /**
    210      * The sound to play.
    211      *
    212      * <p>
    213      * To play the default notification sound, see {@link #defaults}.
    214      * </p>
    215      */
    216     public Uri sound;
    217 
    218     /**
    219      * Use this constant as the value for audioStreamType to request that
    220      * the default stream type for notifications be used.  Currently the
    221      * default stream type is {@link AudioManager#STREAM_NOTIFICATION}.
    222      */
    223     public static final int STREAM_DEFAULT = -1;
    224 
    225     /**
    226      * The audio stream type to use when playing the sound.
    227      * Should be one of the STREAM_ constants from
    228      * {@link android.media.AudioManager}.
    229      */
    230     public int audioStreamType = STREAM_DEFAULT;
    231 
    232     /**
    233      * The pattern with which to vibrate.
    234      *
    235      * <p>
    236      * To vibrate the default pattern, see {@link #defaults}.
    237      * </p>
    238      *
    239      * @see android.os.Vibrator#vibrate(long[],int)
    240      */
    241     public long[] vibrate;
    242 
    243     /**
    244      * The color of the led.  The hardware will do its best approximation.
    245      *
    246      * @see #FLAG_SHOW_LIGHTS
    247      * @see #flags
    248      */
    249     public int ledARGB;
    250 
    251     /**
    252      * The number of milliseconds for the LED to be on while it's flashing.
    253      * The hardware will do its best approximation.
    254      *
    255      * @see #FLAG_SHOW_LIGHTS
    256      * @see #flags
    257      */
    258     public int ledOnMS;
    259 
    260     /**
    261      * The number of milliseconds for the LED to be off while it's flashing.
    262      * The hardware will do its best approximation.
    263      *
    264      * @see #FLAG_SHOW_LIGHTS
    265      * @see #flags
    266      */
    267     public int ledOffMS;
    268 
    269     /**
    270      * Specifies which values should be taken from the defaults.
    271      * <p>
    272      * To set, OR the desired from {@link #DEFAULT_SOUND},
    273      * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
    274      * values, use {@link #DEFAULT_ALL}.
    275      * </p>
    276      */
    277     public int defaults;
    278 
    279     /**
    280      * Bit to be bitwise-ored into the {@link #flags} field that should be
    281      * set if you want the LED on for this notification.
    282      * <ul>
    283      * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
    284      *      or 0 for both ledOnMS and ledOffMS.</li>
    285      * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
    286      * <li>To flash the LED, pass the number of milliseconds that it should
    287      *      be on and off to ledOnMS and ledOffMS.</li>
    288      * </ul>
    289      * <p>
    290      * Since hardware varies, you are not guaranteed that any of the values
    291      * you pass are honored exactly.  Use the system defaults (TODO) if possible
    292      * because they will be set to values that work on any given hardware.
    293      * <p>
    294      * The alpha channel must be set for forward compatibility.
    295      *
    296      */
    297     public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
    298 
    299     /**
    300      * Bit to be bitwise-ored into the {@link #flags} field that should be
    301      * set if this notification is in reference to something that is ongoing,
    302      * like a phone call.  It should not be set if this notification is in
    303      * reference to something that happened at a particular point in time,
    304      * like a missed phone call.
    305      */
    306     public static final int FLAG_ONGOING_EVENT      = 0x00000002;
    307 
    308     /**
    309      * Bit to be bitwise-ored into the {@link #flags} field that if set,
    310      * the audio will be repeated until the notification is
    311      * cancelled or the notification window is opened.
    312      */
    313     public static final int FLAG_INSISTENT          = 0x00000004;
    314 
    315     /**
    316      * Bit to be bitwise-ored into the {@link #flags} field that should be
    317      * set if you want the sound and/or vibration play each time the
    318      * notification is sent, even if it has not been canceled before that.
    319      */
    320     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
    321 
    322     /**
    323      * Bit to be bitwise-ored into the {@link #flags} field that should be
    324      * set if the notification should be canceled when it is clicked by the
    325      * user.
    326 
    327      */
    328     public static final int FLAG_AUTO_CANCEL        = 0x00000010;
    329 
    330     /**
    331      * Bit to be bitwise-ored into the {@link #flags} field that should be
    332      * set if the notification should not be canceled when the user clicks
    333      * the Clear all button.
    334      */
    335     public static final int FLAG_NO_CLEAR           = 0x00000020;
    336 
    337     /**
    338      * Bit to be bitwise-ored into the {@link #flags} field that should be
    339      * set if this notification represents a currently running service.  This
    340      * will normally be set for you by {@link Service#startForeground}.
    341      */
    342     public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
    343 
    344     /**
    345      * Obsolete flag indicating high-priority notifications; use the priority field instead.
    346      *
    347      * @deprecated Use {@link #priority} with a positive value.
    348      */
    349     public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
    350 
    351     public int flags;
    352 
    353     /**
    354      * Default notification {@link #priority}. If your application does not prioritize its own
    355      * notifications, use this value for all notifications.
    356      */
    357     public static final int PRIORITY_DEFAULT = 0;
    358 
    359     /**
    360      * Lower {@link #priority}, for items that are less important. The UI may choose to show these
    361      * items smaller, or at a different position in the list, compared with your app's
    362      * {@link #PRIORITY_DEFAULT} items.
    363      */
    364     public static final int PRIORITY_LOW = -1;
    365 
    366     /**
    367      * Lowest {@link #priority}; these items might not be shown to the user except under special
    368      * circumstances, such as detailed notification logs.
    369      */
    370     public static final int PRIORITY_MIN = -2;
    371 
    372     /**
    373      * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to
    374      * show these items larger, or at a different position in notification lists, compared with
    375      * your app's {@link #PRIORITY_DEFAULT} items.
    376      */
    377     public static final int PRIORITY_HIGH = 1;
    378 
    379     /**
    380      * Highest {@link #priority}, for your application's most important items that require the
    381      * user's prompt attention or input.
    382      */
    383     public static final int PRIORITY_MAX = 2;
    384 
    385     /**
    386      * Relative priority for this notification.
    387      *
    388      * Priority is an indication of how much of the user's valuable attention should be consumed by
    389      * this notification. Low-priority notifications may be hidden from the user in certain
    390      * situations, while the user might be interrupted for a higher-priority notification. The
    391      * system will make a determination about how to interpret this priority when presenting
    392      * the notification.
    393      */
    394     public int priority;
    395 
    396     /**
    397      * @hide
    398      * Notification type: incoming call (voice or video) or similar synchronous communication request.
    399      */
    400     public static final String KIND_CALL = "android.call";
    401 
    402     /**
    403      * @hide
    404      * Notification type: incoming direct message (SMS, instant message, etc.).
    405      */
    406     public static final String KIND_MESSAGE = "android.message";
    407 
    408     /**
    409      * @hide
    410      * Notification type: asynchronous bulk message (email).
    411      */
    412     public static final String KIND_EMAIL = "android.email";
    413 
    414     /**
    415      * @hide
    416      * Notification type: calendar event.
    417      */
    418     public static final String KIND_EVENT = "android.event";
    419 
    420     /**
    421      * @hide
    422      * Notification type: promotion or advertisement.
    423      */
    424     public static final String KIND_PROMO = "android.promo";
    425 
    426     /**
    427      * @hide
    428      * If this notification matches of one or more special types (see the <code>KIND_*</code>
    429      * constants), add them here, best match first.
    430      */
    431     public String[] kind;
    432 
    433     /**
    434      * Additional semantic data to be carried around with this Notification.
    435      * <p>
    436      * The extras keys defined here are intended to capture the original inputs to {@link Builder}
    437      * APIs, and are intended to be used by
    438      * {@link android.service.notification.NotificationListenerService} implementations to extract
    439      * detailed information from notification objects.
    440      */
    441     public Bundle extras = new Bundle();
    442 
    443     /**
    444      * {@link #extras} key: this is the title of the notification,
    445      * as supplied to {@link Builder#setContentTitle(CharSequence)}.
    446      */
    447     public static final String EXTRA_TITLE = "android.title";
    448 
    449     /**
    450      * {@link #extras} key: this is the title of the notification when shown in expanded form,
    451      * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}.
    452      */
    453     public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big";
    454 
    455     /**
    456      * {@link #extras} key: this is the main text payload, as supplied to
    457      * {@link Builder#setContentText(CharSequence)}.
    458      */
    459     public static final String EXTRA_TEXT = "android.text";
    460 
    461     /**
    462      * {@link #extras} key: this is a third line of text, as supplied to
    463      * {@link Builder#setSubText(CharSequence)}.
    464      */
    465     public static final String EXTRA_SUB_TEXT = "android.subText";
    466 
    467     /**
    468      * {@link #extras} key: this is a small piece of additional text as supplied to
    469      * {@link Builder#setContentInfo(CharSequence)}.
    470      */
    471     public static final String EXTRA_INFO_TEXT = "android.infoText";
    472 
    473     /**
    474      * {@link #extras} key: this is a line of summary information intended to be shown
    475      * alongside expanded notifications, as supplied to (e.g.)
    476      * {@link BigTextStyle#setSummaryText(CharSequence)}.
    477      */
    478     public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
    479 
    480     /**
    481      * {@link #extras} key: this is the resource ID of the notification's main small icon, as
    482      * supplied to {@link Builder#setSmallIcon(int)}.
    483      */
    484     public static final String EXTRA_SMALL_ICON = "android.icon";
    485 
    486     /**
    487      * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the
    488      * notification payload, as
    489      * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}.
    490      */
    491     public static final String EXTRA_LARGE_ICON = "android.largeIcon";
    492 
    493     /**
    494      * {@link #extras} key: this is a bitmap to be used instead of the one from
    495      * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is
    496      * shown in its expanded form, as supplied to
    497      * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}.
    498      */
    499     public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big";
    500 
    501     /**
    502      * {@link #extras} key: this is the progress value supplied to
    503      * {@link Builder#setProgress(int, int, boolean)}.
    504      */
    505     public static final String EXTRA_PROGRESS = "android.progress";
    506 
    507     /**
    508      * {@link #extras} key: this is the maximum value supplied to
    509      * {@link Builder#setProgress(int, int, boolean)}.
    510      */
    511     public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
    512 
    513     /**
    514      * {@link #extras} key: whether the progress bar is indeterminate, supplied to
    515      * {@link Builder#setProgress(int, int, boolean)}.
    516      */
    517     public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
    518 
    519     /**
    520      * {@link #extras} key: whether {@link #when} should be shown as a count-up timer (specifically
    521      * a {@link android.widget.Chronometer}) instead of a timestamp, as supplied to
    522      * {@link Builder#setUsesChronometer(boolean)}.
    523      */
    524     public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
    525 
    526     /**
    527      * {@link #extras} key: whether {@link #when} should be shown,
    528      * as supplied to {@link Builder#setShowWhen(boolean)}.
    529      */
    530     public static final String EXTRA_SHOW_WHEN = "android.showWhen";
    531 
    532     /**
    533      * {@link #extras} key: this is a bitmap to be shown in {@link BigPictureStyle} expanded
    534      * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}.
    535      */
    536     public static final String EXTRA_PICTURE = "android.picture";
    537 
    538     /**
    539      * {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
    540      * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
    541      */
    542     public static final String EXTRA_TEXT_LINES = "android.textLines";
    543 
    544     /**
    545      * {@link #extras} key: An array of people that this notification relates to, specified
    546      * by contacts provider contact URI.
    547      */
    548     public static final String EXTRA_PEOPLE = "android.people";
    549 
    550     /**
    551      * @hide
    552      * Extra added by NotificationManagerService to indicate whether a NotificationScorer
    553      * modified the Notifications's score.
    554      */
    555     public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified";
    556 
    557     /**
    558      * Not used.
    559      * @hide
    560      */
    561     public static final String EXTRA_AS_HEADS_UP = "headsup";
    562 
    563     /**
    564      * Value for {@link #EXTRA_AS_HEADS_UP}.
    565      * @hide
    566      */
    567     public static final int HEADS_UP_NEVER = 0;
    568 
    569     /**
    570      * Default value for {@link #EXTRA_AS_HEADS_UP}.
    571      * @hide
    572      */
    573     public static final int HEADS_UP_ALLOWED = 1;
    574 
    575     /**
    576      * Value for {@link #EXTRA_AS_HEADS_UP}.
    577      * @hide
    578      */
    579     public static final int HEADS_UP_REQUESTED = 2;
    580 
    581     /**
    582      * Structure to encapsulate a named action that can be shown as part of this notification.
    583      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
    584      * selected by the user.
    585      * <p>
    586      * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
    587      * attach actions.
    588      */
    589     public static class Action implements Parcelable {
    590         /**
    591          * Small icon representing the action.
    592          */
    593         public int icon;
    594         /**
    595          * Title of the action.
    596          */
    597         public CharSequence title;
    598         /**
    599          * Intent to send when the user invokes this action. May be null, in which case the action
    600          * may be rendered in a disabled presentation by the system UI.
    601          */
    602         public PendingIntent actionIntent;
    603 
    604         private Action() { }
    605         private Action(Parcel in) {
    606             icon = in.readInt();
    607             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    608             if (in.readInt() == 1) {
    609                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
    610             }
    611         }
    612         /**
    613          * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
    614          */
    615         public Action(int icon, CharSequence title, PendingIntent intent) {
    616             this.icon = icon;
    617             this.title = title;
    618             this.actionIntent = intent;
    619         }
    620 
    621         @Override
    622         public Action clone() {
    623             return new Action(
    624                 this.icon,
    625                 this.title,
    626                 this.actionIntent // safe to alias
    627             );
    628         }
    629         @Override
    630         public int describeContents() {
    631             return 0;
    632         }
    633         @Override
    634         public void writeToParcel(Parcel out, int flags) {
    635             out.writeInt(icon);
    636             TextUtils.writeToParcel(title, out, flags);
    637             if (actionIntent != null) {
    638                 out.writeInt(1);
    639                 actionIntent.writeToParcel(out, flags);
    640             } else {
    641                 out.writeInt(0);
    642             }
    643         }
    644         public static final Parcelable.Creator<Action> CREATOR
    645         = new Parcelable.Creator<Action>() {
    646             public Action createFromParcel(Parcel in) {
    647                 return new Action(in);
    648             }
    649             public Action[] newArray(int size) {
    650                 return new Action[size];
    651             }
    652         };
    653     }
    654 
    655     /**
    656      * Array of all {@link Action} structures attached to this notification by
    657      * {@link Builder#addAction(int, CharSequence, PendingIntent)}. Mostly useful for instances of
    658      * {@link android.service.notification.NotificationListenerService} that provide an alternative
    659      * interface for invoking actions.
    660      */
    661     public Action[] actions;
    662 
    663     /**
    664      * Constructs a Notification object with default values.
    665      * You might want to consider using {@link Builder} instead.
    666      */
    667     public Notification()
    668     {
    669         this.when = System.currentTimeMillis();
    670         this.priority = PRIORITY_DEFAULT;
    671     }
    672 
    673     /**
    674      * @hide
    675      */
    676     public Notification(Context context, int icon, CharSequence tickerText, long when,
    677             CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
    678     {
    679         this.when = when;
    680         this.icon = icon;
    681         this.tickerText = tickerText;
    682         setLatestEventInfo(context, contentTitle, contentText,
    683                 PendingIntent.getActivity(context, 0, contentIntent, 0));
    684     }
    685 
    686     /**
    687      * Constructs a Notification object with the information needed to
    688      * have a status bar icon without the standard expanded view.
    689      *
    690      * @param icon          The resource id of the icon to put in the status bar.
    691      * @param tickerText    The text that flows by in the status bar when the notification first
    692      *                      activates.
    693      * @param when          The time to show in the time field.  In the System.currentTimeMillis
    694      *                      timebase.
    695      *
    696      * @deprecated Use {@link Builder} instead.
    697      */
    698     @Deprecated
    699     public Notification(int icon, CharSequence tickerText, long when)
    700     {
    701         this.icon = icon;
    702         this.tickerText = tickerText;
    703         this.when = when;
    704     }
    705 
    706     /**
    707      * Unflatten the notification from a parcel.
    708      */
    709     public Notification(Parcel parcel)
    710     {
    711         int version = parcel.readInt();
    712 
    713         when = parcel.readLong();
    714         icon = parcel.readInt();
    715         number = parcel.readInt();
    716         if (parcel.readInt() != 0) {
    717             contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
    718         }
    719         if (parcel.readInt() != 0) {
    720             deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
    721         }
    722         if (parcel.readInt() != 0) {
    723             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
    724         }
    725         if (parcel.readInt() != 0) {
    726             tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
    727         }
    728         if (parcel.readInt() != 0) {
    729             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
    730         }
    731         if (parcel.readInt() != 0) {
    732             largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
    733         }
    734         defaults = parcel.readInt();
    735         flags = parcel.readInt();
    736         if (parcel.readInt() != 0) {
    737             sound = Uri.CREATOR.createFromParcel(parcel);
    738         }
    739 
    740         audioStreamType = parcel.readInt();
    741         vibrate = parcel.createLongArray();
    742         ledARGB = parcel.readInt();
    743         ledOnMS = parcel.readInt();
    744         ledOffMS = parcel.readInt();
    745         iconLevel = parcel.readInt();
    746 
    747         if (parcel.readInt() != 0) {
    748             fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
    749         }
    750 
    751         priority = parcel.readInt();
    752 
    753         kind = parcel.createStringArray(); // may set kind to null
    754 
    755         extras = parcel.readBundle(); // may be null
    756 
    757         actions = parcel.createTypedArray(Action.CREATOR); // may be null
    758 
    759         if (parcel.readInt() != 0) {
    760             bigContentView = RemoteViews.CREATOR.createFromParcel(parcel);
    761         }
    762     }
    763 
    764     @Override
    765     public Notification clone() {
    766         Notification that = new Notification();
    767         cloneInto(that, true);
    768         return that;
    769     }
    770 
    771     /**
    772      * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members
    773      * of this into that.
    774      * @hide
    775      */
    776     public void cloneInto(Notification that, boolean heavy) {
    777         that.when = this.when;
    778         that.icon = this.icon;
    779         that.number = this.number;
    780 
    781         // PendingIntents are global, so there's no reason (or way) to clone them.
    782         that.contentIntent = this.contentIntent;
    783         that.deleteIntent = this.deleteIntent;
    784         that.fullScreenIntent = this.fullScreenIntent;
    785 
    786         if (this.tickerText != null) {
    787             that.tickerText = this.tickerText.toString();
    788         }
    789         if (heavy && this.tickerView != null) {
    790             that.tickerView = this.tickerView.clone();
    791         }
    792         if (heavy && this.contentView != null) {
    793             that.contentView = this.contentView.clone();
    794         }
    795         if (heavy && this.largeIcon != null) {
    796             that.largeIcon = Bitmap.createBitmap(this.largeIcon);
    797         }
    798         that.iconLevel = this.iconLevel;
    799         that.sound = this.sound; // android.net.Uri is immutable
    800         that.audioStreamType = this.audioStreamType;
    801 
    802         final long[] vibrate = this.vibrate;
    803         if (vibrate != null) {
    804             final int N = vibrate.length;
    805             final long[] vib = that.vibrate = new long[N];
    806             System.arraycopy(vibrate, 0, vib, 0, N);
    807         }
    808 
    809         that.ledARGB = this.ledARGB;
    810         that.ledOnMS = this.ledOnMS;
    811         that.ledOffMS = this.ledOffMS;
    812         that.defaults = this.defaults;
    813 
    814         that.flags = this.flags;
    815 
    816         that.priority = this.priority;
    817 
    818         final String[] thiskind = this.kind;
    819         if (thiskind != null) {
    820             final int N = thiskind.length;
    821             final String[] thatkind = that.kind = new String[N];
    822             System.arraycopy(thiskind, 0, thatkind, 0, N);
    823         }
    824 
    825         if (this.extras != null) {
    826             try {
    827                 that.extras = new Bundle(this.extras);
    828                 // will unparcel
    829                 that.extras.size();
    830             } catch (BadParcelableException e) {
    831                 Log.e(TAG, "could not unparcel extras from notification: " + this, e);
    832                 that.extras = null;
    833             }
    834         }
    835 
    836         if (this.actions != null) {
    837             that.actions = new Action[this.actions.length];
    838             for(int i=0; i<this.actions.length; i++) {
    839                 that.actions[i] = this.actions[i].clone();
    840             }
    841         }
    842 
    843         if (heavy && this.bigContentView != null) {
    844             that.bigContentView = this.bigContentView.clone();
    845         }
    846 
    847         if (!heavy) {
    848             that.lightenPayload(); // will clean out extras
    849         }
    850     }
    851 
    852     /**
    853      * Removes heavyweight parts of the Notification object for archival or for sending to
    854      * listeners when the full contents are not necessary.
    855      * @hide
    856      */
    857     public final void lightenPayload() {
    858         tickerView = null;
    859         contentView = null;
    860         bigContentView = null;
    861         largeIcon = null;
    862         if (extras != null) {
    863             extras.remove(Notification.EXTRA_LARGE_ICON);
    864             extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
    865             extras.remove(Notification.EXTRA_PICTURE);
    866         }
    867     }
    868 
    869     /**
    870      * Make sure this CharSequence is safe to put into a bundle, which basically
    871      * means it had better not be some custom Parcelable implementation.
    872      * @hide
    873      */
    874     public static CharSequence safeCharSequence(CharSequence cs) {
    875         if (cs instanceof Parcelable) {
    876             Log.e(TAG, "warning: " + cs.getClass().getCanonicalName()
    877                     + " instance is a custom Parcelable and not allowed in Notification");
    878             return cs.toString();
    879         }
    880 
    881         return cs;
    882     }
    883 
    884     public int describeContents() {
    885         return 0;
    886     }
    887 
    888     /**
    889      * Flatten this notification from a parcel.
    890      */
    891     public void writeToParcel(Parcel parcel, int flags)
    892     {
    893         parcel.writeInt(1);
    894 
    895         parcel.writeLong(when);
    896         parcel.writeInt(icon);
    897         parcel.writeInt(number);
    898         if (contentIntent != null) {
    899             parcel.writeInt(1);
    900             contentIntent.writeToParcel(parcel, 0);
    901         } else {
    902             parcel.writeInt(0);
    903         }
    904         if (deleteIntent != null) {
    905             parcel.writeInt(1);
    906             deleteIntent.writeToParcel(parcel, 0);
    907         } else {
    908             parcel.writeInt(0);
    909         }
    910         if (tickerText != null) {
    911             parcel.writeInt(1);
    912             TextUtils.writeToParcel(tickerText, parcel, flags);
    913         } else {
    914             parcel.writeInt(0);
    915         }
    916         if (tickerView != null) {
    917             parcel.writeInt(1);
    918             tickerView.writeToParcel(parcel, 0);
    919         } else {
    920             parcel.writeInt(0);
    921         }
    922         if (contentView != null) {
    923             parcel.writeInt(1);
    924             contentView.writeToParcel(parcel, 0);
    925         } else {
    926             parcel.writeInt(0);
    927         }
    928         if (largeIcon != null) {
    929             parcel.writeInt(1);
    930             largeIcon.writeToParcel(parcel, 0);
    931         } else {
    932             parcel.writeInt(0);
    933         }
    934 
    935         parcel.writeInt(defaults);
    936         parcel.writeInt(this.flags);
    937 
    938         if (sound != null) {
    939             parcel.writeInt(1);
    940             sound.writeToParcel(parcel, 0);
    941         } else {
    942             parcel.writeInt(0);
    943         }
    944         parcel.writeInt(audioStreamType);
    945         parcel.writeLongArray(vibrate);
    946         parcel.writeInt(ledARGB);
    947         parcel.writeInt(ledOnMS);
    948         parcel.writeInt(ledOffMS);
    949         parcel.writeInt(iconLevel);
    950 
    951         if (fullScreenIntent != null) {
    952             parcel.writeInt(1);
    953             fullScreenIntent.writeToParcel(parcel, 0);
    954         } else {
    955             parcel.writeInt(0);
    956         }
    957 
    958         parcel.writeInt(priority);
    959 
    960         parcel.writeStringArray(kind); // ok for null
    961 
    962         parcel.writeBundle(extras); // null ok
    963 
    964         parcel.writeTypedArray(actions, 0); // null ok
    965 
    966         if (bigContentView != null) {
    967             parcel.writeInt(1);
    968             bigContentView.writeToParcel(parcel, 0);
    969         } else {
    970             parcel.writeInt(0);
    971         }
    972     }
    973 
    974     /**
    975      * Parcelable.Creator that instantiates Notification objects
    976      */
    977     public static final Parcelable.Creator<Notification> CREATOR
    978             = new Parcelable.Creator<Notification>()
    979     {
    980         public Notification createFromParcel(Parcel parcel)
    981         {
    982             return new Notification(parcel);
    983         }
    984 
    985         public Notification[] newArray(int size)
    986         {
    987             return new Notification[size];
    988         }
    989     };
    990 
    991     /**
    992      * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
    993      * layout.
    994      *
    995      * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
    996      * in the view.</p>
    997      * @param context       The context for your application / activity.
    998      * @param contentTitle The title that goes in the expanded entry.
    999      * @param contentText  The text that goes in the expanded entry.
   1000      * @param contentIntent The intent to launch when the user clicks the expanded notification.
   1001      * If this is an activity, it must include the
   1002      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
   1003      * that you take care of task management as described in the
   1004      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
   1005      * Stack</a> document.
   1006      *
   1007      * @deprecated Use {@link Builder} instead.
   1008      */
   1009     @Deprecated
   1010     public void setLatestEventInfo(Context context,
   1011             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
   1012         Notification.Builder builder = new Notification.Builder(context);
   1013 
   1014         // First, ensure that key pieces of information that may have been set directly
   1015         // are preserved
   1016         builder.setWhen(this.when);
   1017         builder.setSmallIcon(this.icon);
   1018         builder.setPriority(this.priority);
   1019         builder.setTicker(this.tickerText);
   1020         builder.setNumber(this.number);
   1021         builder.mFlags = this.flags;
   1022         builder.setSound(this.sound, this.audioStreamType);
   1023         builder.setDefaults(this.defaults);
   1024         builder.setVibrate(this.vibrate);
   1025 
   1026         // now apply the latestEventInfo fields
   1027         if (contentTitle != null) {
   1028             builder.setContentTitle(contentTitle);
   1029         }
   1030         if (contentText != null) {
   1031             builder.setContentText(contentText);
   1032         }
   1033         builder.setContentIntent(contentIntent);
   1034         builder.buildInto(this);
   1035     }
   1036 
   1037     @Override
   1038     public String toString() {
   1039         StringBuilder sb = new StringBuilder();
   1040         sb.append("Notification(pri=");
   1041         sb.append(priority);
   1042         sb.append(" contentView=");
   1043         if (contentView != null) {
   1044             sb.append(contentView.getPackage());
   1045             sb.append("/0x");
   1046             sb.append(Integer.toHexString(contentView.getLayoutId()));
   1047         } else {
   1048             sb.append("null");
   1049         }
   1050         // TODO(dsandler): defaults take precedence over local values, so reorder the branches below
   1051         sb.append(" vibrate=");
   1052         if ((this.defaults & DEFAULT_VIBRATE) != 0) {
   1053             sb.append("default");
   1054         } else if (this.vibrate != null) {
   1055             int N = this.vibrate.length-1;
   1056             sb.append("[");
   1057             for (int i=0; i<N; i++) {
   1058                 sb.append(this.vibrate[i]);
   1059                 sb.append(',');
   1060             }
   1061             if (N != -1) {
   1062                 sb.append(this.vibrate[N]);
   1063             }
   1064             sb.append("]");
   1065         } else {
   1066             sb.append("null");
   1067         }
   1068         sb.append(" sound=");
   1069         if ((this.defaults & DEFAULT_SOUND) != 0) {
   1070             sb.append("default");
   1071         } else if (this.sound != null) {
   1072             sb.append(this.sound.toString());
   1073         } else {
   1074             sb.append("null");
   1075         }
   1076         sb.append(" defaults=0x");
   1077         sb.append(Integer.toHexString(this.defaults));
   1078         sb.append(" flags=0x");
   1079         sb.append(Integer.toHexString(this.flags));
   1080         sb.append(" kind=[");
   1081         if (this.kind == null) {
   1082             sb.append("null");
   1083         } else {
   1084             for (int i=0; i<this.kind.length; i++) {
   1085                 if (i>0) sb.append(",");
   1086                 sb.append(this.kind[i]);
   1087             }
   1088         }
   1089         sb.append("]");
   1090         if (actions != null) {
   1091             sb.append(" ");
   1092             sb.append(actions.length);
   1093             sb.append(" action");
   1094             if (actions.length > 1) sb.append("s");
   1095         }
   1096         sb.append(")");
   1097         return sb.toString();
   1098     }
   1099 
   1100     /** {@hide} */
   1101     public void setUser(UserHandle user) {
   1102         if (user.getIdentifier() == UserHandle.USER_ALL) {
   1103             user = UserHandle.OWNER;
   1104         }
   1105         if (tickerView != null) {
   1106             tickerView.setUser(user);
   1107         }
   1108         if (contentView != null) {
   1109             contentView.setUser(user);
   1110         }
   1111         if (bigContentView != null) {
   1112             bigContentView.setUser(user);
   1113         }
   1114     }
   1115 
   1116     /**
   1117      * Builder class for {@link Notification} objects.
   1118      *
   1119      * Provides a convenient way to set the various fields of a {@link Notification} and generate
   1120      * content views using the platform's notification layout template. If your app supports
   1121      * versions of Android as old as API level 4, you can instead use
   1122      * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
   1123      * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
   1124      * library</a>.
   1125      *
   1126      * <p>Example:
   1127      *
   1128      * <pre class="prettyprint">
   1129      * Notification noti = new Notification.Builder(mContext)
   1130      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
   1131      *         .setContentText(subject)
   1132      *         .setSmallIcon(R.drawable.new_mail)
   1133      *         .setLargeIcon(aBitmap)
   1134      *         .build();
   1135      * </pre>
   1136      */
   1137     public static class Builder {
   1138         private static final int MAX_ACTION_BUTTONS = 3;
   1139 
   1140         private Context mContext;
   1141 
   1142         private long mWhen;
   1143         private int mSmallIcon;
   1144         private int mSmallIconLevel;
   1145         private int mNumber;
   1146         private CharSequence mContentTitle;
   1147         private CharSequence mContentText;
   1148         private CharSequence mContentInfo;
   1149         private CharSequence mSubText;
   1150         private PendingIntent mContentIntent;
   1151         private RemoteViews mContentView;
   1152         private PendingIntent mDeleteIntent;
   1153         private PendingIntent mFullScreenIntent;
   1154         private CharSequence mTickerText;
   1155         private RemoteViews mTickerView;
   1156         private Bitmap mLargeIcon;
   1157         private Uri mSound;
   1158         private int mAudioStreamType;
   1159         private long[] mVibrate;
   1160         private int mLedArgb;
   1161         private int mLedOnMs;
   1162         private int mLedOffMs;
   1163         private int mDefaults;
   1164         private int mFlags;
   1165         private int mProgressMax;
   1166         private int mProgress;
   1167         private boolean mProgressIndeterminate;
   1168         private ArrayList<String> mKindList = new ArrayList<String>(1);
   1169         private Bundle mExtras;
   1170         private int mPriority;
   1171         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
   1172         private boolean mUseChronometer;
   1173         private Style mStyle;
   1174         private boolean mShowWhen = true;
   1175 
   1176         /**
   1177          * Constructs a new Builder with the defaults:
   1178          *
   1179 
   1180          * <table>
   1181          * <tr><th align=right>priority</th>
   1182          *     <td>{@link #PRIORITY_DEFAULT}</td></tr>
   1183          * <tr><th align=right>when</th>
   1184          *     <td>now ({@link System#currentTimeMillis()})</td></tr>
   1185          * <tr><th align=right>audio stream</th>
   1186          *     <td>{@link #STREAM_DEFAULT}</td></tr>
   1187          * </table>
   1188          *
   1189 
   1190          * @param context
   1191          *            A {@link Context} that will be used by the Builder to construct the
   1192          *            RemoteViews. The Context will not be held past the lifetime of this Builder
   1193          *            object.
   1194          */
   1195         public Builder(Context context) {
   1196             mContext = context;
   1197 
   1198             // Set defaults to match the defaults of a Notification
   1199             mWhen = System.currentTimeMillis();
   1200             mAudioStreamType = STREAM_DEFAULT;
   1201             mPriority = PRIORITY_DEFAULT;
   1202         }
   1203 
   1204         /**
   1205          * Add a timestamp pertaining to the notification (usually the time the event occurred).
   1206          * It will be shown in the notification content view by default; use
   1207          * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
   1208          *
   1209          * @see Notification#when
   1210          */
   1211         public Builder setWhen(long when) {
   1212             mWhen = when;
   1213             return this;
   1214         }
   1215 
   1216         /**
   1217          * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
   1218          * in the content view.
   1219          */
   1220         public Builder setShowWhen(boolean show) {
   1221             mShowWhen = show;
   1222             return this;
   1223         }
   1224 
   1225         /**
   1226          * Show the {@link Notification#when} field as a stopwatch.
   1227          *
   1228          * Instead of presenting <code>when</code> as a timestamp, the notification will show an
   1229          * automatically updating display of the minutes and seconds since <code>when</code>.
   1230          *
   1231          * Useful when showing an elapsed time (like an ongoing phone call).
   1232          *
   1233          * @see android.widget.Chronometer
   1234          * @see Notification#when
   1235          */
   1236         public Builder setUsesChronometer(boolean b) {
   1237             mUseChronometer = b;
   1238             return this;
   1239         }
   1240 
   1241         /**
   1242          * Set the small icon resource, which will be used to represent the notification in the
   1243          * status bar.
   1244          *
   1245 
   1246          * The platform template for the expanded view will draw this icon in the left, unless a
   1247          * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
   1248          * icon will be moved to the right-hand side.
   1249          *
   1250 
   1251          * @param icon
   1252          *            A resource ID in the application's package of the drawable to use.
   1253          * @see Notification#icon
   1254          */
   1255         public Builder setSmallIcon(int icon) {
   1256             mSmallIcon = icon;
   1257             return this;
   1258         }
   1259 
   1260         /**
   1261          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
   1262          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
   1263          * LevelListDrawable}.
   1264          *
   1265          * @param icon A resource ID in the application's package of the drawable to use.
   1266          * @param level The level to use for the icon.
   1267          *
   1268          * @see Notification#icon
   1269          * @see Notification#iconLevel
   1270          */
   1271         public Builder setSmallIcon(int icon, int level) {
   1272             mSmallIcon = icon;
   1273             mSmallIconLevel = level;
   1274             return this;
   1275         }
   1276 
   1277         /**
   1278          * Set the first line of text in the platform notification template.
   1279          */
   1280         public Builder setContentTitle(CharSequence title) {
   1281             mContentTitle = safeCharSequence(title);
   1282             return this;
   1283         }
   1284 
   1285         /**
   1286          * Set the second line of text in the platform notification template.
   1287          */
   1288         public Builder setContentText(CharSequence text) {
   1289             mContentText = safeCharSequence(text);
   1290             return this;
   1291         }
   1292 
   1293         /**
   1294          * Set the third line of text in the platform notification template.
   1295          * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the
   1296          * same location in the standard template.
   1297          */
   1298         public Builder setSubText(CharSequence text) {
   1299             mSubText = safeCharSequence(text);
   1300             return this;
   1301         }
   1302 
   1303         /**
   1304          * Set the large number at the right-hand side of the notification.  This is
   1305          * equivalent to setContentInfo, although it might show the number in a different
   1306          * font size for readability.
   1307          */
   1308         public Builder setNumber(int number) {
   1309             mNumber = number;
   1310             return this;
   1311         }
   1312 
   1313         /**
   1314          * A small piece of additional information pertaining to this notification.
   1315          *
   1316          * The platform template will draw this on the last line of the notification, at the far
   1317          * right (to the right of a smallIcon if it has been placed there).
   1318          */
   1319         public Builder setContentInfo(CharSequence info) {
   1320             mContentInfo = safeCharSequence(info);
   1321             return this;
   1322         }
   1323 
   1324         /**
   1325          * Set the progress this notification represents.
   1326          *
   1327          * The platform template will represent this using a {@link ProgressBar}.
   1328          */
   1329         public Builder setProgress(int max, int progress, boolean indeterminate) {
   1330             mProgressMax = max;
   1331             mProgress = progress;
   1332             mProgressIndeterminate = indeterminate;
   1333             return this;
   1334         }
   1335 
   1336         /**
   1337          * Supply a custom RemoteViews to use instead of the platform template.
   1338          *
   1339          * @see Notification#contentView
   1340          */
   1341         public Builder setContent(RemoteViews views) {
   1342             mContentView = views;
   1343             return this;
   1344         }
   1345 
   1346         /**
   1347          * Supply a {@link PendingIntent} to be sent when the notification is clicked.
   1348          *
   1349          * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
   1350          * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
   1351          * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
   1352          * to assign PendingIntents to individual views in that custom layout (i.e., to create
   1353          * clickable buttons inside the notification view).
   1354          *
   1355          * @see Notification#contentIntent Notification.contentIntent
   1356          */
   1357         public Builder setContentIntent(PendingIntent intent) {
   1358             mContentIntent = intent;
   1359             return this;
   1360         }
   1361 
   1362         /**
   1363          * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
   1364          *
   1365          * @see Notification#deleteIntent
   1366          */
   1367         public Builder setDeleteIntent(PendingIntent intent) {
   1368             mDeleteIntent = intent;
   1369             return this;
   1370         }
   1371 
   1372         /**
   1373          * An intent to launch instead of posting the notification to the status bar.
   1374          * Only for use with extremely high-priority notifications demanding the user's
   1375          * <strong>immediate</strong> attention, such as an incoming phone call or
   1376          * alarm clock that the user has explicitly set to a particular time.
   1377          * If this facility is used for something else, please give the user an option
   1378          * to turn it off and use a normal notification, as this can be extremely
   1379          * disruptive.
   1380          *
   1381          * @param intent The pending intent to launch.
   1382          * @param highPriority Passing true will cause this notification to be sent
   1383          *          even if other notifications are suppressed.
   1384          *
   1385          * @see Notification#fullScreenIntent
   1386          */
   1387         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
   1388             mFullScreenIntent = intent;
   1389             setFlag(FLAG_HIGH_PRIORITY, highPriority);
   1390             return this;
   1391         }
   1392 
   1393         /**
   1394          * Set the "ticker" text which is displayed in the status bar when the notification first
   1395          * arrives.
   1396          *
   1397          * @see Notification#tickerText
   1398          */
   1399         public Builder setTicker(CharSequence tickerText) {
   1400             mTickerText = safeCharSequence(tickerText);
   1401             return this;
   1402         }
   1403 
   1404         /**
   1405          * Set the text that is displayed in the status bar when the notification first
   1406          * arrives, and also a RemoteViews object that may be displayed instead on some
   1407          * devices.
   1408          *
   1409          * @see Notification#tickerText
   1410          * @see Notification#tickerView
   1411          */
   1412         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
   1413             mTickerText = safeCharSequence(tickerText);
   1414             mTickerView = views;
   1415             return this;
   1416         }
   1417 
   1418         /**
   1419          * Add a large icon to the notification (and the ticker on some devices).
   1420          *
   1421          * In the platform template, this image will be shown on the left of the notification view
   1422          * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side).
   1423          *
   1424          * @see Notification#largeIcon
   1425          */
   1426         public Builder setLargeIcon(Bitmap icon) {
   1427             mLargeIcon = icon;
   1428             return this;
   1429         }
   1430 
   1431         /**
   1432          * Set the sound to play.
   1433          *
   1434          * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications.
   1435          *
   1436          * @see Notification#sound
   1437          */
   1438         public Builder setSound(Uri sound) {
   1439             mSound = sound;
   1440             mAudioStreamType = STREAM_DEFAULT;
   1441             return this;
   1442         }
   1443 
   1444         /**
   1445          * Set the sound to play, along with a specific stream on which to play it.
   1446          *
   1447          * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
   1448          *
   1449          * @see Notification#sound
   1450          */
   1451         public Builder setSound(Uri sound, int streamType) {
   1452             mSound = sound;
   1453             mAudioStreamType = streamType;
   1454             return this;
   1455         }
   1456 
   1457         /**
   1458          * Set the vibration pattern to use.
   1459          *
   1460 
   1461          * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
   1462          * <code>pattern</code> parameter.
   1463          *
   1464 
   1465          * @see Notification#vibrate
   1466          */
   1467         public Builder setVibrate(long[] pattern) {
   1468             mVibrate = pattern;
   1469             return this;
   1470         }
   1471 
   1472         /**
   1473          * Set the desired color for the indicator LED on the device, as well as the
   1474          * blink duty cycle (specified in milliseconds).
   1475          *
   1476 
   1477          * Not all devices will honor all (or even any) of these values.
   1478          *
   1479 
   1480          * @see Notification#ledARGB
   1481          * @see Notification#ledOnMS
   1482          * @see Notification#ledOffMS
   1483          */
   1484         public Builder setLights(int argb, int onMs, int offMs) {
   1485             mLedArgb = argb;
   1486             mLedOnMs = onMs;
   1487             mLedOffMs = offMs;
   1488             return this;
   1489         }
   1490 
   1491         /**
   1492          * Set whether this is an "ongoing" notification.
   1493          *
   1494 
   1495          * Ongoing notifications cannot be dismissed by the user, so your application or service
   1496          * must take care of canceling them.
   1497          *
   1498 
   1499          * They are typically used to indicate a background task that the user is actively engaged
   1500          * with (e.g., playing music) or is pending in some way and therefore occupying the device
   1501          * (e.g., a file download, sync operation, active network connection).
   1502          *
   1503 
   1504          * @see Notification#FLAG_ONGOING_EVENT
   1505          * @see Service#setForeground(boolean)
   1506          */
   1507         public Builder setOngoing(boolean ongoing) {
   1508             setFlag(FLAG_ONGOING_EVENT, ongoing);
   1509             return this;
   1510         }
   1511 
   1512         /**
   1513          * Set this flag if you would only like the sound, vibrate
   1514          * and ticker to be played if the notification is not already showing.
   1515          *
   1516          * @see Notification#FLAG_ONLY_ALERT_ONCE
   1517          */
   1518         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
   1519             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
   1520             return this;
   1521         }
   1522 
   1523         /**
   1524          * Make this notification automatically dismissed when the user touches it. The
   1525          * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
   1526          *
   1527          * @see Notification#FLAG_AUTO_CANCEL
   1528          */
   1529         public Builder setAutoCancel(boolean autoCancel) {
   1530             setFlag(FLAG_AUTO_CANCEL, autoCancel);
   1531             return this;
   1532         }
   1533 
   1534         /**
   1535          * Set which notification properties will be inherited from system defaults.
   1536          * <p>
   1537          * The value should be one or more of the following fields combined with
   1538          * bitwise-or:
   1539          * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
   1540          * <p>
   1541          * For all default values, use {@link #DEFAULT_ALL}.
   1542          */
   1543         public Builder setDefaults(int defaults) {
   1544             mDefaults = defaults;
   1545             return this;
   1546         }
   1547 
   1548         /**
   1549          * Set the priority of this notification.
   1550          *
   1551          * @see Notification#priority
   1552          */
   1553         public Builder setPriority(int pri) {
   1554             mPriority = pri;
   1555             return this;
   1556         }
   1557 
   1558         /**
   1559          * @hide
   1560          *
   1561          * Add a kind (category) to this notification. Optional.
   1562          *
   1563          * @see Notification#kind
   1564          */
   1565         public Builder addKind(String k) {
   1566             mKindList.add(k);
   1567             return this;
   1568         }
   1569 
   1570         /**
   1571          * Add metadata to this notification.
   1572          *
   1573          * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
   1574          * current contents are copied into the Notification each time {@link #build()} is
   1575          * called.
   1576          *
   1577          * @see Notification#extras
   1578          */
   1579         public Builder setExtras(Bundle bag) {
   1580             mExtras = bag;
   1581             return this;
   1582         }
   1583 
   1584         /**
   1585          * Add an action to this notification. Actions are typically displayed by
   1586          * the system as a button adjacent to the notification content.
   1587          * <p>
   1588          * Every action must have an icon (32dp square and matching the
   1589          * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
   1590          * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
   1591          * <p>
   1592          * A notification in its expanded form can display up to 3 actions, from left to right in
   1593          * the order they were added. Actions will not be displayed when the notification is
   1594          * collapsed, however, so be sure that any essential functions may be accessed by the user
   1595          * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
   1596          *
   1597          * @param icon Resource ID of a drawable that represents the action.
   1598          * @param title Text describing the action.
   1599          * @param intent PendingIntent to be fired when the action is invoked.
   1600          */
   1601         public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
   1602             mActions.add(new Action(icon, safeCharSequence(title), intent));
   1603             return this;
   1604         }
   1605 
   1606         /**
   1607          * Add a rich notification style to be applied at build time.
   1608          *
   1609          * @param style Object responsible for modifying the notification style.
   1610          */
   1611         public Builder setStyle(Style style) {
   1612             if (mStyle != style) {
   1613                 mStyle = style;
   1614                 if (mStyle != null) {
   1615                     mStyle.setBuilder(this);
   1616                 }
   1617             }
   1618             return this;
   1619         }
   1620 
   1621         private void setFlag(int mask, boolean value) {
   1622             if (value) {
   1623                 mFlags |= mask;
   1624             } else {
   1625                 mFlags &= ~mask;
   1626             }
   1627         }
   1628 
   1629         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
   1630             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
   1631             boolean showLine3 = false;
   1632             boolean showLine2 = false;
   1633             int smallIconImageViewId = R.id.icon;
   1634             if (mLargeIcon != null) {
   1635                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
   1636                 smallIconImageViewId = R.id.right_icon;
   1637             }
   1638             if (mPriority < PRIORITY_LOW) {
   1639                 contentView.setInt(R.id.icon,
   1640                         "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
   1641                 contentView.setInt(R.id.status_bar_latest_event_content,
   1642                         "setBackgroundResource", R.drawable.notification_bg_low);
   1643             }
   1644             if (mSmallIcon != 0) {
   1645                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
   1646                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
   1647             } else {
   1648                 contentView.setViewVisibility(smallIconImageViewId, View.GONE);
   1649             }
   1650             if (mContentTitle != null) {
   1651                 contentView.setTextViewText(R.id.title, mContentTitle);
   1652             }
   1653             if (mContentText != null) {
   1654                 contentView.setTextViewText(R.id.text, mContentText);
   1655                 showLine3 = true;
   1656             }
   1657             if (mContentInfo != null) {
   1658                 contentView.setTextViewText(R.id.info, mContentInfo);
   1659                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
   1660                 showLine3 = true;
   1661             } else if (mNumber > 0) {
   1662                 final int tooBig = mContext.getResources().getInteger(
   1663                         R.integer.status_bar_notification_info_maxnum);
   1664                 if (mNumber > tooBig) {
   1665                     contentView.setTextViewText(R.id.info, mContext.getResources().getString(
   1666                                 R.string.status_bar_notification_info_overflow));
   1667                 } else {
   1668                     NumberFormat f = NumberFormat.getIntegerInstance();
   1669                     contentView.setTextViewText(R.id.info, f.format(mNumber));
   1670                 }
   1671                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
   1672                 showLine3 = true;
   1673             } else {
   1674                 contentView.setViewVisibility(R.id.info, View.GONE);
   1675             }
   1676 
   1677             // Need to show three lines?
   1678             if (mSubText != null) {
   1679                 contentView.setTextViewText(R.id.text, mSubText);
   1680                 if (mContentText != null) {
   1681                     contentView.setTextViewText(R.id.text2, mContentText);
   1682                     contentView.setViewVisibility(R.id.text2, View.VISIBLE);
   1683                     showLine2 = true;
   1684                 } else {
   1685                     contentView.setViewVisibility(R.id.text2, View.GONE);
   1686                 }
   1687             } else {
   1688                 contentView.setViewVisibility(R.id.text2, View.GONE);
   1689                 if (mProgressMax != 0 || mProgressIndeterminate) {
   1690                     contentView.setProgressBar(
   1691                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
   1692                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
   1693                     showLine2 = true;
   1694                 } else {
   1695                     contentView.setViewVisibility(R.id.progress, View.GONE);
   1696                 }
   1697             }
   1698             if (showLine2) {
   1699                 if (fitIn1U) {
   1700                     // need to shrink all the type to make sure everything fits
   1701                     final Resources res = mContext.getResources();
   1702                     final float subTextSize = res.getDimensionPixelSize(
   1703                             R.dimen.notification_subtext_size);
   1704                     contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
   1705                 }
   1706                 // vertical centering
   1707                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
   1708             }
   1709 
   1710             if (mWhen != 0 && mShowWhen) {
   1711                 if (mUseChronometer) {
   1712                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
   1713                     contentView.setLong(R.id.chronometer, "setBase",
   1714                             mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
   1715                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
   1716                 } else {
   1717                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
   1718                     contentView.setLong(R.id.time, "setTime", mWhen);
   1719                 }
   1720             } else {
   1721                 contentView.setViewVisibility(R.id.time, View.GONE);
   1722             }
   1723 
   1724             contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
   1725             contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
   1726             return contentView;
   1727         }
   1728 
   1729         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
   1730             RemoteViews big = applyStandardTemplate(layoutId, false);
   1731 
   1732             int N = mActions.size();
   1733             if (N > 0) {
   1734                 // Log.d("Notification", "has actions: " + mContentText);
   1735                 big.setViewVisibility(R.id.actions, View.VISIBLE);
   1736                 big.setViewVisibility(R.id.action_divider, View.VISIBLE);
   1737                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
   1738                 big.removeAllViews(R.id.actions);
   1739                 for (int i=0; i<N; i++) {
   1740                     final RemoteViews button = generateActionButton(mActions.get(i));
   1741                     //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
   1742                     big.addView(R.id.actions, button);
   1743                 }
   1744             }
   1745             return big;
   1746         }
   1747 
   1748         private RemoteViews makeContentView() {
   1749             if (mContentView != null) {
   1750                 return mContentView;
   1751             } else {
   1752                 return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor
   1753             }
   1754         }
   1755 
   1756         private RemoteViews makeTickerView() {
   1757             if (mTickerView != null) {
   1758                 return mTickerView;
   1759             } else {
   1760                 if (mContentView == null) {
   1761                     return applyStandardTemplate(mLargeIcon == null
   1762                             ? R.layout.status_bar_latest_event_ticker
   1763                             : R.layout.status_bar_latest_event_ticker_large_icon, true);
   1764                 } else {
   1765                     return null;
   1766                 }
   1767             }
   1768         }
   1769 
   1770         private RemoteViews makeBigContentView() {
   1771             if (mActions.size() == 0) return null;
   1772 
   1773             return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
   1774         }
   1775 
   1776         private RemoteViews generateActionButton(Action action) {
   1777             final boolean tombstone = (action.actionIntent == null);
   1778             RemoteViews button = new RemoteViews(mContext.getPackageName(),
   1779                     tombstone ? R.layout.notification_action_tombstone
   1780                               : R.layout.notification_action);
   1781             button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
   1782             button.setTextViewText(R.id.action0, action.title);
   1783             if (!tombstone) {
   1784                 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
   1785             }
   1786             button.setContentDescription(R.id.action0, action.title);
   1787             return button;
   1788         }
   1789 
   1790         /**
   1791          * Apply the unstyled operations and return a new {@link Notification} object.
   1792          * @hide
   1793          */
   1794         public Notification buildUnstyled() {
   1795             Notification n = new Notification();
   1796             n.when = mWhen;
   1797             n.icon = mSmallIcon;
   1798             n.iconLevel = mSmallIconLevel;
   1799             n.number = mNumber;
   1800             n.contentView = makeContentView();
   1801             n.contentIntent = mContentIntent;
   1802             n.deleteIntent = mDeleteIntent;
   1803             n.fullScreenIntent = mFullScreenIntent;
   1804             n.tickerText = mTickerText;
   1805             n.tickerView = makeTickerView();
   1806             n.largeIcon = mLargeIcon;
   1807             n.sound = mSound;
   1808             n.audioStreamType = mAudioStreamType;
   1809             n.vibrate = mVibrate;
   1810             n.ledARGB = mLedArgb;
   1811             n.ledOnMS = mLedOnMs;
   1812             n.ledOffMS = mLedOffMs;
   1813             n.defaults = mDefaults;
   1814             n.flags = mFlags;
   1815             n.bigContentView = makeBigContentView();
   1816             if (mLedOnMs != 0 || mLedOffMs != 0) {
   1817                 n.flags |= FLAG_SHOW_LIGHTS;
   1818             }
   1819             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
   1820                 n.flags |= FLAG_SHOW_LIGHTS;
   1821             }
   1822             if (mKindList.size() > 0) {
   1823                 n.kind = new String[mKindList.size()];
   1824                 mKindList.toArray(n.kind);
   1825             } else {
   1826                 n.kind = null;
   1827             }
   1828             n.priority = mPriority;
   1829             if (mActions.size() > 0) {
   1830                 n.actions = new Action[mActions.size()];
   1831                 mActions.toArray(n.actions);
   1832             }
   1833 
   1834             return n;
   1835         }
   1836 
   1837         /**
   1838          * Capture, in the provided bundle, semantic information used in the construction of
   1839          * this Notification object.
   1840          * @hide
   1841          */
   1842         public void addExtras(Bundle extras) {
   1843             // Store original information used in the construction of this object
   1844             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
   1845             extras.putCharSequence(EXTRA_TEXT, mContentText);
   1846             extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
   1847             extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
   1848             extras.putInt(EXTRA_SMALL_ICON, mSmallIcon);
   1849             extras.putInt(EXTRA_PROGRESS, mProgress);
   1850             extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
   1851             extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
   1852             extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
   1853             extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
   1854             if (mLargeIcon != null) {
   1855                 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
   1856             }
   1857         }
   1858 
   1859         /**
   1860          * @deprecated Use {@link #build()} instead.
   1861          */
   1862         @Deprecated
   1863         public Notification getNotification() {
   1864             return build();
   1865         }
   1866 
   1867         /**
   1868          * Combine all of the options that have been set and return a new {@link Notification}
   1869          * object.
   1870          */
   1871         public Notification build() {
   1872             Notification n = buildUnstyled();
   1873 
   1874             if (mStyle != null) {
   1875                 n = mStyle.buildStyled(n);
   1876             }
   1877 
   1878             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
   1879 
   1880             addExtras(n.extras);
   1881             if (mStyle != null) {
   1882                 mStyle.addExtras(n.extras);
   1883             }
   1884 
   1885             return n;
   1886         }
   1887 
   1888         /**
   1889          * Apply this Builder to an existing {@link Notification} object.
   1890          *
   1891          * @hide
   1892          */
   1893         public Notification buildInto(Notification n) {
   1894             build().cloneInto(n, true);
   1895             return n;
   1896         }
   1897     }
   1898 
   1899     /**
   1900      * An object that can apply a rich notification style to a {@link Notification.Builder}
   1901      * object.
   1902      */
   1903     public static abstract class Style
   1904     {
   1905         private CharSequence mBigContentTitle;
   1906         private CharSequence mSummaryText = null;
   1907         private boolean mSummaryTextSet = false;
   1908 
   1909         protected Builder mBuilder;
   1910 
   1911         /**
   1912          * Overrides ContentTitle in the big form of the template.
   1913          * This defaults to the value passed to setContentTitle().
   1914          */
   1915         protected void internalSetBigContentTitle(CharSequence title) {
   1916             mBigContentTitle = title;
   1917         }
   1918 
   1919         /**
   1920          * Set the first line of text after the detail section in the big form of the template.
   1921          */
   1922         protected void internalSetSummaryText(CharSequence cs) {
   1923             mSummaryText = cs;
   1924             mSummaryTextSet = true;
   1925         }
   1926 
   1927         public void setBuilder(Builder builder) {
   1928             if (mBuilder != builder) {
   1929                 mBuilder = builder;
   1930                 if (mBuilder != null) {
   1931                     mBuilder.setStyle(this);
   1932                 }
   1933             }
   1934         }
   1935 
   1936         protected void checkBuilder() {
   1937             if (mBuilder == null) {
   1938                 throw new IllegalArgumentException("Style requires a valid Builder object");
   1939             }
   1940         }
   1941 
   1942         protected RemoteViews getStandardView(int layoutId) {
   1943             checkBuilder();
   1944 
   1945             if (mBigContentTitle != null) {
   1946                 mBuilder.setContentTitle(mBigContentTitle);
   1947             }
   1948 
   1949             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
   1950 
   1951             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
   1952                 contentView.setViewVisibility(R.id.line1, View.GONE);
   1953             } else {
   1954                 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
   1955             }
   1956 
   1957             // The last line defaults to the subtext, but can be replaced by mSummaryText
   1958             final CharSequence overflowText =
   1959                     mSummaryTextSet ? mSummaryText
   1960                                     : mBuilder.mSubText;
   1961             if (overflowText != null) {
   1962                 contentView.setTextViewText(R.id.text, overflowText);
   1963                 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
   1964                 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
   1965             } else {
   1966                 contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
   1967                 contentView.setViewVisibility(R.id.line3, View.GONE);
   1968             }
   1969 
   1970             return contentView;
   1971         }
   1972 
   1973         /**
   1974          * @hide
   1975          */
   1976         public void addExtras(Bundle extras) {
   1977             if (mSummaryTextSet) {
   1978                 extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText);
   1979             }
   1980             if (mBigContentTitle != null) {
   1981                 extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle);
   1982             }
   1983         }
   1984 
   1985         /**
   1986          * @hide
   1987          */
   1988         public abstract Notification buildStyled(Notification wip);
   1989 
   1990         /**
   1991          * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
   1992          * attached to.
   1993          *
   1994          * @return the fully constructed Notification.
   1995          */
   1996         public Notification build() {
   1997             checkBuilder();
   1998             return mBuilder.build();
   1999         }
   2000     }
   2001 
   2002     /**
   2003      * Helper class for generating large-format notifications that include a large image attachment.
   2004      *
   2005      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   2006      * <pre class="prettyprint">
   2007      * Notification noti = new Notification.BigPictureStyle(
   2008      *      new Notification.Builder()
   2009      *         .setContentTitle(&quot;New photo from &quot; + sender.toString())
   2010      *         .setContentText(subject)
   2011      *         .setSmallIcon(R.drawable.new_post)
   2012      *         .setLargeIcon(aBitmap))
   2013      *      .bigPicture(aBigBitmap)
   2014      *      .build();
   2015      * </pre>
   2016      *
   2017      * @see Notification#bigContentView
   2018      */
   2019     public static class BigPictureStyle extends Style {
   2020         private Bitmap mPicture;
   2021         private Bitmap mBigLargeIcon;
   2022         private boolean mBigLargeIconSet = false;
   2023 
   2024         public BigPictureStyle() {
   2025         }
   2026 
   2027         public BigPictureStyle(Builder builder) {
   2028             setBuilder(builder);
   2029         }
   2030 
   2031         /**
   2032          * Overrides ContentTitle in the big form of the template.
   2033          * This defaults to the value passed to setContentTitle().
   2034          */
   2035         public BigPictureStyle setBigContentTitle(CharSequence title) {
   2036             internalSetBigContentTitle(safeCharSequence(title));
   2037             return this;
   2038         }
   2039 
   2040         /**
   2041          * Set the first line of text after the detail section in the big form of the template.
   2042          */
   2043         public BigPictureStyle setSummaryText(CharSequence cs) {
   2044             internalSetSummaryText(safeCharSequence(cs));
   2045             return this;
   2046         }
   2047 
   2048         /**
   2049          * Provide the bitmap to be used as the payload for the BigPicture notification.
   2050          */
   2051         public BigPictureStyle bigPicture(Bitmap b) {
   2052             mPicture = b;
   2053             return this;
   2054         }
   2055 
   2056         /**
   2057          * Override the large icon when the big notification is shown.
   2058          */
   2059         public BigPictureStyle bigLargeIcon(Bitmap b) {
   2060             mBigLargeIconSet = true;
   2061             mBigLargeIcon = b;
   2062             return this;
   2063         }
   2064 
   2065         private RemoteViews makeBigContentView() {
   2066             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
   2067 
   2068             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
   2069 
   2070             return contentView;
   2071         }
   2072 
   2073         /**
   2074          * @hide
   2075          */
   2076         public void addExtras(Bundle extras) {
   2077             super.addExtras(extras);
   2078 
   2079             if (mBigLargeIconSet) {
   2080                 extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
   2081             }
   2082             extras.putParcelable(EXTRA_PICTURE, mPicture);
   2083         }
   2084 
   2085         /**
   2086          * @hide
   2087          */
   2088         @Override
   2089         public Notification buildStyled(Notification wip) {
   2090             if (mBigLargeIconSet ) {
   2091                 mBuilder.mLargeIcon = mBigLargeIcon;
   2092             }
   2093             wip.bigContentView = makeBigContentView();
   2094             return wip;
   2095         }
   2096     }
   2097 
   2098     /**
   2099      * Helper class for generating large-format notifications that include a lot of text.
   2100      *
   2101      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   2102      * <pre class="prettyprint">
   2103      * Notification noti = new Notification.BigTextStyle(
   2104      *      new Notification.Builder()
   2105      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
   2106      *         .setContentText(subject)
   2107      *         .setSmallIcon(R.drawable.new_mail)
   2108      *         .setLargeIcon(aBitmap))
   2109      *      .bigText(aVeryLongString)
   2110      *      .build();
   2111      * </pre>
   2112      *
   2113      * @see Notification#bigContentView
   2114      */
   2115     public static class BigTextStyle extends Style {
   2116         private CharSequence mBigText;
   2117 
   2118         public BigTextStyle() {
   2119         }
   2120 
   2121         public BigTextStyle(Builder builder) {
   2122             setBuilder(builder);
   2123         }
   2124 
   2125         /**
   2126          * Overrides ContentTitle in the big form of the template.
   2127          * This defaults to the value passed to setContentTitle().
   2128          */
   2129         public BigTextStyle setBigContentTitle(CharSequence title) {
   2130             internalSetBigContentTitle(safeCharSequence(title));
   2131             return this;
   2132         }
   2133 
   2134         /**
   2135          * Set the first line of text after the detail section in the big form of the template.
   2136          */
   2137         public BigTextStyle setSummaryText(CharSequence cs) {
   2138             internalSetSummaryText(safeCharSequence(cs));
   2139             return this;
   2140         }
   2141 
   2142         /**
   2143          * Provide the longer text to be displayed in the big form of the
   2144          * template in place of the content text.
   2145          */
   2146         public BigTextStyle bigText(CharSequence cs) {
   2147             mBigText = safeCharSequence(cs);
   2148             return this;
   2149         }
   2150 
   2151         /**
   2152          * @hide
   2153          */
   2154         public void addExtras(Bundle extras) {
   2155             super.addExtras(extras);
   2156 
   2157             extras.putCharSequence(EXTRA_TEXT, mBigText);
   2158         }
   2159 
   2160         private RemoteViews makeBigContentView() {
   2161             // Remove the content text so line3 only shows if you have a summary
   2162             final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
   2163             mBuilder.mContentText = null;
   2164 
   2165             RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
   2166 
   2167             if (hadThreeLines) {
   2168                 // vertical centering
   2169                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
   2170             }
   2171 
   2172             contentView.setTextViewText(R.id.big_text, mBigText);
   2173             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
   2174             contentView.setViewVisibility(R.id.text2, View.GONE);
   2175 
   2176             return contentView;
   2177         }
   2178 
   2179         /**
   2180          * @hide
   2181          */
   2182         @Override
   2183         public Notification buildStyled(Notification wip) {
   2184             wip.bigContentView = makeBigContentView();
   2185 
   2186             wip.extras.putCharSequence(EXTRA_TEXT, mBigText);
   2187 
   2188             return wip;
   2189         }
   2190     }
   2191 
   2192     /**
   2193      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
   2194      *
   2195      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   2196      * <pre class="prettyprint">
   2197      * Notification noti = new Notification.InboxStyle(
   2198      *      new Notification.Builder()
   2199      *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
   2200      *         .setContentText(subject)
   2201      *         .setSmallIcon(R.drawable.new_mail)
   2202      *         .setLargeIcon(aBitmap))
   2203      *      .addLine(str1)
   2204      *      .addLine(str2)
   2205      *      .setContentTitle("")
   2206      *      .setSummaryText(&quot;+3 more&quot;)
   2207      *      .build();
   2208      * </pre>
   2209      *
   2210      * @see Notification#bigContentView
   2211      */
   2212     public static class InboxStyle extends Style {
   2213         private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
   2214 
   2215         public InboxStyle() {
   2216         }
   2217 
   2218         public InboxStyle(Builder builder) {
   2219             setBuilder(builder);
   2220         }
   2221 
   2222         /**
   2223          * Overrides ContentTitle in the big form of the template.
   2224          * This defaults to the value passed to setContentTitle().
   2225          */
   2226         public InboxStyle setBigContentTitle(CharSequence title) {
   2227             internalSetBigContentTitle(safeCharSequence(title));
   2228             return this;
   2229         }
   2230 
   2231         /**
   2232          * Set the first line of text after the detail section in the big form of the template.
   2233          */
   2234         public InboxStyle setSummaryText(CharSequence cs) {
   2235             internalSetSummaryText(safeCharSequence(cs));
   2236             return this;
   2237         }
   2238 
   2239         /**
   2240          * Append a line to the digest section of the Inbox notification.
   2241          */
   2242         public InboxStyle addLine(CharSequence cs) {
   2243             mTexts.add(safeCharSequence(cs));
   2244             return this;
   2245         }
   2246 
   2247         /**
   2248          * @hide
   2249          */
   2250         public void addExtras(Bundle extras) {
   2251             super.addExtras(extras);
   2252             CharSequence[] a = new CharSequence[mTexts.size()];
   2253             extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a));
   2254         }
   2255 
   2256         private RemoteViews makeBigContentView() {
   2257             // Remove the content text so line3 disappears unless you have a summary
   2258             mBuilder.mContentText = null;
   2259             RemoteViews contentView = getStandardView(R.layout.notification_template_inbox);
   2260 
   2261             contentView.setViewVisibility(R.id.text2, View.GONE);
   2262 
   2263             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
   2264                     R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
   2265 
   2266             // Make sure all rows are gone in case we reuse a view.
   2267             for (int rowId : rowIds) {
   2268                 contentView.setViewVisibility(rowId, View.GONE);
   2269             }
   2270 
   2271 
   2272             int i=0;
   2273             while (i < mTexts.size() && i < rowIds.length) {
   2274                 CharSequence str = mTexts.get(i);
   2275                 if (str != null && !str.equals("")) {
   2276                     contentView.setViewVisibility(rowIds[i], View.VISIBLE);
   2277                     contentView.setTextViewText(rowIds[i], str);
   2278                 }
   2279                 i++;
   2280             }
   2281 
   2282             contentView.setViewVisibility(R.id.inbox_end_pad,
   2283                     mTexts.size() > 0 ? View.VISIBLE : View.GONE);
   2284 
   2285             contentView.setViewVisibility(R.id.inbox_more,
   2286                     mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE);
   2287 
   2288             return contentView;
   2289         }
   2290 
   2291         /**
   2292          * @hide
   2293          */
   2294         @Override
   2295         public Notification buildStyled(Notification wip) {
   2296             wip.bigContentView = makeBigContentView();
   2297 
   2298             return wip;
   2299         }
   2300     }
   2301 }
   2302