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