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