Notification.java revision 8d0b655c496e9125fc8d289c4e5bc9a78297ba3d
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.text.NumberFormat;
20import java.util.Date;
21
22import android.app.PendingIntent;
23import android.content.Context;
24import android.content.Intent;
25import android.graphics.Bitmap;
26import android.media.AudioManager;
27import android.net.Uri;
28import android.os.Parcel;
29import android.os.Parcelable;
30import android.text.TextUtils;
31import android.text.format.DateFormat;
32import android.text.format.DateUtils;
33import android.util.Slog;
34import android.view.View;
35import android.widget.RemoteViews;
36
37import com.android.internal.R;
38
39/**
40 * A class that represents how a persistent notification is to be presented to
41 * the user using the {@link android.app.NotificationManager}.
42 *
43 * <p>For a guide to creating notifications, see the
44 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Creating Status
45 * Bar Notifications</a> document in the Dev Guide.</p>
46 */
47public class Notification implements Parcelable
48{
49    private static final String TAG = "Notification";
50
51    /**
52     * Use all default values (where applicable).
53     */
54    public static final int DEFAULT_ALL = ~0;
55
56    /**
57     * Use the default notification sound. This will ignore any given
58     * {@link #sound}.
59     *
60     * @see #defaults
61     */
62    public static final int DEFAULT_SOUND = 1;
63
64    /**
65     * Use the default notification vibrate. This will ignore any given
66     * {@link #vibrate}. Using phone vibration requires the
67     * {@link android.Manifest.permission#VIBRATE VIBRATE} permission.
68     *
69     * @see #defaults
70     */
71    public static final int DEFAULT_VIBRATE = 2;
72
73    /**
74     * Use the default notification lights. This will ignore the
75     * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or
76     * {@link #ledOnMS}.
77     *
78     * @see #defaults
79     */
80    public static final int DEFAULT_LIGHTS = 4;
81
82    /**
83     * The timestamp for the notification.  The icons and expanded views
84     * are sorted by this key.
85     */
86    public long when;
87
88    /**
89     * The resource id of a drawable to use as the icon in the status bar.
90     */
91    public int icon;
92
93    /**
94     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
95     * leave it at its default value of 0.
96     *
97     * @see android.widget.ImageView#setImageLevel
98     * @see android.graphics.drawable#setLevel
99     */
100    public int iconLevel;
101
102    /**
103     * The number of events that this notification represents.  For example, in a new mail
104     * notification, this could be the number of unread messages.  This number is superimposed over
105     * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status
106     * bar.
107     */
108    public int number;
109
110    /**
111     * The intent to execute when the expanded status entry is clicked.  If
112     * this is an activity, it must include the
113     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
114     * that you take care of task management as described in the <em>Activities and Tasks</em>
115     * section of the <a href="{@docRoot}guide/topics/fundamentals.html#acttask">Application
116     * Fundamentals</a> document.
117     */
118    public PendingIntent contentIntent;
119
120    /**
121     * The intent to execute when the status entry is deleted by the user
122     * with the "Clear All Notifications" button. This probably shouldn't
123     * be launching an activity since several of those will be sent at the
124     * same time.
125     */
126    public PendingIntent deleteIntent;
127
128    /**
129     * An intent to launch instead of posting the notification to the status bar.
130     * Only for use with extremely high-priority notifications demanding the user's
131     * <strong>immediate</strong> attention, such as an incoming phone call or
132     * alarm clock that the user has explicitly set to a particular time.
133     * If this facility is used for something else, please give the user an option
134     * to turn it off and use a normal notification, as this can be extremely
135     * disruptive.
136     *
137     * <p>Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification
138     * will reach the user even when other notifications are suppressed.
139     */
140    public PendingIntent fullScreenIntent;
141
142    /**
143     * Text to scroll across the screen when this item is added to
144     * the status bar on large and smaller devices.
145     *
146     * <p>This field is provided separately from the other ticker fields
147     * both for compatibility and to allow an application to choose different
148     * text for when the text scrolls in and when it is displayed all at once
149     * in conjunction with one or more icons.
150     *
151     * @see #tickerView
152     */
153    public CharSequence tickerText;
154
155    /**
156     * The view to show as the ticker in the status bar when the notification
157     * is posted.
158     */
159    public RemoteViews tickerView;
160
161    /**
162     * The view that will represent this notification in the expanded status bar.
163     */
164    public RemoteViews contentView;
165
166    /**
167     * The bitmap that may escape the bounds of the panel and bar.
168     */
169    public Bitmap largeIcon;
170
171    /**
172     * The sound to play.
173     *
174     * <p>
175     * To play the default notification sound, see {@link #defaults}.
176     * </p>
177     */
178    public Uri sound;
179
180    /**
181     * Use this constant as the value for audioStreamType to request that
182     * the default stream type for notifications be used.  Currently the
183     * default stream type is STREAM_RING.
184     */
185    public static final int STREAM_DEFAULT = -1;
186
187    /**
188     * The audio stream type to use when playing the sound.
189     * Should be one of the STREAM_ constants from
190     * {@link android.media.AudioManager}.
191     */
192    public int audioStreamType = STREAM_DEFAULT;
193
194
195    /**
196     * The pattern with which to vibrate.
197     *
198     * <p>
199     * To vibrate the default pattern, see {@link #defaults}.
200     * </p>
201     *
202     * @see android.os.Vibrator#vibrate(long[],int)
203     */
204    public long[] vibrate;
205
206    /**
207     * The color of the led.  The hardware will do its best approximation.
208     *
209     * @see #FLAG_SHOW_LIGHTS
210     * @see #flags
211     */
212    public int ledARGB;
213
214    /**
215     * The number of milliseconds for the LED to be on while it's flashing.
216     * The hardware will do its best approximation.
217     *
218     * @see #FLAG_SHOW_LIGHTS
219     * @see #flags
220     */
221    public int ledOnMS;
222
223    /**
224     * The number of milliseconds for the LED to be off while it's flashing.
225     * The hardware will do its best approximation.
226     *
227     * @see #FLAG_SHOW_LIGHTS
228     * @see #flags
229     */
230    public int ledOffMS;
231
232    /**
233     * Specifies which values should be taken from the defaults.
234     * <p>
235     * To set, OR the desired from {@link #DEFAULT_SOUND},
236     * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default
237     * values, use {@link #DEFAULT_ALL}.
238     * </p>
239     */
240    public int defaults;
241
242
243    /**
244     * Bit to be bitwise-ored into the {@link #flags} field that should be
245     * set if you want the LED on for this notification.
246     * <ul>
247     * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB
248     *      or 0 for both ledOnMS and ledOffMS.</li>
249     * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li>
250     * <li>To flash the LED, pass the number of milliseconds that it should
251     *      be on and off to ledOnMS and ledOffMS.</li>
252     * </ul>
253     * <p>
254     * Since hardware varies, you are not guaranteed that any of the values
255     * you pass are honored exactly.  Use the system defaults (TODO) if possible
256     * because they will be set to values that work on any given hardware.
257     * <p>
258     * The alpha channel must be set for forward compatibility.
259     *
260     */
261    public static final int FLAG_SHOW_LIGHTS        = 0x00000001;
262
263    /**
264     * Bit to be bitwise-ored into the {@link #flags} field that should be
265     * set if this notification is in reference to something that is ongoing,
266     * like a phone call.  It should not be set if this notification is in
267     * reference to something that happened at a particular point in time,
268     * like a missed phone call.
269     */
270    public static final int FLAG_ONGOING_EVENT      = 0x00000002;
271
272    /**
273     * Bit to be bitwise-ored into the {@link #flags} field that if set,
274     * the audio will be repeated until the notification is
275     * cancelled or the notification window is opened.
276     */
277    public static final int FLAG_INSISTENT          = 0x00000004;
278
279    /**
280     * Bit to be bitwise-ored into the {@link #flags} field that should be
281     * set if you want the sound and/or vibration play each time the
282     * notification is sent, even if it has not been canceled before that.
283     */
284    public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
285
286    /**
287     * Bit to be bitwise-ored into the {@link #flags} field that should be
288     * set if the notification should be canceled when it is clicked by the
289     * user.
290     */
291    public static final int FLAG_AUTO_CANCEL        = 0x00000010;
292
293    /**
294     * Bit to be bitwise-ored into the {@link #flags} field that should be
295     * set if the notification should not be canceled when the user clicks
296     * the Clear all button.
297     */
298    public static final int FLAG_NO_CLEAR           = 0x00000020;
299
300    /**
301     * Bit to be bitwise-ored into the {@link #flags} field that should be
302     * set if this notification represents a currently running service.  This
303     * will normally be set for you by {@link Service#startForeground}.
304     */
305    public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
306
307    /**
308     * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification
309     * represents a high-priority event that may be shown to the user even if notifications are
310     * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used
311     * in conjunction with {@link #fullScreenIntent}.
312     */
313    public static final int FLAG_HIGH_PRIORITY = 0x00000080;
314
315    public int flags;
316
317    /**
318     * Constructs a Notification object with everything set to 0.
319     * You might want to consider using {@link Builder} instead.
320     */
321    public Notification()
322    {
323        this.when = System.currentTimeMillis();
324    }
325
326    /**
327     * @hide
328     */
329    public Notification(Context context, int icon, CharSequence tickerText, long when,
330            CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
331    {
332        this.when = when;
333        this.icon = icon;
334        this.tickerText = tickerText;
335        setLatestEventInfo(context, contentTitle, contentText,
336                PendingIntent.getActivity(context, 0, contentIntent, 0));
337    }
338
339    /**
340     * Constructs a Notification object with the information needed to
341     * have a status bar icon without the standard expanded view.
342     *
343     * @param icon          The resource id of the icon to put in the status bar.
344     * @param tickerText    The text that flows by in the status bar when the notification first
345     *                      activates.
346     * @param when          The time to show in the time field.  In the System.currentTimeMillis
347     *                      timebase.
348     *
349     * @deprecated Use {@link Builder} instead.
350     */
351    @Deprecated
352    public Notification(int icon, CharSequence tickerText, long when)
353    {
354        this.icon = icon;
355        this.tickerText = tickerText;
356        this.when = when;
357    }
358
359    /**
360     * Unflatten the notification from a parcel.
361     */
362    public Notification(Parcel parcel)
363    {
364        int version = parcel.readInt();
365
366        when = parcel.readLong();
367        icon = parcel.readInt();
368        number = parcel.readInt();
369        if (parcel.readInt() != 0) {
370            contentIntent = PendingIntent.CREATOR.createFromParcel(parcel);
371        }
372        if (parcel.readInt() != 0) {
373            deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel);
374        }
375        if (parcel.readInt() != 0) {
376            tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
377        }
378        if (parcel.readInt() != 0) {
379            tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
380        }
381        if (parcel.readInt() != 0) {
382            contentView = RemoteViews.CREATOR.createFromParcel(parcel);
383        }
384        if (parcel.readInt() != 0) {
385            largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
386        }
387        defaults = parcel.readInt();
388        flags = parcel.readInt();
389        if (parcel.readInt() != 0) {
390            sound = Uri.CREATOR.createFromParcel(parcel);
391        }
392
393        audioStreamType = parcel.readInt();
394        vibrate = parcel.createLongArray();
395        ledARGB = parcel.readInt();
396        ledOnMS = parcel.readInt();
397        ledOffMS = parcel.readInt();
398        iconLevel = parcel.readInt();
399
400        if (parcel.readInt() != 0) {
401            fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel);
402        }
403    }
404
405    public Notification clone() {
406        Notification that = new Notification();
407
408        that.when = this.when;
409        that.icon = this.icon;
410        that.number = this.number;
411
412        // PendingIntents are global, so there's no reason (or way) to clone them.
413        that.contentIntent = this.contentIntent;
414        that.deleteIntent = this.deleteIntent;
415        that.fullScreenIntent = this.fullScreenIntent;
416
417        if (this.tickerText != null) {
418            that.tickerText = this.tickerText.toString();
419        }
420        if (this.tickerView != null) {
421            that.tickerView = this.tickerView.clone();
422        }
423        if (this.contentView != null) {
424            that.contentView = this.contentView.clone();
425        }
426        if (this.largeIcon != null) {
427            that.largeIcon = Bitmap.createBitmap(this.largeIcon);
428        }
429        that.iconLevel = that.iconLevel;
430        that.sound = this.sound; // android.net.Uri is immutable
431        that.audioStreamType = this.audioStreamType;
432
433        final long[] vibrate = this.vibrate;
434        if (vibrate != null) {
435            final int N = vibrate.length;
436            final long[] vib = that.vibrate = new long[N];
437            System.arraycopy(vibrate, 0, vib, 0, N);
438        }
439
440        that.ledARGB = this.ledARGB;
441        that.ledOnMS = this.ledOnMS;
442        that.ledOffMS = this.ledOffMS;
443        that.defaults = this.defaults;
444
445        that.flags = this.flags;
446
447        return that;
448    }
449
450    public int describeContents() {
451        return 0;
452    }
453
454    /**
455     * Flatten this notification from a parcel.
456     */
457    public void writeToParcel(Parcel parcel, int flags)
458    {
459        parcel.writeInt(1);
460
461        parcel.writeLong(when);
462        parcel.writeInt(icon);
463        parcel.writeInt(number);
464        if (contentIntent != null) {
465            parcel.writeInt(1);
466            contentIntent.writeToParcel(parcel, 0);
467        } else {
468            parcel.writeInt(0);
469        }
470        if (deleteIntent != null) {
471            parcel.writeInt(1);
472            deleteIntent.writeToParcel(parcel, 0);
473        } else {
474            parcel.writeInt(0);
475        }
476        if (tickerText != null) {
477            parcel.writeInt(1);
478            TextUtils.writeToParcel(tickerText, parcel, flags);
479        } else {
480            parcel.writeInt(0);
481        }
482        if (tickerView != null) {
483            parcel.writeInt(1);
484            tickerView.writeToParcel(parcel, 0);
485        } else {
486            parcel.writeInt(0);
487        }
488        if (contentView != null) {
489            parcel.writeInt(1);
490            contentView.writeToParcel(parcel, 0);
491        } else {
492            parcel.writeInt(0);
493        }
494        if (largeIcon != null) {
495            parcel.writeInt(1);
496            largeIcon.writeToParcel(parcel, 0);
497        } else {
498            parcel.writeInt(0);
499        }
500
501        parcel.writeInt(defaults);
502        parcel.writeInt(this.flags);
503
504        if (sound != null) {
505            parcel.writeInt(1);
506            sound.writeToParcel(parcel, 0);
507        } else {
508            parcel.writeInt(0);
509        }
510        parcel.writeInt(audioStreamType);
511        parcel.writeLongArray(vibrate);
512        parcel.writeInt(ledARGB);
513        parcel.writeInt(ledOnMS);
514        parcel.writeInt(ledOffMS);
515        parcel.writeInt(iconLevel);
516
517        if (fullScreenIntent != null) {
518            parcel.writeInt(1);
519            fullScreenIntent.writeToParcel(parcel, 0);
520        } else {
521            parcel.writeInt(0);
522        }
523    }
524
525    /**
526     * Parcelable.Creator that instantiates Notification objects
527     */
528    public static final Parcelable.Creator<Notification> CREATOR
529            = new Parcelable.Creator<Notification>()
530    {
531        public Notification createFromParcel(Parcel parcel)
532        {
533            return new Notification(parcel);
534        }
535
536        public Notification[] newArray(int size)
537        {
538            return new Notification[size];
539        }
540    };
541
542    /**
543     * Sets the {@link #contentView} field to be a view with the standard "Latest Event"
544     * layout.
545     *
546     * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields
547     * in the view.</p>
548     * @param context       The context for your application / activity.
549     * @param contentTitle The title that goes in the expanded entry.
550     * @param contentText  The text that goes in the expanded entry.
551     * @param contentIntent The intent to launch when the user clicks the expanded notification.
552     * If this is an activity, it must include the
553     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
554     * that you take care of task management as described in
555     * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
556     *
557     * @deprecated Use {@link Builder} instead.
558     */
559    @Deprecated
560    public void setLatestEventInfo(Context context,
561            CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
562        RemoteViews contentView = new RemoteViews(context.getPackageName(),
563                R.layout.status_bar_latest_event_content);
564        if (this.icon != 0) {
565            contentView.setImageViewResource(R.id.icon, this.icon);
566        }
567        if (contentTitle != null) {
568            contentView.setTextViewText(R.id.title, contentTitle);
569        }
570        if (contentText != null) {
571            contentView.setTextViewText(R.id.text, contentText);
572        }
573        if (this.when != 0) {
574            contentView.setLong(R.id.time, "setTime", when);
575        }
576
577        this.contentView = contentView;
578        this.contentIntent = contentIntent;
579    }
580
581    @Override
582    public String toString() {
583        StringBuilder sb = new StringBuilder();
584        sb.append("Notification(vibrate=");
585        if (this.vibrate != null) {
586            int N = this.vibrate.length-1;
587            sb.append("[");
588            for (int i=0; i<N; i++) {
589                sb.append(this.vibrate[i]);
590                sb.append(',');
591            }
592            if (N != -1) {
593                sb.append(this.vibrate[N]);
594            }
595            sb.append("]");
596        } else if ((this.defaults & DEFAULT_VIBRATE) != 0) {
597            sb.append("default");
598        } else {
599            sb.append("null");
600        }
601        sb.append(",sound=");
602        if (this.sound != null) {
603            sb.append(this.sound.toString());
604        } else if ((this.defaults & DEFAULT_SOUND) != 0) {
605            sb.append("default");
606        } else {
607            sb.append("null");
608        }
609        sb.append(",defaults=0x");
610        sb.append(Integer.toHexString(this.defaults));
611        sb.append(",flags=0x");
612        sb.append(Integer.toHexString(this.flags));
613        if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
614            sb.append("!!!1!one!");
615        }
616        sb.append(")");
617        return sb.toString();
618    }
619
620    public static class Builder {
621        private Context mContext;
622
623        private long mWhen;
624        private int mSmallIcon;
625        private int mSmallIconLevel;
626        private int mNumber;
627        private CharSequence mContentTitle;
628        private CharSequence mContentText;
629        private CharSequence mContentInfo;
630        private PendingIntent mContentIntent;
631        private RemoteViews mContentView;
632        private PendingIntent mDeleteIntent;
633        private PendingIntent mFullScreenIntent;
634        private CharSequence mTickerText;
635        private RemoteViews mTickerView;
636        private Bitmap mLargeIcon;
637        private Uri mSound;
638        private int mAudioStreamType;
639        private long[] mVibrate;
640        private int mLedArgb;
641        private int mLedOnMs;
642        private int mLedOffMs;
643        private int mDefaults;
644        private int mFlags;
645
646        public Builder(Context context) {
647            mContext = context;
648            mWhen = System.currentTimeMillis();
649        }
650
651        public Builder setWhen(long when) {
652            mWhen = when;
653            return this;
654        }
655
656        public Builder setSmallIcon(int icon) {
657            mSmallIcon = icon;
658            return this;
659        }
660
661        public Builder setSmallIcon(int icon, int level) {
662            mSmallIcon = icon;
663            mSmallIconLevel = level;
664            return this;
665        }
666
667        public Builder setContentTitle(CharSequence title) {
668            mContentTitle = title;
669            return this;
670        }
671
672        public Builder setContentText(CharSequence text) {
673            mContentText = text;
674            return this;
675        }
676
677        public Builder setNumber(int number) {
678            mNumber = number;
679            return this;
680        }
681
682        public Builder setContentInfo(CharSequence info) {
683            mContentInfo = info;
684            return this;
685        }
686
687        public Builder setContent(RemoteViews views) {
688            mContentView = views;
689            return this;
690        }
691
692        public Builder setContentIntent(PendingIntent intent) {
693            mContentIntent = intent;
694            return this;
695        }
696
697        public Builder setDeleteIntent(PendingIntent intent) {
698            mDeleteIntent = intent;
699            return this;
700        }
701
702        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
703            mFullScreenIntent = intent;
704            setFlag(FLAG_HIGH_PRIORITY, highPriority);
705            return this;
706        }
707
708        public Builder setTicker(CharSequence tickerText) {
709            mTickerText = tickerText;
710            return this;
711        }
712
713        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
714            mTickerText = tickerText;
715            mTickerView = views;
716            return this;
717        }
718
719        public Builder setLargeIcon(Bitmap icon) {
720            mLargeIcon = icon;
721            return this;
722        }
723
724        public Builder setSound(Uri sound) {
725            mSound = sound;
726            mAudioStreamType = STREAM_DEFAULT;
727            return this;
728        }
729
730        public Builder setSound(Uri sound, int streamType) {
731            mSound = sound;
732            mAudioStreamType = streamType;
733            return this;
734        }
735
736        public Builder setVibrate(long[] pattern) {
737            mVibrate = pattern;
738            return this;
739        }
740
741        public Builder setLights(int argb, int onMs, int offMs) {
742            mLedArgb = argb;
743            mLedOnMs = onMs;
744            mLedOffMs = offMs;
745            return this;
746        }
747
748        public Builder setOngoing(boolean ongoing) {
749            setFlag(FLAG_ONGOING_EVENT, ongoing);
750            return this;
751        }
752
753        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
754            setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
755            return this;
756        }
757
758        public Builder setAutoCancel(boolean autoCancel) {
759            setFlag(FLAG_ONLY_ALERT_ONCE, autoCancel);
760            return this;
761        }
762
763        public Builder setDefaults(int defaults) {
764            mDefaults = defaults;
765            return this;
766        }
767
768        private void setFlag(int mask, boolean value) {
769            if (value) {
770                mFlags |= mask;
771            } else {
772                mFlags &= ~mask;
773            }
774        }
775
776        private RemoteViews makeRemoteViews(int resId) {
777            RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
778            if (mSmallIcon != 0) {
779                contentView.setImageViewResource(R.id.icon, mSmallIcon);
780            }
781            if (mContentTitle != null) {
782                contentView.setTextViewText(R.id.title, mContentTitle);
783            }
784            if (mContentText != null) {
785                contentView.setTextViewText(R.id.text, mContentText);
786            }
787            if (mContentInfo != null) {
788                contentView.setTextViewText(R.id.info, mContentInfo);
789            } else if (mNumber > 0) {
790                NumberFormat f = NumberFormat.getIntegerInstance();
791                contentView.setTextViewText(R.id.info, f.format(mNumber));
792                contentView.setFloat(R.id.info, "setTextSize",
793                        mContext.getResources().getDimensionPixelSize(
794                            R.dimen.status_bar_content_number_size));
795            } else {
796                contentView.setViewVisibility(R.id.info, View.GONE);
797            }
798            if (mWhen != 0) {
799                contentView.setLong(R.id.time, "setTime", mWhen);
800            }
801            return contentView;
802        }
803
804        private RemoteViews makeContentView() {
805            if (mContentView != null) {
806                return mContentView;
807            } else {
808                    return makeRemoteViews(mLargeIcon == null
809                            ? R.layout.status_bar_latest_event_content
810                        : R.layout.status_bar_latest_event_content_large_icon);
811            }
812        }
813
814        private RemoteViews makeTickerView() {
815            if (mTickerView != null) {
816                return mTickerView;
817            } else {
818                if (mContentView == null) {
819                    return makeRemoteViews(mLargeIcon == null
820                            ? R.layout.status_bar_latest_event_ticker
821                            : R.layout.status_bar_latest_event_ticker_large_icon);
822                } else {
823                    return null;
824                }
825            }
826        }
827
828        public Notification getNotification() {
829            Notification n = new Notification();
830            n.when = mWhen;
831            n.icon = mSmallIcon;
832            n.iconLevel = mSmallIconLevel;
833            n.number = mNumber;
834            n.contentView = makeContentView();
835            n.contentIntent = mContentIntent;
836            n.deleteIntent = mDeleteIntent;
837            n.fullScreenIntent = mFullScreenIntent;
838            n.tickerText = mTickerText;
839            n.tickerView = makeTickerView();
840            n.largeIcon = mLargeIcon;
841            n.sound = mSound;
842            n.audioStreamType = mAudioStreamType;
843            n.vibrate = mVibrate;
844            n.ledARGB = mLedArgb;
845            n.ledOnMS = mLedOnMs;
846            n.ledOffMS = mLedOffMs;
847            n.defaults = mDefaults;
848            n.flags = mFlags;
849            if (mLedOnMs != 0 && mLedOffMs != 0) {
850                n.flags |= FLAG_SHOW_LIGHTS;
851            }
852            if ((mDefaults & DEFAULT_LIGHTS) != 0) {
853                n.flags |= FLAG_SHOW_LIGHTS;
854            }
855            return n;
856        }
857    }
858}
859