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