NotificationCompat.java revision 3b3e1c4da1c0a710a74204a6ba44389a6f26b27a
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 Notification n = builder.build(); 516 if (b.mContentView != null) { 517 n.contentView = b.mContentView; 518 } 519 return n; 520 } 521 } 522 523 static class NotificationCompatImplBase implements NotificationCompatImpl { 524 @Override 525 public Notification build(Builder b, BuilderExtender extender) { 526 Notification result = b.mNotification; 527 result = NotificationCompatBase.add(result, b.mContext, 528 b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent); 529 // translate high priority requests into legacy flag 530 if (b.mPriority > PRIORITY_DEFAULT) { 531 result.flags |= FLAG_HIGH_PRIORITY; 532 } 533 if (b.mContentView != null) { 534 result.contentView = b.mContentView; 535 } 536 return result; 537 } 538 539 @Override 540 public Bundle getExtras(Notification n) { 541 return null; 542 } 543 544 @Override 545 public int getActionCount(Notification n) { 546 return 0; 547 } 548 549 @Override 550 public Action getAction(Notification n, int actionIndex) { 551 return null; 552 } 553 554 @Override 555 public Action[] getActionsFromParcelableArrayList( 556 ArrayList<Parcelable> parcelables) { 557 return null; 558 } 559 560 @Override 561 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions) { 562 return null; 563 } 564 565 @Override 566 public String getCategory(Notification n) { 567 return null; 568 } 569 570 @Override 571 public boolean getLocalOnly(Notification n) { 572 return false; 573 } 574 575 @Override 576 public String getGroup(Notification n) { 577 return null; 578 } 579 580 @Override 581 public boolean isGroupSummary(Notification n) { 582 return false; 583 } 584 585 @Override 586 public String getSortKey(Notification n) { 587 return null; 588 } 589 590 @Override 591 public Bundle getBundleForUnreadConversation(NotificationCompatBase.UnreadConversation uc) { 592 return null; 593 } 594 595 @Override 596 public NotificationCompatBase.UnreadConversation getUnreadConversationFromBundle( 597 Bundle b, NotificationCompatBase.UnreadConversation.Factory factory, 598 RemoteInputCompatBase.RemoteInput.Factory remoteInputFactory) { 599 return null; 600 } 601 } 602 603 static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase { 604 @Override 605 public Notification build(Builder b, BuilderExtender extender) { 606 Notification notification = NotificationCompatHoneycomb.add(b.mContext, b.mNotification, 607 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 608 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon); 609 if (b.mContentView != null) { 610 notification.contentView = b.mContentView; 611 } 612 return notification; 613 } 614 } 615 616 static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase { 617 @Override 618 public Notification build(Builder b, BuilderExtender extender) { 619 NotificationCompatIceCreamSandwich.Builder builder = 620 new NotificationCompatIceCreamSandwich.Builder( 621 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 622 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 623 b.mProgressMax, b.mProgress, b.mProgressIndeterminate); 624 return extender.build(b, builder); 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 * @hide 1746 */ 1747 public RemoteViews getContentView() { 1748 return mContentView; 1749 } 1750 1751 /** 1752 * @hide 1753 */ 1754 public RemoteViews getBigContentView() { 1755 return mBigContentView; 1756 } 1757 1758 /** 1759 * @hide 1760 */ 1761 public RemoteViews getHeadsUpContentView() { 1762 return mHeadsUpContentView; 1763 } 1764 1765 /** 1766 * return when if it is showing or 0 otherwise 1767 * 1768 * @hide 1769 */ 1770 public long getWhenIfShowing() { 1771 return mShowWhen ? mNotification.when : 0; 1772 } 1773 1774 /** 1775 * @return the priority set on the notification 1776 * 1777 * @hide 1778 */ 1779 public int getPriority() { 1780 return mPriority; 1781 } 1782 1783 /** 1784 * @return the color of the notification 1785 * 1786 * @hide 1787 */ 1788 public int getColor() { 1789 return mColor; 1790 } 1791 } 1792 1793 /** 1794 * An object that can apply a rich notification style to a {@link Notification.Builder} 1795 * object. 1796 * <br> 1797 * If the platform does not provide rich notification styles, methods in this class have no 1798 * effect. 1799 */ 1800 public static abstract class Style { 1801 Builder mBuilder; 1802 CharSequence mBigContentTitle; 1803 CharSequence mSummaryText; 1804 boolean mSummaryTextSet = false; 1805 1806 public void setBuilder(Builder builder) { 1807 if (mBuilder != builder) { 1808 mBuilder = builder; 1809 if (mBuilder != null) { 1810 mBuilder.setStyle(this); 1811 } 1812 } 1813 } 1814 1815 public Notification build() { 1816 Notification notification = null; 1817 if (mBuilder != null) { 1818 notification = mBuilder.build(); 1819 } 1820 return notification; 1821 } 1822 1823 /** 1824 * @hide 1825 */ 1826 // TODO: implement for all styles 1827 public void addCompatExtras(Bundle extras) { 1828 } 1829 1830 /** 1831 * @hide 1832 */ 1833 // TODO: implement for all styles 1834 protected void restoreFromCompatExtras(Bundle extras) { 1835 } 1836 } 1837 1838 /** 1839 * Helper class for generating large-format notifications that include a large image attachment. 1840 * <br> 1841 * If the platform does not provide large-format notifications, this method has no effect. The 1842 * user will always see the normal notification view. 1843 * <br> 1844 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1845 * <pre class="prettyprint"> 1846 * Notification notif = new Notification.Builder(mContext) 1847 * .setContentTitle("New photo from " + sender.toString()) 1848 * .setContentText(subject) 1849 * .setSmallIcon(R.drawable.new_post) 1850 * .setLargeIcon(aBitmap) 1851 * .setStyle(new Notification.BigPictureStyle() 1852 * .bigPicture(aBigBitmap)) 1853 * .build(); 1854 * </pre> 1855 * 1856 * @see Notification#bigContentView 1857 */ 1858 public static class BigPictureStyle extends Style { 1859 Bitmap mPicture; 1860 Bitmap mBigLargeIcon; 1861 boolean mBigLargeIconSet; 1862 1863 public BigPictureStyle() { 1864 } 1865 1866 public BigPictureStyle(Builder builder) { 1867 setBuilder(builder); 1868 } 1869 1870 /** 1871 * Overrides ContentTitle in the big form of the template. 1872 * This defaults to the value passed to setContentTitle(). 1873 */ 1874 public BigPictureStyle setBigContentTitle(CharSequence title) { 1875 mBigContentTitle = Builder.limitCharSequenceLength(title); 1876 return this; 1877 } 1878 1879 /** 1880 * Set the first line of text after the detail section in the big form of the template. 1881 */ 1882 public BigPictureStyle setSummaryText(CharSequence cs) { 1883 mSummaryText = Builder.limitCharSequenceLength(cs); 1884 mSummaryTextSet = true; 1885 return this; 1886 } 1887 1888 /** 1889 * Provide the bitmap to be used as the payload for the BigPicture notification. 1890 */ 1891 public BigPictureStyle bigPicture(Bitmap b) { 1892 mPicture = b; 1893 return this; 1894 } 1895 1896 /** 1897 * Override the large icon when the big notification is shown. 1898 */ 1899 public BigPictureStyle bigLargeIcon(Bitmap b) { 1900 mBigLargeIcon = b; 1901 mBigLargeIconSet = true; 1902 return this; 1903 } 1904 } 1905 1906 /** 1907 * Helper class for generating large-format notifications that include a lot of text. 1908 * 1909 * <br> 1910 * If the platform does not provide large-format notifications, this method has no effect. The 1911 * user will always see the normal notification view. 1912 * <br> 1913 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1914 * <pre class="prettyprint"> 1915 * Notification notif = new Notification.Builder(mContext) 1916 * .setContentTitle("New mail from " + sender.toString()) 1917 * .setContentText(subject) 1918 * .setSmallIcon(R.drawable.new_mail) 1919 * .setLargeIcon(aBitmap) 1920 * .setStyle(new Notification.BigTextStyle() 1921 * .bigText(aVeryLongString)) 1922 * .build(); 1923 * </pre> 1924 * 1925 * @see Notification#bigContentView 1926 */ 1927 public static class BigTextStyle extends Style { 1928 CharSequence mBigText; 1929 1930 public BigTextStyle() { 1931 } 1932 1933 public BigTextStyle(Builder builder) { 1934 setBuilder(builder); 1935 } 1936 1937 /** 1938 * Overrides ContentTitle in the big form of the template. 1939 * This defaults to the value passed to setContentTitle(). 1940 */ 1941 public BigTextStyle setBigContentTitle(CharSequence title) { 1942 mBigContentTitle = Builder.limitCharSequenceLength(title); 1943 return this; 1944 } 1945 1946 /** 1947 * Set the first line of text after the detail section in the big form of the template. 1948 */ 1949 public BigTextStyle setSummaryText(CharSequence cs) { 1950 mSummaryText = Builder.limitCharSequenceLength(cs); 1951 mSummaryTextSet = true; 1952 return this; 1953 } 1954 1955 /** 1956 * Provide the longer text to be displayed in the big form of the 1957 * template in place of the content text. 1958 */ 1959 public BigTextStyle bigText(CharSequence cs) { 1960 mBigText = Builder.limitCharSequenceLength(cs); 1961 return this; 1962 } 1963 } 1964 1965 /** 1966 * Helper class for generating large-format notifications that include multiple back-and-forth 1967 * messages of varying types between any number of people. 1968 * 1969 * <br> 1970 * If the platform does not provide large-format notifications, this method has no effect. The 1971 * user will always see the normal notification view. 1972 * <br> 1973 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like 1974 * so: 1975 * <pre class="prettyprint"> 1976 * 1977 * Notification noti = new Notification.Builder() 1978 * .setContentTitle("2 new messages wtih " + sender.toString()) 1979 * .setContentText(subject) 1980 * .setSmallIcon(R.drawable.new_message) 1981 * .setLargeIcon(aBitmap) 1982 * .setStyle(new Notification.MessagingStyle(resources.getString(R.string.reply_name)) 1983 * .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender()) 1984 * .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender())) 1985 * .build(); 1986 * </pre> 1987 */ 1988 public static class MessagingStyle extends Style { 1989 1990 /** 1991 * The maximum number of messages that will be retained in the Notification itself (the 1992 * number displayed is up to the platform). 1993 */ 1994 public static final int MAXIMUM_RETAINED_MESSAGES = 25; 1995 1996 CharSequence mUserDisplayName; 1997 CharSequence mConversationTitle; 1998 List<Message> mMessages = new ArrayList<>(); 1999 2000 MessagingStyle() { 2001 } 2002 2003 /** 2004 * @param userDisplayName the name to be displayed for any replies sent by the user before the 2005 * posting app reposts the notification with those messages after they've been actually 2006 * sent and in previous messages sent by the user added in 2007 * {@link #addMessage(Message)} 2008 */ 2009 public MessagingStyle(CharSequence userDisplayName) { 2010 mUserDisplayName = userDisplayName; 2011 } 2012 2013 /** 2014 * Returns the name to be displayed for any replies sent by the user 2015 */ 2016 public CharSequence getUserDisplayName() { 2017 return mUserDisplayName; 2018 } 2019 2020 /** 2021 * Sets the title to be displayed on this conversation. This should only be used for 2022 * group messaging and left unset for one-on-one conversations. 2023 * @param conversationTitle 2024 * @return this object for method chaining. 2025 */ 2026 public MessagingStyle setConversationTitle(CharSequence conversationTitle) { 2027 mConversationTitle = conversationTitle; 2028 return this; 2029 } 2030 2031 /** 2032 * Return the title to be displayed on this conversation. Can be <code>null</code> and 2033 * should be for one-on-one conversations 2034 */ 2035 public CharSequence getConversationTitle() { 2036 return mConversationTitle; 2037 } 2038 2039 /** 2040 * Adds a message for display by this notification. Convenience call for a simple 2041 * {@link Message} in {@link #addMessage(Message)} 2042 * @param text A {@link CharSequence} to be displayed as the message content 2043 * @param timestamp Time at which the message arrived 2044 * @param sender A {@link CharSequence} to be used for displaying the name of the 2045 * sender. Should be <code>null</code> for messages by the current user, in which case 2046 * the platform will insert {@link #getUserDisplayName()}. 2047 * Should be unique amongst all individuals in the conversation, and should be 2048 * consistent during re-posts of the notification. 2049 * 2050 * @see Message#Message(CharSequence, long, CharSequence) 2051 * 2052 * @return this object for method chaining 2053 */ 2054 public MessagingStyle addMessage(CharSequence text, long timestamp, CharSequence sender) { 2055 mMessages.add(new Message(text, timestamp, sender)); 2056 if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { 2057 mMessages.remove(0); 2058 } 2059 return this; 2060 } 2061 2062 /** 2063 * Adds a {@link Message} for display in this notification. 2064 * @param message The {@link Message} to be displayed 2065 * @return this object for method chaining 2066 */ 2067 public MessagingStyle addMessage(Message message) { 2068 mMessages.add(message); 2069 if (mMessages.size() > MAXIMUM_RETAINED_MESSAGES) { 2070 mMessages.remove(0); 2071 } 2072 return this; 2073 } 2074 2075 /** 2076 * Gets the list of {@code Message} objects that represent the notification 2077 */ 2078 public List<Message> getMessages() { 2079 return mMessages; 2080 } 2081 2082 /** 2083 * Retrieves a {@link MessagingStyle} from a {@link Notification}, enabling an application 2084 * that has set a {@link MessagingStyle} using {@link NotificationCompat} or 2085 * {@link android.app.Notification.Builder} to send messaging information to another 2086 * application using {@link NotificationCompat}, regardless of the API level of the system. 2087 * Returns {@code null} if there is no {@link MessagingStyle} set. 2088 */ 2089 public static MessagingStyle extractMessagingStyleFromNotification(Notification notif) { 2090 MessagingStyle style; 2091 Bundle extras = IMPL.getExtras(notif); 2092 if (!extras.containsKey(EXTRA_SELF_DISPLAY_NAME)) { 2093 style = null; 2094 } else { 2095 try { 2096 style = new MessagingStyle(); 2097 style.restoreFromCompatExtras(extras); 2098 } catch (ClassCastException e) { 2099 style = null; 2100 } 2101 } 2102 return style; 2103 } 2104 2105 @Override 2106 public void addCompatExtras(Bundle extras) { 2107 super.addCompatExtras(extras); 2108 if (mUserDisplayName != null) { 2109 extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName); 2110 } 2111 if (mConversationTitle != null) { 2112 extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle); 2113 } 2114 if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES, 2115 Message.getBundleArrayForMessages(mMessages)); 2116 } 2117 } 2118 2119 /** 2120 * @hide 2121 */ 2122 @Override 2123 protected void restoreFromCompatExtras(Bundle extras) { 2124 mMessages.clear(); 2125 mUserDisplayName = extras.getString(EXTRA_SELF_DISPLAY_NAME); 2126 mConversationTitle = extras.getString(EXTRA_CONVERSATION_TITLE); 2127 Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES); 2128 if (parcelables != null) { 2129 mMessages = Message.getMessagesFromBundleArray(parcelables); 2130 } 2131 } 2132 2133 public static final class Message { 2134 2135 static final String KEY_TEXT = "text"; 2136 static final String KEY_TIMESTAMP = "time"; 2137 static final String KEY_SENDER = "sender"; 2138 static final String KEY_DATA_MIME_TYPE = "type"; 2139 static final String KEY_DATA_URI= "uri"; 2140 2141 private final CharSequence mText; 2142 private final long mTimestamp; 2143 private final CharSequence mSender; 2144 2145 private String mDataMimeType; 2146 private Uri mDataUri; 2147 2148 /** 2149 * Constructor 2150 * @param text A {@link CharSequence} to be displayed as the message content 2151 * @param timestamp Time at which the message arrived 2152 * @param sender A {@link CharSequence} to be used for displaying the name of the 2153 * sender. Should be <code>null</code> for messages by the current user, in which case 2154 * the platform will insert {@link MessagingStyle#getUserDisplayName()}. 2155 * Should be unique amongst all individuals in the conversation, and should be 2156 * consistent during re-posts of the notification. 2157 */ 2158 public Message(CharSequence text, long timestamp, CharSequence sender){ 2159 mText = text; 2160 mTimestamp = timestamp; 2161 mSender = sender; 2162 } 2163 2164 /** 2165 * Sets a binary blob of data and an associated MIME type for a message. In the case 2166 * where the platform doesn't support the MIME type, the original text provided in the 2167 * constructor will be used. 2168 * @param dataMimeType The MIME type of the content. See 2169 * <a href="{@docRoot}notifications/messaging.html"> for the list of supported MIME 2170 * types on Android and Android Wear. 2171 * @param dataUri The uri containing the content whose type is given by the MIME type. 2172 * <p class="note"> 2173 * <ol> 2174 * <li>Notification Listeners including the System UI need permission to access the 2175 * data the Uri points to. The recommended ways to do this are:</li> 2176 * <li>Store the data in your own ContentProvider, making sure that other apps have 2177 * the correct permission to access your provider. The preferred mechanism for 2178 * providing access is to use per-URI permissions which are temporary and only 2179 * grant access to the receiving application. An easy way to create a 2180 * ContentProvider like this is to use the FileProvider helper class.</li> 2181 * <li>Use the system MediaStore. The MediaStore is primarily aimed at video, audio 2182 * and image MIME types, however beginning with Android 3.0 (API level 11) it can 2183 * also store non-media types (see MediaStore.Files for more info). Files can be 2184 * inserted into the MediaStore using scanFile() after which a content:// style 2185 * Uri suitable for sharing is passed to the provided onScanCompleted() callback. 2186 * Note that once added to the system MediaStore the content is accessible to any 2187 * app on the device.</li> 2188 * </ol> 2189 * @return this object for method chaining 2190 */ 2191 public Message setData(String dataMimeType, Uri dataUri) { 2192 mDataMimeType = dataMimeType; 2193 mDataUri = dataUri; 2194 return this; 2195 } 2196 2197 /** 2198 * Get the text to be used for this message, or the fallback text if a type and content 2199 * Uri have been set 2200 */ 2201 public CharSequence getText() { 2202 return mText; 2203 } 2204 2205 /** 2206 * Get the time at which this message arrived 2207 */ 2208 public long getTimestamp() { 2209 return mTimestamp; 2210 } 2211 2212 /** 2213 * Get the text used to display the contact's name in the messaging experience 2214 */ 2215 public CharSequence getSender() { 2216 return mSender; 2217 } 2218 2219 /** 2220 * Get the MIME type of the data pointed to by the Uri 2221 */ 2222 public String getDataMimeType() { 2223 return mDataMimeType; 2224 } 2225 2226 /** 2227 * Get the the Uri pointing to the content of the message. Can be null, in which case 2228 * {@see #getText()} is used. 2229 */ 2230 public Uri getDataUri() { 2231 return mDataUri; 2232 } 2233 2234 private Bundle toBundle() { 2235 Bundle bundle = new Bundle(); 2236 if (mText != null) { 2237 bundle.putCharSequence(KEY_TEXT, mText); 2238 } 2239 bundle.putLong(KEY_TIMESTAMP, mTimestamp); 2240 if (mSender != null) { 2241 bundle.putCharSequence(KEY_SENDER, mSender); 2242 } 2243 if (mDataMimeType != null) { 2244 bundle.putString(KEY_DATA_MIME_TYPE, mDataMimeType); 2245 } 2246 if (mDataUri != null) { 2247 bundle.putParcelable(KEY_DATA_URI, mDataUri); 2248 } 2249 return bundle; 2250 } 2251 2252 static Bundle[] getBundleArrayForMessages(List<Message> messages) { 2253 Bundle[] bundles = new Bundle[messages.size()]; 2254 final int N = messages.size(); 2255 for (int i = 0; i < N; i++) { 2256 bundles[i] = messages.get(i).toBundle(); 2257 } 2258 return bundles; 2259 } 2260 2261 static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) { 2262 List<Message> messages = new ArrayList<>(bundles.length); 2263 for (int i = 0; i < bundles.length; i++) { 2264 if (bundles[i] instanceof Bundle) { 2265 Message message = getMessageFromBundle((Bundle)bundles[i]); 2266 if (message != null) { 2267 messages.add(message); 2268 } 2269 } 2270 } 2271 return messages; 2272 } 2273 2274 static Message getMessageFromBundle(Bundle bundle) { 2275 try { 2276 if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) { 2277 return null; 2278 } else { 2279 Message message = new Message(bundle.getCharSequence(KEY_TEXT), 2280 bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER)); 2281 if (bundle.containsKey(KEY_DATA_MIME_TYPE) && 2282 bundle.containsKey(KEY_DATA_URI)) { 2283 2284 message.setData(bundle.getString(KEY_DATA_MIME_TYPE), 2285 (Uri) bundle.getParcelable(KEY_DATA_URI)); 2286 } 2287 return message; 2288 } 2289 } catch (ClassCastException e) { 2290 return null; 2291 } 2292 } 2293 } 2294 } 2295 2296 /** 2297 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 2298 * 2299 * <br> 2300 * If the platform does not provide large-format notifications, this method has no effect. The 2301 * user will always see the normal notification view. 2302 * <br> 2303 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 2304 * <pre class="prettyprint"> 2305 * Notification noti = new Notification.Builder() 2306 * .setContentTitle("5 New mails from " + sender.toString()) 2307 * .setContentText(subject) 2308 * .setSmallIcon(R.drawable.new_mail) 2309 * .setLargeIcon(aBitmap) 2310 * .setStyle(new Notification.InboxStyle() 2311 * .addLine(str1) 2312 * .addLine(str2) 2313 * .setContentTitle("") 2314 * .setSummaryText("+3 more")) 2315 * .build(); 2316 * </pre> 2317 * 2318 * @see Notification#bigContentView 2319 */ 2320 public static class InboxStyle extends Style { 2321 ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 2322 2323 public InboxStyle() { 2324 } 2325 2326 public InboxStyle(Builder builder) { 2327 setBuilder(builder); 2328 } 2329 2330 /** 2331 * Overrides ContentTitle in the big form of the template. 2332 * This defaults to the value passed to setContentTitle(). 2333 */ 2334 public InboxStyle setBigContentTitle(CharSequence title) { 2335 mBigContentTitle = Builder.limitCharSequenceLength(title); 2336 return this; 2337 } 2338 2339 /** 2340 * Set the first line of text after the detail section in the big form of the template. 2341 */ 2342 public InboxStyle setSummaryText(CharSequence cs) { 2343 mSummaryText = Builder.limitCharSequenceLength(cs); 2344 mSummaryTextSet = true; 2345 return this; 2346 } 2347 2348 /** 2349 * Append a line to the digest section of the Inbox notification. 2350 */ 2351 public InboxStyle addLine(CharSequence cs) { 2352 mTexts.add(Builder.limitCharSequenceLength(cs)); 2353 return this; 2354 } 2355 } 2356 2357 /** 2358 * Structure to encapsulate a named action that can be shown as part of this notification. 2359 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is 2360 * selected by the user. Action buttons won't appear on platforms prior to Android 4.1. 2361 * <p> 2362 * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)} 2363 * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)} 2364 * to attach actions. 2365 */ 2366 public static class Action extends NotificationCompatBase.Action { 2367 private final Bundle mExtras; 2368 private final RemoteInput[] mRemoteInputs; 2369 private boolean mAllowGeneratedReplies = false; 2370 2371 /** 2372 * Small icon representing the action. 2373 */ 2374 public int icon; 2375 /** 2376 * Title of the action. 2377 */ 2378 public CharSequence title; 2379 /** 2380 * Intent to send when the user invokes this action. May be null, in which case the action 2381 * may be rendered in a disabled presentation. 2382 */ 2383 public PendingIntent actionIntent; 2384 2385 public Action(int icon, CharSequence title, PendingIntent intent) { 2386 this(icon, title, intent, new Bundle(), null, false); 2387 } 2388 2389 private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, 2390 RemoteInput[] remoteInputs, boolean allowGeneratedReplies) { 2391 this.icon = icon; 2392 this.title = NotificationCompat.Builder.limitCharSequenceLength(title); 2393 this.actionIntent = intent; 2394 this.mExtras = extras != null ? extras : new Bundle(); 2395 this.mRemoteInputs = remoteInputs; 2396 this.mAllowGeneratedReplies = allowGeneratedReplies; 2397 } 2398 2399 @Override 2400 public int getIcon() { 2401 return icon; 2402 } 2403 2404 @Override 2405 public CharSequence getTitle() { 2406 return title; 2407 } 2408 2409 @Override 2410 public PendingIntent getActionIntent() { 2411 return actionIntent; 2412 } 2413 2414 /** 2415 * Get additional metadata carried around with this Action. 2416 */ 2417 @Override 2418 public Bundle getExtras() { 2419 return mExtras; 2420 } 2421 2422 /** 2423 * Return whether the platform should automatically generate possible replies for this 2424 * {@link Action} 2425 */ 2426 @Override 2427 public boolean getAllowGeneratedReplies() { 2428 return mAllowGeneratedReplies; 2429 } 2430 2431 /** 2432 * Get the list of inputs to be collected from the user when this action is sent. 2433 * May return null if no remote inputs were added. 2434 */ 2435 @Override 2436 public RemoteInput[] getRemoteInputs() { 2437 return mRemoteInputs; 2438 } 2439 2440 /** 2441 * Builder class for {@link Action} objects. 2442 */ 2443 public static final class Builder { 2444 private final int mIcon; 2445 private final CharSequence mTitle; 2446 private final PendingIntent mIntent; 2447 private boolean mAllowGeneratedReplies; 2448 private final Bundle mExtras; 2449 private ArrayList<RemoteInput> mRemoteInputs; 2450 2451 /** 2452 * Construct a new builder for {@link Action} object. 2453 * @param icon icon to show for this action 2454 * @param title the title of the action 2455 * @param intent the {@link PendingIntent} to fire when users trigger this action 2456 */ 2457 public Builder(int icon, CharSequence title, PendingIntent intent) { 2458 this(icon, title, intent, new Bundle()); 2459 } 2460 2461 /** 2462 * Construct a new builder for {@link Action} object using the fields from an 2463 * {@link Action}. 2464 * @param action the action to read fields from. 2465 */ 2466 public Builder(Action action) { 2467 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras)); 2468 } 2469 2470 private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) { 2471 mIcon = icon; 2472 mTitle = NotificationCompat.Builder.limitCharSequenceLength(title); 2473 mIntent = intent; 2474 mExtras = extras; 2475 } 2476 2477 /** 2478 * Merge additional metadata into this builder. 2479 * 2480 * <p>Values within the Bundle will replace existing extras values in this Builder. 2481 * 2482 * @see NotificationCompat.Action#getExtras 2483 */ 2484 public Builder addExtras(Bundle extras) { 2485 if (extras != null) { 2486 mExtras.putAll(extras); 2487 } 2488 return this; 2489 } 2490 2491 /** 2492 * Get the metadata Bundle used by this Builder. 2493 * 2494 * <p>The returned Bundle is shared with this Builder. 2495 */ 2496 public Bundle getExtras() { 2497 return mExtras; 2498 } 2499 2500 /** 2501 * Add an input to be collected from the user when this action is sent. 2502 * Response values can be retrieved from the fired intent by using the 2503 * {@link RemoteInput#getResultsFromIntent} function. 2504 * @param remoteInput a {@link RemoteInput} to add to the action 2505 * @return this object for method chaining 2506 */ 2507 public Builder addRemoteInput(RemoteInput remoteInput) { 2508 if (mRemoteInputs == null) { 2509 mRemoteInputs = new ArrayList<RemoteInput>(); 2510 } 2511 mRemoteInputs.add(remoteInput); 2512 return this; 2513 } 2514 2515 /** 2516 * Set whether the platform should automatically generate possible replies to add to 2517 * {@link RemoteInput#getChoices()}. If the {@link Action} doesn't have a 2518 * {@link RemoteInput}, this has no effect. 2519 * @param allowGeneratedReplies {@code true} to allow generated replies, {@code false} 2520 * otherwise 2521 * @return this object for method chaining 2522 * The default value is {@code false} 2523 */ 2524 public Builder setAllowGeneratedReplies(boolean allowGeneratedReplies) { 2525 mAllowGeneratedReplies = allowGeneratedReplies; 2526 return this; 2527 } 2528 2529 /** 2530 * Apply an extender to this action builder. Extenders may be used to add 2531 * metadata or change options on this builder. 2532 */ 2533 public Builder extend(Extender extender) { 2534 extender.extend(this); 2535 return this; 2536 } 2537 2538 /** 2539 * Combine all of the options that have been set and return a new {@link Action} 2540 * object. 2541 * @return the built action 2542 */ 2543 public Action build() { 2544 RemoteInput[] remoteInputs = mRemoteInputs != null 2545 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; 2546 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs, 2547 mAllowGeneratedReplies); 2548 } 2549 } 2550 2551 2552 /** 2553 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 2554 * metadata or change options on an action builder. 2555 */ 2556 public interface Extender { 2557 /** 2558 * Apply this extender to a notification action builder. 2559 * @param builder the builder to be modified. 2560 * @return the build object for chaining. 2561 */ 2562 public Builder extend(Builder builder); 2563 } 2564 2565 /** 2566 * Wearable extender for notification actions. To add extensions to an action, 2567 * create a new {@link NotificationCompat.Action.WearableExtender} object using 2568 * the {@code WearableExtender()} constructor and apply it to a 2569 * {@link NotificationCompat.Action.Builder} using 2570 * {@link NotificationCompat.Action.Builder#extend}. 2571 * 2572 * <pre class="prettyprint"> 2573 * NotificationCompat.Action action = new NotificationCompat.Action.Builder( 2574 * R.drawable.archive_all, "Archive all", actionIntent) 2575 * .extend(new NotificationCompat.Action.WearableExtender() 2576 * .setAvailableOffline(false)) 2577 * .build();</pre> 2578 */ 2579 public static final class WearableExtender implements Extender { 2580 /** Notification action extra which contains wearable extensions */ 2581 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2582 2583 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 2584 private static final String KEY_FLAGS = "flags"; 2585 private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel"; 2586 private static final String KEY_CONFIRM_LABEL = "confirmLabel"; 2587 private static final String KEY_CANCEL_LABEL = "cancelLabel"; 2588 2589 // Flags bitwise-ored to mFlags 2590 private static final int FLAG_AVAILABLE_OFFLINE = 0x1; 2591 private static final int FLAG_HINT_LAUNCHES_ACTIVITY = 1 << 1; 2592 private static final int FLAG_HINT_DISPLAY_INLINE = 1 << 2; 2593 2594 // Default value for flags integer 2595 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE; 2596 2597 private int mFlags = DEFAULT_FLAGS; 2598 2599 private CharSequence mInProgressLabel; 2600 private CharSequence mConfirmLabel; 2601 private CharSequence mCancelLabel; 2602 2603 /** 2604 * Create a {@link NotificationCompat.Action.WearableExtender} with default 2605 * options. 2606 */ 2607 public WearableExtender() { 2608 } 2609 2610 /** 2611 * Create a {@link NotificationCompat.Action.WearableExtender} by reading 2612 * wearable options present in an existing notification action. 2613 * @param action the notification action to inspect. 2614 */ 2615 public WearableExtender(Action action) { 2616 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS); 2617 if (wearableBundle != null) { 2618 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 2619 mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL); 2620 mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL); 2621 mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL); 2622 } 2623 } 2624 2625 /** 2626 * Apply wearable extensions to a notification action that is being built. This is 2627 * typically called by the {@link NotificationCompat.Action.Builder#extend} 2628 * method of {@link NotificationCompat.Action.Builder}. 2629 */ 2630 @Override 2631 public Action.Builder extend(Action.Builder builder) { 2632 Bundle wearableBundle = new Bundle(); 2633 2634 if (mFlags != DEFAULT_FLAGS) { 2635 wearableBundle.putInt(KEY_FLAGS, mFlags); 2636 } 2637 if (mInProgressLabel != null) { 2638 wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel); 2639 } 2640 if (mConfirmLabel != null) { 2641 wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel); 2642 } 2643 if (mCancelLabel != null) { 2644 wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel); 2645 } 2646 2647 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 2648 return builder; 2649 } 2650 2651 @Override 2652 public WearableExtender clone() { 2653 WearableExtender that = new WearableExtender(); 2654 that.mFlags = this.mFlags; 2655 that.mInProgressLabel = this.mInProgressLabel; 2656 that.mConfirmLabel = this.mConfirmLabel; 2657 that.mCancelLabel = this.mCancelLabel; 2658 return that; 2659 } 2660 2661 /** 2662 * Set whether this action is available when the wearable device is not connected to 2663 * a companion device. The user can still trigger this action when the wearable device 2664 * is offline, but a visual hint will indicate that the action may not be available. 2665 * Defaults to true. 2666 */ 2667 public WearableExtender setAvailableOffline(boolean availableOffline) { 2668 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline); 2669 return this; 2670 } 2671 2672 /** 2673 * Get whether this action is available when the wearable device is not connected to 2674 * a companion device. The user can still trigger this action when the wearable device 2675 * is offline, but a visual hint will indicate that the action may not be available. 2676 * Defaults to true. 2677 */ 2678 public boolean isAvailableOffline() { 2679 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0; 2680 } 2681 2682 private void setFlag(int mask, boolean value) { 2683 if (value) { 2684 mFlags |= mask; 2685 } else { 2686 mFlags &= ~mask; 2687 } 2688 } 2689 2690 /** 2691 * Set a label to display while the wearable is preparing to automatically execute the 2692 * action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2693 * 2694 * @param label the label to display while the action is being prepared to execute 2695 * @return this object for method chaining 2696 */ 2697 public WearableExtender setInProgressLabel(CharSequence label) { 2698 mInProgressLabel = label; 2699 return this; 2700 } 2701 2702 /** 2703 * Get the label to display while the wearable is preparing to automatically execute 2704 * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2705 * 2706 * @return the label to display while the action is being prepared to execute 2707 */ 2708 public CharSequence getInProgressLabel() { 2709 return mInProgressLabel; 2710 } 2711 2712 /** 2713 * Set a label to display to confirm that the action should be executed. 2714 * This is usually an imperative verb like "Send". 2715 * 2716 * @param label the label to confirm the action should be executed 2717 * @return this object for method chaining 2718 */ 2719 public WearableExtender setConfirmLabel(CharSequence label) { 2720 mConfirmLabel = label; 2721 return this; 2722 } 2723 2724 /** 2725 * Get the label to display to confirm that the action should be executed. 2726 * This is usually an imperative verb like "Send". 2727 * 2728 * @return the label to confirm the action should be executed 2729 */ 2730 public CharSequence getConfirmLabel() { 2731 return mConfirmLabel; 2732 } 2733 2734 /** 2735 * Set a label to display to cancel the action. 2736 * This is usually an imperative verb, like "Cancel". 2737 * 2738 * @param label the label to display to cancel the action 2739 * @return this object for method chaining 2740 */ 2741 public WearableExtender setCancelLabel(CharSequence label) { 2742 mCancelLabel = label; 2743 return this; 2744 } 2745 2746 /** 2747 * Get the label to display to cancel the action. 2748 * This is usually an imperative verb like "Cancel". 2749 * 2750 * @return the label to display to cancel the action 2751 */ 2752 public CharSequence getCancelLabel() { 2753 return mCancelLabel; 2754 } 2755 2756 /** 2757 * Set a hint that this Action will launch an {@link Activity} directly, telling the 2758 * platform that it can generate the appropriate transitions. 2759 * @param hintLaunchesActivity {@code true} if the content intent will launch 2760 * an activity and transitions should be generated, false otherwise. 2761 * @return this object for method chaining 2762 */ 2763 public WearableExtender setHintLaunchesActivity( 2764 boolean hintLaunchesActivity) { 2765 setFlag(FLAG_HINT_LAUNCHES_ACTIVITY, hintLaunchesActivity); 2766 return this; 2767 } 2768 2769 /** 2770 * Get a hint that this Action will launch an {@link Activity} directly, telling the 2771 * platform that it can generate the appropriate transitions 2772 * @return {@code true} if the content intent will launch an activity and transitions 2773 * should be generated, false otherwise. The default value is {@code false} if this was 2774 * never set. 2775 */ 2776 public boolean getHintLaunchesActivity() { 2777 return (mFlags & FLAG_HINT_LAUNCHES_ACTIVITY) != 0; 2778 } 2779 2780 /** 2781 * Set a hint that this Action should be displayed inline - i.e. it will have a visual 2782 * representation directly on the notification surface in addition to the expanded 2783 * Notification 2784 * 2785 * @param hintDisplayInline {@code true} if action should be displayed inline, false 2786 * otherwise 2787 * @return this object for method chaining 2788 */ 2789 public WearableExtender setHintDisplayActionInline( 2790 boolean hintDisplayInline) { 2791 setFlag(FLAG_HINT_DISPLAY_INLINE, hintDisplayInline); 2792 return this; 2793 } 2794 2795 /** 2796 * Get a hint that this Action should be displayed inline - i.e. it should have a 2797 * visual representation directly on the notification surface in addition to the 2798 * expanded Notification 2799 * 2800 * @return {@code true} if the Action should be displayed inline, {@code false} 2801 * otherwise. The default value is {@code false} if this was never set. 2802 */ 2803 public boolean getHintDisplayActionInline() { 2804 return (mFlags & FLAG_HINT_DISPLAY_INLINE) != 0; 2805 } 2806 } 2807 2808 /** @hide */ 2809 public static final Factory FACTORY = new Factory() { 2810 @Override 2811 public NotificationCompatBase.Action build(int icon, CharSequence title, 2812 PendingIntent actionIntent, Bundle extras, 2813 RemoteInputCompatBase.RemoteInput[] remoteInputs, 2814 boolean allowGeneratedReplies) { 2815 return new Action(icon, title, actionIntent, extras, 2816 (RemoteInput[]) remoteInputs, allowGeneratedReplies); 2817 } 2818 2819 @Override 2820 public Action[] newArray(int length) { 2821 return new Action[length]; 2822 } 2823 }; 2824 } 2825 2826 2827 /** 2828 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 2829 * metadata or change options on a notification builder. 2830 */ 2831 public interface Extender { 2832 /** 2833 * Apply this extender to a notification builder. 2834 * @param builder the builder to be modified. 2835 * @return the build object for chaining. 2836 */ 2837 public Builder extend(Builder builder); 2838 } 2839 2840 /** 2841 * Helper class to add wearable extensions to notifications. 2842 * <p class="note"> See 2843 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications 2844 * for Android Wear</a> for more information on how to use this class. 2845 * <p> 2846 * To create a notification with wearable extensions: 2847 * <ol> 2848 * <li>Create a {@link NotificationCompat.Builder}, setting any desired 2849 * properties. 2850 * <li>Create a {@link NotificationCompat.WearableExtender}. 2851 * <li>Set wearable-specific properties using the 2852 * {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}. 2853 * <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a 2854 * notification. 2855 * <li>Post the notification to the notification 2856 * system with the {@code NotificationManagerCompat.notify(...)} methods 2857 * and not the {@code NotificationManager.notify(...)} methods. 2858 * </ol> 2859 * 2860 * <pre class="prettyprint"> 2861 * Notification notif = new NotificationCompat.Builder(mContext) 2862 * .setContentTitle("New mail from " + sender.toString()) 2863 * .setContentText(subject) 2864 * .setSmallIcon(R.drawable.new_mail) 2865 * .extend(new NotificationCompat.WearableExtender() 2866 * .setContentIcon(R.drawable.new_mail)) 2867 * .build(); 2868 * NotificationManagerCompat.from(mContext).notify(0, notif);</pre> 2869 * 2870 * <p>Wearable extensions can be accessed on an existing notification by using the 2871 * {@code WearableExtender(Notification)} constructor, 2872 * and then using the {@code get} methods to access values. 2873 * 2874 * <pre class="prettyprint"> 2875 * NotificationCompat.WearableExtender wearableExtender = 2876 * new NotificationCompat.WearableExtender(notification); 2877 * List<Notification> pages = wearableExtender.getPages();</pre> 2878 */ 2879 public static final class WearableExtender implements Extender { 2880 /** 2881 * Sentinel value for an action index that is unset. 2882 */ 2883 public static final int UNSET_ACTION_INDEX = -1; 2884 2885 /** 2886 * Size value for use with {@link #setCustomSizePreset} to show this notification with 2887 * default sizing. 2888 * <p>For custom display notifications created using {@link #setDisplayIntent}, 2889 * the default is {@link #SIZE_MEDIUM}. All other notifications size automatically based 2890 * on their content. 2891 */ 2892 public static final int SIZE_DEFAULT = 0; 2893 2894 /** 2895 * Size value for use with {@link #setCustomSizePreset} to show this notification 2896 * with an extra small size. 2897 * <p>This value is only applicable for custom display notifications created using 2898 * {@link #setDisplayIntent}. 2899 */ 2900 public static final int SIZE_XSMALL = 1; 2901 2902 /** 2903 * Size value for use with {@link #setCustomSizePreset} to show this notification 2904 * with a small size. 2905 * <p>This value is only applicable for custom display notifications created using 2906 * {@link #setDisplayIntent}. 2907 */ 2908 public static final int SIZE_SMALL = 2; 2909 2910 /** 2911 * Size value for use with {@link #setCustomSizePreset} to show this notification 2912 * with a medium size. 2913 * <p>This value is only applicable for custom display notifications created using 2914 * {@link #setDisplayIntent}. 2915 */ 2916 public static final int SIZE_MEDIUM = 3; 2917 2918 /** 2919 * Size value for use with {@link #setCustomSizePreset} to show this notification 2920 * with a large size. 2921 * <p>This value is only applicable for custom display notifications created using 2922 * {@link #setDisplayIntent}. 2923 */ 2924 public static final int SIZE_LARGE = 4; 2925 2926 /** 2927 * Size value for use with {@link #setCustomSizePreset} to show this notification 2928 * full screen. 2929 * <p>This value is only applicable for custom display notifications created using 2930 * {@link #setDisplayIntent}. 2931 */ 2932 public static final int SIZE_FULL_SCREEN = 5; 2933 2934 /** 2935 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a 2936 * short amount of time when this notification is displayed on the screen. This 2937 * is the default value. 2938 */ 2939 public static final int SCREEN_TIMEOUT_SHORT = 0; 2940 2941 /** 2942 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on 2943 * for a longer amount of time when this notification is displayed on the screen. 2944 */ 2945 public static final int SCREEN_TIMEOUT_LONG = -1; 2946 2947 /** Notification extra which contains wearable extensions */ 2948 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2949 2950 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 2951 private static final String KEY_ACTIONS = "actions"; 2952 private static final String KEY_FLAGS = "flags"; 2953 private static final String KEY_DISPLAY_INTENT = "displayIntent"; 2954 private static final String KEY_PAGES = "pages"; 2955 private static final String KEY_BACKGROUND = "background"; 2956 private static final String KEY_CONTENT_ICON = "contentIcon"; 2957 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity"; 2958 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex"; 2959 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset"; 2960 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; 2961 private static final String KEY_GRAVITY = "gravity"; 2962 private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout"; 2963 private static final String KEY_DISMISSAL_ID = "dismissalId"; 2964 2965 // Flags bitwise-ored to mFlags 2966 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; 2967 private static final int FLAG_HINT_HIDE_ICON = 1 << 1; 2968 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2; 2969 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3; 2970 private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4; 2971 private static final int FLAG_BIG_PICTURE_AMBIENT = 1 << 5; 2972 private static final int FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY = 1 << 6; 2973 2974 // Default value for flags integer 2975 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE; 2976 2977 private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END; 2978 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM; 2979 2980 private ArrayList<Action> mActions = new ArrayList<Action>(); 2981 private int mFlags = DEFAULT_FLAGS; 2982 private PendingIntent mDisplayIntent; 2983 private ArrayList<Notification> mPages = new ArrayList<Notification>(); 2984 private Bitmap mBackground; 2985 private int mContentIcon; 2986 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY; 2987 private int mContentActionIndex = UNSET_ACTION_INDEX; 2988 private int mCustomSizePreset = SIZE_DEFAULT; 2989 private int mCustomContentHeight; 2990 private int mGravity = DEFAULT_GRAVITY; 2991 private int mHintScreenTimeout; 2992 private String mDismissalId; 2993 2994 /** 2995 * Create a {@link NotificationCompat.WearableExtender} with default 2996 * options. 2997 */ 2998 public WearableExtender() { 2999 } 3000 3001 public WearableExtender(Notification notif) { 3002 Bundle extras = getExtras(notif); 3003 Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS) 3004 : null; 3005 if (wearableBundle != null) { 3006 Action[] actions = IMPL.getActionsFromParcelableArrayList( 3007 wearableBundle.getParcelableArrayList(KEY_ACTIONS)); 3008 if (actions != null) { 3009 Collections.addAll(mActions, actions); 3010 } 3011 3012 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 3013 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); 3014 3015 Notification[] pages = getNotificationArrayFromBundle( 3016 wearableBundle, KEY_PAGES); 3017 if (pages != null) { 3018 Collections.addAll(mPages, pages); 3019 } 3020 3021 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND); 3022 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON); 3023 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY, 3024 DEFAULT_CONTENT_ICON_GRAVITY); 3025 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX, 3026 UNSET_ACTION_INDEX); 3027 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET, 3028 SIZE_DEFAULT); 3029 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); 3030 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); 3031 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT); 3032 mDismissalId = wearableBundle.getString(KEY_DISMISSAL_ID); 3033 } 3034 } 3035 3036 /** 3037 * Apply wearable extensions to a notification that is being built. This is typically 3038 * called by the {@link NotificationCompat.Builder#extend} method of 3039 * {@link NotificationCompat.Builder}. 3040 */ 3041 @Override 3042 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 3043 Bundle wearableBundle = new Bundle(); 3044 3045 if (!mActions.isEmpty()) { 3046 wearableBundle.putParcelableArrayList(KEY_ACTIONS, 3047 IMPL.getParcelableArrayListForActions(mActions.toArray( 3048 new Action[mActions.size()]))); 3049 } 3050 if (mFlags != DEFAULT_FLAGS) { 3051 wearableBundle.putInt(KEY_FLAGS, mFlags); 3052 } 3053 if (mDisplayIntent != null) { 3054 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent); 3055 } 3056 if (!mPages.isEmpty()) { 3057 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( 3058 new Notification[mPages.size()])); 3059 } 3060 if (mBackground != null) { 3061 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); 3062 } 3063 if (mContentIcon != 0) { 3064 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); 3065 } 3066 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) { 3067 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity); 3068 } 3069 if (mContentActionIndex != UNSET_ACTION_INDEX) { 3070 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX, 3071 mContentActionIndex); 3072 } 3073 if (mCustomSizePreset != SIZE_DEFAULT) { 3074 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset); 3075 } 3076 if (mCustomContentHeight != 0) { 3077 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight); 3078 } 3079 if (mGravity != DEFAULT_GRAVITY) { 3080 wearableBundle.putInt(KEY_GRAVITY, mGravity); 3081 } 3082 if (mHintScreenTimeout != 0) { 3083 wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout); 3084 } 3085 if (mDismissalId != null) { 3086 wearableBundle.putString(KEY_DISMISSAL_ID, mDismissalId); 3087 } 3088 3089 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 3090 return builder; 3091 } 3092 3093 @Override 3094 public WearableExtender clone() { 3095 WearableExtender that = new WearableExtender(); 3096 that.mActions = new ArrayList<Action>(this.mActions); 3097 that.mFlags = this.mFlags; 3098 that.mDisplayIntent = this.mDisplayIntent; 3099 that.mPages = new ArrayList<Notification>(this.mPages); 3100 that.mBackground = this.mBackground; 3101 that.mContentIcon = this.mContentIcon; 3102 that.mContentIconGravity = this.mContentIconGravity; 3103 that.mContentActionIndex = this.mContentActionIndex; 3104 that.mCustomSizePreset = this.mCustomSizePreset; 3105 that.mCustomContentHeight = this.mCustomContentHeight; 3106 that.mGravity = this.mGravity; 3107 that.mHintScreenTimeout = this.mHintScreenTimeout; 3108 that.mDismissalId = this.mDismissalId; 3109 return that; 3110 } 3111 3112 /** 3113 * Add a wearable action to this notification. 3114 * 3115 * <p>When wearable actions are added using this method, the set of actions that 3116 * show on a wearable device splits from devices that only show actions added 3117 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 3118 * of which actions display on different devices. 3119 * 3120 * @param action the action to add to this notification 3121 * @return this object for method chaining 3122 * @see NotificationCompat.Action 3123 */ 3124 public WearableExtender addAction(Action action) { 3125 mActions.add(action); 3126 return this; 3127 } 3128 3129 /** 3130 * Adds wearable actions to this notification. 3131 * 3132 * <p>When wearable actions are added using this method, the set of actions that 3133 * show on a wearable device splits from devices that only show actions added 3134 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 3135 * of which actions display on different devices. 3136 * 3137 * @param actions the actions to add to this notification 3138 * @return this object for method chaining 3139 * @see NotificationCompat.Action 3140 */ 3141 public WearableExtender addActions(List<Action> actions) { 3142 mActions.addAll(actions); 3143 return this; 3144 } 3145 3146 /** 3147 * Clear all wearable actions present on this builder. 3148 * @return this object for method chaining. 3149 * @see #addAction 3150 */ 3151 public WearableExtender clearActions() { 3152 mActions.clear(); 3153 return this; 3154 } 3155 3156 /** 3157 * Get the wearable actions present on this notification. 3158 */ 3159 public List<Action> getActions() { 3160 return mActions; 3161 } 3162 3163 /** 3164 * Set an intent to launch inside of an activity view when displaying 3165 * this notification. The {@link PendingIntent} provided should be for an activity. 3166 * 3167 * <pre class="prettyprint"> 3168 * Intent displayIntent = new Intent(context, MyDisplayActivity.class); 3169 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context, 3170 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT); 3171 * Notification notif = new NotificationCompat.Builder(context) 3172 * .extend(new NotificationCompat.WearableExtender() 3173 * .setDisplayIntent(displayPendingIntent) 3174 * .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM)) 3175 * .build();</pre> 3176 * 3177 * <p>The activity to launch needs to allow embedding, must be exported, and 3178 * should have an empty task affinity. It is also recommended to use the device 3179 * default light theme. 3180 * 3181 * <p>Example AndroidManifest.xml entry: 3182 * <pre class="prettyprint"> 3183 * <activity android:name="com.example.MyDisplayActivity" 3184 * android:exported="true" 3185 * android:allowEmbedded="true" 3186 * android:taskAffinity="" 3187 * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre> 3188 * 3189 * @param intent the {@link PendingIntent} for an activity 3190 * @return this object for method chaining 3191 * @see NotificationCompat.WearableExtender#getDisplayIntent 3192 */ 3193 public WearableExtender setDisplayIntent(PendingIntent intent) { 3194 mDisplayIntent = intent; 3195 return this; 3196 } 3197 3198 /** 3199 * Get the intent to launch inside of an activity view when displaying this 3200 * notification. This {@code PendingIntent} should be for an activity. 3201 */ 3202 public PendingIntent getDisplayIntent() { 3203 return mDisplayIntent; 3204 } 3205 3206 /** 3207 * Add an additional page of content to display with this notification. The current 3208 * notification forms the first page, and pages added using this function form 3209 * subsequent pages. This field can be used to separate a notification into multiple 3210 * sections. 3211 * 3212 * @param page the notification to add as another page 3213 * @return this object for method chaining 3214 * @see NotificationCompat.WearableExtender#getPages 3215 */ 3216 public WearableExtender addPage(Notification page) { 3217 mPages.add(page); 3218 return this; 3219 } 3220 3221 /** 3222 * Add additional pages of content to display with this notification. The current 3223 * notification forms the first page, and pages added using this function form 3224 * subsequent pages. This field can be used to separate a notification into multiple 3225 * sections. 3226 * 3227 * @param pages a list of notifications 3228 * @return this object for method chaining 3229 * @see NotificationCompat.WearableExtender#getPages 3230 */ 3231 public WearableExtender addPages(List<Notification> pages) { 3232 mPages.addAll(pages); 3233 return this; 3234 } 3235 3236 /** 3237 * Clear all additional pages present on this builder. 3238 * @return this object for method chaining. 3239 * @see #addPage 3240 */ 3241 public WearableExtender clearPages() { 3242 mPages.clear(); 3243 return this; 3244 } 3245 3246 /** 3247 * Get the array of additional pages of content for displaying this notification. The 3248 * current notification forms the first page, and elements within this array form 3249 * subsequent pages. This field can be used to separate a notification into multiple 3250 * sections. 3251 * @return the pages for this notification 3252 */ 3253 public List<Notification> getPages() { 3254 return mPages; 3255 } 3256 3257 /** 3258 * Set a background image to be displayed behind the notification content. 3259 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 3260 * will work with any notification style. 3261 * 3262 * @param background the background bitmap 3263 * @return this object for method chaining 3264 * @see NotificationCompat.WearableExtender#getBackground 3265 */ 3266 public WearableExtender setBackground(Bitmap background) { 3267 mBackground = background; 3268 return this; 3269 } 3270 3271 /** 3272 * Get a background image to be displayed behind the notification content. 3273 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 3274 * will work with any notification style. 3275 * 3276 * @return the background image 3277 * @see NotificationCompat.WearableExtender#setBackground 3278 */ 3279 public Bitmap getBackground() { 3280 return mBackground; 3281 } 3282 3283 /** 3284 * Set an icon that goes with the content of this notification. 3285 */ 3286 public WearableExtender setContentIcon(int icon) { 3287 mContentIcon = icon; 3288 return this; 3289 } 3290 3291 /** 3292 * Get an icon that goes with the content of this notification. 3293 */ 3294 public int getContentIcon() { 3295 return mContentIcon; 3296 } 3297 3298 /** 3299 * Set the gravity that the content icon should have within the notification display. 3300 * Supported values include {@link android.view.Gravity#START} and 3301 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 3302 * @see #setContentIcon 3303 */ 3304 public WearableExtender setContentIconGravity(int contentIconGravity) { 3305 mContentIconGravity = contentIconGravity; 3306 return this; 3307 } 3308 3309 /** 3310 * Get the gravity that the content icon should have within the notification display. 3311 * Supported values include {@link android.view.Gravity#START} and 3312 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 3313 * @see #getContentIcon 3314 */ 3315 public int getContentIconGravity() { 3316 return mContentIconGravity; 3317 } 3318 3319 /** 3320 * Set an action from this notification's actions to be clickable with the content of 3321 * this notification. This action will no longer display separately from the 3322 * notification's content. 3323 * 3324 * <p>For notifications with multiple pages, child pages can also have content actions 3325 * set, although the list of available actions comes from the main notification and not 3326 * from the child page's notification. 3327 * 3328 * @param actionIndex The index of the action to hoist onto the current notification page. 3329 * If wearable actions were added to the main notification, this index 3330 * will apply to that list, otherwise it will apply to the regular 3331 * actions list. 3332 */ 3333 public WearableExtender setContentAction(int actionIndex) { 3334 mContentActionIndex = actionIndex; 3335 return this; 3336 } 3337 3338 /** 3339 * Get the index of the notification action, if any, that was specified as being clickable 3340 * with the content of this notification. This action will no longer display separately 3341 * from the notification's content. 3342 * 3343 * <p>For notifications with multiple pages, child pages can also have content actions 3344 * set, although the list of available actions comes from the main notification and not 3345 * from the child page's notification. 3346 * 3347 * <p>If wearable specific actions were added to the main notification, this index will 3348 * apply to that list, otherwise it will apply to the regular actions list. 3349 * 3350 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected. 3351 */ 3352 public int getContentAction() { 3353 return mContentActionIndex; 3354 } 3355 3356 /** 3357 * Set the gravity that this notification should have within the available viewport space. 3358 * Supported values include {@link android.view.Gravity#TOP}, 3359 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 3360 * The default value is {@link android.view.Gravity#BOTTOM}. 3361 */ 3362 public WearableExtender setGravity(int gravity) { 3363 mGravity = gravity; 3364 return this; 3365 } 3366 3367 /** 3368 * Get the gravity that this notification should have within the available viewport space. 3369 * Supported values include {@link android.view.Gravity#TOP}, 3370 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 3371 * The default value is {@link android.view.Gravity#BOTTOM}. 3372 */ 3373 public int getGravity() { 3374 return mGravity; 3375 } 3376 3377 /** 3378 * Set the custom size preset for the display of this notification out of the available 3379 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 3380 * {@link #SIZE_LARGE}. 3381 * <p>Some custom size presets are only applicable for custom display notifications created 3382 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the 3383 * documentation for the preset in question. See also 3384 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}. 3385 */ 3386 public WearableExtender setCustomSizePreset(int sizePreset) { 3387 mCustomSizePreset = sizePreset; 3388 return this; 3389 } 3390 3391 /** 3392 * Get the custom size preset for the display of this notification out of the available 3393 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 3394 * {@link #SIZE_LARGE}. 3395 * <p>Some custom size presets are only applicable for custom display notifications created 3396 * using {@link #setDisplayIntent}. Check the documentation for the preset in question. 3397 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}. 3398 */ 3399 public int getCustomSizePreset() { 3400 return mCustomSizePreset; 3401 } 3402 3403 /** 3404 * Set the custom height in pixels for the display of this notification's content. 3405 * <p>This option is only available for custom display notifications created 3406 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also 3407 * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and 3408 * {@link #getCustomContentHeight}. 3409 */ 3410 public WearableExtender setCustomContentHeight(int height) { 3411 mCustomContentHeight = height; 3412 return this; 3413 } 3414 3415 /** 3416 * Get the custom height in pixels for the display of this notification's content. 3417 * <p>This option is only available for custom display notifications created 3418 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and 3419 * {@link #setCustomContentHeight}. 3420 */ 3421 public int getCustomContentHeight() { 3422 return mCustomContentHeight; 3423 } 3424 3425 /** 3426 * Set whether the scrolling position for the contents of this notification should start 3427 * at the bottom of the contents instead of the top when the contents are too long to 3428 * display within the screen. Default is false (start scroll at the top). 3429 */ 3430 public WearableExtender setStartScrollBottom(boolean startScrollBottom) { 3431 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom); 3432 return this; 3433 } 3434 3435 /** 3436 * Get whether the scrolling position for the contents of this notification should start 3437 * at the bottom of the contents instead of the top when the contents are too long to 3438 * display within the screen. Default is false (start scroll at the top). 3439 */ 3440 public boolean getStartScrollBottom() { 3441 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0; 3442 } 3443 3444 /** 3445 * Set whether the content intent is available when the wearable device is not connected 3446 * to a companion device. The user can still trigger this intent when the wearable device 3447 * is offline, but a visual hint will indicate that the content intent may not be available. 3448 * Defaults to true. 3449 */ 3450 public WearableExtender setContentIntentAvailableOffline( 3451 boolean contentIntentAvailableOffline) { 3452 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline); 3453 return this; 3454 } 3455 3456 /** 3457 * Get whether the content intent is available when the wearable device is not connected 3458 * to a companion device. The user can still trigger this intent when the wearable device 3459 * is offline, but a visual hint will indicate that the content intent may not be available. 3460 * Defaults to true. 3461 */ 3462 public boolean getContentIntentAvailableOffline() { 3463 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0; 3464 } 3465 3466 /** 3467 * Set a hint that this notification's icon should not be displayed. 3468 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise. 3469 * @return this object for method chaining 3470 */ 3471 public WearableExtender setHintHideIcon(boolean hintHideIcon) { 3472 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon); 3473 return this; 3474 } 3475 3476 /** 3477 * Get a hint that this notification's icon should not be displayed. 3478 * @return {@code true} if this icon should not be displayed, false otherwise. 3479 * The default value is {@code false} if this was never set. 3480 */ 3481 public boolean getHintHideIcon() { 3482 return (mFlags & FLAG_HINT_HIDE_ICON) != 0; 3483 } 3484 3485 /** 3486 * Set a visual hint that only the background image of this notification should be 3487 * displayed, and other semantic content should be hidden. This hint is only applicable 3488 * to sub-pages added using {@link #addPage}. 3489 */ 3490 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) { 3491 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly); 3492 return this; 3493 } 3494 3495 /** 3496 * Get a visual hint that only the background image of this notification should be 3497 * displayed, and other semantic content should be hidden. This hint is only applicable 3498 * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}. 3499 */ 3500 public boolean getHintShowBackgroundOnly() { 3501 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0; 3502 } 3503 3504 /** 3505 * Set a hint that this notification's background should not be clipped if possible, 3506 * and should instead be resized to fully display on the screen, retaining the aspect 3507 * ratio of the image. This can be useful for images like barcodes or qr codes. 3508 * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible. 3509 * @return this object for method chaining 3510 */ 3511 public WearableExtender setHintAvoidBackgroundClipping( 3512 boolean hintAvoidBackgroundClipping) { 3513 setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping); 3514 return this; 3515 } 3516 3517 /** 3518 * Get a hint that this notification's background should not be clipped if possible, 3519 * and should instead be resized to fully display on the screen, retaining the aspect 3520 * ratio of the image. This can be useful for images like barcodes or qr codes. 3521 * @return {@code true} if it's ok if the background is clipped on the screen, false 3522 * otherwise. The default value is {@code false} if this was never set. 3523 */ 3524 public boolean getHintAvoidBackgroundClipping() { 3525 return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0; 3526 } 3527 3528 /** 3529 * Set a hint that the screen should remain on for at least this duration when 3530 * this notification is displayed on the screen. 3531 * @param timeout The requested screen timeout in milliseconds. Can also be either 3532 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 3533 * @return this object for method chaining 3534 */ 3535 public WearableExtender setHintScreenTimeout(int timeout) { 3536 mHintScreenTimeout = timeout; 3537 return this; 3538 } 3539 3540 /** 3541 * Get the duration, in milliseconds, that the screen should remain on for 3542 * when this notification is displayed. 3543 * @return the duration in milliseconds if > 0, or either one of the sentinel values 3544 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 3545 */ 3546 public int getHintScreenTimeout() { 3547 return mHintScreenTimeout; 3548 } 3549 3550 /** 3551 * Set a hint that this notification's {@link BigPictureStyle} (if present) should be 3552 * converted to low-bit and displayed in ambient mode, especially useful for barcodes and 3553 * qr codes, as well as other simple black-and-white tickets. 3554 * @param hintAmbientBigPicture {@code true} to enable converstion and ambient. 3555 * @return this object for method chaining 3556 */ 3557 public WearableExtender setHintAmbientBigPicture(boolean hintAmbientBigPicture) { 3558 setFlag(FLAG_BIG_PICTURE_AMBIENT, hintAmbientBigPicture); 3559 return this; 3560 } 3561 3562 /** 3563 * Get a hint that this notification's {@link BigPictureStyle} (if present) should be 3564 * converted to low-bit and displayed in ambient mode, especially useful for barcodes and 3565 * qr codes, as well as other simple black-and-white tickets. 3566 * @return {@code true} if it should be displayed in ambient, false otherwise 3567 * otherwise. The default value is {@code false} if this was never set. 3568 */ 3569 public boolean getHintAmbientBigPicture() { 3570 return (mFlags & FLAG_BIG_PICTURE_AMBIENT) != 0; 3571 } 3572 3573 /** 3574 * Set a hint that this notification's content intent will launch an {@link Activity} 3575 * directly, telling the platform that it can generate the appropriate transitions. 3576 * @param hintContentIntentLaunchesActivity {@code true} if the content intent will launch 3577 * an activity and transitions should be generated, false otherwise. 3578 * @return this object for method chaining 3579 */ 3580 public WearableExtender setHintContentIntentLaunchesActivity( 3581 boolean hintContentIntentLaunchesActivity) { 3582 setFlag(FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY, hintContentIntentLaunchesActivity); 3583 return this; 3584 } 3585 3586 /** 3587 * Get a hint that this notification's content intent will launch an {@link Activity} 3588 * directly, telling the platform that it can generate the appropriate transitions 3589 * @return {@code true} if the content intent will launch an activity and transitions should 3590 * be generated, false otherwise. The default value is {@code false} if this was never set. 3591 */ 3592 public boolean getHintContentIntentLaunchesActivity() { 3593 return (mFlags & FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY) != 0; 3594 } 3595 3596 /** 3597 * When you post a notification, if you set the dismissal id field, then when that 3598 * notification is canceled, notifications on other wearables and the paired Android phone 3599 * having that same dismissal id will also be canceled. Note that this only works if you 3600 * have notification bridge mode set to NO_BRIDGING in your Wear app manifest. See 3601 * <a href="{@docRoot}wear/notifications/index.html">Adding Wearable Features to 3602 * Notifications</a> for more information on how to use the bridge mode feature. 3603 * @param dismissalId the dismissal id of the notification. 3604 * @return this object for method chaining 3605 */ 3606 public WearableExtender setDismissalId(String dismissalId) { 3607 mDismissalId = dismissalId; 3608 return this; 3609 } 3610 3611 /** 3612 * Returns the dismissal id of the notification. 3613 * @return the dismissal id of the notification or null if it has not been set. 3614 */ 3615 public String getDismissalId() { 3616 return mDismissalId; 3617 } 3618 3619 private void setFlag(int mask, boolean value) { 3620 if (value) { 3621 mFlags |= mask; 3622 } else { 3623 mFlags &= ~mask; 3624 } 3625 } 3626 } 3627 3628 /** 3629 * <p>Helper class to add Android Auto extensions to notifications. To create a notification 3630 * with car extensions: 3631 * 3632 * <ol> 3633 * <li>Create an {@link NotificationCompat.Builder}, setting any desired 3634 * properties. 3635 * <li>Create a {@link CarExtender}. 3636 * <li>Set car-specific properties using the {@code add} and {@code set} methods of 3637 * {@link CarExtender}. 3638 * <li>Call {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)} 3639 * to apply the extensions to a notification. 3640 * <li>Post the notification to the notification system with the 3641 * {@code NotificationManagerCompat.notify(...)} methods and not the 3642 * {@code NotificationManager.notify(...)} methods. 3643 * </ol> 3644 * 3645 * <pre class="prettyprint"> 3646 * Notification notification = new NotificationCompat.Builder(context) 3647 * ... 3648 * .extend(new CarExtender() 3649 * .set*(...)) 3650 * .build(); 3651 * </pre> 3652 * 3653 * <p>Car extensions can be accessed on an existing notification by using the 3654 * {@code CarExtender(Notification)} constructor, and then using the {@code get} methods 3655 * to access values. 3656 */ 3657 public static final class CarExtender implements Extender { 3658 private static final String TAG = "CarExtender"; 3659 3660 private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS"; 3661 private static final String EXTRA_LARGE_ICON = "large_icon"; 3662 private static final String EXTRA_CONVERSATION = "car_conversation"; 3663 private static final String EXTRA_COLOR = "app_color"; 3664 3665 private Bitmap mLargeIcon; 3666 private UnreadConversation mUnreadConversation; 3667 private int mColor = NotificationCompat.COLOR_DEFAULT; 3668 3669 /** 3670 * Create a {@link CarExtender} with default options. 3671 */ 3672 public CarExtender() { 3673 } 3674 3675 /** 3676 * Create a {@link CarExtender} from the CarExtender options of an existing Notification. 3677 * 3678 * @param notif The notification from which to copy options. 3679 */ 3680 public CarExtender(Notification notif) { 3681 if (Build.VERSION.SDK_INT < 21) { 3682 return; 3683 } 3684 3685 Bundle carBundle = getExtras(notif)==null ? 3686 null : getExtras(notif).getBundle(EXTRA_CAR_EXTENDER); 3687 if (carBundle != null) { 3688 mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON); 3689 mColor = carBundle.getInt(EXTRA_COLOR, NotificationCompat.COLOR_DEFAULT); 3690 3691 Bundle b = carBundle.getBundle(EXTRA_CONVERSATION); 3692 mUnreadConversation = (UnreadConversation) IMPL.getUnreadConversationFromBundle( 3693 b, UnreadConversation.FACTORY, RemoteInput.FACTORY); 3694 } 3695 } 3696 3697 /** 3698 * Apply car extensions to a notification that is being built. This is typically called by 3699 * the {@link android.support.v4.app.NotificationCompat.Builder#extend(NotificationCompat.Extender)} 3700 * method of {@link NotificationCompat.Builder}. 3701 */ 3702 @Override 3703 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 3704 if (Build.VERSION.SDK_INT < 21) { 3705 return builder; 3706 } 3707 3708 Bundle carExtensions = new Bundle(); 3709 3710 if (mLargeIcon != null) { 3711 carExtensions.putParcelable(EXTRA_LARGE_ICON, mLargeIcon); 3712 } 3713 if (mColor != NotificationCompat.COLOR_DEFAULT) { 3714 carExtensions.putInt(EXTRA_COLOR, mColor); 3715 } 3716 3717 if (mUnreadConversation != null) { 3718 Bundle b = IMPL.getBundleForUnreadConversation(mUnreadConversation); 3719 carExtensions.putBundle(EXTRA_CONVERSATION, b); 3720 } 3721 3722 builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, carExtensions); 3723 return builder; 3724 } 3725 3726 /** 3727 * Sets the accent color to use when Android Auto presents the notification. 3728 * 3729 * Android Auto uses the color set with {@link android.support.v4.app.NotificationCompat.Builder#setColor(int)} 3730 * to accent the displayed notification. However, not all colors are acceptable in an 3731 * automotive setting. This method can be used to override the color provided in the 3732 * notification in such a situation. 3733 */ 3734 public CarExtender setColor(@ColorInt int color) { 3735 mColor = color; 3736 return this; 3737 } 3738 3739 /** 3740 * Gets the accent color. 3741 * 3742 * @see #setColor 3743 */ 3744 @ColorInt 3745 public int getColor() { 3746 return mColor; 3747 } 3748 3749 /** 3750 * Sets the large icon of the car notification. 3751 * 3752 * If no large icon is set in the extender, Android Auto will display the icon 3753 * specified by {@link android.support.v4.app.NotificationCompat.Builder#setLargeIcon(android.graphics.Bitmap)} 3754 * 3755 * @param largeIcon The large icon to use in the car notification. 3756 * @return This object for method chaining. 3757 */ 3758 public CarExtender setLargeIcon(Bitmap largeIcon) { 3759 mLargeIcon = largeIcon; 3760 return this; 3761 } 3762 3763 /** 3764 * Gets the large icon used in this car notification, or null if no icon has been set. 3765 * 3766 * @return The large icon for the car notification. 3767 * @see CarExtender#setLargeIcon 3768 */ 3769 public Bitmap getLargeIcon() { 3770 return mLargeIcon; 3771 } 3772 3773 /** 3774 * Sets the unread conversation in a message notification. 3775 * 3776 * @param unreadConversation The unread part of the conversation this notification conveys. 3777 * @return This object for method chaining. 3778 */ 3779 public CarExtender setUnreadConversation(UnreadConversation unreadConversation) { 3780 mUnreadConversation = unreadConversation; 3781 return this; 3782 } 3783 3784 /** 3785 * Returns the unread conversation conveyed by this notification. 3786 * @see #setUnreadConversation(UnreadConversation) 3787 */ 3788 public UnreadConversation getUnreadConversation() { 3789 return mUnreadConversation; 3790 } 3791 3792 /** 3793 * A class which holds the unread messages from a conversation. 3794 */ 3795 public static class UnreadConversation extends NotificationCompatBase.UnreadConversation { 3796 private final String[] mMessages; 3797 private final RemoteInput mRemoteInput; 3798 private final PendingIntent mReplyPendingIntent; 3799 private final PendingIntent mReadPendingIntent; 3800 private final String[] mParticipants; 3801 private final long mLatestTimestamp; 3802 3803 UnreadConversation(String[] messages, RemoteInput remoteInput, 3804 PendingIntent replyPendingIntent, PendingIntent readPendingIntent, 3805 String[] participants, long latestTimestamp) { 3806 mMessages = messages; 3807 mRemoteInput = remoteInput; 3808 mReadPendingIntent = readPendingIntent; 3809 mReplyPendingIntent = replyPendingIntent; 3810 mParticipants = participants; 3811 mLatestTimestamp = latestTimestamp; 3812 } 3813 3814 /** 3815 * Gets the list of messages conveyed by this notification. 3816 */ 3817 @Override 3818 public String[] getMessages() { 3819 return mMessages; 3820 } 3821 3822 /** 3823 * Gets the remote input that will be used to convey the response to a message list, or 3824 * null if no such remote input exists. 3825 */ 3826 @Override 3827 public RemoteInput getRemoteInput() { 3828 return mRemoteInput; 3829 } 3830 3831 /** 3832 * Gets the pending intent that will be triggered when the user replies to this 3833 * notification. 3834 */ 3835 @Override 3836 public PendingIntent getReplyPendingIntent() { 3837 return mReplyPendingIntent; 3838 } 3839 3840 /** 3841 * Gets the pending intent that Android Auto will send after it reads aloud all messages 3842 * in this object's message list. 3843 */ 3844 @Override 3845 public PendingIntent getReadPendingIntent() { 3846 return mReadPendingIntent; 3847 } 3848 3849 /** 3850 * Gets the participants in the conversation. 3851 */ 3852 @Override 3853 public String[] getParticipants() { 3854 return mParticipants; 3855 } 3856 3857 /** 3858 * Gets the firs participant in the conversation. 3859 */ 3860 @Override 3861 public String getParticipant() { 3862 return mParticipants.length > 0 ? mParticipants[0] : null; 3863 } 3864 3865 /** 3866 * Gets the timestamp of the conversation. 3867 */ 3868 @Override 3869 public long getLatestTimestamp() { 3870 return mLatestTimestamp; 3871 } 3872 3873 /** @hide */ 3874 static final Factory FACTORY = new Factory() { 3875 @Override 3876 public UnreadConversation build( 3877 String[] messages, RemoteInputCompatBase.RemoteInput remoteInput, 3878 PendingIntent replyPendingIntent, PendingIntent readPendingIntent, 3879 String[] participants, long latestTimestamp) { 3880 return new UnreadConversation( 3881 messages, (RemoteInput) remoteInput, replyPendingIntent, 3882 readPendingIntent, 3883 participants, latestTimestamp); 3884 } 3885 }; 3886 3887 /** 3888 * Builder class for {@link CarExtender.UnreadConversation} objects. 3889 */ 3890 public static class Builder { 3891 private final List<String> mMessages = new ArrayList<String>(); 3892 private final String mParticipant; 3893 private RemoteInput mRemoteInput; 3894 private PendingIntent mReadPendingIntent; 3895 private PendingIntent mReplyPendingIntent; 3896 private long mLatestTimestamp; 3897 3898 /** 3899 * Constructs a new builder for {@link CarExtender.UnreadConversation}. 3900 * 3901 * @param name The name of the other participant in the conversation. 3902 */ 3903 public Builder(String name) { 3904 mParticipant = name; 3905 } 3906 3907 /** 3908 * Appends a new unread message to the list of messages for this conversation. 3909 * 3910 * The messages should be added from oldest to newest. 3911 * 3912 * @param message The text of the new unread message. 3913 * @return This object for method chaining. 3914 */ 3915 public Builder addMessage(String message) { 3916 mMessages.add(message); 3917 return this; 3918 } 3919 3920 /** 3921 * Sets the pending intent and remote input which will convey the reply to this 3922 * notification. 3923 * 3924 * @param pendingIntent The pending intent which will be triggered on a reply. 3925 * @param remoteInput The remote input parcelable which will carry the reply. 3926 * @return This object for method chaining. 3927 * 3928 * @see CarExtender.UnreadConversation#getRemoteInput 3929 * @see CarExtender.UnreadConversation#getReplyPendingIntent 3930 */ 3931 public Builder setReplyAction( 3932 PendingIntent pendingIntent, RemoteInput remoteInput) { 3933 mRemoteInput = remoteInput; 3934 mReplyPendingIntent = pendingIntent; 3935 3936 return this; 3937 } 3938 3939 /** 3940 * Sets the pending intent that will be sent once the messages in this notification 3941 * are read. 3942 * 3943 * @param pendingIntent The pending intent to use. 3944 * @return This object for method chaining. 3945 */ 3946 public Builder setReadPendingIntent(PendingIntent pendingIntent) { 3947 mReadPendingIntent = pendingIntent; 3948 return this; 3949 } 3950 3951 /** 3952 * Sets the timestamp of the most recent message in an unread conversation. 3953 * 3954 * If a messaging notification has been posted by your application and has not 3955 * yet been cancelled, posting a later notification with the same id and tag 3956 * but without a newer timestamp may result in Android Auto not displaying a 3957 * heads up notification for the later notification. 3958 * 3959 * @param timestamp The timestamp of the most recent message in the conversation. 3960 * @return This object for method chaining. 3961 */ 3962 public Builder setLatestTimestamp(long timestamp) { 3963 mLatestTimestamp = timestamp; 3964 return this; 3965 } 3966 3967 /** 3968 * Builds a new unread conversation object. 3969 * 3970 * @return The new unread conversation object. 3971 */ 3972 public UnreadConversation build() { 3973 String[] messages = mMessages.toArray(new String[mMessages.size()]); 3974 String[] participants = { mParticipant }; 3975 return new UnreadConversation(messages, mRemoteInput, mReplyPendingIntent, 3976 mReadPendingIntent, participants, mLatestTimestamp); 3977 } 3978 } 3979 } 3980 } 3981 3982 3983 /** 3984 * Get an array of Notification objects from a parcelable array bundle field. 3985 * Update the bundle to have a typed array so fetches in the future don't need 3986 * to do an array copy. 3987 */ 3988 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { 3989 Parcelable[] array = bundle.getParcelableArray(key); 3990 if (array instanceof Notification[] || array == null) { 3991 return (Notification[]) array; 3992 } 3993 Notification[] typedArray = new Notification[array.length]; 3994 for (int i = 0; i < array.length; i++) { 3995 typedArray[i] = (Notification) array[i]; 3996 } 3997 bundle.putParcelableArray(key, typedArray); 3998 return typedArray; 3999 } 4000 4001 /** 4002 * Gets the {@link Notification#extras} field from a notification in a backwards 4003 * compatible manner. Extras field was supported from JellyBean (Api level 16) 4004 * forwards. This function will return null on older api levels. 4005 */ 4006 public static Bundle getExtras(Notification notif) { 4007 return IMPL.getExtras(notif); 4008 } 4009 4010 /** 4011 * Get the number of actions in this notification in a backwards compatible 4012 * manner. Actions were supported from JellyBean (Api level 16) forwards. 4013 */ 4014 public static int getActionCount(Notification notif) { 4015 return IMPL.getActionCount(notif); 4016 } 4017 4018 /** 4019 * Get an action on this notification in a backwards compatible 4020 * manner. Actions were supported from JellyBean (Api level 16) forwards. 4021 * @param notif The notification to inspect. 4022 * @param actionIndex The index of the action to retrieve. 4023 */ 4024 public static Action getAction(Notification notif, int actionIndex) { 4025 return IMPL.getAction(notif, actionIndex); 4026 } 4027 4028 /** 4029 * Get the category of this notification in a backwards compatible 4030 * manner. 4031 * @param notif The notification to inspect. 4032 */ 4033 public static String getCategory(Notification notif) { 4034 return IMPL.getCategory(notif); 4035 } 4036 4037 /** 4038 * Get whether or not this notification is only relevant to the current device. 4039 * 4040 * <p>Some notifications can be bridged to other devices for remote display. 4041 * If this hint is set, it is recommend that this notification not be bridged. 4042 */ 4043 public static boolean getLocalOnly(Notification notif) { 4044 return IMPL.getLocalOnly(notif); 4045 } 4046 4047 /** 4048 * Get the key used to group this notification into a cluster or stack 4049 * with other notifications on devices which support such rendering. 4050 */ 4051 public static String getGroup(Notification notif) { 4052 return IMPL.getGroup(notif); 4053 } 4054 4055 /** 4056 * Get whether this notification to be the group summary for a group of notifications. 4057 * Grouped notifications may display in a cluster or stack on devices which 4058 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 4059 * @return Whether this notification is a group summary. 4060 */ 4061 public static boolean isGroupSummary(Notification notif) { 4062 return IMPL.isGroupSummary(notif); 4063 } 4064 4065 /** 4066 * Get a sort key that orders this notification among other notifications from the 4067 * same package. This can be useful if an external sort was already applied and an app 4068 * would like to preserve this. Notifications will be sorted lexicographically using this 4069 * value, although providing different priorities in addition to providing sort key may 4070 * cause this value to be ignored. 4071 * 4072 * <p>This sort key can also be used to order members of a notification group. See 4073 * {@link Builder#setGroup}. 4074 * 4075 * @see String#compareTo(String) 4076 */ 4077 public static String getSortKey(Notification notif) { 4078 return IMPL.getSortKey(notif); 4079 } 4080} 4081