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