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