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 604 private Action() { } 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 */ 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 622 public Action clone() { 623 return new Action( 624 this.icon, 625 this.title, 626 this.actionIntent // safe to alias 627 ); 628 } 629 @Override 630 public int describeContents() { 631 return 0; 632 } 633 @Override 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 */ 667 public Notification() 668 { 669 this.when = System.currentTimeMillis(); 670 this.priority = PRIORITY_DEFAULT; 671 } 672 673 /** 674 * @hide 675 */ 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 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 */ 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 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 */ 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 */ 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 */ 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 884 public int describeContents() { 885 return 0; 886 } 887 888 /** 889 * Flatten this notification from a parcel. 890 */ 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 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 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} */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 1621 private void setFlag(int mask, boolean value) { 1622 if (value) { 1623 mFlags |= mask; 1624 } else { 1625 mFlags &= ~mask; 1626 } 1627 } 1628 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 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 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 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 1770 private RemoteViews makeBigContentView() { 1771 if (mActions.size() == 0) return null; 1772 1773 return applyStandardTemplateWithActions(R.layout.notification_template_big_base); 1774 } 1775 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.setTextViewCompoundDrawables(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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 1922 protected void internalSetSummaryText(CharSequence cs) { 1923 mSummaryText = cs; 1924 mSummaryTextSet = true; 1925 } 1926 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 1936 protected void checkBuilder() { 1937 if (mBuilder == null) { 1938 throw new IllegalArgumentException("Style requires a valid Builder object"); 1939 } 1940 } 1941 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 */ 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 */ 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 */ 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 2024 public BigPictureStyle() { 2025 } 2026 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 */ 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 */ 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 */ 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 */ 2059 public BigPictureStyle bigLargeIcon(Bitmap b) { 2060 mBigLargeIconSet = true; 2061 mBigLargeIcon = b; 2062 return this; 2063 } 2064 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 */ 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 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 2118 public BigTextStyle() { 2119 } 2120 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 */ 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 */ 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 */ 2146 public BigTextStyle bigText(CharSequence cs) { 2147 mBigText = safeCharSequence(cs); 2148 return this; 2149 } 2150 2151 /** 2152 * @hide 2153 */ 2154 public void addExtras(Bundle extras) { 2155 super.addExtras(extras); 2156 2157 extras.putCharSequence(EXTRA_TEXT, mBigText); 2158 } 2159 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 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 2215 public InboxStyle() { 2216 } 2217 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 */ 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 */ 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 */ 2242 public InboxStyle addLine(CharSequence cs) { 2243 mTexts.add(safeCharSequence(cs)); 2244 return this; 2245 } 2246 2247 /** 2248 * @hide 2249 */ 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 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 2295 public Notification buildStyled(Notification wip) { 2296 wip.bigContentView = makeBigContentView(); 2297 2298 return wip; 2299 } 2300 } 2301 } 2302