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