Notification.java revision b720abeee8474f4c641f57c58ac97d537da20cbf
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 android.annotation.IntDef; 20import android.content.Context; 21import android.content.Intent; 22import android.content.res.Resources; 23import android.graphics.Bitmap; 24import android.graphics.PorterDuff; 25import android.media.AudioManager; 26import android.net.Uri; 27import android.os.BadParcelableException; 28import android.os.Build; 29import android.os.Bundle; 30import android.os.Parcel; 31import android.os.Parcelable; 32import android.os.SystemClock; 33import android.os.UserHandle; 34import android.text.TextUtils; 35import android.util.Log; 36import android.util.TypedValue; 37import android.view.View; 38import android.widget.ProgressBar; 39import android.widget.RemoteViews; 40 41import com.android.internal.R; 42import com.android.internal.util.NotificationColorUtil; 43 44import java.lang.annotation.Retention; 45import java.lang.annotation.RetentionPolicy; 46import java.text.NumberFormat; 47import java.util.ArrayList; 48import java.util.Collections; 49 50/** 51 * A class that represents how a persistent notification is to be presented to 52 * the user using the {@link android.app.NotificationManager}. 53 * 54 * <p>The {@link Notification.Builder Notification.Builder} has been added to make it 55 * easier to construct Notifications.</p> 56 * 57 * <div class="special reference"> 58 * <h3>Developer Guides</h3> 59 * <p>For a guide to creating notifications, read the 60 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">Status Bar Notifications</a> 61 * developer guide.</p> 62 * </div> 63 */ 64public class Notification implements Parcelable 65{ 66 private static final String TAG = "Notification"; 67 68 /** 69 * Use all default values (where applicable). 70 */ 71 public static final int DEFAULT_ALL = ~0; 72 73 /** 74 * Use the default notification sound. This will ignore any given 75 * {@link #sound}. 76 * 77 78 * @see #defaults 79 */ 80 81 public static final int DEFAULT_SOUND = 1; 82 83 /** 84 * Use the default notification vibrate. This will ignore any given 85 * {@link #vibrate}. Using phone vibration requires the 86 * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. 87 * 88 * @see #defaults 89 */ 90 91 public static final int DEFAULT_VIBRATE = 2; 92 93 /** 94 * Use the default notification lights. This will ignore the 95 * {@link #FLAG_SHOW_LIGHTS} bit, and {@link #ledARGB}, {@link #ledOffMS}, or 96 * {@link #ledOnMS}. 97 * 98 * @see #defaults 99 */ 100 101 public static final int DEFAULT_LIGHTS = 4; 102 103 /** 104 * A timestamp related to this notification, in milliseconds since the epoch. 105 * 106 * Default value: {@link System#currentTimeMillis() Now}. 107 * 108 * Choose a timestamp that will be most relevant to the user. For most finite events, this 109 * corresponds to the time the event happened (or will happen, in the case of events that have 110 * yet to occur but about which the user is being informed). Indefinite events should be 111 * timestamped according to when the activity began. 112 * 113 * Some examples: 114 * 115 * <ul> 116 * <li>Notification of a new chat message should be stamped when the message was received.</li> 117 * <li>Notification of an ongoing file download (with a progress bar, for example) should be stamped when the download started.</li> 118 * <li>Notification of a completed file download should be stamped when the download finished.</li> 119 * <li>Notification of an upcoming meeting should be stamped with the time the meeting will begin (that is, in the future).</li> 120 * <li>Notification of an ongoing stopwatch (increasing timer) should be stamped with the watch's start time. 121 * <li>Notification of an ongoing countdown timer should be stamped with the timer's end time. 122 * </ul> 123 * 124 */ 125 public long when; 126 127 /** 128 * The resource id of a drawable to use as the icon in the status bar. 129 * This is required; notifications with an invalid icon resource will not be shown. 130 */ 131 public int icon; 132 133 /** 134 * If the icon in the status bar is to have more than one level, you can set this. Otherwise, 135 * leave it at its default value of 0. 136 * 137 * @see android.widget.ImageView#setImageLevel 138 * @see android.graphics.drawable.Drawable#setLevel 139 */ 140 public int iconLevel; 141 142 /** 143 * The number of events that this notification represents. For example, in a new mail 144 * notification, this could be the number of unread messages. 145 * 146 * The system may or may not use this field to modify the appearance of the notification. For 147 * example, before {@link android.os.Build.VERSION_CODES#HONEYCOMB}, this number was 148 * superimposed over the icon in the status bar. Starting with 149 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, the template used by 150 * {@link Notification.Builder} has displayed the number in the expanded notification view. 151 * 152 * If the number is 0 or negative, it is never shown. 153 */ 154 public int number; 155 156 /** 157 * The intent to execute when the expanded status entry is clicked. If 158 * this is an activity, it must include the 159 * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires 160 * that you take care of task management as described in the 161 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back 162 * Stack</a> document. In particular, make sure to read the notification section 163 * <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#HandlingNotifications">Handling 164 * Notifications</a> for the correct ways to launch an application from a 165 * notification. 166 */ 167 public PendingIntent contentIntent; 168 169 /** 170 * The intent to execute when the notification is explicitly dismissed by the user, either with 171 * the "Clear All" button or by swiping it away individually. 172 * 173 * This probably shouldn't be launching an activity since several of those will be sent 174 * at the same time. 175 */ 176 public PendingIntent deleteIntent; 177 178 /** 179 * An intent to launch instead of posting the notification to the status bar. 180 * 181 * @see Notification.Builder#setFullScreenIntent 182 */ 183 public PendingIntent fullScreenIntent; 184 185 /** 186 * Text to scroll across the screen when this item is added to 187 * the status bar on large and smaller devices. 188 * 189 * @see #tickerView 190 */ 191 public CharSequence tickerText; 192 193 /** 194 * The view to show as the ticker in the status bar when the notification 195 * is posted. 196 */ 197 public RemoteViews tickerView; 198 199 /** 200 * The view that will represent this notification in the expanded status bar. 201 */ 202 public RemoteViews contentView; 203 204 /** 205 * A large-format version of {@link #contentView}, giving the Notification an 206 * opportunity to show more detail. The system UI may choose to show this 207 * instead of the normal content view at its discretion. 208 */ 209 public RemoteViews bigContentView; 210 211 212 /** 213 * @hide 214 * A medium-format version of {@link #contentView}, giving the Notification an 215 * opportunity to add action buttons to contentView. The system UI may 216 * choose to show this as a popup notification at its discretion. 217 */ 218 public RemoteViews headsUpContentView; 219 220 /** 221 * The bitmap that may escape the bounds of the panel and bar. 222 */ 223 public Bitmap largeIcon; 224 225 /** 226 * The sound to play. 227 * 228 * <p> 229 * To play the default notification sound, see {@link #defaults}. 230 * </p> 231 */ 232 public Uri sound; 233 234 /** 235 * Use this constant as the value for audioStreamType to request that 236 * the default stream type for notifications be used. Currently the 237 * default stream type is {@link AudioManager#STREAM_NOTIFICATION}. 238 */ 239 public static final int STREAM_DEFAULT = -1; 240 241 /** 242 * The audio stream type to use when playing the sound. 243 * Should be one of the STREAM_ constants from 244 * {@link android.media.AudioManager}. 245 */ 246 public int audioStreamType = STREAM_DEFAULT; 247 248 /** 249 * The pattern with which to vibrate. 250 * 251 * <p> 252 * To vibrate the default pattern, see {@link #defaults}. 253 * </p> 254 * 255 * @see android.os.Vibrator#vibrate(long[],int) 256 */ 257 public long[] vibrate; 258 259 /** 260 * The color of the led. The hardware will do its best approximation. 261 * 262 * @see #FLAG_SHOW_LIGHTS 263 * @see #flags 264 */ 265 public int ledARGB; 266 267 /** 268 * The number of milliseconds for the LED to be on while it's flashing. 269 * The hardware will do its best approximation. 270 * 271 * @see #FLAG_SHOW_LIGHTS 272 * @see #flags 273 */ 274 public int ledOnMS; 275 276 /** 277 * The number of milliseconds for the LED to be off while it's flashing. 278 * The hardware will do its best approximation. 279 * 280 * @see #FLAG_SHOW_LIGHTS 281 * @see #flags 282 */ 283 public int ledOffMS; 284 285 /** 286 * Specifies which values should be taken from the defaults. 287 * <p> 288 * To set, OR the desired from {@link #DEFAULT_SOUND}, 289 * {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. For all default 290 * values, use {@link #DEFAULT_ALL}. 291 * </p> 292 */ 293 public int defaults; 294 295 /** 296 * Bit to be bitwise-ored into the {@link #flags} field that should be 297 * set if you want the LED on for this notification. 298 * <ul> 299 * <li>To turn the LED off, pass 0 in the alpha channel for colorARGB 300 * or 0 for both ledOnMS and ledOffMS.</li> 301 * <li>To turn the LED on, pass 1 for ledOnMS and 0 for ledOffMS.</li> 302 * <li>To flash the LED, pass the number of milliseconds that it should 303 * be on and off to ledOnMS and ledOffMS.</li> 304 * </ul> 305 * <p> 306 * Since hardware varies, you are not guaranteed that any of the values 307 * you pass are honored exactly. Use the system defaults (TODO) if possible 308 * because they will be set to values that work on any given hardware. 309 * <p> 310 * The alpha channel must be set for forward compatibility. 311 * 312 */ 313 public static final int FLAG_SHOW_LIGHTS = 0x00000001; 314 315 /** 316 * Bit to be bitwise-ored into the {@link #flags} field that should be 317 * set if this notification is in reference to something that is ongoing, 318 * like a phone call. It should not be set if this notification is in 319 * reference to something that happened at a particular point in time, 320 * like a missed phone call. 321 */ 322 public static final int FLAG_ONGOING_EVENT = 0x00000002; 323 324 /** 325 * Bit to be bitwise-ored into the {@link #flags} field that if set, 326 * the audio will be repeated until the notification is 327 * cancelled or the notification window is opened. 328 */ 329 public static final int FLAG_INSISTENT = 0x00000004; 330 331 /** 332 * Bit to be bitwise-ored into the {@link #flags} field that should be 333 * set if you would only like the sound, vibrate and ticker to be played 334 * if the notification was not already showing. 335 */ 336 public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008; 337 338 /** 339 * Bit to be bitwise-ored into the {@link #flags} field that should be 340 * set if the notification should be canceled when it is clicked by the 341 * user. 342 343 */ 344 public static final int FLAG_AUTO_CANCEL = 0x00000010; 345 346 /** 347 * Bit to be bitwise-ored into the {@link #flags} field that should be 348 * set if the notification should not be canceled when the user clicks 349 * the Clear all button. 350 */ 351 public static final int FLAG_NO_CLEAR = 0x00000020; 352 353 /** 354 * Bit to be bitwise-ored into the {@link #flags} field that should be 355 * set if this notification represents a currently running service. This 356 * will normally be set for you by {@link Service#startForeground}. 357 */ 358 public static final int FLAG_FOREGROUND_SERVICE = 0x00000040; 359 360 /** 361 * Obsolete flag indicating high-priority notifications; use the priority field instead. 362 * 363 * @deprecated Use {@link #priority} with a positive value. 364 */ 365 public static final int FLAG_HIGH_PRIORITY = 0x00000080; 366 367 /** 368 * Bit to be bitswise-ored into the {@link #flags} field that should be 369 * set if this notification is relevant to the current device only 370 * and it is not recommended that it bridge to other devices. 371 */ 372 public static final int FLAG_LOCAL_ONLY = 0x00000100; 373 374 /** 375 * Bit to be bitswise-ored into the {@link #flags} field that should be 376 * set if this notification is the group summary for a group of notifications. 377 * Grouped notifications may display in a cluster or stack on devices which 378 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 379 */ 380 public static final int FLAG_GROUP_SUMMARY = 0x00000200; 381 382 public int flags; 383 384 /** @hide */ 385 @IntDef({PRIORITY_DEFAULT,PRIORITY_LOW,PRIORITY_MIN,PRIORITY_HIGH,PRIORITY_MAX}) 386 @Retention(RetentionPolicy.SOURCE) 387 public @interface Priority {} 388 389 /** 390 * Default notification {@link #priority}. If your application does not prioritize its own 391 * notifications, use this value for all notifications. 392 */ 393 public static final int PRIORITY_DEFAULT = 0; 394 395 /** 396 * Lower {@link #priority}, for items that are less important. The UI may choose to show these 397 * items smaller, or at a different position in the list, compared with your app's 398 * {@link #PRIORITY_DEFAULT} items. 399 */ 400 public static final int PRIORITY_LOW = -1; 401 402 /** 403 * Lowest {@link #priority}; these items might not be shown to the user except under special 404 * circumstances, such as detailed notification logs. 405 */ 406 public static final int PRIORITY_MIN = -2; 407 408 /** 409 * Higher {@link #priority}, for more important notifications or alerts. The UI may choose to 410 * show these items larger, or at a different position in notification lists, compared with 411 * your app's {@link #PRIORITY_DEFAULT} items. 412 */ 413 public static final int PRIORITY_HIGH = 1; 414 415 /** 416 * Highest {@link #priority}, for your application's most important items that require the 417 * user's prompt attention or input. 418 */ 419 public static final int PRIORITY_MAX = 2; 420 421 /** 422 * Relative priority for this notification. 423 * 424 * Priority is an indication of how much of the user's valuable attention should be consumed by 425 * this notification. Low-priority notifications may be hidden from the user in certain 426 * situations, while the user might be interrupted for a higher-priority notification. The 427 * system will make a determination about how to interpret this priority when presenting 428 * the notification. 429 */ 430 @Priority 431 public int priority; 432 433 /** 434 * Accent color (an ARGB integer like the constants in {@link android.graphics.Color}) 435 * to be applied by the standard Style templates when presenting this notification. 436 * 437 * The current template design constructs a colorful header image by overlaying the 438 * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are 439 * ignored. 440 */ 441 public int color = COLOR_DEFAULT; 442 443 /** 444 * Special value of {@link #color} telling the system not to decorate this notification with 445 * any special color but instead use default colors when presenting this notification. 446 */ 447 public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT 448 449 /** 450 * Sphere of visibility of this notification, which affects how and when the SystemUI reveals 451 * the notification's presence and contents in untrusted situations (namely, on the secure 452 * lockscreen). 453 * 454 * The default level, {@link #VISIBILITY_PRIVATE}, behaves exactly as notifications have always 455 * done on Android: The notification's {@link #icon} and {@link #tickerText} (if available) are 456 * shown in all situations, but the contents are only available if the device is unlocked for 457 * the appropriate user. 458 * 459 * A more permissive policy can be expressed by {@link #VISIBILITY_PUBLIC}; such a notification 460 * can be read even in an "insecure" context (that is, above a secure lockscreen). 461 * To modify the public version of this notification—for example, to redact some portions—see 462 * {@link Builder#setPublicVersion(Notification)}. 463 * 464 * Finally, a notification can be made {@link #VISIBILITY_SECRET}, which will suppress its icon 465 * and ticker until the user has bypassed the lockscreen. 466 */ 467 public int visibility; 468 469 public static final int VISIBILITY_PUBLIC = 1; 470 public static final int VISIBILITY_PRIVATE = 0; 471 public static final int VISIBILITY_SECRET = -1; 472 473 /** 474 * Notification category: incoming call (voice or video) or similar synchronous communication request. 475 */ 476 public static final String CATEGORY_CALL = "call"; 477 478 /** 479 * Notification category: incoming direct message (SMS, instant message, etc.). 480 */ 481 public static final String CATEGORY_MESSAGE = "msg"; 482 483 /** 484 * Notification category: asynchronous bulk message (email). 485 */ 486 public static final String CATEGORY_EMAIL = "email"; 487 488 /** 489 * Notification category: calendar event. 490 */ 491 public static final String CATEGORY_EVENT = "event"; 492 493 /** 494 * Notification category: promotion or advertisement. 495 */ 496 public static final String CATEGORY_PROMO = "promo"; 497 498 /** 499 * Notification category: alarm or timer. 500 */ 501 public static final String CATEGORY_ALARM = "alarm"; 502 503 /** 504 * Notification category: progress of a long-running background operation. 505 */ 506 public static final String CATEGORY_PROGRESS = "progress"; 507 508 /** 509 * Notification category: social network or sharing update. 510 */ 511 public static final String CATEGORY_SOCIAL = "social"; 512 513 /** 514 * Notification category: error in background operation or authentication status. 515 */ 516 public static final String CATEGORY_ERROR = "err"; 517 518 /** 519 * Notification category: media transport control for playback. 520 */ 521 public static final String CATEGORY_TRANSPORT = "transport"; 522 523 /** 524 * Notification category: system or device status update. Reserved for system use. 525 */ 526 public static final String CATEGORY_SYSTEM = "sys"; 527 528 /** 529 * Notification category: indication of running background service. 530 */ 531 public static final String CATEGORY_SERVICE = "service"; 532 533 /** 534 * Notification category: a specific, timely recommendation for a single thing. 535 * For example, a news app might want to recommend a news story it believes the user will 536 * want to read next. 537 */ 538 public static final String CATEGORY_RECOMMENDATION = "recommendation"; 539 540 /** 541 * Notification category: ongoing information about device or contextual status. 542 */ 543 public static final String CATEGORY_STATUS = "status"; 544 545 /** 546 * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants) 547 * that best describes this Notification. May be used by the system for ranking and filtering. 548 */ 549 public String category; 550 551 private String mGroupKey; 552 553 /** 554 * Get the key used to group this notification into a cluster or stack 555 * with other notifications on devices which support such rendering. 556 */ 557 public String getGroup() { 558 return mGroupKey; 559 } 560 561 private String mSortKey; 562 563 /** 564 * Get a sort key that orders this notification among other notifications from the 565 * same package. This can be useful if an external sort was already applied and an app 566 * would like to preserve this. Notifications will be sorted lexicographically using this 567 * value, although providing different priorities in addition to providing sort key may 568 * cause this value to be ignored. 569 * 570 * <p>This sort key can also be used to order members of a notification group. See 571 * {@link Builder#setGroup}. 572 * 573 * @see String#compareTo(String) 574 */ 575 public String getSortKey() { 576 return mSortKey; 577 } 578 579 /** 580 * Additional semantic data to be carried around with this Notification. 581 * <p> 582 * The extras keys defined here are intended to capture the original inputs to {@link Builder} 583 * APIs, and are intended to be used by 584 * {@link android.service.notification.NotificationListenerService} implementations to extract 585 * detailed information from notification objects. 586 */ 587 public Bundle extras = new Bundle(); 588 589 /** 590 * {@link #extras} key: this is the title of the notification, 591 * as supplied to {@link Builder#setContentTitle(CharSequence)}. 592 */ 593 public static final String EXTRA_TITLE = "android.title"; 594 595 /** 596 * {@link #extras} key: this is the title of the notification when shown in expanded form, 597 * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}. 598 */ 599 public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big"; 600 601 /** 602 * {@link #extras} key: this is the main text payload, as supplied to 603 * {@link Builder#setContentText(CharSequence)}. 604 */ 605 public static final String EXTRA_TEXT = "android.text"; 606 607 /** 608 * {@link #extras} key: this is a third line of text, as supplied to 609 * {@link Builder#setSubText(CharSequence)}. 610 */ 611 public static final String EXTRA_SUB_TEXT = "android.subText"; 612 613 /** 614 * {@link #extras} key: this is a small piece of additional text as supplied to 615 * {@link Builder#setContentInfo(CharSequence)}. 616 */ 617 public static final String EXTRA_INFO_TEXT = "android.infoText"; 618 619 /** 620 * {@link #extras} key: this is a line of summary information intended to be shown 621 * alongside expanded notifications, as supplied to (e.g.) 622 * {@link BigTextStyle#setSummaryText(CharSequence)}. 623 */ 624 public static final String EXTRA_SUMMARY_TEXT = "android.summaryText"; 625 626 /** 627 * {@link #extras} key: this is the resource ID of the notification's main small icon, as 628 * supplied to {@link Builder#setSmallIcon(int)}. 629 */ 630 public static final String EXTRA_SMALL_ICON = "android.icon"; 631 632 /** 633 * {@link #extras} key: this is a bitmap to be used instead of the small icon when showing the 634 * notification payload, as 635 * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}. 636 */ 637 public static final String EXTRA_LARGE_ICON = "android.largeIcon"; 638 639 /** 640 * {@link #extras} key: this is a bitmap to be used instead of the one from 641 * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is 642 * shown in its expanded form, as supplied to 643 * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}. 644 */ 645 public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big"; 646 647 /** 648 * {@link #extras} key: this is the progress value supplied to 649 * {@link Builder#setProgress(int, int, boolean)}. 650 */ 651 public static final String EXTRA_PROGRESS = "android.progress"; 652 653 /** 654 * {@link #extras} key: this is the maximum value supplied to 655 * {@link Builder#setProgress(int, int, boolean)}. 656 */ 657 public static final String EXTRA_PROGRESS_MAX = "android.progressMax"; 658 659 /** 660 * {@link #extras} key: whether the progress bar is indeterminate, supplied to 661 * {@link Builder#setProgress(int, int, boolean)}. 662 */ 663 public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; 664 665 /** 666 * {@link #extras} key: whether {@link #when} should be shown as a count-up timer (specifically 667 * a {@link android.widget.Chronometer}) instead of a timestamp, as supplied to 668 * {@link Builder#setUsesChronometer(boolean)}. 669 */ 670 public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; 671 672 /** 673 * {@link #extras} key: whether {@link #when} should be shown, 674 * as supplied to {@link Builder#setShowWhen(boolean)}. 675 */ 676 public static final String EXTRA_SHOW_WHEN = "android.showWhen"; 677 678 /** 679 * {@link #extras} key: this is a bitmap to be shown in {@link BigPictureStyle} expanded 680 * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}. 681 */ 682 public static final String EXTRA_PICTURE = "android.picture"; 683 684 /** 685 * {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded 686 * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}. 687 */ 688 public static final String EXTRA_TEXT_LINES = "android.textLines"; 689 public static final String EXTRA_TEMPLATE = "android.template"; 690 691 /** 692 * {@link #extras} key: An array of people that this notification relates to, specified 693 * by contacts provider contact URI. 694 */ 695 public static final String EXTRA_PEOPLE = "android.people"; 696 697 /** 698 * @hide 699 * Extra added by NotificationManagerService to indicate whether 700 * the Notifications's score has been modified. 701 */ 702 public static final String EXTRA_SCORE_MODIFIED = "android.scoreModified"; 703 704 /** 705 * Not used. 706 * @hide 707 */ 708 public static final String EXTRA_AS_HEADS_UP = "headsup"; 709 710 /** 711 * Allow certain system-generated notifications to appear before the device is provisioned. 712 * Only available to notifications coming from the android package. 713 * @hide 714 */ 715 public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup"; 716 717 /** 718 * Value for {@link #EXTRA_AS_HEADS_UP}. 719 * @hide 720 */ 721 public static final int HEADS_UP_NEVER = 0; 722 723 /** 724 * Default value for {@link #EXTRA_AS_HEADS_UP}. 725 * @hide 726 */ 727 public static final int HEADS_UP_ALLOWED = 1; 728 729 /** 730 * Value for {@link #EXTRA_AS_HEADS_UP}. 731 * @hide 732 */ 733 public static final int HEADS_UP_REQUESTED = 2; 734 735 /** 736 * Structure to encapsulate a named action that can be shown as part of this notification. 737 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is 738 * selected by the user. 739 * <p> 740 * Apps should use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)} 741 * or {@link Notification.Builder#addAction(Notification.Action)} 742 * to attach actions. 743 */ 744 public static class Action implements Parcelable { 745 private final Bundle mExtras; 746 private RemoteInput[] mRemoteInputs; 747 748 /** 749 * Small icon representing the action. 750 */ 751 public int icon; 752 753 /** 754 * Title of the action. 755 */ 756 public CharSequence title; 757 758 /** 759 * Intent to send when the user invokes this action. May be null, in which case the action 760 * may be rendered in a disabled presentation by the system UI. 761 */ 762 public PendingIntent actionIntent; 763 764 private Action(Parcel in) { 765 icon = in.readInt(); 766 title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); 767 if (in.readInt() == 1) { 768 actionIntent = PendingIntent.CREATOR.createFromParcel(in); 769 } 770 mExtras = in.readBundle(); 771 mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR); 772 } 773 774 /** 775 * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}. 776 */ 777 public Action(int icon, CharSequence title, PendingIntent intent) { 778 this(icon, title, intent, new Bundle(), null); 779 } 780 781 private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, 782 RemoteInput[] remoteInputs) { 783 this.icon = icon; 784 this.title = title; 785 this.actionIntent = intent; 786 this.mExtras = extras != null ? extras : new Bundle(); 787 this.mRemoteInputs = remoteInputs; 788 } 789 790 /** 791 * Get additional metadata carried around with this Action. 792 */ 793 public Bundle getExtras() { 794 return mExtras; 795 } 796 797 /** 798 * Get the list of inputs to be collected from the user when this action is sent. 799 * May return null if no remote inputs were added. 800 */ 801 public RemoteInput[] getRemoteInputs() { 802 return mRemoteInputs; 803 } 804 805 /** 806 * Builder class for {@link Action} objects. 807 */ 808 public static final class Builder { 809 private final int mIcon; 810 private final CharSequence mTitle; 811 private final PendingIntent mIntent; 812 private final Bundle mExtras; 813 private ArrayList<RemoteInput> mRemoteInputs; 814 815 /** 816 * Construct a new builder for {@link Action} object. 817 * @param icon icon to show for this action 818 * @param title the title of the action 819 * @param intent the {@link PendingIntent} to fire when users trigger this action 820 */ 821 public Builder(int icon, CharSequence title, PendingIntent intent) { 822 this(icon, title, intent, new Bundle(), null); 823 } 824 825 /** 826 * Construct a new builder for {@link Action} object using the fields from an 827 * {@link Action}. 828 * @param action the action to read fields from. 829 */ 830 public Builder(Action action) { 831 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras), 832 action.getRemoteInputs()); 833 } 834 835 private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras, 836 RemoteInput[] remoteInputs) { 837 mIcon = icon; 838 mTitle = title; 839 mIntent = intent; 840 mExtras = extras; 841 if (remoteInputs != null) { 842 mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length); 843 Collections.addAll(mRemoteInputs, remoteInputs); 844 } 845 } 846 847 /** 848 * Merge additional metadata into this builder. 849 * 850 * <p>Values within the Bundle will replace existing extras values in this Builder. 851 * 852 * @see Notification.Action#extras 853 */ 854 public Builder addExtras(Bundle extras) { 855 if (extras != null) { 856 mExtras.putAll(extras); 857 } 858 return this; 859 } 860 861 /** 862 * Get the metadata Bundle used by this Builder. 863 * 864 * <p>The returned Bundle is shared with this Builder. 865 */ 866 public Bundle getExtras() { 867 return mExtras; 868 } 869 870 /** 871 * Add an input to be collected from the user when this action is sent. 872 * Response values can be retrieved from the fired intent by using the 873 * {@link RemoteInput#getResultsFromIntent} function. 874 * @param remoteInput a {@link RemoteInput} to add to the action 875 * @return this object for method chaining 876 */ 877 public Builder addRemoteInput(RemoteInput remoteInput) { 878 if (mRemoteInputs == null) { 879 mRemoteInputs = new ArrayList<RemoteInput>(); 880 } 881 mRemoteInputs.add(remoteInput); 882 return this; 883 } 884 885 /** 886 * Apply an extender to this action builder. Extenders may be used to add 887 * metadata or change options on this builder. 888 */ 889 public Builder apply(Extender extender) { 890 extender.applyTo(this); 891 return this; 892 } 893 894 /** 895 * Extender interface for use with {@link #apply}. Extenders may be used to add 896 * metadata or change options on this builder. 897 */ 898 public interface Extender { 899 /** 900 * Apply this extender to a notification action builder. 901 * @param builder the builder to be modified. 902 * @return the build object for chaining. 903 */ 904 public Builder applyTo(Builder builder); 905 } 906 907 /** 908 * Combine all of the options that have been set and return a new {@link Action} 909 * object. 910 * @return the built action 911 */ 912 public Action build() { 913 RemoteInput[] remoteInputs = mRemoteInputs != null 914 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; 915 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs); 916 } 917 } 918 919 @Override 920 public Action clone() { 921 return new Action( 922 icon, 923 title, 924 actionIntent, // safe to alias 925 new Bundle(mExtras), 926 getRemoteInputs()); 927 } 928 @Override 929 public int describeContents() { 930 return 0; 931 } 932 @Override 933 public void writeToParcel(Parcel out, int flags) { 934 out.writeInt(icon); 935 TextUtils.writeToParcel(title, out, flags); 936 if (actionIntent != null) { 937 out.writeInt(1); 938 actionIntent.writeToParcel(out, flags); 939 } else { 940 out.writeInt(0); 941 } 942 out.writeBundle(mExtras); 943 out.writeTypedArray(mRemoteInputs, flags); 944 } 945 public static final Parcelable.Creator<Action> CREATOR = 946 new Parcelable.Creator<Action>() { 947 public Action createFromParcel(Parcel in) { 948 return new Action(in); 949 } 950 public Action[] newArray(int size) { 951 return new Action[size]; 952 } 953 }; 954 } 955 956 /** 957 * Array of all {@link Action} structures attached to this notification by 958 * {@link Builder#addAction(int, CharSequence, PendingIntent)}. Mostly useful for instances of 959 * {@link android.service.notification.NotificationListenerService} that provide an alternative 960 * interface for invoking actions. 961 */ 962 public Action[] actions; 963 964 /** 965 * Replacement version of this notification whose content will be shown 966 * in an insecure context such as atop a secure keyguard. See {@link #visibility} 967 * and {@link #VISIBILITY_PUBLIC}. 968 */ 969 public Notification publicVersion; 970 971 /** 972 * Constructs a Notification object with default values. 973 * You might want to consider using {@link Builder} instead. 974 */ 975 public Notification() 976 { 977 this.when = System.currentTimeMillis(); 978 this.priority = PRIORITY_DEFAULT; 979 } 980 981 /** 982 * @hide 983 */ 984 public Notification(Context context, int icon, CharSequence tickerText, long when, 985 CharSequence contentTitle, CharSequence contentText, Intent contentIntent) 986 { 987 this.when = when; 988 this.icon = icon; 989 this.tickerText = tickerText; 990 setLatestEventInfo(context, contentTitle, contentText, 991 PendingIntent.getActivity(context, 0, contentIntent, 0)); 992 } 993 994 /** 995 * Constructs a Notification object with the information needed to 996 * have a status bar icon without the standard expanded view. 997 * 998 * @param icon The resource id of the icon to put in the status bar. 999 * @param tickerText The text that flows by in the status bar when the notification first 1000 * activates. 1001 * @param when The time to show in the time field. In the System.currentTimeMillis 1002 * timebase. 1003 * 1004 * @deprecated Use {@link Builder} instead. 1005 */ 1006 @Deprecated 1007 public Notification(int icon, CharSequence tickerText, long when) 1008 { 1009 this.icon = icon; 1010 this.tickerText = tickerText; 1011 this.when = when; 1012 } 1013 1014 /** 1015 * Unflatten the notification from a parcel. 1016 */ 1017 public Notification(Parcel parcel) 1018 { 1019 int version = parcel.readInt(); 1020 1021 when = parcel.readLong(); 1022 icon = parcel.readInt(); 1023 number = parcel.readInt(); 1024 if (parcel.readInt() != 0) { 1025 contentIntent = PendingIntent.CREATOR.createFromParcel(parcel); 1026 } 1027 if (parcel.readInt() != 0) { 1028 deleteIntent = PendingIntent.CREATOR.createFromParcel(parcel); 1029 } 1030 if (parcel.readInt() != 0) { 1031 tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 1032 } 1033 if (parcel.readInt() != 0) { 1034 tickerView = RemoteViews.CREATOR.createFromParcel(parcel); 1035 } 1036 if (parcel.readInt() != 0) { 1037 contentView = RemoteViews.CREATOR.createFromParcel(parcel); 1038 } 1039 if (parcel.readInt() != 0) { 1040 largeIcon = Bitmap.CREATOR.createFromParcel(parcel); 1041 } 1042 defaults = parcel.readInt(); 1043 flags = parcel.readInt(); 1044 if (parcel.readInt() != 0) { 1045 sound = Uri.CREATOR.createFromParcel(parcel); 1046 } 1047 1048 audioStreamType = parcel.readInt(); 1049 vibrate = parcel.createLongArray(); 1050 ledARGB = parcel.readInt(); 1051 ledOnMS = parcel.readInt(); 1052 ledOffMS = parcel.readInt(); 1053 iconLevel = parcel.readInt(); 1054 1055 if (parcel.readInt() != 0) { 1056 fullScreenIntent = PendingIntent.CREATOR.createFromParcel(parcel); 1057 } 1058 1059 priority = parcel.readInt(); 1060 1061 category = parcel.readString(); 1062 1063 mGroupKey = parcel.readString(); 1064 1065 mSortKey = parcel.readString(); 1066 1067 extras = parcel.readBundle(); // may be null 1068 1069 actions = parcel.createTypedArray(Action.CREATOR); // may be null 1070 1071 if (parcel.readInt() != 0) { 1072 bigContentView = RemoteViews.CREATOR.createFromParcel(parcel); 1073 } 1074 1075 if (parcel.readInt() != 0) { 1076 headsUpContentView = RemoteViews.CREATOR.createFromParcel(parcel); 1077 } 1078 1079 visibility = parcel.readInt(); 1080 1081 if (parcel.readInt() != 0) { 1082 publicVersion = Notification.CREATOR.createFromParcel(parcel); 1083 } 1084 1085 color = parcel.readInt(); 1086 } 1087 1088 @Override 1089 public Notification clone() { 1090 Notification that = new Notification(); 1091 cloneInto(that, true); 1092 return that; 1093 } 1094 1095 /** 1096 * Copy all (or if heavy is false, all except Bitmaps and RemoteViews) members 1097 * of this into that. 1098 * @hide 1099 */ 1100 public void cloneInto(Notification that, boolean heavy) { 1101 that.when = this.when; 1102 that.icon = this.icon; 1103 that.number = this.number; 1104 1105 // PendingIntents are global, so there's no reason (or way) to clone them. 1106 that.contentIntent = this.contentIntent; 1107 that.deleteIntent = this.deleteIntent; 1108 that.fullScreenIntent = this.fullScreenIntent; 1109 1110 if (this.tickerText != null) { 1111 that.tickerText = this.tickerText.toString(); 1112 } 1113 if (heavy && this.tickerView != null) { 1114 that.tickerView = this.tickerView.clone(); 1115 } 1116 if (heavy && this.contentView != null) { 1117 that.contentView = this.contentView.clone(); 1118 } 1119 if (heavy && this.largeIcon != null) { 1120 that.largeIcon = Bitmap.createBitmap(this.largeIcon); 1121 } 1122 that.iconLevel = this.iconLevel; 1123 that.sound = this.sound; // android.net.Uri is immutable 1124 that.audioStreamType = this.audioStreamType; 1125 1126 final long[] vibrate = this.vibrate; 1127 if (vibrate != null) { 1128 final int N = vibrate.length; 1129 final long[] vib = that.vibrate = new long[N]; 1130 System.arraycopy(vibrate, 0, vib, 0, N); 1131 } 1132 1133 that.ledARGB = this.ledARGB; 1134 that.ledOnMS = this.ledOnMS; 1135 that.ledOffMS = this.ledOffMS; 1136 that.defaults = this.defaults; 1137 1138 that.flags = this.flags; 1139 1140 that.priority = this.priority; 1141 1142 that.category = this.category; 1143 1144 that.mGroupKey = this.mGroupKey; 1145 1146 that.mSortKey = this.mSortKey; 1147 1148 if (this.extras != null) { 1149 try { 1150 that.extras = new Bundle(this.extras); 1151 // will unparcel 1152 that.extras.size(); 1153 } catch (BadParcelableException e) { 1154 Log.e(TAG, "could not unparcel extras from notification: " + this, e); 1155 that.extras = null; 1156 } 1157 } 1158 1159 if (this.actions != null) { 1160 that.actions = new Action[this.actions.length]; 1161 for(int i=0; i<this.actions.length; i++) { 1162 that.actions[i] = this.actions[i].clone(); 1163 } 1164 } 1165 1166 if (heavy && this.bigContentView != null) { 1167 that.bigContentView = this.bigContentView.clone(); 1168 } 1169 1170 if (heavy && this.headsUpContentView != null) { 1171 that.headsUpContentView = this.headsUpContentView.clone(); 1172 } 1173 1174 that.visibility = this.visibility; 1175 1176 if (this.publicVersion != null) { 1177 that.publicVersion = new Notification(); 1178 this.publicVersion.cloneInto(that.publicVersion, heavy); 1179 } 1180 1181 that.color = this.color; 1182 1183 if (!heavy) { 1184 that.lightenPayload(); // will clean out extras 1185 } 1186 } 1187 1188 /** 1189 * Removes heavyweight parts of the Notification object for archival or for sending to 1190 * listeners when the full contents are not necessary. 1191 * @hide 1192 */ 1193 public final void lightenPayload() { 1194 tickerView = null; 1195 contentView = null; 1196 bigContentView = null; 1197 headsUpContentView = null; 1198 largeIcon = null; 1199 if (extras != null) { 1200 extras.remove(Notification.EXTRA_LARGE_ICON); 1201 extras.remove(Notification.EXTRA_LARGE_ICON_BIG); 1202 extras.remove(Notification.EXTRA_PICTURE); 1203 } 1204 } 1205 1206 /** 1207 * Make sure this CharSequence is safe to put into a bundle, which basically 1208 * means it had better not be some custom Parcelable implementation. 1209 * @hide 1210 */ 1211 public static CharSequence safeCharSequence(CharSequence cs) { 1212 if (cs instanceof Parcelable) { 1213 Log.e(TAG, "warning: " + cs.getClass().getCanonicalName() 1214 + " instance is a custom Parcelable and not allowed in Notification"); 1215 return cs.toString(); 1216 } 1217 1218 return cs; 1219 } 1220 1221 public int describeContents() { 1222 return 0; 1223 } 1224 1225 /** 1226 * Flatten this notification from a parcel. 1227 */ 1228 public void writeToParcel(Parcel parcel, int flags) 1229 { 1230 parcel.writeInt(1); 1231 1232 parcel.writeLong(when); 1233 parcel.writeInt(icon); 1234 parcel.writeInt(number); 1235 if (contentIntent != null) { 1236 parcel.writeInt(1); 1237 contentIntent.writeToParcel(parcel, 0); 1238 } else { 1239 parcel.writeInt(0); 1240 } 1241 if (deleteIntent != null) { 1242 parcel.writeInt(1); 1243 deleteIntent.writeToParcel(parcel, 0); 1244 } else { 1245 parcel.writeInt(0); 1246 } 1247 if (tickerText != null) { 1248 parcel.writeInt(1); 1249 TextUtils.writeToParcel(tickerText, parcel, flags); 1250 } else { 1251 parcel.writeInt(0); 1252 } 1253 if (tickerView != null) { 1254 parcel.writeInt(1); 1255 tickerView.writeToParcel(parcel, 0); 1256 } else { 1257 parcel.writeInt(0); 1258 } 1259 if (contentView != null) { 1260 parcel.writeInt(1); 1261 contentView.writeToParcel(parcel, 0); 1262 } else { 1263 parcel.writeInt(0); 1264 } 1265 if (largeIcon != null) { 1266 parcel.writeInt(1); 1267 largeIcon.writeToParcel(parcel, 0); 1268 } else { 1269 parcel.writeInt(0); 1270 } 1271 1272 parcel.writeInt(defaults); 1273 parcel.writeInt(this.flags); 1274 1275 if (sound != null) { 1276 parcel.writeInt(1); 1277 sound.writeToParcel(parcel, 0); 1278 } else { 1279 parcel.writeInt(0); 1280 } 1281 parcel.writeInt(audioStreamType); 1282 parcel.writeLongArray(vibrate); 1283 parcel.writeInt(ledARGB); 1284 parcel.writeInt(ledOnMS); 1285 parcel.writeInt(ledOffMS); 1286 parcel.writeInt(iconLevel); 1287 1288 if (fullScreenIntent != null) { 1289 parcel.writeInt(1); 1290 fullScreenIntent.writeToParcel(parcel, 0); 1291 } else { 1292 parcel.writeInt(0); 1293 } 1294 1295 parcel.writeInt(priority); 1296 1297 parcel.writeString(category); 1298 1299 parcel.writeString(mGroupKey); 1300 1301 parcel.writeString(mSortKey); 1302 1303 parcel.writeBundle(extras); // null ok 1304 1305 parcel.writeTypedArray(actions, 0); // null ok 1306 1307 if (bigContentView != null) { 1308 parcel.writeInt(1); 1309 bigContentView.writeToParcel(parcel, 0); 1310 } else { 1311 parcel.writeInt(0); 1312 } 1313 1314 if (headsUpContentView != null) { 1315 parcel.writeInt(1); 1316 headsUpContentView.writeToParcel(parcel, 0); 1317 } else { 1318 parcel.writeInt(0); 1319 } 1320 1321 parcel.writeInt(visibility); 1322 1323 if (publicVersion != null) { 1324 parcel.writeInt(1); 1325 publicVersion.writeToParcel(parcel, 0); 1326 } else { 1327 parcel.writeInt(0); 1328 } 1329 1330 parcel.writeInt(color); 1331 } 1332 1333 /** 1334 * Parcelable.Creator that instantiates Notification objects 1335 */ 1336 public static final Parcelable.Creator<Notification> CREATOR 1337 = new Parcelable.Creator<Notification>() 1338 { 1339 public Notification createFromParcel(Parcel parcel) 1340 { 1341 return new Notification(parcel); 1342 } 1343 1344 public Notification[] newArray(int size) 1345 { 1346 return new Notification[size]; 1347 } 1348 }; 1349 1350 /** 1351 * Sets the {@link #contentView} field to be a view with the standard "Latest Event" 1352 * layout. 1353 * 1354 * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields 1355 * in the view.</p> 1356 * @param context The context for your application / activity. 1357 * @param contentTitle The title that goes in the expanded entry. 1358 * @param contentText The text that goes in the expanded entry. 1359 * @param contentIntent The intent to launch when the user clicks the expanded notification. 1360 * If this is an activity, it must include the 1361 * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires 1362 * that you take care of task management as described in the 1363 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back 1364 * Stack</a> document. 1365 * 1366 * @deprecated Use {@link Builder} instead. 1367 */ 1368 @Deprecated 1369 public void setLatestEventInfo(Context context, 1370 CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) { 1371 Notification.Builder builder = new Notification.Builder(context); 1372 1373 // First, ensure that key pieces of information that may have been set directly 1374 // are preserved 1375 builder.setWhen(this.when); 1376 builder.setSmallIcon(this.icon); 1377 builder.setPriority(this.priority); 1378 builder.setTicker(this.tickerText); 1379 builder.setNumber(this.number); 1380 builder.mFlags = this.flags; 1381 builder.setSound(this.sound, this.audioStreamType); 1382 builder.setDefaults(this.defaults); 1383 builder.setVibrate(this.vibrate); 1384 1385 // now apply the latestEventInfo fields 1386 if (contentTitle != null) { 1387 builder.setContentTitle(contentTitle); 1388 } 1389 if (contentText != null) { 1390 builder.setContentText(contentText); 1391 } 1392 builder.setContentIntent(contentIntent); 1393 builder.buildInto(this); 1394 } 1395 1396 @Override 1397 public String toString() { 1398 StringBuilder sb = new StringBuilder(); 1399 sb.append("Notification(pri="); 1400 sb.append(priority); 1401 sb.append(" contentView="); 1402 if (contentView != null) { 1403 sb.append(contentView.getPackage()); 1404 sb.append("/0x"); 1405 sb.append(Integer.toHexString(contentView.getLayoutId())); 1406 } else { 1407 sb.append("null"); 1408 } 1409 // TODO(dsandler): defaults take precedence over local values, so reorder the branches below 1410 sb.append(" vibrate="); 1411 if ((this.defaults & DEFAULT_VIBRATE) != 0) { 1412 sb.append("default"); 1413 } else if (this.vibrate != null) { 1414 int N = this.vibrate.length-1; 1415 sb.append("["); 1416 for (int i=0; i<N; i++) { 1417 sb.append(this.vibrate[i]); 1418 sb.append(','); 1419 } 1420 if (N != -1) { 1421 sb.append(this.vibrate[N]); 1422 } 1423 sb.append("]"); 1424 } else { 1425 sb.append("null"); 1426 } 1427 sb.append(" sound="); 1428 if ((this.defaults & DEFAULT_SOUND) != 0) { 1429 sb.append("default"); 1430 } else if (this.sound != null) { 1431 sb.append(this.sound.toString()); 1432 } else { 1433 sb.append("null"); 1434 } 1435 sb.append(" defaults=0x"); 1436 sb.append(Integer.toHexString(this.defaults)); 1437 sb.append(" flags=0x"); 1438 sb.append(Integer.toHexString(this.flags)); 1439 sb.append(String.format(" color=0x%08x", this.color)); 1440 if (this.category != null) { 1441 sb.append(" category="); 1442 sb.append(this.category); 1443 } 1444 if (this.mGroupKey != null) { 1445 sb.append(" groupKey="); 1446 sb.append(this.mGroupKey); 1447 } 1448 if (this.mSortKey != null) { 1449 sb.append(" sortKey="); 1450 sb.append(this.mSortKey); 1451 } 1452 if (actions != null) { 1453 sb.append(" "); 1454 sb.append(actions.length); 1455 sb.append(" action"); 1456 if (actions.length > 1) sb.append("s"); 1457 } 1458 sb.append(")"); 1459 return sb.toString(); 1460 } 1461 1462 /** {@hide} */ 1463 public void setUser(UserHandle user) { 1464 if (user.getIdentifier() == UserHandle.USER_ALL) { 1465 user = UserHandle.OWNER; 1466 } 1467 if (tickerView != null) { 1468 tickerView.setUser(user); 1469 } 1470 if (contentView != null) { 1471 contentView.setUser(user); 1472 } 1473 if (bigContentView != null) { 1474 bigContentView.setUser(user); 1475 } 1476 if (headsUpContentView != null) { 1477 headsUpContentView.setUser(user); 1478 } 1479 } 1480 1481 /** 1482 * Builder class for {@link Notification} objects. 1483 * 1484 * Provides a convenient way to set the various fields of a {@link Notification} and generate 1485 * content views using the platform's notification layout template. If your app supports 1486 * versions of Android as old as API level 4, you can instead use 1487 * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}, 1488 * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support 1489 * library</a>. 1490 * 1491 * <p>Example: 1492 * 1493 * <pre class="prettyprint"> 1494 * Notification noti = new Notification.Builder(mContext) 1495 * .setContentTitle("New mail from " + sender.toString()) 1496 * .setContentText(subject) 1497 * .setSmallIcon(R.drawable.new_mail) 1498 * .setLargeIcon(aBitmap) 1499 * .build(); 1500 * </pre> 1501 */ 1502 public static class Builder { 1503 private static final int MAX_ACTION_BUTTONS = 3; 1504 1505 private Context mContext; 1506 1507 private long mWhen; 1508 private int mSmallIcon; 1509 private int mSmallIconLevel; 1510 private int mNumber; 1511 private CharSequence mContentTitle; 1512 private CharSequence mContentText; 1513 private CharSequence mContentInfo; 1514 private CharSequence mSubText; 1515 private PendingIntent mContentIntent; 1516 private RemoteViews mContentView; 1517 private PendingIntent mDeleteIntent; 1518 private PendingIntent mFullScreenIntent; 1519 private CharSequence mTickerText; 1520 private RemoteViews mTickerView; 1521 private Bitmap mLargeIcon; 1522 private Uri mSound; 1523 private int mAudioStreamType; 1524 private long[] mVibrate; 1525 private int mLedArgb; 1526 private int mLedOnMs; 1527 private int mLedOffMs; 1528 private int mDefaults; 1529 private int mFlags; 1530 private int mProgressMax; 1531 private int mProgress; 1532 private boolean mProgressIndeterminate; 1533 private String mCategory; 1534 private String mGroupKey; 1535 private String mSortKey; 1536 private Bundle mExtras; 1537 private int mPriority; 1538 private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); 1539 private boolean mUseChronometer; 1540 private Style mStyle; 1541 private boolean mShowWhen = true; 1542 private int mVisibility = VISIBILITY_PRIVATE; 1543 private Notification mPublicVersion = null; 1544 private final NotificationColorUtil mColorUtil; 1545 private ArrayList<String> mPeople; 1546 private boolean mPreQuantum; 1547 private int mColor = COLOR_DEFAULT; 1548 1549 /** 1550 * Constructs a new Builder with the defaults: 1551 * 1552 1553 * <table> 1554 * <tr><th align=right>priority</th> 1555 * <td>{@link #PRIORITY_DEFAULT}</td></tr> 1556 * <tr><th align=right>when</th> 1557 * <td>now ({@link System#currentTimeMillis()})</td></tr> 1558 * <tr><th align=right>audio stream</th> 1559 * <td>{@link #STREAM_DEFAULT}</td></tr> 1560 * </table> 1561 * 1562 1563 * @param context 1564 * A {@link Context} that will be used by the Builder to construct the 1565 * RemoteViews. The Context will not be held past the lifetime of this Builder 1566 * object. 1567 */ 1568 public Builder(Context context) { 1569 mContext = context; 1570 1571 // Set defaults to match the defaults of a Notification 1572 mWhen = System.currentTimeMillis(); 1573 mAudioStreamType = STREAM_DEFAULT; 1574 mPriority = PRIORITY_DEFAULT; 1575 mPeople = new ArrayList<String>(); 1576 1577 mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L; 1578 mColorUtil = NotificationColorUtil.getInstance(); 1579 } 1580 1581 /** 1582 * Add a timestamp pertaining to the notification (usually the time the event occurred). 1583 * It will be shown in the notification content view by default; use 1584 * {@link #setShowWhen(boolean) setShowWhen} to control this. 1585 * 1586 * @see Notification#when 1587 */ 1588 public Builder setWhen(long when) { 1589 mWhen = when; 1590 return this; 1591 } 1592 1593 /** 1594 * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown 1595 * in the content view. 1596 */ 1597 public Builder setShowWhen(boolean show) { 1598 mShowWhen = show; 1599 return this; 1600 } 1601 1602 /** 1603 * Show the {@link Notification#when} field as a stopwatch. 1604 * 1605 * Instead of presenting <code>when</code> as a timestamp, the notification will show an 1606 * automatically updating display of the minutes and seconds since <code>when</code>. 1607 * 1608 * Useful when showing an elapsed time (like an ongoing phone call). 1609 * 1610 * @see android.widget.Chronometer 1611 * @see Notification#when 1612 */ 1613 public Builder setUsesChronometer(boolean b) { 1614 mUseChronometer = b; 1615 return this; 1616 } 1617 1618 /** 1619 * Set the small icon resource, which will be used to represent the notification in the 1620 * status bar. 1621 * 1622 1623 * The platform template for the expanded view will draw this icon in the left, unless a 1624 * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small 1625 * icon will be moved to the right-hand side. 1626 * 1627 1628 * @param icon 1629 * A resource ID in the application's package of the drawable to use. 1630 * @see Notification#icon 1631 */ 1632 public Builder setSmallIcon(int icon) { 1633 mSmallIcon = icon; 1634 return this; 1635 } 1636 1637 /** 1638 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional 1639 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable 1640 * LevelListDrawable}. 1641 * 1642 * @param icon A resource ID in the application's package of the drawable to use. 1643 * @param level The level to use for the icon. 1644 * 1645 * @see Notification#icon 1646 * @see Notification#iconLevel 1647 */ 1648 public Builder setSmallIcon(int icon, int level) { 1649 mSmallIcon = icon; 1650 mSmallIconLevel = level; 1651 return this; 1652 } 1653 1654 /** 1655 * Set the first line of text in the platform notification template. 1656 */ 1657 public Builder setContentTitle(CharSequence title) { 1658 mContentTitle = safeCharSequence(title); 1659 return this; 1660 } 1661 1662 /** 1663 * Set the second line of text in the platform notification template. 1664 */ 1665 public Builder setContentText(CharSequence text) { 1666 mContentText = safeCharSequence(text); 1667 return this; 1668 } 1669 1670 /** 1671 * Set the third line of text in the platform notification template. 1672 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the 1673 * same location in the standard template. 1674 */ 1675 public Builder setSubText(CharSequence text) { 1676 mSubText = safeCharSequence(text); 1677 return this; 1678 } 1679 1680 /** 1681 * Set the large number at the right-hand side of the notification. This is 1682 * equivalent to setContentInfo, although it might show the number in a different 1683 * font size for readability. 1684 */ 1685 public Builder setNumber(int number) { 1686 mNumber = number; 1687 return this; 1688 } 1689 1690 /** 1691 * A small piece of additional information pertaining to this notification. 1692 * 1693 * The platform template will draw this on the last line of the notification, at the far 1694 * right (to the right of a smallIcon if it has been placed there). 1695 */ 1696 public Builder setContentInfo(CharSequence info) { 1697 mContentInfo = safeCharSequence(info); 1698 return this; 1699 } 1700 1701 /** 1702 * Set the progress this notification represents. 1703 * 1704 * The platform template will represent this using a {@link ProgressBar}. 1705 */ 1706 public Builder setProgress(int max, int progress, boolean indeterminate) { 1707 mProgressMax = max; 1708 mProgress = progress; 1709 mProgressIndeterminate = indeterminate; 1710 return this; 1711 } 1712 1713 /** 1714 * Supply a custom RemoteViews to use instead of the platform template. 1715 * 1716 * @see Notification#contentView 1717 */ 1718 public Builder setContent(RemoteViews views) { 1719 mContentView = views; 1720 return this; 1721 } 1722 1723 /** 1724 * Supply a {@link PendingIntent} to be sent when the notification is clicked. 1725 * 1726 * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you 1727 * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use 1728 * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)} 1729 * to assign PendingIntents to individual views in that custom layout (i.e., to create 1730 * clickable buttons inside the notification view). 1731 * 1732 * @see Notification#contentIntent Notification.contentIntent 1733 */ 1734 public Builder setContentIntent(PendingIntent intent) { 1735 mContentIntent = intent; 1736 return this; 1737 } 1738 1739 /** 1740 * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user. 1741 * 1742 * @see Notification#deleteIntent 1743 */ 1744 public Builder setDeleteIntent(PendingIntent intent) { 1745 mDeleteIntent = intent; 1746 return this; 1747 } 1748 1749 /** 1750 * An intent to launch instead of posting the notification to the status bar. 1751 * Only for use with extremely high-priority notifications demanding the user's 1752 * <strong>immediate</strong> attention, such as an incoming phone call or 1753 * alarm clock that the user has explicitly set to a particular time. 1754 * If this facility is used for something else, please give the user an option 1755 * to turn it off and use a normal notification, as this can be extremely 1756 * disruptive. 1757 * 1758 * @param intent The pending intent to launch. 1759 * @param highPriority Passing true will cause this notification to be sent 1760 * even if other notifications are suppressed. 1761 * 1762 * @see Notification#fullScreenIntent 1763 */ 1764 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { 1765 mFullScreenIntent = intent; 1766 setFlag(FLAG_HIGH_PRIORITY, highPriority); 1767 return this; 1768 } 1769 1770 /** 1771 * Set the "ticker" text which is displayed in the status bar when the notification first 1772 * arrives. 1773 * 1774 * @see Notification#tickerText 1775 */ 1776 public Builder setTicker(CharSequence tickerText) { 1777 mTickerText = safeCharSequence(tickerText); 1778 return this; 1779 } 1780 1781 /** 1782 * Set the text that is displayed in the status bar when the notification first 1783 * arrives, and also a RemoteViews object that may be displayed instead on some 1784 * devices. 1785 * 1786 * @see Notification#tickerText 1787 * @see Notification#tickerView 1788 */ 1789 public Builder setTicker(CharSequence tickerText, RemoteViews views) { 1790 mTickerText = safeCharSequence(tickerText); 1791 mTickerView = views; 1792 return this; 1793 } 1794 1795 /** 1796 * Add a large icon to the notification (and the ticker on some devices). 1797 * 1798 * In the platform template, this image will be shown on the left of the notification view 1799 * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side). 1800 * 1801 * @see Notification#largeIcon 1802 */ 1803 public Builder setLargeIcon(Bitmap icon) { 1804 mLargeIcon = icon; 1805 return this; 1806 } 1807 1808 /** 1809 * Set the sound to play. 1810 * 1811 * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications. 1812 * 1813 * @see Notification#sound 1814 */ 1815 public Builder setSound(Uri sound) { 1816 mSound = sound; 1817 mAudioStreamType = STREAM_DEFAULT; 1818 return this; 1819 } 1820 1821 /** 1822 * Set the sound to play, along with a specific stream on which to play it. 1823 * 1824 * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants. 1825 * 1826 * @see Notification#sound 1827 */ 1828 public Builder setSound(Uri sound, int streamType) { 1829 mSound = sound; 1830 mAudioStreamType = streamType; 1831 return this; 1832 } 1833 1834 /** 1835 * Set the vibration pattern to use. 1836 * 1837 1838 * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the 1839 * <code>pattern</code> parameter. 1840 * 1841 1842 * @see Notification#vibrate 1843 */ 1844 public Builder setVibrate(long[] pattern) { 1845 mVibrate = pattern; 1846 return this; 1847 } 1848 1849 /** 1850 * Set the desired color for the indicator LED on the device, as well as the 1851 * blink duty cycle (specified in milliseconds). 1852 * 1853 1854 * Not all devices will honor all (or even any) of these values. 1855 * 1856 1857 * @see Notification#ledARGB 1858 * @see Notification#ledOnMS 1859 * @see Notification#ledOffMS 1860 */ 1861 public Builder setLights(int argb, int onMs, int offMs) { 1862 mLedArgb = argb; 1863 mLedOnMs = onMs; 1864 mLedOffMs = offMs; 1865 return this; 1866 } 1867 1868 /** 1869 * Set whether this is an "ongoing" notification. 1870 * 1871 1872 * Ongoing notifications cannot be dismissed by the user, so your application or service 1873 * must take care of canceling them. 1874 * 1875 1876 * They are typically used to indicate a background task that the user is actively engaged 1877 * with (e.g., playing music) or is pending in some way and therefore occupying the device 1878 * (e.g., a file download, sync operation, active network connection). 1879 * 1880 1881 * @see Notification#FLAG_ONGOING_EVENT 1882 * @see Service#setForeground(boolean) 1883 */ 1884 public Builder setOngoing(boolean ongoing) { 1885 setFlag(FLAG_ONGOING_EVENT, ongoing); 1886 return this; 1887 } 1888 1889 /** 1890 * Set this flag if you would only like the sound, vibrate 1891 * and ticker to be played if the notification is not already showing. 1892 * 1893 * @see Notification#FLAG_ONLY_ALERT_ONCE 1894 */ 1895 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { 1896 setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); 1897 return this; 1898 } 1899 1900 /** 1901 * Make this notification automatically dismissed when the user touches it. The 1902 * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens. 1903 * 1904 * @see Notification#FLAG_AUTO_CANCEL 1905 */ 1906 public Builder setAutoCancel(boolean autoCancel) { 1907 setFlag(FLAG_AUTO_CANCEL, autoCancel); 1908 return this; 1909 } 1910 1911 /** 1912 * Set whether or not this notification should not bridge to other devices. 1913 * 1914 * <p>Some notifications can be bridged to other devices for remote display. 1915 * This hint can be set to recommend this notification not be bridged. 1916 */ 1917 public Builder setLocalOnly(boolean localOnly) { 1918 setFlag(FLAG_LOCAL_ONLY, localOnly); 1919 return this; 1920 } 1921 1922 /** 1923 * Set which notification properties will be inherited from system defaults. 1924 * <p> 1925 * The value should be one or more of the following fields combined with 1926 * bitwise-or: 1927 * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. 1928 * <p> 1929 * For all default values, use {@link #DEFAULT_ALL}. 1930 */ 1931 public Builder setDefaults(int defaults) { 1932 mDefaults = defaults; 1933 return this; 1934 } 1935 1936 /** 1937 * Set the priority of this notification. 1938 * 1939 * @see Notification#priority 1940 */ 1941 public Builder setPriority(@Priority int pri) { 1942 mPriority = pri; 1943 return this; 1944 } 1945 1946 /** 1947 * Set the notification category. 1948 * 1949 * @see Notification#category 1950 */ 1951 public Builder setCategory(String category) { 1952 mCategory = category; 1953 return this; 1954 } 1955 1956 /** 1957 * Add a person that is relevant to this notification. 1958 * 1959 * @see Notification#EXTRA_PEOPLE 1960 */ 1961 public Builder addPerson(String handle) { 1962 mPeople.add(handle); 1963 return this; 1964 } 1965 1966 /** 1967 * Set this notification to be part of a group of notifications sharing the same key. 1968 * Grouped notifications may display in a cluster or stack on devices which 1969 * support such rendering. 1970 * 1971 * <p>To make this notification the summary for its group, also call 1972 * {@link #setGroupSummary}. A sort order can be specified for group members by using 1973 * {@link #setSortKey}. 1974 * @param groupKey The group key of the group. 1975 * @return this object for method chaining 1976 */ 1977 public Builder setGroup(String groupKey) { 1978 mGroupKey = groupKey; 1979 return this; 1980 } 1981 1982 /** 1983 * Set this notification to be the group summary for a group of notifications. 1984 * Grouped notifications may display in a cluster or stack on devices which 1985 * support such rendering. Requires a group key also be set using {@link #setGroup}. 1986 * @param isGroupSummary Whether this notification should be a group summary. 1987 * @return this object for method chaining 1988 */ 1989 public Builder setGroupSummary(boolean isGroupSummary) { 1990 setFlag(FLAG_GROUP_SUMMARY, isGroupSummary); 1991 return this; 1992 } 1993 1994 /** 1995 * Set a sort key that orders this notification among other notifications from the 1996 * same package. This can be useful if an external sort was already applied and an app 1997 * would like to preserve this. Notifications will be sorted lexicographically using this 1998 * value, although providing different priorities in addition to providing sort key may 1999 * cause this value to be ignored. 2000 * 2001 * <p>This sort key can also be used to order members of a notification group. See 2002 * {@link Builder#setGroup}. 2003 * 2004 * @see String#compareTo(String) 2005 */ 2006 public Builder setSortKey(String sortKey) { 2007 mSortKey = sortKey; 2008 return this; 2009 } 2010 2011 /** 2012 * Merge additional metadata into this notification. 2013 * 2014 * <p>Values within the Bundle will replace existing extras values in this Builder. 2015 * 2016 * @see Notification#extras 2017 */ 2018 public Builder addExtras(Bundle extras) { 2019 if (extras != null) { 2020 if (mExtras == null) { 2021 mExtras = new Bundle(extras); 2022 } else { 2023 mExtras.putAll(extras); 2024 } 2025 } 2026 return this; 2027 } 2028 2029 /** 2030 * Set metadata for this notification. 2031 * 2032 * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's 2033 * current contents are copied into the Notification each time {@link #build()} is 2034 * called. 2035 * 2036 * <p>Replaces any existing extras values with those from the provided Bundle. 2037 * Use {@link #addExtras} to merge in metadata instead. 2038 * 2039 * @see Notification#extras 2040 */ 2041 public Builder setExtras(Bundle extras) { 2042 mExtras = extras; 2043 return this; 2044 } 2045 2046 /** 2047 * Get the current metadata Bundle used by this notification Builder. 2048 * 2049 * <p>The returned Bundle is shared with this Builder. 2050 * 2051 * <p>The current contents of this Bundle are copied into the Notification each time 2052 * {@link #build()} is called. 2053 * 2054 * @see Notification#extras 2055 */ 2056 public Bundle getExtras() { 2057 if (mExtras == null) { 2058 mExtras = new Bundle(); 2059 } 2060 return mExtras; 2061 } 2062 2063 /** 2064 * Add an action to this notification. Actions are typically displayed by 2065 * the system as a button adjacent to the notification content. 2066 * <p> 2067 * Every action must have an icon (32dp square and matching the 2068 * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo 2069 * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}. 2070 * <p> 2071 * A notification in its expanded form can display up to 3 actions, from left to right in 2072 * the order they were added. Actions will not be displayed when the notification is 2073 * collapsed, however, so be sure that any essential functions may be accessed by the user 2074 * in some other way (for example, in the Activity pointed to by {@link #contentIntent}). 2075 * 2076 * @param icon Resource ID of a drawable that represents the action. 2077 * @param title Text describing the action. 2078 * @param intent PendingIntent to be fired when the action is invoked. 2079 */ 2080 public Builder addAction(int icon, CharSequence title, PendingIntent intent) { 2081 mActions.add(new Action(icon, safeCharSequence(title), intent)); 2082 return this; 2083 } 2084 2085 /** 2086 * Add an action to this notification. Actions are typically displayed by 2087 * the system as a button adjacent to the notification content. 2088 * <p> 2089 * Every action must have an icon (32dp square and matching the 2090 * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo 2091 * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}. 2092 * <p> 2093 * A notification in its expanded form can display up to 3 actions, from left to right in 2094 * the order they were added. Actions will not be displayed when the notification is 2095 * collapsed, however, so be sure that any essential functions may be accessed by the user 2096 * in some other way (for example, in the Activity pointed to by {@link #contentIntent}). 2097 * 2098 * @param action The action to add. 2099 */ 2100 public Builder addAction(Action action) { 2101 mActions.add(action); 2102 return this; 2103 } 2104 2105 /** 2106 * Add a rich notification style to be applied at build time. 2107 * 2108 * @param style Object responsible for modifying the notification style. 2109 */ 2110 public Builder setStyle(Style style) { 2111 if (mStyle != style) { 2112 mStyle = style; 2113 if (mStyle != null) { 2114 mStyle.setBuilder(this); 2115 } 2116 } 2117 return this; 2118 } 2119 2120 /** 2121 * Specify the value of {@link #visibility}. 2122 * 2123 * @param visibility One of {@link #VISIBILITY_PRIVATE} (the default), 2124 * {@link #VISIBILITY_SECRET}, or {@link #VISIBILITY_PUBLIC}. 2125 * 2126 * @return The same Builder. 2127 */ 2128 public Builder setVisibility(int visibility) { 2129 mVisibility = visibility; 2130 return this; 2131 } 2132 2133 /** 2134 * Supply a replacement Notification whose contents should be shown in insecure contexts 2135 * (i.e. atop the secure lockscreen). See {@link #visibility} and {@link #VISIBILITY_PUBLIC}. 2136 * @param n A replacement notification, presumably with some or all info redacted. 2137 * @return The same Builder. 2138 */ 2139 public Builder setPublicVersion(Notification n) { 2140 mPublicVersion = n; 2141 return this; 2142 } 2143 2144 /** 2145 * Apply an extender to this notification builder. Extenders may be used to add 2146 * metadata or change options on this builder. 2147 */ 2148 public Builder apply(Extender extender) { 2149 extender.applyTo(this); 2150 return this; 2151 } 2152 2153 /** 2154 * Extender interface for use with {@link #apply}. Extenders may be used to add 2155 * metadata or change options on this builder. 2156 */ 2157 public interface Extender { 2158 /** 2159 * Apply this extender to a notification builder. 2160 * @param builder the builder to be modified. 2161 * @return the build object for chaining. 2162 */ 2163 public Builder applyTo(Builder builder); 2164 } 2165 2166 private void setFlag(int mask, boolean value) { 2167 if (value) { 2168 mFlags |= mask; 2169 } else { 2170 mFlags &= ~mask; 2171 } 2172 } 2173 2174 /** 2175 * Sets {@link Notification#color}. 2176 * 2177 * @param argb The accent color to use 2178 * 2179 * @return The same Builder. 2180 */ 2181 public Builder setColor(int argb) { 2182 mColor = argb; 2183 return this; 2184 } 2185 2186 private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) { 2187 RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId); 2188 boolean showLine3 = false; 2189 boolean showLine2 = false; 2190 2191 if (mPriority < PRIORITY_LOW) { 2192 // TODO: Low priority presentation 2193 } 2194 if (mLargeIcon != null) { 2195 contentView.setImageViewBitmap(R.id.icon, mLargeIcon); 2196 processLargeIcon(mLargeIcon, contentView); 2197 contentView.setImageViewResource(R.id.right_icon, mSmallIcon); 2198 contentView.setViewVisibility(R.id.right_icon, View.VISIBLE); 2199 processSmallRightIcon(mSmallIcon, contentView); 2200 } else { // small icon at left 2201 contentView.setImageViewResource(R.id.icon, mSmallIcon); 2202 contentView.setViewVisibility(R.id.icon, View.VISIBLE); 2203 processSmallIconAsLarge(mSmallIcon, contentView); 2204 } 2205 if (mContentTitle != null) { 2206 contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle)); 2207 } 2208 if (mContentText != null) { 2209 contentView.setTextViewText(R.id.text, processLegacyText(mContentText)); 2210 showLine3 = true; 2211 } 2212 if (mContentInfo != null) { 2213 contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo)); 2214 contentView.setViewVisibility(R.id.info, View.VISIBLE); 2215 showLine3 = true; 2216 } else if (mNumber > 0) { 2217 final int tooBig = mContext.getResources().getInteger( 2218 R.integer.status_bar_notification_info_maxnum); 2219 if (mNumber > tooBig) { 2220 contentView.setTextViewText(R.id.info, processLegacyText( 2221 mContext.getResources().getString( 2222 R.string.status_bar_notification_info_overflow))); 2223 } else { 2224 NumberFormat f = NumberFormat.getIntegerInstance(); 2225 contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber))); 2226 } 2227 contentView.setViewVisibility(R.id.info, View.VISIBLE); 2228 showLine3 = true; 2229 } else { 2230 contentView.setViewVisibility(R.id.info, View.GONE); 2231 } 2232 2233 // Need to show three lines? 2234 if (mSubText != null) { 2235 contentView.setTextViewText(R.id.text, processLegacyText(mSubText)); 2236 if (mContentText != null) { 2237 contentView.setTextViewText(R.id.text2, processLegacyText(mContentText)); 2238 contentView.setViewVisibility(R.id.text2, View.VISIBLE); 2239 showLine2 = true; 2240 } else { 2241 contentView.setViewVisibility(R.id.text2, View.GONE); 2242 } 2243 } else { 2244 contentView.setViewVisibility(R.id.text2, View.GONE); 2245 if (mProgressMax != 0 || mProgressIndeterminate) { 2246 contentView.setProgressBar( 2247 R.id.progress, mProgressMax, mProgress, mProgressIndeterminate); 2248 contentView.setViewVisibility(R.id.progress, View.VISIBLE); 2249 showLine2 = true; 2250 } else { 2251 contentView.setViewVisibility(R.id.progress, View.GONE); 2252 } 2253 } 2254 if (showLine2) { 2255 if (fitIn1U) { 2256 // need to shrink all the type to make sure everything fits 2257 final Resources res = mContext.getResources(); 2258 final float subTextSize = res.getDimensionPixelSize( 2259 R.dimen.notification_subtext_size); 2260 contentView.setTextViewTextSize(R.id.text, TypedValue.COMPLEX_UNIT_PX, subTextSize); 2261 } 2262 // vertical centering 2263 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0); 2264 } 2265 2266 if (mWhen != 0 && mShowWhen) { 2267 if (mUseChronometer) { 2268 contentView.setViewVisibility(R.id.chronometer, View.VISIBLE); 2269 contentView.setLong(R.id.chronometer, "setBase", 2270 mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis())); 2271 contentView.setBoolean(R.id.chronometer, "setStarted", true); 2272 } else { 2273 contentView.setViewVisibility(R.id.time, View.VISIBLE); 2274 contentView.setLong(R.id.time, "setTime", mWhen); 2275 } 2276 } else { 2277 contentView.setViewVisibility(R.id.time, View.GONE); 2278 } 2279 2280 contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE); 2281 contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE); 2282 return contentView; 2283 } 2284 2285 private RemoteViews applyStandardTemplateWithActions(int layoutId) { 2286 RemoteViews big = applyStandardTemplate(layoutId, false); 2287 2288 int N = mActions.size(); 2289 if (N > 0) { 2290 // Log.d("Notification", "has actions: " + mContentText); 2291 big.setViewVisibility(R.id.actions, View.VISIBLE); 2292 big.setViewVisibility(R.id.action_divider, View.VISIBLE); 2293 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; 2294 big.removeAllViews(R.id.actions); 2295 for (int i=0; i<N; i++) { 2296 final RemoteViews button = generateActionButton(mActions.get(i)); 2297 //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title); 2298 big.addView(R.id.actions, button); 2299 } 2300 } 2301 return big; 2302 } 2303 2304 private RemoteViews makeContentView() { 2305 if (mContentView != null) { 2306 return mContentView; 2307 } else { 2308 return applyStandardTemplate(getBaseLayoutResource(), true); // no more special large_icon flavor 2309 } 2310 } 2311 2312 private RemoteViews makeTickerView() { 2313 if (mTickerView != null) { 2314 return mTickerView; 2315 } else { 2316 if (mContentView == null) { 2317 return applyStandardTemplate(mLargeIcon == null 2318 ? R.layout.status_bar_latest_event_ticker 2319 : R.layout.status_bar_latest_event_ticker_large_icon, true); 2320 } else { 2321 return null; 2322 } 2323 } 2324 } 2325 2326 private RemoteViews makeBigContentView() { 2327 if (mActions.size() == 0) return null; 2328 2329 return applyStandardTemplateWithActions(getBigBaseLayoutResource()); 2330 } 2331 2332 private RemoteViews makeHeadsUpContentView() { 2333 if (mActions.size() == 0) return null; 2334 2335 return applyStandardTemplateWithActions(getBigBaseLayoutResource()); 2336 } 2337 2338 2339 private RemoteViews generateActionButton(Action action) { 2340 final boolean tombstone = (action.actionIntent == null); 2341 RemoteViews button = new RemoteViews(mContext.getPackageName(), 2342 tombstone ? getActionTombstoneLayoutResource() 2343 : getActionLayoutResource()); 2344 button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0); 2345 button.setTextViewText(R.id.action0, processLegacyText(action.title)); 2346 if (!tombstone) { 2347 button.setOnClickPendingIntent(R.id.action0, action.actionIntent); 2348 } 2349 button.setContentDescription(R.id.action0, action.title); 2350 processLegacyAction(action, button); 2351 return button; 2352 } 2353 2354 /** 2355 * @return Whether we are currently building a notification from a legacy (an app that 2356 * doesn't create quantum notifications by itself) app. 2357 */ 2358 private boolean isLegacy() { 2359 return mColorUtil != null; 2360 } 2361 2362 private void processLegacyAction(Action action, RemoteViews button) { 2363 if (isLegacy()) { 2364 if (mColorUtil.isGrayscale(mContext, action.icon)) { 2365 button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0, 2366 mContext.getResources().getColor( 2367 R.color.notification_action_legacy_color_filter), 2368 PorterDuff.Mode.MULTIPLY); 2369 } 2370 } 2371 } 2372 2373 private CharSequence processLegacyText(CharSequence charSequence) { 2374 if (isLegacy()) { 2375 return mColorUtil.invertCharSequenceColors(charSequence); 2376 } else { 2377 return charSequence; 2378 } 2379 } 2380 2381 /** 2382 * Apply any necessary background to smallIcons being used in the largeIcon spot. 2383 */ 2384 private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) { 2385 if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) { 2386 applyLargeIconBackground(contentView); 2387 } 2388 } 2389 2390 /** 2391 * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is, 2392 * if it's grayscale). 2393 */ 2394 // TODO: also check bounds, transparency, that sort of thing. 2395 private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) { 2396 if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) { 2397 applyLargeIconBackground(contentView); 2398 } else { 2399 removeLargeIconBackground(contentView); 2400 } 2401 } 2402 2403 /** 2404 * Add a colored circle behind the largeIcon slot. 2405 */ 2406 private void applyLargeIconBackground(RemoteViews contentView) { 2407 contentView.setInt(R.id.icon, "setBackgroundResource", 2408 R.drawable.notification_icon_legacy_bg_inset); 2409 2410 contentView.setDrawableParameters( 2411 R.id.icon, 2412 true, 2413 -1, 2414 mColor, 2415 PorterDuff.Mode.SRC_ATOP, 2416 -1); 2417 } 2418 2419 private void removeLargeIconBackground(RemoteViews contentView) { 2420 contentView.setInt(R.id.icon, "setBackgroundResource", 0); 2421 } 2422 2423 /** 2424 * Recolor small icons when used in the R.id.right_icon slot. 2425 */ 2426 private void processSmallRightIcon(int smallIconDrawableId, 2427 RemoteViews contentView) { 2428 if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) { 2429 contentView.setDrawableParameters(R.id.right_icon, false, -1, 2430 0xFFFFFFFF, 2431 PorterDuff.Mode.SRC_ATOP, -1); 2432 2433 contentView.setInt(R.id.right_icon, 2434 "setBackgroundResource", 2435 R.drawable.notification_icon_legacy_bg); 2436 2437 contentView.setDrawableParameters( 2438 R.id.right_icon, 2439 true, 2440 -1, 2441 mColor, 2442 PorterDuff.Mode.SRC_ATOP, 2443 -1); 2444 } 2445 } 2446 2447 private int resolveColor() { 2448 if (mColor == COLOR_DEFAULT) { 2449 mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color); 2450 } else { 2451 mColor |= 0xFF000000; // no alpha for custom colors 2452 } 2453 return mColor; 2454 } 2455 2456 /** 2457 * Apply the unstyled operations and return a new {@link Notification} object. 2458 * @hide 2459 */ 2460 public Notification buildUnstyled() { 2461 Notification n = new Notification(); 2462 n.when = mWhen; 2463 n.icon = mSmallIcon; 2464 n.iconLevel = mSmallIconLevel; 2465 n.number = mNumber; 2466 2467 n.color = resolveColor(); 2468 2469 n.contentView = makeContentView(); 2470 n.contentIntent = mContentIntent; 2471 n.deleteIntent = mDeleteIntent; 2472 n.fullScreenIntent = mFullScreenIntent; 2473 n.tickerText = mTickerText; 2474 n.tickerView = makeTickerView(); 2475 n.largeIcon = mLargeIcon; 2476 n.sound = mSound; 2477 n.audioStreamType = mAudioStreamType; 2478 n.vibrate = mVibrate; 2479 n.ledARGB = mLedArgb; 2480 n.ledOnMS = mLedOnMs; 2481 n.ledOffMS = mLedOffMs; 2482 n.defaults = mDefaults; 2483 n.flags = mFlags; 2484 n.bigContentView = makeBigContentView(); 2485 n.headsUpContentView = makeHeadsUpContentView(); 2486 if (mLedOnMs != 0 || mLedOffMs != 0) { 2487 n.flags |= FLAG_SHOW_LIGHTS; 2488 } 2489 if ((mDefaults & DEFAULT_LIGHTS) != 0) { 2490 n.flags |= FLAG_SHOW_LIGHTS; 2491 } 2492 n.category = mCategory; 2493 n.mGroupKey = mGroupKey; 2494 n.mSortKey = mSortKey; 2495 n.priority = mPriority; 2496 if (mActions.size() > 0) { 2497 n.actions = new Action[mActions.size()]; 2498 mActions.toArray(n.actions); 2499 } 2500 n.visibility = mVisibility; 2501 2502 if (mPublicVersion != null) { 2503 n.publicVersion = new Notification(); 2504 mPublicVersion.cloneInto(n.publicVersion, true); 2505 } 2506 2507 return n; 2508 } 2509 2510 /** 2511 * Capture, in the provided bundle, semantic information used in the construction of 2512 * this Notification object. 2513 * @hide 2514 */ 2515 public void populateExtras(Bundle extras) { 2516 // Store original information used in the construction of this object 2517 extras.putCharSequence(EXTRA_TITLE, mContentTitle); 2518 extras.putCharSequence(EXTRA_TEXT, mContentText); 2519 extras.putCharSequence(EXTRA_SUB_TEXT, mSubText); 2520 extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo); 2521 extras.putInt(EXTRA_SMALL_ICON, mSmallIcon); 2522 extras.putInt(EXTRA_PROGRESS, mProgress); 2523 extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax); 2524 extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate); 2525 extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer); 2526 extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen); 2527 if (mLargeIcon != null) { 2528 extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); 2529 } 2530 if (!mPeople.isEmpty()) { 2531 extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()])); 2532 } 2533 } 2534 2535 /** 2536 * @deprecated Use {@link #build()} instead. 2537 */ 2538 @Deprecated 2539 public Notification getNotification() { 2540 return build(); 2541 } 2542 2543 /** 2544 * Combine all of the options that have been set and return a new {@link Notification} 2545 * object. 2546 */ 2547 public Notification build() { 2548 Notification n = buildUnstyled(); 2549 2550 if (mStyle != null) { 2551 n = mStyle.buildStyled(n); 2552 } 2553 2554 n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle(); 2555 2556 populateExtras(n.extras); 2557 if (mStyle != null) { 2558 mStyle.addExtras(n.extras); 2559 } 2560 2561 return n; 2562 } 2563 2564 /** 2565 * Apply this Builder to an existing {@link Notification} object. 2566 * 2567 * @hide 2568 */ 2569 public Notification buildInto(Notification n) { 2570 build().cloneInto(n, true); 2571 return n; 2572 } 2573 2574 2575 private int getBaseLayoutResource() { 2576 return R.layout.notification_template_quantum_base; 2577 } 2578 2579 private int getBigBaseLayoutResource() { 2580 return R.layout.notification_template_quantum_big_base; 2581 } 2582 2583 private int getBigPictureLayoutResource() { 2584 return R.layout.notification_template_quantum_big_picture; 2585 } 2586 2587 private int getBigTextLayoutResource() { 2588 return R.layout.notification_template_quantum_big_text; 2589 } 2590 2591 private int getInboxLayoutResource() { 2592 return R.layout.notification_template_quantum_inbox; 2593 } 2594 2595 private int getActionLayoutResource() { 2596 return R.layout.notification_quantum_action; 2597 } 2598 2599 private int getActionTombstoneLayoutResource() { 2600 return R.layout.notification_quantum_action_tombstone; 2601 } 2602 } 2603 2604 /** 2605 * An object that can apply a rich notification style to a {@link Notification.Builder} 2606 * object. 2607 */ 2608 public static abstract class Style { 2609 private CharSequence mBigContentTitle; 2610 private CharSequence mSummaryText = null; 2611 private boolean mSummaryTextSet = false; 2612 2613 protected Builder mBuilder; 2614 2615 /** 2616 * Overrides ContentTitle in the big form of the template. 2617 * This defaults to the value passed to setContentTitle(). 2618 */ 2619 protected void internalSetBigContentTitle(CharSequence title) { 2620 mBigContentTitle = title; 2621 } 2622 2623 /** 2624 * Set the first line of text after the detail section in the big form of the template. 2625 */ 2626 protected void internalSetSummaryText(CharSequence cs) { 2627 mSummaryText = cs; 2628 mSummaryTextSet = true; 2629 } 2630 2631 public void setBuilder(Builder builder) { 2632 if (mBuilder != builder) { 2633 mBuilder = builder; 2634 if (mBuilder != null) { 2635 mBuilder.setStyle(this); 2636 } 2637 } 2638 } 2639 2640 protected void checkBuilder() { 2641 if (mBuilder == null) { 2642 throw new IllegalArgumentException("Style requires a valid Builder object"); 2643 } 2644 } 2645 2646 protected RemoteViews getStandardView(int layoutId) { 2647 checkBuilder(); 2648 2649 if (mBigContentTitle != null) { 2650 mBuilder.setContentTitle(mBigContentTitle); 2651 } 2652 2653 RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId); 2654 2655 if (mBigContentTitle != null && mBigContentTitle.equals("")) { 2656 contentView.setViewVisibility(R.id.line1, View.GONE); 2657 } else { 2658 contentView.setViewVisibility(R.id.line1, View.VISIBLE); 2659 } 2660 2661 // The last line defaults to the subtext, but can be replaced by mSummaryText 2662 final CharSequence overflowText = 2663 mSummaryTextSet ? mSummaryText 2664 : mBuilder.mSubText; 2665 if (overflowText != null) { 2666 contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText)); 2667 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE); 2668 contentView.setViewVisibility(R.id.line3, View.VISIBLE); 2669 } else { 2670 contentView.setViewVisibility(R.id.overflow_divider, View.GONE); 2671 contentView.setViewVisibility(R.id.line3, View.GONE); 2672 } 2673 2674 return contentView; 2675 } 2676 2677 /** 2678 * @hide 2679 */ 2680 public void addExtras(Bundle extras) { 2681 if (mSummaryTextSet) { 2682 extras.putCharSequence(EXTRA_SUMMARY_TEXT, mSummaryText); 2683 } 2684 if (mBigContentTitle != null) { 2685 extras.putCharSequence(EXTRA_TITLE_BIG, mBigContentTitle); 2686 } 2687 extras.putString(EXTRA_TEMPLATE, this.getClass().getName()); 2688 } 2689 2690 /** 2691 * @hide 2692 */ 2693 public abstract Notification buildStyled(Notification wip); 2694 2695 /** 2696 * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is 2697 * attached to. 2698 * 2699 * @return the fully constructed Notification. 2700 */ 2701 public Notification build() { 2702 checkBuilder(); 2703 return mBuilder.build(); 2704 } 2705 } 2706 2707 /** 2708 * Helper class for generating large-format notifications that include a large image attachment. 2709 * 2710 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 2711 * <pre class="prettyprint"> 2712 * Notification noti = new Notification.BigPictureStyle( 2713 * new Notification.Builder() 2714 * .setContentTitle("New photo from " + sender.toString()) 2715 * .setContentText(subject) 2716 * .setSmallIcon(R.drawable.new_post) 2717 * .setLargeIcon(aBitmap)) 2718 * .bigPicture(aBigBitmap) 2719 * .build(); 2720 * </pre> 2721 * 2722 * @see Notification#bigContentView 2723 */ 2724 public static class BigPictureStyle extends Style { 2725 private Bitmap mPicture; 2726 private Bitmap mBigLargeIcon; 2727 private boolean mBigLargeIconSet = false; 2728 2729 public BigPictureStyle() { 2730 } 2731 2732 public BigPictureStyle(Builder builder) { 2733 setBuilder(builder); 2734 } 2735 2736 /** 2737 * Overrides ContentTitle in the big form of the template. 2738 * This defaults to the value passed to setContentTitle(). 2739 */ 2740 public BigPictureStyle setBigContentTitle(CharSequence title) { 2741 internalSetBigContentTitle(safeCharSequence(title)); 2742 return this; 2743 } 2744 2745 /** 2746 * Set the first line of text after the detail section in the big form of the template. 2747 */ 2748 public BigPictureStyle setSummaryText(CharSequence cs) { 2749 internalSetSummaryText(safeCharSequence(cs)); 2750 return this; 2751 } 2752 2753 /** 2754 * Provide the bitmap to be used as the payload for the BigPicture notification. 2755 */ 2756 public BigPictureStyle bigPicture(Bitmap b) { 2757 mPicture = b; 2758 return this; 2759 } 2760 2761 /** 2762 * Override the large icon when the big notification is shown. 2763 */ 2764 public BigPictureStyle bigLargeIcon(Bitmap b) { 2765 mBigLargeIconSet = true; 2766 mBigLargeIcon = b; 2767 return this; 2768 } 2769 2770 private RemoteViews makeBigContentView() { 2771 RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource()); 2772 2773 contentView.setImageViewBitmap(R.id.big_picture, mPicture); 2774 2775 return contentView; 2776 } 2777 2778 /** 2779 * @hide 2780 */ 2781 public void addExtras(Bundle extras) { 2782 super.addExtras(extras); 2783 2784 if (mBigLargeIconSet) { 2785 extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon); 2786 } 2787 extras.putParcelable(EXTRA_PICTURE, mPicture); 2788 } 2789 2790 /** 2791 * @hide 2792 */ 2793 @Override 2794 public Notification buildStyled(Notification wip) { 2795 if (mBigLargeIconSet ) { 2796 mBuilder.mLargeIcon = mBigLargeIcon; 2797 } 2798 wip.bigContentView = makeBigContentView(); 2799 return wip; 2800 } 2801 } 2802 2803 /** 2804 * Helper class for generating large-format notifications that include a lot of text. 2805 * 2806 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 2807 * <pre class="prettyprint"> 2808 * Notification noti = new Notification.BigTextStyle( 2809 * new Notification.Builder() 2810 * .setContentTitle("New mail from " + sender.toString()) 2811 * .setContentText(subject) 2812 * .setSmallIcon(R.drawable.new_mail) 2813 * .setLargeIcon(aBitmap)) 2814 * .bigText(aVeryLongString) 2815 * .build(); 2816 * </pre> 2817 * 2818 * @see Notification#bigContentView 2819 */ 2820 public static class BigTextStyle extends Style { 2821 private CharSequence mBigText; 2822 2823 public BigTextStyle() { 2824 } 2825 2826 public BigTextStyle(Builder builder) { 2827 setBuilder(builder); 2828 } 2829 2830 /** 2831 * Overrides ContentTitle in the big form of the template. 2832 * This defaults to the value passed to setContentTitle(). 2833 */ 2834 public BigTextStyle setBigContentTitle(CharSequence title) { 2835 internalSetBigContentTitle(safeCharSequence(title)); 2836 return this; 2837 } 2838 2839 /** 2840 * Set the first line of text after the detail section in the big form of the template. 2841 */ 2842 public BigTextStyle setSummaryText(CharSequence cs) { 2843 internalSetSummaryText(safeCharSequence(cs)); 2844 return this; 2845 } 2846 2847 /** 2848 * Provide the longer text to be displayed in the big form of the 2849 * template in place of the content text. 2850 */ 2851 public BigTextStyle bigText(CharSequence cs) { 2852 mBigText = safeCharSequence(cs); 2853 return this; 2854 } 2855 2856 /** 2857 * @hide 2858 */ 2859 public void addExtras(Bundle extras) { 2860 super.addExtras(extras); 2861 2862 extras.putCharSequence(EXTRA_TEXT, mBigText); 2863 } 2864 2865 private RemoteViews makeBigContentView() { 2866 // Remove the content text so line3 only shows if you have a summary 2867 final boolean hadThreeLines = (mBuilder.mContentText != null && mBuilder.mSubText != null); 2868 mBuilder.mContentText = null; 2869 2870 RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource()); 2871 2872 if (hadThreeLines) { 2873 // vertical centering 2874 contentView.setViewPadding(R.id.line1, 0, 0, 0, 0); 2875 } 2876 2877 contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText)); 2878 contentView.setViewVisibility(R.id.big_text, View.VISIBLE); 2879 contentView.setViewVisibility(R.id.text2, View.GONE); 2880 2881 return contentView; 2882 } 2883 2884 /** 2885 * @hide 2886 */ 2887 @Override 2888 public Notification buildStyled(Notification wip) { 2889 wip.bigContentView = makeBigContentView(); 2890 2891 wip.extras.putCharSequence(EXTRA_TEXT, mBigText); 2892 2893 return wip; 2894 } 2895 } 2896 2897 /** 2898 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 2899 * 2900 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 2901 * <pre class="prettyprint"> 2902 * Notification noti = new Notification.InboxStyle( 2903 * new Notification.Builder() 2904 * .setContentTitle("5 New mails from " + sender.toString()) 2905 * .setContentText(subject) 2906 * .setSmallIcon(R.drawable.new_mail) 2907 * .setLargeIcon(aBitmap)) 2908 * .addLine(str1) 2909 * .addLine(str2) 2910 * .setContentTitle("") 2911 * .setSummaryText("+3 more") 2912 * .build(); 2913 * </pre> 2914 * 2915 * @see Notification#bigContentView 2916 */ 2917 public static class InboxStyle extends Style { 2918 private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5); 2919 2920 public InboxStyle() { 2921 } 2922 2923 public InboxStyle(Builder builder) { 2924 setBuilder(builder); 2925 } 2926 2927 /** 2928 * Overrides ContentTitle in the big form of the template. 2929 * This defaults to the value passed to setContentTitle(). 2930 */ 2931 public InboxStyle setBigContentTitle(CharSequence title) { 2932 internalSetBigContentTitle(safeCharSequence(title)); 2933 return this; 2934 } 2935 2936 /** 2937 * Set the first line of text after the detail section in the big form of the template. 2938 */ 2939 public InboxStyle setSummaryText(CharSequence cs) { 2940 internalSetSummaryText(safeCharSequence(cs)); 2941 return this; 2942 } 2943 2944 /** 2945 * Append a line to the digest section of the Inbox notification. 2946 */ 2947 public InboxStyle addLine(CharSequence cs) { 2948 mTexts.add(safeCharSequence(cs)); 2949 return this; 2950 } 2951 2952 /** 2953 * @hide 2954 */ 2955 public void addExtras(Bundle extras) { 2956 super.addExtras(extras); 2957 CharSequence[] a = new CharSequence[mTexts.size()]; 2958 extras.putCharSequenceArray(EXTRA_TEXT_LINES, mTexts.toArray(a)); 2959 } 2960 2961 private RemoteViews makeBigContentView() { 2962 // Remove the content text so line3 disappears unless you have a summary 2963 mBuilder.mContentText = null; 2964 RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource()); 2965 2966 contentView.setViewVisibility(R.id.text2, View.GONE); 2967 2968 int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3, 2969 R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6}; 2970 2971 // Make sure all rows are gone in case we reuse a view. 2972 for (int rowId : rowIds) { 2973 contentView.setViewVisibility(rowId, View.GONE); 2974 } 2975 2976 2977 int i=0; 2978 while (i < mTexts.size() && i < rowIds.length) { 2979 CharSequence str = mTexts.get(i); 2980 if (str != null && !str.equals("")) { 2981 contentView.setViewVisibility(rowIds[i], View.VISIBLE); 2982 contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str)); 2983 } 2984 i++; 2985 } 2986 2987 contentView.setViewVisibility(R.id.inbox_end_pad, 2988 mTexts.size() > 0 ? View.VISIBLE : View.GONE); 2989 2990 contentView.setViewVisibility(R.id.inbox_more, 2991 mTexts.size() > rowIds.length ? View.VISIBLE : View.GONE); 2992 2993 return contentView; 2994 } 2995 2996 /** 2997 * @hide 2998 */ 2999 @Override 3000 public Notification buildStyled(Notification wip) { 3001 wip.bigContentView = makeBigContentView(); 3002 3003 return wip; 3004 } 3005 } 3006} 3007