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