1/* 2 * Copyright (C) 2015 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.app.recommendation; 18 19import android.app.Notification; 20import android.app.PendingIntent; 21import android.content.Context; 22import android.content.Intent; 23import android.graphics.Bitmap; 24import android.os.Bundle; 25import android.support.annotation.IntDef; 26import android.support.annotation.Nullable; 27import android.support.annotation.StringDef; 28import android.text.TextUtils; 29 30import java.util.Arrays; 31 32/** 33 * The ContentRecommendation object encapsulates all application provided data for a single content 34 * recommendation item. 35 */ 36public final class ContentRecommendation 37{ 38 @StringDef({ 39 CONTENT_TYPE_VIDEO, 40 CONTENT_TYPE_MOVIE, 41 CONTENT_TYPE_TRAILER, 42 CONTENT_TYPE_SERIAL, 43 CONTENT_TYPE_MUSIC, 44 CONTENT_TYPE_RADIO, 45 CONTENT_TYPE_PODCAST, 46 CONTENT_TYPE_NEWS, 47 CONTENT_TYPE_SPORTS, 48 CONTENT_TYPE_APP, 49 CONTENT_TYPE_GAME, 50 CONTENT_TYPE_BOOK, 51 CONTENT_TYPE_COMIC, 52 CONTENT_TYPE_MAGAZINE, 53 CONTENT_TYPE_WEBSITE, 54 }) 55 public @interface ContentType {} 56 57 /** 58 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 59 * by the notification item is a video clip. 60 */ 61 public static final String CONTENT_TYPE_VIDEO = "android.contentType.video"; 62 63 /** 64 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 65 * by the notification item is a movie. 66 */ 67 public static final String CONTENT_TYPE_MOVIE = "android.contentType.movie"; 68 69 /** 70 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 71 * by the notification item is a trailer. 72 */ 73 public static final String CONTENT_TYPE_TRAILER = "android.contentType.trailer"; 74 75 /** 76 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 77 * by the notification item is serial. It can refer to an entire show, a single season or 78 * series, or a single episode. 79 */ 80 public static final String CONTENT_TYPE_SERIAL = "android.contentType.serial"; 81 82 /** 83 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 84 * by the notification item is a song or album. 85 */ 86 public static final String CONTENT_TYPE_MUSIC = "android.contentType.music"; 87 88 /** 89 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 90 * by the notification item is a radio station. 91 */ 92 public static final String CONTENT_TYPE_RADIO = "android.contentType.radio"; 93 94 /** 95 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 96 * by the notification item is a podcast. 97 */ 98 public static final String CONTENT_TYPE_PODCAST = "android.contentType.podcast"; 99 100 /** 101 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 102 * by the notification item is a news item. 103 */ 104 public static final String CONTENT_TYPE_NEWS = "android.contentType.news"; 105 106 /** 107 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 108 * by the notification item is sports. 109 */ 110 public static final String CONTENT_TYPE_SPORTS = "android.contentType.sports"; 111 112 /** 113 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 114 * by the notification item is an application. 115 */ 116 public static final String CONTENT_TYPE_APP = "android.contentType.app"; 117 118 /** 119 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 120 * by the notification item is a game. 121 */ 122 public static final String CONTENT_TYPE_GAME = "android.contentType.game"; 123 124 /** 125 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 126 * by the notification item is a book. 127 */ 128 public static final String CONTENT_TYPE_BOOK = "android.contentType.book"; 129 130 /** 131 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 132 * by the notification item is a comic book. 133 */ 134 public static final String CONTENT_TYPE_COMIC = "android.contentType.comic"; 135 136 /** 137 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 138 * by the notification item is a magazine. 139 */ 140 public static final String CONTENT_TYPE_MAGAZINE = "android.contentType.magazine"; 141 142 /** 143 * Value to be used with {@link Builder#setContentTypes} to indicate that the content referred 144 * by the notification item is a website. 145 */ 146 public static final String CONTENT_TYPE_WEBSITE = "android.contentType.website"; 147 148 @StringDef({ 149 CONTENT_PRICING_FREE, 150 CONTENT_PRICING_RENTAL, 151 CONTENT_PRICING_PURCHASE, 152 CONTENT_PRICING_PREORDER, 153 CONTENT_PRICING_SUBSCRIPTION, 154 }) 155 public @interface ContentPricing {} 156 157 /** 158 * Value to be used with {@link Builder#setPricingInformation} to indicate that the content 159 * referred by the notification item is free to consume. 160 */ 161 public static final String CONTENT_PRICING_FREE = "android.contentPrice.free"; 162 163 /** 164 * Value to be used with {@link Builder#setPricingInformation} to indicate that the content 165 * referred by the notification item is available as a rental, and the price value provided is 166 * the rental price for the item. 167 */ 168 public static final String CONTENT_PRICING_RENTAL = "android.contentPrice.rental"; 169 170 /** 171 * Value to be used with {@link Builder#setPricingInformation} to indicate that the content 172 * referred by the notification item is available for purchase, and the price value provided is 173 * the purchase price for the item. 174 */ 175 public static final String CONTENT_PRICING_PURCHASE = "android.contentPrice.purchase"; 176 177 /** 178 * Value to be used with {@link Builder#setPricingInformation} to indicate that the content 179 * referred by the notification item is available currently as a pre-order, and the price value 180 * provided is the purchase price for the item. 181 */ 182 public static final String CONTENT_PRICING_PREORDER = "android.contentPrice.preorder"; 183 184 /** 185 * Value to be used with {@link Builder#setPricingInformation} to indicate that the content 186 * referred by the notification item is available as part of a subscription based service, and 187 * the price value provided is the subscription price for the service. 188 */ 189 public static final String CONTENT_PRICING_SUBSCRIPTION = 190 "android.contentPrice.subscription"; 191 192 @IntDef({ 193 CONTENT_STATUS_READY, 194 CONTENT_STATUS_PENDING, 195 CONTENT_STATUS_AVAILABLE, 196 CONTENT_STATUS_UNAVAILABLE, 197 }) 198 public @interface ContentStatus {} 199 200 /** 201 * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the 202 * notification is available and ready to be consumed immediately. 203 */ 204 public static final int CONTENT_STATUS_READY = 0; 205 206 /** 207 * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the 208 * notification is pending, waiting on either a download or purchase operation to complete 209 * before it can be consumed. 210 */ 211 public static final int CONTENT_STATUS_PENDING = 1; 212 213 /** 214 * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the 215 * notification is available, but needs to be first purchased, rented, subscribed or downloaded 216 * before it can be consumed. 217 */ 218 public static final int CONTENT_STATUS_AVAILABLE = 2; 219 220 /** 221 * Value to be used with {@link Builder#setStatus} to indicate that the content referred by the 222 * notification is not available. This could be content not available in a certain region or 223 * incompatible with the device in use. 224 */ 225 public static final int CONTENT_STATUS_UNAVAILABLE = 3; 226 227 @StringDef({ 228 CONTENT_MATURITY_ALL, 229 CONTENT_MATURITY_LOW, 230 CONTENT_MATURITY_MEDIUM, 231 CONTENT_MATURITY_HIGH, 232 }) 233 public @interface ContentMaturity {} 234 235 /** 236 * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred 237 * by the notification is suitable for all audiences. 238 */ 239 public static final String CONTENT_MATURITY_ALL = "android.contentMaturity.all"; 240 241 /** 242 * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred 243 * by the notification is suitable for audiences of low maturity and above. 244 */ 245 public static final String CONTENT_MATURITY_LOW = "android.contentMaturity.low"; 246 247 /** 248 * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred 249 * by the notification is suitable for audiences of medium maturity and above. 250 */ 251 public static final String CONTENT_MATURITY_MEDIUM = "android.contentMaturity.medium"; 252 253 /** 254 * Value to be used with {@link Builder#setMaturityRating} to indicate that the content referred 255 * by the notification is suitable for audiences of high maturity and above. 256 */ 257 public static final String CONTENT_MATURITY_HIGH = "android.contentMaturity.high"; 258 259 @IntDef({ 260 INTENT_TYPE_ACTIVITY, 261 INTENT_TYPE_BROADCAST, 262 INTENT_TYPE_SERVICE, 263 }) 264 public @interface IntentType { 265 } 266 267 /** 268 * Value to be used with {@link Builder#setContentIntentData} and 269 * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for an Activity 270 * should be created when posting the recommendation to the HomeScreen. 271 */ 272 public static final int INTENT_TYPE_ACTIVITY = 1; 273 274 /** 275 * Value to be used with {@link Builder#setContentIntentData} and 276 * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for a Broadcast 277 * should be created when posting the recommendation to the HomeScreen. 278 */ 279 public static final int INTENT_TYPE_BROADCAST = 2; 280 281 /** 282 * Value to be used with {@link Builder#setContentIntentData} and 283 * {@link Builder#setDismissIntentData} to indicate that a {@link PendingIntent} for a Service 284 * should be created when posting the recommendation to the HomeScreen. 285 */ 286 public static final int INTENT_TYPE_SERVICE = 3; 287 288 /** 289 * Object used to encapsulate the data to be used to build the {@link PendingIntent} object 290 * associated with a given content recommendation, at the time this recommendation gets posted 291 * to the home Screen. 292 * <p> 293 * The members of this object correspond to the fields passed into the {@link PendingIntent} 294 * factory methods, when creating a new PendingIntent. 295 */ 296 public static class IntentData { 297 int mType; 298 Intent mIntent; 299 int mRequestCode; 300 Bundle mOptions; 301 } 302 303 private final String mIdTag; 304 private final String mTitle; 305 private final String mText; 306 private final String mSourceName; 307 private final Bitmap mContentImage; 308 private final int mBadgeIconId; 309 private final String mBackgroundImageUri; 310 private final int mColor; 311 private final IntentData mContentIntentData; 312 private final IntentData mDismissIntentData; 313 private final String[] mContentTypes; 314 private final String[] mContentGenres; 315 private final String mPriceType; 316 private final String mPriceValue; 317 private final String mMaturityRating; 318 private final long mRunningTime; 319 320 // Mutable fields 321 private String mGroup; 322 private String mSortKey; 323 private int mProgressAmount; 324 private int mProgressMax; 325 private boolean mAutoDismiss; 326 private int mStatus; 327 328 private ContentRecommendation(Builder builder) { 329 mIdTag = builder.mBuilderIdTag; 330 mTitle = builder.mBuilderTitle; 331 mText = builder.mBuilderText; 332 mSourceName = builder.mBuilderSourceName; 333 mContentImage = builder.mBuilderContentImage; 334 mBadgeIconId = builder.mBuilderBadgeIconId; 335 mBackgroundImageUri = builder.mBuilderBackgroundImageUri; 336 mColor = builder.mBuilderColor; 337 mContentIntentData = builder.mBuilderContentIntentData; 338 mDismissIntentData = builder.mBuilderDismissIntentData; 339 mContentTypes = builder.mBuilderContentTypes; 340 mContentGenres = builder.mBuilderContentGenres; 341 mPriceType = builder.mBuilderPriceType; 342 mPriceValue = builder.mBuilderPriceValue; 343 mMaturityRating = builder.mBuilderMaturityRating; 344 mRunningTime = builder.mBuilderRunningTime; 345 346 mGroup = builder.mBuilderGroup; 347 mSortKey = builder.mBuilderSortKey; 348 mProgressAmount = builder.mBuilderProgressAmount; 349 mProgressMax = builder.mBuilderProgressMax; 350 mAutoDismiss = builder.mBuilderAutoDismiss; 351 mStatus = builder.mBuilderStatus; 352 } 353 354 /** 355 * Returns the String Id tag which uniquely identifies this recommendation. 356 * 357 * @return The String Id tag for this recommendation. 358 */ 359 public String getIdTag() { 360 return mIdTag; 361 } 362 363 /** 364 * Returns the content title for this recommendation. 365 * 366 * @return A String containing the recommendation content title. 367 */ 368 public String getTitle() { 369 return mTitle; 370 } 371 372 /** 373 * Returns the description text for this recommendation. 374 * 375 * @return A String containing the recommendation description text. 376 */ 377 public String getText() { 378 return mText; 379 } 380 381 /** 382 * Returns the source application name for this recommendation. 383 * 384 * @return A String containing the recommendation source name. 385 */ 386 public String getSourceName() { 387 return mSourceName; 388 } 389 390 /** 391 * Returns the Bitmap containing the recommendation image. 392 * 393 * @return A Bitmap containing the recommendation image. 394 */ 395 public Bitmap getContentImage() { 396 return mContentImage; 397 } 398 399 /** 400 * Returns the resource id for the recommendation badging icon. 401 * <p> 402 * The resource id represents the icon resource in the source application package. 403 * 404 * @return An integer id for the badge icon resource. 405 */ 406 public int getBadgeImageResourceId() { 407 return mBadgeIconId; 408 } 409 410 /** 411 * Returns a Content URI that can be used to retrieve the background image for this 412 * recommendation. 413 * 414 * @return A Content URI pointing to the recommendation background image. 415 */ 416 public String getBackgroundImageUri() { 417 return mBackgroundImageUri; 418 } 419 420 /** 421 * Returns the accent color value to be used in the UI when displaying this content 422 * recommendation to the user. 423 * 424 * @return An integer value representing the accent color for this recommendation. 425 */ 426 public int getColor() { 427 return mColor; 428 } 429 430 /** 431 * Sets the String group ID tag for this recommendation. 432 * <p> 433 * Recommendations in the same group are ranked by the Home Screen together, and the sort order 434 * within a group is respected. This can be useful if the application has different sources for 435 * recommendations, like "trending", "subscriptions", and "new music" categories for YouTube, 436 * where the user can be more interested in recommendations from one group than another. 437 * 438 * @param groupTag A String containing the group ID tag for this recommendation. 439 */ 440 public void setGroup(String groupTag) { 441 mGroup = groupTag; 442 } 443 444 /** 445 * Returns the String group ID tag for this recommendation. 446 * 447 * @return A String containing the group ID tag for this recommendation. 448 */ 449 public String getGroup() { 450 return mGroup; 451 } 452 453 /** 454 * Sets the String sort key for this recommendation. 455 * <p> 456 * The sort key must be a String representation of a float number between 0.0 and 1.0, and is 457 * used to indicate the relative importance (and sort order) of a single recommendation within 458 * its specified group. The recommendations will be ordered in decreasing order of importance 459 * within a given group. 460 * 461 * @param sortKey A String containing the sort key for this recommendation. 462 */ 463 public void setSortKey(String sortKey) { 464 mSortKey = sortKey; 465 } 466 467 /** 468 * Returns the String sort key for this recommendation. 469 * 470 * @return A String containing the sort key for this recommendation. 471 */ 472 public String getSortKey() { 473 return mSortKey; 474 } 475 476 /** 477 * Sets the progress information for the content pointed to by this recommendation. 478 * 479 * @param max The maximum value for the progress of this content. 480 * @param progress The progress amount for this content. Must be in the range (0 - max). 481 */ 482 public void setProgress(int max, int progress) { 483 if (max < 0 || progress < 0) { 484 throw new IllegalArgumentException(); 485 } 486 mProgressMax = max; 487 mProgressAmount = progress; 488 } 489 490 /** 491 * Indicates if this recommendation contains valid progress information. 492 * 493 * @return true if the recommendation contains valid progress data, false otherwise. 494 */ 495 public boolean hasProgressInfo() { 496 return mProgressMax != 0; 497 } 498 499 /** 500 * Returns the maximum value for the progress data of this recommendation. 501 * 502 * @return An integer representing the maximum progress value. 503 */ 504 public int getProgressMax() { 505 return mProgressMax; 506 } 507 508 /** 509 * Returns the progress amount for this recommendation. 510 * 511 * @return An integer representing the recommendation progress amount. 512 */ 513 public int getProgressValue() { 514 return mProgressAmount; 515 } 516 517 /** 518 * Sets the flag indicating if this recommendation should be dismissed automatically. 519 * <p> 520 * Auto-dismiss notifications are automatically removed from the Home Screen when the user 521 * clicks on them. 522 * 523 * @param autoDismiss A boolean indicating if the recommendation should be auto dismissed or 524 * not. 525 */ 526 public void setAutoDismiss(boolean autoDismiss) { 527 mAutoDismiss = autoDismiss; 528 } 529 530 /** 531 * Indicates whether this recommendation should be dismissed automatically. 532 * <p> 533 * Auto-dismiss notifications are automatically removed from the Home Screen when the user 534 * clicks on them. 535 * 536 * @return true if the recommendation is marked for auto dismissal, or false otherwise. 537 */ 538 public boolean isAutoDismiss() { 539 return mAutoDismiss; 540 } 541 542 /** 543 * Returns the data for the Intent that will be issued when the user clicks on the 544 * recommendation. 545 * 546 * @return An IntentData object, containing the data for the Intent that gets issued when the 547 * recommendation is clicked on. 548 */ 549 public IntentData getContentIntent() { 550 return mContentIntentData; 551 } 552 553 /** 554 * Returns the data for the Intent that will be issued when the recommendation gets dismissed 555 * from the Home Screen, due to an user action. 556 * 557 * @return An IntentData object, containing the data for the Intent that gets issued when the 558 * recommendation is dismissed from the Home Screen. 559 */ 560 public IntentData getDismissIntent() { 561 return mDismissIntentData; 562 } 563 564 /** 565 * Returns an array containing the content types tags that describe the content. The first tag 566 * entry is considered the primary type for the content, and is used for content ranking 567 * purposes. 568 * 569 * @return An array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) that 570 * describe the recommended content. 571 */ 572 public String[] getContentTypes() { 573 if (mContentTypes != null) { 574 return Arrays.copyOf(mContentTypes, mContentTypes.length); 575 } 576 return mContentTypes; 577 } 578 579 /** 580 * Returns the primary content type tag for the recommendation, or null if no content types have 581 * been specified. 582 * 583 * @return A predefined type tag (see the <code>CONTENT_TYPE_*</code> constants) indicating the 584 * primary content type for the recommendation. 585 */ 586 public String getPrimaryContentType() { 587 if (mContentTypes != null && mContentTypes.length > 0) { 588 return mContentTypes[0]; 589 } 590 return null; 591 } 592 593 /** 594 * Returns an array containing the genres that describe the content. Genres are open ended 595 * String tags. 596 * 597 * @return An array of genre tags that describe the recommended content. 598 */ 599 public String[] getGenres() { 600 if (mContentGenres != null) { 601 return Arrays.copyOf(mContentGenres, mContentGenres.length); 602 } 603 return mContentGenres; 604 } 605 606 /** 607 * Gets the pricing type for the content. 608 * 609 * @return A predefined tag indicating the pricing type for the content (see the <code> 610 * CONTENT_PRICING_*</code> constants). 611 */ 612 public String getPricingType() { 613 return mPriceType; 614 } 615 616 /** 617 * Gets the price value (when applicable) for the content. The value will be provided as a 618 * String containing the price in the appropriate currency for the current locale. 619 * 620 * @return A string containing a representation of the content price in the current locale and 621 * currency. 622 */ 623 public String getPricingValue() { 624 return mPriceValue; 625 } 626 627 /** 628 * Sets the availability status value for the content. This status indicates whether the content 629 * is ready to be consumed on the device, or if the user must first purchase, rent, subscribe 630 * to, or download the content. 631 * 632 * @param status The status value for the content. (see the <code>CONTENT_STATUS_*</code> for 633 * the valid status values). 634 */ 635 public void setStatus(@ContentStatus int status) { 636 mStatus = status; 637 } 638 639 /** 640 * Returns availability status value for the content. This status indicates whether the content 641 * is ready to be consumed on the device, or if the user must first purchase, rent, subscribe 642 * to, or download the content. 643 * 644 * @return The status value for the content, or -1 is a valid status has not been specified (see 645 * the <code>CONTENT_STATUS_*</code> constants for the valid status values). 646 */ 647 public int getStatus() { 648 return mStatus; 649 } 650 651 /** 652 * Returns the maturity level rating for the content. 653 * 654 * @return returns a predefined tag indicating the maturity level rating for the content (see 655 * the <code>CONTENT_MATURITY_*</code> constants). 656 */ 657 public String getMaturityRating() { 658 return mMaturityRating; 659 } 660 661 /** 662 * Returns the running time for the content. 663 * 664 * @return The run length, in seconds, of the content associated with the notification. 665 */ 666 public long getRunningTime() { 667 return mRunningTime; 668 } 669 670 @Override 671 public boolean equals(Object other) { 672 if (other instanceof ContentRecommendation) { 673 return TextUtils.equals(mIdTag, ((ContentRecommendation) other).getIdTag()); 674 } 675 return false; 676 } 677 678 @Override 679 public int hashCode() { 680 if (mIdTag != null) { 681 return mIdTag.hashCode(); 682 } 683 return Integer.MAX_VALUE; 684 } 685 686 /** 687 * Builder class for {@link ContentRecommendation} objects. Provides a convenient way to set the 688 * various fields of a {@link ContentRecommendation}. 689 * <p> 690 * Example: 691 * 692 * <pre class="prettyprint"> 693 * ContentRecommendation rec = new ContentRecommendation.Builder() 694 * .setIdInfo(id, "MyTagId") 695 * .setTitle("My Content Recommendation") 696 * .setText("An example of content recommendation") 697 * .setContentImage(myBitmap) 698 * .setBadgeIcon(R.drawable.app_icon) 699 * .setGroup("Trending") 700 * .build(); 701 * </pre> 702 */ 703 public static final class Builder { 704 private String mBuilderIdTag; 705 private String mBuilderTitle; 706 private String mBuilderText; 707 private String mBuilderSourceName; 708 private Bitmap mBuilderContentImage; 709 private int mBuilderBadgeIconId; 710 private String mBuilderBackgroundImageUri; 711 private int mBuilderColor; 712 private String mBuilderGroup; 713 private String mBuilderSortKey; 714 private int mBuilderProgressAmount; 715 private int mBuilderProgressMax; 716 private boolean mBuilderAutoDismiss; 717 private IntentData mBuilderContentIntentData; 718 private IntentData mBuilderDismissIntentData; 719 private String[] mBuilderContentTypes; 720 private String[] mBuilderContentGenres; 721 private String mBuilderPriceType; 722 private String mBuilderPriceValue; 723 private int mBuilderStatus; 724 private String mBuilderMaturityRating; 725 private long mBuilderRunningTime; 726 727 /** 728 * Constructs a new Builder. 729 * 730 */ 731 public Builder() { 732 } 733 734 /** 735 * Sets the Id tag that uniquely identifies this recommendation object. 736 * 737 * @param idTag A String tag identifier for this recommendation. 738 * @return The Builder object, for chaining. 739 */ 740 public Builder setIdTag(String idTag) { 741 mBuilderIdTag = checkNotNull(idTag); 742 return this; 743 } 744 745 /** 746 * Sets the content title for the recommendation. 747 * 748 * @param title A String containing the recommendation content title. 749 * @return The Builder object, for chaining. 750 */ 751 public Builder setTitle(String title) { 752 mBuilderTitle = checkNotNull(title); 753 return this; 754 } 755 756 /** 757 * Sets the description text for the recommendation. 758 * 759 * @param description A String containing the recommendation description text. 760 * @return The Builder object, for chaining. 761 */ 762 public Builder setText(@Nullable String description) { 763 mBuilderText = description; 764 return this; 765 } 766 767 /** 768 * Sets the source application name for the recommendation. 769 * <P> 770 * If the source name is never set, or set to null, the application name retrieved from its 771 * package will be used by default. 772 * 773 * @param source A String containing the recommendation source name. 774 * @return The Builder object, for chaining. 775 */ 776 public Builder setSourceName(@Nullable String source) { 777 mBuilderSourceName = source; 778 return this; 779 } 780 781 /** 782 * Sets the recommendation image. 783 * 784 * @param image A Bitmap containing the recommendation image. 785 * @return The Builder object, for chaining. 786 */ 787 public Builder setContentImage(Bitmap image) { 788 mBuilderContentImage = checkNotNull(image); 789 return this; 790 } 791 792 /** 793 * Sets the resource ID for the recommendation badging icon. 794 * <p> 795 * The resource id represents the icon resource in the source application package. If not 796 * set, or an invalid resource ID is specified, the application icon retrieved from its 797 * package will be used by default. 798 * 799 * @param iconResourceId An integer id for the badge icon resource. 800 * @return The Builder object, for chaining. 801 */ 802 public Builder setBadgeIcon(int iconResourceId) { 803 mBuilderBadgeIconId = iconResourceId; 804 return this; 805 } 806 807 /** 808 * Sets the Content URI that will be used to retrieve the background image for the 809 * recommendation. 810 * 811 * @param imageUri A Content URI pointing to the recommendation background image. 812 * @return The Builder object, for chaining. 813 */ 814 public Builder setBackgroundImageUri(@Nullable String imageUri) { 815 mBuilderBackgroundImageUri = imageUri; 816 return this; 817 } 818 819 /** 820 * Sets the accent color value to be used in the UI when displaying this content 821 * recommendation to the user. 822 * 823 * @param color An integer value representing the accent color for this recommendation. 824 * @return The Builder object, for chaining. 825 */ 826 public Builder setColor(int color) { 827 mBuilderColor = color; 828 return this; 829 } 830 831 /** 832 * Sets the String group ID tag for the recommendation. 833 * <p> 834 * Recommendations in the same group are ranked by the Home Screen together, and the sort 835 * order within a group is respected. This can be useful if the application has different 836 * sources for recommendations, like "trending", "subscriptions", and "new music" categories 837 * for YouTube, where the user can be more interested in recommendations from one group than 838 * another. 839 * 840 * @param groupTag A String containing the group ID tag for this recommendation. 841 * @return The Builder object, for chaining. 842 */ 843 public Builder setGroup(@Nullable String groupTag) { 844 mBuilderGroup = groupTag; 845 return this; 846 } 847 848 /** 849 * Sets the String sort key for the recommendation. 850 * <p> 851 * The sort key must be a String representation of a float number between 0.0 and 1.0, and 852 * is used to indicate the relative importance (and sort order) of a single recommendation 853 * within its specified group. The recommendations will be ordered in decreasing order of 854 * importance within a given group. 855 * 856 * @param sortKey A String containing the sort key for this recommendation. 857 * @return The Builder object, for chaining. 858 */ 859 public Builder setSortKey(@Nullable String sortKey) { 860 mBuilderSortKey = sortKey; 861 return this; 862 } 863 864 /** 865 * Sets the progress information for the content pointed to by the recommendation. 866 * 867 * @param max The maximum value for the progress of this content. 868 * @param progress The progress amount for this content. Must be in the range (0 - max). 869 * @return The Builder object, for chaining. 870 */ 871 public Builder setProgress(int max, int progress) { 872 if (max < 0 || progress < 0) { 873 throw new IllegalArgumentException(); 874 } 875 mBuilderProgressMax = max; 876 mBuilderProgressAmount = progress; 877 return this; 878 } 879 880 /** 881 * Sets the flag indicating if the recommendation should be dismissed automatically. 882 * <p> 883 * Auto-dismiss notifications are automatically removed from the Home Screen when the user 884 * clicks on them. 885 * 886 * @param autoDismiss A boolean indicating if the recommendation should be auto dismissed or 887 * not. 888 * @return The Builder object, for chaining. 889 */ 890 public Builder setAutoDismiss(boolean autoDismiss) { 891 mBuilderAutoDismiss = autoDismiss; 892 return this; 893 } 894 895 /** 896 * Sets the data for the Intent that will be issued when the user clicks on the 897 * recommendation. 898 * <p> 899 * The Intent data fields provided correspond to the fields passed into the 900 * {@link PendingIntent} factory methods, when creating a new PendingIntent. The actual 901 * PengindIntent object will only be created at the time a recommendation is posted to the 902 * Home Screen. 903 * 904 * @param intentType The type of {@link PendingIntent} to be created when posting this 905 * recommendation. 906 * @param intent The Intent which to be issued when the recommendation is clicked on. 907 * @param requestCode The private request code to be used when creating the 908 * {@link PendingIntent} 909 * @param options Only used for the Activity Intent type. Additional options for how the 910 * Activity should be started. May be null if there are no options. 911 * @return The Builder object, for chaining. 912 */ 913 public Builder setContentIntentData(@IntentType int intentType, Intent intent, 914 int requestCode, @Nullable Bundle options) { 915 if (intentType != INTENT_TYPE_ACTIVITY && 916 intentType != INTENT_TYPE_BROADCAST && 917 intentType != INTENT_TYPE_SERVICE) { 918 throw new IllegalArgumentException("Invalid Intent type specified."); 919 } 920 921 mBuilderContentIntentData = new IntentData(); 922 mBuilderContentIntentData.mType = intentType; 923 mBuilderContentIntentData.mIntent = checkNotNull(intent); 924 mBuilderContentIntentData.mRequestCode = requestCode; 925 mBuilderContentIntentData.mOptions = options; 926 927 return this; 928 } 929 930 /** 931 * Sets the data for the Intent that will be issued when the recommendation gets dismissed 932 * from the Home Screen, due to an user action. 933 * <p> 934 * The Intent data fields provided correspond to the fields passed into the 935 * {@link PendingIntent} factory methods, when creating a new PendingIntent. The actual 936 * PengindIntent object will only be created at the time a recommendation is posted to the 937 * Home Screen. 938 * 939 * @param intentType The type of {@link PendingIntent} to be created when posting this 940 * recommendation. 941 * @param intent The Intent which gets issued when the recommendation is dismissed from the 942 * Home Screen. 943 * @param requestCode The private request code to be used when creating the 944 * {@link PendingIntent} 945 * @param options Only used for the Activity Intent type. Additional options for how the 946 * Activity should be started. May be null if there are no options. 947 * @return The Builder object, for chaining. 948 */ 949 public Builder setDismissIntentData(@IntentType int intentType, @Nullable Intent intent, 950 int requestCode, @Nullable Bundle options) { 951 if (intent != null) { 952 if (intentType != INTENT_TYPE_ACTIVITY && 953 intentType != INTENT_TYPE_BROADCAST && 954 intentType != INTENT_TYPE_SERVICE) { 955 throw new IllegalArgumentException("Invalid Intent type specified."); 956 } 957 958 mBuilderDismissIntentData = new IntentData(); 959 mBuilderDismissIntentData.mType = intentType; 960 mBuilderDismissIntentData.mIntent = intent; 961 mBuilderDismissIntentData.mRequestCode = requestCode; 962 mBuilderDismissIntentData.mOptions = options; 963 } else { 964 mBuilderDismissIntentData = null; 965 } 966 return this; 967 } 968 969 /** 970 * Sets the content types associated with the content recommendation. The first tag entry 971 * will be considered the primary type for the content and will be used for ranking 972 * purposes. Other secondary type tags may be provided, if applicable, and may be used for 973 * filtering purposes. 974 * 975 * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code> 976 * constants) that describe the recommended content. 977 */ 978 public Builder setContentTypes(String[] types) { 979 mBuilderContentTypes = checkNotNull(types); 980 return this; 981 } 982 983 /** 984 * Sets the content genres for the recommendation. These genres may be used for content 985 * ranking. Genres are open ended String tags. 986 * <p> 987 * Some examples: "comedy", "action", "dance", "electronica", "racing", etc. 988 * 989 * @param genres Array of genre string tags that describe the recommended content. 990 */ 991 public Builder setGenres(String[] genres) { 992 mBuilderContentGenres = genres; 993 return this; 994 } 995 996 /** 997 * Sets the pricing and availability information for the recommendation. The provided 998 * information will indicate the access model for the content (free, rental, purchase or 999 * subscription) and the price value (if not free). 1000 * 1001 * @param priceType Pricing type for this content. Must be one of the predefined pricing 1002 * type tags (see the <code>CONTENT_PRICING_*</code> constants). 1003 * @param priceValue A string containing a representation of the content price in the 1004 * current locale and currency. 1005 */ 1006 public Builder setPricingInformation(@ContentPricing String priceType, 1007 @Nullable String priceValue) { 1008 mBuilderPriceType = checkNotNull(priceType); 1009 mBuilderPriceValue = priceValue; 1010 return this; 1011 } 1012 1013 /** 1014 * Sets the availability status for the content. This status indicates whether the referred 1015 * content is ready to be consumed on the device, or if the user must first purchase, rent, 1016 * subscribe to, or download the content. 1017 * 1018 * @param contentStatus The status value for this content. Must be one of the predefined 1019 * content status values (see the <code>CONTENT_STATUS_*</code> constants). 1020 */ 1021 public Builder setStatus(@ContentStatus int contentStatus) { 1022 mBuilderStatus = contentStatus; 1023 return this; 1024 } 1025 1026 /** 1027 * Sets the maturity level rating for the content. 1028 * 1029 * @param maturityRating A tag indicating the maturity level rating for the content. This 1030 * tag must be one of the predefined maturity rating tags (see the <code> 1031 * CONTENT_MATURITY_*</code> constants). 1032 */ 1033 public Builder setMaturityRating(@ContentMaturity String maturityRating) { 1034 mBuilderMaturityRating = checkNotNull(maturityRating); 1035 return this; 1036 } 1037 1038 /** 1039 * Sets the running time (when applicable) for the content. 1040 * 1041 * @param length The running time, in seconds, of the content. 1042 */ 1043 public Builder setRunningTime(long length) { 1044 if (length < 0) { 1045 throw new IllegalArgumentException(); 1046 } 1047 mBuilderRunningTime = length; 1048 return this; 1049 } 1050 1051 /** 1052 * Combine all of the options that have been set and return a new 1053 * {@link ContentRecommendation} object. 1054 */ 1055 public ContentRecommendation build() { 1056 return new ContentRecommendation(this); 1057 } 1058 } 1059 1060 /** 1061 * Returns a {@link android.app.Notification Notification} object which contains the content 1062 * recommendation data encapsulated by this object, which can be used for posting the 1063 * recommendation via the {@link android.app.NotificationManager NotificationManager}. 1064 * 1065 * @param context A {@link Context} that will be used to construct the 1066 * {@link android.app.Notification Notification} object which will carry the 1067 * recommendation data. 1068 * @return A {@link android.app.Notification Notification} containing the stored recommendation 1069 * data. 1070 */ 1071 public Notification getNotificationObject(Context context) { 1072 Notification.Builder builder = new Notification.Builder(context); 1073 RecommendationExtender recExtender = new RecommendationExtender(); 1074 1075 // Encode all the content recommendation data in a Notification object 1076 1077 builder.setCategory(Notification.CATEGORY_RECOMMENDATION); 1078 builder.setContentTitle(mTitle); 1079 builder.setContentText(mText); 1080 builder.setContentInfo(mSourceName); 1081 builder.setLargeIcon(mContentImage); 1082 builder.setSmallIcon(mBadgeIconId); 1083 if (mBackgroundImageUri != null) { 1084 builder.getExtras().putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, 1085 mBackgroundImageUri); 1086 } 1087 builder.setColor(mColor); 1088 builder.setGroup(mGroup); 1089 builder.setSortKey(mSortKey); 1090 builder.setProgress(mProgressMax, mProgressAmount, false); 1091 builder.setAutoCancel(mAutoDismiss); 1092 1093 if (mContentIntentData != null) { 1094 PendingIntent contentPending; 1095 if (mContentIntentData.mType == INTENT_TYPE_ACTIVITY) { 1096 contentPending = PendingIntent.getActivity(context, mContentIntentData.mRequestCode, 1097 mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT, 1098 mContentIntentData.mOptions); 1099 } else if (mContentIntentData.mType == INTENT_TYPE_SERVICE) { 1100 contentPending = PendingIntent.getService(context, mContentIntentData.mRequestCode, 1101 mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT); 1102 } else { // Default:INTENT_TYPE_BROADCAST{ 1103 contentPending = PendingIntent.getBroadcast(context, 1104 mContentIntentData.mRequestCode, 1105 mContentIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT); 1106 } 1107 builder.setContentIntent(contentPending); 1108 } 1109 1110 if (mDismissIntentData != null) { 1111 PendingIntent dismissPending; 1112 if (mDismissIntentData.mType == INTENT_TYPE_ACTIVITY) { 1113 dismissPending = PendingIntent.getActivity(context, mDismissIntentData.mRequestCode, 1114 mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT, 1115 mDismissIntentData.mOptions); 1116 } else if (mDismissIntentData.mType == INTENT_TYPE_SERVICE) { 1117 dismissPending = PendingIntent.getService(context, mDismissIntentData.mRequestCode, 1118 mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT); 1119 } else { // Default:INTENT_TYPE_BROADCAST{ 1120 dismissPending = PendingIntent.getBroadcast(context, 1121 mDismissIntentData.mRequestCode, 1122 mDismissIntentData.mIntent, PendingIntent.FLAG_UPDATE_CURRENT); 1123 } 1124 builder.setDeleteIntent(dismissPending); 1125 } 1126 1127 recExtender.setContentTypes(mContentTypes); 1128 recExtender.setGenres(mContentGenres); 1129 recExtender.setPricingInformation(mPriceType, mPriceValue); 1130 recExtender.setStatus(mStatus); 1131 recExtender.setMaturityRating(mMaturityRating); 1132 recExtender.setRunningTime(mRunningTime); 1133 1134 builder.extend(recExtender); 1135 Notification notif = builder.build(); 1136 return notif; 1137 } 1138 1139 /** 1140 * Ensures that an object reference passed as a parameter to the calling method is not null. 1141 * 1142 * @param reference an object reference 1143 * @return the non-null reference that was validated 1144 * @throws NullPointerException if {@code reference} is null 1145 */ 1146 private static <T> T checkNotNull(final T reference) { 1147 if (reference == null) { 1148 throw new NullPointerException(); 1149 } 1150 return reference; 1151 } 1152 1153}