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