NotificationCompat.java revision 1f94e518424cbf818607f63e353f2a597ed1dd37
1/* 2 * Copyright (C) 2012 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.support.v4.app; 18 19import android.app.Notification; 20import android.app.PendingIntent; 21import android.content.Context; 22import android.graphics.Bitmap; 23import android.graphics.Color; 24import android.media.AudioManager; 25import android.net.Uri; 26import android.os.Build; 27import android.os.Bundle; 28import android.os.Parcelable; 29import android.support.v4.view.GravityCompat; 30import android.view.Gravity; 31import android.widget.RemoteViews; 32 33import java.util.ArrayList; 34import java.util.Collections; 35import java.util.List; 36 37/** 38 * Helper for accessing features in {@link android.app.Notification} 39 * introduced after API level 4 in a backwards compatible fashion. 40 */ 41public class NotificationCompat { 42 43 /** 44 * Use all default values (where applicable). 45 */ 46 public static final int DEFAULT_ALL = ~0; 47 48 /** 49 * Use the default notification sound. This will ignore any sound set using 50 * {@link Builder#setSound} 51 * 52 * <p> 53 * A notification that is noisy is more likely to be presented as a heads-up notification, 54 * on some platforms. 55 * </p> 56 * 57 * @see Builder#setDefaults 58 */ 59 public static final int DEFAULT_SOUND = 1; 60 61 /** 62 * Use the default notification vibrate. This will ignore any vibrate set using 63 * {@link Builder#setVibrate}. Using phone vibration requires the 64 * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. 65 * 66 * <p> 67 * A notification that vibrates is more likely to be presented as a heads-up notification, 68 * on some platforms. 69 * </p> 70 * 71 * @see Builder#setDefaults 72 */ 73 public static final int DEFAULT_VIBRATE = 2; 74 75 /** 76 * Use the default notification lights. This will ignore the 77 * {@link #FLAG_SHOW_LIGHTS} bit, and values set with {@link Builder#setLights}. 78 * 79 * @see Builder#setDefaults 80 */ 81 public static final int DEFAULT_LIGHTS = 4; 82 83 /** 84 * Use this constant as the value for audioStreamType to request that 85 * the default stream type for notifications be used. Currently the 86 * default stream type is {@link AudioManager#STREAM_NOTIFICATION}. 87 */ 88 public static final int STREAM_DEFAULT = -1; 89 90 /** 91 * Bit set in the Notification flags field when LEDs should be turned on 92 * for this notification. 93 */ 94 public static final int FLAG_SHOW_LIGHTS = 0x00000001; 95 96 /** 97 * Bit set in the Notification flags field if this notification is in 98 * reference to something that is ongoing, like a phone call. It should 99 * not be set if this notification is in reference to something that 100 * happened at a particular point in time, like a missed phone call. 101 */ 102 public static final int FLAG_ONGOING_EVENT = 0x00000002; 103 104 /** 105 * Bit set in the Notification flags field if 106 * the audio will be repeated until the notification is 107 * cancelled or the notification window is opened. 108 */ 109 public static final int FLAG_INSISTENT = 0x00000004; 110 111 /** 112 * Bit set in the Notification flags field if the notification's sound, 113 * vibrate and ticker should only be played if the notification is not already showing. 114 */ 115 public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008; 116 117 /** 118 * Bit set in the Notification flags field if the notification should be canceled when 119 * it is clicked by the user. 120 */ 121 public static final int FLAG_AUTO_CANCEL = 0x00000010; 122 123 /** 124 * Bit set in the Notification flags field if the notification should not be canceled 125 * when the user clicks the Clear all button. 126 */ 127 public static final int FLAG_NO_CLEAR = 0x00000020; 128 129 /** 130 * Bit set in the Notification flags field if this notification represents a currently 131 * running service. This will normally be set for you by 132 * {@link android.app.Service#startForeground}. 133 */ 134 public static final int FLAG_FOREGROUND_SERVICE = 0x00000040; 135 136 /** 137 * Obsolete flag indicating high-priority notifications; use the priority field instead. 138 * 139 * @deprecated Use {@link NotificationCompat.Builder#setPriority(int)} with a positive value. 140 */ 141 public static final int FLAG_HIGH_PRIORITY = 0x00000080; 142 143 /** 144 * Bit set in the Notification flags field if this notification is relevant to the current 145 * device only and it is not recommended that it bridge to other devices. 146 */ 147 public static final int FLAG_LOCAL_ONLY = 0x00000100; 148 149 /** 150 * Bit set in the Notification flags field if this notification is the group summary for a 151 * group of notifications. Grouped notifications may display in a cluster or stack on devices 152 * which support such rendering. Requires a group key also be set using 153 * {@link Builder#setGroup}. 154 */ 155 public static final int FLAG_GROUP_SUMMARY = 0x00000200; 156 157 /** 158 * Default notification priority for {@link NotificationCompat.Builder#setPriority(int)}. 159 * If your application does not prioritize its own notifications, 160 * use this value for all notifications. 161 */ 162 public static final int PRIORITY_DEFAULT = 0; 163 164 /** 165 * Lower notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 166 * for items that are less important. The UI may choose to show 167 * these items smaller, or at a different position in the list, 168 * compared with your app's {@link #PRIORITY_DEFAULT} items. 169 */ 170 public static final int PRIORITY_LOW = -1; 171 172 /** 173 * Lowest notification priority for {@link NotificationCompat.Builder#setPriority(int)}; 174 * these items might not be shown to the user except under 175 * special circumstances, such as detailed notification logs. 176 */ 177 public static final int PRIORITY_MIN = -2; 178 179 /** 180 * Higher notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 181 * for more important notifications or alerts. The UI may choose 182 * to show these items larger, or at a different position in 183 * notification lists, compared with your app's {@link #PRIORITY_DEFAULT} items. 184 */ 185 public static final int PRIORITY_HIGH = 1; 186 187 /** 188 * Highest notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 189 * for your application's most important items that require the user's 190 * prompt attention or input. 191 */ 192 public static final int PRIORITY_MAX = 2; 193 194 /** 195 * Notification extras key: this is the title of the notification, 196 * as supplied to {@link Builder#setContentTitle(CharSequence)}. 197 */ 198 public static final String EXTRA_TITLE = "android.title"; 199 200 /** 201 * Notification extras key: this is the title of the notification when shown in expanded form, 202 * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}. 203 */ 204 public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big"; 205 206 /** 207 * Notification extras key: this is the main text payload, as supplied to 208 * {@link Builder#setContentText(CharSequence)}. 209 */ 210 public static final String EXTRA_TEXT = "android.text"; 211 212 /** 213 * Notification extras key: this is a third line of text, as supplied to 214 * {@link Builder#setSubText(CharSequence)}. 215 */ 216 public static final String EXTRA_SUB_TEXT = "android.subText"; 217 218 /** 219 * Notification extras key: this is a small piece of additional text as supplied to 220 * {@link Builder#setContentInfo(CharSequence)}. 221 */ 222 public static final String EXTRA_INFO_TEXT = "android.infoText"; 223 224 /** 225 * Notification extras key: this is a line of summary information intended to be shown 226 * alongside expanded notifications, as supplied to (e.g.) 227 * {@link BigTextStyle#setSummaryText(CharSequence)}. 228 */ 229 public static final String EXTRA_SUMMARY_TEXT = "android.summaryText"; 230 231 /** 232 * Notification extras key: this is the resource ID of the notification's main small icon, as 233 * supplied to {@link Builder#setSmallIcon(int)}. 234 */ 235 public static final String EXTRA_SMALL_ICON = "android.icon"; 236 237 /** 238 * Notification extras key: this is a bitmap to be used instead of the small icon when showing the 239 * notification payload, as 240 * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}. 241 */ 242 public static final String EXTRA_LARGE_ICON = "android.largeIcon"; 243 244 /** 245 * Notification extras key: this is a bitmap to be used instead of the one from 246 * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is 247 * shown in its expanded form, as supplied to 248 * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}. 249 */ 250 public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big"; 251 252 /** 253 * Notification extras key: this is the progress value supplied to 254 * {@link Builder#setProgress(int, int, boolean)}. 255 */ 256 public static final String EXTRA_PROGRESS = "android.progress"; 257 258 /** 259 * Notification extras key: this is the maximum value supplied to 260 * {@link Builder#setProgress(int, int, boolean)}. 261 */ 262 public static final String EXTRA_PROGRESS_MAX = "android.progressMax"; 263 264 /** 265 * Notification extras key: whether the progress bar is indeterminate, supplied to 266 * {@link Builder#setProgress(int, int, boolean)}. 267 */ 268 public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; 269 270 /** 271 * Notification extras key: whether the when field set using {@link Builder#setWhen} should 272 * be shown as a count-up timer (specifically a {@link android.widget.Chronometer}) instead 273 * of a timestamp, as supplied to {@link Builder#setUsesChronometer(boolean)}. 274 */ 275 public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; 276 277 /** 278 * Notification extras key: this is a bitmap to be shown in {@link BigPictureStyle} expanded 279 * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}. 280 */ 281 public static final String EXTRA_PICTURE = "android.picture"; 282 283 /** 284 * Notification extras key: An array of CharSequences to show in {@link InboxStyle} expanded 285 * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}. 286 */ 287 public static final String EXTRA_TEXT_LINES = "android.textLines"; 288 289 /** 290 * Notification extras key: An array of people that this notification relates to, specified 291 * by contacts provider contact URI. 292 */ 293 public static final String EXTRA_PEOPLE = "android.people"; 294 295 /** 296 * Value of {@link Notification#color} equal to 0 (also known as 297 * {@link android.graphics.Color#TRANSPARENT Color.TRANSPARENT}), 298 * telling the system not to decorate this notification with any special color but instead use 299 * default colors when presenting this notification. 300 */ 301 public static final int COLOR_DEFAULT = Color.TRANSPARENT; 302 303 /** 304 * Notification visibility: Show this notification in its entirety on all lockscreens. 305 * 306 * {@see android.app.Notification#visibility} 307 */ 308 public static final int VISIBILITY_PUBLIC = 1; 309 310 /** 311 * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or 312 * private information on secure lockscreens. 313 * 314 * {@see android.app.Notification#visibility} 315 */ 316 public static final int VISIBILITY_PRIVATE = 0; 317 318 /** 319 * Notification visibility: Do not reveal any part of this notification on a secure lockscreen. 320 * 321 * {@see android.app.Notification#visibility} 322 */ 323 public static final int VISIBILITY_SECRET = -1; 324 325 /** 326 * Notification category: incoming call (voice or video) or similar synchronous communication request. 327 */ 328 public static final String CATEGORY_CALL = NotificationCompatApi21.CATEGORY_CALL; 329 330 /** 331 * Notification category: incoming direct message (SMS, instant message, etc.). 332 */ 333 public static final String CATEGORY_MESSAGE = NotificationCompatApi21.CATEGORY_MESSAGE; 334 335 /** 336 * Notification category: asynchronous bulk message (email). 337 */ 338 public static final String CATEGORY_EMAIL = NotificationCompatApi21.CATEGORY_EMAIL; 339 340 /** 341 * Notification category: calendar event. 342 */ 343 public static final String CATEGORY_EVENT = NotificationCompatApi21.CATEGORY_EVENT; 344 345 /** 346 * Notification category: promotion or advertisement. 347 */ 348 public static final String CATEGORY_PROMO = NotificationCompatApi21.CATEGORY_PROMO; 349 350 /** 351 * Notification category: alarm or timer. 352 */ 353 public static final String CATEGORY_ALARM = NotificationCompatApi21.CATEGORY_ALARM; 354 355 /** 356 * Notification category: progress of a long-running background operation. 357 */ 358 public static final String CATEGORY_PROGRESS = NotificationCompatApi21.CATEGORY_PROGRESS; 359 360 /** 361 * Notification category: social network or sharing update. 362 */ 363 public static final String CATEGORY_SOCIAL = NotificationCompatApi21.CATEGORY_SOCIAL; 364 365 /** 366 * Notification category: error in background operation or authentication status. 367 */ 368 public static final String CATEGORY_ERROR = NotificationCompatApi21.CATEGORY_ERROR; 369 370 /** 371 * Notification category: media transport control for playback. 372 */ 373 public static final String CATEGORY_TRANSPORT = NotificationCompatApi21.CATEGORY_TRANSPORT; 374 375 /** 376 * Notification category: system or device status update. Reserved for system use. 377 */ 378 public static final String CATEGORY_SYSTEM = NotificationCompatApi21.CATEGORY_SYSTEM; 379 380 /** 381 * Notification category: indication of running background service. 382 */ 383 public static final String CATEGORY_SERVICE = NotificationCompatApi21.CATEGORY_SERVICE; 384 385 /** 386 * Notification category: a specific, timely recommendation for a single thing. 387 * For example, a news app might want to recommend a news story it believes the user will 388 * want to read next. 389 */ 390 public static final String CATEGORY_RECOMMENDATION = 391 NotificationCompatApi21.CATEGORY_RECOMMENDATION; 392 393 /** 394 * Notification category: ongoing information about device or contextual status. 395 */ 396 public static final String CATEGORY_STATUS = NotificationCompatApi21.CATEGORY_STATUS; 397 398 private static final NotificationCompatImpl IMPL; 399 400 interface NotificationCompatImpl { 401 public Notification build(Builder b); 402 public Bundle getExtras(Notification n); 403 public int getActionCount(Notification n); 404 public Action getAction(Notification n, int actionIndex); 405 public Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables); 406 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions); 407 public String getCategory(Notification n); 408 public boolean getLocalOnly(Notification n); 409 public String getGroup(Notification n); 410 public boolean isGroupSummary(Notification n); 411 public String getSortKey(Notification n); 412 } 413 414 static class NotificationCompatImplBase implements NotificationCompatImpl { 415 @Override 416 public Notification build(Builder b) { 417 Notification result = b.mNotification; 418 result.setLatestEventInfo(b.mContext, b.mContentTitle, 419 b.mContentText, b.mContentIntent); 420 // translate high priority requests into legacy flag 421 if (b.mPriority > PRIORITY_DEFAULT) { 422 result.flags |= FLAG_HIGH_PRIORITY; 423 } 424 return result; 425 } 426 427 @Override 428 public Bundle getExtras(Notification n) { 429 return null; 430 } 431 432 @Override 433 public int getActionCount(Notification n) { 434 return 0; 435 } 436 437 @Override 438 public Action getAction(Notification n, int actionIndex) { 439 return null; 440 } 441 442 @Override 443 public Action[] getActionsFromParcelableArrayList( 444 ArrayList<Parcelable> parcelables) { 445 return null; 446 } 447 448 @Override 449 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions) { 450 return null; 451 } 452 453 @Override 454 public String getCategory(Notification n) { 455 return null; 456 } 457 458 @Override 459 public boolean getLocalOnly(Notification n) { 460 return false; 461 } 462 463 @Override 464 public String getGroup(Notification n) { 465 return null; 466 } 467 468 @Override 469 public boolean isGroupSummary(Notification n) { 470 return false; 471 } 472 473 @Override 474 public String getSortKey(Notification n) { 475 return null; 476 } 477 } 478 479 static class NotificationCompatImplGingerbread extends NotificationCompatImplBase { 480 @Override 481 public Notification build(Builder b) { 482 Notification result = b.mNotification; 483 result.setLatestEventInfo(b.mContext, b.mContentTitle, 484 b.mContentText, b.mContentIntent); 485 result = NotificationCompatGingerbread.add(result, b.mContext, 486 b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent); 487 // translate high priority requests into legacy flag 488 if (b.mPriority > PRIORITY_DEFAULT) { 489 result.flags |= FLAG_HIGH_PRIORITY; 490 } 491 return result; 492 } 493 } 494 495 static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase { 496 @Override 497 public Notification build(Builder b) { 498 return NotificationCompatHoneycomb.add(b.mContext, b.mNotification, 499 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 500 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon); 501 } 502 } 503 504 static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase { 505 @Override 506 public Notification build(Builder b) { 507 return NotificationCompatIceCreamSandwich.add(b.mContext, b.mNotification, 508 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 509 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 510 b.mProgressMax, b.mProgress, b.mProgressIndeterminate); 511 } 512 } 513 514 static class NotificationCompatImplJellybean extends NotificationCompatImplBase { 515 @Override 516 public Notification build(Builder b) { 517 NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder( 518 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 519 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 520 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, 521 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras, 522 b.mGroupKey, b.mGroupSummary, b.mSortKey); 523 addActionsToBuilder(builder, b.mActions); 524 addStyleToBuilderJellybean(builder, b.mStyle); 525 return builder.build(); 526 } 527 528 @Override 529 public Bundle getExtras(Notification n) { 530 return NotificationCompatJellybean.getExtras(n); 531 } 532 533 @Override 534 public int getActionCount(Notification n) { 535 return NotificationCompatJellybean.getActionCount(n); 536 } 537 538 @Override 539 public Action getAction(Notification n, int actionIndex) { 540 return (Action) NotificationCompatJellybean.getAction(n, actionIndex, Action.FACTORY, 541 RemoteInput.FACTORY); 542 } 543 544 @Override 545 public Action[] getActionsFromParcelableArrayList( 546 ArrayList<Parcelable> parcelables) { 547 return (Action[]) NotificationCompatJellybean.getActionsFromParcelableArrayList( 548 parcelables, Action.FACTORY, RemoteInput.FACTORY); 549 } 550 551 @Override 552 public ArrayList<Parcelable> getParcelableArrayListForActions( 553 Action[] actions) { 554 return NotificationCompatJellybean.getParcelableArrayListForActions(actions); 555 } 556 557 @Override 558 public boolean getLocalOnly(Notification n) { 559 return NotificationCompatJellybean.getLocalOnly(n); 560 } 561 562 @Override 563 public String getGroup(Notification n) { 564 return NotificationCompatJellybean.getGroup(n); 565 } 566 567 @Override 568 public boolean isGroupSummary(Notification n) { 569 return NotificationCompatJellybean.isGroupSummary(n); 570 } 571 572 @Override 573 public String getSortKey(Notification n) { 574 return NotificationCompatJellybean.getSortKey(n); 575 } 576 } 577 578 static class NotificationCompatImplKitKat extends NotificationCompatImplJellybean { 579 @Override 580 public Notification build(Builder b) { 581 NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder( 582 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 583 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 584 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, 585 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras, 586 b.mGroupKey, b.mGroupSummary, b.mSortKey); 587 addActionsToBuilder(builder, b.mActions); 588 addStyleToBuilderJellybean(builder, b.mStyle); 589 return builder.build(); 590 } 591 592 @Override 593 public Bundle getExtras(Notification n) { 594 return NotificationCompatKitKat.getExtras(n); 595 } 596 597 @Override 598 public int getActionCount(Notification n) { 599 return NotificationCompatKitKat.getActionCount(n); 600 } 601 602 @Override 603 public Action getAction(Notification n, int actionIndex) { 604 return (Action) NotificationCompatKitKat.getAction(n, actionIndex, Action.FACTORY, 605 RemoteInput.FACTORY); 606 } 607 608 @Override 609 public boolean getLocalOnly(Notification n) { 610 return NotificationCompatKitKat.getLocalOnly(n); 611 } 612 613 @Override 614 public String getGroup(Notification n) { 615 return NotificationCompatKitKat.getGroup(n); 616 } 617 618 @Override 619 public boolean isGroupSummary(Notification n) { 620 return NotificationCompatKitKat.isGroupSummary(n); 621 } 622 623 @Override 624 public String getSortKey(Notification n) { 625 return NotificationCompatKitKat.getSortKey(n); 626 } 627 } 628 629 static class NotificationCompatImplApi20 extends NotificationCompatImplKitKat { 630 @Override 631 public Notification build(Builder b) { 632 NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder( 633 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 634 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 635 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, 636 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory, 637 b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion, 638 b.mGroupKey, b.mGroupSummary, b.mSortKey); 639 addActionsToBuilder(builder, b.mActions); 640 addStyleToBuilderJellybean(builder, b.mStyle); 641 return builder.build(); 642 } 643 644 @Override 645 public Action getAction(Notification n, int actionIndex) { 646 return (Action) NotificationCompatApi20.getAction(n, actionIndex, Action.FACTORY, 647 RemoteInput.FACTORY); 648 } 649 650 @Override 651 public Action[] getActionsFromParcelableArrayList( 652 ArrayList<Parcelable> parcelables) { 653 return (Action[]) NotificationCompatApi20.getActionsFromParcelableArrayList( 654 parcelables, Action.FACTORY, RemoteInput.FACTORY); 655 } 656 657 @Override 658 public ArrayList<Parcelable> getParcelableArrayListForActions( 659 Action[] actions) { 660 return NotificationCompatApi20.getParcelableArrayListForActions(actions); 661 } 662 663 @Override 664 public boolean getLocalOnly(Notification n) { 665 return NotificationCompatApi20.getLocalOnly(n); 666 } 667 668 @Override 669 public String getGroup(Notification n) { 670 return NotificationCompatApi20.getGroup(n); 671 } 672 673 @Override 674 public boolean isGroupSummary(Notification n) { 675 return NotificationCompatApi20.isGroupSummary(n); 676 } 677 678 @Override 679 public String getSortKey(Notification n) { 680 return NotificationCompatApi20.getSortKey(n); 681 } 682 } 683 684 private static void addActionsToBuilder(NotificationBuilderWithActions builder, 685 ArrayList<Action> actions) { 686 for (Action action : actions) { 687 builder.addAction(action); 688 } 689 } 690 691 private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder, 692 Style style) { 693 if (style != null) { 694 if (style instanceof BigTextStyle) { 695 BigTextStyle bigTextStyle = (BigTextStyle) style; 696 NotificationCompatJellybean.addBigTextStyle(builder, 697 bigTextStyle.mBigContentTitle, 698 bigTextStyle.mSummaryTextSet, 699 bigTextStyle.mSummaryText, 700 bigTextStyle.mBigText); 701 } else if (style instanceof InboxStyle) { 702 InboxStyle inboxStyle = (InboxStyle) style; 703 NotificationCompatJellybean.addInboxStyle(builder, 704 inboxStyle.mBigContentTitle, 705 inboxStyle.mSummaryTextSet, 706 inboxStyle.mSummaryText, 707 inboxStyle.mTexts); 708 } else if (style instanceof BigPictureStyle) { 709 BigPictureStyle bigPictureStyle = (BigPictureStyle) style; 710 NotificationCompatJellybean.addBigPictureStyle(builder, 711 bigPictureStyle.mBigContentTitle, 712 bigPictureStyle.mSummaryTextSet, 713 bigPictureStyle.mSummaryText, 714 bigPictureStyle.mPicture, 715 bigPictureStyle.mBigLargeIcon, 716 bigPictureStyle.mBigLargeIconSet); 717 } 718 } 719 } 720 721 static class NotificationCompatImplApi21 extends NotificationCompatImplApi20 { 722 @Override 723 public String getCategory(Notification notif) { 724 return NotificationCompatApi21.getCategory(notif); 725 } 726 } 727 728 static { 729 // TODO: Replace this if clause when SDK_INT is incremented to 21. 730 if (Build.VERSION.RELEASE.equals("L")) { 731 IMPL = new NotificationCompatImplApi21(); 732 } else if (Build.VERSION.SDK_INT >= 20) { 733 IMPL = new NotificationCompatImplApi20(); 734 } else if (Build.VERSION.SDK_INT >= 19) { 735 IMPL = new NotificationCompatImplKitKat(); 736 } else if (Build.VERSION.SDK_INT >= 16) { 737 IMPL = new NotificationCompatImplJellybean(); 738 } else if (Build.VERSION.SDK_INT >= 14) { 739 IMPL = new NotificationCompatImplIceCreamSandwich(); 740 } else if (Build.VERSION.SDK_INT >= 11) { 741 IMPL = new NotificationCompatImplHoneycomb(); 742 } else if (Build.VERSION.SDK_INT >= 9) { 743 IMPL = new NotificationCompatImplGingerbread(); 744 } else { 745 IMPL = new NotificationCompatImplBase(); 746 } 747 } 748 749 /** 750 * Builder class for {@link NotificationCompat} objects. Allows easier control over 751 * all the flags, as well as help constructing the typical notification layouts. 752 * <p> 753 * On platform versions that don't offer expanded notifications, methods that depend on 754 * expanded notifications have no effect. 755 * </p> 756 * <p> 757 * For example, action buttons won't appear on platforms prior to Android 4.1. Action 758 * buttons depend on expanded notifications, which are only available in Android 4.1 759 * and later. 760 * <p> 761 * For this reason, you should always ensure that UI controls in a notification are also 762 * available in an {@link android.app.Activity} in your app, and you should always start that 763 * {@link android.app.Activity} when users click the notification. To do this, use the 764 * {@link NotificationCompat.Builder#setContentIntent setContentIntent()} 765 * method. 766 * </p> 767 * 768 */ 769 public static class Builder { 770 Context mContext; 771 772 CharSequence mContentTitle; 773 CharSequence mContentText; 774 PendingIntent mContentIntent; 775 PendingIntent mFullScreenIntent; 776 RemoteViews mTickerView; 777 Bitmap mLargeIcon; 778 CharSequence mContentInfo; 779 int mNumber; 780 int mPriority; 781 boolean mUseChronometer; 782 Style mStyle; 783 CharSequence mSubText; 784 int mProgressMax; 785 int mProgress; 786 boolean mProgressIndeterminate; 787 String mGroupKey; 788 boolean mGroupSummary; 789 String mSortKey; 790 ArrayList<Action> mActions = new ArrayList<Action>(); 791 boolean mLocalOnly = false; 792 String mCategory; 793 Bundle mExtras; 794 int mColor = COLOR_DEFAULT; 795 int mVisibility = VISIBILITY_PRIVATE; 796 Notification mPublicVersion; 797 798 Notification mNotification = new Notification(); 799 public ArrayList<String> mPeople; 800 801 /** 802 * Constructor. 803 * 804 * Automatically sets the when field to {@link System#currentTimeMillis() 805 * System.currentTimeMillis()} and the audio stream to the 806 * {@link Notification#STREAM_DEFAULT}. 807 * 808 * @param context A {@link Context} that will be used to construct the 809 * RemoteViews. The Context will not be held past the lifetime of this 810 * Builder object. 811 */ 812 public Builder(Context context) { 813 mContext = context; 814 815 // Set defaults to match the defaults of a Notification 816 mNotification.when = System.currentTimeMillis(); 817 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 818 mPriority = PRIORITY_DEFAULT; 819 mPeople = new ArrayList<String>(); 820 } 821 822 /** 823 * Set the time that the event occurred. Notifications in the panel are 824 * sorted by this time. 825 */ 826 public Builder setWhen(long when) { 827 mNotification.when = when; 828 return this; 829 } 830 831 /** 832 * Show the {@link Notification#when} field as a stopwatch. 833 * 834 * Instead of presenting <code>when</code> as a timestamp, the notification will show an 835 * automatically updating display of the minutes and seconds since <code>when</code>. 836 * 837 * Useful when showing an elapsed time (like an ongoing phone call). 838 * 839 * @see android.widget.Chronometer 840 * @see Notification#when 841 */ 842 public Builder setUsesChronometer(boolean b) { 843 mUseChronometer = b; 844 return this; 845 } 846 847 /** 848 * Set the small icon to use in the notification layouts. Different classes of devices 849 * may return different sizes. See the UX guidelines for more information on how to 850 * design these icons. 851 * 852 * @param icon A resource ID in the application's package of the drawble to use. 853 */ 854 public Builder setSmallIcon(int icon) { 855 mNotification.icon = icon; 856 return this; 857 } 858 859 /** 860 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional 861 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable 862 * LevelListDrawable}. 863 * 864 * @param icon A resource ID in the application's package of the drawble to use. 865 * @param level The level to use for the icon. 866 * 867 * @see android.graphics.drawable.LevelListDrawable 868 */ 869 public Builder setSmallIcon(int icon, int level) { 870 mNotification.icon = icon; 871 mNotification.iconLevel = level; 872 return this; 873 } 874 875 /** 876 * Set the title (first row) of the notification, in a standard notification. 877 */ 878 public Builder setContentTitle(CharSequence title) { 879 mContentTitle = title; 880 return this; 881 } 882 883 /** 884 * Set the text (second row) of the notification, in a standard notification. 885 */ 886 public Builder setContentText(CharSequence text) { 887 mContentText = text; 888 return this; 889 } 890 891 /** 892 * Set the third line of text in the platform notification template. 893 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; 894 * they occupy the same location in the standard template. 895 * <br> 896 * If the platform does not provide large-format notifications, this method has no effect. 897 * The third line of text only appears in expanded view. 898 * <br> 899 */ 900 public Builder setSubText(CharSequence text) { 901 mSubText = text; 902 return this; 903 } 904 905 /** 906 * Set the large number at the right-hand side of the notification. This is 907 * equivalent to setContentInfo, although it might show the number in a different 908 * font size for readability. 909 */ 910 public Builder setNumber(int number) { 911 mNumber = number; 912 return this; 913 } 914 915 /** 916 * Set the large text at the right-hand side of the notification. 917 */ 918 public Builder setContentInfo(CharSequence info) { 919 mContentInfo = info; 920 return this; 921 } 922 923 /** 924 * Set the progress this notification represents, which may be 925 * represented as a {@link android.widget.ProgressBar}. 926 */ 927 public Builder setProgress(int max, int progress, boolean indeterminate) { 928 mProgressMax = max; 929 mProgress = progress; 930 mProgressIndeterminate = indeterminate; 931 return this; 932 } 933 934 /** 935 * Supply a custom RemoteViews to use instead of the standard one. 936 */ 937 public Builder setContent(RemoteViews views) { 938 mNotification.contentView = views; 939 return this; 940 } 941 942 /** 943 * Supply a {@link PendingIntent} to send when the notification is clicked. 944 * If you do not supply an intent, you can now add PendingIntents to individual 945 * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent 946 * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}. Be sure to 947 * read {@link Notification#contentIntent Notification.contentIntent} for 948 * how to correctly use this. 949 */ 950 public Builder setContentIntent(PendingIntent intent) { 951 mContentIntent = intent; 952 return this; 953 } 954 955 /** 956 * Supply a {@link PendingIntent} to send when the notification is cleared by the user 957 * directly from the notification panel. For example, this intent is sent when the user 958 * clicks the "Clear all" button, or the individual "X" buttons on notifications. This 959 * intent is not sent when the application calls 960 * {@link android.app.NotificationManager#cancel NotificationManager.cancel(int)}. 961 */ 962 public Builder setDeleteIntent(PendingIntent intent) { 963 mNotification.deleteIntent = intent; 964 return this; 965 } 966 967 /** 968 * An intent to launch instead of posting the notification to the status bar. 969 * Only for use with extremely high-priority notifications demanding the user's 970 * <strong>immediate</strong> attention, such as an incoming phone call or 971 * alarm clock that the user has explicitly set to a particular time. 972 * If this facility is used for something else, please give the user an option 973 * to turn it off and use a normal notification, as this can be extremely 974 * disruptive. 975 * 976 * <p> 977 * On some platforms, the system UI may choose to display a heads-up notification, 978 * instead of launching this intent, while the user is using the device. 979 * </p> 980 * 981 * @param intent The pending intent to launch. 982 * @param highPriority Passing true will cause this notification to be sent 983 * even if other notifications are suppressed. 984 */ 985 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { 986 mFullScreenIntent = intent; 987 setFlag(FLAG_HIGH_PRIORITY, highPriority); 988 return this; 989 } 990 991 /** 992 * Set the text that is displayed in the status bar when the notification first 993 * arrives. 994 */ 995 public Builder setTicker(CharSequence tickerText) { 996 mNotification.tickerText = tickerText; 997 return this; 998 } 999 1000 /** 1001 * Set the text that is displayed in the status bar when the notification first 1002 * arrives, and also a RemoteViews object that may be displayed instead on some 1003 * devices. 1004 */ 1005 public Builder setTicker(CharSequence tickerText, RemoteViews views) { 1006 mNotification.tickerText = tickerText; 1007 mTickerView = views; 1008 return this; 1009 } 1010 1011 /** 1012 * Set the large icon that is shown in the ticker and notification. 1013 */ 1014 public Builder setLargeIcon(Bitmap icon) { 1015 mLargeIcon = icon; 1016 return this; 1017 } 1018 1019 /** 1020 * Set the sound to play. It will play on the default stream. 1021 * 1022 * <p> 1023 * On some platforms, a notification that is noisy is more likely to be presented 1024 * as a heads-up notification. 1025 * </p> 1026 */ 1027 public Builder setSound(Uri sound) { 1028 mNotification.sound = sound; 1029 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 1030 return this; 1031 } 1032 1033 /** 1034 * Set the sound to play. It will play on the stream you supply. 1035 * 1036 * <p> 1037 * On some platforms, a notification that is noisy is more likely to be presented 1038 * as a heads-up notification. 1039 * </p> 1040 * 1041 * @see Notification#STREAM_DEFAULT 1042 * @see AudioManager for the <code>STREAM_</code> constants. 1043 */ 1044 public Builder setSound(Uri sound, int streamType) { 1045 mNotification.sound = sound; 1046 mNotification.audioStreamType = streamType; 1047 return this; 1048 } 1049 1050 /** 1051 * Set the vibration pattern to use. 1052 * 1053 * <p> 1054 * On some platforms, a notification that vibrates is more likely to be presented 1055 * as a heads-up notification. 1056 * </p> 1057 * 1058 * @see android.os.Vibrator for a discussion of the <code>pattern</code> 1059 * parameter. 1060 */ 1061 public Builder setVibrate(long[] pattern) { 1062 mNotification.vibrate = pattern; 1063 return this; 1064 } 1065 1066 /** 1067 * Set the argb value that you would like the LED on the device to blnk, as well as the 1068 * rate. The rate is specified in terms of the number of milliseconds to be on 1069 * and then the number of milliseconds to be off. 1070 */ 1071 public Builder setLights(int argb, int onMs, int offMs) { 1072 mNotification.ledARGB = argb; 1073 mNotification.ledOnMS = onMs; 1074 mNotification.ledOffMS = offMs; 1075 boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0; 1076 mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) | 1077 (showLights ? Notification.FLAG_SHOW_LIGHTS : 0); 1078 return this; 1079 } 1080 1081 /** 1082 * Set whether this is an ongoing notification. 1083 * 1084 * <p>Ongoing notifications differ from regular notifications in the following ways: 1085 * <ul> 1086 * <li>Ongoing notifications are sorted above the regular notifications in the 1087 * notification panel.</li> 1088 * <li>Ongoing notifications do not have an 'X' close button, and are not affected 1089 * by the "Clear all" button. 1090 * </ul> 1091 */ 1092 public Builder setOngoing(boolean ongoing) { 1093 setFlag(Notification.FLAG_ONGOING_EVENT, ongoing); 1094 return this; 1095 } 1096 1097 /** 1098 * Set this flag if you would only like the sound, vibrate 1099 * and ticker to be played if the notification is not already showing. 1100 */ 1101 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { 1102 setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); 1103 return this; 1104 } 1105 1106 /** 1107 * Setting this flag will make it so the notification is automatically 1108 * canceled when the user clicks it in the panel. The PendingIntent 1109 * set with {@link #setDeleteIntent} will be broadcast when the notification 1110 * is canceled. 1111 */ 1112 public Builder setAutoCancel(boolean autoCancel) { 1113 setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel); 1114 return this; 1115 } 1116 1117 /** 1118 * Set whether or not this notification is only relevant to the current device. 1119 * 1120 * <p>Some notifications can be bridged to other devices for remote display. 1121 * This hint can be set to recommend this notification not be bridged. 1122 */ 1123 public Builder setLocalOnly(boolean b) { 1124 mLocalOnly = b; 1125 return this; 1126 } 1127 1128 /** 1129 * Set the notification category. 1130 * 1131 * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code> 1132 * constants in {@link Notification}) that best describes this notification. 1133 * May be used by the system for ranking and filtering. 1134 */ 1135 public Builder setCategory(String category) { 1136 mCategory = category; 1137 return this; 1138 } 1139 1140 /** 1141 * Set the default notification options that will be used. 1142 * <p> 1143 * The value should be one or more of the following fields combined with 1144 * bitwise-or: 1145 * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE}, 1146 * {@link Notification#DEFAULT_LIGHTS}. 1147 * <p> 1148 * For all default values, use {@link Notification#DEFAULT_ALL}. 1149 */ 1150 public Builder setDefaults(int defaults) { 1151 mNotification.defaults = defaults; 1152 if ((defaults & Notification.DEFAULT_LIGHTS) != 0) { 1153 mNotification.flags |= Notification.FLAG_SHOW_LIGHTS; 1154 } 1155 return this; 1156 } 1157 1158 private void setFlag(int mask, boolean value) { 1159 if (value) { 1160 mNotification.flags |= mask; 1161 } else { 1162 mNotification.flags &= ~mask; 1163 } 1164 } 1165 1166 /** 1167 * Set the relative priority for this notification. 1168 * 1169 * Priority is an indication of how much of the user's 1170 * valuable attention should be consumed by this 1171 * notification. Low-priority notifications may be hidden from 1172 * the user in certain situations, while the user might be 1173 * interrupted for a higher-priority notification. 1174 * The system sets a notification's priority based on various factors including the 1175 * setPriority value. The effect may differ slightly on different platforms. 1176 * 1177 * @param pri Relative priority for this notification. Must be one of 1178 * the priority constants defined by {@link NotificationCompat}. 1179 * Acceptable values range from {@link 1180 * NotificationCompat#PRIORITY_MIN} (-2) to {@link 1181 * NotificationCompat#PRIORITY_MAX} (2). 1182 */ 1183 public Builder setPriority(int pri) { 1184 mPriority = pri; 1185 return this; 1186 } 1187 1188 /** 1189 * Add a person that is relevant to this notification. 1190 * 1191 * @see Notification#EXTRA_PEOPLE 1192 */ 1193 public Builder addPerson(String handle) { 1194 mPeople.add(handle); 1195 return this; 1196 } 1197 1198 /** 1199 * Set this notification to be part of a group of notifications sharing the same key. 1200 * Grouped notifications may display in a cluster or stack on devices which 1201 * support such rendering. 1202 * 1203 * <p>To make this notification the summary for its group, also call 1204 * {@link #setGroupSummary}. A sort order can be specified for group members by using 1205 * {@link #setSortKey}. 1206 * @param groupKey The group key of the group. 1207 * @return this object for method chaining 1208 */ 1209 public Builder setGroup(String groupKey) { 1210 mGroupKey = groupKey; 1211 return this; 1212 } 1213 1214 /** 1215 * Set this notification to be the group summary for a group of notifications. 1216 * Grouped notifications may display in a cluster or stack on devices which 1217 * support such rendering. Requires a group key also be set using {@link #setGroup}. 1218 * @param isGroupSummary Whether this notification should be a group summary. 1219 * @return this object for method chaining 1220 */ 1221 public Builder setGroupSummary(boolean isGroupSummary) { 1222 mGroupSummary = isGroupSummary; 1223 return this; 1224 } 1225 1226 /** 1227 * Set a sort key that orders this notification among other notifications from the 1228 * same package. This can be useful if an external sort was already applied and an app 1229 * would like to preserve this. Notifications will be sorted lexicographically using this 1230 * value, although providing different priorities in addition to providing sort key may 1231 * cause this value to be ignored. 1232 * 1233 * <p>This sort key can also be used to order members of a notification group. See 1234 * {@link Builder#setGroup}. 1235 * 1236 * @see String#compareTo(String) 1237 */ 1238 public Builder setSortKey(String sortKey) { 1239 mSortKey = sortKey; 1240 return this; 1241 } 1242 1243 /** 1244 * Merge additional metadata into this notification. 1245 * 1246 * <p>Values within the Bundle will replace existing extras values in this Builder. 1247 * 1248 * @see Notification#extras 1249 */ 1250 public Builder addExtras(Bundle extras) { 1251 if (extras != null) { 1252 if (mExtras == null) { 1253 mExtras = new Bundle(extras); 1254 } else { 1255 mExtras.putAll(extras); 1256 } 1257 } 1258 return this; 1259 } 1260 1261 /** 1262 * Set metadata for this notification. 1263 * 1264 * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's 1265 * current contents are copied into the Notification each time {@link #build()} is 1266 * called. 1267 * 1268 * <p>Replaces any existing extras values with those from the provided Bundle. 1269 * Use {@link #addExtras} to merge in metadata instead. 1270 * 1271 * @see Notification#extras 1272 */ 1273 public Builder setExtras(Bundle extras) { 1274 mExtras = extras; 1275 return this; 1276 } 1277 1278 /** 1279 * Get the current metadata Bundle used by this notification Builder. 1280 * 1281 * <p>The returned Bundle is shared with this Builder. 1282 * 1283 * <p>The current contents of this Bundle are copied into the Notification each time 1284 * {@link #build()} is called. 1285 * 1286 * @see Notification#extras 1287 */ 1288 public Bundle getExtras() { 1289 if (mExtras == null) { 1290 mExtras = new Bundle(); 1291 } 1292 return mExtras; 1293 } 1294 1295 /** 1296 * Add an action to this notification. Actions are typically displayed by 1297 * the system as a button adjacent to the notification content. 1298 * <br> 1299 * Action buttons won't appear on platforms prior to Android 4.1. Action 1300 * buttons depend on expanded notifications, which are only available in Android 4.1 1301 * and later. To ensure that an action button's functionality is always available, first 1302 * implement the functionality in the {@link android.app.Activity} that starts when a user 1303 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1304 * enhance the notification by implementing the same functionality with 1305 * {@link #addAction addAction()}. 1306 * 1307 * @param icon Resource ID of a drawable that represents the action. 1308 * @param title Text describing the action. 1309 * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked. 1310 */ 1311 public Builder addAction(int icon, CharSequence title, PendingIntent intent) { 1312 mActions.add(new Action(icon, title, intent)); 1313 return this; 1314 } 1315 1316 /** 1317 * Add an action to this notification. Actions are typically displayed by 1318 * the system as a button adjacent to the notification content. 1319 * <br> 1320 * Action buttons won't appear on platforms prior to Android 4.1. Action 1321 * buttons depend on expanded notifications, which are only available in Android 4.1 1322 * and later. To ensure that an action button's functionality is always available, first 1323 * implement the functionality in the {@link android.app.Activity} that starts when a user 1324 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1325 * enhance the notification by implementing the same functionality with 1326 * {@link #addAction addAction()}. 1327 * 1328 * @param action The action to add. 1329 */ 1330 public Builder addAction(Action action) { 1331 mActions.add(action); 1332 return this; 1333 } 1334 1335 /** 1336 * Add a rich notification style to be applied at build time. 1337 * <br> 1338 * If the platform does not provide rich notification styles, this method has no effect. The 1339 * user will always see the normal notification style. 1340 * 1341 * @param style Object responsible for modifying the notification style. 1342 */ 1343 public Builder setStyle(Style style) { 1344 if (mStyle != style) { 1345 mStyle = style; 1346 if (mStyle != null) { 1347 mStyle.setBuilder(this); 1348 } 1349 } 1350 return this; 1351 } 1352 1353 /** 1354 * Sets {@link Notification#color}. 1355 * 1356 * @param argb The accent color to use 1357 * 1358 * @return The same Builder. 1359 */ 1360 public Builder setColor(int argb) { 1361 mColor = argb; 1362 return this; 1363 } 1364 1365 /** 1366 * Sets {@link Notification#visibility}. 1367 * 1368 * @param visibility One of {@link Notification#VISIBILITY_PRIVATE} (the default), 1369 * {@link Notification#VISIBILITY_PUBLIC}, or 1370 * {@link Notification#VISIBILITY_SECRET}. 1371 */ 1372 public Builder setVisibility(int visibility) { 1373 mVisibility = visibility; 1374 return this; 1375 } 1376 1377 /** 1378 * Supply a replacement Notification whose contents should be shown in insecure contexts 1379 * (i.e. atop the secure lockscreen). See {@link Notification#visibility} and 1380 * {@link #VISIBILITY_PUBLIC}. 1381 * 1382 * @param n A replacement notification, presumably with some or all info redacted. 1383 * @return The same Builder. 1384 */ 1385 public Builder setPublicVersion(Notification n) { 1386 mPublicVersion = n; 1387 return this; 1388 } 1389 1390 /** 1391 * Apply an extender to this notification builder. Extenders may be used to add 1392 * metadata or change options on this builder. 1393 */ 1394 public Builder extend(Extender extender) { 1395 extender.extend(this); 1396 return this; 1397 } 1398 1399 /** 1400 * @deprecated Use {@link #build()} instead. 1401 */ 1402 @Deprecated 1403 public Notification getNotification() { 1404 return IMPL.build(this); 1405 } 1406 1407 /** 1408 * Combine all of the options that have been set and return a new {@link Notification} 1409 * object. 1410 */ 1411 public Notification build() { 1412 return IMPL.build(this); 1413 } 1414 } 1415 1416 /** 1417 * An object that can apply a rich notification style to a {@link Notification.Builder} 1418 * object. 1419 * <br> 1420 * If the platform does not provide rich notification styles, methods in this class have no 1421 * effect. 1422 */ 1423 public static abstract class Style { 1424 Builder mBuilder; 1425 CharSequence mBigContentTitle; 1426 CharSequence mSummaryText; 1427 boolean mSummaryTextSet = false; 1428 1429 public void setBuilder(Builder builder) { 1430 if (mBuilder != builder) { 1431 mBuilder = builder; 1432 if (mBuilder != null) { 1433 mBuilder.setStyle(this); 1434 } 1435 } 1436 } 1437 1438 public Notification build() { 1439 Notification notification = null; 1440 if (mBuilder != null) { 1441 notification = mBuilder.build(); 1442 } 1443 return notification; 1444 } 1445 } 1446 1447 /** 1448 * Helper class for generating large-format notifications that include a large image attachment. 1449 * <br> 1450 * If the platform does not provide large-format notifications, this method has no effect. The 1451 * user will always see the normal notification view. 1452 * <br> 1453 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1454 * <pre class="prettyprint"> 1455 * Notification notif = new Notification.Builder(mContext) 1456 * .setContentTitle("New photo from " + sender.toString()) 1457 * .setContentText(subject) 1458 * .setSmallIcon(R.drawable.new_post) 1459 * .setLargeIcon(aBitmap) 1460 * .setStyle(new Notification.BigPictureStyle() 1461 * .bigPicture(aBigBitmap)) 1462 * .build(); 1463 * </pre> 1464 * 1465 * @see Notification#bigContentView 1466 */ 1467 public static class BigPictureStyle extends Style { 1468 Bitmap mPicture; 1469 Bitmap mBigLargeIcon; 1470 boolean mBigLargeIconSet; 1471 1472 public BigPictureStyle() { 1473 } 1474 1475 public BigPictureStyle(Builder builder) { 1476 setBuilder(builder); 1477 } 1478 1479 /** 1480 * Overrides ContentTitle in the big form of the template. 1481 * This defaults to the value passed to setContentTitle(). 1482 */ 1483 public BigPictureStyle setBigContentTitle(CharSequence title) { 1484 mBigContentTitle = title; 1485 return this; 1486 } 1487 1488 /** 1489 * Set the first line of text after the detail section in the big form of the template. 1490 */ 1491 public BigPictureStyle setSummaryText(CharSequence cs) { 1492 mSummaryText = cs; 1493 mSummaryTextSet = true; 1494 return this; 1495 } 1496 1497 /** 1498 * Provide the bitmap to be used as the payload for the BigPicture notification. 1499 */ 1500 public BigPictureStyle bigPicture(Bitmap b) { 1501 mPicture = b; 1502 return this; 1503 } 1504 1505 /** 1506 * Override the large icon when the big notification is shown. 1507 */ 1508 public BigPictureStyle bigLargeIcon(Bitmap b) { 1509 mBigLargeIcon = b; 1510 mBigLargeIconSet = true; 1511 return this; 1512 } 1513 } 1514 1515 /** 1516 * Helper class for generating large-format notifications that include a lot of text. 1517 * 1518 * <br> 1519 * If the platform does not provide large-format notifications, this method has no effect. The 1520 * user will always see the normal notification view. 1521 * <br> 1522 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1523 * <pre class="prettyprint"> 1524 * Notification notif = new Notification.Builder(mContext) 1525 * .setContentTitle("New mail from " + sender.toString()) 1526 * .setContentText(subject) 1527 * .setSmallIcon(R.drawable.new_mail) 1528 * .setLargeIcon(aBitmap) 1529 * .setStyle(new Notification.BigTextStyle() 1530 * .bigText(aVeryLongString)) 1531 * .build(); 1532 * </pre> 1533 * 1534 * @see Notification#bigContentView 1535 */ 1536 public static class BigTextStyle extends Style { 1537 CharSequence mBigText; 1538 1539 public BigTextStyle() { 1540 } 1541 1542 public BigTextStyle(Builder builder) { 1543 setBuilder(builder); 1544 } 1545 1546 /** 1547 * Overrides ContentTitle in the big form of the template. 1548 * This defaults to the value passed to setContentTitle(). 1549 */ 1550 public BigTextStyle setBigContentTitle(CharSequence title) { 1551 mBigContentTitle = title; 1552 return this; 1553 } 1554 1555 /** 1556 * Set the first line of text after the detail section in the big form of the template. 1557 */ 1558 public BigTextStyle setSummaryText(CharSequence cs) { 1559 mSummaryText = cs; 1560 mSummaryTextSet = true; 1561 return this; 1562 } 1563 1564 /** 1565 * Provide the longer text to be displayed in the big form of the 1566 * template in place of the content text. 1567 */ 1568 public BigTextStyle bigText(CharSequence cs) { 1569 mBigText = cs; 1570 return this; 1571 } 1572 } 1573 1574 /** 1575 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 1576 * 1577 * <br> 1578 * If the platform does not provide large-format notifications, this method has no effect. The 1579 * user will always see the normal notification view. 1580 * <br> 1581 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1582 * <pre class="prettyprint"> 1583 * Notification noti = new Notification.Builder() 1584 * .setContentTitle("5 New mails from " + sender.toString()) 1585 * .setContentText(subject) 1586 * .setSmallIcon(R.drawable.new_mail) 1587 * .setLargeIcon(aBitmap) 1588 * .setStyle(new Notification.InboxStyle() 1589 * .addLine(str1) 1590 * .addLine(str2) 1591 * .setContentTitle("") 1592 * .setSummaryText("+3 more")) 1593 * .build(); 1594 * </pre> 1595 * 1596 * @see Notification#bigContentView 1597 */ 1598 public static class InboxStyle extends Style { 1599 ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 1600 1601 public InboxStyle() { 1602 } 1603 1604 public InboxStyle(Builder builder) { 1605 setBuilder(builder); 1606 } 1607 1608 /** 1609 * Overrides ContentTitle in the big form of the template. 1610 * This defaults to the value passed to setContentTitle(). 1611 */ 1612 public InboxStyle setBigContentTitle(CharSequence title) { 1613 mBigContentTitle = title; 1614 return this; 1615 } 1616 1617 /** 1618 * Set the first line of text after the detail section in the big form of the template. 1619 */ 1620 public InboxStyle setSummaryText(CharSequence cs) { 1621 mSummaryText = cs; 1622 mSummaryTextSet = true; 1623 return this; 1624 } 1625 1626 /** 1627 * Append a line to the digest section of the Inbox notification. 1628 */ 1629 public InboxStyle addLine(CharSequence cs) { 1630 mTexts.add(cs); 1631 return this; 1632 } 1633 } 1634 1635 /** 1636 * Structure to encapsulate a named action that can be shown as part of this notification. 1637 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is 1638 * selected by the user. Action buttons won't appear on platforms prior to Android 4.1. 1639 * <p> 1640 * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)} 1641 * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)} 1642 * to attach actions. 1643 */ 1644 public static class Action extends NotificationCompatBase.Action { 1645 private final Bundle mExtras; 1646 private final RemoteInput[] mRemoteInputs; 1647 1648 /** 1649 * Small icon representing the action. 1650 */ 1651 public int icon; 1652 /** 1653 * Title of the action. 1654 */ 1655 public CharSequence title; 1656 /** 1657 * Intent to send when the user invokes this action. May be null, in which case the action 1658 * may be rendered in a disabled presentation. 1659 */ 1660 public PendingIntent actionIntent; 1661 1662 public Action(int icon, CharSequence title, PendingIntent intent) { 1663 this(icon, title, intent, new Bundle(), null); 1664 } 1665 1666 private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, 1667 RemoteInput[] remoteInputs) { 1668 this.icon = icon; 1669 this.title = title; 1670 this.actionIntent = intent; 1671 this.mExtras = extras != null ? extras : new Bundle(); 1672 this.mRemoteInputs = remoteInputs; 1673 } 1674 1675 @Override 1676 protected int getIcon() { 1677 return icon; 1678 } 1679 1680 @Override 1681 protected CharSequence getTitle() { 1682 return title; 1683 } 1684 1685 @Override 1686 protected PendingIntent getActionIntent() { 1687 return actionIntent; 1688 } 1689 1690 /** 1691 * Get additional metadata carried around with this Action. 1692 */ 1693 public Bundle getExtras() { 1694 return mExtras; 1695 } 1696 1697 /** 1698 * Get the list of inputs to be collected from the user when this action is sent. 1699 * May return null if no remote inputs were added. 1700 */ 1701 public RemoteInput[] getRemoteInputs() { 1702 return mRemoteInputs; 1703 } 1704 1705 /** 1706 * Builder class for {@link Action} objects. 1707 */ 1708 public static final class Builder { 1709 private final int mIcon; 1710 private final CharSequence mTitle; 1711 private final PendingIntent mIntent; 1712 private final Bundle mExtras; 1713 private ArrayList<RemoteInput> mRemoteInputs; 1714 1715 /** 1716 * Construct a new builder for {@link Action} object. 1717 * @param icon icon to show for this action 1718 * @param title the title of the action 1719 * @param intent the {@link PendingIntent} to fire when users trigger this action 1720 */ 1721 public Builder(int icon, CharSequence title, PendingIntent intent) { 1722 this(icon, title, intent, new Bundle()); 1723 } 1724 1725 /** 1726 * Construct a new builder for {@link Action} object using the fields from an 1727 * {@link Action}. 1728 * @param action the action to read fields from. 1729 */ 1730 public Builder(Action action) { 1731 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras)); 1732 } 1733 1734 private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) { 1735 mIcon = icon; 1736 mTitle = title; 1737 mIntent = intent; 1738 mExtras = extras; 1739 } 1740 1741 /** 1742 * Merge additional metadata into this builder. 1743 * 1744 * <p>Values within the Bundle will replace existing extras values in this Builder. 1745 * 1746 * @see NotificationCompat.Action#getExtras 1747 */ 1748 public Builder addExtras(Bundle extras) { 1749 if (extras != null) { 1750 mExtras.putAll(extras); 1751 } 1752 return this; 1753 } 1754 1755 /** 1756 * Get the metadata Bundle used by this Builder. 1757 * 1758 * <p>The returned Bundle is shared with this Builder. 1759 */ 1760 public Bundle getExtras() { 1761 return mExtras; 1762 } 1763 1764 /** 1765 * Add an input to be collected from the user when this action is sent. 1766 * Response values can be retrieved from the fired intent by using the 1767 * {@link RemoteInput#getResultsFromIntent} function. 1768 * @param remoteInput a {@link RemoteInput} to add to the action 1769 * @return this object for method chaining 1770 */ 1771 public Builder addRemoteInput(RemoteInput remoteInput) { 1772 if (mRemoteInputs == null) { 1773 mRemoteInputs = new ArrayList<RemoteInput>(); 1774 } 1775 mRemoteInputs.add(remoteInput); 1776 return this; 1777 } 1778 1779 /** 1780 * Apply an extender to this action builder. Extenders may be used to add 1781 * metadata or change options on this builder. 1782 */ 1783 public Builder extend(Extender extender) { 1784 extender.extend(this); 1785 return this; 1786 } 1787 1788 /** 1789 * Combine all of the options that have been set and return a new {@link Action} 1790 * object. 1791 * @return the built action 1792 */ 1793 public Action build() { 1794 RemoteInput[] remoteInputs = mRemoteInputs != null 1795 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; 1796 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs); 1797 } 1798 } 1799 1800 1801 /** 1802 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 1803 * metadata or change options on an action builder. 1804 */ 1805 public interface Extender { 1806 /** 1807 * Apply this extender to a notification action builder. 1808 * @param builder the builder to be modified. 1809 * @return the build object for chaining. 1810 */ 1811 public Builder extend(Builder builder); 1812 } 1813 1814 /** 1815 * Wearable extender for notification actions. To add extensions to an action, 1816 * create a new {@link NotificationCompat.Action.WearableExtender} object using 1817 * the {@code WearableExtender()} constructor and apply it to a 1818 * {@link NotificationCompat.Action.Builder} using 1819 * {@link NotificationCompat.Action.Builder#extend}. 1820 * 1821 * <pre class="prettyprint"> 1822 * NotificationCompat.Action action = new NotificationCompat.Action.Builder( 1823 * R.drawable.archive_all, "Archive all", actionIntent) 1824 * .extend(new NotificationCompat.Action.WearableExtender() 1825 * .setAvailableOffline(false)) 1826 * .build();</pre> 1827 */ 1828 public static final class WearableExtender implements Extender { 1829 /** Notification action extra which contains wearable extensions */ 1830 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 1831 1832 private static final String KEY_FLAGS = "flags"; 1833 1834 // Flags bitwise-ored to mFlags 1835 private static final int FLAG_AVAILABLE_OFFLINE = 0x1; 1836 1837 // Default value for flags integer 1838 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE; 1839 1840 private int mFlags = DEFAULT_FLAGS; 1841 1842 /** 1843 * Create a {@link NotificationCompat.Action.WearableExtender} with default 1844 * options. 1845 */ 1846 public WearableExtender() { 1847 } 1848 1849 /** 1850 * Create a {@link NotificationCompat.Action.WearableExtender} by reading 1851 * wearable options present in an existing notification action. 1852 * @param action the notification action to inspect. 1853 */ 1854 public WearableExtender(Action action) { 1855 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS); 1856 if (wearableBundle != null) { 1857 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 1858 } 1859 } 1860 1861 /** 1862 * Apply wearable extensions to a notification action that is being built. This is 1863 * typically called by the {@link NotificationCompat.Action.Builder#extend} 1864 * method of {@link NotificationCompat.Action.Builder}. 1865 */ 1866 @Override 1867 public Action.Builder extend(Action.Builder builder) { 1868 Bundle wearableBundle = new Bundle(); 1869 1870 if (mFlags != DEFAULT_FLAGS) { 1871 wearableBundle.putInt(KEY_FLAGS, mFlags); 1872 } 1873 1874 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 1875 return builder; 1876 } 1877 1878 @Override 1879 public WearableExtender clone() { 1880 WearableExtender that = new WearableExtender(); 1881 that.mFlags = this.mFlags; 1882 return that; 1883 } 1884 1885 /** 1886 * Set whether this action is available when the wearable device is not connected to 1887 * a companion device. The user can still trigger this action when the wearable device 1888 * is offline, but a visual hint will indicate that the action may not be available. 1889 * Defaults to true. 1890 */ 1891 public WearableExtender setAvailableOffline(boolean availableOffline) { 1892 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline); 1893 return this; 1894 } 1895 1896 /** 1897 * Get whether this action is available when the wearable device is not connected to 1898 * a companion device. The user can still trigger this action when the wearable device 1899 * is offline, but a visual hint will indicate that the action may not be available. 1900 * Defaults to true. 1901 */ 1902 public boolean isAvailableOffline() { 1903 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0; 1904 } 1905 1906 private void setFlag(int mask, boolean value) { 1907 if (value) { 1908 mFlags |= mask; 1909 } else { 1910 mFlags &= ~mask; 1911 } 1912 } 1913 } 1914 1915 /** @hide */ 1916 public static final Factory FACTORY = new Factory() { 1917 @Override 1918 public Action build(int icon, CharSequence title, 1919 PendingIntent actionIntent, Bundle extras, 1920 RemoteInputCompatBase.RemoteInput[] remoteInputs) { 1921 return new Action(icon, title, actionIntent, extras, 1922 (RemoteInput[]) remoteInputs); 1923 } 1924 1925 @Override 1926 public Action[] newArray(int length) { 1927 return new Action[length]; 1928 } 1929 }; 1930 } 1931 1932 1933 /** 1934 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 1935 * metadata or change options on a notification builder. 1936 */ 1937 public interface Extender { 1938 /** 1939 * Apply this extender to a notification builder. 1940 * @param builder the builder to be modified. 1941 * @return the build object for chaining. 1942 */ 1943 public Builder extend(Builder builder); 1944 } 1945 1946 /** 1947 * Helper class to add wearable extensions to notifications. 1948 * <p class="note"> See 1949 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications 1950 * for Android Wear</a> for more information on how to use this class. 1951 * <p> 1952 * To create a notification with wearable extensions: 1953 * <ol> 1954 * <li>Create a {@link NotificationCompat.Builder}, setting any desired 1955 * properties. 1956 * <li>Create a {@link NotificationCompat.WearableExtender}. 1957 * <li>Set wearable-specific properties using the 1958 * {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}. 1959 * <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a 1960 * notification. 1961 * <li>Post the notification to the notification 1962 * system with the {@code NotificationManagerCompat.notify(...)} methods 1963 * and not the {@code NotificationManager.notify(...)} methods. 1964 * </ol> 1965 * 1966 * <pre class="prettyprint"> 1967 * Notification notif = new NotificationCompat.Builder(mContext) 1968 * .setContentTitle("New mail from " + sender.toString()) 1969 * .setContentText(subject) 1970 * .setSmallIcon(R.drawable.new_mail) 1971 * .extend(new NotificationCompat.WearableExtender() 1972 * .setContentIcon(R.drawable.new_mail)) 1973 * .build(); 1974 * NotificationManagerCompat.from(mContext).notify(0, notif);</pre> 1975 * 1976 * <p>Wearable extensions can be accessed on an existing notification by using the 1977 * {@code WearableExtender(Notification)} constructor, 1978 * and then using the {@code get} methods to access values. 1979 * 1980 * <pre class="prettyprint"> 1981 * NotificationCompat.WearableExtender wearableExtender = 1982 * new NotificationCompat.WearableExtender(notification); 1983 * List<Notification> pages = wearableExtender.getPages();</pre> 1984 */ 1985 public static final class WearableExtender implements Extender { 1986 /** 1987 * Sentinel value for an action index that is unset. 1988 */ 1989 public static final int UNSET_ACTION_INDEX = -1; 1990 1991 /** 1992 * Size value for use with {@link #setCustomSizePreset} to show this notification with 1993 * default sizing. 1994 * <p>For custom display notifications created using {@link #setDisplayIntent}, 1995 * the default is {@link #SIZE_LARGE}. All other notifications size automatically based 1996 * on their content. 1997 */ 1998 public static final int SIZE_DEFAULT = 0; 1999 2000 /** 2001 * Size value for use with {@link #setCustomSizePreset} to show this notification 2002 * with an extra small size. 2003 * <p>This value is only applicable for custom display notifications created using 2004 * {@link #setDisplayIntent}. 2005 */ 2006 public static final int SIZE_XSMALL = 1; 2007 2008 /** 2009 * Size value for use with {@link #setCustomSizePreset} to show this notification 2010 * with a small size. 2011 * <p>This value is only applicable for custom display notifications created using 2012 * {@link #setDisplayIntent}. 2013 */ 2014 public static final int SIZE_SMALL = 2; 2015 2016 /** 2017 * Size value for use with {@link #setCustomSizePreset} to show this notification 2018 * with a medium size. 2019 * <p>This value is only applicable for custom display notifications created using 2020 * {@link #setDisplayIntent}. 2021 */ 2022 public static final int SIZE_MEDIUM = 3; 2023 2024 /** 2025 * Size value for use with {@link #setCustomSizePreset} to show this notification 2026 * with a large size. 2027 * <p>This value is only applicable for custom display notifications created using 2028 * {@link #setDisplayIntent}. 2029 */ 2030 public static final int SIZE_LARGE = 4; 2031 2032 /** 2033 * Size value for use with {@link #setCustomSizePreset} to show this notification 2034 * full screen. 2035 * <p>This value is only applicable for custom display notifications created using 2036 * {@link #setDisplayIntent}. 2037 */ 2038 public static final int SIZE_FULL_SCREEN = 5; 2039 2040 /** Notification extra which contains wearable extensions */ 2041 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2042 2043 // Keys within EXTRA_WEARABLE_OPTIONS for wearable options. 2044 private static final String KEY_ACTIONS = "actions"; 2045 private static final String KEY_FLAGS = "flags"; 2046 private static final String KEY_DISPLAY_INTENT = "displayIntent"; 2047 private static final String KEY_PAGES = "pages"; 2048 private static final String KEY_BACKGROUND = "background"; 2049 private static final String KEY_CONTENT_ICON = "contentIcon"; 2050 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity"; 2051 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex"; 2052 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset"; 2053 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; 2054 private static final String KEY_GRAVITY = "gravity"; 2055 2056 // Flags bitwise-ored to mFlags 2057 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; 2058 private static final int FLAG_HINT_HIDE_ICON = 1 << 1; 2059 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2; 2060 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3; 2061 2062 // Default value for flags integer 2063 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE; 2064 2065 private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END; 2066 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM; 2067 2068 private ArrayList<Action> mActions = new ArrayList<Action>(); 2069 private int mFlags = DEFAULT_FLAGS; 2070 private PendingIntent mDisplayIntent; 2071 private ArrayList<Notification> mPages = new ArrayList<Notification>(); 2072 private Bitmap mBackground; 2073 private int mContentIcon; 2074 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY; 2075 private int mContentActionIndex = UNSET_ACTION_INDEX; 2076 private int mCustomSizePreset = SIZE_DEFAULT; 2077 private int mCustomContentHeight; 2078 private int mGravity = DEFAULT_GRAVITY; 2079 2080 /** 2081 * Create a {@link NotificationCompat.WearableExtender} with default 2082 * options. 2083 */ 2084 public WearableExtender() { 2085 } 2086 2087 public WearableExtender(Notification notif) { 2088 Bundle extras = getExtras(notif); 2089 Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS) 2090 : null; 2091 if (wearableBundle != null) { 2092 Action[] actions = IMPL.getActionsFromParcelableArrayList( 2093 wearableBundle.getParcelableArrayList(KEY_ACTIONS)); 2094 if (actions != null) { 2095 Collections.addAll(mActions, actions); 2096 } 2097 2098 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 2099 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); 2100 2101 Notification[] pages = getNotificationArrayFromBundle( 2102 wearableBundle, KEY_PAGES); 2103 if (pages != null) { 2104 Collections.addAll(mPages, pages); 2105 } 2106 2107 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND); 2108 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON); 2109 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY, 2110 DEFAULT_CONTENT_ICON_GRAVITY); 2111 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX, 2112 UNSET_ACTION_INDEX); 2113 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET, 2114 SIZE_DEFAULT); 2115 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); 2116 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); 2117 } 2118 } 2119 2120 /** 2121 * Apply wearable extensions to a notification that is being built. This is typically 2122 * called by the {@link NotificationCompat.Builder#extend} method of 2123 * {@link NotificationCompat.Builder}. 2124 */ 2125 @Override 2126 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 2127 Bundle wearableBundle = new Bundle(); 2128 2129 if (!mActions.isEmpty()) { 2130 wearableBundle.putParcelableArrayList(KEY_ACTIONS, 2131 IMPL.getParcelableArrayListForActions(mActions.toArray( 2132 new Action[mActions.size()]))); 2133 } 2134 if (mFlags != DEFAULT_FLAGS) { 2135 wearableBundle.putInt(KEY_FLAGS, mFlags); 2136 } 2137 if (mDisplayIntent != null) { 2138 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent); 2139 } 2140 if (!mPages.isEmpty()) { 2141 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( 2142 new Notification[mPages.size()])); 2143 } 2144 if (mBackground != null) { 2145 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); 2146 } 2147 if (mContentIcon != 0) { 2148 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); 2149 } 2150 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) { 2151 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity); 2152 } 2153 if (mContentActionIndex != UNSET_ACTION_INDEX) { 2154 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX, 2155 mContentActionIndex); 2156 } 2157 if (mCustomSizePreset != SIZE_DEFAULT) { 2158 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset); 2159 } 2160 if (mCustomContentHeight != 0) { 2161 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight); 2162 } 2163 if (mGravity != DEFAULT_GRAVITY) { 2164 wearableBundle.putInt(KEY_GRAVITY, mGravity); 2165 } 2166 2167 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 2168 return builder; 2169 } 2170 2171 @Override 2172 public WearableExtender clone() { 2173 WearableExtender that = new WearableExtender(); 2174 that.mActions = new ArrayList<Action>(this.mActions); 2175 that.mFlags = this.mFlags; 2176 that.mDisplayIntent = this.mDisplayIntent; 2177 that.mPages = new ArrayList<Notification>(this.mPages); 2178 that.mBackground = this.mBackground; 2179 that.mContentIcon = this.mContentIcon; 2180 that.mContentIconGravity = this.mContentIconGravity; 2181 that.mContentActionIndex = this.mContentActionIndex; 2182 that.mCustomSizePreset = this.mCustomSizePreset; 2183 that.mCustomContentHeight = this.mCustomContentHeight; 2184 that.mGravity = this.mGravity; 2185 return that; 2186 } 2187 2188 /** 2189 * Add a wearable action to this notification. 2190 * 2191 * <p>When wearable actions are added using this method, the set of actions that 2192 * show on a wearable device splits from devices that only show actions added 2193 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2194 * of which actions display on different devices. 2195 * 2196 * @param action the action to add to this notification 2197 * @return this object for method chaining 2198 * @see NotificationCompat.Action 2199 */ 2200 public WearableExtender addAction(Action action) { 2201 mActions.add(action); 2202 return this; 2203 } 2204 2205 /** 2206 * Adds wearable actions to this notification. 2207 * 2208 * <p>When wearable actions are added using this method, the set of actions that 2209 * show on a wearable device splits from devices that only show actions added 2210 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2211 * of which actions display on different devices. 2212 * 2213 * @param actions the actions to add to this notification 2214 * @return this object for method chaining 2215 * @see NotificationCompat.Action 2216 */ 2217 public WearableExtender addActions(List<Action> actions) { 2218 mActions.addAll(actions); 2219 return this; 2220 } 2221 2222 /** 2223 * Clear all wearable actions present on this builder. 2224 * @return this object for method chaining. 2225 * @see #addAction 2226 */ 2227 public WearableExtender clearActions() { 2228 mActions.clear(); 2229 return this; 2230 } 2231 2232 /** 2233 * Get the wearable actions present on this notification. 2234 */ 2235 public List<Action> getActions() { 2236 return mActions; 2237 } 2238 2239 /** 2240 * Set an intent to launch inside of an activity view when displaying 2241 * this notification. The {@link PendingIntent} provided should be for an activity. 2242 * 2243 * <pre class="prettyprint"> 2244 * Intent displayIntent = new Intent(context, MyDisplayActivity.class); 2245 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context, 2246 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT); 2247 * Notification notif = new NotificationCompat.Builder(context) 2248 * .extend(new NotificationCompat.WearableExtender() 2249 * .setDisplayIntent(displayPendingIntent) 2250 * .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM)) 2251 * .build();</pre> 2252 * 2253 * <p>The activity to launch needs to allow embedding, must be exported, and 2254 * should have an empty task affinity. It is also recommended to use the device 2255 * default light theme. 2256 * 2257 * <p>Example AndroidManifest.xml entry: 2258 * <pre class="prettyprint"> 2259 * <activity android:name="com.example.MyDisplayActivity" 2260 * android:exported="true" 2261 * android:allowEmbedded="true" 2262 * android:taskAffinity="" 2263 * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre> 2264 * 2265 * @param intent the {@link PendingIntent} for an activity 2266 * @return this object for method chaining 2267 * @see NotificationCompat.WearableExtender#getDisplayIntent 2268 */ 2269 public WearableExtender setDisplayIntent(PendingIntent intent) { 2270 mDisplayIntent = intent; 2271 return this; 2272 } 2273 2274 /** 2275 * Get the intent to launch inside of an activity view when displaying this 2276 * notification. This {@code PendingIntent} should be for an activity. 2277 */ 2278 public PendingIntent getDisplayIntent() { 2279 return mDisplayIntent; 2280 } 2281 2282 /** 2283 * Add an additional page of content to display with this notification. The current 2284 * notification forms the first page, and pages added using this function form 2285 * subsequent pages. This field can be used to separate a notification into multiple 2286 * sections. 2287 * 2288 * @param page the notification to add as another page 2289 * @return this object for method chaining 2290 * @see NotificationCompat.WearableExtender#getPages 2291 */ 2292 public WearableExtender addPage(Notification page) { 2293 mPages.add(page); 2294 return this; 2295 } 2296 2297 /** 2298 * Add additional pages of content to display with this notification. The current 2299 * notification forms the first page, and pages added using this function form 2300 * subsequent pages. This field can be used to separate a notification into multiple 2301 * sections. 2302 * 2303 * @param pages a list of notifications 2304 * @return this object for method chaining 2305 * @see NotificationCompat.WearableExtender#getPages 2306 */ 2307 public WearableExtender addPages(List<Notification> pages) { 2308 mPages.addAll(pages); 2309 return this; 2310 } 2311 2312 /** 2313 * Clear all additional pages present on this builder. 2314 * @return this object for method chaining. 2315 * @see #addPage 2316 */ 2317 public WearableExtender clearPages() { 2318 mPages.clear(); 2319 return this; 2320 } 2321 2322 /** 2323 * Get the array of additional pages of content for displaying this notification. The 2324 * current notification forms the first page, and elements within this array form 2325 * subsequent pages. This field can be used to separate a notification into multiple 2326 * sections. 2327 * @return the pages for this notification 2328 */ 2329 public List<Notification> getPages() { 2330 return mPages; 2331 } 2332 2333 /** 2334 * Set a background image to be displayed behind the notification content. 2335 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2336 * will work with any notification style. 2337 * 2338 * @param background the background bitmap 2339 * @return this object for method chaining 2340 * @see NotificationCompat.WearableExtender#getBackground 2341 */ 2342 public WearableExtender setBackground(Bitmap background) { 2343 mBackground = background; 2344 return this; 2345 } 2346 2347 /** 2348 * Get a background image to be displayed behind the notification content. 2349 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2350 * will work with any notification style. 2351 * 2352 * @return the background image 2353 * @see NotificationCompat.WearableExtender#setBackground 2354 */ 2355 public Bitmap getBackground() { 2356 return mBackground; 2357 } 2358 2359 /** 2360 * Set an icon that goes with the content of this notification. 2361 */ 2362 public WearableExtender setContentIcon(int icon) { 2363 mContentIcon = icon; 2364 return this; 2365 } 2366 2367 /** 2368 * Get an icon that goes with the content of this notification. 2369 */ 2370 public int getContentIcon() { 2371 return mContentIcon; 2372 } 2373 2374 /** 2375 * Set the gravity that the content icon should have within the notification display. 2376 * Supported values include {@link android.view.Gravity#START} and 2377 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2378 * @see #setContentIcon 2379 */ 2380 public WearableExtender setContentIconGravity(int contentIconGravity) { 2381 mContentIconGravity = contentIconGravity; 2382 return this; 2383 } 2384 2385 /** 2386 * Get the gravity that the content icon should have within the notification display. 2387 * Supported values include {@link android.view.Gravity#START} and 2388 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2389 * @see #getContentIcon 2390 */ 2391 public int getContentIconGravity() { 2392 return mContentIconGravity; 2393 } 2394 2395 /** 2396 * Set an action from this notification's actions to be clickable with the content of 2397 * this notification. This action will no longer display separately from the 2398 * notification's content. 2399 * 2400 * <p>For notifications with multiple pages, child pages can also have content actions 2401 * set, although the list of available actions comes from the main notification and not 2402 * from the child page's notification. 2403 * 2404 * @param actionIndex The index of the action to hoist onto the current notification page. 2405 * If wearable actions were added to the main notification, this index 2406 * will apply to that list, otherwise it will apply to the regular 2407 * actions list. 2408 */ 2409 public WearableExtender setContentAction(int actionIndex) { 2410 mContentActionIndex = actionIndex; 2411 return this; 2412 } 2413 2414 /** 2415 * Get the index of the notification action, if any, that was specified as being clickable 2416 * with the content of this notification. This action will no longer display separately 2417 * from the notification's content. 2418 * 2419 * <p>For notifications with multiple pages, child pages can also have content actions 2420 * set, although the list of available actions comes from the main notification and not 2421 * from the child page's notification. 2422 * 2423 * <p>If wearable specific actions were added to the main notification, this index will 2424 * apply to that list, otherwise it will apply to the regular actions list. 2425 * 2426 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected. 2427 */ 2428 public int getContentAction() { 2429 return mContentActionIndex; 2430 } 2431 2432 /** 2433 * Set the gravity that this notification should have within the available viewport space. 2434 * Supported values include {@link android.view.Gravity#TOP}, 2435 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2436 * The default value is {@link android.view.Gravity#BOTTOM}. 2437 */ 2438 public WearableExtender setGravity(int gravity) { 2439 mGravity = gravity; 2440 return this; 2441 } 2442 2443 /** 2444 * Get the gravity that this notification should have within the available viewport space. 2445 * Supported values include {@link android.view.Gravity#TOP}, 2446 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2447 * The default value is {@link android.view.Gravity#BOTTOM}. 2448 */ 2449 public int getGravity() { 2450 return mGravity; 2451 } 2452 2453 /** 2454 * Set the custom size preset for the display of this notification out of the available 2455 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2456 * {@link #SIZE_LARGE}. 2457 * <p>Some custom size presets are only applicable for custom display notifications created 2458 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the 2459 * documentation for the preset in question. See also 2460 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}. 2461 */ 2462 public WearableExtender setCustomSizePreset(int sizePreset) { 2463 mCustomSizePreset = sizePreset; 2464 return this; 2465 } 2466 2467 /** 2468 * Get the custom size preset for the display of this notification out of the available 2469 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2470 * {@link #SIZE_LARGE}. 2471 * <p>Some custom size presets are only applicable for custom display notifications created 2472 * using {@link #setDisplayIntent}. Check the documentation for the preset in question. 2473 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}. 2474 */ 2475 public int getCustomSizePreset() { 2476 return mCustomSizePreset; 2477 } 2478 2479 /** 2480 * Set the custom height in pixels for the display of this notification's content. 2481 * <p>This option is only available for custom display notifications created 2482 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also 2483 * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and 2484 * {@link #getCustomContentHeight}. 2485 */ 2486 public WearableExtender setCustomContentHeight(int height) { 2487 mCustomContentHeight = height; 2488 return this; 2489 } 2490 2491 /** 2492 * Get the custom height in pixels for the display of this notification's content. 2493 * <p>This option is only available for custom display notifications created 2494 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and 2495 * {@link #setCustomContentHeight}. 2496 */ 2497 public int getCustomContentHeight() { 2498 return mCustomContentHeight; 2499 } 2500 2501 /** 2502 * Set whether the scrolling position for the contents of this notification should start 2503 * at the bottom of the contents instead of the top when the contents are too long to 2504 * display within the screen. Default is false (start scroll at the top). 2505 */ 2506 public WearableExtender setStartScrollBottom(boolean startScrollBottom) { 2507 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom); 2508 return this; 2509 } 2510 2511 /** 2512 * Get whether the scrolling position for the contents of this notification should start 2513 * at the bottom of the contents instead of the top when the contents are too long to 2514 * display within the screen. Default is false (start scroll at the top). 2515 */ 2516 public boolean getStartScrollBottom() { 2517 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0; 2518 } 2519 2520 /** 2521 * Set whether the content intent is available when the wearable device is not connected 2522 * to a companion device. The user can still trigger this intent when the wearable device 2523 * is offline, but a visual hint will indicate that the content intent may not be available. 2524 * Defaults to true. 2525 */ 2526 public WearableExtender setContentIntentAvailableOffline( 2527 boolean contentIntentAvailableOffline) { 2528 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline); 2529 return this; 2530 } 2531 2532 /** 2533 * Get whether the content intent is available when the wearable device is not connected 2534 * to a companion device. The user can still trigger this intent when the wearable device 2535 * is offline, but a visual hint will indicate that the content intent may not be available. 2536 * Defaults to true. 2537 */ 2538 public boolean getContentIntentAvailableOffline() { 2539 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0; 2540 } 2541 2542 /** 2543 * Set a hint that this notification's icon should not be displayed. 2544 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise. 2545 * @return this object for method chaining 2546 */ 2547 public WearableExtender setHintHideIcon(boolean hintHideIcon) { 2548 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon); 2549 return this; 2550 } 2551 2552 /** 2553 * Get a hint that this notification's icon should not be displayed. 2554 * @return {@code true} if this icon should not be displayed, false otherwise. 2555 * The default value is {@code false} if this was never set. 2556 */ 2557 public boolean getHintHideIcon() { 2558 return (mFlags & FLAG_HINT_HIDE_ICON) != 0; 2559 } 2560 2561 /** 2562 * Set a visual hint that only the background image of this notification should be 2563 * displayed, and other semantic content should be hidden. This hint is only applicable 2564 * to sub-pages added using {@link #addPage}. 2565 */ 2566 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) { 2567 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly); 2568 return this; 2569 } 2570 2571 /** 2572 * Get a visual hint that only the background image of this notification should be 2573 * displayed, and other semantic content should be hidden. This hint is only applicable 2574 * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}. 2575 */ 2576 public boolean getHintShowBackgroundOnly() { 2577 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0; 2578 } 2579 2580 private void setFlag(int mask, boolean value) { 2581 if (value) { 2582 mFlags |= mask; 2583 } else { 2584 mFlags &= ~mask; 2585 } 2586 } 2587 } 2588 2589 /** 2590 * Get an array of Notification objects from a parcelable array bundle field. 2591 * Update the bundle to have a typed array so fetches in the future don't need 2592 * to do an array copy. 2593 */ 2594 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { 2595 Parcelable[] array = bundle.getParcelableArray(key); 2596 if (array instanceof Notification[] || array == null) { 2597 return (Notification[]) array; 2598 } 2599 Notification[] typedArray = new Notification[array.length]; 2600 for (int i = 0; i < array.length; i++) { 2601 typedArray[i] = (Notification) array[i]; 2602 } 2603 bundle.putParcelableArray(key, typedArray); 2604 return typedArray; 2605 } 2606 2607 /** 2608 * Gets the {@link Notification#extras} field from a notification in a backwards 2609 * compatible manner. Extras field was supported from JellyBean (Api level 16) 2610 * forwards. This function will return null on older api levels. 2611 */ 2612 public static Bundle getExtras(Notification notif) { 2613 return IMPL.getExtras(notif); 2614 } 2615 2616 /** 2617 * Get the number of actions in this notification in a backwards compatible 2618 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2619 */ 2620 public static int getActionCount(Notification notif) { 2621 return IMPL.getActionCount(notif); 2622 } 2623 2624 /** 2625 * Get an action on this notification in a backwards compatible 2626 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2627 * @param notif The notification to inspect. 2628 * @param actionIndex The index of the action to retrieve. 2629 */ 2630 public static Action getAction(Notification notif, int actionIndex) { 2631 return IMPL.getAction(notif, actionIndex); 2632 } 2633 2634 /** 2635 * Get the category of this notification in a backwards compatible 2636 * manner. 2637 * @param notif The notification to inspect. 2638 */ 2639 public static String getCategory(Notification notif) { 2640 return IMPL.getCategory(notif); 2641 } 2642 2643 /** 2644 * Get whether or not this notification is only relevant to the current device. 2645 * 2646 * <p>Some notifications can be bridged to other devices for remote display. 2647 * If this hint is set, it is recommend that this notification not be bridged. 2648 */ 2649 public static boolean getLocalOnly(Notification notif) { 2650 return IMPL.getLocalOnly(notif); 2651 } 2652 2653 /** 2654 * Get the key used to group this notification into a cluster or stack 2655 * with other notifications on devices which support such rendering. 2656 */ 2657 public static String getGroup(Notification notif) { 2658 return IMPL.getGroup(notif); 2659 } 2660 2661 /** 2662 * Get whether this notification to be the group summary for a group of notifications. 2663 * Grouped notifications may display in a cluster or stack on devices which 2664 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 2665 * @return Whether this notification is a group summary. 2666 */ 2667 public static boolean isGroupSummary(Notification notif) { 2668 return IMPL.isGroupSummary(notif); 2669 } 2670 2671 /** 2672 * Get a sort key that orders this notification among other notifications from the 2673 * same package. This can be useful if an external sort was already applied and an app 2674 * would like to preserve this. Notifications will be sorted lexicographically using this 2675 * value, although providing different priorities in addition to providing sort key may 2676 * cause this value to be ignored. 2677 * 2678 * <p>This sort key can also be used to order members of a notification group. See 2679 * {@link Builder#setGroup}. 2680 * 2681 * @see String#compareTo(String) 2682 */ 2683 public static String getSortKey(Notification notif) { 2684 return IMPL.getSortKey(notif); 2685 } 2686} 2687