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