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