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.
    901      *
    902      * Example:
    903      *
    904      * <pre class="prettyprint">
    905      * Notification noti = new Notification.Builder()
    906      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
    907      *         .setContentText(subject)
    908      *         .setSmallIcon(R.drawable.new_mail)
    909      *         .setLargeIcon(aBitmap)
    910      *         .build();
    911      * </pre>
    912      */
    913     public static class Builder {
    914         private static final int MAX_ACTION_BUTTONS = 3;
    915 
    916         private Context mContext;
    917 
    918         private long mWhen;
    919         private int mSmallIcon;
    920         private int mSmallIconLevel;
    921         private int mNumber;
    922         private CharSequence mContentTitle;
    923         private CharSequence mContentText;
    924         private CharSequence mContentInfo;
    925         private CharSequence mSubText;
    926         private PendingIntent mContentIntent;
    927         private RemoteViews mContentView;
    928         private PendingIntent mDeleteIntent;
    929         private PendingIntent mFullScreenIntent;
    930         private CharSequence mTickerText;
    931         private RemoteViews mTickerView;
    932         private Bitmap mLargeIcon;
    933         private Uri mSound;
    934         private int mAudioStreamType;
    935         private long[] mVibrate;
    936         private int mLedArgb;
    937         private int mLedOnMs;
    938         private int mLedOffMs;
    939         private int mDefaults;
    940         private int mFlags;
    941         private int mProgressMax;
    942         private int mProgress;
    943         private boolean mProgressIndeterminate;
    944         private ArrayList<String> mKindList = new ArrayList<String>(1);
    945         private Bundle mExtras;
    946         private int mPriority;
    947         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
    948         private boolean mUseChronometer;
    949         private Style mStyle;
    950 
    951         /**
    952          * Constructs a new Builder with the defaults:
    953          *
    954 
    955          * <table>
    956          * <tr><th align=right>priority</th>
    957          *     <td>{@link #PRIORITY_DEFAULT}</td></tr>
    958          * <tr><th align=right>when</th>
    959          *     <td>now ({@link System#currentTimeMillis()})</td></tr>
    960          * <tr><th align=right>audio stream</th>
    961          *     <td>{@link #STREAM_DEFAULT}</td></tr>
    962          * </table>
    963          *
    964 
    965          * @param context
    966          *            A {@link Context} that will be used by the Builder to construct the
    967          *            RemoteViews. The Context will not be held past the lifetime of this Builder
    968          *            object.
    969          */
    970         public Builder(Context context) {
    971             mContext = context;
    972 
    973             // Set defaults to match the defaults of a Notification
    974             mWhen = System.currentTimeMillis();
    975             mAudioStreamType = STREAM_DEFAULT;
    976             mPriority = PRIORITY_DEFAULT;
    977         }
    978 
    979         /**
    980          * Add a timestamp pertaining to the notification (usually the time the event occurred).
    981          *
    982 
    983          * @see Notification#when
    984          */
    985         public Builder setWhen(long when) {
    986             mWhen = when;
    987             return this;
    988         }
    989 
    990         /**
    991          * Show the {@link Notification#when} field as a stopwatch.
    992          *
    993          * Instead of presenting <code>when</code> as a timestamp, the notification will show an
    994          * automatically updating display of the minutes and seconds since <code>when</code>.
    995          *
    996          * Useful when showing an elapsed time (like an ongoing phone call).
    997          *
    998          * @see android.widget.Chronometer
    999          * @see Notification#when
   1000          */
   1001         public Builder setUsesChronometer(boolean b) {
   1002             mUseChronometer = b;
   1003             return this;
   1004         }
   1005 
   1006         /**
   1007          * Set the small icon resource, which will be used to represent the notification in the
   1008          * status bar.
   1009          *
   1010 
   1011          * The platform template for the expanded view will draw this icon in the left, unless a
   1012          * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small
   1013          * icon will be moved to the right-hand side.
   1014          *
   1015 
   1016          * @param icon
   1017          *            A resource ID in the application's package of the drawable to use.
   1018          * @see Notification#icon
   1019          */
   1020         public Builder setSmallIcon(int icon) {
   1021             mSmallIcon = icon;
   1022             return this;
   1023         }
   1024 
   1025         /**
   1026          * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional
   1027          * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable
   1028          * LevelListDrawable}.
   1029          *
   1030          * @param icon A resource ID in the application's package of the drawable to use.
   1031          * @param level The level to use for the icon.
   1032          *
   1033          * @see Notification#icon
   1034          * @see Notification#iconLevel
   1035          */
   1036         public Builder setSmallIcon(int icon, int level) {
   1037             mSmallIcon = icon;
   1038             mSmallIconLevel = level;
   1039             return this;
   1040         }
   1041 
   1042         /**
   1043          * Set the first line of text in the platform notification template.
   1044          */
   1045         public Builder setContentTitle(CharSequence title) {
   1046             mContentTitle = title;
   1047             return this;
   1048         }
   1049 
   1050         /**
   1051          * Set the second line of text in the platform notification template.
   1052          */
   1053         public Builder setContentText(CharSequence text) {
   1054             mContentText = text;
   1055             return this;
   1056         }
   1057 
   1058         /**
   1059          * Set the third line of text in the platform notification template.
   1060          * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the same location in the standard template.
   1061          */
   1062         public Builder setSubText(CharSequence text) {
   1063             mSubText = text;
   1064             return this;
   1065         }
   1066 
   1067         /**
   1068          * Set the large number at the right-hand side of the notification.  This is
   1069          * equivalent to setContentInfo, although it might show the number in a different
   1070          * font size for readability.
   1071          */
   1072         public Builder setNumber(int number) {
   1073             mNumber = number;
   1074             return this;
   1075         }
   1076 
   1077         /**
   1078          * A small piece of additional information pertaining to this notification.
   1079          *
   1080          * The platform template will draw this on the last line of the notification, at the far
   1081          * right (to the right of a smallIcon if it has been placed there).
   1082          */
   1083         public Builder setContentInfo(CharSequence info) {
   1084             mContentInfo = info;
   1085             return this;
   1086         }
   1087 
   1088         /**
   1089          * Set the progress this notification represents.
   1090          *
   1091          * The platform template will represent this using a {@link ProgressBar}.
   1092          */
   1093         public Builder setProgress(int max, int progress, boolean indeterminate) {
   1094             mProgressMax = max;
   1095             mProgress = progress;
   1096             mProgressIndeterminate = indeterminate;
   1097             return this;
   1098         }
   1099 
   1100         /**
   1101          * Supply a custom RemoteViews to use instead of the platform template.
   1102          *
   1103          * @see Notification#contentView
   1104          */
   1105         public Builder setContent(RemoteViews views) {
   1106             mContentView = views;
   1107             return this;
   1108         }
   1109 
   1110         /**
   1111          * Supply a {@link PendingIntent} to be sent when the notification is clicked.
   1112          *
   1113          * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you
   1114          * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use
   1115          * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)}
   1116          * to assign PendingIntents to individual views in that custom layout (i.e., to create
   1117          * clickable buttons inside the notification view).
   1118          *
   1119          * @see Notification#contentIntent Notification.contentIntent
   1120          */
   1121         public Builder setContentIntent(PendingIntent intent) {
   1122             mContentIntent = intent;
   1123             return this;
   1124         }
   1125 
   1126         /**
   1127          * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user.
   1128          *
   1129          * @see Notification#deleteIntent
   1130          */
   1131         public Builder setDeleteIntent(PendingIntent intent) {
   1132             mDeleteIntent = intent;
   1133             return this;
   1134         }
   1135 
   1136         /**
   1137          * An intent to launch instead of posting the notification to the status bar.
   1138          * Only for use with extremely high-priority notifications demanding the user's
   1139          * <strong>immediate</strong> attention, such as an incoming phone call or
   1140          * alarm clock that the user has explicitly set to a particular time.
   1141          * If this facility is used for something else, please give the user an option
   1142          * to turn it off and use a normal notification, as this can be extremely
   1143          * disruptive.
   1144          *
   1145          * @param intent The pending intent to launch.
   1146          * @param highPriority Passing true will cause this notification to be sent
   1147          *          even if other notifications are suppressed.
   1148          *
   1149          * @see Notification#fullScreenIntent
   1150          */
   1151         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
   1152             mFullScreenIntent = intent;
   1153             setFlag(FLAG_HIGH_PRIORITY, highPriority);
   1154             return this;
   1155         }
   1156 
   1157         /**
   1158          * Set the "ticker" text which is displayed in the status bar when the notification first
   1159          * arrives.
   1160          *
   1161          * @see Notification#tickerText
   1162          */
   1163         public Builder setTicker(CharSequence tickerText) {
   1164             mTickerText = tickerText;
   1165             return this;
   1166         }
   1167 
   1168         /**
   1169          * Set the text that is displayed in the status bar when the notification first
   1170          * arrives, and also a RemoteViews object that may be displayed instead on some
   1171          * devices.
   1172          *
   1173          * @see Notification#tickerText
   1174          * @see Notification#tickerView
   1175          */
   1176         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
   1177             mTickerText = tickerText;
   1178             mTickerView = views;
   1179             return this;
   1180         }
   1181 
   1182         /**
   1183          * Add a large icon to the notification (and the ticker on some devices).
   1184          *
   1185          * In the platform template, this image will be shown on the left of the notification view
   1186          * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side).
   1187          *
   1188          * @see Notification#largeIcon
   1189          */
   1190         public Builder setLargeIcon(Bitmap icon) {
   1191             mLargeIcon = icon;
   1192             return this;
   1193         }
   1194 
   1195         /**
   1196          * Set the sound to play.
   1197          *
   1198          * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications.
   1199          *
   1200          * @see Notification#sound
   1201          */
   1202         public Builder setSound(Uri sound) {
   1203             mSound = sound;
   1204             mAudioStreamType = STREAM_DEFAULT;
   1205             return this;
   1206         }
   1207 
   1208         /**
   1209          * Set the sound to play, along with a specific stream on which to play it.
   1210          *
   1211          * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants.
   1212          *
   1213          * @see Notification#sound
   1214          */
   1215         public Builder setSound(Uri sound, int streamType) {
   1216             mSound = sound;
   1217             mAudioStreamType = streamType;
   1218             return this;
   1219         }
   1220 
   1221         /**
   1222          * Set the vibration pattern to use.
   1223          *
   1224 
   1225          * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the
   1226          * <code>pattern</code> parameter.
   1227          *
   1228 
   1229          * @see Notification#vibrate
   1230          */
   1231         public Builder setVibrate(long[] pattern) {
   1232             mVibrate = pattern;
   1233             return this;
   1234         }
   1235 
   1236         /**
   1237          * Set the desired color for the indicator LED on the device, as well as the
   1238          * blink duty cycle (specified in milliseconds).
   1239          *
   1240 
   1241          * Not all devices will honor all (or even any) of these values.
   1242          *
   1243 
   1244          * @see Notification#ledARGB
   1245          * @see Notification#ledOnMS
   1246          * @see Notification#ledOffMS
   1247          */
   1248         public Builder setLights(int argb, int onMs, int offMs) {
   1249             mLedArgb = argb;
   1250             mLedOnMs = onMs;
   1251             mLedOffMs = offMs;
   1252             return this;
   1253         }
   1254 
   1255         /**
   1256          * Set whether this is an "ongoing" notification.
   1257          *
   1258 
   1259          * Ongoing notifications cannot be dismissed by the user, so your application or service
   1260          * must take care of canceling them.
   1261          *
   1262 
   1263          * They are typically used to indicate a background task that the user is actively engaged
   1264          * with (e.g., playing music) or is pending in some way and therefore occupying the device
   1265          * (e.g., a file download, sync operation, active network connection).
   1266          *
   1267 
   1268          * @see Notification#FLAG_ONGOING_EVENT
   1269          * @see Service#setForeground(boolean)
   1270          */
   1271         public Builder setOngoing(boolean ongoing) {
   1272             setFlag(FLAG_ONGOING_EVENT, ongoing);
   1273             return this;
   1274         }
   1275 
   1276         /**
   1277          * Set this flag if you would only like the sound, vibrate
   1278          * and ticker to be played if the notification is not already showing.
   1279          *
   1280          * @see Notification#FLAG_ONLY_ALERT_ONCE
   1281          */
   1282         public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
   1283             setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
   1284             return this;
   1285         }
   1286 
   1287         /**
   1288          * Make this notification automatically dismissed when the user touches it. The
   1289          * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens.
   1290          *
   1291          * @see Notification#FLAG_AUTO_CANCEL
   1292          */
   1293         public Builder setAutoCancel(boolean autoCancel) {
   1294             setFlag(FLAG_AUTO_CANCEL, autoCancel);
   1295             return this;
   1296         }
   1297 
   1298         /**
   1299          * Set which notification properties will be inherited from system defaults.
   1300          * <p>
   1301          * The value should be one or more of the following fields combined with
   1302          * bitwise-or:
   1303          * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}.
   1304          * <p>
   1305          * For all default values, use {@link #DEFAULT_ALL}.
   1306          */
   1307         public Builder setDefaults(int defaults) {
   1308             mDefaults = defaults;
   1309             return this;
   1310         }
   1311 
   1312         /**
   1313          * Set the priority of this notification.
   1314          *
   1315          * @see Notification#priority
   1316          */
   1317         public Builder setPriority(int pri) {
   1318             mPriority = pri;
   1319             return this;
   1320         }
   1321 
   1322         /**
   1323          * @hide
   1324          *
   1325          * Add a kind (category) to this notification. Optional.
   1326          *
   1327          * @see Notification#kind
   1328          */
   1329         public Builder addKind(String k) {
   1330             mKindList.add(k);
   1331             return this;
   1332         }
   1333 
   1334         /**
   1335          * Add metadata to this notification.
   1336          *
   1337          * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
   1338          * current contents are copied into the Notification each time {@link #build()} is
   1339          * called.
   1340          *
   1341          * @see Notification#extras
   1342          * @hide
   1343          */
   1344         public Builder setExtras(Bundle bag) {
   1345             mExtras = bag;
   1346             return this;
   1347         }
   1348 
   1349         /**
   1350          * Add an action to this notification. Actions are typically displayed by
   1351          * the system as a button adjacent to the notification content.
   1352          *
   1353          * @param icon Resource ID of a drawable that represents the action.
   1354          * @param title Text describing the action.
   1355          * @param intent PendingIntent to be fired when the action is invoked.
   1356          */
   1357         public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
   1358             mActions.add(new Action(icon, title, intent));
   1359             return this;
   1360         }
   1361 
   1362         /**
   1363          * Add a rich notification style to be applied at build time.
   1364          *
   1365          * @param style Object responsible for modifying the notification style.
   1366          */
   1367         public Builder setStyle(Style style) {
   1368             if (mStyle != style) {
   1369                 mStyle = style;
   1370                 if (mStyle != null) {
   1371                     mStyle.setBuilder(this);
   1372                 }
   1373             }
   1374             return this;
   1375         }
   1376 
   1377         private void setFlag(int mask, boolean value) {
   1378             if (value) {
   1379                 mFlags |= mask;
   1380             } else {
   1381                 mFlags &= ~mask;
   1382             }
   1383         }
   1384 
   1385         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
   1386             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
   1387             boolean showLine3 = false;
   1388             boolean showLine2 = false;
   1389             int smallIconImageViewId = R.id.icon;
   1390             if (mLargeIcon != null) {
   1391                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
   1392                 smallIconImageViewId = R.id.right_icon;
   1393             }
   1394             if (mPriority < PRIORITY_LOW) {
   1395                 contentView.setInt(R.id.icon,
   1396                         "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
   1397                 contentView.setInt(R.id.status_bar_latest_event_content,
   1398                         "setBackgroundResource", R.drawable.notification_bg_low);
   1399             }
   1400             if (mSmallIcon != 0) {
   1401                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
   1402                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
   1403             } else {
   1404                 contentView.setViewVisibility(smallIconImageViewId, View.GONE);
   1405             }
   1406             if (mContentTitle != null) {
   1407                 contentView.setTextViewText(R.id.title, mContentTitle);
   1408             }
   1409             if (mContentText != null) {
   1410                 contentView.setTextViewText(R.id.text, mContentText);
   1411                 showLine3 = true;
   1412             }
   1413             if (mContentInfo != null) {
   1414                 contentView.setTextViewText(R.id.info, mContentInfo);
   1415                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
   1416                 showLine3 = true;
   1417             } else if (mNumber > 0) {
   1418                 final int tooBig = mContext.getResources().getInteger(
   1419                         R.integer.status_bar_notification_info_maxnum);
   1420                 if (mNumber > tooBig) {
   1421                     contentView.setTextViewText(R.id.info, mContext.getResources().getString(
   1422                                 R.string.status_bar_notification_info_overflow));
   1423                 } else {
   1424                     NumberFormat f = NumberFormat.getIntegerInstance();
   1425                     contentView.setTextViewText(R.id.info, f.format(mNumber));
   1426                 }
   1427                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
   1428                 showLine3 = true;
   1429             } else {
   1430                 contentView.setViewVisibility(R.id.info, View.GONE);
   1431             }
   1432 
   1433             // Need to show three lines?
   1434             if (mSubText != null) {
   1435                 contentView.setTextViewText(R.id.text, mSubText);
   1436                 if (mContentText != null) {
   1437                     contentView.setTextViewText(R.id.text2, mContentText);
   1438                     contentView.setViewVisibility(R.id.text2, View.VISIBLE);
   1439                     showLine2 = true;
   1440                 } else {
   1441                     contentView.setViewVisibility(R.id.text2, View.GONE);
   1442                 }
   1443             } else {
   1444                 contentView.setViewVisibility(R.id.text2, View.GONE);
   1445                 if (mProgressMax != 0 || mProgressIndeterminate) {
   1446                     contentView.setProgressBar(
   1447                             R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
   1448                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
   1449                     showLine2 = true;
   1450                 } else {
   1451                     contentView.setViewVisibility(R.id.progress, View.GONE);
   1452                 }
   1453             }
   1454             if (showLine2) {
   1455                 if (fitIn1U) {
   1456                     // need to shrink all the type to make sure everything fits
   1457                     final Resources res = mContext.getResources();
   1458                     final float subTextSize = res.getDimensionPixelSize(
   1459                             R.dimen.notification_subtext_size);
   1460                     contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize);
   1461                 }
   1462                 // vertical centering
   1463                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
   1464             }
   1465 
   1466             if (mWhen != 0) {
   1467                 if (mUseChronometer) {
   1468                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
   1469                     contentView.setLong(R.id.chronometer, "setBase",
   1470                             mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
   1471                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
   1472                 } else {
   1473                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
   1474                     contentView.setLong(R.id.time, "setTime", mWhen);
   1475                 }
   1476             }
   1477             contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
   1478             contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
   1479             return contentView;
   1480         }
   1481 
   1482         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
   1483             RemoteViews big = applyStandardTemplate(layoutId, false);
   1484 
   1485             int N = mActions.size();
   1486             if (N > 0) {
   1487                 // Log.d("Notification", "has actions: " + mContentText);
   1488                 big.setViewVisibility(R.id.actions, View.VISIBLE);
   1489                 big.setViewVisibility(R.id.action_divider, View.VISIBLE);
   1490                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
   1491                 big.removeAllViews(R.id.actions);
   1492                 for (int i=0; i<N; i++) {
   1493                     final RemoteViews button = generateActionButton(mActions.get(i));
   1494                     //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title);
   1495                     big.addView(R.id.actions, button);
   1496                 }
   1497             }
   1498             return big;
   1499         }
   1500 
   1501         private RemoteViews makeContentView() {
   1502             if (mContentView != null) {
   1503                 return mContentView;
   1504             } else {
   1505                 return applyStandardTemplate(R.layout.notification_template_base, true); // no more special large_icon flavor
   1506             }
   1507         }
   1508 
   1509         private RemoteViews makeTickerView() {
   1510             if (mTickerView != null) {
   1511                 return mTickerView;
   1512             } else {
   1513                 if (mContentView == null) {
   1514                     return applyStandardTemplate(mLargeIcon == null
   1515                             ? R.layout.status_bar_latest_event_ticker
   1516                             : R.layout.status_bar_latest_event_ticker_large_icon, true);
   1517                 } else {
   1518                     return null;
   1519                 }
   1520             }
   1521         }
   1522 
   1523         private RemoteViews makeBigContentView() {
   1524             if (mActions.size() == 0) return null;
   1525 
   1526             return applyStandardTemplateWithActions(R.layout.notification_template_big_base);
   1527         }
   1528 
   1529         private RemoteViews generateActionButton(Action action) {
   1530             final boolean tombstone = (action.actionIntent == null);
   1531             RemoteViews button = new RemoteViews(mContext.getPackageName(),
   1532                     tombstone ? R.layout.notification_action_tombstone
   1533                               : R.layout.notification_action);
   1534             button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0);
   1535             button.setTextViewText(R.id.action0, action.title);
   1536             if (!tombstone) {
   1537                 button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
   1538             }
   1539             button.setContentDescription(R.id.action0, action.title);
   1540             return button;
   1541         }
   1542 
   1543         /**
   1544          * Apply the unstyled operations and return a new {@link Notification} object.
   1545          */
   1546         private Notification buildUnstyled() {
   1547             Notification n = new Notification();
   1548             n.when = mWhen;
   1549             n.icon = mSmallIcon;
   1550             n.iconLevel = mSmallIconLevel;
   1551             n.number = mNumber;
   1552             n.contentView = makeContentView();
   1553             n.contentIntent = mContentIntent;
   1554             n.deleteIntent = mDeleteIntent;
   1555             n.fullScreenIntent = mFullScreenIntent;
   1556             n.tickerText = mTickerText;
   1557             n.tickerView = makeTickerView();
   1558             n.largeIcon = mLargeIcon;
   1559             n.sound = mSound;
   1560             n.audioStreamType = mAudioStreamType;
   1561             n.vibrate = mVibrate;
   1562             n.ledARGB = mLedArgb;
   1563             n.ledOnMS = mLedOnMs;
   1564             n.ledOffMS = mLedOffMs;
   1565             n.defaults = mDefaults;
   1566             n.flags = mFlags;
   1567             n.bigContentView = makeBigContentView();
   1568             if (mLedOnMs != 0 && mLedOffMs != 0) {
   1569                 n.flags |= FLAG_SHOW_LIGHTS;
   1570             }
   1571             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
   1572                 n.flags |= FLAG_SHOW_LIGHTS;
   1573             }
   1574             if (mKindList.size() > 0) {
   1575                 n.kind = new String[mKindList.size()];
   1576                 mKindList.toArray(n.kind);
   1577             } else {
   1578                 n.kind = null;
   1579             }
   1580             n.priority = mPriority;
   1581             n.extras = mExtras != null ? new Bundle(mExtras) : null;
   1582             if (mActions.size() > 0) {
   1583                 n.actions = new Action[mActions.size()];
   1584                 mActions.toArray(n.actions);
   1585             }
   1586             return n;
   1587         }
   1588 
   1589         /**
   1590          * @deprecated Use {@link #build()} instead.
   1591          */
   1592         @Deprecated
   1593         public Notification getNotification() {
   1594             return build();
   1595         }
   1596 
   1597         /**
   1598          * Combine all of the options that have been set and return a new {@link Notification}
   1599          * object.
   1600          */
   1601         public Notification build() {
   1602             if (mStyle != null) {
   1603                 return mStyle.build();
   1604             } else {
   1605                 return buildUnstyled();
   1606             }
   1607         }
   1608     }
   1609 
   1610 
   1611     /**
   1612      * An object that can apply a rich notification style to a {@link Notification.Builder}
   1613      * object.
   1614      */
   1615     public static abstract class Style
   1616     {
   1617         private CharSequence mBigContentTitle;
   1618         private CharSequence mSummaryText = null;
   1619         private boolean mSummaryTextSet = false;
   1620 
   1621         protected Builder mBuilder;
   1622 
   1623         /**
   1624          * Overrides ContentTitle in the big form of the template.
   1625          * This defaults to the value passed to setContentTitle().
   1626          */
   1627         protected void internalSetBigContentTitle(CharSequence title) {
   1628             mBigContentTitle = title;
   1629         }
   1630 
   1631         /**
   1632          * Set the first line of text after the detail section in the big form of the template.
   1633          */
   1634         protected void internalSetSummaryText(CharSequence cs) {
   1635             mSummaryText = cs;
   1636             mSummaryTextSet = true;
   1637         }
   1638 
   1639         public void setBuilder(Builder builder) {
   1640             if (mBuilder != builder) {
   1641                 mBuilder = builder;
   1642                 if (mBuilder != null) {
   1643                     mBuilder.setStyle(this);
   1644                 }
   1645             }
   1646         }
   1647 
   1648         protected void checkBuilder() {
   1649             if (mBuilder == null) {
   1650                 throw new IllegalArgumentException("Style requires a valid Builder object");
   1651             }
   1652         }
   1653 
   1654         protected RemoteViews getStandardView(int layoutId) {
   1655             checkBuilder();
   1656 
   1657             if (mBigContentTitle != null) {
   1658                 mBuilder.setContentTitle(mBigContentTitle);
   1659             }
   1660 
   1661             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
   1662 
   1663             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
   1664                 contentView.setViewVisibility(R.id.line1, View.GONE);
   1665             } else {
   1666                 contentView.setViewVisibility(R.id.line1, View.VISIBLE);
   1667             }
   1668 
   1669             // The last line defaults to the subtext, but can be replaced by mSummaryText
   1670             final CharSequence overflowText =
   1671                     mSummaryTextSet ? mSummaryText
   1672                                     : mBuilder.mSubText;
   1673             if (overflowText != null) {
   1674                 contentView.setTextViewText(R.id.text, overflowText);
   1675                 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
   1676                 contentView.setViewVisibility(R.id.line3, View.VISIBLE);
   1677             } else {
   1678                 contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
   1679                 contentView.setViewVisibility(R.id.line3, View.GONE);
   1680             }
   1681 
   1682             return contentView;
   1683         }
   1684 
   1685         public abstract Notification build();
   1686     }
   1687 
   1688     /**
   1689      * Helper class for generating large-format notifications that include a large image attachment.
   1690      *
   1691      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   1692      * <pre class="prettyprint">
   1693      * Notification noti = new Notification.BigPictureStyle(
   1694      *      new Notification.Builder()
   1695      *         .setContentTitle(&quot;New photo from &quot; + sender.toString())
   1696      *         .setContentText(subject)
   1697      *         .setSmallIcon(R.drawable.new_post)
   1698      *         .setLargeIcon(aBitmap))
   1699      *      .bigPicture(aBigBitmap)
   1700      *      .build();
   1701      * </pre>
   1702      *
   1703      * @see Notification#bigContentView
   1704      */
   1705     public static class BigPictureStyle extends Style {
   1706         private Bitmap mPicture;
   1707         private Bitmap mBigLargeIcon;
   1708         private boolean mBigLargeIconSet = false;
   1709 
   1710         public BigPictureStyle() {
   1711         }
   1712 
   1713         public BigPictureStyle(Builder builder) {
   1714             setBuilder(builder);
   1715         }
   1716 
   1717         /**
   1718          * Overrides ContentTitle in the big form of the template.
   1719          * This defaults to the value passed to setContentTitle().
   1720          */
   1721         public BigPictureStyle setBigContentTitle(CharSequence title) {
   1722             internalSetBigContentTitle(title);
   1723             return this;
   1724         }
   1725 
   1726         /**
   1727          * Set the first line of text after the detail section in the big form of the template.
   1728          */
   1729         public BigPictureStyle setSummaryText(CharSequence cs) {
   1730             internalSetSummaryText(cs);
   1731             return this;
   1732         }
   1733 
   1734         public BigPictureStyle bigPicture(Bitmap b) {
   1735             mPicture = b;
   1736             return this;
   1737         }
   1738 
   1739         /**
   1740          * Override the large icon when the big notification is shown.
   1741          */
   1742         public BigPictureStyle bigLargeIcon(Bitmap b) {
   1743             mBigLargeIconSet = true;
   1744             mBigLargeIcon = b;
   1745             return this;
   1746         }
   1747 
   1748         private RemoteViews makeBigContentView() {
   1749             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
   1750 
   1751             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
   1752 
   1753             return contentView;
   1754         }
   1755 
   1756         @Override
   1757         public Notification build() {
   1758             checkBuilder();
   1759             Notification wip = mBuilder.buildUnstyled();
   1760             if (mBigLargeIconSet ) {
   1761                 mBuilder.mLargeIcon = mBigLargeIcon;
   1762             }
   1763             wip.bigContentView = makeBigContentView();
   1764             return wip;
   1765         }
   1766     }
   1767 
   1768     /**
   1769      * Helper class for generating large-format notifications that include a lot of text.
   1770      *
   1771      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   1772      * <pre class="prettyprint">
   1773      * Notification noti = new Notification.BigPictureStyle(
   1774      *      new Notification.Builder()
   1775      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
   1776      *         .setContentText(subject)
   1777      *         .setSmallIcon(R.drawable.new_mail)
   1778      *         .setLargeIcon(aBitmap))
   1779      *      .bigText(aVeryLongString)
   1780      *      .build();
   1781      * </pre>
   1782      *
   1783      * @see Notification#bigContentView
   1784      */
   1785     public static class BigTextStyle extends Style {
   1786         private CharSequence mBigText;
   1787 
   1788         public BigTextStyle() {
   1789         }
   1790 
   1791         public BigTextStyle(Builder builder) {
   1792             setBuilder(builder);
   1793         }
   1794 
   1795         /**
   1796          * Overrides ContentTitle in the big form of the template.
   1797          * This defaults to the value passed to setContentTitle().
   1798          */
   1799         public BigTextStyle setBigContentTitle(CharSequence title) {
   1800             internalSetBigContentTitle(title);
   1801             return this;
   1802         }
   1803 
   1804         /**
   1805          * Set the first line of text after the detail section in the big form of the template.
   1806          */
   1807         public BigTextStyle setSummaryText(CharSequence cs) {
   1808             internalSetSummaryText(cs);
   1809             return this;
   1810         }
   1811 
   1812         public BigTextStyle bigText(CharSequence cs) {
   1813             mBigText = cs;
   1814             return this;
   1815         }
   1816 
   1817         private RemoteViews makeBigContentView() {
   1818             // Remove the content text so line3 only shows if you have a summary
   1819             final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null);
   1820             mBuilder.mContentText = null;
   1821 
   1822             RemoteViews contentView = getStandardView(R.layout.notification_template_big_text);
   1823 
   1824             if (hadThreeLines) {
   1825                 // vertical centering
   1826                 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0);
   1827             }
   1828 
   1829             contentView.setTextViewText(R.id.big_text, mBigText);
   1830             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
   1831             contentView.setViewVisibility(R.id.text2, View.GONE);
   1832 
   1833             return contentView;
   1834         }
   1835 
   1836         @Override
   1837         public Notification build() {
   1838             checkBuilder();
   1839             Notification wip = mBuilder.buildUnstyled();
   1840             wip.bigContentView = makeBigContentView();
   1841             return wip;
   1842         }
   1843     }
   1844 
   1845     /**
   1846      * Helper class for generating large-format notifications that include a list of (up to 5) strings.
   1847      *
   1848      * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
   1849      * <pre class="prettyprint">
   1850      * Notification noti = new Notification.InboxStyle(
   1851      *      new Notification.Builder()
   1852      *         .setContentTitle(&quot;5 New mails from &quot; + sender.toString())
   1853      *         .setContentText(subject)
   1854      *         .setSmallIcon(R.drawable.new_mail)
   1855      *         .setLargeIcon(aBitmap))
   1856      *      .addLine(str1)
   1857      *      .addLine(str2)
   1858      *      .setContentTitle("")
   1859      *      .setSummaryText(&quot;+3 more&quot;)
   1860      *      .build();
   1861      * </pre>
   1862      *
   1863      * @see Notification#bigContentView
   1864      */
   1865     public static class InboxStyle extends Style {
   1866         private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
   1867 
   1868         public InboxStyle() {
   1869         }
   1870 
   1871         public InboxStyle(Builder builder) {
   1872             setBuilder(builder);
   1873         }
   1874 
   1875         /**
   1876          * Overrides ContentTitle in the big form of the template.
   1877          * This defaults to the value passed to setContentTitle().
   1878          */
   1879         public InboxStyle setBigContentTitle(CharSequence title) {
   1880             internalSetBigContentTitle(title);
   1881             return this;
   1882         }
   1883 
   1884         /**
   1885          * Set the first line of text after the detail section in the big form of the template.
   1886          */
   1887         public InboxStyle setSummaryText(CharSequence cs) {
   1888             internalSetSummaryText(cs);
   1889             return this;
   1890         }
   1891 
   1892         public InboxStyle addLine(CharSequence cs) {
   1893             mTexts.add(cs);
   1894             return this;
   1895         }
   1896 
   1897         private RemoteViews makeBigContentView() {
   1898             // Remove the content text so line3 disappears unless you have a summary
   1899             mBuilder.mContentText = null;
   1900             RemoteViews contentView = getStandardView(R.layout.notification_template_inbox);
   1901 
   1902             contentView.setViewVisibility(R.id.text2, View.GONE);
   1903 
   1904             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
   1905                     R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
   1906 
   1907             // Make sure all rows are gone in case we reuse a view.
   1908             for (int rowId : rowIds) {
   1909                 contentView.setViewVisibility(rowId, View.GONE);
   1910             }
   1911 
   1912             int i=0;
   1913             while (i < mTexts.size() && i < rowIds.length) {
   1914                 CharSequence str = mTexts.get(i);
   1915                 if (str != null && !str.equals("")) {
   1916                     contentView.setViewVisibility(rowIds[i], View.VISIBLE);
   1917                     contentView.setTextViewText(rowIds[i], str);
   1918                 }
   1919                 i++;
   1920             }
   1921 
   1922             if  (mTexts.size() > rowIds.length) {
   1923                 contentView.setViewVisibility(R.id.inbox_more, View.VISIBLE);
   1924             } else {
   1925                 contentView.setViewVisibility(R.id.inbox_more, View.GONE);
   1926             }
   1927 
   1928             return contentView;
   1929         }
   1930 
   1931         @Override
   1932         public Notification build() {
   1933             checkBuilder();
   1934             Notification wip = mBuilder.buildUnstyled();
   1935             wip.bigContentView = makeBigContentView();
   1936             return wip;
   1937         }
   1938     }
   1939 }
   1940