NotificationCompat.java revision c9e4b6fcfcc361f65f2f579b2c001ad99a194638
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 } 457 458 static class NotificationCompatImplBase implements NotificationCompatImpl { 459 @Override 460 public Notification build(Builder b) { 461 Notification result = b.mNotification; 462 result.setLatestEventInfo(b.mContext, b.mContentTitle, 463 b.mContentText, b.mContentIntent); 464 // translate high priority requests into legacy flag 465 if (b.mPriority > PRIORITY_DEFAULT) { 466 result.flags |= FLAG_HIGH_PRIORITY; 467 } 468 return result; 469 } 470 471 @Override 472 public Bundle getExtras(Notification n) { 473 return null; 474 } 475 476 @Override 477 public int getActionCount(Notification n) { 478 return 0; 479 } 480 481 @Override 482 public Action getAction(Notification n, int actionIndex) { 483 return null; 484 } 485 486 @Override 487 public Action[] getActionsFromParcelableArrayList( 488 ArrayList<Parcelable> parcelables) { 489 return null; 490 } 491 492 @Override 493 public ArrayList<Parcelable> getParcelableArrayListForActions(Action[] actions) { 494 return null; 495 } 496 497 @Override 498 public String getCategory(Notification n) { 499 return null; 500 } 501 502 @Override 503 public boolean getLocalOnly(Notification n) { 504 return false; 505 } 506 507 @Override 508 public String getGroup(Notification n) { 509 return null; 510 } 511 512 @Override 513 public boolean isGroupSummary(Notification n) { 514 return false; 515 } 516 517 @Override 518 public String getSortKey(Notification n) { 519 return null; 520 } 521 } 522 523 static class NotificationCompatImplGingerbread extends NotificationCompatImplBase { 524 @Override 525 public Notification build(Builder b) { 526 Notification result = b.mNotification; 527 result.setLatestEventInfo(b.mContext, b.mContentTitle, 528 b.mContentText, b.mContentIntent); 529 result = NotificationCompatGingerbread.add(result, b.mContext, 530 b.mContentTitle, b.mContentText, b.mContentIntent, b.mFullScreenIntent); 531 // translate high priority requests into legacy flag 532 if (b.mPriority > PRIORITY_DEFAULT) { 533 result.flags |= FLAG_HIGH_PRIORITY; 534 } 535 return result; 536 } 537 } 538 539 static class NotificationCompatImplHoneycomb extends NotificationCompatImplBase { 540 @Override 541 public Notification build(Builder b) { 542 return NotificationCompatHoneycomb.add(b.mContext, b.mNotification, 543 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 544 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon); 545 } 546 } 547 548 static class NotificationCompatImplIceCreamSandwich extends NotificationCompatImplBase { 549 @Override 550 public Notification build(Builder b) { 551 return NotificationCompatIceCreamSandwich.add(b.mContext, b.mNotification, 552 b.mContentTitle, b.mContentText, b.mContentInfo, b.mTickerView, 553 b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 554 b.mProgressMax, b.mProgress, b.mProgressIndeterminate); 555 } 556 } 557 558 static class NotificationCompatImplJellybean extends NotificationCompatImplBase { 559 @Override 560 public Notification build(Builder b) { 561 NotificationCompatJellybean.Builder builder = new NotificationCompatJellybean.Builder( 562 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 563 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 564 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, 565 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mExtras, 566 b.mGroupKey, b.mGroupSummary, b.mSortKey); 567 addActionsToBuilder(builder, b.mActions); 568 addStyleToBuilderJellybean(builder, b.mStyle); 569 return builder.build(); 570 } 571 572 @Override 573 public Bundle getExtras(Notification n) { 574 return NotificationCompatJellybean.getExtras(n); 575 } 576 577 @Override 578 public int getActionCount(Notification n) { 579 return NotificationCompatJellybean.getActionCount(n); 580 } 581 582 @Override 583 public Action getAction(Notification n, int actionIndex) { 584 return (Action) NotificationCompatJellybean.getAction(n, actionIndex, Action.FACTORY, 585 RemoteInput.FACTORY); 586 } 587 588 @Override 589 public Action[] getActionsFromParcelableArrayList( 590 ArrayList<Parcelable> parcelables) { 591 return (Action[]) NotificationCompatJellybean.getActionsFromParcelableArrayList( 592 parcelables, Action.FACTORY, RemoteInput.FACTORY); 593 } 594 595 @Override 596 public ArrayList<Parcelable> getParcelableArrayListForActions( 597 Action[] actions) { 598 return NotificationCompatJellybean.getParcelableArrayListForActions(actions); 599 } 600 601 @Override 602 public boolean getLocalOnly(Notification n) { 603 return NotificationCompatJellybean.getLocalOnly(n); 604 } 605 606 @Override 607 public String getGroup(Notification n) { 608 return NotificationCompatJellybean.getGroup(n); 609 } 610 611 @Override 612 public boolean isGroupSummary(Notification n) { 613 return NotificationCompatJellybean.isGroupSummary(n); 614 } 615 616 @Override 617 public String getSortKey(Notification n) { 618 return NotificationCompatJellybean.getSortKey(n); 619 } 620 } 621 622 static class NotificationCompatImplKitKat extends NotificationCompatImplJellybean { 623 @Override 624 public Notification build(Builder b) { 625 NotificationCompatKitKat.Builder builder = new NotificationCompatKitKat.Builder( 626 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 627 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 628 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 629 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, 630 b.mPeople, b.mExtras, b.mGroupKey, b.mGroupSummary, b.mSortKey); 631 addActionsToBuilder(builder, b.mActions); 632 addStyleToBuilderJellybean(builder, b.mStyle); 633 return builder.build(); 634 } 635 636 @Override 637 public Bundle getExtras(Notification n) { 638 return NotificationCompatKitKat.getExtras(n); 639 } 640 641 @Override 642 public int getActionCount(Notification n) { 643 return NotificationCompatKitKat.getActionCount(n); 644 } 645 646 @Override 647 public Action getAction(Notification n, int actionIndex) { 648 return (Action) NotificationCompatKitKat.getAction(n, actionIndex, Action.FACTORY, 649 RemoteInput.FACTORY); 650 } 651 652 @Override 653 public boolean getLocalOnly(Notification n) { 654 return NotificationCompatKitKat.getLocalOnly(n); 655 } 656 657 @Override 658 public String getGroup(Notification n) { 659 return NotificationCompatKitKat.getGroup(n); 660 } 661 662 @Override 663 public boolean isGroupSummary(Notification n) { 664 return NotificationCompatKitKat.isGroupSummary(n); 665 } 666 667 @Override 668 public String getSortKey(Notification n) { 669 return NotificationCompatKitKat.getSortKey(n); 670 } 671 } 672 673 static class NotificationCompatImplApi20 extends NotificationCompatImplKitKat { 674 @Override 675 public Notification build(Builder b) { 676 NotificationCompatApi20.Builder builder = new NotificationCompatApi20.Builder( 677 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 678 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 679 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 680 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mPeople, b.mExtras, 681 b.mGroupKey, b.mGroupSummary, b.mSortKey); 682 addActionsToBuilder(builder, b.mActions); 683 addStyleToBuilderJellybean(builder, b.mStyle); 684 return builder.build(); 685 } 686 687 @Override 688 public Action getAction(Notification n, int actionIndex) { 689 return (Action) NotificationCompatApi20.getAction(n, actionIndex, Action.FACTORY, 690 RemoteInput.FACTORY); 691 } 692 693 @Override 694 public Action[] getActionsFromParcelableArrayList( 695 ArrayList<Parcelable> parcelables) { 696 return (Action[]) NotificationCompatApi20.getActionsFromParcelableArrayList( 697 parcelables, Action.FACTORY, RemoteInput.FACTORY); 698 } 699 700 @Override 701 public ArrayList<Parcelable> getParcelableArrayListForActions( 702 Action[] actions) { 703 return NotificationCompatApi20.getParcelableArrayListForActions(actions); 704 } 705 706 @Override 707 public boolean getLocalOnly(Notification n) { 708 return NotificationCompatApi20.getLocalOnly(n); 709 } 710 711 @Override 712 public String getGroup(Notification n) { 713 return NotificationCompatApi20.getGroup(n); 714 } 715 716 @Override 717 public boolean isGroupSummary(Notification n) { 718 return NotificationCompatApi20.isGroupSummary(n); 719 } 720 721 @Override 722 public String getSortKey(Notification n) { 723 return NotificationCompatApi20.getSortKey(n); 724 } 725 } 726 727 static class NotificationCompatImplApi21 extends NotificationCompatImplApi20 { 728 @Override 729 public Notification build(Builder b) { 730 NotificationCompatApi21.Builder builder = new NotificationCompatApi21.Builder( 731 b.mContext, b.mNotification, b.mContentTitle, b.mContentText, b.mContentInfo, 732 b.mTickerView, b.mNumber, b.mContentIntent, b.mFullScreenIntent, b.mLargeIcon, 733 b.mProgressMax, b.mProgress, b.mProgressIndeterminate, b.mShowWhen, 734 b.mUseChronometer, b.mPriority, b.mSubText, b.mLocalOnly, b.mCategory, 735 b.mPeople, b.mExtras, b.mColor, b.mVisibility, b.mPublicVersion, 736 b.mGroupKey, b.mGroupSummary, b.mSortKey); 737 addActionsToBuilder(builder, b.mActions); 738 addStyleToBuilderJellybean(builder, b.mStyle); 739 return builder.build(); 740 } 741 742 @Override 743 public String getCategory(Notification notif) { 744 return NotificationCompatApi21.getCategory(notif); 745 } 746 } 747 748 private static void addActionsToBuilder(NotificationBuilderWithActions builder, 749 ArrayList<Action> actions) { 750 for (Action action : actions) { 751 builder.addAction(action); 752 } 753 } 754 755 private static void addStyleToBuilderJellybean(NotificationBuilderWithBuilderAccessor builder, 756 Style style) { 757 if (style != null) { 758 if (style instanceof BigTextStyle) { 759 BigTextStyle bigTextStyle = (BigTextStyle) style; 760 NotificationCompatJellybean.addBigTextStyle(builder, 761 bigTextStyle.mBigContentTitle, 762 bigTextStyle.mSummaryTextSet, 763 bigTextStyle.mSummaryText, 764 bigTextStyle.mBigText); 765 } else if (style instanceof InboxStyle) { 766 InboxStyle inboxStyle = (InboxStyle) style; 767 NotificationCompatJellybean.addInboxStyle(builder, 768 inboxStyle.mBigContentTitle, 769 inboxStyle.mSummaryTextSet, 770 inboxStyle.mSummaryText, 771 inboxStyle.mTexts); 772 } else if (style instanceof BigPictureStyle) { 773 BigPictureStyle bigPictureStyle = (BigPictureStyle) style; 774 NotificationCompatJellybean.addBigPictureStyle(builder, 775 bigPictureStyle.mBigContentTitle, 776 bigPictureStyle.mSummaryTextSet, 777 bigPictureStyle.mSummaryText, 778 bigPictureStyle.mPicture, 779 bigPictureStyle.mBigLargeIcon, 780 bigPictureStyle.mBigLargeIconSet); 781 } 782 } 783 } 784 785 static { 786 if (Build.VERSION.SDK_INT >= 21) { 787 IMPL = new NotificationCompatImplApi21(); 788 } else if (Build.VERSION.SDK_INT >= 20) { 789 IMPL = new NotificationCompatImplApi20(); 790 } else if (Build.VERSION.SDK_INT >= 19) { 791 IMPL = new NotificationCompatImplKitKat(); 792 } else if (Build.VERSION.SDK_INT >= 16) { 793 IMPL = new NotificationCompatImplJellybean(); 794 } else if (Build.VERSION.SDK_INT >= 14) { 795 IMPL = new NotificationCompatImplIceCreamSandwich(); 796 } else if (Build.VERSION.SDK_INT >= 11) { 797 IMPL = new NotificationCompatImplHoneycomb(); 798 } else if (Build.VERSION.SDK_INT >= 9) { 799 IMPL = new NotificationCompatImplGingerbread(); 800 } else { 801 IMPL = new NotificationCompatImplBase(); 802 } 803 } 804 805 /** 806 * Builder class for {@link NotificationCompat} objects. Allows easier control over 807 * all the flags, as well as help constructing the typical notification layouts. 808 * <p> 809 * On platform versions that don't offer expanded notifications, methods that depend on 810 * expanded notifications have no effect. 811 * </p> 812 * <p> 813 * For example, action buttons won't appear on platforms prior to Android 4.1. Action 814 * buttons depend on expanded notifications, which are only available in Android 4.1 815 * and later. 816 * <p> 817 * For this reason, you should always ensure that UI controls in a notification are also 818 * available in an {@link android.app.Activity} in your app, and you should always start that 819 * {@link android.app.Activity} when users click the notification. To do this, use the 820 * {@link NotificationCompat.Builder#setContentIntent setContentIntent()} 821 * method. 822 * </p> 823 * 824 */ 825 public static class Builder { 826 /** 827 * Maximum length of CharSequences accepted by Builder and friends. 828 * 829 * <p> 830 * Avoids spamming the system with overly large strings such as full e-mails. 831 */ 832 private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024; 833 834 Context mContext; 835 836 CharSequence mContentTitle; 837 CharSequence mContentText; 838 PendingIntent mContentIntent; 839 PendingIntent mFullScreenIntent; 840 RemoteViews mTickerView; 841 Bitmap mLargeIcon; 842 CharSequence mContentInfo; 843 int mNumber; 844 int mPriority; 845 boolean mShowWhen = true; 846 boolean mUseChronometer; 847 Style mStyle; 848 CharSequence mSubText; 849 int mProgressMax; 850 int mProgress; 851 boolean mProgressIndeterminate; 852 String mGroupKey; 853 boolean mGroupSummary; 854 String mSortKey; 855 ArrayList<Action> mActions = new ArrayList<Action>(); 856 boolean mLocalOnly = false; 857 String mCategory; 858 Bundle mExtras; 859 int mColor = COLOR_DEFAULT; 860 int mVisibility = VISIBILITY_PRIVATE; 861 Notification mPublicVersion; 862 863 Notification mNotification = new Notification(); 864 public ArrayList<String> mPeople; 865 866 /** 867 * Constructor. 868 * 869 * Automatically sets the when field to {@link System#currentTimeMillis() 870 * System.currentTimeMillis()} and the audio stream to the 871 * {@link Notification#STREAM_DEFAULT}. 872 * 873 * @param context A {@link Context} that will be used to construct the 874 * RemoteViews. The Context will not be held past the lifetime of this 875 * Builder object. 876 */ 877 public Builder(Context context) { 878 mContext = context; 879 880 // Set defaults to match the defaults of a Notification 881 mNotification.when = System.currentTimeMillis(); 882 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 883 mPriority = PRIORITY_DEFAULT; 884 mPeople = new ArrayList<String>(); 885 } 886 887 /** 888 * Set the time that the event occurred. Notifications in the panel are 889 * sorted by this time. 890 */ 891 public Builder setWhen(long when) { 892 mNotification.when = when; 893 return this; 894 } 895 896 /** 897 * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown 898 * in the content view. 899 */ 900 public Builder setShowWhen(boolean show) { 901 mShowWhen = show; 902 return this; 903 } 904 905 /** 906 * Show the {@link Notification#when} field as a stopwatch. 907 * 908 * Instead of presenting <code>when</code> as a timestamp, the notification will show an 909 * automatically updating display of the minutes and seconds since <code>when</code>. 910 * 911 * Useful when showing an elapsed time (like an ongoing phone call). 912 * 913 * @see android.widget.Chronometer 914 * @see Notification#when 915 */ 916 public Builder setUsesChronometer(boolean b) { 917 mUseChronometer = b; 918 return this; 919 } 920 921 /** 922 * Set the small icon to use in the notification layouts. Different classes of devices 923 * may return different sizes. See the UX guidelines for more information on how to 924 * design these icons. 925 * 926 * @param icon A resource ID in the application's package of the drawble to use. 927 */ 928 public Builder setSmallIcon(int icon) { 929 mNotification.icon = icon; 930 return this; 931 } 932 933 /** 934 * A variant of {@link #setSmallIcon(int) setSmallIcon(int)} that takes an additional 935 * level parameter for when the icon is a {@link android.graphics.drawable.LevelListDrawable 936 * LevelListDrawable}. 937 * 938 * @param icon A resource ID in the application's package of the drawble to use. 939 * @param level The level to use for the icon. 940 * 941 * @see android.graphics.drawable.LevelListDrawable 942 */ 943 public Builder setSmallIcon(int icon, int level) { 944 mNotification.icon = icon; 945 mNotification.iconLevel = level; 946 return this; 947 } 948 949 /** 950 * Set the title (first row) of the notification, in a standard notification. 951 */ 952 public Builder setContentTitle(CharSequence title) { 953 mContentTitle = limitCharSequenceLength(title); 954 return this; 955 } 956 957 /** 958 * Set the text (second row) of the notification, in a standard notification. 959 */ 960 public Builder setContentText(CharSequence text) { 961 mContentText = limitCharSequenceLength(text); 962 return this; 963 } 964 965 /** 966 * Set the third line of text in the platform notification template. 967 * Don't use if you're also using {@link #setProgress(int, int, boolean)}; 968 * they occupy the same location in the standard template. 969 * <br> 970 * If the platform does not provide large-format notifications, this method has no effect. 971 * The third line of text only appears in expanded view. 972 * <br> 973 */ 974 public Builder setSubText(CharSequence text) { 975 mSubText = limitCharSequenceLength(text); 976 return this; 977 } 978 979 /** 980 * Set the large number at the right-hand side of the notification. This is 981 * equivalent to setContentInfo, although it might show the number in a different 982 * font size for readability. 983 */ 984 public Builder setNumber(int number) { 985 mNumber = number; 986 return this; 987 } 988 989 /** 990 * Set the large text at the right-hand side of the notification. 991 */ 992 public Builder setContentInfo(CharSequence info) { 993 mContentInfo = limitCharSequenceLength(info); 994 return this; 995 } 996 997 /** 998 * Set the progress this notification represents, which may be 999 * represented as a {@link android.widget.ProgressBar}. 1000 */ 1001 public Builder setProgress(int max, int progress, boolean indeterminate) { 1002 mProgressMax = max; 1003 mProgress = progress; 1004 mProgressIndeterminate = indeterminate; 1005 return this; 1006 } 1007 1008 /** 1009 * Supply a custom RemoteViews to use instead of the standard one. 1010 */ 1011 public Builder setContent(RemoteViews views) { 1012 mNotification.contentView = views; 1013 return this; 1014 } 1015 1016 /** 1017 * Supply a {@link PendingIntent} to send when the notification is clicked. 1018 * If you do not supply an intent, you can now add PendingIntents to individual 1019 * views to be launched when clicked by calling {@link RemoteViews#setOnClickPendingIntent 1020 * RemoteViews.setOnClickPendingIntent(int,PendingIntent)}. Be sure to 1021 * read {@link Notification#contentIntent Notification.contentIntent} for 1022 * how to correctly use this. 1023 */ 1024 public Builder setContentIntent(PendingIntent intent) { 1025 mContentIntent = intent; 1026 return this; 1027 } 1028 1029 /** 1030 * Supply a {@link PendingIntent} to send when the notification is cleared by the user 1031 * directly from the notification panel. For example, this intent is sent when the user 1032 * clicks the "Clear all" button, or the individual "X" buttons on notifications. This 1033 * intent is not sent when the application calls 1034 * {@link android.app.NotificationManager#cancel NotificationManager.cancel(int)}. 1035 */ 1036 public Builder setDeleteIntent(PendingIntent intent) { 1037 mNotification.deleteIntent = intent; 1038 return this; 1039 } 1040 1041 /** 1042 * An intent to launch instead of posting the notification to the status bar. 1043 * Only for use with extremely high-priority notifications demanding the user's 1044 * <strong>immediate</strong> attention, such as an incoming phone call or 1045 * alarm clock that the user has explicitly set to a particular time. 1046 * If this facility is used for something else, please give the user an option 1047 * to turn it off and use a normal notification, as this can be extremely 1048 * disruptive. 1049 * 1050 * <p> 1051 * On some platforms, the system UI may choose to display a heads-up notification, 1052 * instead of launching this intent, while the user is using the device. 1053 * </p> 1054 * 1055 * @param intent The pending intent to launch. 1056 * @param highPriority Passing true will cause this notification to be sent 1057 * even if other notifications are suppressed. 1058 */ 1059 public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { 1060 mFullScreenIntent = intent; 1061 setFlag(FLAG_HIGH_PRIORITY, highPriority); 1062 return this; 1063 } 1064 1065 /** 1066 * Set the text that is displayed in the status bar when the notification first 1067 * arrives. 1068 */ 1069 public Builder setTicker(CharSequence tickerText) { 1070 mNotification.tickerText = limitCharSequenceLength(tickerText); 1071 return this; 1072 } 1073 1074 /** 1075 * Set the text that is displayed in the status bar when the notification first 1076 * arrives, and also a RemoteViews object that may be displayed instead on some 1077 * devices. 1078 */ 1079 public Builder setTicker(CharSequence tickerText, RemoteViews views) { 1080 mNotification.tickerText = limitCharSequenceLength(tickerText); 1081 mTickerView = views; 1082 return this; 1083 } 1084 1085 /** 1086 * Set the large icon that is shown in the ticker and notification. 1087 */ 1088 public Builder setLargeIcon(Bitmap icon) { 1089 mLargeIcon = icon; 1090 return this; 1091 } 1092 1093 /** 1094 * Set the sound to play. It will play on the default stream. 1095 * 1096 * <p> 1097 * On some platforms, a notification that is noisy is more likely to be presented 1098 * as a heads-up notification. 1099 * </p> 1100 */ 1101 public Builder setSound(Uri sound) { 1102 mNotification.sound = sound; 1103 mNotification.audioStreamType = Notification.STREAM_DEFAULT; 1104 return this; 1105 } 1106 1107 /** 1108 * Set the sound to play. It will play on the stream you supply. 1109 * 1110 * <p> 1111 * On some platforms, a notification that is noisy is more likely to be presented 1112 * as a heads-up notification. 1113 * </p> 1114 * 1115 * @see Notification#STREAM_DEFAULT 1116 * @see AudioManager for the <code>STREAM_</code> constants. 1117 */ 1118 public Builder setSound(Uri sound, int streamType) { 1119 mNotification.sound = sound; 1120 mNotification.audioStreamType = streamType; 1121 return this; 1122 } 1123 1124 /** 1125 * Set the vibration pattern to use. 1126 * 1127 * <p> 1128 * On some platforms, a notification that vibrates is more likely to be presented 1129 * as a heads-up notification. 1130 * </p> 1131 * 1132 * @see android.os.Vibrator for a discussion of the <code>pattern</code> 1133 * parameter. 1134 */ 1135 public Builder setVibrate(long[] pattern) { 1136 mNotification.vibrate = pattern; 1137 return this; 1138 } 1139 1140 /** 1141 * Set the argb value that you would like the LED on the device to blnk, as well as the 1142 * rate. The rate is specified in terms of the number of milliseconds to be on 1143 * and then the number of milliseconds to be off. 1144 */ 1145 public Builder setLights(int argb, int onMs, int offMs) { 1146 mNotification.ledARGB = argb; 1147 mNotification.ledOnMS = onMs; 1148 mNotification.ledOffMS = offMs; 1149 boolean showLights = mNotification.ledOnMS != 0 && mNotification.ledOffMS != 0; 1150 mNotification.flags = (mNotification.flags & ~Notification.FLAG_SHOW_LIGHTS) | 1151 (showLights ? Notification.FLAG_SHOW_LIGHTS : 0); 1152 return this; 1153 } 1154 1155 /** 1156 * Set whether this is an ongoing notification. 1157 * 1158 * <p>Ongoing notifications differ from regular notifications in the following ways: 1159 * <ul> 1160 * <li>Ongoing notifications are sorted above the regular notifications in the 1161 * notification panel.</li> 1162 * <li>Ongoing notifications do not have an 'X' close button, and are not affected 1163 * by the "Clear all" button. 1164 * </ul> 1165 */ 1166 public Builder setOngoing(boolean ongoing) { 1167 setFlag(Notification.FLAG_ONGOING_EVENT, ongoing); 1168 return this; 1169 } 1170 1171 /** 1172 * Set this flag if you would only like the sound, vibrate 1173 * and ticker to be played if the notification is not already showing. 1174 */ 1175 public Builder setOnlyAlertOnce(boolean onlyAlertOnce) { 1176 setFlag(Notification.FLAG_ONLY_ALERT_ONCE, onlyAlertOnce); 1177 return this; 1178 } 1179 1180 /** 1181 * Setting this flag will make it so the notification is automatically 1182 * canceled when the user clicks it in the panel. The PendingIntent 1183 * set with {@link #setDeleteIntent} will be broadcast when the notification 1184 * is canceled. 1185 */ 1186 public Builder setAutoCancel(boolean autoCancel) { 1187 setFlag(Notification.FLAG_AUTO_CANCEL, autoCancel); 1188 return this; 1189 } 1190 1191 /** 1192 * Set whether or not this notification is only relevant to the current device. 1193 * 1194 * <p>Some notifications can be bridged to other devices for remote display. 1195 * This hint can be set to recommend this notification not be bridged. 1196 */ 1197 public Builder setLocalOnly(boolean b) { 1198 mLocalOnly = b; 1199 return this; 1200 } 1201 1202 /** 1203 * Set the notification category. 1204 * 1205 * <p>Must be one of the predefined notification categories (see the <code>CATEGORY_*</code> 1206 * constants in {@link Notification}) that best describes this notification. 1207 * May be used by the system for ranking and filtering. 1208 */ 1209 public Builder setCategory(String category) { 1210 mCategory = category; 1211 return this; 1212 } 1213 1214 /** 1215 * Set the default notification options that will be used. 1216 * <p> 1217 * The value should be one or more of the following fields combined with 1218 * bitwise-or: 1219 * {@link Notification#DEFAULT_SOUND}, {@link Notification#DEFAULT_VIBRATE}, 1220 * {@link Notification#DEFAULT_LIGHTS}. 1221 * <p> 1222 * For all default values, use {@link Notification#DEFAULT_ALL}. 1223 */ 1224 public Builder setDefaults(int defaults) { 1225 mNotification.defaults = defaults; 1226 if ((defaults & Notification.DEFAULT_LIGHTS) != 0) { 1227 mNotification.flags |= Notification.FLAG_SHOW_LIGHTS; 1228 } 1229 return this; 1230 } 1231 1232 private void setFlag(int mask, boolean value) { 1233 if (value) { 1234 mNotification.flags |= mask; 1235 } else { 1236 mNotification.flags &= ~mask; 1237 } 1238 } 1239 1240 /** 1241 * Set the relative priority for this notification. 1242 * 1243 * Priority is an indication of how much of the user's 1244 * valuable attention should be consumed by this 1245 * notification. Low-priority notifications may be hidden from 1246 * the user in certain situations, while the user might be 1247 * interrupted for a higher-priority notification. 1248 * The system sets a notification's priority based on various factors including the 1249 * setPriority value. The effect may differ slightly on different platforms. 1250 * 1251 * @param pri Relative priority for this notification. Must be one of 1252 * the priority constants defined by {@link NotificationCompat}. 1253 * Acceptable values range from {@link 1254 * NotificationCompat#PRIORITY_MIN} (-2) to {@link 1255 * NotificationCompat#PRIORITY_MAX} (2). 1256 */ 1257 public Builder setPriority(int pri) { 1258 mPriority = pri; 1259 return this; 1260 } 1261 1262 /** 1263 * Add a person that is relevant to this notification. 1264 * 1265 * <P> 1266 * Depending on user preferences, this annotation may allow the notification to pass 1267 * through interruption filters, and to appear more prominently in the user interface. 1268 * </P> 1269 * 1270 * <P> 1271 * The person should be specified by the {@code String} representation of a 1272 * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}. 1273 * </P> 1274 * 1275 * <P>The system will also attempt to resolve {@code mailto:} and {@code tel:} schema 1276 * URIs. The path part of these URIs must exist in the contacts database, in the 1277 * appropriate column, or the reference will be discarded as invalid. Telephone schema 1278 * URIs will be resolved by {@link android.provider.ContactsContract.PhoneLookup}. 1279 * </P> 1280 * 1281 * @param uri A URI for the person. 1282 * @see Notification#EXTRA_PEOPLE 1283 */ 1284 public Builder addPerson(String uri) { 1285 mPeople.add(uri); 1286 return this; 1287 } 1288 1289 /** 1290 * Set this notification to be part of a group of notifications sharing the same key. 1291 * Grouped notifications may display in a cluster or stack on devices which 1292 * support such rendering. 1293 * 1294 * <p>To make this notification the summary for its group, also call 1295 * {@link #setGroupSummary}. A sort order can be specified for group members by using 1296 * {@link #setSortKey}. 1297 * @param groupKey The group key of the group. 1298 * @return this object for method chaining 1299 */ 1300 public Builder setGroup(String groupKey) { 1301 mGroupKey = groupKey; 1302 return this; 1303 } 1304 1305 /** 1306 * Set this notification to be the group summary for a group of notifications. 1307 * Grouped notifications may display in a cluster or stack on devices which 1308 * support such rendering. Requires a group key also be set using {@link #setGroup}. 1309 * @param isGroupSummary Whether this notification should be a group summary. 1310 * @return this object for method chaining 1311 */ 1312 public Builder setGroupSummary(boolean isGroupSummary) { 1313 mGroupSummary = isGroupSummary; 1314 return this; 1315 } 1316 1317 /** 1318 * Set a sort key that orders this notification among other notifications from the 1319 * same package. This can be useful if an external sort was already applied and an app 1320 * would like to preserve this. Notifications will be sorted lexicographically using this 1321 * value, although providing different priorities in addition to providing sort key may 1322 * cause this value to be ignored. 1323 * 1324 * <p>This sort key can also be used to order members of a notification group. See 1325 * {@link Builder#setGroup}. 1326 * 1327 * @see String#compareTo(String) 1328 */ 1329 public Builder setSortKey(String sortKey) { 1330 mSortKey = sortKey; 1331 return this; 1332 } 1333 1334 /** 1335 * Merge additional metadata into this notification. 1336 * 1337 * <p>Values within the Bundle will replace existing extras values in this Builder. 1338 * 1339 * @see Notification#extras 1340 */ 1341 public Builder addExtras(Bundle extras) { 1342 if (extras != null) { 1343 if (mExtras == null) { 1344 mExtras = new Bundle(extras); 1345 } else { 1346 mExtras.putAll(extras); 1347 } 1348 } 1349 return this; 1350 } 1351 1352 /** 1353 * Set metadata for this notification. 1354 * 1355 * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's 1356 * current contents are copied into the Notification each time {@link #build()} is 1357 * called. 1358 * 1359 * <p>Replaces any existing extras values with those from the provided Bundle. 1360 * Use {@link #addExtras} to merge in metadata instead. 1361 * 1362 * @see Notification#extras 1363 */ 1364 public Builder setExtras(Bundle extras) { 1365 mExtras = extras; 1366 return this; 1367 } 1368 1369 /** 1370 * Get the current metadata Bundle used by this notification Builder. 1371 * 1372 * <p>The returned Bundle is shared with this Builder. 1373 * 1374 * <p>The current contents of this Bundle are copied into the Notification each time 1375 * {@link #build()} is called. 1376 * 1377 * @see Notification#extras 1378 */ 1379 public Bundle getExtras() { 1380 if (mExtras == null) { 1381 mExtras = new Bundle(); 1382 } 1383 return mExtras; 1384 } 1385 1386 /** 1387 * Add an action to this notification. Actions are typically displayed by 1388 * the system as a button adjacent to the notification content. 1389 * <br> 1390 * Action buttons won't appear on platforms prior to Android 4.1. Action 1391 * buttons depend on expanded notifications, which are only available in Android 4.1 1392 * and later. To ensure that an action button's functionality is always available, first 1393 * implement the functionality in the {@link android.app.Activity} that starts when a user 1394 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1395 * enhance the notification by implementing the same functionality with 1396 * {@link #addAction addAction()}. 1397 * 1398 * @param icon Resource ID of a drawable that represents the action. 1399 * @param title Text describing the action. 1400 * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked. 1401 */ 1402 public Builder addAction(int icon, CharSequence title, PendingIntent intent) { 1403 mActions.add(new Action(icon, title, intent)); 1404 return this; 1405 } 1406 1407 /** 1408 * Add an action to this notification. Actions are typically displayed by 1409 * the system as a button adjacent to the notification content. 1410 * <br> 1411 * Action buttons won't appear on platforms prior to Android 4.1. Action 1412 * buttons depend on expanded notifications, which are only available in Android 4.1 1413 * and later. To ensure that an action button's functionality is always available, first 1414 * implement the functionality in the {@link android.app.Activity} that starts when a user 1415 * clicks the notification (see {@link #setContentIntent setContentIntent()}), and then 1416 * enhance the notification by implementing the same functionality with 1417 * {@link #addAction addAction()}. 1418 * 1419 * @param action The action to add. 1420 */ 1421 public Builder addAction(Action action) { 1422 mActions.add(action); 1423 return this; 1424 } 1425 1426 /** 1427 * Add a rich notification style to be applied at build time. 1428 * <br> 1429 * If the platform does not provide rich notification styles, this method has no effect. The 1430 * user will always see the normal notification style. 1431 * 1432 * @param style Object responsible for modifying the notification style. 1433 */ 1434 public Builder setStyle(Style style) { 1435 if (mStyle != style) { 1436 mStyle = style; 1437 if (mStyle != null) { 1438 mStyle.setBuilder(this); 1439 } 1440 } 1441 return this; 1442 } 1443 1444 /** 1445 * Sets {@link Notification#color}. 1446 * 1447 * @param argb The accent color to use 1448 * 1449 * @return The same Builder. 1450 */ 1451 public Builder setColor(int argb) { 1452 mColor = argb; 1453 return this; 1454 } 1455 1456 /** 1457 * Sets {@link Notification#visibility}. 1458 * 1459 * @param visibility One of {@link Notification#VISIBILITY_PRIVATE} (the default), 1460 * {@link Notification#VISIBILITY_PUBLIC}, or 1461 * {@link Notification#VISIBILITY_SECRET}. 1462 */ 1463 public Builder setVisibility(int visibility) { 1464 mVisibility = visibility; 1465 return this; 1466 } 1467 1468 /** 1469 * Supply a replacement Notification whose contents should be shown in insecure contexts 1470 * (i.e. atop the secure lockscreen). See {@link Notification#visibility} and 1471 * {@link #VISIBILITY_PUBLIC}. 1472 * 1473 * @param n A replacement notification, presumably with some or all info redacted. 1474 * @return The same Builder. 1475 */ 1476 public Builder setPublicVersion(Notification n) { 1477 mPublicVersion = n; 1478 return this; 1479 } 1480 1481 /** 1482 * Apply an extender to this notification builder. Extenders may be used to add 1483 * metadata or change options on this builder. 1484 */ 1485 public Builder extend(Extender extender) { 1486 extender.extend(this); 1487 return this; 1488 } 1489 1490 /** 1491 * @deprecated Use {@link #build()} instead. 1492 */ 1493 @Deprecated 1494 public Notification getNotification() { 1495 return IMPL.build(this); 1496 } 1497 1498 /** 1499 * Combine all of the options that have been set and return a new {@link Notification} 1500 * object. 1501 */ 1502 public Notification build() { 1503 return IMPL.build(this); 1504 } 1505 1506 protected static CharSequence limitCharSequenceLength(CharSequence cs) { 1507 if (cs == null) return cs; 1508 if (cs.length() > MAX_CHARSEQUENCE_LENGTH) { 1509 cs = cs.subSequence(0, MAX_CHARSEQUENCE_LENGTH); 1510 } 1511 return cs; 1512 } 1513 } 1514 1515 /** 1516 * An object that can apply a rich notification style to a {@link Notification.Builder} 1517 * object. 1518 * <br> 1519 * If the platform does not provide rich notification styles, methods in this class have no 1520 * effect. 1521 */ 1522 public static abstract class Style { 1523 Builder mBuilder; 1524 CharSequence mBigContentTitle; 1525 CharSequence mSummaryText; 1526 boolean mSummaryTextSet = false; 1527 1528 public void setBuilder(Builder builder) { 1529 if (mBuilder != builder) { 1530 mBuilder = builder; 1531 if (mBuilder != null) { 1532 mBuilder.setStyle(this); 1533 } 1534 } 1535 } 1536 1537 public Notification build() { 1538 Notification notification = null; 1539 if (mBuilder != null) { 1540 notification = mBuilder.build(); 1541 } 1542 return notification; 1543 } 1544 } 1545 1546 /** 1547 * Helper class for generating large-format notifications that include a large image attachment. 1548 * <br> 1549 * If the platform does not provide large-format notifications, this method has no effect. The 1550 * user will always see the normal notification view. 1551 * <br> 1552 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1553 * <pre class="prettyprint"> 1554 * Notification notif = new Notification.Builder(mContext) 1555 * .setContentTitle("New photo from " + sender.toString()) 1556 * .setContentText(subject) 1557 * .setSmallIcon(R.drawable.new_post) 1558 * .setLargeIcon(aBitmap) 1559 * .setStyle(new Notification.BigPictureStyle() 1560 * .bigPicture(aBigBitmap)) 1561 * .build(); 1562 * </pre> 1563 * 1564 * @see Notification#bigContentView 1565 */ 1566 public static class BigPictureStyle extends Style { 1567 Bitmap mPicture; 1568 Bitmap mBigLargeIcon; 1569 boolean mBigLargeIconSet; 1570 1571 public BigPictureStyle() { 1572 } 1573 1574 public BigPictureStyle(Builder builder) { 1575 setBuilder(builder); 1576 } 1577 1578 /** 1579 * Overrides ContentTitle in the big form of the template. 1580 * This defaults to the value passed to setContentTitle(). 1581 */ 1582 public BigPictureStyle setBigContentTitle(CharSequence title) { 1583 mBigContentTitle = Builder.limitCharSequenceLength(title); 1584 return this; 1585 } 1586 1587 /** 1588 * Set the first line of text after the detail section in the big form of the template. 1589 */ 1590 public BigPictureStyle setSummaryText(CharSequence cs) { 1591 mSummaryText = Builder.limitCharSequenceLength(cs); 1592 mSummaryTextSet = true; 1593 return this; 1594 } 1595 1596 /** 1597 * Provide the bitmap to be used as the payload for the BigPicture notification. 1598 */ 1599 public BigPictureStyle bigPicture(Bitmap b) { 1600 mPicture = b; 1601 return this; 1602 } 1603 1604 /** 1605 * Override the large icon when the big notification is shown. 1606 */ 1607 public BigPictureStyle bigLargeIcon(Bitmap b) { 1608 mBigLargeIcon = b; 1609 mBigLargeIconSet = true; 1610 return this; 1611 } 1612 } 1613 1614 /** 1615 * Helper class for generating large-format notifications that include a lot of text. 1616 * 1617 * <br> 1618 * If the platform does not provide large-format notifications, this method has no effect. The 1619 * user will always see the normal notification view. 1620 * <br> 1621 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1622 * <pre class="prettyprint"> 1623 * Notification notif = new Notification.Builder(mContext) 1624 * .setContentTitle("New mail from " + sender.toString()) 1625 * .setContentText(subject) 1626 * .setSmallIcon(R.drawable.new_mail) 1627 * .setLargeIcon(aBitmap) 1628 * .setStyle(new Notification.BigTextStyle() 1629 * .bigText(aVeryLongString)) 1630 * .build(); 1631 * </pre> 1632 * 1633 * @see Notification#bigContentView 1634 */ 1635 public static class BigTextStyle extends Style { 1636 CharSequence mBigText; 1637 1638 public BigTextStyle() { 1639 } 1640 1641 public BigTextStyle(Builder builder) { 1642 setBuilder(builder); 1643 } 1644 1645 /** 1646 * Overrides ContentTitle in the big form of the template. 1647 * This defaults to the value passed to setContentTitle(). 1648 */ 1649 public BigTextStyle setBigContentTitle(CharSequence title) { 1650 mBigContentTitle = Builder.limitCharSequenceLength(title); 1651 return this; 1652 } 1653 1654 /** 1655 * Set the first line of text after the detail section in the big form of the template. 1656 */ 1657 public BigTextStyle setSummaryText(CharSequence cs) { 1658 mSummaryText = Builder.limitCharSequenceLength(cs); 1659 mSummaryTextSet = true; 1660 return this; 1661 } 1662 1663 /** 1664 * Provide the longer text to be displayed in the big form of the 1665 * template in place of the content text. 1666 */ 1667 public BigTextStyle bigText(CharSequence cs) { 1668 mBigText = Builder.limitCharSequenceLength(cs); 1669 return this; 1670 } 1671 } 1672 1673 /** 1674 * Helper class for generating large-format notifications that include a list of (up to 5) strings. 1675 * 1676 * <br> 1677 * If the platform does not provide large-format notifications, this method has no effect. The 1678 * user will always see the normal notification view. 1679 * <br> 1680 * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like so: 1681 * <pre class="prettyprint"> 1682 * Notification noti = new Notification.Builder() 1683 * .setContentTitle("5 New mails from " + sender.toString()) 1684 * .setContentText(subject) 1685 * .setSmallIcon(R.drawable.new_mail) 1686 * .setLargeIcon(aBitmap) 1687 * .setStyle(new Notification.InboxStyle() 1688 * .addLine(str1) 1689 * .addLine(str2) 1690 * .setContentTitle("") 1691 * .setSummaryText("+3 more")) 1692 * .build(); 1693 * </pre> 1694 * 1695 * @see Notification#bigContentView 1696 */ 1697 public static class InboxStyle extends Style { 1698 ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 1699 1700 public InboxStyle() { 1701 } 1702 1703 public InboxStyle(Builder builder) { 1704 setBuilder(builder); 1705 } 1706 1707 /** 1708 * Overrides ContentTitle in the big form of the template. 1709 * This defaults to the value passed to setContentTitle(). 1710 */ 1711 public InboxStyle setBigContentTitle(CharSequence title) { 1712 mBigContentTitle = Builder.limitCharSequenceLength(title); 1713 return this; 1714 } 1715 1716 /** 1717 * Set the first line of text after the detail section in the big form of the template. 1718 */ 1719 public InboxStyle setSummaryText(CharSequence cs) { 1720 mSummaryText = Builder.limitCharSequenceLength(cs); 1721 mSummaryTextSet = true; 1722 return this; 1723 } 1724 1725 /** 1726 * Append a line to the digest section of the Inbox notification. 1727 */ 1728 public InboxStyle addLine(CharSequence cs) { 1729 mTexts.add(Builder.limitCharSequenceLength(cs)); 1730 return this; 1731 } 1732 } 1733 1734 /** 1735 * Structure to encapsulate a named action that can be shown as part of this notification. 1736 * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is 1737 * selected by the user. Action buttons won't appear on platforms prior to Android 4.1. 1738 * <p> 1739 * Apps should use {@link NotificationCompat.Builder#addAction(int, CharSequence, PendingIntent)} 1740 * or {@link NotificationCompat.Builder#addAction(NotificationCompat.Action)} 1741 * to attach actions. 1742 */ 1743 public static class Action extends NotificationCompatBase.Action { 1744 private final Bundle mExtras; 1745 private final RemoteInput[] mRemoteInputs; 1746 1747 /** 1748 * Small icon representing the action. 1749 */ 1750 public int icon; 1751 /** 1752 * Title of the action. 1753 */ 1754 public CharSequence title; 1755 /** 1756 * Intent to send when the user invokes this action. May be null, in which case the action 1757 * may be rendered in a disabled presentation. 1758 */ 1759 public PendingIntent actionIntent; 1760 1761 public Action(int icon, CharSequence title, PendingIntent intent) { 1762 this(icon, title, intent, new Bundle(), null); 1763 } 1764 1765 private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras, 1766 RemoteInput[] remoteInputs) { 1767 this.icon = icon; 1768 this.title = NotificationCompat.Builder.limitCharSequenceLength(title); 1769 this.actionIntent = intent; 1770 this.mExtras = extras != null ? extras : new Bundle(); 1771 this.mRemoteInputs = remoteInputs; 1772 } 1773 1774 @Override 1775 protected int getIcon() { 1776 return icon; 1777 } 1778 1779 @Override 1780 protected CharSequence getTitle() { 1781 return title; 1782 } 1783 1784 @Override 1785 protected PendingIntent getActionIntent() { 1786 return actionIntent; 1787 } 1788 1789 /** 1790 * Get additional metadata carried around with this Action. 1791 */ 1792 public Bundle getExtras() { 1793 return mExtras; 1794 } 1795 1796 /** 1797 * Get the list of inputs to be collected from the user when this action is sent. 1798 * May return null if no remote inputs were added. 1799 */ 1800 public RemoteInput[] getRemoteInputs() { 1801 return mRemoteInputs; 1802 } 1803 1804 /** 1805 * Builder class for {@link Action} objects. 1806 */ 1807 public static final class Builder { 1808 private final int mIcon; 1809 private final CharSequence mTitle; 1810 private final PendingIntent mIntent; 1811 private final Bundle mExtras; 1812 private ArrayList<RemoteInput> mRemoteInputs; 1813 1814 /** 1815 * Construct a new builder for {@link Action} object. 1816 * @param icon icon to show for this action 1817 * @param title the title of the action 1818 * @param intent the {@link PendingIntent} to fire when users trigger this action 1819 */ 1820 public Builder(int icon, CharSequence title, PendingIntent intent) { 1821 this(icon, title, intent, new Bundle()); 1822 } 1823 1824 /** 1825 * Construct a new builder for {@link Action} object using the fields from an 1826 * {@link Action}. 1827 * @param action the action to read fields from. 1828 */ 1829 public Builder(Action action) { 1830 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras)); 1831 } 1832 1833 private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) { 1834 mIcon = icon; 1835 mTitle = NotificationCompat.Builder.limitCharSequenceLength(title); 1836 mIntent = intent; 1837 mExtras = extras; 1838 } 1839 1840 /** 1841 * Merge additional metadata into this builder. 1842 * 1843 * <p>Values within the Bundle will replace existing extras values in this Builder. 1844 * 1845 * @see NotificationCompat.Action#getExtras 1846 */ 1847 public Builder addExtras(Bundle extras) { 1848 if (extras != null) { 1849 mExtras.putAll(extras); 1850 } 1851 return this; 1852 } 1853 1854 /** 1855 * Get the metadata Bundle used by this Builder. 1856 * 1857 * <p>The returned Bundle is shared with this Builder. 1858 */ 1859 public Bundle getExtras() { 1860 return mExtras; 1861 } 1862 1863 /** 1864 * Add an input to be collected from the user when this action is sent. 1865 * Response values can be retrieved from the fired intent by using the 1866 * {@link RemoteInput#getResultsFromIntent} function. 1867 * @param remoteInput a {@link RemoteInput} to add to the action 1868 * @return this object for method chaining 1869 */ 1870 public Builder addRemoteInput(RemoteInput remoteInput) { 1871 if (mRemoteInputs == null) { 1872 mRemoteInputs = new ArrayList<RemoteInput>(); 1873 } 1874 mRemoteInputs.add(remoteInput); 1875 return this; 1876 } 1877 1878 /** 1879 * Apply an extender to this action builder. Extenders may be used to add 1880 * metadata or change options on this builder. 1881 */ 1882 public Builder extend(Extender extender) { 1883 extender.extend(this); 1884 return this; 1885 } 1886 1887 /** 1888 * Combine all of the options that have been set and return a new {@link Action} 1889 * object. 1890 * @return the built action 1891 */ 1892 public Action build() { 1893 RemoteInput[] remoteInputs = mRemoteInputs != null 1894 ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; 1895 return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs); 1896 } 1897 } 1898 1899 1900 /** 1901 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 1902 * metadata or change options on an action builder. 1903 */ 1904 public interface Extender { 1905 /** 1906 * Apply this extender to a notification action builder. 1907 * @param builder the builder to be modified. 1908 * @return the build object for chaining. 1909 */ 1910 public Builder extend(Builder builder); 1911 } 1912 1913 /** 1914 * Wearable extender for notification actions. To add extensions to an action, 1915 * create a new {@link NotificationCompat.Action.WearableExtender} object using 1916 * the {@code WearableExtender()} constructor and apply it to a 1917 * {@link NotificationCompat.Action.Builder} using 1918 * {@link NotificationCompat.Action.Builder#extend}. 1919 * 1920 * <pre class="prettyprint"> 1921 * NotificationCompat.Action action = new NotificationCompat.Action.Builder( 1922 * R.drawable.archive_all, "Archive all", actionIntent) 1923 * .extend(new NotificationCompat.Action.WearableExtender() 1924 * .setAvailableOffline(false)) 1925 * .build();</pre> 1926 */ 1927 public static final class WearableExtender implements Extender { 1928 /** Notification action extra which contains wearable extensions */ 1929 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 1930 1931 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 1932 private static final String KEY_FLAGS = "flags"; 1933 private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel"; 1934 private static final String KEY_CONFIRM_LABEL = "confirmLabel"; 1935 private static final String KEY_CANCEL_LABEL = "cancelLabel"; 1936 1937 // Flags bitwise-ored to mFlags 1938 private static final int FLAG_AVAILABLE_OFFLINE = 0x1; 1939 1940 // Default value for flags integer 1941 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE; 1942 1943 private int mFlags = DEFAULT_FLAGS; 1944 1945 private CharSequence mInProgressLabel; 1946 private CharSequence mConfirmLabel; 1947 private CharSequence mCancelLabel; 1948 1949 /** 1950 * Create a {@link NotificationCompat.Action.WearableExtender} with default 1951 * options. 1952 */ 1953 public WearableExtender() { 1954 } 1955 1956 /** 1957 * Create a {@link NotificationCompat.Action.WearableExtender} by reading 1958 * wearable options present in an existing notification action. 1959 * @param action the notification action to inspect. 1960 */ 1961 public WearableExtender(Action action) { 1962 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS); 1963 if (wearableBundle != null) { 1964 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 1965 mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL); 1966 mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL); 1967 mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL); 1968 } 1969 } 1970 1971 /** 1972 * Apply wearable extensions to a notification action that is being built. This is 1973 * typically called by the {@link NotificationCompat.Action.Builder#extend} 1974 * method of {@link NotificationCompat.Action.Builder}. 1975 */ 1976 @Override 1977 public Action.Builder extend(Action.Builder builder) { 1978 Bundle wearableBundle = new Bundle(); 1979 1980 if (mFlags != DEFAULT_FLAGS) { 1981 wearableBundle.putInt(KEY_FLAGS, mFlags); 1982 } 1983 if (mInProgressLabel != null) { 1984 wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel); 1985 } 1986 if (mConfirmLabel != null) { 1987 wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel); 1988 } 1989 if (mCancelLabel != null) { 1990 wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel); 1991 } 1992 1993 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 1994 return builder; 1995 } 1996 1997 @Override 1998 public WearableExtender clone() { 1999 WearableExtender that = new WearableExtender(); 2000 that.mFlags = this.mFlags; 2001 that.mInProgressLabel = this.mInProgressLabel; 2002 that.mConfirmLabel = this.mConfirmLabel; 2003 that.mCancelLabel = this.mCancelLabel; 2004 return that; 2005 } 2006 2007 /** 2008 * Set whether this action is available when the wearable device is not connected to 2009 * a companion device. The user can still trigger this action when the wearable device 2010 * is offline, but a visual hint will indicate that the action may not be available. 2011 * Defaults to true. 2012 */ 2013 public WearableExtender setAvailableOffline(boolean availableOffline) { 2014 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline); 2015 return this; 2016 } 2017 2018 /** 2019 * Get whether this action is available when the wearable device is not connected to 2020 * a companion device. The user can still trigger this action when the wearable device 2021 * is offline, but a visual hint will indicate that the action may not be available. 2022 * Defaults to true. 2023 */ 2024 public boolean isAvailableOffline() { 2025 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0; 2026 } 2027 2028 private void setFlag(int mask, boolean value) { 2029 if (value) { 2030 mFlags |= mask; 2031 } else { 2032 mFlags &= ~mask; 2033 } 2034 } 2035 2036 /** 2037 * Set a label to display while the wearable is preparing to automatically execute the 2038 * action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2039 * 2040 * @param label the label to display while the action is being prepared to execute 2041 * @return this object for method chaining 2042 */ 2043 public WearableExtender setInProgressLabel(CharSequence label) { 2044 mInProgressLabel = label; 2045 return this; 2046 } 2047 2048 /** 2049 * Get the label to display while the wearable is preparing to automatically execute 2050 * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..." 2051 * 2052 * @return the label to display while the action is being prepared to execute 2053 */ 2054 public CharSequence getInProgressLabel() { 2055 return mInProgressLabel; 2056 } 2057 2058 /** 2059 * Set a label to display to confirm that the action should be executed. 2060 * This is usually an imperative verb like "Send". 2061 * 2062 * @param label the label to confirm the action should be executed 2063 * @return this object for method chaining 2064 */ 2065 public WearableExtender setConfirmLabel(CharSequence label) { 2066 mConfirmLabel = label; 2067 return this; 2068 } 2069 2070 /** 2071 * Get the label to display to confirm that the action should be executed. 2072 * This is usually an imperative verb like "Send". 2073 * 2074 * @return the label to confirm the action should be executed 2075 */ 2076 public CharSequence getConfirmLabel() { 2077 return mConfirmLabel; 2078 } 2079 2080 /** 2081 * Set a label to display to cancel the action. 2082 * This is usually an imperative verb, like "Cancel". 2083 * 2084 * @param label the label to display to cancel the action 2085 * @return this object for method chaining 2086 */ 2087 public WearableExtender setCancelLabel(CharSequence label) { 2088 mCancelLabel = label; 2089 return this; 2090 } 2091 2092 /** 2093 * Get the label to display to cancel the action. 2094 * This is usually an imperative verb like "Cancel". 2095 * 2096 * @return the label to display to cancel the action 2097 */ 2098 public CharSequence getCancelLabel() { 2099 return mCancelLabel; 2100 } 2101 } 2102 2103 /** @hide */ 2104 public static final Factory FACTORY = new Factory() { 2105 @Override 2106 public Action build(int icon, CharSequence title, 2107 PendingIntent actionIntent, Bundle extras, 2108 RemoteInputCompatBase.RemoteInput[] remoteInputs) { 2109 return new Action(icon, title, actionIntent, extras, 2110 (RemoteInput[]) remoteInputs); 2111 } 2112 2113 @Override 2114 public Action[] newArray(int length) { 2115 return new Action[length]; 2116 } 2117 }; 2118 } 2119 2120 2121 /** 2122 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 2123 * metadata or change options on a notification builder. 2124 */ 2125 public interface Extender { 2126 /** 2127 * Apply this extender to a notification builder. 2128 * @param builder the builder to be modified. 2129 * @return the build object for chaining. 2130 */ 2131 public Builder extend(Builder builder); 2132 } 2133 2134 /** 2135 * Helper class to add wearable extensions to notifications. 2136 * <p class="note"> See 2137 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications 2138 * for Android Wear</a> for more information on how to use this class. 2139 * <p> 2140 * To create a notification with wearable extensions: 2141 * <ol> 2142 * <li>Create a {@link NotificationCompat.Builder}, setting any desired 2143 * properties. 2144 * <li>Create a {@link NotificationCompat.WearableExtender}. 2145 * <li>Set wearable-specific properties using the 2146 * {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}. 2147 * <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a 2148 * notification. 2149 * <li>Post the notification to the notification 2150 * system with the {@code NotificationManagerCompat.notify(...)} methods 2151 * and not the {@code NotificationManager.notify(...)} methods. 2152 * </ol> 2153 * 2154 * <pre class="prettyprint"> 2155 * Notification notif = new NotificationCompat.Builder(mContext) 2156 * .setContentTitle("New mail from " + sender.toString()) 2157 * .setContentText(subject) 2158 * .setSmallIcon(R.drawable.new_mail) 2159 * .extend(new NotificationCompat.WearableExtender() 2160 * .setContentIcon(R.drawable.new_mail)) 2161 * .build(); 2162 * NotificationManagerCompat.from(mContext).notify(0, notif);</pre> 2163 * 2164 * <p>Wearable extensions can be accessed on an existing notification by using the 2165 * {@code WearableExtender(Notification)} constructor, 2166 * and then using the {@code get} methods to access values. 2167 * 2168 * <pre class="prettyprint"> 2169 * NotificationCompat.WearableExtender wearableExtender = 2170 * new NotificationCompat.WearableExtender(notification); 2171 * List<Notification> pages = wearableExtender.getPages();</pre> 2172 */ 2173 public static final class WearableExtender implements Extender { 2174 /** 2175 * Sentinel value for an action index that is unset. 2176 */ 2177 public static final int UNSET_ACTION_INDEX = -1; 2178 2179 /** 2180 * Size value for use with {@link #setCustomSizePreset} to show this notification with 2181 * default sizing. 2182 * <p>For custom display notifications created using {@link #setDisplayIntent}, 2183 * the default is {@link #SIZE_LARGE}. All other notifications size automatically based 2184 * on their content. 2185 */ 2186 public static final int SIZE_DEFAULT = 0; 2187 2188 /** 2189 * Size value for use with {@link #setCustomSizePreset} to show this notification 2190 * with an extra small size. 2191 * <p>This value is only applicable for custom display notifications created using 2192 * {@link #setDisplayIntent}. 2193 */ 2194 public static final int SIZE_XSMALL = 1; 2195 2196 /** 2197 * Size value for use with {@link #setCustomSizePreset} to show this notification 2198 * with a small size. 2199 * <p>This value is only applicable for custom display notifications created using 2200 * {@link #setDisplayIntent}. 2201 */ 2202 public static final int SIZE_SMALL = 2; 2203 2204 /** 2205 * Size value for use with {@link #setCustomSizePreset} to show this notification 2206 * with a medium size. 2207 * <p>This value is only applicable for custom display notifications created using 2208 * {@link #setDisplayIntent}. 2209 */ 2210 public static final int SIZE_MEDIUM = 3; 2211 2212 /** 2213 * Size value for use with {@link #setCustomSizePreset} to show this notification 2214 * with a large size. 2215 * <p>This value is only applicable for custom display notifications created using 2216 * {@link #setDisplayIntent}. 2217 */ 2218 public static final int SIZE_LARGE = 4; 2219 2220 /** 2221 * Size value for use with {@link #setCustomSizePreset} to show this notification 2222 * full screen. 2223 * <p>This value is only applicable for custom display notifications created using 2224 * {@link #setDisplayIntent}. 2225 */ 2226 public static final int SIZE_FULL_SCREEN = 5; 2227 2228 /** 2229 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a 2230 * short amount of time when this notification is displayed on the screen. This 2231 * is the default value. 2232 */ 2233 public static final int SCREEN_TIMEOUT_SHORT = 0; 2234 2235 /** 2236 * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on 2237 * for a longer amount of time when this notification is displayed on the screen. 2238 */ 2239 public static final int SCREEN_TIMEOUT_LONG = -1; 2240 2241 /** Notification extra which contains wearable extensions */ 2242 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 2243 2244 // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options. 2245 private static final String KEY_ACTIONS = "actions"; 2246 private static final String KEY_FLAGS = "flags"; 2247 private static final String KEY_DISPLAY_INTENT = "displayIntent"; 2248 private static final String KEY_PAGES = "pages"; 2249 private static final String KEY_BACKGROUND = "background"; 2250 private static final String KEY_CONTENT_ICON = "contentIcon"; 2251 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity"; 2252 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex"; 2253 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset"; 2254 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; 2255 private static final String KEY_GRAVITY = "gravity"; 2256 private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout"; 2257 2258 // Flags bitwise-ored to mFlags 2259 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; 2260 private static final int FLAG_HINT_HIDE_ICON = 1 << 1; 2261 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2; 2262 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3; 2263 private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4; 2264 2265 // Default value for flags integer 2266 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE; 2267 2268 private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END; 2269 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM; 2270 2271 private ArrayList<Action> mActions = new ArrayList<Action>(); 2272 private int mFlags = DEFAULT_FLAGS; 2273 private PendingIntent mDisplayIntent; 2274 private ArrayList<Notification> mPages = new ArrayList<Notification>(); 2275 private Bitmap mBackground; 2276 private int mContentIcon; 2277 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY; 2278 private int mContentActionIndex = UNSET_ACTION_INDEX; 2279 private int mCustomSizePreset = SIZE_DEFAULT; 2280 private int mCustomContentHeight; 2281 private int mGravity = DEFAULT_GRAVITY; 2282 private int mHintScreenTimeout; 2283 2284 /** 2285 * Create a {@link NotificationCompat.WearableExtender} with default 2286 * options. 2287 */ 2288 public WearableExtender() { 2289 } 2290 2291 public WearableExtender(Notification notif) { 2292 Bundle extras = getExtras(notif); 2293 Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS) 2294 : null; 2295 if (wearableBundle != null) { 2296 Action[] actions = IMPL.getActionsFromParcelableArrayList( 2297 wearableBundle.getParcelableArrayList(KEY_ACTIONS)); 2298 if (actions != null) { 2299 Collections.addAll(mActions, actions); 2300 } 2301 2302 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 2303 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); 2304 2305 Notification[] pages = getNotificationArrayFromBundle( 2306 wearableBundle, KEY_PAGES); 2307 if (pages != null) { 2308 Collections.addAll(mPages, pages); 2309 } 2310 2311 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND); 2312 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON); 2313 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY, 2314 DEFAULT_CONTENT_ICON_GRAVITY); 2315 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX, 2316 UNSET_ACTION_INDEX); 2317 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET, 2318 SIZE_DEFAULT); 2319 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); 2320 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); 2321 mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT); 2322 } 2323 } 2324 2325 /** 2326 * Apply wearable extensions to a notification that is being built. This is typically 2327 * called by the {@link NotificationCompat.Builder#extend} method of 2328 * {@link NotificationCompat.Builder}. 2329 */ 2330 @Override 2331 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 2332 Bundle wearableBundle = new Bundle(); 2333 2334 if (!mActions.isEmpty()) { 2335 wearableBundle.putParcelableArrayList(KEY_ACTIONS, 2336 IMPL.getParcelableArrayListForActions(mActions.toArray( 2337 new Action[mActions.size()]))); 2338 } 2339 if (mFlags != DEFAULT_FLAGS) { 2340 wearableBundle.putInt(KEY_FLAGS, mFlags); 2341 } 2342 if (mDisplayIntent != null) { 2343 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent); 2344 } 2345 if (!mPages.isEmpty()) { 2346 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( 2347 new Notification[mPages.size()])); 2348 } 2349 if (mBackground != null) { 2350 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); 2351 } 2352 if (mContentIcon != 0) { 2353 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); 2354 } 2355 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) { 2356 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity); 2357 } 2358 if (mContentActionIndex != UNSET_ACTION_INDEX) { 2359 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX, 2360 mContentActionIndex); 2361 } 2362 if (mCustomSizePreset != SIZE_DEFAULT) { 2363 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset); 2364 } 2365 if (mCustomContentHeight != 0) { 2366 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight); 2367 } 2368 if (mGravity != DEFAULT_GRAVITY) { 2369 wearableBundle.putInt(KEY_GRAVITY, mGravity); 2370 } 2371 if (mHintScreenTimeout != 0) { 2372 wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout); 2373 } 2374 2375 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 2376 return builder; 2377 } 2378 2379 @Override 2380 public WearableExtender clone() { 2381 WearableExtender that = new WearableExtender(); 2382 that.mActions = new ArrayList<Action>(this.mActions); 2383 that.mFlags = this.mFlags; 2384 that.mDisplayIntent = this.mDisplayIntent; 2385 that.mPages = new ArrayList<Notification>(this.mPages); 2386 that.mBackground = this.mBackground; 2387 that.mContentIcon = this.mContentIcon; 2388 that.mContentIconGravity = this.mContentIconGravity; 2389 that.mContentActionIndex = this.mContentActionIndex; 2390 that.mCustomSizePreset = this.mCustomSizePreset; 2391 that.mCustomContentHeight = this.mCustomContentHeight; 2392 that.mGravity = this.mGravity; 2393 that.mHintScreenTimeout = this.mHintScreenTimeout; 2394 return that; 2395 } 2396 2397 /** 2398 * Add a wearable action to this notification. 2399 * 2400 * <p>When wearable actions are added using this method, the set of actions that 2401 * show on a wearable device splits from devices that only show actions added 2402 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2403 * of which actions display on different devices. 2404 * 2405 * @param action the action to add to this notification 2406 * @return this object for method chaining 2407 * @see NotificationCompat.Action 2408 */ 2409 public WearableExtender addAction(Action action) { 2410 mActions.add(action); 2411 return this; 2412 } 2413 2414 /** 2415 * Adds wearable actions to this notification. 2416 * 2417 * <p>When wearable actions are added using this method, the set of actions that 2418 * show on a wearable device splits from devices that only show actions added 2419 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2420 * of which actions display on different devices. 2421 * 2422 * @param actions the actions to add to this notification 2423 * @return this object for method chaining 2424 * @see NotificationCompat.Action 2425 */ 2426 public WearableExtender addActions(List<Action> actions) { 2427 mActions.addAll(actions); 2428 return this; 2429 } 2430 2431 /** 2432 * Clear all wearable actions present on this builder. 2433 * @return this object for method chaining. 2434 * @see #addAction 2435 */ 2436 public WearableExtender clearActions() { 2437 mActions.clear(); 2438 return this; 2439 } 2440 2441 /** 2442 * Get the wearable actions present on this notification. 2443 */ 2444 public List<Action> getActions() { 2445 return mActions; 2446 } 2447 2448 /** 2449 * Set an intent to launch inside of an activity view when displaying 2450 * this notification. The {@link PendingIntent} provided should be for an activity. 2451 * 2452 * <pre class="prettyprint"> 2453 * Intent displayIntent = new Intent(context, MyDisplayActivity.class); 2454 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context, 2455 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT); 2456 * Notification notif = new NotificationCompat.Builder(context) 2457 * .extend(new NotificationCompat.WearableExtender() 2458 * .setDisplayIntent(displayPendingIntent) 2459 * .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM)) 2460 * .build();</pre> 2461 * 2462 * <p>The activity to launch needs to allow embedding, must be exported, and 2463 * should have an empty task affinity. It is also recommended to use the device 2464 * default light theme. 2465 * 2466 * <p>Example AndroidManifest.xml entry: 2467 * <pre class="prettyprint"> 2468 * <activity android:name="com.example.MyDisplayActivity" 2469 * android:exported="true" 2470 * android:allowEmbedded="true" 2471 * android:taskAffinity="" 2472 * android:theme="@android:style/Theme.DeviceDefault.Light" /></pre> 2473 * 2474 * @param intent the {@link PendingIntent} for an activity 2475 * @return this object for method chaining 2476 * @see NotificationCompat.WearableExtender#getDisplayIntent 2477 */ 2478 public WearableExtender setDisplayIntent(PendingIntent intent) { 2479 mDisplayIntent = intent; 2480 return this; 2481 } 2482 2483 /** 2484 * Get the intent to launch inside of an activity view when displaying this 2485 * notification. This {@code PendingIntent} should be for an activity. 2486 */ 2487 public PendingIntent getDisplayIntent() { 2488 return mDisplayIntent; 2489 } 2490 2491 /** 2492 * Add an additional page of content to display with this notification. The current 2493 * notification forms the first page, and pages added using this function form 2494 * subsequent pages. This field can be used to separate a notification into multiple 2495 * sections. 2496 * 2497 * @param page the notification to add as another page 2498 * @return this object for method chaining 2499 * @see NotificationCompat.WearableExtender#getPages 2500 */ 2501 public WearableExtender addPage(Notification page) { 2502 mPages.add(page); 2503 return this; 2504 } 2505 2506 /** 2507 * Add additional pages of content to display with this notification. The current 2508 * notification forms the first page, and pages added using this function form 2509 * subsequent pages. This field can be used to separate a notification into multiple 2510 * sections. 2511 * 2512 * @param pages a list of notifications 2513 * @return this object for method chaining 2514 * @see NotificationCompat.WearableExtender#getPages 2515 */ 2516 public WearableExtender addPages(List<Notification> pages) { 2517 mPages.addAll(pages); 2518 return this; 2519 } 2520 2521 /** 2522 * Clear all additional pages present on this builder. 2523 * @return this object for method chaining. 2524 * @see #addPage 2525 */ 2526 public WearableExtender clearPages() { 2527 mPages.clear(); 2528 return this; 2529 } 2530 2531 /** 2532 * Get the array of additional pages of content for displaying this notification. The 2533 * current notification forms the first page, and elements within this array form 2534 * subsequent pages. This field can be used to separate a notification into multiple 2535 * sections. 2536 * @return the pages for this notification 2537 */ 2538 public List<Notification> getPages() { 2539 return mPages; 2540 } 2541 2542 /** 2543 * Set a background image to be displayed behind the notification content. 2544 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2545 * will work with any notification style. 2546 * 2547 * @param background the background bitmap 2548 * @return this object for method chaining 2549 * @see NotificationCompat.WearableExtender#getBackground 2550 */ 2551 public WearableExtender setBackground(Bitmap background) { 2552 mBackground = background; 2553 return this; 2554 } 2555 2556 /** 2557 * Get a background image to be displayed behind the notification content. 2558 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2559 * will work with any notification style. 2560 * 2561 * @return the background image 2562 * @see NotificationCompat.WearableExtender#setBackground 2563 */ 2564 public Bitmap getBackground() { 2565 return mBackground; 2566 } 2567 2568 /** 2569 * Set an icon that goes with the content of this notification. 2570 */ 2571 public WearableExtender setContentIcon(int icon) { 2572 mContentIcon = icon; 2573 return this; 2574 } 2575 2576 /** 2577 * Get an icon that goes with the content of this notification. 2578 */ 2579 public int getContentIcon() { 2580 return mContentIcon; 2581 } 2582 2583 /** 2584 * Set the gravity that the content icon should have within the notification display. 2585 * Supported values include {@link android.view.Gravity#START} and 2586 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2587 * @see #setContentIcon 2588 */ 2589 public WearableExtender setContentIconGravity(int contentIconGravity) { 2590 mContentIconGravity = contentIconGravity; 2591 return this; 2592 } 2593 2594 /** 2595 * Get the gravity that the content icon should have within the notification display. 2596 * Supported values include {@link android.view.Gravity#START} and 2597 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2598 * @see #getContentIcon 2599 */ 2600 public int getContentIconGravity() { 2601 return mContentIconGravity; 2602 } 2603 2604 /** 2605 * Set an action from this notification's actions to be clickable with the content of 2606 * this notification. This action will no longer display separately from the 2607 * notification's content. 2608 * 2609 * <p>For notifications with multiple pages, child pages can also have content actions 2610 * set, although the list of available actions comes from the main notification and not 2611 * from the child page's notification. 2612 * 2613 * @param actionIndex The index of the action to hoist onto the current notification page. 2614 * If wearable actions were added to the main notification, this index 2615 * will apply to that list, otherwise it will apply to the regular 2616 * actions list. 2617 */ 2618 public WearableExtender setContentAction(int actionIndex) { 2619 mContentActionIndex = actionIndex; 2620 return this; 2621 } 2622 2623 /** 2624 * Get the index of the notification action, if any, that was specified as being clickable 2625 * with the content of this notification. This action will no longer display separately 2626 * from the notification's content. 2627 * 2628 * <p>For notifications with multiple pages, child pages can also have content actions 2629 * set, although the list of available actions comes from the main notification and not 2630 * from the child page's notification. 2631 * 2632 * <p>If wearable specific actions were added to the main notification, this index will 2633 * apply to that list, otherwise it will apply to the regular actions list. 2634 * 2635 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected. 2636 */ 2637 public int getContentAction() { 2638 return mContentActionIndex; 2639 } 2640 2641 /** 2642 * Set the gravity that this notification should have within the available viewport space. 2643 * Supported values include {@link android.view.Gravity#TOP}, 2644 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2645 * The default value is {@link android.view.Gravity#BOTTOM}. 2646 */ 2647 public WearableExtender setGravity(int gravity) { 2648 mGravity = gravity; 2649 return this; 2650 } 2651 2652 /** 2653 * Get the gravity that this notification should have within the available viewport space. 2654 * Supported values include {@link android.view.Gravity#TOP}, 2655 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2656 * The default value is {@link android.view.Gravity#BOTTOM}. 2657 */ 2658 public int getGravity() { 2659 return mGravity; 2660 } 2661 2662 /** 2663 * Set the custom size preset for the display of this notification out of the available 2664 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2665 * {@link #SIZE_LARGE}. 2666 * <p>Some custom size presets are only applicable for custom display notifications created 2667 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the 2668 * documentation for the preset in question. See also 2669 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}. 2670 */ 2671 public WearableExtender setCustomSizePreset(int sizePreset) { 2672 mCustomSizePreset = sizePreset; 2673 return this; 2674 } 2675 2676 /** 2677 * Get the custom size preset for the display of this notification out of the available 2678 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2679 * {@link #SIZE_LARGE}. 2680 * <p>Some custom size presets are only applicable for custom display notifications created 2681 * using {@link #setDisplayIntent}. Check the documentation for the preset in question. 2682 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}. 2683 */ 2684 public int getCustomSizePreset() { 2685 return mCustomSizePreset; 2686 } 2687 2688 /** 2689 * Set the custom height in pixels for the display of this notification's content. 2690 * <p>This option is only available for custom display notifications created 2691 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also 2692 * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and 2693 * {@link #getCustomContentHeight}. 2694 */ 2695 public WearableExtender setCustomContentHeight(int height) { 2696 mCustomContentHeight = height; 2697 return this; 2698 } 2699 2700 /** 2701 * Get the custom height in pixels for the display of this notification's content. 2702 * <p>This option is only available for custom display notifications created 2703 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and 2704 * {@link #setCustomContentHeight}. 2705 */ 2706 public int getCustomContentHeight() { 2707 return mCustomContentHeight; 2708 } 2709 2710 /** 2711 * Set whether the scrolling position for the contents of this notification should start 2712 * at the bottom of the contents instead of the top when the contents are too long to 2713 * display within the screen. Default is false (start scroll at the top). 2714 */ 2715 public WearableExtender setStartScrollBottom(boolean startScrollBottom) { 2716 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom); 2717 return this; 2718 } 2719 2720 /** 2721 * Get whether the scrolling position for the contents of this notification should start 2722 * at the bottom of the contents instead of the top when the contents are too long to 2723 * display within the screen. Default is false (start scroll at the top). 2724 */ 2725 public boolean getStartScrollBottom() { 2726 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0; 2727 } 2728 2729 /** 2730 * Set whether the content intent is available when the wearable device is not connected 2731 * to a companion device. The user can still trigger this intent when the wearable device 2732 * is offline, but a visual hint will indicate that the content intent may not be available. 2733 * Defaults to true. 2734 */ 2735 public WearableExtender setContentIntentAvailableOffline( 2736 boolean contentIntentAvailableOffline) { 2737 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline); 2738 return this; 2739 } 2740 2741 /** 2742 * Get whether the content intent is available when the wearable device is not connected 2743 * to a companion device. The user can still trigger this intent when the wearable device 2744 * is offline, but a visual hint will indicate that the content intent may not be available. 2745 * Defaults to true. 2746 */ 2747 public boolean getContentIntentAvailableOffline() { 2748 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0; 2749 } 2750 2751 /** 2752 * Set a hint that this notification's icon should not be displayed. 2753 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise. 2754 * @return this object for method chaining 2755 */ 2756 public WearableExtender setHintHideIcon(boolean hintHideIcon) { 2757 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon); 2758 return this; 2759 } 2760 2761 /** 2762 * Get a hint that this notification's icon should not be displayed. 2763 * @return {@code true} if this icon should not be displayed, false otherwise. 2764 * The default value is {@code false} if this was never set. 2765 */ 2766 public boolean getHintHideIcon() { 2767 return (mFlags & FLAG_HINT_HIDE_ICON) != 0; 2768 } 2769 2770 /** 2771 * Set a visual hint that only the background image of this notification should be 2772 * displayed, and other semantic content should be hidden. This hint is only applicable 2773 * to sub-pages added using {@link #addPage}. 2774 */ 2775 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) { 2776 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly); 2777 return this; 2778 } 2779 2780 /** 2781 * Get a visual hint that only the background image of this notification should be 2782 * displayed, and other semantic content should be hidden. This hint is only applicable 2783 * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}. 2784 */ 2785 public boolean getHintShowBackgroundOnly() { 2786 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0; 2787 } 2788 2789 /** 2790 * Set a hint that this notification's background should not be clipped if possible. 2791 * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible. 2792 * @return this object for method chaining 2793 */ 2794 public WearableExtender setHintAvoidBackgroundClipping( 2795 boolean hintAvoidBackgroundClipping) { 2796 setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping); 2797 return this; 2798 } 2799 2800 /** 2801 * Get a hint that this notification's background should not be clipped if possible. 2802 * @return {@code true} if it's ok if the background is clipped on the screen, false 2803 * otherwise. The default value is {@code false} if this was never set. 2804 */ 2805 public boolean getHintAvoidBackgroundClipping() { 2806 return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0; 2807 } 2808 2809 /** 2810 * Set a hint that the screen should remain on for at least this duration when 2811 * this notification is displayed on the screen. 2812 * @param timeout The requested screen timeout in milliseconds. Can also be either 2813 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 2814 * @return this object for method chaining 2815 */ 2816 public WearableExtender setHintScreenTimeout(int timeout) { 2817 mHintScreenTimeout = timeout; 2818 return this; 2819 } 2820 2821 /** 2822 * Get the duration, in milliseconds, that the screen should remain on for 2823 * when this notification is displayed. 2824 * @return the duration in milliseconds if > 0, or either one of the sentinel values 2825 * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}. 2826 */ 2827 public int getHintScreenTimeout() { 2828 return mHintScreenTimeout; 2829 } 2830 2831 private void setFlag(int mask, boolean value) { 2832 if (value) { 2833 mFlags |= mask; 2834 } else { 2835 mFlags &= ~mask; 2836 } 2837 } 2838 } 2839 2840 /** 2841 * Get an array of Notification objects from a parcelable array bundle field. 2842 * Update the bundle to have a typed array so fetches in the future don't need 2843 * to do an array copy. 2844 */ 2845 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { 2846 Parcelable[] array = bundle.getParcelableArray(key); 2847 if (array instanceof Notification[] || array == null) { 2848 return (Notification[]) array; 2849 } 2850 Notification[] typedArray = new Notification[array.length]; 2851 for (int i = 0; i < array.length; i++) { 2852 typedArray[i] = (Notification) array[i]; 2853 } 2854 bundle.putParcelableArray(key, typedArray); 2855 return typedArray; 2856 } 2857 2858 /** 2859 * Gets the {@link Notification#extras} field from a notification in a backwards 2860 * compatible manner. Extras field was supported from JellyBean (Api level 16) 2861 * forwards. This function will return null on older api levels. 2862 */ 2863 public static Bundle getExtras(Notification notif) { 2864 return IMPL.getExtras(notif); 2865 } 2866 2867 /** 2868 * Get the number of actions in this notification in a backwards compatible 2869 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2870 */ 2871 public static int getActionCount(Notification notif) { 2872 return IMPL.getActionCount(notif); 2873 } 2874 2875 /** 2876 * Get an action on this notification in a backwards compatible 2877 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2878 * @param notif The notification to inspect. 2879 * @param actionIndex The index of the action to retrieve. 2880 */ 2881 public static Action getAction(Notification notif, int actionIndex) { 2882 return IMPL.getAction(notif, actionIndex); 2883 } 2884 2885 /** 2886 * Get the category of this notification in a backwards compatible 2887 * manner. 2888 * @param notif The notification to inspect. 2889 */ 2890 public static String getCategory(Notification notif) { 2891 return IMPL.getCategory(notif); 2892 } 2893 2894 /** 2895 * Get whether or not this notification is only relevant to the current device. 2896 * 2897 * <p>Some notifications can be bridged to other devices for remote display. 2898 * If this hint is set, it is recommend that this notification not be bridged. 2899 */ 2900 public static boolean getLocalOnly(Notification notif) { 2901 return IMPL.getLocalOnly(notif); 2902 } 2903 2904 /** 2905 * Get the key used to group this notification into a cluster or stack 2906 * with other notifications on devices which support such rendering. 2907 */ 2908 public static String getGroup(Notification notif) { 2909 return IMPL.getGroup(notif); 2910 } 2911 2912 /** 2913 * Get whether this notification to be the group summary for a group of notifications. 2914 * Grouped notifications may display in a cluster or stack on devices which 2915 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 2916 * @return Whether this notification is a group summary. 2917 */ 2918 public static boolean isGroupSummary(Notification notif) { 2919 return IMPL.isGroupSummary(notif); 2920 } 2921 2922 /** 2923 * Get a sort key that orders this notification among other notifications from the 2924 * same package. This can be useful if an external sort was already applied and an app 2925 * would like to preserve this. Notifications will be sorted lexicographically using this 2926 * value, although providing different priorities in addition to providing sort key may 2927 * cause this value to be ignored. 2928 * 2929 * <p>This sort key can also be used to order members of a notification group. See 2930 * {@link Builder#setGroup}. 2931 * 2932 * @see String#compareTo(String) 2933 */ 2934 public static String getSortKey(Notification notif) { 2935 return IMPL.getSortKey(notif); 2936 } 2937} 2938