Notification.java revision 392fea53ece4c874997df33cfe564925a3736f35
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.
113     * Only for use with extremely high-priority notifications demanding the user's
114     * <strong>immediate</strong> attention, such as an incoming phone call or
115     * alarm clock that the user has explicitly set to a particular time.
116     * If this facility is used for something else, please give the user an option
117     * to turn it off and use a normal notification, as this can be extremely
118     * disruptive.
119     */
120    public PendingIntent fullScreenIntent;
121
122    /**
123     * Text to scroll across the screen when this item is added to
124     * the status bar.
125     */
126    public CharSequence tickerText;
127
128    /**
129     * The view that will represent this notification in the expanded status bar.
130     */
131    public RemoteViews contentView;
132
133    /**
134     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
135     * leave it at its default value of 0.
136     *
137     * @see android.widget.ImageView#setImageLevel
138     * @see android.graphics.drawable#setLevel
139     */
140    public int iconLevel;
141
142    /**
143     * The sound to play.
144     *
145     * <p>
146     * To play the default notification sound, see {@link #defaults}.
147     * </p>
148     */
149    public Uri sound;
150
151    /**
152     * Use this constant as the value for audioStreamType to request that
153     * the default stream type for notifications be used.  Currently the
154     * default stream type is STREAM_RING.
155     */
156    public static final int STREAM_DEFAULT = -1;
157
158    /**
159     * The audio stream type to use when playing the sound.
160     * Should be one of the STREAM_ constants from
161     * {@link android.media.AudioManager}.
162     */
163    public int audioStreamType = STREAM_DEFAULT;
164
165
166    /**
167     * The pattern with which to vibrate.
168     *
169     * <p>
170     * To vibrate the default pattern, see {@link #defaults}.
171     * </p>
172     *
173     * @see android.os.Vibrator#vibrate(long[],int)
174     */
175    public long[] vibrate;
176
177    /**
178     * The color of the led.  The hardware will do its best approximation.
179     *
180     * @see #FLAG_SHOW_LIGHTS
181     * @see #flags
182     */
183    public int ledARGB;
184
185    /**
186     * The number of milliseconds for the LED to be on while it's flashing.
187     * The hardware will do its best approximation.
188     *
189     * @see #FLAG_SHOW_LIGHTS
190     * @see #flags
191     */
192    public int ledOnMS;
193
194    /**
195     * The number of milliseconds for the LED to be off while it's flashing.
196     * The hardware will do its best approximation.
197     *
198     * @see #FLAG_SHOW_LIGHTS
199     * @see #flags
200     */
201    public int ledOffMS;
202
203    /**
204     * Specifies which values should be taken from the defaults.
205     * <p>
206     * To set, OR the desired from {@link #DEFAULT_SOUND},
207     * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
208     * values, use {@link #DEFAULT_ALL}.
209     * </p>
210     */
211    public int defaults;
212
213
214    /**
215     * Bit to be bitwise-ored into the {@link #flags} field that should be
216     * set if you want the LED on for this notification.
217     * <ul>
218     * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
219     *      or 0 for both ledOnMS and ledOffMS.</li>
220     * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
221     * <li>To flash the LED, pass the number of milliseconds that it should
222     *      be on and off to ledOnMS and ledOffMS.</li>
223     * </ul>
224     * <p>
225     * Since hardware varies, you are not guaranteed that any of the values
226     * you pass are honored exactly.  Use the system defaults (TODO) if possible
227     * because they will be set to values that work on any given hardware.
228     * <p>
229     * The alpha channel must be set for forward compatibility.
230     *
231     */
232    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
233
234    /**
235     * Bit to be bitwise-ored into the {@link #flags} field that should be
236     * set if this notification is in reference to something that is ongoing,
237     * like a phone call.  It should not be set if this notification is in
238     * reference to something that happened at a particular point in time,
239     * like a missed phone call.
240     */
241    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
242
243    /**
244     * Bit to be bitwise-ored into the {@link #flags} field that if set,
245     * the audio will be repeated until the notification is
246     * cancelled or the notification window is opened.
247     */
248    public static final int FLAG_INSISTENT          = 0x00000004;
249
250    /**
251     * Bit to be bitwise-ored into the {@link #flags} field that should be
252     * set if you want the sound and/or vibration play each time the
253     * notification is sent, even if it has not been canceled before that.
254     */
255    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
256
257    /**
258     * Bit to be bitwise-ored into the {@link #flags} field that should be
259     * set if the notification should be canceled when it is clicked by the
260     * user.
261     */
262    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
263
264    /**
265     * Bit to be bitwise-ored into the {@link #flags} field that should be
266     * set if the notification should not be canceled when the user clicks
267     * the Clear all button.
268     */
269    public static final int FLAG_NO_CLEAR           = 0x00000020;
270
271    /**
272     * Bit to be bitwise-ored into the {@link #flags} field that should be
273     * set if this notification represents a currently running service.  This
274     * will normally be set for you by {@link Service#startForeground}.
275     */
276    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
277
278    public int flags;
279
280    /**
281     * Constructs a Notification object with everything set to 0.
282     */
283    public Notification()
284    {
285        this.when = System.currentTimeMillis();
286    }
287
288    /**
289     * @deprecated use {@link #Notification(int,CharSequence,long)} and {@link #setLatestEventInfo}.
290     * @hide
291     */
292    public Notification(Context context, int icon, CharSequence tickerText, long when,
293            CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
294    {
295        this.when = when;
296        this.icon = icon;
297        this.tickerText = tickerText;
298        setLatestEventInfo(context, contentTitle, contentText,
299                PendingIntent.getActivity(context, 0, contentIntent, 0));
300    }
301
302    /**
303     * Constructs a Notification object with the information needed to
304     * have a status bar icon without the standard expanded view.
305     *
306     * @param icon          The resource id of the icon to put in the status bar.
307     * @param tickerText    The text that flows by in the status bar when the notification first
308     *                      activates.
309     * @param when          The time to show in the time field.  In the System.currentTimeMillis
310     *                      timebase.
311     */
312    public Notification(int icon, CharSequence tickerText, long when)
313    {
314        this.icon = icon;
315        this.tickerText = tickerText;
316        this.when = when;
317    }
318
319    /**
320     * Unflatten the notification from a parcel.
321     */
322    public Notification(Parcel parcel)
323    {
324        int version = parcel.readInt();
325
326        when = parcel.readLong();
327        icon = parcel.readInt();
328        number = parcel.readInt();
329        if (parcel.readInt() != 0) {
330            contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
331        }
332        if (parcel.readInt() != 0) {
333            deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
334        }
335        if (parcel.readInt() != 0) {
336            tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
337        }
338        if (parcel.readInt() != 0) {
339            contentView = RemoteViews.CREATOR.createFromParcel(parcel);
340        }
341        defaults = parcel.readInt();
342        flags = parcel.readInt();
343        if (parcel.readInt() != 0) {
344            sound = Uri.CREATOR.createFromParcel(parcel);
345        }
346
347        audioStreamType = parcel.readInt();
348        vibrate = parcel.createLongArray();
349        ledARGB = parcel.readInt();
350        ledOnMS = parcel.readInt();
351        ledOffMS = parcel.readInt();
352        iconLevel = parcel.readInt();
353
354        if (parcel.readInt() != 0) {
355            fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
356        }
357    }
358
359    public Notification clone() {
360        Notification that = new Notification();
361
362        that.when = this.when;
363        that.icon = this.icon;
364        that.number = this.number;
365
366        // PendingIntents are global, so there's no reason (or way) to clone them.
367        that.contentIntent = this.contentIntent;
368        that.deleteIntent = this.deleteIntent;
369        that.fullScreenIntent = this.fullScreenIntent;
370
371        if (this.tickerText != null) {
372            that.tickerText = this.tickerText.toString();
373        }
374        if (this.contentView != null) {
375            that.contentView = this.contentView.clone();
376        }
377        that.iconLevel = that.iconLevel;
378        that.sound = this.sound; // android.net.Uri is immutable
379        that.audioStreamType = this.audioStreamType;
380
381        final long[] vibrate = this.vibrate;
382        if (vibrate != null) {
383            final int N = vibrate.length;
384            final long[] vib = that.vibrate = new long[N];
385            System.arraycopy(vibrate, 0, vib, 0, N);
386        }
387
388        that.ledARGB = this.ledARGB;
389        that.ledOnMS = this.ledOnMS;
390        that.ledOffMS = this.ledOffMS;
391        that.defaults = this.defaults;
392
393        that.flags = this.flags;
394
395        return that;
396    }
397
398    public int describeContents() {
399        return 0;
400    }
401
402    /**
403     * Flatten this notification from a parcel.
404     */
405    public void writeToParcel(Parcel parcel, int flags)
406    {
407        parcel.writeInt(1);
408
409        parcel.writeLong(when);
410        parcel.writeInt(icon);
411        parcel.writeInt(number);
412        if (contentIntent != null) {
413            parcel.writeInt(1);
414            contentIntent.writeToParcel(parcel, 0);
415        } else {
416            parcel.writeInt(0);
417        }
418        if (deleteIntent != null) {
419            parcel.writeInt(1);
420            deleteIntent.writeToParcel(parcel, 0);
421        } else {
422            parcel.writeInt(0);
423        }
424        if (tickerText != null) {
425            parcel.writeInt(1);
426            TextUtils.writeToParcel(tickerText, parcel, flags);
427        } else {
428            parcel.writeInt(0);
429        }
430        if (contentView != null) {
431            parcel.writeInt(1);
432            contentView.writeToParcel(parcel, 0);
433        } else {
434            parcel.writeInt(0);
435        }
436
437        parcel.writeInt(defaults);
438        parcel.writeInt(this.flags);
439
440        if (sound != null) {
441            parcel.writeInt(1);
442            sound.writeToParcel(parcel, 0);
443        } else {
444            parcel.writeInt(0);
445        }
446        parcel.writeInt(audioStreamType);
447        parcel.writeLongArray(vibrate);
448        parcel.writeInt(ledARGB);
449        parcel.writeInt(ledOnMS);
450        parcel.writeInt(ledOffMS);
451        parcel.writeInt(iconLevel);
452
453        if (fullScreenIntent != null) {
454            parcel.writeInt(1);
455            fullScreenIntent.writeToParcel(parcel, 0);
456        } else {
457            parcel.writeInt(0);
458        }
459    }
460
461    /**
462     * Parcelable.Creator that instantiates Notification objects
463     */
464    public static final Parcelable.Creator<Notification> CREATOR
465            = new Parcelable.Creator<Notification>()
466    {
467        public Notification createFromParcel(Parcel parcel)
468        {
469            return new Notification(parcel);
470        }
471
472        public Notification[] newArray(int size)
473        {
474            return new Notification[size];
475        }
476    };
477
478    /**
479     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
480     * layout.
481     *
482     * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
483     * in the view.</p>
484     * @param context       The context for your application / activity.
485     * @param contentTitle The title that goes in the expanded entry.
486     * @param contentText  The text that goes in the expanded entry.
487     * @param contentIntent The intent to launch when the user clicks the expanded notification.
488     * If this is an activity, it must include the
489     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
490     * that you take care of task management as described in
491     * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
492     */
493    public void setLatestEventInfo(Context context,
494            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
495        RemoteViews contentView = new RemoteViews(context.getPackageName(),
496                com.android.internal.R.layout.status_bar_latest_event_content);
497        if (this.icon != 0) {
498            contentView.setImageViewResource(com.android.internal.R.id.icon, this.icon);
499        }
500        if (contentTitle != null) {
501            contentView.setTextViewText(com.android.internal.R.id.title, contentTitle);
502        }
503        if (contentText != null) {
504            contentView.setTextViewText(com.android.internal.R.id.text, contentText);
505        }
506        if (this.when != 0) {
507            contentView.setLong(com.android.internal.R.id.time, "setTime", when);
508        }
509
510        this.contentView = contentView;
511        this.contentIntent = contentIntent;
512    }
513
514    @Override
515    public String toString() {
516        StringBuilder sb = new StringBuilder();
517        sb.append("Notification(vibrate=");
518        if (this.vibrate != null) {
519            int N = this.vibrate.length-1;
520            sb.append("[");
521            for (int i=0; i<N; i++) {
522                sb.append(this.vibrate[i]);
523                sb.append(',');
524            }
525            if (N != -1) {
526                sb.append(this.vibrate[N]);
527            }
528            sb.append("]");
529        } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
530            sb.append("default");
531        } else {
532            sb.append("null");
533        }
534        sb.append(",sound=");
535        if (this.sound != null) {
536            sb.append(this.sound.toString());
537        } else if ((this.defaults & DEFAULT_SOUND) != 0) {
538            sb.append("default");
539        } else {
540            sb.append("null");
541        }
542        sb.append(",defaults=0x");
543        sb.append(Integer.toHexString(this.defaults));
544        sb.append(",flags=0x");
545        sb.append(Integer.toHexString(this.flags));
546        sb.append(")");
547        return sb.toString();
548    }
549}
550