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