1 /* 2 * Copyright 2018 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 17 package androidx.recommendation.app; 18 19 import android.app.Notification; 20 import android.os.Bundle; 21 22 /** 23 * <p> 24 * Helper class to add content info extensions to notifications. To create a notification with 25 * content info extensions: 26 * <ol> 27 * <li>Create an {@link Notification.Builder}, setting any desired properties. 28 * <li>Create a {@link RecommendationExtender}. 29 * <li>Set content info specific properties using the {@code add} and {@code set} methods of 30 * {@link RecommendationExtender}. 31 * <li>Call {@link android.app.Notification.Builder#extend(Notification.Extender) 32 * Notification.Builder.extend(Notification.Extender)} to apply the extensions to a notification. 33 * </ol> 34 * 35 * <pre class="prettyprint">Notification notification = new Notification.Builder(context) * ... * .extend(new RecommendationExtender() * .set*(...)) * .build(); * </pre> 36 * <p> 37 * Content info extensions can be accessed on an existing notification by using the 38 * {@code RecommendationExtender(Notification)} constructor, and then using the {@code get} methods 39 * to access values. 40 */ 41 public final class RecommendationExtender implements Notification.Extender { 42 private static final String TAG = "RecommendationExtender"; 43 44 // Key for the Content info extensions bundle in the main Notification extras bundle 45 private static final String EXTRA_CONTENT_INFO_EXTENDER = "android.CONTENT_INFO_EXTENSIONS"; 46 47 // Keys within EXTRA_CONTENT_INFO_EXTENDER for individual content info options. 48 49 private static final String KEY_CONTENT_TYPE = "android.contentType"; 50 51 private static final String KEY_CONTENT_GENRES = "android.contentGenre"; 52 53 private static final String KEY_CONTENT_PRICING_TYPE = "android.contentPricing.type"; 54 55 private static final String KEY_CONTENT_PRICING_VALUE = "android.contentPricing.value"; 56 57 private static final String KEY_CONTENT_STATUS = "android.contentStatus"; 58 59 private static final String KEY_CONTENT_MATURITY_RATING = "android.contentMaturity"; 60 61 private static final String KEY_CONTENT_RUN_LENGTH = "android.contentLength"; 62 63 private String[] mTypes; 64 private String[] mGenres; 65 private String mPricingType; 66 private String mPricingValue; 67 private int mContentStatus = -1; 68 private String mMaturityRating; 69 private long mRunLength = -1; 70 71 /** 72 * Create a {@link RecommendationExtender} with default options. 73 */ 74 public RecommendationExtender() { 75 } 76 77 /** 78 * Create a {@link RecommendationExtender} from the RecommendationExtender options of an 79 * existing Notification. 80 * 81 * @param notif The notification from which to copy options. 82 */ 83 public RecommendationExtender(Notification notif) { 84 Bundle contentBundle = notif.extras == null ? 85 null : notif.extras.getBundle(EXTRA_CONTENT_INFO_EXTENDER); 86 if (contentBundle != null) { 87 mTypes = contentBundle.getStringArray(KEY_CONTENT_TYPE); 88 mGenres = contentBundle.getStringArray(KEY_CONTENT_GENRES); 89 mPricingType = contentBundle.getString(KEY_CONTENT_PRICING_TYPE); 90 mPricingValue = contentBundle.getString(KEY_CONTENT_PRICING_VALUE); 91 mContentStatus = contentBundle.getInt(KEY_CONTENT_STATUS, -1); 92 mMaturityRating = contentBundle.getString(KEY_CONTENT_MATURITY_RATING); 93 mRunLength = contentBundle.getLong(KEY_CONTENT_RUN_LENGTH, -1); 94 } 95 } 96 97 /** 98 * Apply content extensions to a notification that is being built. This is typically called by 99 * the {@link android.app.Notification.Builder#extend(Notification.Extender) 100 * Notification.Builder.extend(Notification.Extender)} method of {@link Notification.Builder}. 101 */ 102 @Override 103 public Notification.Builder extend(Notification.Builder builder) { 104 Bundle contentBundle = new Bundle(); 105 106 if (mTypes != null) { 107 contentBundle.putStringArray(KEY_CONTENT_TYPE, mTypes); 108 } 109 if (mGenres != null) { 110 contentBundle.putStringArray(KEY_CONTENT_GENRES, mGenres); 111 } 112 if (mPricingType != null) { 113 contentBundle.putString(KEY_CONTENT_PRICING_TYPE, mPricingType); 114 } 115 if (mPricingValue != null) { 116 contentBundle.putString(KEY_CONTENT_PRICING_VALUE, mPricingValue); 117 } 118 if (mContentStatus != -1) { 119 contentBundle.putInt(KEY_CONTENT_STATUS, mContentStatus); 120 } 121 if (mMaturityRating != null) { 122 contentBundle.putString(KEY_CONTENT_MATURITY_RATING, mMaturityRating); 123 } 124 if (mRunLength > 0) { 125 contentBundle.putLong(KEY_CONTENT_RUN_LENGTH, mRunLength); 126 } 127 128 builder.getExtras().putBundle(EXTRA_CONTENT_INFO_EXTENDER, contentBundle); 129 return builder; 130 } 131 132 /** 133 * Sets the content types associated with the notification content. The first tag entry will be 134 * considered the primary type for the content and will be used for ranking purposes. Other 135 * secondary type tags may be provided, if applicable, and may be used for filtering purposes. 136 * 137 * @param types Array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) 138 * that describe the content referred to by a notification. 139 */ 140 public RecommendationExtender setContentTypes(String[] types) { 141 mTypes = types; 142 return this; 143 } 144 145 /** 146 * Returns an array containing the content types that describe the content associated with the 147 * notification. The first tag entry is considered the primary type for the content, and is used 148 * for content ranking purposes. 149 * 150 * @return An array of predefined type tags (see the <code>CONTENT_TYPE_*</code> constants) that 151 * describe the content associated with the notification. 152 * @see RecommendationExtender#setContentTypes 153 */ 154 public String[] getContentTypes() { 155 return mTypes; 156 } 157 158 /** 159 * Returns the primary content type tag for the content associated with the notification. 160 * 161 * @return A predefined type tag (see the <code>CONTENT_TYPE_*</code> constants) indicating the 162 * primary type for the content associated with the notification. 163 * @see RecommendationExtender#setContentTypes 164 */ 165 public String getPrimaryContentType() { 166 if (mTypes == null || mTypes.length == 0) { 167 return null; 168 } 169 return mTypes[0]; 170 } 171 172 /** 173 * Sets the content genres associated with the notification content. These genres may be used 174 * for content ranking. Genres are open ended String tags. 175 * <p> 176 * Some examples: "comedy", "action", "dance", "electronica", "racing", etc. 177 * 178 * @param genres Array of genre string tags that describe the content referred to by a 179 * notification. 180 */ 181 public RecommendationExtender setGenres(String[] genres) { 182 mGenres = genres; 183 return this; 184 } 185 186 /** 187 * Returns an array containing the content genres that describe the content associated with the 188 * notification. 189 * 190 * @return An array of genre tags that describe the content associated with the notification. 191 * @see RecommendationExtender#setGenres 192 */ 193 public String[] getGenres() { 194 return mGenres; 195 } 196 197 /** 198 * Sets the pricing and availability information for the content associated with the 199 * notification. The provided information will indicate the access model for the content (free, 200 * rental, purchase or subscription) and the price value (if not free). 201 * 202 * @param priceType Pricing type for this content. Must be one of the predefined pricing type 203 * tags (see the <code>CONTENT_PRICING_*</code> constants). 204 * @param priceValue A string containing a representation of the content price in the current 205 * locale and currency. 206 * @return This object for method chaining. 207 */ 208 public RecommendationExtender setPricingInformation( 209 @ContentRecommendation.ContentPricing String priceType, String priceValue) { 210 mPricingType = priceType; 211 mPricingValue = priceValue; 212 return this; 213 } 214 215 /** 216 * Gets the pricing type for the content associated with the notification. 217 * 218 * @return A predefined tag indicating the pricing type for the content (see the <code> CONTENT_PRICING_*</code> 219 * constants). 220 * @see RecommendationExtender#setPricingInformation 221 */ 222 public String getPricingType() { 223 return mPricingType; 224 } 225 226 /** 227 * Gets the price value (when applicable) for the content associated with a notification. The 228 * value will be provided as a String containing the price in the appropriate currency for the 229 * current locale. 230 * 231 * @return A string containing a representation of the content price in the current locale and 232 * currency. 233 * @see RecommendationExtender#setPricingInformation 234 */ 235 public String getPricingValue() { 236 if (mPricingType == null) { 237 return null; 238 } 239 return mPricingValue; 240 } 241 242 /** 243 * Sets the availability status for the content associated with the notification. This status 244 * indicates whether the referred content is ready to be consumed on the device, or if the user 245 * must first purchase, rent, subscribe to, or download the content. 246 * 247 * @param contentStatus The status value for this content. Must be one of the predefined content 248 * status values (see the <code>CONTENT_STATUS_*</code> constants). 249 */ 250 public RecommendationExtender setStatus( 251 @ContentRecommendation.ContentStatus int contentStatus) { 252 mContentStatus = contentStatus; 253 return this; 254 } 255 256 /** 257 * Returns status value for the content associated with the notification. This status indicates 258 * whether the referred content is ready to be consumed on the device, or if the user must first 259 * purchase, rent, subscribe to, or download the content. 260 * 261 * @return The status value for this content, or -1 is a valid status has not been specified 262 * (see the <code>CONTENT_STATUS_*</code> for the defined valid status values). 263 * @see RecommendationExtender#setStatus 264 */ 265 public int getStatus() { 266 return mContentStatus; 267 } 268 269 /** 270 * Sets the maturity level rating for the content associated with the notification. 271 * 272 * @param maturityRating A tag indicating the maturity level rating for the content. This tag 273 * must be one of the predefined maturity rating tags (see the <code> CONTENT_MATURITY_*</code> 274 * constants). 275 */ 276 public RecommendationExtender setMaturityRating( 277 @ContentRecommendation.ContentMaturity String maturityRating) { 278 mMaturityRating = maturityRating; 279 return this; 280 } 281 282 /** 283 * Returns the maturity level rating for the content associated with the notification. 284 * 285 * @return returns a predefined tag indicating the maturity level rating for the content (see 286 * the <code>CONTENT_MATURITY_*</code> constants). 287 * @see RecommendationExtender#setMaturityRating 288 */ 289 public String getMaturityRating() { 290 return mMaturityRating; 291 } 292 293 /** 294 * Sets the running time (when applicable) for the content associated with the notification. 295 * 296 * @param length The runing time, in seconds, of the content associated with the notification. 297 */ 298 public RecommendationExtender setRunningTime(long length) { 299 if (length < 0) { 300 throw new IllegalArgumentException("Invalid value for Running Time"); 301 } 302 mRunLength = length; 303 return this; 304 } 305 306 /** 307 * Returns the running time for the content associated with the notification. 308 * 309 * @return The running time, in seconds, of the content associated with the notification. 310 * @see RecommendationExtender#setRunningTime 311 */ 312 public long getRunningTime() { 313 return mRunLength; 314 } 315 } 316