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