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