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