NotificationCompat.java revision de49561684ae0fc52343e357e3e08b1b14d3a842
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 * .extend(new NotificationCompat.Action.WearableExtender() 1707 * .setAvailableOffline(false)) 1708 * .build();</pre> 1709 */ 1710 public static final class WearableExtender implements Extender { 1711 /** Notification action extra which contains wearable extensions */ 1712 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 1713 1714 private static final String KEY_FLAGS = "flags"; 1715 1716 // Flags bitwise-ored to mFlags 1717 private static final int FLAG_AVAILABLE_OFFLINE = 0x1; 1718 1719 // Default value for flags integer 1720 private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE; 1721 1722 private int mFlags = DEFAULT_FLAGS; 1723 1724 /** 1725 * Create a {@link NotificationCompat.Action.WearableExtender} with default 1726 * options. 1727 */ 1728 public WearableExtender() { 1729 } 1730 1731 /** 1732 * Create a {@link NotificationCompat.Action.WearableExtender} by reading 1733 * wearable options present in an existing notification action. 1734 * @param action the notification action to inspect. 1735 */ 1736 public WearableExtender(Action action) { 1737 Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS); 1738 if (wearableBundle != null) { 1739 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 1740 } 1741 } 1742 1743 /** 1744 * Apply wearable extensions to a notification action that is being built. This is 1745 * typically called by the {@link NotificationCompat.Action.Builder#extend} 1746 * method of {@link NotificationCompat.Action.Builder}. 1747 */ 1748 @Override 1749 public Action.Builder extend(Action.Builder builder) { 1750 Bundle wearableBundle = new Bundle(); 1751 1752 if (mFlags != DEFAULT_FLAGS) { 1753 wearableBundle.putInt(KEY_FLAGS, mFlags); 1754 } 1755 1756 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 1757 return builder; 1758 } 1759 1760 @Override 1761 public WearableExtender clone() { 1762 WearableExtender that = new WearableExtender(); 1763 that.mFlags = this.mFlags; 1764 return that; 1765 } 1766 1767 /** 1768 * Set whether this action is available when the wearable device is not connected to 1769 * a companion device. The user can still trigger this action when the wearable device 1770 * is offline, but a visual hint will indicate that the action may not be available. 1771 * Defaults to true. 1772 */ 1773 public WearableExtender setAvailableOffline(boolean availableOffline) { 1774 setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline); 1775 return this; 1776 } 1777 1778 /** 1779 * Get whether this action is available when the wearable device is not connected to 1780 * a companion device. The user can still trigger this action when the wearable device 1781 * is offline, but a visual hint will indicate that the action may not be available. 1782 * Defaults to true. 1783 */ 1784 public boolean isAvailableOffline() { 1785 return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0; 1786 } 1787 1788 private void setFlag(int mask, boolean value) { 1789 if (value) { 1790 mFlags |= mask; 1791 } else { 1792 mFlags &= ~mask; 1793 } 1794 } 1795 } 1796 1797 /** @hide */ 1798 public static final Factory FACTORY = new Factory() { 1799 @Override 1800 public Action build(int icon, CharSequence title, 1801 PendingIntent actionIntent, Bundle extras, 1802 RemoteInputCompatBase.RemoteInput[] remoteInputs) { 1803 return new Action(icon, title, actionIntent, extras, 1804 (RemoteInput[]) remoteInputs); 1805 } 1806 1807 @Override 1808 public Action[] newArray(int length) { 1809 return new Action[length]; 1810 } 1811 }; 1812 } 1813 1814 1815 /** 1816 * Extender interface for use with {@link Builder#extend}. Extenders may be used to add 1817 * metadata or change options on a notification builder. 1818 */ 1819 public interface Extender { 1820 /** 1821 * Apply this extender to a notification builder. 1822 * @param builder the builder to be modified. 1823 * @return the build object for chaining. 1824 */ 1825 public Builder extend(Builder builder); 1826 } 1827 1828 /** 1829 * Helper class to add wearable extensions to notifications. 1830 * <p class="note"> See 1831 * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications 1832 * for Android Wear</a> for more information on how to use this class. 1833 * <p> 1834 * To create a notification with wearable extensions: 1835 * <ol> 1836 * <li>Create a {@link NotificationCompat.Builder}, setting any desired 1837 * properties. 1838 * <li>Create a {@link NotificationCompat.WearableExtender}. 1839 * <li>Set wearable-specific properties using the 1840 * {@code add} and {@code set} methods of {@link NotificationCompat.WearableExtender}. 1841 * <li>Call {@link NotificationCompat.Builder#extend} to apply the extensions to a 1842 * notification. 1843 * <li>Post the notification to the notification 1844 * system with the {@code NotificationManagerCompat.notify(...)} methods 1845 * and not the {@code NotificationManager.notify(...)} methods. 1846 * </ol> 1847 * 1848 * <pre class="prettyprint"> 1849 * Notification notif = new NotificationCompat.Builder(mContext) 1850 * .setContentTitle("New mail from " + sender.toString()) 1851 * .setContentText(subject) 1852 * .setSmallIcon(R.drawable.new_mail) 1853 * .extend(new NotificationCompat.WearableExtender() 1854 * .setContentIcon(R.drawable.new_mail)) 1855 * .build(); 1856 * NotificationManagerCompat.from(mContext).notify(0, notif);</pre> 1857 * 1858 * <p>Wearable extensions can be accessed on an existing notification by using the 1859 * {@code WearableExtender(Notification)} constructor, 1860 * and then using the {@code get} methods to access values. 1861 * 1862 * <pre class="prettyprint"> 1863 * NotificationCompat.WearableExtender wearableExtender = 1864 * new NotificationCompat.WearableExtender(notification); 1865 * List<Notification> pages = wearableExtender.getPages();</pre> 1866 */ 1867 public static final class WearableExtender implements Extender { 1868 /** 1869 * Sentinel value for an action index that is unset. 1870 */ 1871 public static final int UNSET_ACTION_INDEX = -1; 1872 1873 /** 1874 * Size value for use with {@link #setCustomSizePreset} to show this notification with 1875 * default sizing. 1876 * <p>For custom display notifications created using {@link #setDisplayIntent}, 1877 * the default is {@link #SIZE_LARGE}. All other notifications size automatically based 1878 * on their content. 1879 */ 1880 public static final int SIZE_DEFAULT = 0; 1881 1882 /** 1883 * Size value for use with {@link #setCustomSizePreset} to show this notification 1884 * with an extra small size. 1885 * <p>This value is only applicable for custom display notifications created using 1886 * {@link #setDisplayIntent}. 1887 */ 1888 public static final int SIZE_XSMALL = 1; 1889 1890 /** 1891 * Size value for use with {@link #setCustomSizePreset} to show this notification 1892 * with a small size. 1893 * <p>This value is only applicable for custom display notifications created using 1894 * {@link #setDisplayIntent}. 1895 */ 1896 public static final int SIZE_SMALL = 2; 1897 1898 /** 1899 * Size value for use with {@link #setCustomSizePreset} to show this notification 1900 * with a medium size. 1901 * <p>This value is only applicable for custom display notifications created using 1902 * {@link #setDisplayIntent}. 1903 */ 1904 public static final int SIZE_MEDIUM = 3; 1905 1906 /** 1907 * Size value for use with {@link #setCustomSizePreset} to show this notification 1908 * with a large size. 1909 * <p>This value is only applicable for custom display notifications created using 1910 * {@link #setDisplayIntent}. 1911 */ 1912 public static final int SIZE_LARGE = 4; 1913 1914 /** 1915 * Size value for use with {@link #setCustomSizePreset} to show this notification 1916 * full screen. 1917 * <p>This value is only applicable for custom display notifications created using 1918 * {@link #setDisplayIntent}. 1919 */ 1920 public static final int SIZE_FULL_SCREEN = 5; 1921 1922 /** Notification extra which contains wearable extensions */ 1923 private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"; 1924 1925 // Keys within EXTRA_WEARABLE_OPTIONS for wearable options. 1926 private static final String KEY_ACTIONS = "actions"; 1927 private static final String KEY_FLAGS = "flags"; 1928 private static final String KEY_DISPLAY_INTENT = "displayIntent"; 1929 private static final String KEY_PAGES = "pages"; 1930 private static final String KEY_BACKGROUND = "background"; 1931 private static final String KEY_CONTENT_ICON = "contentIcon"; 1932 private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity"; 1933 private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex"; 1934 private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset"; 1935 private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; 1936 private static final String KEY_GRAVITY = "gravity"; 1937 1938 // Flags bitwise-ored to mFlags 1939 private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; 1940 private static final int FLAG_HINT_HIDE_ICON = 1 << 1; 1941 private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2; 1942 private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3; 1943 1944 // Default value for flags integer 1945 private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE; 1946 1947 private static final int DEFAULT_CONTENT_ICON_GRAVITY = GravityCompat.END; 1948 private static final int DEFAULT_GRAVITY = Gravity.BOTTOM; 1949 1950 private ArrayList<Action> mActions = new ArrayList<Action>(); 1951 private int mFlags = DEFAULT_FLAGS; 1952 private PendingIntent mDisplayIntent; 1953 private ArrayList<Notification> mPages = new ArrayList<Notification>(); 1954 private Bitmap mBackground; 1955 private int mContentIcon; 1956 private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY; 1957 private int mContentActionIndex = UNSET_ACTION_INDEX; 1958 private int mCustomSizePreset = SIZE_DEFAULT; 1959 private int mCustomContentHeight; 1960 private int mGravity = DEFAULT_GRAVITY; 1961 1962 /** 1963 * Create a {@link NotificationCompat.WearableExtender} with default 1964 * options. 1965 */ 1966 public WearableExtender() { 1967 } 1968 1969 public WearableExtender(Notification notif) { 1970 Bundle extras = getExtras(notif); 1971 Bundle wearableBundle = extras != null ? extras.getBundle(EXTRA_WEARABLE_EXTENSIONS) 1972 : null; 1973 if (wearableBundle != null) { 1974 Action[] actions = IMPL.getActionsFromParcelableArrayList( 1975 wearableBundle.getParcelableArrayList(KEY_ACTIONS)); 1976 if (actions != null) { 1977 Collections.addAll(mActions, actions); 1978 } 1979 1980 mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS); 1981 mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT); 1982 1983 Notification[] pages = getNotificationArrayFromBundle( 1984 wearableBundle, KEY_PAGES); 1985 if (pages != null) { 1986 Collections.addAll(mPages, pages); 1987 } 1988 1989 mBackground = wearableBundle.getParcelable(KEY_BACKGROUND); 1990 mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON); 1991 mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY, 1992 DEFAULT_CONTENT_ICON_GRAVITY); 1993 mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX, 1994 UNSET_ACTION_INDEX); 1995 mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET, 1996 SIZE_DEFAULT); 1997 mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); 1998 mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); 1999 } 2000 } 2001 2002 /** 2003 * Apply wearable extensions to a notification that is being built. This is typically 2004 * called by the {@link NotificationCompat.Builder#extend} method of 2005 * {@link NotificationCompat.Builder}. 2006 */ 2007 @Override 2008 public NotificationCompat.Builder extend(NotificationCompat.Builder builder) { 2009 Bundle wearableBundle = new Bundle(); 2010 2011 if (!mActions.isEmpty()) { 2012 wearableBundle.putParcelableArrayList(KEY_ACTIONS, 2013 IMPL.getParcelableArrayListForActions(mActions.toArray( 2014 new Action[mActions.size()]))); 2015 } 2016 if (mFlags != DEFAULT_FLAGS) { 2017 wearableBundle.putInt(KEY_FLAGS, mFlags); 2018 } 2019 if (mDisplayIntent != null) { 2020 wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent); 2021 } 2022 if (!mPages.isEmpty()) { 2023 wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray( 2024 new Notification[mPages.size()])); 2025 } 2026 if (mBackground != null) { 2027 wearableBundle.putParcelable(KEY_BACKGROUND, mBackground); 2028 } 2029 if (mContentIcon != 0) { 2030 wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon); 2031 } 2032 if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) { 2033 wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity); 2034 } 2035 if (mContentActionIndex != UNSET_ACTION_INDEX) { 2036 wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX, 2037 mContentActionIndex); 2038 } 2039 if (mCustomSizePreset != SIZE_DEFAULT) { 2040 wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset); 2041 } 2042 if (mCustomContentHeight != 0) { 2043 wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight); 2044 } 2045 if (mGravity != DEFAULT_GRAVITY) { 2046 wearableBundle.putInt(KEY_GRAVITY, mGravity); 2047 } 2048 2049 builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); 2050 return builder; 2051 } 2052 2053 @Override 2054 public WearableExtender clone() { 2055 WearableExtender that = new WearableExtender(); 2056 that.mActions = new ArrayList<Action>(this.mActions); 2057 that.mFlags = this.mFlags; 2058 that.mDisplayIntent = this.mDisplayIntent; 2059 that.mPages = new ArrayList<Notification>(this.mPages); 2060 that.mBackground = this.mBackground; 2061 that.mContentIcon = this.mContentIcon; 2062 that.mContentIconGravity = this.mContentIconGravity; 2063 that.mContentActionIndex = this.mContentActionIndex; 2064 that.mCustomSizePreset = this.mCustomSizePreset; 2065 that.mCustomContentHeight = this.mCustomContentHeight; 2066 that.mGravity = this.mGravity; 2067 return that; 2068 } 2069 2070 /** 2071 * Add a wearable action to this notification. 2072 * 2073 * <p>When wearable actions are added using this method, the set of actions that 2074 * show on a wearable device splits from devices that only show actions added 2075 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2076 * of which actions display on different devices. 2077 * 2078 * @param action the action to add to this notification 2079 * @return this object for method chaining 2080 * @see NotificationCompat.Action 2081 */ 2082 public WearableExtender addAction(Action action) { 2083 mActions.add(action); 2084 return this; 2085 } 2086 2087 /** 2088 * Adds wearable actions to this notification. 2089 * 2090 * <p>When wearable actions are added using this method, the set of actions that 2091 * show on a wearable device splits from devices that only show actions added 2092 * using {@link NotificationCompat.Builder#addAction}. This allows for customization 2093 * of which actions display on different devices. 2094 * 2095 * @param actions the actions to add to this notification 2096 * @return this object for method chaining 2097 * @see NotificationCompat.Action 2098 */ 2099 public WearableExtender addActions(List<Action> actions) { 2100 mActions.addAll(actions); 2101 return this; 2102 } 2103 2104 /** 2105 * Clear all wearable actions present on this builder. 2106 * @return this object for method chaining. 2107 * @see #addAction 2108 */ 2109 public WearableExtender clearActions() { 2110 mActions.clear(); 2111 return this; 2112 } 2113 2114 /** 2115 * Get the wearable actions present on this notification. 2116 */ 2117 public List<Action> getActions() { 2118 return mActions; 2119 } 2120 2121 /** 2122 * Set an intent to launch inside of an activity view when displaying 2123 * this notification. The {@link PendingIntent} provided should be for an activity. 2124 * 2125 * <pre class="prettyprint"> 2126 * Intent displayIntent = new Intent(context, MyDisplayActivity.class); 2127 * PendingIntent displayPendingIntent = PendingIntent.getActivity(context, 2128 * 0, displayIntent, PendingIntent.FLAG_UPDATE_CURRENT); 2129 * Notification notif = new NotificationCompat.Builder(context) 2130 * .extend(new NotificationCompat.WearableExtender() 2131 * .setDisplayIntent(displayPendingIntent) 2132 * .setCustomSizePreset(NotificationCompat.WearableExtender.SIZE_MEDIUM)) 2133 * .build();</pre> 2134 * 2135 * <p>The activity to launch needs to allow embedding, must be exported, and 2136 * should have an empty task affinity. 2137 * 2138 * <p>Example AndroidManifest.xml entry: 2139 * <pre class="prettyprint"> 2140 * <activity android:name="com.example.MyDisplayActivity" 2141 * android:exported="true" 2142 * android:allowEmbedded="true" 2143 * android:taskAffinity="" /></pre> 2144 * 2145 * @param intent the {@link PendingIntent} for an activity 2146 * @return this object for method chaining 2147 * @see NotificationCompat.WearableExtender#getDisplayIntent 2148 */ 2149 public WearableExtender setDisplayIntent(PendingIntent intent) { 2150 mDisplayIntent = intent; 2151 return this; 2152 } 2153 2154 /** 2155 * Get the intent to launch inside of an activity view when displaying this 2156 * notification. This {@code PendingIntent} should be for an activity. 2157 */ 2158 public PendingIntent getDisplayIntent() { 2159 return mDisplayIntent; 2160 } 2161 2162 /** 2163 * Add an additional page of content to display with this notification. The current 2164 * notification forms the first page, and pages added using this function form 2165 * subsequent pages. This field can be used to separate a notification into multiple 2166 * sections. 2167 * 2168 * @param page the notification to add as another page 2169 * @return this object for method chaining 2170 * @see NotificationCompat.WearableExtender#getPages 2171 */ 2172 public WearableExtender addPage(Notification page) { 2173 mPages.add(page); 2174 return this; 2175 } 2176 2177 /** 2178 * Add additional pages of content to display with this notification. The current 2179 * notification forms the first page, and pages added using this function form 2180 * subsequent pages. This field can be used to separate a notification into multiple 2181 * sections. 2182 * 2183 * @param pages a list of notifications 2184 * @return this object for method chaining 2185 * @see NotificationCompat.WearableExtender#getPages 2186 */ 2187 public WearableExtender addPages(List<Notification> pages) { 2188 mPages.addAll(pages); 2189 return this; 2190 } 2191 2192 /** 2193 * Clear all additional pages present on this builder. 2194 * @return this object for method chaining. 2195 * @see #addPage 2196 */ 2197 public WearableExtender clearPages() { 2198 mPages.clear(); 2199 return this; 2200 } 2201 2202 /** 2203 * Get the array of additional pages of content for displaying this notification. The 2204 * current notification forms the first page, and elements within this array form 2205 * subsequent pages. This field can be used to separate a notification into multiple 2206 * sections. 2207 * @return the pages for this notification 2208 */ 2209 public List<Notification> getPages() { 2210 return mPages; 2211 } 2212 2213 /** 2214 * Set a background image to be displayed behind the notification content. 2215 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2216 * will work with any notification style. 2217 * 2218 * @param background the background bitmap 2219 * @return this object for method chaining 2220 * @see NotificationCompat.WearableExtender#getBackground 2221 */ 2222 public WearableExtender setBackground(Bitmap background) { 2223 mBackground = background; 2224 return this; 2225 } 2226 2227 /** 2228 * Get a background image to be displayed behind the notification content. 2229 * Contrary to the {@link NotificationCompat.BigPictureStyle}, this background 2230 * will work with any notification style. 2231 * 2232 * @return the background image 2233 * @see NotificationCompat.WearableExtender#setBackground 2234 */ 2235 public Bitmap getBackground() { 2236 return mBackground; 2237 } 2238 2239 /** 2240 * Set an icon that goes with the content of this notification. 2241 */ 2242 public WearableExtender setContentIcon(int icon) { 2243 mContentIcon = icon; 2244 return this; 2245 } 2246 2247 /** 2248 * Get an icon that goes with the content of this notification. 2249 */ 2250 public int getContentIcon() { 2251 return mContentIcon; 2252 } 2253 2254 /** 2255 * Set the gravity that the content icon should have within the notification display. 2256 * Supported values include {@link android.view.Gravity#START} and 2257 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2258 * @see #setContentIcon 2259 */ 2260 public WearableExtender setContentIconGravity(int contentIconGravity) { 2261 mContentIconGravity = contentIconGravity; 2262 return this; 2263 } 2264 2265 /** 2266 * Get the gravity that the content icon should have within the notification display. 2267 * Supported values include {@link android.view.Gravity#START} and 2268 * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}. 2269 * @see #getContentIcon 2270 */ 2271 public int getContentIconGravity() { 2272 return mContentIconGravity; 2273 } 2274 2275 /** 2276 * Set an action from this notification's actions to be clickable with the content of 2277 * this notification. This action will no longer display separately from the 2278 * notification's content. 2279 * 2280 * <p>For notifications with multiple pages, child pages can also have content actions 2281 * set, although the list of available actions comes from the main notification and not 2282 * from the child page's notification. 2283 * 2284 * @param actionIndex The index of the action to hoist onto the current notification page. 2285 * If wearable actions were added to the main notification, this index 2286 * will apply to that list, otherwise it will apply to the regular 2287 * actions list. 2288 */ 2289 public WearableExtender setContentAction(int actionIndex) { 2290 mContentActionIndex = actionIndex; 2291 return this; 2292 } 2293 2294 /** 2295 * Get the index of the notification action, if any, that was specified as being clickable 2296 * with the content of this notification. This action will no longer display separately 2297 * from the notification's content. 2298 * 2299 * <p>For notifications with multiple pages, child pages can also have content actions 2300 * set, although the list of available actions comes from the main notification and not 2301 * from the child page's notification. 2302 * 2303 * <p>If wearable specific actions were added to the main notification, this index will 2304 * apply to that list, otherwise it will apply to the regular actions list. 2305 * 2306 * @return the action index or {@link #UNSET_ACTION_INDEX} if no action was selected. 2307 */ 2308 public int getContentAction() { 2309 return mContentActionIndex; 2310 } 2311 2312 /** 2313 * Set the gravity that this notification should have within the available viewport space. 2314 * Supported values include {@link android.view.Gravity#TOP}, 2315 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2316 * The default value is {@link android.view.Gravity#BOTTOM}. 2317 */ 2318 public WearableExtender setGravity(int gravity) { 2319 mGravity = gravity; 2320 return this; 2321 } 2322 2323 /** 2324 * Get the gravity that this notification should have within the available viewport space. 2325 * Supported values include {@link android.view.Gravity#TOP}, 2326 * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}. 2327 * The default value is {@link android.view.Gravity#BOTTOM}. 2328 */ 2329 public int getGravity() { 2330 return mGravity; 2331 } 2332 2333 /** 2334 * Set the custom size preset for the display of this notification out of the available 2335 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2336 * {@link #SIZE_LARGE}. 2337 * <p>Some custom size presets are only applicable for custom display notifications created 2338 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. Check the 2339 * documentation for the preset in question. See also 2340 * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}. 2341 */ 2342 public WearableExtender setCustomSizePreset(int sizePreset) { 2343 mCustomSizePreset = sizePreset; 2344 return this; 2345 } 2346 2347 /** 2348 * Get the custom size preset for the display of this notification out of the available 2349 * presets found in {@link NotificationCompat.WearableExtender}, e.g. 2350 * {@link #SIZE_LARGE}. 2351 * <p>Some custom size presets are only applicable for custom display notifications created 2352 * using {@link #setDisplayIntent}. Check the documentation for the preset in question. 2353 * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}. 2354 */ 2355 public int getCustomSizePreset() { 2356 return mCustomSizePreset; 2357 } 2358 2359 /** 2360 * Set the custom height in pixels for the display of this notification's content. 2361 * <p>This option is only available for custom display notifications created 2362 * using {@link NotificationCompat.WearableExtender#setDisplayIntent}. See also 2363 * {@link NotificationCompat.WearableExtender#setCustomSizePreset} and 2364 * {@link #getCustomContentHeight}. 2365 */ 2366 public WearableExtender setCustomContentHeight(int height) { 2367 mCustomContentHeight = height; 2368 return this; 2369 } 2370 2371 /** 2372 * Get the custom height in pixels for the display of this notification's content. 2373 * <p>This option is only available for custom display notifications created 2374 * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and 2375 * {@link #setCustomContentHeight}. 2376 */ 2377 public int getCustomContentHeight() { 2378 return mCustomContentHeight; 2379 } 2380 2381 /** 2382 * Set whether the scrolling position for the contents of this notification should start 2383 * at the bottom of the contents instead of the top when the contents are too long to 2384 * display within the screen. Default is false (start scroll at the top). 2385 */ 2386 public WearableExtender setStartScrollBottom(boolean startScrollBottom) { 2387 setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom); 2388 return this; 2389 } 2390 2391 /** 2392 * Get whether the scrolling position for the contents of this notification should start 2393 * at the bottom of the contents instead of the top when the contents are too long to 2394 * display within the screen. Default is false (start scroll at the top). 2395 */ 2396 public boolean getStartScrollBottom() { 2397 return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0; 2398 } 2399 2400 /** 2401 * Set whether the content intent is available when the wearable device is not connected 2402 * to a companion device. The user can still trigger this intent when the wearable device 2403 * is offline, but a visual hint will indicate that the content intent may not be available. 2404 * Defaults to true. 2405 */ 2406 public WearableExtender setContentIntentAvailableOffline( 2407 boolean contentIntentAvailableOffline) { 2408 setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline); 2409 return this; 2410 } 2411 2412 /** 2413 * Get whether the content intent is available when the wearable device is not connected 2414 * to a companion device. The user can still trigger this intent when the wearable device 2415 * is offline, but a visual hint will indicate that the content intent may not be available. 2416 * Defaults to true. 2417 */ 2418 public boolean getContentIntentAvailableOffline() { 2419 return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0; 2420 } 2421 2422 /** 2423 * Set a hint that this notification's icon should not be displayed. 2424 * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise. 2425 * @return this object for method chaining 2426 */ 2427 public WearableExtender setHintHideIcon(boolean hintHideIcon) { 2428 setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon); 2429 return this; 2430 } 2431 2432 /** 2433 * Get a hint that this notification's icon should not be displayed. 2434 * @return {@code true} if this icon should not be displayed, false otherwise. 2435 * The default value is {@code false} if this was never set. 2436 */ 2437 public boolean getHintHideIcon() { 2438 return (mFlags & FLAG_HINT_HIDE_ICON) != 0; 2439 } 2440 2441 /** 2442 * Set a visual hint that only the background image of this notification should be 2443 * displayed, and other semantic content should be hidden. This hint is only applicable 2444 * to sub-pages added using {@link #addPage}. 2445 */ 2446 public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) { 2447 setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly); 2448 return this; 2449 } 2450 2451 /** 2452 * Get a visual hint that only the background image of this notification should be 2453 * displayed, and other semantic content should be hidden. This hint is only applicable 2454 * to sub-pages added using {@link NotificationCompat.WearableExtender#addPage}. 2455 */ 2456 public boolean getHintShowBackgroundOnly() { 2457 return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0; 2458 } 2459 2460 private void setFlag(int mask, boolean value) { 2461 if (value) { 2462 mFlags |= mask; 2463 } else { 2464 mFlags &= ~mask; 2465 } 2466 } 2467 } 2468 2469 /** 2470 * Get an array of Notification objects from a parcelable array bundle field. 2471 * Update the bundle to have a typed array so fetches in the future don't need 2472 * to do an array copy. 2473 */ 2474 private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) { 2475 Parcelable[] array = bundle.getParcelableArray(key); 2476 if (array instanceof Notification[] || array == null) { 2477 return (Notification[]) array; 2478 } 2479 Notification[] typedArray = new Notification[array.length]; 2480 for (int i = 0; i < array.length; i++) { 2481 typedArray[i] = (Notification) array[i]; 2482 } 2483 bundle.putParcelableArray(key, typedArray); 2484 return typedArray; 2485 } 2486 2487 /** 2488 * Gets the {@link Notification#extras} field from a notification in a backwards 2489 * compatible manner. Extras field was supported from JellyBean (Api level 16) 2490 * forwards. This function will return null on older api levels. 2491 */ 2492 public static Bundle getExtras(Notification notif) { 2493 return IMPL.getExtras(notif); 2494 } 2495 2496 /** 2497 * Get the number of actions in this notification in a backwards compatible 2498 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2499 */ 2500 public static int getActionCount(Notification notif) { 2501 return IMPL.getActionCount(notif); 2502 } 2503 2504 /** 2505 * Get an action on this notification in a backwards compatible 2506 * manner. Actions were supported from JellyBean (Api level 16) forwards. 2507 * @param notif The notification to inspect. 2508 * @param actionIndex The index of the action to retrieve. 2509 */ 2510 public static Action getAction(Notification notif, int actionIndex) { 2511 return IMPL.getAction(notif, actionIndex); 2512 } 2513 2514 /** 2515 * Get whether or not this notification is only relevant to the current device. 2516 * 2517 * <p>Some notifications can be bridged to other devices for remote display. 2518 * If this hint is set, it is recommend that this notification not be bridged. 2519 */ 2520 public static boolean getLocalOnly(Notification notif) { 2521 return IMPL.getLocalOnly(notif); 2522 } 2523 2524 /** 2525 * Get the key used to group this notification into a cluster or stack 2526 * with other notifications on devices which support such rendering. 2527 */ 2528 public static String getGroup(Notification notif) { 2529 return IMPL.getGroup(notif); 2530 } 2531 2532 /** 2533 * Get whether this notification to be the group summary for a group of notifications. 2534 * Grouped notifications may display in a cluster or stack on devices which 2535 * support such rendering. Requires a group key also be set using {@link Builder#setGroup}. 2536 * @return Whether this notification is a group summary. 2537 */ 2538 public static boolean isGroupSummary(Notification notif) { 2539 return IMPL.isGroupSummary(notif); 2540 } 2541 2542 /** 2543 * Get a sort key that orders this notification among other notifications from the 2544 * same package. This can be useful if an external sort was already applied and an app 2545 * would like to preserve this. Notifications will be sorted lexicographically using this 2546 * value, although providing different priorities in addition to providing sort key may 2547 * cause this value to be ignored. 2548 * 2549 * <p>This sort key can also be used to order members of a notification group. See 2550 * {@link Builder#setGroup}. 2551 * 2552 * @see String#compareTo(String) 2553 */ 2554 public static String getSortKey(Notification notif) { 2555 return IMPL.getSortKey(notif); 2556 } 2557} 2558