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