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