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