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