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