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