Notification.java revision 4ed80d581c3448f075d65efafc585b4691f8b301
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.media.AudioManager; 25import android.net.Uri; 26import android.os.Bundle; 27import android.os.IBinder; 28import android.os.Parcel; 29import android.os.Parcelable; 30import android.os.SystemClock; 31import android.text.TextUtils; 32import android.util.IntProperty; 33import android.util.Log; 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. On tablets, the 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 notification priority as described in 388 * MUMBLE MUMBLE. 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 * Notification type: promotion or advertisement. 418 */ 419 public static final String KIND_PROMO = "android.promo"; 420 421 /** 422 * @hide 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 bigContentView = RemoteViews.CREATOR.createFromParcel(parcel); 594 } 595 } 596 597 @Override 598 public Notification clone() { 599 Notification that = new Notification(); 600 601 that.when = this.when; 602 that.icon = this.icon; 603 that.number = this.number; 604 605 // PendingIntents are global, so there's no reason (or way) to clone them. 606 that.contentIntent = this.contentIntent; 607 that.deleteIntent = this.deleteIntent; 608 that.fullScreenIntent = this.fullScreenIntent; 609 610 if (this.tickerText != null) { 611 that.tickerText = this.tickerText.toString(); 612 } 613 if (this.tickerView != null) { 614 that.tickerView = this.tickerView.clone(); 615 } 616 if (this.contentView != null) { 617 that.contentView = this.contentView.clone(); 618 } 619 if (this.largeIcon != null) { 620 that.largeIcon = Bitmap.createBitmap(this.largeIcon); 621 } 622 that.iconLevel = this.iconLevel; 623 that.sound = this.sound; // android.net.Uri is immutable 624 that.audioStreamType = this.audioStreamType; 625 626 final long[] vibrate = this.vibrate; 627 if (vibrate != null) { 628 final int N = vibrate.length; 629 final long[] vib = that.vibrate = new long[N]; 630 System.arraycopy(vibrate, 0, vib, 0, N); 631 } 632 633 that.ledARGB = this.ledARGB; 634 that.ledOnMS = this.ledOnMS; 635 that.ledOffMS = this.ledOffMS; 636 that.defaults = this.defaults; 637 638 that.flags = this.flags; 639 640 that.priority = this.priority; 641 642 final String[] thiskind = this.kind; 643 if (thiskind != null) { 644 final int N = thiskind.length; 645 final String[] thatkind = that.kind = new String[N]; 646 System.arraycopy(thiskind, 0, thatkind, 0, N); 647 } 648 649 if (this.extras != null) { 650 that.extras = new Bundle(this.extras); 651 652 } 653 654 that.actions = new Action[this.actions.length]; 655 for(int i=0; i<this.actions.length; i++) { 656 that.actions[i] = this.actions[i].clone(); 657 } 658 if (this.bigContentView != null) { 659 that.bigContentView = this.bigContentView.clone(); 660 } 661 662 return that; 663 } 664 665 public int describeContents() { 666 return 0; 667 } 668 669 /** 670 * Flatten this notification from a parcel. 671 */ 672 public void writeToParcel(Parcel parcel, int flags) 673 { 674 parcel.writeInt(1); 675 676 parcel.writeLong(when); 677 parcel.writeInt(icon); 678 parcel.writeInt(number); 679 if (contentIntent != null) { 680 parcel.writeInt(1); 681 contentIntent.writeToParcel(parcel, 0); 682 } else { 683 parcel.writeInt(0); 684 } 685 if (deleteIntent != null) { 686 parcel.writeInt(1); 687 deleteIntent.writeToParcel(parcel, 0); 688 } else { 689 parcel.writeInt(0); 690 } 691 if (tickerText != null) { 692 parcel.writeInt(1); 693 TextUtils.writeToParcel(tickerText, parcel, flags); 694 } else { 695 parcel.writeInt(0); 696 } 697 if (tickerView != null) { 698 parcel.writeInt(1); 699 tickerView.writeToParcel(parcel, 0); 700 } else { 701 parcel.writeInt(0); 702 } 703 if (contentView != null) { 704 parcel.writeInt(1); 705 contentView.writeToParcel(parcel, 0); 706 } else { 707 parcel.writeInt(0); 708 } 709 if (largeIcon != null) { 710 parcel.writeInt(1); 711 largeIcon.writeToParcel(parcel, 0); 712 } else { 713 parcel.writeInt(0); 714 } 715 716 parcel.writeInt(defaults); 717 parcel.writeInt(this.flags); 718 719 if (sound != null) { 720 parcel.writeInt(1); 721 sound.writeToParcel(parcel, 0); 722 } else { 723 parcel.writeInt(0); 724 } 725 parcel.writeInt(audioStreamType); 726 parcel.writeLongArray(vibrate); 727 parcel.writeInt(ledARGB); 728 parcel.writeInt(ledOnMS); 729 parcel.writeInt(ledOffMS); 730 parcel.writeInt(iconLevel); 731 732 if (fullScreenIntent != null) { 733 parcel.writeInt(1); 734 fullScreenIntent.writeToParcel(parcel, 0); 735 } else { 736 parcel.writeInt(0); 737 } 738 739 parcel.writeInt(priority); 740 741 parcel.writeStringArray(kind); // ok for null 742 743 if (extras != null) { 744 parcel.writeInt(1); 745 extras.writeToParcel(parcel, 0); 746 } else { 747 parcel.writeInt(0); 748 } 749 750 parcel.writeTypedArray(actions, 0); 751 752 if (bigContentView != null) { 753 parcel.writeInt(1); 754 bigContentView.writeToParcel(parcel, 0); 755 } else { 756 parcel.writeInt(0); 757 } 758 } 759 760 /** 761 * Parcelable.Creator that instantiates Notification objects 762 */ 763 public static final Parcelable.Creator<Notification> CREATOR 764 = new Parcelable.Creator<Notification>() 765 { 766 public Notification createFromParcel(Parcel parcel) 767 { 768 return new Notification(parcel); 769 } 770 771 public Notification[] newArray(int size) 772 { 773 return new Notification[size]; 774 } 775 }; 776 777 /** 778 * Sets the {@link #contentView} field to be a view with the standard "Latest Event" 779 * layout. 780 * 781 * <p>Uses the {@link #icon} and {@link #when} fields to set the icon and time fields 782 * in the view.</p> 783 * @param context The context for your application / activity. 784 * @param contentTitle The title that goes in the expanded entry. 785 * @param contentText The text that goes in the expanded entry. 786 * @param contentIntent The intent to launch when the user clicks the expanded notification. 787 * If this is an activity, it must include the 788 * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires 789 * that you take care of task management as described in the 790 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back 791 * Stack</a> document. 792 * 793 * @deprecated Use {@link Builder} instead. 794 */ 795 @Deprecated 796 public void setLatestEventInfo(Context context, 797 CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) { 798 // TODO: rewrite this to use Builder 799 RemoteViews contentView = new RemoteViews(context.getPackageName(), 800 R.layout.notification_template_base); 801 if (this.icon != 0) { 802 contentView.setImageViewResource(R.id.icon, this.icon); 803 } 804 if (priority < PRIORITY_LOW) { 805 contentView.setInt(R.id.icon, 806 "setBackgroundResource", R.drawable.notification_template_icon_low_bg); 807 contentView.setInt(R.id.status_bar_latest_event_content, 808 "setBackgroundResource", R.drawable.notification_bg_low); 809 } 810 if (contentTitle != null) { 811 contentView.setTextViewText(R.id.title, contentTitle); 812 } 813 if (contentText != null) { 814 contentView.setTextViewText(R.id.text, contentText); 815 } 816 if (this.when != 0) { 817 contentView.setViewVisibility(R.id.time, View.VISIBLE); 818 contentView.setLong(R.id.time, "setTime", when); 819 } 820 if (this.number != 0) { 821 NumberFormat f = NumberFormat.getIntegerInstance(); 822 contentView.setTextViewText(R.id.info, f.format(this.number)); 823 } 824 825 this.contentView = contentView; 826 this.contentIntent = contentIntent; 827 } 828 829 @Override 830 public String toString() { 831 StringBuilder sb = new StringBuilder(); 832 sb.append("Notification(pri="); 833 sb.append(priority); 834 sb.append(" contentView="); 835 if (contentView != null) { 836 sb.append(contentView.getPackage()); 837 sb.append("/0x"); 838 sb.append(Integer.toHexString(contentView.getLayoutId())); 839 } else { 840 sb.append("null"); 841 } 842 // TODO(dsandler): defaults take precedence over local values, so reorder the branches below 843 sb.append(" vibrate="); 844 if (this.vibrate != null) { 845 int N = this.vibrate.length-1; 846 sb.append("["); 847 for (int i=0; i<N; i++) { 848 sb.append(this.vibrate[i]); 849 sb.append(','); 850 } 851 if (N != -1) { 852 sb.append(this.vibrate[N]); 853 } 854 sb.append("]"); 855 } else if ((this.defaults & DEFAULT_VIBRATE) != 0) { 856 sb.append("default"); 857 } else { 858 sb.append("null"); 859 } 860 sb.append(" sound="); 861 if (this.sound != null) { 862 sb.append(this.sound.toString()); 863 } else if ((this.defaults & DEFAULT_SOUND) != 0) { 864 sb.append("default"); 865 } else { 866 sb.append("null"); 867 } 868 sb.append(" defaults=0x"); 869 sb.append(Integer.toHexString(this.defaults)); 870 sb.append(" flags=0x"); 871 sb.append(Integer.toHexString(this.flags)); 872 sb.append(" kind=["); 873 if (this.kind == null) { 874 sb.append("null"); 875 } else { 876 for (int i=0; i<this.kind.length; i++) { 877 if (i>0) sb.append(","); 878 sb.append(this.kind[i]); 879 } 880 } 881 sb.append("]"); 882 if (actions != null) { 883 sb.append(" "); 884 sb.append(actions.length); 885 sb.append(" action"); 886 if (actions.length > 1) sb.append("s"); 887 } 888 sb.append(")"); 889 return sb.toString(); 890 } 891 892 /** 893 * Builder class for {@link Notification} objects. 894 * 895 * Provides a convenient way to set the various fields of a {@link Notification} and generate 896 * content views using the platform's notification layout template. 897 * 898 * Example: 899 * 900 * <pre class="prettyprint"> 901 * Notification noti = new Notification.Builder() 902 * .setContentTitle("New mail from " + sender.toString()) 903 * .setContentText(subject) 904 * .setSmallIcon(R.drawable.new_mail) 905 * .setLargeIcon(aBitmap) 906 * .build(); 907 * </pre> 908 */ 909 public static class Builder { 910 private static final int MAX_ACTION_BUTTONS = 2; 911 912 private Context mContext; 913 914 private long mWhen; 915 private int mSmallIcon; 916 private int mSmallIconLevel; 917 private int mNumber; 918 private CharSequence mContentTitle; 919 private CharSequence mContentText; 920 private CharSequence mContentInfo; 921 private CharSequence mSubText; 922 private PendingIntent mContentIntent; 923 private RemoteViews mContentView; 924 private PendingIntent mDeleteIntent; 925 private PendingIntent mFullScreenIntent; 926 private CharSequence mTickerText; 927 private RemoteViews mTickerView; 928 private Bitmap mLargeIcon; 929 private Uri mSound; 930 private int mAudioStreamType; 931 private long[] mVibrate; 932 private int mLedArgb; 933 private int mLedOnMs; 934 private int mLedOffMs; 935 private int mDefaults; 936 private int mFlags; 937 private int mProgressMax; 938 private int mProgress; 939 private boolean mProgressIndeterminate; 940 private ArrayList<String> mKindList = new ArrayList<String>(1); 941 private Bundle mExtras; 942 private int mPriority; 943 private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); 944 private boolean mUseChronometer; 945 private Style mStyle; 946 947 /** 948 * Constructs a new Builder with the defaults: 949 * 950 951 * <table> 952 * <tr><th align=right>priority</th> 953 * <td>{@link #PRIORITY_DEFAULT}</td></tr> 954 * <tr><th align=right>when</th> 955 * <td>now ({@link System#currentTimeMillis()})</td></tr> 956 * <tr><th align=right>audio stream</th> 957 * <td>{@link #STREAM_DEFAULT}</td></tr> 958 * </table> 959 * 960 961 * @param context 962 * A {@link Context} that will be used by the Builder to construct the 963 * RemoteViews. The Context will not be held past the lifetime of this Builder 964 * object. 965 */ 966 public Builder(Context context) { 967 mContext = context; 968 969 // Set defaults to match the defaults of a Notification 970 mWhen = System.currentTimeMillis(); 971 mAudioStreamType = STREAM_DEFAULT; 972 mPriority = PRIORITY_DEFAULT; 973 } 974 975 /** 976 * Add a timestamp pertaining to the notification (usually the time the event occurred). 977 * 978 979 * @see Notification#when 980 */ 981 public Builder setWhen(long when) { 982 mWhen = when; 983 return this; 984 } 985 986 /** 987 * Show the {@link Notification#when} field as a stopwatch. 988 * 989 * Instead of presenting <code>when</code> as a timestamp, the notification will show an 990 * automatically updating display of the minutes and seconds since <code>when</code>. 991 * 992 * Useful when showing an elapsed time (like an ongoing phone call). 993 * 994 * @see android.widget.Chronometer 995 * @see Notification#when 996 */ 997 public Builder setUsesChronometer(boolean b) { 998 mUseChronometer = b; 999 return this; 1000 } 1001 1002 /** 1003 * Set the small icon resource, which will be used to represent the notification in the 1004 * status bar. 1005 * 1006 1007 * The platform template for the expanded view will draw this icon in the left, unless a 1008 * {@link #setLargeIcon(Bitmap) large icon} has also been specified, in which case the small 1009 * icon will be moved to the right-hand side. 1010 * 1011 1012 * @param icon 1013 * A resource ID in the application's package of the drawable to use. 1014 * @see Notification#icon 1015 */ 1016 public Builder setSmallIcon(int icon) { 1017 mSmallIcon = icon; 1018 return this; 1019 } 1020 1021 /** 1022 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional 1023 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable 1024 * LevelListDrawable}. 1025 * 1026 * @param icon A resource ID in the application's package of the drawable to use. 1027 * @param level The level to use for the icon. 1028 * 1029 * @see Notification#icon 1030 * @see Notification#iconLevel 1031 */ 1032 public Builder setSmallIcon(int icon, int level) { 1033 mSmallIcon = icon; 1034 mSmallIconLevel = level; 1035 return this; 1036 } 1037 1038 /** 1039 * Set the first line of text in the platform notification template. 1040 */ 1041 public Builder setContentTitle(CharSequence title) { 1042 mContentTitle = title; 1043 return this; 1044 } 1045 1046 /** 1047 * Set the second line of text in the platform notification template. 1048 */ 1049 public Builder setContentText(CharSequence text) { 1050 mContentText = text; 1051 return this; 1052 } 1053 1054 /** 1055 * Set the third line of text in the platform notification template. 1056 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; they occupy the same location in the standard template. 1057 */ 1058 public Builder setSubText(CharSequence text) { 1059 mSubText = text; 1060 return this; 1061 } 1062 1063 /** 1064 * Set the large number at the right-hand side of the notification. This is 1065 * equivalent to setContentInfo, although it might show the number in a different 1066 * font size for readability. 1067 */ 1068 public Builder setNumber(int number) { 1069 mNumber = number; 1070 return this; 1071 } 1072 1073 /** 1074 * A small piece of additional information pertaining to this notification. 1075 * 1076 * The platform template will draw this on the last line of the notification, at the far 1077 * right (to the right of a smallIcon if it has been placed there). 1078 */ 1079 public Builder setContentInfo(CharSequence info) { 1080 mContentInfo = info; 1081 return this; 1082 } 1083 1084 /** 1085 * Set the progress this notification represents. 1086 * 1087 * The platform template will represent this using a {@link ProgressBar}. 1088 */ 1089 public Builder setProgress(int max, int progress, boolean indeterminate) { 1090 mProgressMax = max; 1091 mProgress = progress; 1092 mProgressIndeterminate = indeterminate; 1093 return this; 1094 } 1095 1096 /** 1097 * Supply a custom RemoteViews to use instead of the platform template. 1098 * 1099 * @see Notification#contentView 1100 */ 1101 public Builder setContent(RemoteViews views) { 1102 mContentView = views; 1103 return this; 1104 } 1105 1106 /** 1107 * Supply a {@link PendingIntent} to be sent when the notification is clicked. 1108 * 1109 * As of {@link android.os.Build.VERSION_CODES#HONEYCOMB}, if this field is unset and you 1110 * have specified a custom RemoteViews with {@link #setContent(RemoteViews)}, you can use 1111 * {@link RemoteViews#setOnClickPendingIntent RemoteViews.setOnClickPendingIntent(int,PendingIntent)} 1112 * to assign PendingIntents to individual views in that custom layout (i.e., to create 1113 * clickable buttons inside the notification view). 1114 * 1115 * @see Notification#contentIntent Notification.contentIntent 1116 */ 1117 public Builder setContentIntent(PendingIntent intent) { 1118 mContentIntent = intent; 1119 return this; 1120 } 1121 1122 /** 1123 * Supply a {@link PendingIntent} to send when the notification is cleared explicitly by the user. 1124 * 1125 * @see Notification#deleteIntent 1126 */ 1127 public Builder setDeleteIntent(PendingIntent intent) { 1128 mDeleteIntent = intent; 1129 return this; 1130 } 1131 1132 /** 1133 * An intent to launch instead of posting the notification to the status bar. 1134 * Only for use with extremely high-priority notifications demanding the user's 1135 * <strong>immediate</strong> attention, such as an incoming phone call or 1136 * alarm clock that the user has explicitly set to a particular time. 1137 * If this facility is used for something else, please give the user an option 1138 * to turn it off and use a normal notification, as this can be extremely 1139 * disruptive. 1140 * 1141 * @param intent The pending intent to launch. 1142 * @param highPriority Passing true will cause this notification to be sent 1143 * even if other notifications are suppressed. 1144 * 1145 * @see Notification#fullScreenIntent 1146 */ 1147 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { 1148 mFullScreenIntent = intent; 1149 setFlag(FLAG_HIGH_PRIORITY, highPriority); 1150 return this; 1151 } 1152 1153 /** 1154 * Set the "ticker" text which is displayed in the status bar when the notification first 1155 * arrives. 1156 * 1157 * @see Notification#tickerText 1158 */ 1159 public Builder setTicker(CharSequence tickerText) { 1160 mTickerText = tickerText; 1161 return this; 1162 } 1163 1164 /** 1165 * Set the text that is displayed in the status bar when the notification first 1166 * arrives, and also a RemoteViews object that may be displayed instead on some 1167 * devices. 1168 * 1169 * @see Notification#tickerText 1170 * @see Notification#tickerView 1171 */ 1172 public Builder setTicker(CharSequence tickerText, RemoteViews views) { 1173 mTickerText = tickerText; 1174 mTickerView = views; 1175 return this; 1176 } 1177 1178 /** 1179 * Add a large icon to the notification (and the ticker on some devices). 1180 * 1181 * In the platform template, this image will be shown on the left of the notification view 1182 * in place of the {@link #setSmallIcon(int) small icon} (which will move to the right side). 1183 * 1184 * @see Notification#largeIcon 1185 */ 1186 public Builder setLargeIcon(Bitmap icon) { 1187 mLargeIcon = icon; 1188 return this; 1189 } 1190 1191 /** 1192 * Set the sound to play. 1193 * 1194 * It will be played on the {@link #STREAM_DEFAULT default stream} for notifications. 1195 * 1196 * @see Notification#sound 1197 */ 1198 public Builder setSound(Uri sound) { 1199 mSound = sound; 1200 mAudioStreamType = STREAM_DEFAULT; 1201 return this; 1202 } 1203 1204 /** 1205 * Set the sound to play, along with a specific stream on which to play it. 1206 * 1207 * See {@link android.media.AudioManager} for the <code>STREAM_</code> constants. 1208 * 1209 * @see Notification#sound 1210 */ 1211 public Builder setSound(Uri sound, int streamType) { 1212 mSound = sound; 1213 mAudioStreamType = streamType; 1214 return this; 1215 } 1216 1217 /** 1218 * Set the vibration pattern to use. 1219 * 1220 1221 * See {@link android.os.Vibrator#vibrate(long[], int)} for a discussion of the 1222 * <code>pattern</code> parameter. 1223 * 1224 1225 * @see Notification#vibrate 1226 */ 1227 public Builder setVibrate(long[] pattern) { 1228 mVibrate = pattern; 1229 return this; 1230 } 1231 1232 /** 1233 * Set the desired color for the indicator LED on the device, as well as the 1234 * blink duty cycle (specified in milliseconds). 1235 * 1236 1237 * Not all devices will honor all (or even any) of these values. 1238 * 1239 1240 * @see Notification#ledARGB 1241 * @see Notification#ledOnMS 1242 * @see Notification#ledOffMS 1243 */ 1244 public Builder setLights(int argb, int onMs, int offMs) { 1245 mLedArgb = argb; 1246 mLedOnMs = onMs; 1247 mLedOffMs = offMs; 1248 return this; 1249 } 1250 1251 /** 1252 * Set whether this is an "ongoing" notification. 1253 * 1254 1255 * Ongoing notifications cannot be dismissed by the user, so your application or service 1256 * must take care of canceling them. 1257 * 1258 1259 * They are typically used to indicate a background task that the user is actively engaged 1260 * with (e.g., playing music) or is pending in some way and therefore occupying the device 1261 * (e.g., a file download, sync operation, active network connection). 1262 * 1263 1264 * @see Notification#FLAG_ONGOING_EVENT 1265 * @see Service#setForeground(boolean) 1266 */ 1267 public Builder setOngoing(boolean ongoing) { 1268 setFlag(FLAG_ONGOING_EVENT, ongoing); 1269 return this; 1270 } 1271 1272 /** 1273 * Set this flag if you would only like the sound, vibrate 1274 * and ticker to be played if the notification is not already showing. 1275 * 1276 * @see Notification#FLAG_ONLY_ALERT_ONCE 1277 */ 1278 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { 1279 setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); 1280 return this; 1281 } 1282 1283 /** 1284 * Make this notification automatically dismissed when the user touches it. The 1285 * PendingIntent set with {@link #setDeleteIntent} will be sent when this happens. 1286 * 1287 * @see Notification#FLAG_AUTO_CANCEL 1288 */ 1289 public Builder setAutoCancel(boolean autoCancel) { 1290 setFlag(FLAG_AUTO_CANCEL, autoCancel); 1291 return this; 1292 } 1293 1294 /** 1295 * Set which notification properties will be inherited from system defaults. 1296 * <p> 1297 * The value should be one or more of the following fields combined with 1298 * bitwise-or: 1299 * {@link #DEFAULT_SOUND}, {@link #DEFAULT_VIBRATE}, {@link #DEFAULT_LIGHTS}. 1300 * <p> 1301 * For all default values, use {@link #DEFAULT_ALL}. 1302 */ 1303 public Builder setDefaults(int defaults) { 1304 mDefaults = defaults; 1305 return this; 1306 } 1307 1308 /** 1309 * Set the priority of this notification. 1310 * 1311 * @see Notification#priority 1312 */ 1313 public Builder setPriority(int pri) { 1314 mPriority = pri; 1315 return this; 1316 } 1317 1318 /** 1319 * @hide 1320 * 1321 * Add a kind (category) to this notification. Optional. 1322 * 1323 * @see Notification#kind 1324 */ 1325 public Builder addKind(String k) { 1326 mKindList.add(k); 1327 return this; 1328 } 1329 1330 /** 1331 * Add metadata to this notification. 1332 * 1333 * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's 1334 * current contents are copied into the Notification each time {@link #build()} is 1335 * called. 1336 * 1337 * @see Notification#extras 1338 * @hide 1339 */ 1340 public Builder setExtras(Bundle bag) { 1341 mExtras = bag; 1342 return this; 1343 } 1344 1345 /** 1346 * Add an action to this notification. Actions are typically displayed by 1347 * the system as a button adjacent to the notification content. 1348 * 1349 * @param icon Resource ID of a drawable that represents the action. 1350 * @param title Text describing the action. 1351 * @param intent PendingIntent to be fired when the action is invoked. 1352 */ 1353 public Builder addAction(int icon, CharSequence title, PendingIntent intent) { 1354 mActions.add(new Action(icon, title, intent)); 1355 return this; 1356 } 1357 1358 /** 1359 * Add a rich notification style to be applied at build time. 1360 * 1361 * @param style Object responsible for modifying the notification style. 1362 */ 1363 public Builder setStyle(Style style) { 1364 if (mStyle != style) { 1365 mStyle = style; 1366 mStyle.setBuilder(this); 1367 } 1368 return this; 1369 } 1370 1371 private void setFlag(int mask, boolean value) { 1372 if (value) { 1373 mFlags |= mask; 1374 } else { 1375 mFlags &= ~mask; 1376 } 1377 } 1378 1379 private RemoteViews applyStandardTemplate(int resId) { 1380 RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId); 1381 boolean hasLine3 = false; 1382 boolean hasLine2 = false; 1383 int smallIconImageViewId = R.id.icon; 1384 if (mLargeIcon != null) { 1385 contentView.setImageViewBitmap(R.id.icon, mLargeIcon); 1386 smallIconImageViewId = R.id.right_icon; 1387 } 1388 if (mPriority < PRIORITY_LOW) { 1389 contentView.setInt(R.id.icon, 1390 "setBackgroundResource", R.drawable.notification_template_icon_low_bg); 1391 contentView.setInt(R.id.status_bar_latest_event_content, 1392 "setBackgroundResource", R.drawable.notification_bg_low); 1393 } 1394 if (mSmallIcon != 0) { 1395 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon); 1396 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE); 1397 } else { 1398 contentView.setViewVisibility(smallIconImageViewId, View.GONE); 1399 } 1400 if (mContentTitle != null) { 1401 contentView.setTextViewText(R.id.title, mContentTitle); 1402 } 1403 if (mContentText != null) { 1404 contentView.setTextViewText( 1405 (mSubText != null) ? R.id.text2 : R.id.text, 1406 mContentText); 1407 hasLine3 = true; 1408 } 1409 if (mContentInfo != null) { 1410 contentView.setTextViewText(R.id.info, mContentInfo); 1411 contentView.setViewVisibility(R.id.info, View.VISIBLE); 1412 hasLine3 = true; 1413 } else if (mNumber > 0) { 1414 final int tooBig = mContext.getResources().getInteger( 1415 R.integer.status_bar_notification_info_maxnum); 1416 if (mNumber > tooBig) { 1417 contentView.setTextViewText(R.id.info, mContext.getResources().getString( 1418 R.string.status_bar_notification_info_overflow)); 1419 } else { 1420 NumberFormat f = NumberFormat.getIntegerInstance(); 1421 contentView.setTextViewText(R.id.info, f.format(mNumber)); 1422 } 1423 contentView.setViewVisibility(R.id.info, View.VISIBLE); 1424 hasLine3 = true; 1425 } else { 1426 contentView.setViewVisibility(R.id.info, View.GONE); 1427 } 1428 1429 if (mSubText != null) { 1430 contentView.setTextViewText(R.id.text, mSubText); 1431 contentView.setViewVisibility(R.id.text2, 1432 mContentText != null ? View.VISIBLE : View.GONE); 1433 } else { 1434 contentView.setViewVisibility(R.id.text2, View.GONE); 1435 if (mProgressMax != 0 || mProgressIndeterminate) { 1436 contentView.setProgressBar( 1437 R.id.progress, mProgressMax, mProgress, mProgressIndeterminate); 1438 contentView.setViewVisibility(R.id.progress, View.VISIBLE); 1439 } else { 1440 contentView.setViewVisibility(R.id.progress, View.GONE); 1441 } 1442 } 1443 if (mWhen != 0) { 1444 if (mUseChronometer) { 1445 contentView.setViewVisibility(R.id.chronometer, View.VISIBLE); 1446 contentView.setLong(R.id.chronometer, "setBase", 1447 mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis())); 1448 contentView.setBoolean(R.id.chronometer, "setStarted", true); 1449 } else { 1450 contentView.setViewVisibility(R.id.time, View.VISIBLE); 1451 contentView.setLong(R.id.time, "setTime", mWhen); 1452 } 1453 } 1454 contentView.setViewVisibility(R.id.line3, hasLine3 ? View.VISIBLE : View.GONE); 1455 return contentView; 1456 } 1457 1458 private RemoteViews applyStandardTemplateWithActions(int layoutId) { 1459 RemoteViews big = applyStandardTemplate(layoutId); 1460 1461 int N = mActions.size(); 1462 if (N > 0) { 1463 // Log.d("Notification", "has actions: " + mContentText); 1464 big.setViewVisibility(R.id.actions, View.VISIBLE); 1465 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS; 1466 big.removeAllViews(R.id.actions); 1467 for (int i=0; i<N; i++) { 1468 final RemoteViews button = generateActionButton(mActions.get(i)); 1469 //Log.d("Notification", "adding action " + i + ": " + mActions.get(i).title); 1470 big.addView(R.id.actions, button); 1471 } 1472 } 1473 return big; 1474 } 1475 1476 private RemoteViews makeContentView() { 1477 if (mContentView != null) { 1478 return mContentView; 1479 } else { 1480 return applyStandardTemplate(R.layout.notification_template_base); // no more special large_icon flavor 1481 } 1482 } 1483 1484 private RemoteViews makeTickerView() { 1485 if (mTickerView != null) { 1486 return mTickerView; 1487 } else { 1488 if (mContentView == null) { 1489 return applyStandardTemplate(mLargeIcon == null 1490 ? R.layout.status_bar_latest_event_ticker 1491 : R.layout.status_bar_latest_event_ticker_large_icon); 1492 } else { 1493 return null; 1494 } 1495 } 1496 } 1497 1498 private RemoteViews makeBigContentView() { 1499 if (mActions.size() == 0) return null; 1500 1501 return applyStandardTemplateWithActions(R.layout.notification_template_big_base); 1502 } 1503 1504 private RemoteViews generateActionButton(Action action) { 1505 final boolean tombstone = (action.actionIntent == null); 1506 RemoteViews button = new RemoteViews(mContext.getPackageName(), 1507 tombstone ? R.layout.notification_action_tombstone 1508 : R.layout.notification_action); 1509 button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0); 1510 button.setTextViewText(R.id.action0, action.title); 1511 if (!tombstone) { 1512 button.setOnClickPendingIntent(R.id.action0, action.actionIntent); 1513 } 1514 button.setContentDescription(R.id.action0, action.title); 1515 return button; 1516 } 1517 1518 /** 1519 * Apply the unstyled operations and return a new {@link Notification} object. 1520 */ 1521 private Notification buildUnstyled() { 1522 Notification n = new Notification(); 1523 n.when = mWhen; 1524 n.icon = mSmallIcon; 1525 n.iconLevel = mSmallIconLevel; 1526 n.number = mNumber; 1527 n.contentView = makeContentView(); 1528 n.contentIntent = mContentIntent; 1529 n.deleteIntent = mDeleteIntent; 1530 n.fullScreenIntent = mFullScreenIntent; 1531 n.tickerText = mTickerText; 1532 n.tickerView = makeTickerView(); 1533 n.largeIcon = mLargeIcon; 1534 n.sound = mSound; 1535 n.audioStreamType = mAudioStreamType; 1536 n.vibrate = mVibrate; 1537 n.ledARGB = mLedArgb; 1538 n.ledOnMS = mLedOnMs; 1539 n.ledOffMS = mLedOffMs; 1540 n.defaults = mDefaults; 1541 n.flags = mFlags; 1542 n.bigContentView = makeBigContentView(); 1543 if (mLedOnMs != 0 && mLedOffMs != 0) { 1544 n.flags |= FLAG_SHOW_LIGHTS; 1545 } 1546 if ((mDefaults & DEFAULT_LIGHTS) != 0) { 1547 n.flags |= FLAG_SHOW_LIGHTS; 1548 } 1549 if (mKindList.size() > 0) { 1550 n.kind = new String[mKindList.size()]; 1551 mKindList.toArray(n.kind); 1552 } else { 1553 n.kind = null; 1554 } 1555 n.priority = mPriority; 1556 n.extras = mExtras != null ? new Bundle(mExtras) : null; 1557 if (mActions.size() > 0) { 1558 n.actions = new Action[mActions.size()]; 1559 mActions.toArray(n.actions); 1560 } 1561 return n; 1562 } 1563 1564 /** 1565 * @deprecated Use {@link #build()} instead. 1566 */ 1567 @Deprecated 1568 public Notification getNotification() { 1569 return build(); 1570 } 1571 1572 /** 1573 * Combine all of the options that have been set and return a new {@link Notification} 1574 * object. 1575 */ 1576 public Notification build() { 1577 if (mStyle != null) { 1578 return mStyle.build(); 1579 } else { 1580 return buildUnstyled(); 1581 } 1582 } 1583 } 1584 1585 1586 /** 1587 * An object that can apply a rich notification style to a {@link Notification.Builder} 1588 * object. 1589 */ 1590 public static abstract class Style 1591 { 1592 private CharSequence mBigContentTitle; 1593 private CharSequence mSummaryText = null; 1594 1595 protected Builder mBuilder; 1596 1597 /** 1598 * Overrides ContentTitle in the big form of the template. 1599 * This defaults to the value passed to setContentTitle(). 1600 */ 1601 protected void internalSetBigContentTitle(CharSequence title) { 1602 mBigContentTitle = title; 1603 } 1604 1605 /** 1606 * Set the first line of text after the detail section in the big form of the template. 1607 */ 1608 protected void internalSetSummaryText(CharSequence cs) { 1609 mSummaryText = cs; 1610 } 1611 1612 public void setBuilder(Builder builder) { 1613 if (mBuilder != builder) { 1614 mBuilder = builder; 1615 mBuilder.setStyle(this); 1616 } 1617 } 1618 1619 protected void checkBuilder() { 1620 if (mBuilder == null) { 1621 throw new IllegalArgumentException("Style requires a valid Builder object"); 1622 } 1623 } 1624 1625 protected RemoteViews getStandardView(int layoutId) { 1626 checkBuilder(); 1627 1628 if (mBigContentTitle != null) { 1629 mBuilder.setContentTitle(mBigContentTitle); 1630 } 1631 1632 if (mBuilder.mSubText == null) { 1633 mBuilder.setContentText(null); 1634 } 1635 1636 RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId); 1637 1638 if (mBuilder.mSubText == null) { 1639 contentView.setViewVisibility(R.id.line3, View.GONE); 1640 } else { 1641 contentView.setViewVisibility(R.id.line3, View.VISIBLE); 1642 } 1643 1644 if (mBigContentTitle != null && mBigContentTitle.equals("")) { 1645 contentView.setViewVisibility(R.id.line1, View.GONE); 1646 } else { 1647 contentView.setViewVisibility(R.id.line1, View.VISIBLE); 1648 } 1649 1650 if (mSummaryText != null && !mSummaryText.equals("")) { 1651 contentView.setViewVisibility(R.id.overflow_title, View.VISIBLE); 1652 contentView.setTextViewText(R.id.overflow_title, mSummaryText); 1653 } else { 1654 contentView.setViewVisibility(R.id.overflow_title, View.GONE); 1655 } 1656 1657 return contentView; 1658 } 1659 1660 public abstract Notification build(); 1661 } 1662 1663 /** 1664 * Helper class for generating large-format notifications that include a large image attachment. 1665 * 1666 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 1667 * <pre class="prettyprint"> 1668 * Notification noti = new Notification.BigPictureStyle( 1669 * new Notification.Builder() 1670 * .setContentTitle("New photo from " + sender.toString()) 1671 * .setContentText(subject) 1672 * .setSmallIcon(R.drawable.new_post) 1673 * .setLargeIcon(aBitmap)) 1674 * .bigPicture(aBigBitmap) 1675 * .build(); 1676 * </pre> 1677 * 1678 * @see Notification#bigContentView 1679 */ 1680 public static class BigPictureStyle extends Style { 1681 private Bitmap mPicture; 1682 1683 public BigPictureStyle() { 1684 } 1685 1686 public BigPictureStyle(Builder builder) { 1687 setBuilder(builder); 1688 } 1689 1690 /** 1691 * Overrides ContentTitle in the big form of the template. 1692 * This defaults to the value passed to setContentTitle(). 1693 */ 1694 public BigPictureStyle setBigContentTitle(CharSequence title) { 1695 internalSetBigContentTitle(title); 1696 return this; 1697 } 1698 1699 /** 1700 * Set the first line of text after the detail section in the big form of the template. 1701 */ 1702 public BigPictureStyle setSummaryText(CharSequence cs) { 1703 internalSetSummaryText(cs); 1704 return this; 1705 } 1706 1707 public BigPictureStyle bigPicture(Bitmap b) { 1708 mPicture = b; 1709 return this; 1710 } 1711 1712 private RemoteViews makeBigContentView() { 1713 RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture); 1714 1715 contentView.setImageViewBitmap(R.id.big_picture, mPicture); 1716 1717 return contentView; 1718 } 1719 1720 @Override 1721 public Notification build() { 1722 checkBuilder(); 1723 Notification wip = mBuilder.buildUnstyled(); 1724 wip.bigContentView = makeBigContentView(); 1725 return wip; 1726 } 1727 } 1728 1729 /** 1730 * Helper class for generating large-format notifications that include a lot of text. 1731 * 1732 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 1733 * <pre class="prettyprint"> 1734 * Notification noti = new Notification.BigPictureStyle( 1735 * new Notification.Builder() 1736 * .setContentTitle("New mail from " + sender.toString()) 1737 * .setContentText(subject) 1738 * .setSmallIcon(R.drawable.new_mail) 1739 * .setLargeIcon(aBitmap)) 1740 * .bigText(aVeryLongString) 1741 * .build(); 1742 * </pre> 1743 * 1744 * @see Notification#bigContentView 1745 */ 1746 public static class BigTextStyle extends Style { 1747 private CharSequence mBigText; 1748 1749 public BigTextStyle() { 1750 } 1751 1752 public BigTextStyle(Builder builder) { 1753 setBuilder(builder); 1754 } 1755 1756 /** 1757 * Overrides ContentTitle in the big form of the template. 1758 * This defaults to the value passed to setContentTitle(). 1759 */ 1760 public BigTextStyle setBigContentTitle(CharSequence title) { 1761 internalSetBigContentTitle(title); 1762 return this; 1763 } 1764 1765 /** 1766 * Set the first line of text after the detail section in the big form of the template. 1767 */ 1768 public BigTextStyle setSummaryText(CharSequence cs) { 1769 internalSetSummaryText(cs); 1770 return this; 1771 } 1772 1773 public BigTextStyle bigText(CharSequence cs) { 1774 mBigText = cs; 1775 return this; 1776 } 1777 1778 private RemoteViews makeBigContentView() { 1779 RemoteViews contentView = getStandardView(R.layout.notification_template_big_text); 1780 contentView.setTextViewText(R.id.big_text, mBigText); 1781 contentView.setViewVisibility(R.id.big_text, View.VISIBLE); 1782 contentView.setViewVisibility(R.id.text2, View.GONE); 1783 1784 return contentView; 1785 } 1786 1787 @Override 1788 public Notification build() { 1789 checkBuilder(); 1790 Notification wip = mBuilder.buildUnstyled(); 1791 wip.bigContentView = makeBigContentView(); 1792 return wip; 1793 } 1794 } 1795 1796 /** 1797 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 1798 * 1799 * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so: 1800 * <pre class="prettyprint"> 1801 * Notification noti = new Notification.InboxStyle( 1802 * new Notification.Builder() 1803 * .setContentTitle("5 New mails from " + sender.toString()) 1804 * .setContentText(subject) 1805 * .setSmallIcon(R.drawable.new_mail) 1806 * .setLargeIcon(aBitmap)) 1807 * .addLine(str1) 1808 * .addLine(str2) 1809 * .setContentTitle("") 1810 * .setSummaryText("+3 more") 1811 * .build(); 1812 * </pre> 1813 * 1814 * @see Notification#bigContentView 1815 */ 1816 public static class InboxStyle extends Style { 1817 private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5); 1818 1819 public InboxStyle() { 1820 } 1821 1822 public InboxStyle(Builder builder) { 1823 setBuilder(builder); 1824 } 1825 1826 /** 1827 * Overrides ContentTitle in the big form of the template. 1828 * This defaults to the value passed to setContentTitle(). 1829 */ 1830 public InboxStyle setBigContentTitle(CharSequence title) { 1831 internalSetBigContentTitle(title); 1832 return this; 1833 } 1834 1835 /** 1836 * Set the first line of text after the detail section in the big form of the template. 1837 */ 1838 public InboxStyle setSummaryText(CharSequence cs) { 1839 internalSetSummaryText(cs); 1840 return this; 1841 } 1842 1843 public InboxStyle addLine(CharSequence cs) { 1844 mTexts.add(cs); 1845 return this; 1846 } 1847 1848 private RemoteViews makeBigContentView() { 1849 RemoteViews contentView = getStandardView(R.layout.notification_template_inbox); 1850 contentView.setViewVisibility(R.id.text2, View.GONE); 1851 1852 int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3, 1853 R.id.inbox_text4}; 1854 1855 // Make sure all rows are gone in case we reuse a view. 1856 for (int rowId : rowIds) { 1857 contentView.setViewVisibility(rowId, View.GONE); 1858 } 1859 1860 int i=0; 1861 while (i < mTexts.size() && i < rowIds.length) { 1862 CharSequence str = mTexts.get(i); 1863 if (str != null && !str.equals("")) { 1864 contentView.setViewVisibility(rowIds[i], View.VISIBLE); 1865 contentView.setTextViewText(rowIds[i], str); 1866 } 1867 i++; 1868 } 1869 1870 return contentView; 1871 } 1872 1873 @Override 1874 public Notification build() { 1875 checkBuilder(); 1876 Notification wip = mBuilder.buildUnstyled(); 1877 wip.bigContentView = makeBigContentView(); 1878 return wip; 1879 } 1880 } 1881} 1882