NotificationCompat.java revision ca3133e389ded7b6fd142d514523c6ebf41d6599
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.Activity; 20import android.app.Notification; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.graphics.Bitmap; 24import android.graphics.Color; 25import android.media.AudioManager; 26import android.net.Uri; 27import android.os.Build; 28import android.os.Bundle; 29import android.os.Parcelable; 30import android.support.annotation.ColorInt; 31import android.support.v4.os.BuildCompat; 32import android.support.v4.view.GravityCompat; 33import android.view.Gravity; 34import android.widget.RemoteViews; 35 36import java.util.ArrayList; 37import java.util.Collections; 38import java.util.List; 39 40/** 41 * Helper for accessing features in {@link android.app.Notification} 42 * introduced after API level 4 in a backwards compatible fashion. 43 */ 44public class NotificationCompat { 45 46 /** 47 * Use all default values (where applicable). 48 */ 49 public static final int DEFAULT_ALL = ~0; 50 51 /** 52 * Use the default notification sound. This will ignore any sound set using 53 * {@link Builder#setSound} 54 * 55 * <p> 56 * A notification that is noisy is more likely to be presented as a heads-up notification, 57 * on some platforms. 58 * </p> 59 * 60 * @see Builder#setDefaults 61 */ 62 public static final int DEFAULT_SOUND = 1; 63 64 /** 65 * Use the default notification vibrate. This will ignore any vibrate set using 66 * {@link Builder#setVibrate}. Using phone vibration requires the 67 * {@link android.Manifest.permission#VIBRATE VIBRATE} permission. 68 * 69 * <p> 70 * A notification that vibrates is more likely to be presented as a heads-up notification, 71 * on some platforms. 72 * </p> 73 * 74 * @see Builder#setDefaults 75 */ 76 public static final int DEFAULT_VIBRATE = 2; 77 78 /** 79 * Use the default notification lights. This will ignore the 80 * {@link #FLAG_SHOW_LIGHTS} bit, and values set with {@link Builder#setLights}. 81 * 82 * @see Builder#setDefaults 83 */ 84 public static final int DEFAULT_LIGHTS = 4; 85 86 /** 87 * Use this constant as the value for audioStreamType to request that 88 * the default stream type for notifications be used. Currently the 89 * default stream type is {@link AudioManager#STREAM_NOTIFICATION}. 90 */ 91 public static final int STREAM_DEFAULT = -1; 92 93 /** 94 * Bit set in the Notification flags field when LEDs should be turned on 95 * for this notification. 96 */ 97 public static final int FLAG_SHOW_LIGHTS = 0x00000001; 98 99 /** 100 * Bit set in the Notification flags field if this notification is in 101 * reference to something that is ongoing, like a phone call. It should 102 * not be set if this notification is in reference to something that 103 * happened at a particular point in time, like a missed phone call. 104 */ 105 public static final int FLAG_ONGOING_EVENT = 0x00000002; 106 107 /** 108 * Bit set in the Notification flags field if 109 * the audio will be repeated until the notification is 110 * cancelled or the notification window is opened. 111 */ 112 public static final int FLAG_INSISTENT = 0x00000004; 113 114 /** 115 * Bit set in the Notification flags field if the notification's sound, 116 * vibrate and ticker should only be played if the notification is not already showing. 117 */ 118 public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008; 119 120 /** 121 * Bit set in the Notification flags field if the notification should be canceled when 122 * it is clicked by the user. 123 */ 124 public static final int FLAG_AUTO_CANCEL = 0x00000010; 125 126 /** 127 * Bit set in the Notification flags field if the notification should not be canceled 128 * when the user clicks the Clear all button. 129 */ 130 public static final int FLAG_NO_CLEAR = 0x00000020; 131 132 /** 133 * Bit set in the Notification flags field if this notification represents a currently 134 * running service. This will normally be set for you by 135 * {@link android.app.Service#startForeground}. 136 */ 137 public static final int FLAG_FOREGROUND_SERVICE = 0x00000040; 138 139 /** 140 * Obsolete flag indicating high-priority notifications; use the priority field instead. 141 * 142 * @deprecated Use {@link NotificationCompat.Builder#setPriority(int)} with a positive value. 143 */ 144 @Deprecated 145 public static final int FLAG_HIGH_PRIORITY = 0x00000080; 146 147 /** 148 * Bit set in the Notification flags field if this notification is relevant to the current 149 * device only and it is not recommended that it bridge to other devices. 150 */ 151 public static final int FLAG_LOCAL_ONLY = 0x00000100; 152 153 /** 154 * Bit set in the Notification flags field if this notification is the group summary for a 155 * group of notifications. Grouped notifications may display in a cluster or stack on devices 156 * which support such rendering. Requires a group key also be set using 157 * {@link Builder#setGroup}. 158 */ 159 public static final int FLAG_GROUP_SUMMARY = 0x00000200; 160 161 /** 162 * Default notification priority for {@link NotificationCompat.Builder#setPriority(int)}. 163 * If your application does not prioritize its own notifications, 164 * use this value for all notifications. 165 */ 166 public static final int PRIORITY_DEFAULT = 0; 167 168 /** 169 * Lower notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 170 * for items that are less important. The UI may choose to show 171 * these items smaller, or at a different position in the list, 172 * compared with your app's {@link #PRIORITY_DEFAULT} items. 173 */ 174 public static final int PRIORITY_LOW = -1; 175 176 /** 177 * Lowest notification priority for {@link NotificationCompat.Builder#setPriority(int)}; 178 * these items might not be shown to the user except under 179 * special circumstances, such as detailed notification logs. 180 */ 181 public static final int PRIORITY_MIN = -2; 182 183 /** 184 * Higher notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 185 * for more important notifications or alerts. The UI may choose 186 * to show these items larger, or at a different position in 187 * notification lists, compared with your app's {@link #PRIORITY_DEFAULT} items. 188 */ 189 public static final int PRIORITY_HIGH = 1; 190 191 /** 192 * Highest notification priority for {@link NotificationCompat.Builder#setPriority(int)}, 193 * for your application's most important items that require the user's 194 * prompt attention or input. 195 */ 196 public static final int PRIORITY_MAX = 2; 197 198 /** 199 * Notification extras key: this is the title of the notification, 200 * as supplied to {@link Builder#setContentTitle(CharSequence)}. 201 */ 202 public static final String EXTRA_TITLE = "android.title"; 203 204 /** 205 * Notification extras key: this is the title of the notification when shown in expanded form, 206 * e.g. as supplied to {@link BigTextStyle#setBigContentTitle(CharSequence)}. 207 */ 208 public static final String EXTRA_TITLE_BIG = EXTRA_TITLE + ".big"; 209 210 /** 211 * Notification extras key: this is the main text payload, as supplied to 212 * {@link Builder#setContentText(CharSequence)}. 213 */ 214 public static final String EXTRA_TEXT = "android.text"; 215 216 /** 217 * Notification extras key: this is a third line of text, as supplied to 218 * {@link Builder#setSubText(CharSequence)}. 219 */ 220 public static final String EXTRA_SUB_TEXT = "android.subText"; 221 222 /** 223 * Notification extras key: this is the remote input history, as supplied to 224 * {@link Builder#setRemoteInputHistory(CharSequence[])}. 225 * 226 * Apps can fill this through {@link Builder#setRemoteInputHistory(CharSequence[])} 227 * with the most recent inputs that have been sent through a {@link RemoteInput} of this 228 * Notification and are expected to clear it once the it is no longer relevant (e.g. for chat 229 * notifications once the other party has responded). 230 * 231 * The extra with this key is of type CharSequence[] and contains the most recent entry at 232 * the 0 index, the second most recent at the 1 index, etc. 233 * 234 * @see Builder#setRemoteInputHistory(CharSequence[]) 235 */ 236 public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory"; 237 238 /** 239 * Notification extras key: this is a small piece of additional text as supplied to 240 * {@link Builder#setContentInfo(CharSequence)}. 241 */ 242 public static final String EXTRA_INFO_TEXT = "android.infoText"; 243 244 /** 245 * Notification extras key: this is a line of summary information intended to be shown 246 * alongside expanded notifications, as supplied to (e.g.) 247 * {@link BigTextStyle#setSummaryText(CharSequence)}. 248 */ 249 public static final String EXTRA_SUMMARY_TEXT = "android.summaryText"; 250 251 /** 252 * Notification extras key: this is the longer text shown in the big form of a 253 * {@link BigTextStyle} notification, as supplied to 254 * {@link BigTextStyle#bigText(CharSequence)}. 255 */ 256 public static final String EXTRA_BIG_TEXT = "android.bigText"; 257 258 /** 259 * Notification extras key: this is the resource ID of the notification's main small icon, as 260 * supplied to {@link Builder#setSmallIcon(int)}. 261 */ 262 public static final String EXTRA_SMALL_ICON = "android.icon"; 263 264 /** 265 * Notification extras key: this is a bitmap to be used instead of the small icon when showing the 266 * notification payload, as 267 * supplied to {@link Builder#setLargeIcon(android.graphics.Bitmap)}. 268 */ 269 public static final String EXTRA_LARGE_ICON = "android.largeIcon"; 270 271 /** 272 * Notification extras key: this is a bitmap to be used instead of the one from 273 * {@link Builder#setLargeIcon(android.graphics.Bitmap)} when the notification is 274 * shown in its expanded form, as supplied to 275 * {@link BigPictureStyle#bigLargeIcon(android.graphics.Bitmap)}. 276 */ 277 public static final String EXTRA_LARGE_ICON_BIG = EXTRA_LARGE_ICON + ".big"; 278 279 /** 280 * Notification extras key: this is the progress value supplied to 281 * {@link Builder#setProgress(int, int, boolean)}. 282 */ 283 public static final String EXTRA_PROGRESS = "android.progress"; 284 285 /** 286 * Notification extras key: this is the maximum value supplied to 287 * {@link Builder#setProgress(int, int, boolean)}. 288 */ 289 public static final String EXTRA_PROGRESS_MAX = "android.progressMax"; 290 291 /** 292 * Notification extras key: whether the progress bar is indeterminate, supplied to 293 * {@link Builder#setProgress(int, int, boolean)}. 294 */ 295 public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate"; 296 297 /** 298 * Notification extras key: whether the when field set using {@link Builder#setWhen} should 299 * be shown as a count-up timer (specifically a {@link android.widget.Chronometer}) instead 300 * of a timestamp, as supplied to {@link Builder#setUsesChronometer(boolean)}. 301 */ 302 public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer"; 303 304 /** 305 * Notification extras key: whether the when field set using {@link Builder#setWhen} should 306 * be shown, as supplied to {@link Builder#setShowWhen(boolean)}. 307 */ 308 public static final String EXTRA_SHOW_WHEN = "android.showWhen"; 309 310 /** 311 * Notification extras key: this is a bitmap to be shown in {@link BigPictureStyle} expanded 312 * notifications, supplied to {@link BigPictureStyle#bigPicture(android.graphics.Bitmap)}. 313 */ 314 public static final String EXTRA_PICTURE = "android.picture"; 315 316 /** 317 * Notification extras key: An array of CharSequences to show in {@link InboxStyle} expanded 318 * notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}. 319 */ 320 public static final String EXTRA_TEXT_LINES = "android.textLines"; 321 322 /** 323 * Notification extras key: A string representing the name of the specific 324 * {@link android.app.Notification.Style} used to create this notification. 325 */ 326 public static final String EXTRA_TEMPLATE = "android.template"; 327 328 /** 329 * Notification extras key: A String array containing the people that this 330 * notification relates to, each of which was supplied to 331 * {@link Builder#addPerson(String)}. 332 */ 333 public static final String EXTRA_PEOPLE = "android.people"; 334 335 /** 336 * Notification extras key: A 337 * {@link android.content.ContentUris content URI} pointing to an image that can be displayed 338 * in the background when the notification is selected. The URI must point to an image stream 339 * suitable for passing into 340 * {@link android.graphics.BitmapFactory#decodeStream(java.io.InputStream) 341 * BitmapFactory.decodeStream}; all other content types will be ignored. The content provider 342 * URI used for this purpose must require no permissions to read the image data. 343 */ 344 public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; 345 346 /** 347 * Notification key: A 348 * {@link android.media.session.MediaSession.Token} associated with a 349 * {@link android.app.Notification.MediaStyle} notification. 350 */ 351 public static final String EXTRA_MEDIA_SESSION = "android.mediaSession"; 352 353 /** 354 * Notification extras key: the indices of actions to be shown in the compact view, 355 * as supplied to (e.g.) {@link Notification.MediaStyle#setShowActionsInCompactView(int...)}. 356 */ 357 public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions"; 358 359 /** 360 * Notification key: the username to be displayed for all messages sent by the user 361 * including 362 * direct replies 363 * {@link MessagingStyle} notification. 364 */ 365 public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; 366 367 /** 368 * Notification key: a {@link String} to be displayed as the title to a conversation 369 * represented by a {@link MessagingStyle} 370 */ 371 public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle"; 372 373 /** 374 * Notification key: an array of {@link Bundle} objects representing 375 * {@link MessagingStyle.Message} objects for a {@link MessagingStyle} notification. 376 */ 377 public static final String EXTRA_MESSAGES = "android.messages"; 378 379 /** 380 * Value of {@link Notification#color} equal to 0 (also known as 381 * {@link android.graphics.Color#TRANSPARENT Color.TRANSPARENT}), 382 * telling the system not to decorate this notification with any special color but instead use 383 * default colors when presenting this notification. 384 */ 385 @ColorInt 386 public static final int COLOR_DEFAULT = Color.TRANSPARENT; 387 388 /** 389 * Notification visibility: Show this notification in its entirety on all lockscreens. 390 * 391 * {@see android.app.Notification#visibility} 392 */ 393 public static final int VISIBILITY_PUBLIC = 1; 394 395 /** 396 * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or 397 * private information on secure lockscreens. 398 * 399 * {@see android.app.Notification#visibility} 400 */ 401 public static final int VISIBILITY_PRIVATE = 0; 402 403 /** 404 * Notification visibility: Do not reveal any part of this notification on a secure lockscreen. 405 * 406 * {@see android.app.Notification#visibility} 407 */ 408 public static final int VISIBILITY_SECRET = -1; 409 410 /** 411 * Notification category: incoming call (voice or video) or similar synchronous communication request. 412 */ 413 public static final String CATEGORY_CALL = NotificationCompatApi21.CATEGORY_CALL; 414 415 /** 416 * Notification category: incoming direct message (SMS, instant message, etc.). 417 */ 418 public static final String CATEGORY_MESSAGE = NotificationCompatApi21.CATEGORY_MESSAGE; 419 420 /** 421 * Notification category: asynchronous bulk message (email). 422 */ 423 public static final String CATEGORY_EMAIL = NotificationCompatApi21.CATEGORY_EMAIL; 424 425 /** 426 * Notification category: calendar event. 427 */ 428 public static final String CATEGORY_EVENT = NotificationCompatApi21.CATEGORY_EVENT; 429 430 /** 431 * Notification category: promotion or advertisement. 432 */ 433 public static final String CATEGORY_PROMO = NotificationCompatApi21.CATEGORY_PROMO; 434 435 /** 436 * Notification category: alarm or timer. 437 */ 438 public static final String CATEGORY_ALARM = NotificationCompatApi21.CATEGORY_ALARM; 439 440 /** 441 * Notification category: progress of a long-running background operation. 442 */ 443 public static final String CATEGORY_PROGRESS = NotificationCompatApi21.CATEGORY_PROGRESS; 444 445 /** 446 * Notification category: social network or sharing update. 447 */ 448 public static final String CATEGORY_SOCIAL = NotificationCompatApi21.CATEGORY_SOCIAL; 449 450 /** 451 * Notification category: error in background operation or authentication status. 452 */ 453 public static final String CATEGORY_ERROR = NotificationCompatApi21.CATEGORY_ERROR; 454 455 /** 456 * Notification category: media transport control for playback. 457 */ 458 public static final String CATEGORY_TRANSPORT = NotificationCompatApi21.CATEGORY_TRANSPORT; 459 460 /** 461 * Notification category: system or device status update. Reserved for system use. 462 */ 463 public static final String CATEGORY_SYSTEM = NotificationCompatApi21.CATEGORY_SYSTEM; 464 465 /** 466 * Notification category: indication of running background service. 467 */ 468 public static final String CATEGORY_SERVICE = NotificationCompatApi21.CATEGORY_SERVICE; 469 470 /** 471 * Notification category: user-scheduled reminder. 472 */ 473 public static final String CATEGORY_REMINDER = NotificationCompatApi23.CATEGORY_REMINDER; 474 475 /** 476 * Notification category: a specific, timely recommendation for a single thing. 477 * For example, a news app might want to recommend a news story it believes the user will 478 * want to read next. 479 */ 480 public static final String CATEGORY_RECOMMENDATION = 481 NotificationCompatApi21.CATEGORY_RECOMMENDATION; 482 483 /** 484 * Notification category: ongoing information about device or contextual status. 485 */ 486 public static final String CATEGORY_STATUS = NotificationCompatApi21.CATEGORY_STATUS; 487 488 private static final NotificationCompatImpl IMPL; 489 490 interface NotificationCompatImpl { 491 public Notification build(Builder b, BuilderExtender extender); 492 public Bundle getExtras(Notification n); 493 public int getActionCount(Notification n); 494 public Action getAction(Notification n, int actionIndex); 495 public Action[] getActionsFromParcelableArrayList(ArrayList<Parcelable> parcelables); 496 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions); 497 public String getCategory(Notification n); 498 public boolean getLocalOnly(Notification n); 499 public String getGroup(Notification n); 500 public boolean isGroupSummary(Notification n); 501 public String getSortKey(Notification n); 502 Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc); 503 NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle( 504 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory, 505 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory); 506 } 507 508 /** 509 * Interface for appcompat to extend v4 builder with media style. 510 * 511 * @hide 512 */ 513 protected static class BuilderExtender { 514 public Notification build(Builder b, NotificationBuilderWithBuilderAccessor builder) { 515 return builder.build(); 516 } 517 } 518 519 static class NotificationCompatImplBase implements NotificationCompatImpl { 520 @Override 521 public Notification build(Builder b, BuilderExtender extender) { 522 Notification result = b.mNotification; 523 result = NotificationCompatBase.add(result, b.mContext, 524 b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent); 525 // translate high priority requests into legacy flag 526 if (b.mPriority > PRIORITY_DEFAULT) { 527 result.flags |= FLAG_HIGH_PRIORITY; 528 } 529 if (b.mContentView != null) { 530 result.contentView = b.mContentView; 531 } 532 return result; 533 } 534 535 @Override 536 public Bundle getExtras(Notification n) { 537 return null; 538 } 539 540 @Override 541 public int getActionCount(Notification n) { 542 return 0; 543 } 544 545 @Override 546 public Action getAction(Notification n, int actionIndex) { 547 return null; 548 } 549 550 @Override 551 public Action[] getActionsFromParcelableArrayList( 552 ArrayList<Parcelable> parcelables) { 553 return null; 554 } 555 556 @Override 557 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions) { 558 return null; 559 } 560 561 @Override 562 public String getCategory(Notification n) { 563 return null; 564 } 565 566 @Override 567 public boolean getLocalOnly(Notification n) { 568 return false; 569 } 570 571 @Override 572 public String getGroup(Notification n) { 573 return null; 574 } 575 576 @Override 577 public boolean isGroupSummary(Notification n) { 578 return false; 579 } 580 581 @Override 582 public String getSortKey(Notification n) { 583 return null; 584 } 585 586 @Override 587 public Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) { 588 return null; 589 } 590 591 @Override 592 public NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle( 593 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory, 594 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) { 595 return null; 596 } 597 } 598 599 static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase { 600 @Override 601 public Notification build(Builder b, BuilderExtender extender) { 602 Notification notification = NotificationCompatHoneycomb.add(b.mContext, b.mNotification, 603 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 604 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon); 605 if (b.mContentView != null) { 606 notification.contentView = b.mContentView; 607 } 608 return notification; 609 } 610 } 611 612 static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase { 613 @Override 614 public Notification build(Builder b, BuilderExtender extender) { 615 NotificationCompatIceCreamSandwich.Builder builder = 616 new NotificationCompatIceCreamSandwich.Builder( 617 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 618 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 619 b.mProgressMax, b.mProgress, b.mProgressIndeterminate); 620 Notification notification = extender.build(b, builder); 621 if (b.mContentView != null) { 622 notification.contentView = b.mContentView; 623 } 624 return notification; 625 } 626 } 627 628 static class NotificationCompatImplJellybean extends NotificationCompatImplBase { 629 @Override 630 public Notification build(Builder b, BuilderExtender extender) { 631 NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder( 632 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 633 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 634 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, 635 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras, 636 b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView); 637 addActionsToBuilder(builder, b.mActions); 638 addStyleToBuilderJellybean(builder, b.mStyle); 639 Notification notification = extender.build(b, builder); 640 if (b.mStyle != null) { 641 b.mStyle.addCompatExtras(getExtras(notification)); 642 } 643 return notification; 644 } 645 646 @Override 647 public Bundle getExtras(Notification n) { 648 return NotificationCompatJellybean.getExtras(n); 649 } 650 651 @Override 652 public int getActionCount(Notification n) { 653 return NotificationCompatJellybean.getActionCount(n); 654 } 655 656 @Override 657 public Action getAction(Notification n, int actionIndex) { 658 return (Action) NotificationCompatJellybean.getAction(n, actionIndex, Action.FACTORY, 659 RemoteInput.FACTORY); 660 } 661 662 @Override 663 public Action[] getActionsFromParcelableArrayList( 664 ArrayList<Parcelable> parcelables) { 665 return (Action[]) NotificationCompatJellybean.getActionsFromParcelableArrayList( 666 parcelables, Action.FACTORY, RemoteInput.FACTORY); 667 } 668 669 @Override 670 public ArrayList<Parcelable> getParcelableArrayListForActions( 671 Action[] actions) { 672 return NotificationCompatJellybean.getParcelableArrayListForActions(actions); 673 } 674 675 @Override 676 public boolean getLocalOnly(Notification n) { 677 return NotificationCompatJellybean.getLocalOnly(n); 678 } 679 680 @Override 681 public String getGroup(Notification n) { 682 return NotificationCompatJellybean.getGroup(n); 683 } 684 685 @Override 686 public boolean isGroupSummary(Notification n) { 687 return NotificationCompatJellybean.isGroupSummary(n); 688 } 689 690 @Override 691 public String getSortKey(Notification n) { 692 return NotificationCompatJellybean.getSortKey(n); 693 } 694 } 695 696 static class NotificationCompatImplKitKat extends NotificationCompatImplJellybean { 697 @Override 698 public Notification build(Builder b, BuilderExtender extender) { 699 NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder( 700 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 701 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 702 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 703 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, 704 b.mPeople, b.mExtras, b.mGroupKey, b.mGroupSummary, b.mSortKey, 705 b.mContentView, b.mBigContentView); 706 addActionsToBuilder(builder, b.mActions); 707 addStyleToBuilderJellybean(builder, b.mStyle); 708 return extender.build(b, builder); 709 } 710 711 @Override 712 public Bundle getExtras(Notification n) { 713 return NotificationCompatKitKat.getExtras(n); 714 } 715 716 @Override 717 public int getActionCount(Notification n) { 718 return NotificationCompatKitKat.getActionCount(n); 719 } 720 721 @Override 722 public Action getAction(Notification n, int actionIndex) { 723 return (Action) NotificationCompatKitKat.getAction(n, actionIndex, Action.FACTORY, 724 RemoteInput.FACTORY); 725 } 726 727 @Override 728 public boolean getLocalOnly(Notification n) { 729 return NotificationCompatKitKat.getLocalOnly(n); 730 } 731 732 @Override 733 public String getGroup(Notification n) { 734 return NotificationCompatKitKat.getGroup(n); 735 } 736 737 @Override 738 public boolean isGroupSummary(Notification n) { 739 return NotificationCompatKitKat.isGroupSummary(n); 740 } 741 742 @Override 743 public String getSortKey(Notification n) { 744 return NotificationCompatKitKat.getSortKey(n); 745 } 746 } 747 748 static class NotificationCompatImplApi20 extends NotificationCompatImplKitKat { 749 @Override 750 public Notification build(Builder b, BuilderExtender extender) { 751 NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder( 752 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 753 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 754 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 755 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras, 756 b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView); 757 addActionsToBuilder(builder, b.mActions); 758 addStyleToBuilderJellybean(builder, b.mStyle); 759 Notification notification = extender.build(b, builder); 760 if (b.mStyle != null) { 761 b.mStyle.addCompatExtras(getExtras(notification)); 762 } 763 return notification; 764 } 765 766 @Override 767 public Action getAction(Notification n, int actionIndex) { 768 return (Action) NotificationCompatApi20.getAction(n, actionIndex, Action.FACTORY, 769 RemoteInput.FACTORY); 770 } 771 772 @Override 773 public Action[] getActionsFromParcelableArrayList( 774 ArrayList<Parcelable> parcelables) { 775 return (Action[]) NotificationCompatApi20.getActionsFromParcelableArrayList( 776 parcelables, Action.FACTORY, RemoteInput.FACTORY); 777 } 778 779 @Override 780 public ArrayList<Parcelable> getParcelableArrayListForActions( 781 Action[] actions) { 782 return NotificationCompatApi20.getParcelableArrayListForActions(actions); 783 } 784 785 @Override 786 public boolean getLocalOnly(Notification n) { 787 return NotificationCompatApi20.getLocalOnly(n); 788 } 789 790 @Override 791 public String getGroup(Notification n) { 792 return NotificationCompatApi20.getGroup(n); 793 } 794 795 @Override 796 public boolean isGroupSummary(Notification n) { 797 return NotificationCompatApi20.isGroupSummary(n); 798 } 799 800 @Override 801 public String getSortKey(Notification n) { 802 return NotificationCompatApi20.getSortKey(n); 803 } 804 } 805 806 static class NotificationCompatImplApi21 extends NotificationCompatImplApi20 { 807 @Override 808 public Notification build(Builder b, BuilderExtender extender) { 809 NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder( 810 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 811 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 812 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 813 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory, 814 b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion, 815 b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mContentView, b.mBigContentView, 816 b.mHeadsUpContentView); 817 addActionsToBuilder(builder, b.mActions); 818 addStyleToBuilderJellybean(builder, b.mStyle); 819 Notification notification = extender.build(b, builder); 820 if (b.mStyle != null) { 821 b.mStyle.addCompatExtras(getExtras(notification)); 822 } 823 return notification; 824 } 825 826 @Override 827 public String getCategory(Notification notif) { 828 return NotificationCompatApi21.getCategory(notif); 829 } 830 831 @Override 832 public Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) { 833 return NotificationCompatApi21.getBundleForUnreadConversation(uc); 834 } 835 836 @Override 837 public NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle( 838 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory, 839 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) { 840 return NotificationCompatApi21.getUnreadConversationFromBundle( 841 b, factory, remoteInputFactory); 842 } 843 } 844 845 static class NotificationCompatImplApi24 extends NotificationCompatImplApi21 { 846 @Override 847 public Notification build(Builder b, 848 BuilderExtender extender) { 849 NotificationCompatApi24.Builder builder = new NotificationCompatApi24.Builder( 850 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 851 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 852 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 853 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory, 854 b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion, 855 b.mGroupKey, b.mGroupSummary, b.mSortKey, b.mRemoteInputHistory, b.mContentView, 856 b.mBigContentView, b.mHeadsUpContentView); 857 addActionsToBuilder(builder, b.mActions); 858 addStyleToBuilderApi24(builder, b.mStyle); 859 Notification notification = extender.build(b, builder); 860 if (b.mStyle != null) { 861 b.mStyle.addCompatExtras(getExtras(notification)); 862 } 863 return notification; 864 } 865 } 866 867 private static void addActionsToBuilder(NotificationBuilderWithActions builder, 868 ArrayList<Action> actions) { 869 for (Action action : actions) { 870 builder.addAction(action); 871 } 872 } 873 874 private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder, 875 Style style) { 876 if (style != null) { 877 if (style instanceof BigTextStyle) { 878 BigTextStyle bigTextStyle = (BigTextStyle) style; 879 NotificationCompatJellybean.addBigTextStyle(builder, 880 bigTextStyle.mBigContentTitle, 881 bigTextStyle.mSummaryTextSet, 882 bigTextStyle.mSummaryText, 883 bigTextStyle.mBigText); 884 } else if (style instanceof InboxStyle) { 885 InboxStyle inboxStyle = (InboxStyle) style; 886 NotificationCompatJellybean.addInboxStyle(builder, 887 inboxStyle.mBigContentTitle, 888 inboxStyle.mSummaryTextSet, 889 inboxStyle.mSummaryText, 890 inboxStyle.mTexts); 891 } else if (style instanceof BigPictureStyle) { 892 BigPictureStyle bigPictureStyle = (BigPictureStyle) style; 893 NotificationCompatJellybean.addBigPictureStyle(builder, 894 bigPictureStyle.mBigContentTitle, 895 bigPictureStyle.mSummaryTextSet, 896 bigPictureStyle.mSummaryText, 897 bigPictureStyle.mPicture, 898 bigPictureStyle.mBigLargeIcon, 899 bigPictureStyle.mBigLargeIconSet); 900 } else if (style instanceof MessagingStyle) { 901 // TODO implement BigText fallback 902 } 903 } 904 } 905 906 private static void addStyleToBuilderApi24(NotificationBuilderWithBuilderAccessor builder, 907 Style style) { 908 if (style != null) { 909 if (style instanceof MessagingStyle) { 910 MessagingStyle messagingStyle = (MessagingStyle) style; 911 List<CharSequence> texts = new ArrayList<>(); 912 List<Long> timestamps = new ArrayList<>(); 913 List<CharSequence> senders = new ArrayList<>(); 914 List<String> dataMimeTypes = new ArrayList<>(); 915 List<Uri> dataUris = new ArrayList<>(); 916 917 for (MessagingStyle.Message message : messagingStyle.mMessages) { 918 texts.add(message.getText()); 919 timestamps.add(message.getTimestamp()); 920 senders.add(message.getSender()); 921 dataMimeTypes.add(message.getDataMimeType()); 922 dataUris.add(message.getDataUri()); 923 } 924 NotificationCompatApi24.addMessagingStyle(builder, messagingStyle.mUserDisplayName, 925 messagingStyle.mConversationTitle, texts, timestamps, senders, 926 dataMimeTypes, dataUris); 927 } else { 928 addStyleToBuilderJellybean(builder, style); 929 } 930 } 931 } 932 933 static { 934 if (BuildCompat.isAtLeastN()) { 935 IMPL = new NotificationCompatImplApi24(); 936 } else if (Build.VERSION.SDK_INT >= 21) { 937 IMPL = new NotificationCompatImplApi21(); 938 } else if (Build.VERSION.SDK_INT >= 20) { 939 IMPL = new NotificationCompatImplApi20(); 940 } else if (Build.VERSION.SDK_INT >= 19) { 941 IMPL = new NotificationCompatImplKitKat(); 942 } else if (Build.VERSION.SDK_INT >= 16) { 943 IMPL = new NotificationCompatImplJellybean(); 944 } else if (Build.VERSION.SDK_INT >= 14) { 945 IMPL = new NotificationCompatImplIceCreamSandwich(); 946 } else if (Build.VERSION.SDK_INT >= 11) { 947 IMPL = new NotificationCompatImplHoneycomb(); 948 } else { 949 IMPL = new NotificationCompatImplBase(); 950 } 951 } 952 953 /** 954 * Builder class for {@link NotificationCompat} objects. Allows easier control over 955 * all the flags, as well as help constructing the typical notification layouts. 956 * <p> 957 * On platform versions that don't offer expanded notifications, methods that depend on 958 * expanded notifications have no effect. 959 * </p> 960 * <p> 961 * For example, action buttons won't appear on platforms prior to Android 4.1. Action 962 * buttons depend on expanded notifications, which are only available in Android 4.1 963 * and later. 964 * <p> 965 * For this reason, you should always ensure that UI controls in a notification are also 966 * available in an {@link android.app.Activity} in your app, and you should always start that 967 * {@link android.app.Activity} when users click the notification. To do this, use the 968 * {@link NotificationCompat.Builder#setContentIntent setContentIntent()} 969 * method. 970 * </p> 971 * 972 */ 973 public static class Builder { 974 /** 975 * Maximum length of CharSequences accepted by Builder and friends. 976 * 977 * <p> 978 * Avoids spamming the system with overly large strings such as full e-mails. 979 */ 980 private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024; 981 982 // All these variables are declared public/hidden so they can be accessed by a builder 983 // extender. 984 985 /** @hide */ 986 public Context mContext; 987 988 /** @hide */ 989 public CharSequence mContentTitle; 990 /** @hide */ 991 public CharSequence mContentText; 992 PendingIntent mContentIntent; 993 PendingIntent mFullScreenIntent; 994 RemoteViews mTickerView; 995 /** @hide */ 996 public Bitmap mLargeIcon; 997 /** @hide */ 998 public CharSequence mContentInfo; 999 /** @hide */ 1000 public int mNumber; 1001 int mPriority; 1002 boolean mShowWhen = true; 1003 /** @hide */ 1004 public boolean mUseChronometer; 1005 /** @hide */ 1006 public Style mStyle; 1007 /** @hide */ 1008 public CharSequence mSubText; 1009 /** @hide */ 1010 public CharSequence[] mRemoteInputHistory; 1011 int mProgressMax; 1012 int mProgress; 1013 boolean mProgressIndeterminate; 1014 String mGroupKey; 1015 boolean mGroupSummary; 1016 String mSortKey; 1017 /** @hide */ 1018 public ArrayList<Action> mActions = new ArrayList<Action>(); 1019 boolean mLocalOnly = false; 1020 String mCategory; 1021 Bundle mExtras; 1022 int mColor = COLOR_DEFAULT; 1023 int mVisibility = VISIBILITY_PRIVATE; 1024 Notification mPublicVersion; 1025 RemoteViews mContentView; 1026 RemoteViews mBigContentView; 1027 RemoteViews mHeadsUpContentView; 1028 1029 /** @hide */ 1030 public Notification mNotification = new Notification(); 1031 public ArrayList<String> mPeople; 1032 1033 /** 1034 * Constructor. 1035 * 1036 * Automatically sets the when field to {@link System#currentTimeMillis() 1037 * System.currentTimeMillis()} and the audio stream to the 1038 * {@link Notification#STREAM_DEFAULT}. 1039 * 1040 * @param context A {@link Context} that will be used to construct the 1041 * RemoteViews. The Context will not be held past the lifetime of this 1042 * Builder object. 1043 */ 1044 public Builder(Context context) { 1045 mContext = context; 1046 1047 // Set defaults to match the defaults of a Notification 1048 mNotification.when = System.currentTimeMillis(); 1049 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 1050 mPriority = PRIORITY_DEFAULT; 1051 mPeople = new ArrayList<String>(); 1052 } 1053 1054 /** 1055 * Set the time that the event occurred. Notifications in the panel are 1056 * sorted by this time. 1057 */ 1058 public Builder setWhen(long when) { 1059 mNotification.when = when; 1060 return this; 1061 } 1062 1063 /** 1064 * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown 1065 * in the content view. 1066 */ 1067 public Builder setShowWhen(boolean show) { 1068 mShowWhen = show; 1069 return this; 1070 } 1071 1072 /** 1073 * Show the {@link Notification#when} field as a stopwatch. 1074 * 1075 * Instead of presenting <code>when</code> as a timestamp, the notification will show an 1076 * automatically updating display of the minutes and seconds since <code>when</code>. 1077 * 1078 * Useful when showing an elapsed time (like an ongoing phone call). 1079 * 1080 * @see android.widget.Chronometer 1081 * @see Notification#when 1082 */ 1083 public Builder setUsesChronometer(boolean b) { 1084 mUseChronometer = b; 1085 return this; 1086 } 1087 1088 /** 1089 * Set the small icon to use in the notification layouts. Different classes of devices 1090 * may return different sizes. See the UX guidelines for more information on how to 1091 * design these icons. 1092 * 1093 * @param icon A resource ID in the application's package of the drawble to use. 1094 */ 1095 public Builder setSmallIcon(int icon) { 1096 mNotification.icon = icon; 1097 return this; 1098 } 1099 1100 /** 1101 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional 1102 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable 1103 * LevelListDrawable}. 1104 * 1105 * @param icon A resource ID in the application's package of the drawble to use. 1106 * @param level The level to use for the icon. 1107 * 1108 * @see android.graphics.drawable.LevelListDrawable 1109 */ 1110 public Builder setSmallIcon(int icon, int level) { 1111 mNotification.icon = icon; 1112 mNotification.iconLevel = level; 1113 return this; 1114 } 1115 1116 /** 1117 * Set the title (first row) of the notification, in a standard notification. 1118 */ 1119 public Builder setContentTitle(CharSequence title) { 1120 mContentTitle = limitCharSequenceLength(title); 1121 return this; 1122 } 1123 1124 /** 1125 * Set the text (second row) of the notification, in a standard notification. 1126 */ 1127 public Builder setContentText(CharSequence text) { 1128 mContentText = limitCharSequenceLength(text); 1129 return this; 1130 } 1131 1132 /** 1133 * Set the third line of text in the platform notification template. 1134 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; 1135 * they occupy the same location in the standard template. 1136 * <br> 1137 * If the platform does not provide large-format notifications, this method has no effect. 1138 * The third line of text only appears in expanded view. 1139 * <br> 1140 */ 1141 public Builder setSubText(CharSequence text) { 1142 mSubText = limitCharSequenceLength(text); 1143 return this; 1144 } 1145 1146 /** 1147 * Set the remote input history. 1148 * 1149 * This should be set to the most recent inputs that have been sent 1150 * through a {@link RemoteInput} of this Notification and cleared once the it is no 1151 * longer relevant (e.g. for chat notifications once the other party has responded). 1152 * 1153 * The most recent input must be stored at the 0 index, the second most recent at the 1154 * 1 index, etc. Note that the system will limit both how far back the inputs will be shown 1155 * and how much of each individual input is shown. 1156 * 1157 * <p>Note: The reply text will only be shown on notifications that have least one action 1158 * with a {@code RemoteInput}.</p> 1159 */ 1160 public Builder setRemoteInputHistory(CharSequence[] text) { 1161 mRemoteInputHistory = text; 1162 return this; 1163 } 1164 1165 /** 1166 * Set the large number at the right-hand side of the notification. This is 1167 * equivalent to setContentInfo, although it might show the number in a different 1168 * font size for readability. 1169 */ 1170 public Builder setNumber(int number) { 1171 mNumber = number; 1172 return this; 1173 } 1174 1175 /** 1176 * Set the large text at the right-hand side of the notification. 1177 */ 1178 public Builder setContentInfo(CharSequence info) { 1179 mContentInfo = limitCharSequenceLength(info); 1180 return this; 1181 } 1182 1183 /** 1184 * Set the progress this notification represents, which may be 1185 * represented as a {@link android.widget.ProgressBar}. 1186 */ 1187 public Builder setProgress(int max, int progress, boolean indeterminate) { 1188 mProgressMax = max; 1189 mProgress = progress; 1190 mProgressIndeterminate = indeterminate; 1191 return this; 1192 } 1193 1194 /** 1195 * Supply a custom RemoteViews to use instead of the standard one. 1196 */ 1197 public Builder setContent(RemoteViews views) { 1198 mNotification.contentView = views; 1199 return this; 1200 } 1201 1202 /** 1203 * Supply a {@link PendingIntent} to send when the notification is clicked. 1204 * If you do not supply an intent, you can now add PendingIntents to individual 1205 * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent 1206 * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}. Be sure to 1207 * read {@link Notification#contentIntent Notification.contentIntent} for 1208 * how to correctly use this. 1209 */ 1210 public Builder setContentIntent(PendingIntent intent) { 1211 mContentIntent = intent; 1212 return this; 1213 } 1214 1215 /** 1216 * Supply a {@link PendingIntent} to send when the notification is cleared by the user 1217 * directly from the notification panel. For example, this intent is sent when the user 1218 * clicks the "Clear all" button, or the individual "X" buttons on notifications. This 1219 * intent is not sent when the application calls 1220 * {@link android.app.NotificationManager#cancel NotificationManager.cancel(int)}. 1221 */ 1222 public Builder setDeleteIntent(PendingIntent intent) { 1223 mNotification.deleteIntent = intent; 1224 return this; 1225 } 1226 1227 /** 1228 * An intent to launch instead of posting the notification to the status bar. 1229 * Only for use with extremely high-priority notifications demanding the user's 1230 * <strong>immediate</strong> attention, such as an incoming phone call or 1231 * alarm clock that the user has explicitly set to a particular time. 1232 * If this facility is used for something else, please give the user an option 1233 * to turn it off and use a normal notification, as this can be extremely 1234 * disruptive. 1235 * 1236 * <p> 1237 * On some platforms, the system UI may choose to display a heads-up notification, 1238 * instead of launching this intent, while the user is using the device. 1239 * </p> 1240 * 1241 * @param intent The pending intent to launch. 1242 * @param highPriority Passing true will cause this notification to be sent 1243 * even if other notifications are suppressed. 1244 */ 1245 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { 1246 mFullScreenIntent = intent; 1247 setFlag(FLAG_HIGH_PRIORITY, highPriority); 1248 return this; 1249 } 1250 1251 /** 1252 * Set the text that is displayed in the status bar when the notification first 1253 * arrives. 1254 */ 1255 public Builder setTicker(CharSequence tickerText) { 1256 mNotification.tickerText = limitCharSequenceLength(tickerText); 1257 return this; 1258 } 1259 1260 /** 1261 * Set the text that is displayed in the status bar when the notification first 1262 * arrives, and also a RemoteViews object that may be displayed instead on some 1263 * devices. 1264 */ 1265 public Builder setTicker(CharSequence tickerText, RemoteViews views) { 1266 mNotification.tickerText = limitCharSequenceLength(tickerText); 1267 mTickerView = views; 1268 return this; 1269 } 1270 1271 /** 1272 * Set the large icon that is shown in the ticker and notification. 1273 */ 1274 public Builder setLargeIcon(Bitmap icon) { 1275 mLargeIcon = icon; 1276 return this; 1277 } 1278 1279 /** 1280 * Set the sound to play. It will play on the default stream. 1281 * 1282 * <p> 1283 * On some platforms, a notification that is noisy is more likely to be presented 1284 * as a heads-up notification. 1285 * </p> 1286 */ 1287 public Builder setSound(Uri sound) { 1288 mNotification.sound = sound; 1289 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 1290 return this; 1291 } 1292 1293 /** 1294 * Set the sound to play. It will play on the stream you supply. 1295 * 1296 * <p> 1297 * On some platforms, a notification that is noisy is more likely to be presented 1298 * as a heads-up notification. 1299 * </p> 1300 * 1301 * @see Notification#STREAM_DEFAULT 1302 * @see AudioManager for the <code>STREAM_</code> constants. 1303 */ 1304 public Builder setSound(Uri sound, int streamType) { 1305 mNotification.sound = sound; 1306 mNotification.audioStreamType = streamType; 1307 return this; 1308 } 1309 1310 /** 1311 * Set the vibration pattern to use. 1312 * 1313 * <p> 1314 * On some platforms, a notification that vibrates is more likely to be presented 1315 * as a heads-up notification. 1316 * </p> 1317 * 1318 * @see android.os.Vibrator for a discussion of the <code>pattern</code> 1319 * parameter. 1320 */ 1321 public Builder setVibrate(long[] pattern) { 1322 mNotification.vibrate = pattern; 1323 return this; 1324 } 1325 1326 /** 1327 * Set the argb value that you would like the LED on the device to blink, as well as the 1328 * rate. The rate is specified in terms of the number of milliseconds to be on 1329 * and then the number of milliseconds to be off. 1330 */ 1331 public Builder setLights(@ColorInt int argb, int onMs, int offMs) { 1332 mNotification.ledARGB = argb; 1333 mNotification.ledOnMS = onMs; 1334 mNotification.ledOffMS = offMs; 1335 boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0; 1336 mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) | 1337 (showLights ? Notification.FLAG_SHOW_LIGHTS : 0); 1338 return this; 1339 } 1340 1341 /** 1342 * Set whether this is an ongoing notification. 1343 * 1344 * <p>Ongoing notifications differ from regular notifications in the following ways: 1345 * <ul> 1346 * <li>Ongoing notifications are sorted above the regular notifications in the 1347 * notification panel.</li> 1348 * <li>Ongoing notifications do not have an 'X' close button, and are not affected 1349 * by the "Clear all" button. 1350 * </ul> 1351 */ 1352 public Builder setOngoing(boolean ongoing) { 1353 setFlag(Notification.FLAG_ONGOING_EVENT, ongoing); 1354 return this; 1355 } 1356 1357 /** 1358 * Set this flag if you would only like the sound, vibrate 1359 * and ticker to be played if the notification is not already showing. 1360 */ 1361 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { 1362 setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); 1363 return this; 1364 } 1365 1366 /** 1367 * Setting this flag will make it so the notification is automatically 1368 * canceled when the user clicks it in the panel. The PendingIntent 1369 * set with {@link #setDeleteIntent} will be broadcast when the notification 1370 * is canceled. 1371 */ 1372 public Builder setAutoCancel(boolean autoCancel) { 1373 setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel); 1374 return this; 1375 } 1376 1377 /** 1378 * Set whether or not this notification is only relevant to the current device. 1379 * 1380 * <p>Some notifications can be bridged to other devices for remote display. 1381 * This hint can be set to recommend this notification not be bridged. 1382 */ 1383 public Builder setLocalOnly(boolean b) { 1384 mLocalOnly = b; 1385 return this; 1386 } 1387 1388 /** 1389 * Set the notification category. 1390 * 1391 * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code> 1392 * constants in {@link Notification}) that best describes this notification. 1393 * May be used by the system for ranking and filtering. 1394 */ 1395 public Builder setCategory(String category) { 1396 mCategory = category; 1397 return this; 1398 } 1399 1400 /** 1401 * Set the default notification options that will be used. 1402 * <p> 1403 * The value should be one or more of the following fields combined with 1404 * bitwise-or: 1405 * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE}, 1406 * {@link Notification#DEFAULT_LIGHTS}. 1407 * <p> 1408 * For all default values, use {@link Notification#DEFAULT_ALL}. 1409 */ 1410 public Builder setDefaults(int defaults) { 1411 mNotification.defaults = defaults; 1412 if ((defaults & Notification.DEFAULT_LIGHTS) != 0) { 1413 mNotification.flags |= Notification.FLAG_SHOW_LIGHTS; 1414 } 1415 return this; 1416 } 1417 1418 private void setFlag(int mask, boolean value) { 1419 if (value) { 1420 mNotification.flags |= mask; 1421 } else { 1422 mNotification.flags &= ~mask; 1423 } 1424 } 1425 1426 /** 1427 * Set the relative priority for this notification. 1428 * 1429 * Priority is an indication of how much of the user's 1430 * valuable attention should be consumed by this 1431 * notification. Low-priority notifications may be hidden from 1432 * the user in certain situations, while the user might be 1433 * interrupted for a higher-priority notification. 1434 * The system sets a notification's priority based on various factors including the 1435 * setPriority value. The effect may differ slightly on different platforms. 1436 * 1437 * @param pri Relative priority for this notification. Must be one of 1438 * the priority constants defined by {@link NotificationCompat}. 1439 * Acceptable values range from {@link 1440 * NotificationCompat#PRIORITY_MIN} (-2) to {@link 1441 * NotificationCompat#PRIORITY_MAX} (2). 1442 */ 1443 public Builder setPriority(int pri) { 1444 mPriority = pri; 1445 return this; 1446 } 1447 1448 /** 1449 * Add a person that is relevant to this notification. 1450 * 1451 * <P> 1452 * Depending on user preferences, this annotation may allow the notification to pass 1453 * through interruption filters, and to appear more prominently in the user interface. 1454 * </P> 1455 * 1456 * <P> 1457 * The person should be specified by the {@code String} representation of a 1458 * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}. 1459 * </P> 1460 * 1461 * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema 1462 * URIs. The path part of these URIs must exist in the contacts database, in the 1463 * appropriate column, or the reference will be discarded as invalid. Telephone schema 1464 * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}. 1465 * </P> 1466 * 1467 * @param uri A URI for the person. 1468 * @see Notification#EXTRA_PEOPLE 1469 */ 1470 public Builder addPerson(String uri) { 1471 mPeople.add(uri); 1472 return this; 1473 } 1474 1475 /** 1476 * Set this notification to be part of a group of notifications sharing the same key. 1477 * Grouped notifications may display in a cluster or stack on devices which 1478 * support such rendering. 1479 * 1480 * <p>To make this notification the summary for its group, also call 1481 * {@link #setGroupSummary}. A sort order can be specified for group members by using 1482 * {@link #setSortKey}. 1483 * @param groupKey The group key of the group. 1484 * @return this object for method chaining 1485 */ 1486 public Builder setGroup(String groupKey) { 1487 mGroupKey = groupKey; 1488 return this; 1489 } 1490 1491 /** 1492 * Set this notification to be the group summary for a group of notifications. 1493 * Grouped notifications may display in a cluster or stack on devices which 1494 * support such rendering. Requires a group key also be set using {@link #setGroup}. 1495 * @param isGroupSummary Whether this notification should be a group summary. 1496 * @return this object for method chaining 1497 */ 1498 public Builder setGroupSummary(boolean isGroupSummary) { 1499 mGroupSummary = isGroupSummary; 1500 return this; 1501 } 1502 1503 /** 1504 * Set a sort key that orders this notification among other notifications from the 1505 * same package. This can be useful if an external sort was already applied and an app 1506 * would like to preserve this. Notifications will be sorted lexicographically using this 1507 * value, although providing different priorities in addition to providing sort key may 1508 * cause this value to be ignored. 1509 * 1510 * <p>This sort key can also be used to order members of a notification group. See 1511 * {@link Builder#setGroup}. 1512 * 1513 * @see String#compareTo(String) 1514 */ 1515 public Builder setSortKey(String sortKey) { 1516 mSortKey = sortKey; 1517 return this; 1518 } 1519 1520 /** 1521 * Merge additional metadata into this notification. 1522 * 1523 * <p>Values within the Bundle will replace existing extras values in this Builder. 1524 * 1525 * @see Notification#extras 1526 */ 1527 public Builder addExtras(Bundle extras) { 1528 if (extras != null) { 1529 if (mExtras == null) { 1530 mExtras = new Bundle(extras); 1531 } else { 1532 mExtras.putAll(extras); 1533 } 1534 } 1535 return this; 1536 } 1537 1538 /** 1539 * Set metadata for this notification. 1540 * 1541 * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's 1542 * current contents are copied into the Notification each time {@link #build()} is 1543 * called. 1544 * 1545 * <p>Replaces any existing extras values with those from the provided Bundle. 1546 * Use {@link #addExtras} to merge in metadata instead. 1547 * 1548 * @see Notification#extras 1549 */ 1550 public Builder setExtras(Bundle extras) { 1551 mExtras = extras; 1552 return this; 1553 } 1554 1555 /** 1556 * Get the current metadata Bundle used by this notification Builder. 1557 * 1558 * <p>The returned Bundle is shared with this Builder. 1559 * 1560 * <p>The current contents of this Bundle are copied into the Notification each time 1561 * {@link #build()} is called. 1562 * 1563 * @see Notification#extras 1564 */ 1565 public Bundle getExtras() { 1566 if (mExtras == null) { 1567 mExtras = new Bundle(); 1568 } 1569 return mExtras; 1570 } 1571 1572 /** 1573 * Add an action to this notification. Actions are typically displayed by 1574 * the system as a button adjacent to the notification content. 1575 * <br> 1576 * Action buttons won't appear on platforms prior to Android 4.1. Action 1577 * buttons depend on expanded notifications, which are only available in Android 4.1 1578 * and later. To ensure that an action button's functionality is always available, first 1579 * implement the functionality in the {@link android.app.Activity} that starts when a user 1580 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1581 * enhance the notification by implementing the same functionality with 1582 * {@link #addAction addAction()}. 1583 * 1584 * @param icon Resource ID of a drawable that represents the action. 1585 * @param title Text describing the action. 1586 * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked. 1587 */ 1588 public Builder addAction(int icon, CharSequence title, PendingIntent intent) { 1589 mActions.add(new Action(icon, title, intent)); 1590 return this; 1591 } 1592 1593 /** 1594 * Add an action to this notification. Actions are typically displayed by 1595 * the system as a button adjacent to the notification content. 1596 * <br> 1597 * Action buttons won't appear on platforms prior to Android 4.1. Action 1598 * buttons depend on expanded notifications, which are only available in Android 4.1 1599 * and later. To ensure that an action button's functionality is always available, first 1600 * implement the functionality in the {@link android.app.Activity} that starts when a user 1601 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1602 * enhance the notification by implementing the same functionality with 1603 * {@link #addAction addAction()}. 1604 * 1605 * @param action The action to add. 1606 */ 1607 public Builder addAction(Action action) { 1608 mActions.add(action); 1609 return this; 1610 } 1611 1612 /** 1613 * Add a rich notification style to be applied at build time. 1614 * <br> 1615 * If the platform does not provide rich notification styles, this method has no effect. The 1616 * user will always see the normal notification style. 1617 * 1618 * @param style Object responsible for modifying the notification style. 1619 */ 1620 public Builder setStyle(Style style) { 1621 if (mStyle != style) { 1622 mStyle = style; 1623 if (mStyle != null) { 1624 mStyle.setBuilder(this); 1625 } 1626 } 1627 return this; 1628 } 1629 1630 /** 1631 * Sets {@link Notification#color}. 1632 * 1633 * @param argb The accent color to use 1634 * 1635 * @return The same Builder. 1636 */ 1637 public Builder setColor(@ColorInt int argb) { 1638 mColor = argb; 1639 return this; 1640 } 1641 1642 /** 1643 * Sets {@link Notification#visibility}. 1644 * 1645 * @param visibility One of {@link Notification#VISIBILITY_PRIVATE} (the default), 1646 * {@link Notification#VISIBILITY_PUBLIC}, or 1647 * {@link Notification#VISIBILITY_SECRET}. 1648 */ 1649 public Builder setVisibility(int visibility) { 1650 mVisibility = visibility; 1651 return this; 1652 } 1653 1654 /** 1655 * Supply a replacement Notification whose contents should be shown in insecure contexts 1656 * (i.e. atop the secure lockscreen). See {@link Notification#visibility} and 1657 * {@link #VISIBILITY_PUBLIC}. 1658 * 1659 * @param n A replacement notification, presumably with some or all info redacted. 1660 * @return The same Builder. 1661 */ 1662 public Builder setPublicVersion(Notification n) { 1663 mPublicVersion = n; 1664 return this; 1665 } 1666 1667 /** 1668 * Supply custom RemoteViews to use instead of the platform template. 1669 * 1670 * This will override the layout that would otherwise be constructed by this Builder 1671 * object. 1672 */ 1673 public Builder setCustomContentView(RemoteViews contentView) { 1674 mContentView = contentView; 1675 return this; 1676 } 1677 1678 /** 1679 * Supply custom RemoteViews to use instead of the platform template in the expanded form. 1680 * 1681 * This will override the expanded layout that would otherwise be constructed by this 1682 * Builder object. 1683 * 1684 * No-op on versions prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN}. 1685 */ 1686 public Builder setCustomBigContentView(RemoteViews contentView) { 1687 mBigContentView = contentView; 1688 return this; 1689 } 1690 1691 /** 1692 * Supply custom RemoteViews to use instead of the platform template in the heads up dialog. 1693 * 1694 * This will override the heads-up layout that would otherwise be constructed by this 1695 * Builder object. 1696 * 1697 * No-op on versions prior to {@link android.os.Build.VERSION_CODES#LOLLIPOP}. 1698 */ 1699 public Builder setCustomHeadsUpContentView(RemoteViews contentView) { 1700 mHeadsUpContentView = contentView; 1701 return this; 1702 } 1703 1704 /** 1705 * Apply an extender to this notification builder. Extenders may be used to add 1706 * metadata or change options on this builder. 1707 */ 1708 public Builder extend(Extender extender) { 1709 extender.extend(this); 1710 return this; 1711 } 1712 1713 /** 1714 * @deprecated Use {@link #build()} instead. 1715 */ 1716 @Deprecated 1717 public Notification getNotification() { 1718 return build(); 1719 } 1720 1721 /** 1722 * Combine all of the options that have been set and return a new {@link Notification} 1723 * object. 1724 */ 1725 public Notification build() { 1726 return IMPL.build(this, getExtender()); 1727 } 1728 1729 /** 1730 * @hide 1731 */ 1732 protected BuilderExtender getExtender() { 1733 return new BuilderExtender(); 1734 } 1735 1736 protected static CharSequence limitCharSequenceLength(CharSequence cs) { 1737 if (cs == null) return cs; 1738 if (cs.length() > MAX_CHARSEQUENCE_LENGTH) { 1739 cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH); 1740 } 1741 return cs; 1742 } 1743 } 1744 1745 /** 1746 * An object that can apply a rich notification style to a {@link Notification.Builder} 1747 * object. 1748 * <br> 1749 * If the platform does not provide rich notification styles, methods in this class have no 1750 * effect. 1751 */ 1752 public static abstract class Style { 1753 Builder mBuilder; 1754 CharSequence mBigContentTitle; 1755 CharSequence mSummaryText; 1756 boolean mSummaryTextSet = false; 1757 1758 public void setBuilder(Builder builder) { 1759 if (mBuilder != builder) { 1760 mBuilder = builder; 1761 if (mBuilder != null) { 1762 mBuilder.setStyle(this); 1763 } 1764 } 1765 } 1766 1767 public Notification build() { 1768 Notification notification = null; 1769 if (mBuilder != null) { 1770 notification = mBuilder.build(); 1771 } 1772 return notification; 1773 } 1774 1775 /** 1776 * @hide 1777 */ 1778 // TODO: implement for all styles 1779 public void addCompatExtras(Bundle extras) { 1780 } 1781 1782 /** 1783 * @hide 1784 */ 1785 // TODO: implement for all styles 1786 protected void restoreFromCompatExtras(Bundle extras) { 1787 } 1788 } 1789 1790 /** 1791 * Helper class for generating large-format notifications that include a large image attachment. 1792 * <br> 1793 * If the platform does not provide large-format notifications, this method has no effect. The 1794 * user will always see the normal notification view. 1795 * <br> 1796 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1797 * <pre class="prettyprint"> 1798 * Notification notif = new Notification.Builder(mContext) 1799 * .setContentTitle("New photo from " + sender.toString()) 1800 * .setContentText(subject) 1801 * .setSmallIcon(R.drawable.new_post) 1802 * .setLargeIcon(aBitmap) 1803 * .setStyle(new Notification.BigPictureStyle() 1804 * .bigPicture(aBigBitmap)) 1805 * .build(); 1806 * </pre> 1807 * 1808 * @see Notification#bigContentView 1809 */ 1810 public static class BigPictureStyle extends Style { 1811 Bitmap mPicture; 1812 Bitmap mBigLargeIcon; 1813 boolean mBigLargeIconSet; 1814 1815 public BigPictureStyle() { 1816 } 1817 1818 public BigPictureStyle(Builder builder) { 1819 setBuilder(builder); 1820 } 1821 1822 /** 1823 * Overrides ContentTitle in the big form of the template. 1824 * This defaults to the value passed to setContentTitle(). 1825 */ 1826 public BigPictureStyle setBigContentTitle(CharSequence title) { 1827 mBigContentTitle = Builder.limitCharSequenceLength(title); 1828 return this; 1829 } 1830 1831 /** 1832 * Set the first line of text after the detail section in the big form of the template. 1833 */ 1834 public BigPictureStyle setSummaryText(CharSequence cs) { 1835 mSummaryText = Builder.limitCharSequenceLength(cs); 1836 mSummaryTextSet = true; 1837 return this; 1838 } 1839 1840 /** 1841 * Provide the bitmap to be used as the payload for the BigPicture notification. 1842 */ 1843 public BigPictureStyle bigPicture(Bitmap b) { 1844 mPicture = b; 1845 return this; 1846 } 1847 1848 /** 1849 * Override the large icon when the big notification is shown. 1850 */ 1851 public BigPictureStyle bigLargeIcon(Bitmap b) { 1852 mBigLargeIcon = b; 1853 mBigLargeIconSet = true; 1854 return this; 1855 } 1856 } 1857 1858 /** 1859 * Helper class for generating large-format notifications that include a lot of text. 1860 * 1861 * <br> 1862 * If the platform does not provide large-format notifications, this method has no effect. The 1863 * user will always see the normal notification view. 1864 * <br> 1865 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1866 * <pre class="prettyprint"> 1867 * Notification notif = new Notification.Builder(mContext) 1868 * .setContentTitle("New mail from " + sender.toString()) 1869 * .setContentText(subject) 1870 * .setSmallIcon(R.drawable.new_mail) 1871 * .setLargeIcon(aBitmap) 1872 * .setStyle(new Notification.BigTextStyle() 1873 * .bigText(aVeryLongString)) 1874 * .build(); 1875 * </pre> 1876 * 1877 * @see Notification#bigContentView 1878 */ 1879 public static class BigTextStyle extends Style { 1880 CharSequence mBigText; 1881 1882 public BigTextStyle() { 1883 } 1884 1885 public BigTextStyle(Builder builder) { 1886 setBuilder(builder); 1887 } 1888 1889 /** 1890 * Overrides ContentTitle in the big form of the template. 1891 * This defaults to the value passed to setContentTitle(). 1892 */ 1893 public BigTextStyle setBigContentTitle(CharSequence title) { 1894 mBigContentTitle = Builder.limitCharSequenceLength(title); 1895 return this; 1896 } 1897 1898 /** 1899 * Set the first line of text after the detail section in the big form of the template. 1900 */ 1901 public BigTextStyle setSummaryText(CharSequence cs) { 1902 mSummaryText = Builder.limitCharSequenceLength(cs); 1903 mSummaryTextSet = true; 1904 return this; 1905 } 1906 1907 /** 1908 * Provide the longer text to be displayed in the big form of the 1909 * template in place of the content text. 1910 */ 1911 public BigTextStyle bigText(CharSequence cs) { 1912 mBigText = Builder.limitCharSequenceLength(cs); 1913 return this; 1914 } 1915 } 1916 1917 /** 1918 * Helper class for generating large-format notifications that include multiple back-and-forth 1919 * messages of varying types between any number of people. 1920 * 1921 * <br> 1922 * If the platform does not provide large-format notifications, this method has no effect. The 1923 * user will always see the normal notification view. 1924 * <br> 1925 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like 1926 * so: 1927 * <pre class="prettyprint"> 1928 * 1929 * Notification noti = new Notification.Builder() 1930 * .setContentTitle("2 new messages wtih " + sender.toString()) 1931 * .setContentText(subject) 1932 * .setSmallIcon(R.drawable.new_message) 1933 * .setLargeIcon(aBitmap) 1934 * .setStyle(new Notification.MessagingStyle(resources.getString(R.string.reply_name)) 1935 * .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender()) 1936 * .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender())) 1937 * .build(); 1938 * </pre> 1939 */ 1940 public static class MessagingStyle extends Style { 1941 1942 /** 1943 * The maximum number of messages that will be retained in the Notification itself (the 1944 * number displayed is up to the platform). 1945 */ 1946 public static final int MAXIMUM_RETAINED_MESSAGES = 25; 1947 1948 CharSequence mUserDisplayName; 1949 CharSequence mConversationTitle; 1950 List<Message> mMessages = new ArrayList<>(); 1951 1952 MessagingStyle() { 1953 } 1954 1955 /** 1956 * @param userDisplayName the name to be displayed for any replies sent by the user before the 1957 * posting app reposts the notification with those messages after they've been actually 1958 * sent and in previous messages sent by the user added in 1959 * {@link #addMessage(Message)} 1960 */ 1961 public MessagingStyle(CharSequence userDisplayName) { 1962 mUserDisplayName = userDisplayName; 1963 } 1964 1965 /** 1966 * Returns the name to be displayed for any replies sent by the user 1967 */ 1968 public CharSequence getUserDisplayName() { 1969 return mUserDisplayName; 1970 } 1971 1972 /** 1973 * Sets the title to be displayed on this conversation. This should only be used for 1974 * group messaging and left unset for one-on-one conversations. 1975 * @param conversationTitle 1976 * @return this object for method chaining. 1977 */ 1978 public MessagingStyle setConversationTitle(CharSequence conversationTitle) { 1979 mConversationTitle = conversationTitle; 1980 return this; 1981 } 1982 1983 /** 1984 * Return the title to be displayed on this conversation. Can be <code>null</code> and 1985 * should be for one-on-one conversations 1986 */ 1987 public CharSequence getConversationTitle() { 1988 return mConversationTitle; 1989 } 1990 1991 /** 1992 * Adds a message for display by this notification. Convenience call for a simple 1993 * {@link Message} in {@link #addMessage(Message)} 1994 * @param text A {@link CharSequence} to be displayed as the message content 1995 * @param timestamp Time at which the message arrived 1996 * @param sender A {@link CharSequence} to be used for displaying the name of the 1997 * sender. Should be <code>null</code> for messages by the current user, in which case 1998 * the platform will insert {@link #getUserDisplayName()}. 1999 * Should be unique amongst all individuals in the conversation, and should be 2000 * consistent during re-posts of the notification. 2001 * 2002 * @see Message#Message(CharSequence, long, CharSequence) 2003 * 2004 * @return this object for method chaining 2005 */ 2006 public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) { 2007 mMessages.add(new Message(text, timestamp, sender)); 2008 if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { 2009 mMessages.remove(0); 2010 } 2011 return this; 2012 } 2013 2014 /** 2015 * Adds a {@link Message} for display in this notification. 2016 * @param message The {@link Message} to be displayed 2017 * @return this object for method chaining 2018 */ 2019 public MessagingStyle addMessage(Message message) { 2020 mMessages.add(message); 2021 if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { 2022 mMessages.remove(0); 2023 } 2024 return this; 2025 } 2026 2027 /** 2028 * Gets the list of {@code Message} objects that represent the notification 2029 */ 2030 public List<Message> getMessages() { 2031 return mMessages; 2032 } 2033 2034 /** 2035 * Retrieves a {@link MessagingStyle} from a {@link Notification}, enabling an application 2036 * that has set a {@link MessagingStyle} using {@link NotificationCompat} or 2037 * {@link android.app.Notification.Builder} to send messaging information to another 2038 * application using {@link NotificationCompat}, regardless of the API level of the system. 2039 * Returns {@code null} if there is no {@link MessagingStyle} set. 2040 */ 2041 public static MessagingStyle extractMessagingStyleFromNotification(Notification notif) { 2042 MessagingStyle style; 2043 Bundle extras = IMPL.getExtras(notif); 2044 if (!extras.containsKey(EXTRA_SELF_DISPLAY_NAME)) { 2045 style = null; 2046 } else { 2047 try { 2048 style = new MessagingStyle(); 2049 style.restoreFromCompatExtras(extras); 2050 } catch (ClassCastException e) { 2051 style = null; 2052 } 2053 } 2054 return style; 2055 } 2056 2057 @Override 2058 public void addCompatExtras(Bundle extras) { 2059 super.addCompatExtras(extras); 2060 if (mUserDisplayName != null) { 2061 extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName); 2062 } 2063 if (mConversationTitle != null) { 2064 extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle); 2065 } 2066 if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES, 2067 Message.getBundleArrayForMessages(mMessages)); 2068 } 2069 } 2070 2071 /** 2072 * @hide 2073 */ 2074 @Override 2075 protected void restoreFromCompatExtras(Bundle extras) { 2076 mMessages.clear(); 2077 mUserDisplayName = extras.getString(EXTRA_SELF_DISPLAY_NAME); 2078 mConversationTitle = extras.getString(EXTRA_CONVERSATION_TITLE); 2079 Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES); 2080 if (parcelables != null) { 2081 mMessages = Message.getMessagesFromBundleArray(parcelables); 2082 } 2083 } 2084 2085 public static final class Message { 2086 2087 static final String KEY_TEXT = "text"; 2088 static final String KEY_TIMESTAMP = "time"; 2089 static final String KEY_SENDER = "sender"; 2090 static final String KEY_DATA_MIME_TYPE = "type"; 2091 static final String KEY_DATA_URI= "uri"; 2092 2093 private final CharSequence mText; 2094 private final long mTimestamp; 2095 private final CharSequence mSender; 2096 2097 private String mDataMimeType; 2098 private Uri mDataUri; 2099 2100 /** 2101 * Constructor 2102 * @param text A {@link CharSequence} to be displayed as the message content 2103 * @param timestamp Time at which the message arrived 2104 * @param sender A {@link CharSequence} to be used for displaying the name of the 2105 * sender. Should be <code>null</code> for messages by the current user, in which case 2106 * the platform will insert {@link MessagingStyle#getUserDisplayName()}. 2107 * Should be unique amongst all individuals in the conversation, and should be 2108 * consistent during re-posts of the notification. 2109 */ 2110 public Message(CharSequence text, long timestamp, CharSequence sender){ 2111 mText = text; 2112 mTimestamp = timestamp; 2113 mSender = sender; 2114 } 2115 2116 /** 2117 * Sets a binary blob of data and an associated MIME type for a message. In the case 2118 * where the platform doesn't support the MIME type, the original text provided in the 2119 * constructor will be used. 2120 * @param dataMimeType The MIME type of the content. See 2121 * <a href="{@docRoot}notifications/messaging.html"> for the list of supported MIME 2122 * types on Android and Android Wear. 2123 * @param dataUri The uri containing the content whose type is given by the MIME type. 2124 * <p class="note"> 2125 * <ol> 2126 * <li>Notification Listeners including the System UI need permission to access the 2127 * data the Uri points to. The recommended ways to do this are:</li> 2128 * <li>Store the data in your own ContentProvider, making sure that other apps have 2129 * the correct permission to access your provider. The preferred mechanism for 2130 * providing access is to use per-URI permissions which are temporary and only 2131 * grant access to the receiving application. An easy way to create a 2132 * ContentProvider like this is to use the FileProvider helper class.</li> 2133 * <li>Use the system MediaStore. The MediaStore is primarily aimed at video, audio 2134 * and image MIME types, however beginning with Android 3.0 (API level 11) it can 2135 * also store non-media types (see MediaStore.Files for more info). Files can be 2136 * inserted into the MediaStore using scanFile() after which a content:// style 2137 * Uri suitable for sharing is passed to the provided onScanCompleted() callback. 2138 * Note that once added to the system MediaStore the content is accessible to any 2139 * app on the device.</li> 2140 * </ol> 2141 * @return this object for method chaining 2142 */ 2143 public Message setData(String dataMimeType, Uri dataUri) { 2144 mDataMimeType = dataMimeType; 2145 mDataUri = dataUri; 2146 return this; 2147 } 2148 2149 /** 2150 * Get the text to be used for this message, or the fallback text if a type and content 2151 * Uri have been set 2152 */ 2153 public CharSequence getText() { 2154 return mText; 2155 } 2156 2157 /** 2158 * Get the time at which this message arrived 2159 */ 2160 public long getTimestamp() { 2161 return mTimestamp; 2162 } 2163 2164 /** 2165 * Get the text used to display the contact's name in the messaging experience 2166 */ 2167 public CharSequence getSender() { 2168 return mSender; 2169 } 2170 2171 /** 2172 * Get the MIME type of the data pointed to by the Uri 2173 */ 2174 public String getDataMimeType() { 2175 return mDataMimeType; 2176 } 2177 2178 /** 2179 * Get the the Uri pointing to the content of the message. Can be null, in which case 2180 * {@see #getText()} is used. 2181 */ 2182 public Uri getDataUri() { 2183 return mDataUri; 2184 } 2185 2186 private Bundle toBundle() { 2187 Bundle bundle = new Bundle(); 2188 if (mText != null) { 2189 bundle.putCharSequence(KEY_TEXT, mText); 2190 } 2191 bundle.putLong(KEY_TIMESTAMP, mTimestamp); 2192 if (mSender != null) { 2193 bundle.putCharSequence(KEY_SENDER, mSender); 2194 } 2195 if (mDataMimeType != null) { 2196 bundle.putString(KEY_DATA_MIME_TYPE, mDataMimeType); 2197 } 2198 if (mDataUri != null) { 2199 bundle.putParcelable(KEY_DATA_URI, mDataUri); 2200 } 2201 return bundle; 2202 } 2203 2204 static Bundle[] getBundleArrayForMessages(List<Message> messages) { 2205 Bundle[] bundles = new Bundle[messages.size()]; 2206 final int N = messages.size(); 2207 for (int i = 0; i < N; i++) { 2208 bundles[i] = messages.get(i).toBundle(); 2209 } 2210 return bundles; 2211 } 2212 2213 static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) { 2214 List<Message> messages = new ArrayList<>(bundles.length); 2215 for (int i = 0; i < bundles.length; i++) { 2216 if (bundles[i] instanceof Bundle) { 2217 Message message = getMessageFromBundle((Bundle)bundles[i]); 2218 if (message != null) { 2219 messages.add(message); 2220 } 2221 } 2222 } 2223 return messages; 2224 } 2225 2226 static Message getMessageFromBundle(Bundle bundle) { 2227 try { 2228 if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) { 2229 return null; 2230 } else { 2231 Message message = new Message(bundle.getCharSequence(KEY_TEXT), 2232 bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER)); 2233 if (bundle.containsKey(KEY_DATA_MIME_TYPE) && 2234 bundle.containsKey(KEY_DATA_URI)) { 2235 2236 message.setData(bundle.getString(KEY_DATA_MIME_TYPE), 2237 (Uri) bundle.getParcelable(KEY_DATA_URI)); 2238 } 2239 return message; 2240 } 2241 } catch (ClassCastException e) { 2242 return null; 2243 } 2244 } 2245 } 2246 } 2247 2248 /** 2249 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 2250 * 2251 * <br> 2252 * If the platform does not provide large-format notifications, this method has no effect. The 2253 * user will always see the normal notification view. 2254 * <br> 2255 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 2256 * <pre class="prettyprint"> 2257 * Notification noti = new Notification.Builder() 2258 * .setContentTitle("5 New mails from " + sender.toString()) 2259 * .setContentText(subject) 2260 * .setSmallIcon(R.drawable.new_mail) 2261 * .setLargeIcon(aBitmap) 2262 * .setStyle(new Notification.InboxStyle() 2263 * .addLine(str1) 2264 * .addLine(str2) 2265 * .setContentTitle("") 2266 * .setSummaryText("+3 more")) 2267 * .build(); 2268 * </pre> 2269 * 2270 * @see Notification#bigContentView 2271 */ 2272 public static class InboxStyle extends Style { 2273 ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 2274 2275 public InboxStyle() { 2276 } 2277 2278 public InboxStyle(Builder builder) { 2279 setBuilder(builder); 2280 } 2281 2282 /** 2283 * Overrides ContentTitle in the big form of the template. 2284 * This defaults to the value passed to setContentTitle(). 2285 */ 2286 public InboxStyle setBigContentTitle(CharSequence title) { 2287 mBigContentTitle = Builder.limitCharSequenceLength(title); 2288 return this; 2289 } 2290 2291 /** 2292 * Set the first line of text after the detail section in the big form of the template. 2293 */ 2294 public InboxStyle setSummaryText(CharSequence cs) { 2295 mSummaryText = Builder.limitCharSequenceLength(cs); 2296 mSummaryTextSet = true; 2297 return this; 2298 } 2299 2300 /** 2301 * Append a line to the digest section of the Inbox notification. 2302 */ 2303 public InboxStyle addLine(CharSequence cs) { 2304 mTexts.add(Builder.limitCharSequenceLength(cs)); 2305 return this; 2306 } 2307 } 2308 2309 /** 2310 * Structure to encapsulate a named action that can be shown as part of this notification. 2311 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is 2312 * selected by the user. Action buttons won't appear on platforms prior to Android 4.1. 2313 * <p> 2314 * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)} 2315 * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)} 2316 * to attach actions. 2317 */ 2318 public static class Action extends NotificationCompatBase.Action { 2319 private final Bundle mExtras; 2320 private final RemoteInput[] mRemoteInputs; 2321 private boolean mAllowGeneratedReplies = false; 2322 2323 /** 2324 * Small icon representing the action. 2325 */ 2326 public int icon; 2327 /** 2328 * Title of the action. 2329 */ 2330 public CharSequence title; 2331 /** 2332 * Intent to send when the user invokes this action. May be null, in which case the action 2333 * may be rendered in a disabled presentation. 2334 */ 2335 public PendingIntent actionIntent; 2336 2337 public Action(int icon, CharSequence title, PendingIntent intent) { 2338 this(icon, title, intent, new Bundle(), null, false); 2339 } 2340 2341 private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, 2342 RemoteInput[] remoteInputs, boolean allowGeneratedReplies) { 2343 this.icon = icon; 2344 this.title = NotificationCompat.Builder.limitCharSequenceLength(title); 2345 this.actionIntent = intent; 2346 this.mExtras = extras != null ? extras : new Bundle(); 2347 this.mRemoteInputs = remoteInputs; 2348 this.mAllowGeneratedReplies = allowGeneratedReplies; 2349 } 2350 2351 @Override 2352 public int getIcon() { 2353 return icon; 2354 } 2355 2356 @Override 2357 public CharSequence getTitle() { 2358 return title; 2359 } 2360 2361 @Override 2362 public PendingIntent getActionIntent() { 2363 return actionIntent; 2364 } 2365 2366 /** 2367 * Get additional metadata carried around with this Action. 2368 */ 2369 @Override 2370 public Bundle getExtras() { 2371 return mExtras; 2372 } 2373 2374 /** 2375 * Return whether the platform should automatically generate possible replies for this 2376 * {@link Action} 2377 */ 2378 @Override 2379 public boolean getAllowGeneratedReplies() { 2380 return mAllowGeneratedReplies; 2381 } 2382 2383 /** 2384 * Get the list of inputs to be collected from the user when this action is sent. 2385 * May return null if no remote inputs were added. 2386 */ 2387 @Override 2388 public RemoteInput[] getRemoteInputs() { 2389 return mRemoteInputs; 2390 } 2391 2392 /** 2393 * Builder class for {@link Action} objects. 2394 */ 2395 public static final class Builder { 2396 private final int mIcon; 2397 private final CharSequence mTitle; 2398 private final PendingIntent mIntent; 2399 private boolean mAllowGeneratedReplies; 2400 private final Bundle mExtras; 2401 private ArrayList<RemoteInput> mRemoteInputs; 2402 2403 /** 2404 * Construct a new builder for {@link Action} object. 2405 * @param icon icon to show for this action 2406 * @param title the title of the action 2407 * @param intent the {@link PendingIntent} to fire when users trigger this action 2408 */ 2409 public Builder(int icon, CharSequence title, PendingIntent intent) { 2410 this(icon, title, intent, new Bundle()); 2411 } 2412 2413 /** 2414 * Construct a new builder for {@link Action} object using the fields from an 2415 * {@link Action}. 2416 * @param action the action to read fields from. 2417 */ 2418 public Builder(Action action) { 2419 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras)); 2420 } 2421 2422 private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) { 2423 mIcon = icon; 2424 mTitle = NotificationCompat.Builder.limitCharSequenceLength(title); 2425 mIntent = intent; 2426 mExtras = extras; 2427 } 2428 2429 /** 2430 * Merge additional metadata into this builder. 2431 * 2432 * <p>Values within the Bundle will replace existing extras values in this Builder. 2433 * 2434 * @see NotificationCompat.Action#getExtras 2435 */ 2436 public Builder addExtras(Bundle extras) { 2437 if (extras != null) { 2438 mExtras.putAll(extras); 2439 } 2440 return this; 2441 } 2442 2443 /** 2444 * Get the metadata Bundle used by this Builder. 2445 * 2446 * <p>The returned Bundle is shared with this Builder. 2447 */ 2448 public Bundle getExtras() { 2449 return mExtras; 2450 } 2451 2452 /** 2453 * Add an input to be collected from the user when this action is sent. 2454 * Response values can be retrieved from the fired intent by using the 2455 * {@link RemoteInput#getResultsFromIntent} function. 2456 * @param remoteInput a {@link RemoteInput} to add to the action 2457 * @return this object for method chaining 2458 */ 2459 public Builder addRemoteInput(RemoteInput remoteInput) { 2460 if (mRemoteInputs == null) { 2461 mRemoteInputs = new ArrayList<RemoteInput>(); 2462 } 2463 mRemoteInputs.add(remoteInput); 2464 return this; 2465 } 2466 2467 /** 2468 * Set whether the platform should automatically generate possible replies to add to 2469 * {@link RemoteInput#getChoices()}. If the {@link Action} doesn't have a 2470 * {@link RemoteInput}, this has no effect. 2471 * @param allowGeneratedReplies {@code true} to allow generated replies, {@code false} 2472 * otherwise 2473 * @return this object for method chaining 2474 * The default value is {@code false} 2475 */ 2476 public Builder setAllowGeneratedReplies(boolean allowGeneratedReplies) { 2477 mAllowGeneratedReplies = allowGeneratedReplies; 2478 return this; 2479 } 2480 2481 /** 2482 * Apply an extender to this action builder. Extenders may be used to add 2483 * metadata or change options on this builder. 2484 */ 2485 public Builder extend(Extender extender) { 2486 extender.extend(this); 2487 return this; 2488 } 2489 2490 /** 2491 * Combine all of the options that have been set and return a new {@link Action} 2492 * object. 2493 * @return the built action 2494 */ 2495 public Action build() { 2496 RemoteInput[] remoteInputs = mRemoteInputs != null 2497 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; 2498 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs, 2499 mAllowGeneratedReplies); 2500 } 2501 } 2502 2503 2504 /** 2505 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 2506 * metadata or change options on an action builder. 2507 */ 2508 public interface Extender { 2509 /** 2510 * Apply this extender to a notification action builder. 2511 * @param builder the builder to be modified. 2512 * @return the build object for chaining. 2513 */ 2514 public Builder extend(Builder builder); 2515 } 2516 2517 /** 2518 * Wearable extender for notification actions. To add extensions to an action, 2519 * create a new {@link NotificationCompat.Action.WearableExtender} object using 2520 * the {@code WearableExtender()} constructor and apply it to a 2521 * {@link NotificationCompat.Action.Builder} using 2522 * {@link NotificationCompat.Action.Builder#extend}. 2523 * 2524 * <pre class="prettyprint"> 2525 * NotificationCompat.Action action = new NotificationCompat.Action.Builder( 2526 * R.drawable.archive_all, "Archive all", actionIntent) 2527 * .extend(new NotificationCompat.Action.WearableExtender() 2528 * .setAvailableOffline(false)) 2529 * .build();</pre> 2530 */ 2531 public static final class WearableExtender implements Extender { 2532 /** Notification action extra which contains wearable extensions */ 2533 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2534 2535 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 2536 private static final String KEY_FLAGS = "flags"; 2537 private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel"; 2538 private static final String KEY_CONFIRM_LABEL = "confirmLabel"; 2539 private static final String KEY_CANCEL_LABEL = "cancelLabel"; 2540 2541 // Flags bitwise-ored to mFlags 2542 private static final int FLAG_AVAILABLE_OFFLINE = 0x1; 2543 private static final int FLAG_HINT_LAUNCHES_ACTIVITY = 1 << 1; 2544 2545 // Default value for flags integer 2546 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE; 2547 2548 private int mFlags = DEFAULT_FLAGS; 2549 2550 private CharSequence mInProgressLabel; 2551 private CharSequence mConfirmLabel; 2552 private CharSequence mCancelLabel; 2553 2554 /** 2555 * Create a {@link NotificationCompat.Action.WearableExtender} with default 2556 * options. 2557 */ 2558 public WearableExtender() { 2559 } 2560 2561 /** 2562 * Create a {@link NotificationCompat.Action.WearableExtender} by reading 2563 * wearable options present in an existing notification action. 2564 * @param action the notification action to inspect. 2565 */ 2566 public WearableExtender(Action action) { 2567 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS); 2568 if (wearableBundle != null) { 2569 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 2570 mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL); 2571 mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL); 2572 mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL); 2573 } 2574 } 2575 2576 /** 2577 * Apply wearable extensions to a notification action that is being built. This is 2578 * typically called by the {@link NotificationCompat.Action.Builder#extend} 2579 * method of {@link NotificationCompat.Action.Builder}. 2580 */ 2581 @Override 2582 public Action.Builder extend(Action.Builder builder) { 2583 Bundle wearableBundle = new Bundle(); 2584 2585 if (mFlags != DEFAULT_FLAGS) { 2586 wearableBundle.putInt(KEY_FLAGS, mFlags); 2587 } 2588 if (mInProgressLabel != null) { 2589 wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel); 2590 } 2591 if (mConfirmLabel != null) { 2592 wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel); 2593 } 2594 if (mCancelLabel != null) { 2595 wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel); 2596 } 2597 2598 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 2599 return builder; 2600 } 2601 2602 @Override 2603 public WearableExtender clone() { 2604 WearableExtender that = new WearableExtender(); 2605 that.mFlags = this.mFlags; 2606 that.mInProgressLabel = this.mInProgressLabel; 2607 that.mConfirmLabel = this.mConfirmLabel; 2608 that.mCancelLabel = this.mCancelLabel; 2609 return that; 2610 } 2611 2612 /** 2613 * Set whether this action is available when the wearable device is not connected to 2614 * a companion device. The user can still trigger this action when the wearable device 2615 * is offline, but a visual hint will indicate that the action may not be available. 2616 * Defaults to true. 2617 */ 2618 public WearableExtender setAvailableOffline(boolean availableOffline) { 2619 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline); 2620 return this; 2621 } 2622 2623 /** 2624 * Get whether this action is available when the wearable device is not connected to 2625 * a companion device. The user can still trigger this action when the wearable device 2626 * is offline, but a visual hint will indicate that the action may not be available. 2627 * Defaults to true. 2628 */ 2629 public boolean isAvailableOffline() { 2630 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0; 2631 } 2632 2633 private void setFlag(int mask, boolean value) { 2634 if (value) { 2635 mFlags |= mask; 2636 } else { 2637 mFlags &= ~mask; 2638 } 2639 } 2640 2641 /** 2642 * Set a label to display while the wearable is preparing to automatically execute the 2643 * action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2644 * 2645 * @param label the label to display while the action is being prepared to execute 2646 * @return this object for method chaining 2647 */ 2648 public WearableExtender setInProgressLabel(CharSequence label) { 2649 mInProgressLabel = label; 2650 return this; 2651 } 2652 2653 /** 2654 * Get the label to display while the wearable is preparing to automatically execute 2655 * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2656 * 2657 * @return the label to display while the action is being prepared to execute 2658 */ 2659 public CharSequence getInProgressLabel() { 2660 return mInProgressLabel; 2661 } 2662 2663 /** 2664 * Set a label to display to confirm that the action should be executed. 2665 * This is usually an imperative verb like "Send". 2666 * 2667 * @param label the label to confirm the action should be executed 2668 * @return this object for method chaining 2669 */ 2670 public WearableExtender setConfirmLabel(CharSequence label) { 2671 mConfirmLabel = label; 2672 return this; 2673 } 2674 2675 /** 2676 * Get the label to display to confirm that the action should be executed. 2677 * This is usually an imperative verb like "Send". 2678 * 2679 * @return the label to confirm the action should be executed 2680 */ 2681 public CharSequence getConfirmLabel() { 2682 return mConfirmLabel; 2683 } 2684 2685 /** 2686 * Set a label to display to cancel the action. 2687 * This is usually an imperative verb, like "Cancel". 2688 * 2689 * @param label the label to display to cancel the action 2690 * @return this object for method chaining 2691 */ 2692 public WearableExtender setCancelLabel(CharSequence label) { 2693 mCancelLabel = label; 2694 return this; 2695 } 2696 2697 /** 2698 * Get the label to display to cancel the action. 2699 * This is usually an imperative verb like "Cancel". 2700 * 2701 * @return the label to display to cancel the action 2702 */ 2703 public CharSequence getCancelLabel() { 2704 return mCancelLabel; 2705 } 2706 2707 /** 2708 * Set a hint that this Action will launch an {@link Activity} directly, telling the 2709 * platform that it can generate the appropriate transitions. 2710 * @param hintLaunchesActivity {@code true} if the content intent will launch 2711 * an activity and transitions should be generated, false otherwise. 2712 * @return this object for method chaining 2713 */ 2714 public WearableExtender setHintLaunchesActivity( 2715 boolean hintLaunchesActivity) { 2716 setFlag(FLAG_HINT_LAUNCHES_ACTIVITY, hintLaunchesActivity); 2717 return this; 2718 } 2719 2720 /** 2721 * Get a hint that this Action will launch an {@link Activity} directly, telling the 2722 * platform that it can generate the appropriate transitions 2723 * @return {@code true} if the content intent will launch an activity and transitions 2724 * should be generated, false otherwise. The default value is {@code false} if this was 2725 * never set. 2726 */ 2727 public boolean getHintLaunchesActivity() { 2728 return (mFlags & FLAG_HINT_LAUNCHES_ACTIVITY) != 0; 2729 } 2730 } 2731 2732 /** @hide */ 2733 public static final Factory FACTORY = new Factory() { 2734 @Override 2735 public NotificationCompatBase.Action build(int icon, CharSequence title, 2736 PendingIntent actionIntent, Bundle extras, 2737 RemoteInputCompatBase.RemoteInput[] remoteInputs, 2738 boolean allowGeneratedReplies) { 2739 return new Action(icon, title, actionIntent, extras, 2740 (RemoteInput[]) remoteInputs, allowGeneratedReplies); 2741 } 2742 2743 @Override 2744 public Action[] newArray(int length) { 2745 return new Action[length]; 2746 } 2747 }; 2748 } 2749 2750 2751 /** 2752 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 2753 * metadata or change options on a notification builder. 2754 */ 2755 public interface Extender { 2756 /** 2757 * Apply this extender to a notification builder. 2758 * @param builder the builder to be modified. 2759 * @return the build object for chaining. 2760 */ 2761 public Builder extend(Builder builder); 2762 } 2763 2764 /** 2765 * Helper class to add wearable extensions to notifications. 2766 * <p class="note"> See 2767 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications 2768 * for Android Wear</a> for more information on how to use this class. 2769 * <p> 2770 * To create a notification with wearable extensions: 2771 * <ol> 2772 * <li>Create a {@link NotificationCompat.Builder}, setting any desired 2773 * properties. 2774 * <li>Create a {@link NotificationCompat.WearableExtender}. 2775 * <li>Set wearable-specific properties using the 2776 * {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}. 2777 * <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a 2778 * notification. 2779 * <li>Post the notification to the notification 2780 * system with the {@code NotificationManagerCompat.notify(...)} methods 2781 * and not the {@code NotificationManager.notify(...)} methods. 2782 * </ol> 2783 * 2784 * <pre class="prettyprint"> 2785 * Notification notif = new NotificationCompat.Builder(mContext) 2786 * .setContentTitle("New mail from " + sender.toString()) 2787 * .setContentText(subject) 2788 * .setSmallIcon(R.drawable.new_mail) 2789 * .extend(new NotificationCompat.WearableExtender() 2790 * .setContentIcon(R.drawable.new_mail)) 2791 * .build(); 2792 * NotificationManagerCompat.from(mContext).notify(0, notif);</pre> 2793 * 2794 * <p>Wearable extensions can be accessed on an existing notification by using the 2795 * {@code WearableExtender(Notification)} constructor, 2796 * and then using the {@code get} methods to access values. 2797 * 2798 * <pre class="prettyprint"> 2799 * NotificationCompat.WearableExtender wearableExtender = 2800 * new NotificationCompat.WearableExtender(notification); 2801 * List<Notification> pages = wearableExtender.getPages();</pre> 2802 */ 2803 public static final class WearableExtender implements Extender { 2804 /** 2805 * Sentinel value for an action index that is unset. 2806 */ 2807 public static final int UNSET_ACTION_INDEX = -1; 2808 2809 /** 2810 * Size value for use with {@link #setCustomSizePreset} to show this notification with 2811 * default sizing. 2812 * <p>For custom display notifications created using {@link #setDisplayIntent}, 2813 * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based 2814 * on their content. 2815 */ 2816 public static final int SIZE_DEFAULT = 0; 2817 2818 /** 2819 * Size value for use with {@link #setCustomSizePreset} to show this notification 2820 * with an extra small size. 2821 * <p>This value is only applicable for custom display notifications created using 2822 * {@link #setDisplayIntent}. 2823 */ 2824 public static final int SIZE_XSMALL = 1; 2825 2826 /** 2827 * Size value for use with {@link #setCustomSizePreset} to show this notification 2828 * with a small size. 2829 * <p>This value is only applicable for custom display notifications created using 2830 * {@link #setDisplayIntent}. 2831 */ 2832 public static final int SIZE_SMALL = 2; 2833 2834 /** 2835 * Size value for use with {@link #setCustomSizePreset} to show this notification 2836 * with a medium size. 2837 * <p>This value is only applicable for custom display notifications created using 2838 * {@link #setDisplayIntent}. 2839 */ 2840 public static final int SIZE_MEDIUM = 3; 2841 2842 /** 2843 * Size value for use with {@link #setCustomSizePreset} to show this notification 2844 * with a large size. 2845 * <p>This value is only applicable for custom display notifications created using 2846 * {@link #setDisplayIntent}. 2847 */ 2848 public static final int SIZE_LARGE = 4; 2849 2850 /** 2851 * Size value for use with {@link #setCustomSizePreset} to show this notification 2852 * full screen. 2853 * <p>This value is only applicable for custom display notifications created using 2854 * {@link #setDisplayIntent}. 2855 */ 2856 public static final int SIZE_FULL_SCREEN = 5; 2857 2858 /** 2859 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a 2860 * short amount of time when this notification is displayed on the screen. This 2861 * is the default value. 2862 */ 2863 public static final int SCREEN_TIMEOUT_SHORT = 0; 2864 2865 /** 2866 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on 2867 * for a longer amount of time when this notification is displayed on the screen. 2868 */ 2869 public static final int SCREEN_TIMEOUT_LONG = -1; 2870 2871 /** Notification extra which contains wearable extensions */ 2872 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2873 2874 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 2875 private static final String KEY_ACTIONS = "actions"; 2876 private static final String KEY_FLAGS = "flags"; 2877 private static final String KEY_DISPLAY_INTENT = "displayIntent"; 2878 private static final String KEY_PAGES = "pages"; 2879 private static final String KEY_BACKGROUND = "background"; 2880 private static final String KEY_CONTENT_ICON = "contentIcon"; 2881 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity"; 2882 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex"; 2883 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset"; 2884 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; 2885 private static final String KEY_GRAVITY = "gravity"; 2886 private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout"; 2887 private static final String KEY_DISMISSAL_ID = "dismissalId"; 2888 2889 // Flags bitwise-ored to mFlags 2890 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; 2891 private static final int FLAG_HINT_HIDE_ICON = 1 << 1; 2892 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2; 2893 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3; 2894 private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4; 2895 private static final int FLAG_BIG_PICTURE_AMBIENT = 1 << 5; 2896 private static final int FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY = 1 << 6; 2897 2898 // Default value for flags integer 2899 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE; 2900 2901 private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END; 2902 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM; 2903 2904 private ArrayList<Action> mActions = new ArrayList<Action>(); 2905 private int mFlags = DEFAULT_FLAGS; 2906 private PendingIntent mDisplayIntent; 2907 private ArrayList<Notification> mPages = new ArrayList<Notification>(); 2908 private Bitmap mBackground; 2909 private int mContentIcon; 2910 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY; 2911 private int mContentActionIndex = UNSET_ACTION_INDEX; 2912 private int mCustomSizePreset = SIZE_DEFAULT; 2913 private int mCustomContentHeight; 2914 private int mGravity = DEFAULT_GRAVITY; 2915 private int mHintScreenTimeout; 2916 private String mDismissalId; 2917 2918 /** 2919 * Create a {@link NotificationCompat.WearableExtender} with default 2920 * options. 2921 */ 2922 public WearableExtender() { 2923 } 2924 2925 public WearableExtender(Notification notif) { 2926 Bundle extras = getExtras(notif); 2927 Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS) 2928 : null; 2929 if (wearableBundle != null) { 2930 Action[] actions = IMPL.getActionsFromParcelableArrayList( 2931 wearableBundle.getParcelableArrayList(KEY_ACTIONS)); 2932 if (actions != null) { 2933 Collections.addAll(mActions, actions); 2934 } 2935 2936 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 2937 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); 2938 2939 Notification[] pages = getNotificationArrayFromBundle( 2940 wearableBundle, KEY_PAGES); 2941 if (pages != null) { 2942 Collections.addAll(mPages, pages); 2943 } 2944 2945 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND); 2946 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON); 2947 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY, 2948 DEFAULT_CONTENT_ICON_GRAVITY); 2949 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX, 2950 UNSET_ACTION_INDEX); 2951 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET, 2952 SIZE_DEFAULT); 2953 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); 2954 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); 2955 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT); 2956 mDismissalId = wearableBundle.getString(KEY_DISMISSAL_ID); 2957 } 2958 } 2959 2960 /** 2961 * Apply wearable extensions to a notification that is being built. This is typically 2962 * called by the {@link NotificationCompat.Builder#extend} method of 2963 * {@link NotificationCompat.Builder}. 2964 */ 2965 @Override 2966 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 2967 Bundle wearableBundle = new Bundle(); 2968 2969 if (!mActions.isEmpty()) { 2970 wearableBundle.putParcelableArrayList(KEY_ACTIONS, 2971 IMPL.getParcelableArrayListForActions(mActions.toArray( 2972 new Action[mActions.size()]))); 2973 } 2974 if (mFlags != DEFAULT_FLAGS) { 2975 wearableBundle.putInt(KEY_FLAGS, mFlags); 2976 } 2977 if (mDisplayIntent != null) { 2978 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent); 2979 } 2980 if (!mPages.isEmpty()) { 2981 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( 2982 new Notification[mPages.size()])); 2983 } 2984 if (mBackground != null) { 2985 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); 2986 } 2987 if (mContentIcon != 0) { 2988 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); 2989 } 2990 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) { 2991 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity); 2992 } 2993 if (mContentActionIndex != UNSET_ACTION_INDEX) { 2994 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX, 2995 mContentActionIndex); 2996 } 2997 if (mCustomSizePreset != SIZE_DEFAULT) { 2998 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset); 2999 } 3000 if (mCustomContentHeight != 0) { 3001 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight); 3002 } 3003 if (mGravity != DEFAULT_GRAVITY) { 3004 wearableBundle.putInt(KEY_GRAVITY, mGravity); 3005 } 3006 if (mHintScreenTimeout != 0) { 3007 wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout); 3008 } 3009 if (mDismissalId != null) { 3010 wearableBundle.putString(KEY_DISMISSAL_ID, mDismissalId); 3011 } 3012 3013 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 3014 return builder; 3015 } 3016 3017 @Override 3018 public WearableExtender clone() { 3019 WearableExtender that = new WearableExtender(); 3020 that.mActions = new ArrayList<Action>(this.mActions); 3021 that.mFlags = this.mFlags; 3022 that.mDisplayIntent = this.mDisplayIntent; 3023 that.mPages = new ArrayList<Notification>(this.mPages); 3024 that.mBackground = this.mBackground; 3025 that.mContentIcon = this.mContentIcon; 3026 that.mContentIconGravity = this.mContentIconGravity; 3027 that.mContentActionIndex = this.mContentActionIndex; 3028 that.mCustomSizePreset = this.mCustomSizePreset; 3029 that.mCustomContentHeight = this.mCustomContentHeight; 3030 that.mGravity = this.mGravity; 3031 that.mHintScreenTimeout = this.mHintScreenTimeout; 3032 that.mDismissalId = this.mDismissalId; 3033 return that; 3034 } 3035 3036 /** 3037 * Add a wearable action to this notification. 3038 * 3039 * <p>When wearable actions are added using this method, the set of actions that 3040 * show on a wearable device splits from devices that only show actions added 3041 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 3042 * of which actions display on different devices. 3043 * 3044 * @param action the action to add to this notification 3045 * @return this object for method chaining 3046 * @see NotificationCompat.Action 3047 */ 3048 public WearableExtender addAction(Action action) { 3049 mActions.add(action); 3050 return this; 3051 } 3052 3053 /** 3054 * Adds wearable actions to this notification. 3055 * 3056 * <p>When wearable actions are added using this method, the set of actions that 3057 * show on a wearable device splits from devices that only show actions added 3058 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 3059 * of which actions display on different devices. 3060 * 3061 * @param actions the actions to add to this notification 3062 * @return this object for method chaining 3063 * @see NotificationCompat.Action 3064 */ 3065 public WearableExtender addActions(List<Action> actions) { 3066 mActions.addAll(actions); 3067 return this; 3068 } 3069 3070 /** 3071 * Clear all wearable actions present on this builder. 3072 * @return this object for method chaining. 3073 * @see #addAction 3074 */ 3075 public WearableExtender clearActions() { 3076 mActions.clear(); 3077 return this; 3078 } 3079 3080 /** 3081 * Get the wearable actions present on this notification. 3082 */ 3083 public List<Action> getActions() { 3084 return mActions; 3085 } 3086 3087 /** 3088 * Set an intent to launch inside of an activity view when displaying 3089 * this notification. The {@link PendingIntent} provided should be for an activity. 3090 * 3091 * <pre class="prettyprint"> 3092 * Intent displayIntent = new Intent(context, MyDisplayActivity.class); 3093 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context, 3094 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT); 3095 * Notification notif = new NotificationCompat.Builder(context) 3096 * .extend(new NotificationCompat.WearableExtender() 3097 * .setDisplayIntent(displayPendingIntent) 3098 * .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM)) 3099 * .build();</pre> 3100 * 3101 * <p>The activity to launch needs to allow embedding, must be exported, and 3102 * should have an empty task affinity. It is also recommended to use the device 3103 * default light theme. 3104 * 3105 * <p>Example AndroidManifest.xml entry: 3106 * <pre class="prettyprint"> 3107 * <activity android:name="com.example.MyDisplayActivity" 3108 * android:exported="true" 3109 * android:allowEmbedded="true" 3110 * android:taskAffinity="" 3111 * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre> 3112 * 3113 * @param intent the {@link PendingIntent} for an activity 3114 * @return this object for method chaining 3115 * @see NotificationCompat.WearableExtender#getDisplayIntent 3116 */ 3117 public WearableExtender setDisplayIntent(PendingIntent intent) { 3118 mDisplayIntent = intent; 3119 return this; 3120 } 3121 3122 /** 3123 * Get the intent to launch inside of an activity view when displaying this 3124 * notification. This {@code PendingIntent} should be for an activity. 3125 */ 3126 public PendingIntent getDisplayIntent() { 3127 return mDisplayIntent; 3128 } 3129 3130 /** 3131 * Add an additional page of content to display with this notification. The current 3132 * notification forms the first page, and pages added using this function form 3133 * subsequent pages. This field can be used to separate a notification into multiple 3134 * sections. 3135 * 3136 * @param page the notification to add as another page 3137 * @return this object for method chaining 3138 * @see NotificationCompat.WearableExtender#getPages 3139 */ 3140 public WearableExtender addPage(Notification page) { 3141 mPages.add(page); 3142 return this; 3143 } 3144 3145 /** 3146 * Add additional pages of content to display with this notification. The current 3147 * notification forms the first page, and pages added using this function form 3148 * subsequent pages. This field can be used to separate a notification into multiple 3149 * sections. 3150 * 3151 * @param pages a list of notifications 3152 * @return this object for method chaining 3153 * @see NotificationCompat.WearableExtender#getPages 3154 */ 3155 public WearableExtender addPages(List<Notification> pages) { 3156 mPages.addAll(pages); 3157 return this; 3158 } 3159 3160 /** 3161 * Clear all additional pages present on this builder. 3162 * @return this object for method chaining. 3163 * @see #addPage 3164 */ 3165 public WearableExtender clearPages() { 3166 mPages.clear(); 3167 return this; 3168 } 3169 3170 /** 3171 * Get the array of additional pages of content for displaying this notification. The 3172 * current notification forms the first page, and elements within this array form 3173 * subsequent pages. This field can be used to separate a notification into multiple 3174 * sections. 3175 * @return the pages for this notification 3176 */ 3177 public List<Notification> getPages() { 3178 return mPages; 3179 } 3180 3181 /** 3182 * Set a background image to be displayed behind the notification content. 3183 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 3184 * will work with any notification style. 3185 * 3186 * @param background the background bitmap 3187 * @return this object for method chaining 3188 * @see NotificationCompat.WearableExtender#getBackground 3189 */ 3190 public WearableExtender setBackground(Bitmap background) { 3191 mBackground = background; 3192 return this; 3193 } 3194 3195 /** 3196 * Get a background image to be displayed behind the notification content. 3197 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 3198 * will work with any notification style. 3199 * 3200 * @return the background image 3201 * @see NotificationCompat.WearableExtender#setBackground 3202 */ 3203 public Bitmap getBackground() { 3204 return mBackground; 3205 } 3206 3207 /** 3208 * Set an icon that goes with the content of this notification. 3209 */ 3210 public WearableExtender setContentIcon(int icon) { 3211 mContentIcon = icon; 3212 return this; 3213 } 3214 3215 /** 3216 * Get an icon that goes with the content of this notification. 3217 */ 3218 public int getContentIcon() { 3219 return mContentIcon; 3220 } 3221 3222 /** 3223 * Set the gravity that the content icon should have within the notification display. 3224 * Supported values include {@link android.view.Gravity#START} and 3225 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 3226 * @see #setContentIcon 3227 */ 3228 public WearableExtender setContentIconGravity(int contentIconGravity) { 3229 mContentIconGravity = contentIconGravity; 3230 return this; 3231 } 3232 3233 /** 3234 * Get the gravity that the content icon should have within the notification display. 3235 * Supported values include {@link android.view.Gravity#START} and 3236 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 3237 * @see #getContentIcon 3238 */ 3239 public int getContentIconGravity() { 3240 return mContentIconGravity; 3241 } 3242 3243 /** 3244 * Set an action from this notification's actions to be clickable with the content of 3245 * this notification. This action will no longer display separately from the 3246 * notification's content. 3247 * 3248 * <p>For notifications with multiple pages, child pages can also have content actions 3249 * set, although the list of available actions comes from the main notification and not 3250 * from the child page's notification. 3251 * 3252 * @param actionIndex The index of the action to hoist onto the current notification page. 3253 * If wearable actions were added to the main notification, this index 3254 * will apply to that list, otherwise it will apply to the regular 3255 * actions list. 3256 */ 3257 public WearableExtender setContentAction(int actionIndex) { 3258 mContentActionIndex = actionIndex; 3259 return this; 3260 } 3261 3262 /** 3263 * Get the index of the notification action, if any, that was specified as being clickable 3264 * with the content of this notification. This action will no longer display separately 3265 * from the notification's content. 3266 * 3267 * <p>For notifications with multiple pages, child pages can also have content actions 3268 * set, although the list of available actions comes from the main notification and not 3269 * from the child page's notification. 3270 * 3271 * <p>If wearable specific actions were added to the main notification, this index will 3272 * apply to that list, otherwise it will apply to the regular actions list. 3273 * 3274 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected. 3275 */ 3276 public int getContentAction() { 3277 return mContentActionIndex; 3278 } 3279 3280 /** 3281 * Set the gravity that this notification should have within the available viewport space. 3282 * Supported values include {@link android.view.Gravity#TOP}, 3283 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 3284 * The default value is {@link android.view.Gravity#BOTTOM}. 3285 */ 3286 public WearableExtender setGravity(int gravity) { 3287 mGravity = gravity; 3288 return this; 3289 } 3290 3291 /** 3292 * Get the gravity that this notification should have within the available viewport space. 3293 * Supported values include {@link android.view.Gravity#TOP}, 3294 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 3295 * The default value is {@link android.view.Gravity#BOTTOM}. 3296 */ 3297 public int getGravity() { 3298 return mGravity; 3299 } 3300 3301 /** 3302 * Set the custom size preset for the display of this notification out of the available 3303 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 3304 * {@link #SIZE_LARGE}. 3305 * <p>Some custom size presets are only applicable for custom display notifications created 3306 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the 3307 * documentation for the preset in question. See also 3308 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}. 3309 */ 3310 public WearableExtender setCustomSizePreset(int sizePreset) { 3311 mCustomSizePreset = sizePreset; 3312 return this; 3313 } 3314 3315 /** 3316 * Get the custom size preset for the display of this notification out of the available 3317 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 3318 * {@link #SIZE_LARGE}. 3319 * <p>Some custom size presets are only applicable for custom display notifications created 3320 * using {@link #setDisplayIntent}. Check the documentation for the preset in question. 3321 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}. 3322 */ 3323 public int getCustomSizePreset() { 3324 return mCustomSizePreset; 3325 } 3326 3327 /** 3328 * Set the custom height in pixels for the display of this notification's content. 3329 * <p>This option is only available for custom display notifications created 3330 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also 3331 * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and 3332 * {@link #getCustomContentHeight}. 3333 */ 3334 public WearableExtender setCustomContentHeight(int height) { 3335 mCustomContentHeight = height; 3336 return this; 3337 } 3338 3339 /** 3340 * Get the custom height in pixels for the display of this notification's content. 3341 * <p>This option is only available for custom display notifications created 3342 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and 3343 * {@link #setCustomContentHeight}. 3344 */ 3345 public int getCustomContentHeight() { 3346 return mCustomContentHeight; 3347 } 3348 3349 /** 3350 * Set whether the scrolling position for the contents of this notification should start 3351 * at the bottom of the contents instead of the top when the contents are too long to 3352 * display within the screen. Default is false (start scroll at the top). 3353 */ 3354 public WearableExtender setStartScrollBottom(boolean startScrollBottom) { 3355 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom); 3356 return this; 3357 } 3358 3359 /** 3360 * Get whether the scrolling position for the contents of this notification should start 3361 * at the bottom of the contents instead of the top when the contents are too long to 3362 * display within the screen. Default is false (start scroll at the top). 3363 */ 3364 public boolean getStartScrollBottom() { 3365 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0; 3366 } 3367 3368 /** 3369 * Set whether the content intent is available when the wearable device is not connected 3370 * to a companion device. The user can still trigger this intent when the wearable device 3371 * is offline, but a visual hint will indicate that the content intent may not be available. 3372 * Defaults to true. 3373 */ 3374 public WearableExtender setContentIntentAvailableOffline( 3375 boolean contentIntentAvailableOffline) { 3376 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline); 3377 return this; 3378 } 3379 3380 /** 3381 * Get whether the content intent is available when the wearable device is not connected 3382 * to a companion device. The user can still trigger this intent when the wearable device 3383 * is offline, but a visual hint will indicate that the content intent may not be available. 3384 * Defaults to true. 3385 */ 3386 public boolean getContentIntentAvailableOffline() { 3387 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0; 3388 } 3389 3390 /** 3391 * Set a hint that this notification's icon should not be displayed. 3392 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise. 3393 * @return this object for method chaining 3394 */ 3395 public WearableExtender setHintHideIcon(boolean hintHideIcon) { 3396 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon); 3397 return this; 3398 } 3399 3400 /** 3401 * Get a hint that this notification's icon should not be displayed. 3402 * @return {@code true} if this icon should not be displayed, false otherwise. 3403 * The default value is {@code false} if this was never set. 3404 */ 3405 public boolean getHintHideIcon() { 3406 return (mFlags & FLAG_HINT_HIDE_ICON) != 0; 3407 } 3408 3409 /** 3410 * Set a visual hint that only the background image of this notification should be 3411 * displayed, and other semantic content should be hidden. This hint is only applicable 3412 * to sub-pages added using {@link #addPage}. 3413 */ 3414 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) { 3415 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly); 3416 return this; 3417 } 3418 3419 /** 3420 * Get a visual hint that only the background image of this notification should be 3421 * displayed, and other semantic content should be hidden. This hint is only applicable 3422 * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}. 3423 */ 3424 public boolean getHintShowBackgroundOnly() { 3425 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0; 3426 } 3427 3428 /** 3429 * Set a hint that this notification's background should not be clipped if possible, 3430 * and should instead be resized to fully display on the screen, retaining the aspect 3431 * ratio of the image. This can be useful for images like barcodes or qr codes. 3432 * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible. 3433 * @return this object for method chaining 3434 */ 3435 public WearableExtender setHintAvoidBackgroundClipping( 3436 boolean hintAvoidBackgroundClipping) { 3437 setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping); 3438 return this; 3439 } 3440 3441 /** 3442 * Get a hint that this notification's background should not be clipped if possible, 3443 * and should instead be resized to fully display on the screen, retaining the aspect 3444 * ratio of the image. This can be useful for images like barcodes or qr codes. 3445 * @return {@code true} if it's ok if the background is clipped on the screen, false 3446 * otherwise. The default value is {@code false} if this was never set. 3447 */ 3448 public boolean getHintAvoidBackgroundClipping() { 3449 return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0; 3450 } 3451 3452 /** 3453 * Set a hint that the screen should remain on for at least this duration when 3454 * this notification is displayed on the screen. 3455 * @param timeout The requested screen timeout in milliseconds. Can also be either 3456 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 3457 * @return this object for method chaining 3458 */ 3459 public WearableExtender setHintScreenTimeout(int timeout) { 3460 mHintScreenTimeout = timeout; 3461 return this; 3462 } 3463 3464 /** 3465 * Get the duration, in milliseconds, that the screen should remain on for 3466 * when this notification is displayed. 3467 * @return the duration in milliseconds if > 0, or either one of the sentinel values 3468 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 3469 */ 3470 public int getHintScreenTimeout() { 3471 return mHintScreenTimeout; 3472 } 3473 3474 /** 3475 * Set a hint that this notification's {@link BigPictureStyle} (if present) should be 3476 * converted to low-bit and displayed in ambient mode, especially useful for barcodes and 3477 * qr codes, as well as other simple black-and-white tickets. 3478 * @param hintAmbientBigPicture {@code true} to enable converstion and ambient. 3479 * @return this object for method chaining 3480 */ 3481 public WearableExtender setHintAmbientBigPicture(boolean hintAmbientBigPicture) { 3482 setFlag(FLAG_BIG_PICTURE_AMBIENT, hintAmbientBigPicture); 3483 return this; 3484 } 3485 3486 /** 3487 * Get a hint that this notification's {@link BigPictureStyle} (if present) should be 3488 * converted to low-bit and displayed in ambient mode, especially useful for barcodes and 3489 * qr codes, as well as other simple black-and-white tickets. 3490 * @return {@code true} if it should be displayed in ambient, false otherwise 3491 * otherwise. The default value is {@code false} if this was never set. 3492 */ 3493 public boolean getHintAmbientBigPicture() { 3494 return (mFlags & FLAG_BIG_PICTURE_AMBIENT) != 0; 3495 } 3496 3497 /** 3498 * Set a hint that this notification's content intent will launch an {@link Activity} 3499 * directly, telling the platform that it can generate the appropriate transitions. 3500 * @param hintContentIntentLaunchesActivity {@code true} if the content intent will launch 3501 * an activity and transitions should be generated, false otherwise. 3502 * @return this object for method chaining 3503 */ 3504 public WearableExtender setHintContentIntentLaunchesActivity( 3505 boolean hintContentIntentLaunchesActivity) { 3506 setFlag(FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY, hintContentIntentLaunchesActivity); 3507 return this; 3508 } 3509 3510 /** 3511 * Get a hint that this notification's content intent will launch an {@link Activity} 3512 * directly, telling the platform that it can generate the appropriate transitions 3513 * @return {@code true} if the content intent will launch an activity and transitions should 3514 * be generated, false otherwise. The default value is {@code false} if this was never set. 3515 */ 3516 public boolean getHintContentIntentLaunchesActivity() { 3517 return (mFlags & FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY) != 0; 3518 } 3519 3520 /** 3521 * When you post a notification, if you set the dismissal id field, then when that 3522 * notification is canceled, notifications on other wearables and the paired Android phone 3523 * having that same dismissal id will also be canceled. Note that this only works if you 3524 * have notification bridge mode set to NO_BRIDGING in your Wear app manifest. See 3525 * <a href="{@docRoot}wear/notifications/index.html">Adding Wearable Features to 3526 * Notifications</a> for more information on how to use the bridge mode feature. 3527 * @param dismissalId the dismissal id of the notification. 3528 * @return this object for method chaining 3529 */ 3530 public WearableExtender setDismissalId(String dismissalId) { 3531 mDismissalId = dismissalId; 3532 return this; 3533 } 3534 3535 /** 3536 * Returns the dismissal id of the notification. 3537 * @return the dismissal id of the notification or null if it has not been set. 3538 */ 3539 public String getDismissalId() { 3540 return mDismissalId; 3541 } 3542 3543 private void setFlag(int mask, boolean value) { 3544 if (value) { 3545 mFlags |= mask; 3546 } else { 3547 mFlags &= ~mask; 3548 } 3549 } 3550 } 3551 3552 /** 3553 * <p>Helper class to add Android Auto extensions to notifications. To create a notification 3554 * with car extensions: 3555 * 3556 * <ol> 3557 * <li>Create an {@link NotificationCompat.Builder}, setting any desired 3558 * properties. 3559 * <li>Create a {@link CarExtender}. 3560 * <li>Set car-specific properties using the {@code add} and {@code set} methods of 3561 * {@link CarExtender}. 3562 * <li>Call {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)} 3563 * to apply the extensions to a notification. 3564 * <li>Post the notification to the notification system with the 3565 * {@code NotificationManagerCompat.notify(...)} methods and not the 3566 * {@code NotificationManager.notify(...)} methods. 3567 * </ol> 3568 * 3569 * <pre class="prettyprint"> 3570 * Notification notification = new NotificationCompat.Builder(context) 3571 * ... 3572 * .extend(new CarExtender() 3573 * .set*(...)) 3574 * .build(); 3575 * </pre> 3576 * 3577 * <p>Car extensions can be accessed on an existing notification by using the 3578 * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods 3579 * to access values. 3580 */ 3581 public static final class CarExtender implements Extender { 3582 private static final String TAG = "CarExtender"; 3583 3584 private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS"; 3585 private static final String EXTRA_LARGE_ICON = "large_icon"; 3586 private static final String EXTRA_CONVERSATION = "car_conversation"; 3587 private static final String EXTRA_COLOR = "app_color"; 3588 3589 private Bitmap mLargeIcon; 3590 private UnreadConversation mUnreadConversation; 3591 private int mColor = NotificationCompat.COLOR_DEFAULT; 3592 3593 /** 3594 * Create a {@link CarExtender} with default options. 3595 */ 3596 public CarExtender() { 3597 } 3598 3599 /** 3600 * Create a {@link CarExtender} from the CarExtender options of an existing Notification. 3601 * 3602 * @param notif The notification from which to copy options. 3603 */ 3604 public CarExtender(Notification notif) { 3605 if (Build.VERSION.SDK_INT < 21) { 3606 return; 3607 } 3608 3609 Bundle carBundle = getExtras(notif)==null ? 3610 null : getExtras(notif).getBundle(EXTRA_CAR_EXTENDER); 3611 if (carBundle != null) { 3612 mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON); 3613 mColor = carBundle.getInt(EXTRA_COLOR, NotificationCompat.COLOR_DEFAULT); 3614 3615 Bundle b = carBundle.getBundle(EXTRA_CONVERSATION); 3616 mUnreadConversation = (UnreadConversation) IMPL.getUnreadConversationFromBundle( 3617 b, UnreadConversation.FACTORY, RemoteInput.FACTORY); 3618 } 3619 } 3620 3621 /** 3622 * Apply car extensions to a notification that is being built. This is typically called by 3623 * the {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)} 3624 * method of {@link NotificationCompat.Builder}. 3625 */ 3626 @Override 3627 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 3628 if (Build.VERSION.SDK_INT < 21) { 3629 return builder; 3630 } 3631 3632 Bundle carExtensions = new Bundle(); 3633 3634 if (mLargeIcon != null) { 3635 carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); 3636 } 3637 if (mColor != NotificationCompat.COLOR_DEFAULT) { 3638 carExtensions.putInt(EXTRA_COLOR, mColor); 3639 } 3640 3641 if (mUnreadConversation != null) { 3642 Bundle b = IMPL.getBundleForUnreadConversation(mUnreadConversation); 3643 carExtensions.putBundle(EXTRA_CONVERSATION, b); 3644 } 3645 3646 builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions); 3647 return builder; 3648 } 3649 3650 /** 3651 * Sets the accent color to use when Android Auto presents the notification. 3652 * 3653 * Android Auto uses the color set with {@link android.support.v4.app.NotificationCompat.Builder#setColor(int)} 3654 * to accent the displayed notification. However, not all colors are acceptable in an 3655 * automotive setting. This method can be used to override the color provided in the 3656 * notification in such a situation. 3657 */ 3658 public CarExtender setColor(@ColorInt int color) { 3659 mColor = color; 3660 return this; 3661 } 3662 3663 /** 3664 * Gets the accent color. 3665 * 3666 * @see #setColor 3667 */ 3668 @ColorInt 3669 public int getColor() { 3670 return mColor; 3671 } 3672 3673 /** 3674 * Sets the large icon of the car notification. 3675 * 3676 * If no large icon is set in the extender, Android Auto will display the icon 3677 * specified by {@link android.support.v4.app.NotificationCompat.Builder#setLargeIcon(android.graphics.Bitmap)} 3678 * 3679 * @param largeIcon The large icon to use in the car notification. 3680 * @return This object for method chaining. 3681 */ 3682 public CarExtender setLargeIcon(Bitmap largeIcon) { 3683 mLargeIcon = largeIcon; 3684 return this; 3685 } 3686 3687 /** 3688 * Gets the large icon used in this car notification, or null if no icon has been set. 3689 * 3690 * @return The large icon for the car notification. 3691 * @see CarExtender#setLargeIcon 3692 */ 3693 public Bitmap getLargeIcon() { 3694 return mLargeIcon; 3695 } 3696 3697 /** 3698 * Sets the unread conversation in a message notification. 3699 * 3700 * @param unreadConversation The unread part of the conversation this notification conveys. 3701 * @return This object for method chaining. 3702 */ 3703 public CarExtender setUnreadConversation(UnreadConversation unreadConversation) { 3704 mUnreadConversation = unreadConversation; 3705 return this; 3706 } 3707 3708 /** 3709 * Returns the unread conversation conveyed by this notification. 3710 * @see #setUnreadConversation(UnreadConversation) 3711 */ 3712 public UnreadConversation getUnreadConversation() { 3713 return mUnreadConversation; 3714 } 3715 3716 /** 3717 * A class which holds the unread messages from a conversation. 3718 */ 3719 public static class UnreadConversation extends NotificationCompatBase.UnreadConversation { 3720 private final String[] mMessages; 3721 private final RemoteInput mRemoteInput; 3722 private final PendingIntent mReplyPendingIntent; 3723 private final PendingIntent mReadPendingIntent; 3724 private final String[] mParticipants; 3725 private final long mLatestTimestamp; 3726 3727 UnreadConversation(String[] messages, RemoteInput remoteInput, 3728 PendingIntent replyPendingIntent, PendingIntent readPendingIntent, 3729 String[] participants, long latestTimestamp) { 3730 mMessages = messages; 3731 mRemoteInput = remoteInput; 3732 mReadPendingIntent = readPendingIntent; 3733 mReplyPendingIntent = replyPendingIntent; 3734 mParticipants = participants; 3735 mLatestTimestamp = latestTimestamp; 3736 } 3737 3738 /** 3739 * Gets the list of messages conveyed by this notification. 3740 */ 3741 @Override 3742 public String[] getMessages() { 3743 return mMessages; 3744 } 3745 3746 /** 3747 * Gets the remote input that will be used to convey the response to a message list, or 3748 * null if no such remote input exists. 3749 */ 3750 @Override 3751 public RemoteInput getRemoteInput() { 3752 return mRemoteInput; 3753 } 3754 3755 /** 3756 * Gets the pending intent that will be triggered when the user replies to this 3757 * notification. 3758 */ 3759 @Override 3760 public PendingIntent getReplyPendingIntent() { 3761 return mReplyPendingIntent; 3762 } 3763 3764 /** 3765 * Gets the pending intent that Android Auto will send after it reads aloud all messages 3766 * in this object's message list. 3767 */ 3768 @Override 3769 public PendingIntent getReadPendingIntent() { 3770 return mReadPendingIntent; 3771 } 3772 3773 /** 3774 * Gets the participants in the conversation. 3775 */ 3776 @Override 3777 public String[] getParticipants() { 3778 return mParticipants; 3779 } 3780 3781 /** 3782 * Gets the firs participant in the conversation. 3783 */ 3784 @Override 3785 public String getParticipant() { 3786 return mParticipants.length > 0 ? mParticipants[0] : null; 3787 } 3788 3789 /** 3790 * Gets the timestamp of the conversation. 3791 */ 3792 @Override 3793 public long getLatestTimestamp() { 3794 return mLatestTimestamp; 3795 } 3796 3797 /** @hide */ 3798 static final Factory FACTORY = new Factory() { 3799 @Override 3800 public UnreadConversation build( 3801 String[] messages, RemoteInputCompatBase.RemoteInput remoteInput, 3802 PendingIntent replyPendingIntent, PendingIntent readPendingIntent, 3803 String[] participants, long latestTimestamp) { 3804 return new UnreadConversation( 3805 messages, (RemoteInput) remoteInput, replyPendingIntent, 3806 readPendingIntent, 3807 participants, latestTimestamp); 3808 } 3809 }; 3810 3811 /** 3812 * Builder class for {@link CarExtender.UnreadConversation} objects. 3813 */ 3814 public static class Builder { 3815 private final List<String> mMessages = new ArrayList<String>(); 3816 private final String mParticipant; 3817 private RemoteInput mRemoteInput; 3818 private PendingIntent mReadPendingIntent; 3819 private PendingIntent mReplyPendingIntent; 3820 private long mLatestTimestamp; 3821 3822 /** 3823 * Constructs a new builder for {@link CarExtender.UnreadConversation}. 3824 * 3825 * @param name The name of the other participant in the conversation. 3826 */ 3827 public Builder(String name) { 3828 mParticipant = name; 3829 } 3830 3831 /** 3832 * Appends a new unread message to the list of messages for this conversation. 3833 * 3834 * The messages should be added from oldest to newest. 3835 * 3836 * @param message The text of the new unread message. 3837 * @return This object for method chaining. 3838 */ 3839 public Builder addMessage(String message) { 3840 mMessages.add(message); 3841 return this; 3842 } 3843 3844 /** 3845 * Sets the pending intent and remote input which will convey the reply to this 3846 * notification. 3847 * 3848 * @param pendingIntent The pending intent which will be triggered on a reply. 3849 * @param remoteInput The remote input parcelable which will carry the reply. 3850 * @return This object for method chaining. 3851 * 3852 * @see CarExtender.UnreadConversation#getRemoteInput 3853 * @see CarExtender.UnreadConversation#getReplyPendingIntent 3854 */ 3855 public Builder setReplyAction( 3856 PendingIntent pendingIntent, RemoteInput remoteInput) { 3857 mRemoteInput = remoteInput; 3858 mReplyPendingIntent = pendingIntent; 3859 3860 return this; 3861 } 3862 3863 /** 3864 * Sets the pending intent that will be sent once the messages in this notification 3865 * are read. 3866 * 3867 * @param pendingIntent The pending intent to use. 3868 * @return This object for method chaining. 3869 */ 3870 public Builder setReadPendingIntent(PendingIntent pendingIntent) { 3871 mReadPendingIntent = pendingIntent; 3872 return this; 3873 } 3874 3875 /** 3876 * Sets the timestamp of the most recent message in an unread conversation. 3877 * 3878 * If a messaging notification has been posted by your application and has not 3879 * yet been cancelled, posting a later notification with the same id and tag 3880 * but without a newer timestamp may result in Android Auto not displaying a 3881 * heads up notification for the later notification. 3882 * 3883 * @param timestamp The timestamp of the most recent message in the conversation. 3884 * @return This object for method chaining. 3885 */ 3886 public Builder setLatestTimestamp(long timestamp) { 3887 mLatestTimestamp = timestamp; 3888 return this; 3889 } 3890 3891 /** 3892 * Builds a new unread conversation object. 3893 * 3894 * @return The new unread conversation object. 3895 */ 3896 public UnreadConversation build() { 3897 String[] messages = mMessages.toArray(new String[mMessages.size()]); 3898 String[] participants = { mParticipant }; 3899 return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent, 3900 mReadPendingIntent, participants, mLatestTimestamp); 3901 } 3902 } 3903 } 3904 } 3905 3906 3907 /** 3908 * Get an array of Notification objects from a parcelable array bundle field. 3909 * Update the bundle to have a typed array so fetches in the future don't need 3910 * to do an array copy. 3911 */ 3912 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { 3913 Parcelable[] array = bundle.getParcelableArray(key); 3914 if (array instanceof Notification[] || array == null) { 3915 return (Notification[]) array; 3916 } 3917 Notification[] typedArray = new Notification[array.length]; 3918 for (int i = 0; i < array.length; i++) { 3919 typedArray[i] = (Notification) array[i]; 3920 } 3921 bundle.putParcelableArray(key, typedArray); 3922 return typedArray; 3923 } 3924 3925 /** 3926 * Gets the {@link Notification#extras} field from a notification in a backwards 3927 * compatible manner. Extras field was supported from JellyBean (Api level 16) 3928 * forwards. This function will return null on older api levels. 3929 */ 3930 public static Bundle getExtras(Notification notif) { 3931 return IMPL.getExtras(notif); 3932 } 3933 3934 /** 3935 * Get the number of actions in this notification in a backwards compatible 3936 * manner. Actions were supported from JellyBean (Api level 16) forwards. 3937 */ 3938 public static int getActionCount(Notification notif) { 3939 return IMPL.getActionCount(notif); 3940 } 3941 3942 /** 3943 * Get an action on this notification in a backwards compatible 3944 * manner. Actions were supported from JellyBean (Api level 16) forwards. 3945 * @param notif The notification to inspect. 3946 * @param actionIndex The index of the action to retrieve. 3947 */ 3948 public static Action getAction(Notification notif, int actionIndex) { 3949 return IMPL.getAction(notif, actionIndex); 3950 } 3951 3952 /** 3953 * Get the category of this notification in a backwards compatible 3954 * manner. 3955 * @param notif The notification to inspect. 3956 */ 3957 public static String getCategory(Notification notif) { 3958 return IMPL.getCategory(notif); 3959 } 3960 3961 /** 3962 * Get whether or not this notification is only relevant to the current device. 3963 * 3964 * <p>Some notifications can be bridged to other devices for remote display. 3965 * If this hint is set, it is recommend that this notification not be bridged. 3966 */ 3967 public static boolean getLocalOnly(Notification notif) { 3968 return IMPL.getLocalOnly(notif); 3969 } 3970 3971 /** 3972 * Get the key used to group this notification into a cluster or stack 3973 * with other notifications on devices which support such rendering. 3974 */ 3975 public static String getGroup(Notification notif) { 3976 return IMPL.getGroup(notif); 3977 } 3978 3979 /** 3980 * Get whether this notification to be the group summary for a group of notifications. 3981 * Grouped notifications may display in a cluster or stack on devices which 3982 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 3983 * @return Whether this notification is a group summary. 3984 */ 3985 public static boolean isGroupSummary(Notification notif) { 3986 return IMPL.isGroupSummary(notif); 3987 } 3988 3989 /** 3990 * Get a sort key that orders this notification among other notifications from the 3991 * same package. This can be useful if an external sort was already applied and an app 3992 * would like to preserve this. Notifications will be sorted lexicographically using this 3993 * value, although providing different priorities in addition to providing sort key may 3994 * cause this value to be ignored. 3995 * 3996 * <p>This sort key can also be used to order members of a notification group. See 3997 * {@link Builder#setGroup}. 3998 * 3999 * @see String#compareTo(String) 4000 */ 4001 public static String getSortKey(Notification notif) { 4002 return IMPL.getSortKey(notif); 4003 } 4004} 4005