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