Notification.java revision e46cbd379a3c19708c7f7e5d3f35e2c596de0c46
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
17package android.app;
18
19import java.util.Date;
20
21import android.app.PendingIntent;
22import android.content.Context;
23import android.content.Intent;
24import android.media.AudioManager;
25import android.net.Uri;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.text.TextUtils;
29import android.text.format.DateFormat;
30import android.text.format.DateUtils;
31import android.widget.RemoteViews;
32
33/**
34 * A class that represents how a persistent notification is to be presented to
35 * the user using the {@link android.app.NotificationManager}.
36 *
37 * <p>For a guide to creating notifications, see the
38 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status
39 * Bar Notifications</a> document in the Dev Guide.</p>
40 */
41public class Notification implements Parcelable
42{
43    /**
44     * Use all default values (where applicable).
45     */
46    public static final int DEFAULT_ALL = ~0;
47
48    /**
49     * Use the default notification sound. This will ignore any given
50     * {@link #sound}.
51     *
52     * @see #defaults
53     */
54    public static final int DEFAULT_SOUND = 1;
55
56    /**
57     * Use the default notification vibrate. This will ignore any given
58     * {@link #vibrate}. Using phone vibration requires the
59     * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
60     *
61     * @see #defaults
62     */
63    public static final int DEFAULT_VIBRATE = 2;
64
65    /**
66     * Use the default notification lights. This will ignore the
67     * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
68     * {@link #ledOnMS}.
69     *
70     * @see #defaults
71     */
72    public static final int DEFAULT_LIGHTS = 4;
73
74    /**
75     * The timestamp for the notification.  The icons and expanded views
76     * are sorted by this key.
77     */
78    public long when;
79
80    /**
81     * The resource id of a drawable to use as the icon in the status bar.
82     */
83    public int icon;
84
85    /**
86     * The number of events that this notification represents.  For example, in a new mail
87     * notification, this could be the number of unread messages.  This number is superimposed over
88     * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status
89     * bar.
90     */
91    public int number;
92
93    /**
94     * The intent to execute when the expanded status entry is clicked.  If
95     * this is an activity, it must include the
96     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
97     * that you take care of task management as described in the <em>Activities and Tasks</em>
98     * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application
99     * Fundamentals</a> document.
100     */
101    public PendingIntent contentIntent;
102
103    /**
104     * The intent to execute when the status entry is deleted by the user
105     * with the "Clear All Notifications" button. This probably shouldn't
106     * be launching an activity since several of those will be sent at the
107     * same time.
108     */
109    public PendingIntent deleteIntent;
110
111    /**
112     * An intent to launch instead of posting the notification to the status bar. Only for use with
113     * extremely high-priority notifications demanding the user's attention, such as an incoming
114     * call (handled in the core Android Phone app with a full-screen Activity).
115     * Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification will reach the user
116     * even when other notifications are suppressed.
117     */
118    public PendingIntent fullScreenIntent;
119
120    /**
121     * Text to scroll across the screen when this item is added to
122     * the status bar.
123     */
124    public CharSequence tickerText;
125
126    /**
127     * The view that will represent this notification in the expanded status bar.
128     */
129    public RemoteViews contentView;
130
131    /**
132     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
133     * leave it at its default value of 0.
134     *
135     * @see android.widget.ImageView#setImageLevel
136     * @see android.graphics.drawable#setLevel
137     */
138    public int iconLevel;
139
140    /**
141     * The sound to play.
142     *
143     * <p>
144     * To play the default notification sound, see {@link #defaults}.
145     * </p>
146     */
147    public Uri sound;
148
149    /**
150     * Use this constant as the value for audioStreamType to request that
151     * the default stream type for notifications be used.  Currently the
152     * default stream type is STREAM_RING.
153     */
154    public static final int STREAM_DEFAULT = -1;
155
156    /**
157     * The audio stream type to use when playing the sound.
158     * Should be one of the STREAM_ constants from
159     * {@link android.media.AudioManager}.
160     */
161    public int audioStreamType = STREAM_DEFAULT;
162
163
164    /**
165     * The pattern with which to vibrate.
166     *
167     * <p>
168     * To vibrate the default pattern, see {@link #defaults}.
169     * </p>
170     *
171     * @see android.os.Vibrator#vibrate(long[],int)
172     */
173    public long[] vibrate;
174
175    /**
176     * The color of the led.  The hardware will do its best approximation.
177     *
178     * @see #FLAG_SHOW_LIGHTS
179     * @see #flags
180     */
181    public int ledARGB;
182
183    /**
184     * The number of milliseconds for the LED to be on while it's flashing.
185     * The hardware will do its best approximation.
186     *
187     * @see #FLAG_SHOW_LIGHTS
188     * @see #flags
189     */
190    public int ledOnMS;
191
192    /**
193     * The number of milliseconds for the LED to be off while it's flashing.
194     * The hardware will do its best approximation.
195     *
196     * @see #FLAG_SHOW_LIGHTS
197     * @see #flags
198     */
199    public int ledOffMS;
200
201    /**
202     * Specifies which values should be taken from the defaults.
203     * <p>
204     * To set, OR the desired from {@link #DEFAULT_SOUND},
205     * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
206     * values, use {@link #DEFAULT_ALL}.
207     * </p>
208     */
209    public int defaults;
210
211
212    /**
213     * Bit to be bitwise-ored into the {@link #flags} field that should be
214     * set if you want the LED on for this notification.
215     * <ul>
216     * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
217     *      or 0 for both ledOnMS and ledOffMS.</li>
218     * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
219     * <li>To flash the LED, pass the number of milliseconds that it should
220     *      be on and off to ledOnMS and ledOffMS.</li>
221     * </ul>
222     * <p>
223     * Since hardware varies, you are not guaranteed that any of the values
224     * you pass are honored exactly.  Use the system defaults (TODO) if possible
225     * because they will be set to values that work on any given hardware.
226     * <p>
227     * The alpha channel must be set for forward compatibility.
228     *
229     */
230    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
231
232    /**
233     * Bit to be bitwise-ored into the {@link #flags} field that should be
234     * set if this notification is in reference to something that is ongoing,
235     * like a phone call.  It should not be set if this notification is in
236     * reference to something that happened at a particular point in time,
237     * like a missed phone call.
238     */
239    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
240
241    /**
242     * Bit to be bitwise-ored into the {@link #flags} field that if set,
243     * the audio will be repeated until the notification is
244     * cancelled or the notification window is opened.
245     */
246    public static final int FLAG_INSISTENT          = 0x00000004;
247
248    /**
249     * Bit to be bitwise-ored into the {@link #flags} field that should be
250     * set if you want the sound and/or vibration play each time the
251     * notification is sent, even if it has not been canceled before that.
252     */
253    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
254
255    /**
256     * Bit to be bitwise-ored into the {@link #flags} field that should be
257     * set if the notification should be canceled when it is clicked by the
258     * user.
259     */
260    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
261
262    /**
263     * Bit to be bitwise-ored into the {@link #flags} field that should be
264     * set if the notification should not be canceled when the user clicks
265     * the Clear all button.
266     */
267    public static final int FLAG_NO_CLEAR           = 0x00000020;
268
269    /**
270     * Bit to be bitwise-ored into the {@link #flags} field that should be
271     * set if this notification represents a currently running service.  This
272     * will normally be set for you by {@link Service#startForeground}.
273     */
274    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
275
276    /**
277     * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification
278     * represents a high-priority event that may be shown to the user even if notifications are
279     * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used
280     * in conjunction with {@link #fullScreenIntent}.
281     */
282    public static final int FLAG_HIGH_PRIORITY = 0x00000080;
283
284    public int flags;
285
286    /**
287     * Constructs a Notification object with everything set to 0.
288     */
289    public Notification()
290    {
291        this.when = System.currentTimeMillis();
292    }
293
294    /**
295     * @deprecated use {@link #Notification(int,CharSequence,long)} and {@link #setLatestEventInfo}.
296     * @hide
297     */
298    public Notification(Context context, int icon, CharSequence tickerText, long when,
299            CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
300    {
301        this.when = when;
302        this.icon = icon;
303        this.tickerText = tickerText;
304        setLatestEventInfo(context, contentTitle, contentText,
305                PendingIntent.getActivity(context, 0, contentIntent, 0));
306    }
307
308    /**
309     * Constructs a Notification object with the information needed to
310     * have a status bar icon without the standard expanded view.
311     *
312     * @param icon          The resource id of the icon to put in the status bar.
313     * @param tickerText    The text that flows by in the status bar when the notification first
314     *                      activates.
315     * @param when          The time to show in the time field.  In the System.currentTimeMillis
316     *                      timebase.
317     */
318    public Notification(int icon, CharSequence tickerText, long when)
319    {
320        this.icon = icon;
321        this.tickerText = tickerText;
322        this.when = when;
323    }
324
325    /**
326     * Unflatten the notification from a parcel.
327     */
328    public Notification(Parcel parcel)
329    {
330        int version = parcel.readInt();
331
332        when = parcel.readLong();
333        icon = parcel.readInt();
334        number = parcel.readInt();
335        if (parcel.readInt() != 0) {
336            contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
337        }
338        if (parcel.readInt() != 0) {
339            deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
340        }
341        if (parcel.readInt() != 0) {
342            tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
343        }
344        if (parcel.readInt() != 0) {
345            contentView = RemoteViews.CREATOR.createFromParcel(parcel);
346        }
347        defaults = parcel.readInt();
348        flags = parcel.readInt();
349        if (parcel.readInt() != 0) {
350            sound = Uri.CREATOR.createFromParcel(parcel);
351        }
352
353        audioStreamType = parcel.readInt();
354        vibrate = parcel.createLongArray();
355        ledARGB = parcel.readInt();
356        ledOnMS = parcel.readInt();
357        ledOffMS = parcel.readInt();
358        iconLevel = parcel.readInt();
359
360        if (parcel.readInt() != 0) {
361            fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
362        }
363    }
364
365    public Notification clone() {
366        Notification that = new Notification();
367
368        that.when = this.when;
369        that.icon = this.icon;
370        that.number = this.number;
371
372        // PendingIntents are global, so there's no reason (or way) to clone them.
373        that.contentIntent = this.contentIntent;
374        that.deleteIntent = this.deleteIntent;
375        that.fullScreenIntent = this.fullScreenIntent;
376
377        if (this.tickerText != null) {
378            that.tickerText = this.tickerText.toString();
379        }
380        if (this.contentView != null) {
381            that.contentView = this.contentView.clone();
382        }
383        that.iconLevel = that.iconLevel;
384        that.sound = this.sound; // android.net.Uri is immutable
385        that.audioStreamType = this.audioStreamType;
386
387        final long[] vibrate = this.vibrate;
388        if (vibrate != null) {
389            final int N = vibrate.length;
390            final long[] vib = that.vibrate = new long[N];
391            System.arraycopy(vibrate, 0, vib, 0, N);
392        }
393
394        that.ledARGB = this.ledARGB;
395        that.ledOnMS = this.ledOnMS;
396        that.ledOffMS = this.ledOffMS;
397        that.defaults = this.defaults;
398
399        that.flags = this.flags;
400
401        return that;
402    }
403
404    public int describeContents() {
405        return 0;
406    }
407
408    /**
409     * Flatten this notification from a parcel.
410     */
411    public void writeToParcel(Parcel parcel, int flags)
412    {
413        parcel.writeInt(1);
414
415        parcel.writeLong(when);
416        parcel.writeInt(icon);
417        parcel.writeInt(number);
418        if (contentIntent != null) {
419            parcel.writeInt(1);
420            contentIntent.writeToParcel(parcel, 0);
421        } else {
422            parcel.writeInt(0);
423        }
424        if (deleteIntent != null) {
425            parcel.writeInt(1);
426            deleteIntent.writeToParcel(parcel, 0);
427        } else {
428            parcel.writeInt(0);
429        }
430        if (tickerText != null) {
431            parcel.writeInt(1);
432            TextUtils.writeToParcel(tickerText, parcel, flags);
433        } else {
434            parcel.writeInt(0);
435        }
436        if (contentView != null) {
437            parcel.writeInt(1);
438            contentView.writeToParcel(parcel, 0);
439        } else {
440            parcel.writeInt(0);
441        }
442
443        parcel.writeInt(defaults);
444        parcel.writeInt(this.flags);
445
446        if (sound != null) {
447            parcel.writeInt(1);
448            sound.writeToParcel(parcel, 0);
449        } else {
450            parcel.writeInt(0);
451        }
452        parcel.writeInt(audioStreamType);
453        parcel.writeLongArray(vibrate);
454        parcel.writeInt(ledARGB);
455        parcel.writeInt(ledOnMS);
456        parcel.writeInt(ledOffMS);
457        parcel.writeInt(iconLevel);
458
459        if (fullScreenIntent != null) {
460            parcel.writeInt(1);
461            fullScreenIntent.writeToParcel(parcel, 0);
462        } else {
463            parcel.writeInt(0);
464        }
465    }
466
467    /**
468     * Parcelable.Creator that instantiates Notification objects
469     */
470    public static final Parcelable.Creator<Notification> CREATOR
471            = new Parcelable.Creator<Notification>()
472    {
473        public Notification createFromParcel(Parcel parcel)
474        {
475            return new Notification(parcel);
476        }
477
478        public Notification[] newArray(int size)
479        {
480            return new Notification[size];
481        }
482    };
483
484    /**
485     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
486     * layout.
487     *
488     * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
489     * in the view.</p>
490     * @param context       The context for your application / activity.
491     * @param contentTitle The title that goes in the expanded entry.
492     * @param contentText  The text that goes in the expanded entry.
493     * @param contentIntent The intent to launch when the user clicks the expanded notification.
494     * If this is an activity, it must include the
495     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
496     * that you take care of task management as described in
497     * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
498     */
499    public void setLatestEventInfo(Context context,
500            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
501        RemoteViews contentView = new RemoteViews(context.getPackageName(),
502                com.android.internal.R.layout.status_bar_latest_event_content);
503        if (this.icon != 0) {
504            contentView.setImageViewResource(com.android.internal.R.id.icon, this.icon);
505        }
506        if (contentTitle != null) {
507            contentView.setTextViewText(com.android.internal.R.id.title, contentTitle);
508        }
509        if (contentText != null) {
510            contentView.setTextViewText(com.android.internal.R.id.text, contentText);
511        }
512        if (this.when != 0) {
513            contentView.setLong(com.android.internal.R.id.time, "setTime", when);
514        }
515
516        this.contentView = contentView;
517        this.contentIntent = contentIntent;
518    }
519
520    @Override
521    public String toString() {
522        StringBuilder sb = new StringBuilder();
523        sb.append("Notification(vibrate=");
524        if (this.vibrate != null) {
525            int N = this.vibrate.length-1;
526            sb.append("[");
527            for (int i=0; i<N; i++) {
528                sb.append(this.vibrate[i]);
529                sb.append(',');
530            }
531            if (N != -1) {
532                sb.append(this.vibrate[N]);
533            }
534            sb.append("]");
535        } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
536            sb.append("default");
537        } else {
538            sb.append("null");
539        }
540        sb.append(",sound=");
541        if (this.sound != null) {
542            sb.append(this.sound.toString());
543        } else if ((this.defaults & DEFAULT_SOUND) != 0) {
544            sb.append("default");
545        } else {
546            sb.append("null");
547        }
548        sb.append(",defaults=0x");
549        sb.append(Integer.toHexString(this.defaults));
550        sb.append(",flags=0x");
551        sb.append(Integer.toHexString(this.flags));
552        if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
553            sb.append("!!!1!one!");
554        }
555        sb.append(")");
556        return sb.toString();
557    }
558}
559