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 17package androidx.media; 18 19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20 21import android.os.Bundle; 22import android.util.Log; 23 24import androidx.annotation.IntDef; 25import androidx.annotation.Nullable; 26import androidx.annotation.RestrictTo; 27import androidx.core.util.ObjectsCompat; 28 29import java.lang.annotation.Retention; 30import java.lang.annotation.RetentionPolicy; 31 32/** 33 * A class to encapsulate rating information used as content metadata. 34 * A rating is defined by its rating style (see {@link #RATING_HEART}, 35 * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, 36 * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may 37 * be defined as "unrated"), both of which are defined when the rating instance is constructed 38 * through one of the factory methods. 39 */ 40// New version of Rating with following change 41// - Don't implement Parcelable for updatable support. 42public final class Rating2 { 43 /** 44 * @hide 45 */ 46 @RestrictTo(LIBRARY_GROUP) 47 @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, 48 RATING_5_STARS, RATING_PERCENTAGE}) 49 @Retention(RetentionPolicy.SOURCE) 50 public @interface Style {} 51 52 /** 53 * @hide 54 */ 55 @RestrictTo(LIBRARY_GROUP) 56 @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS}) 57 @Retention(RetentionPolicy.SOURCE) 58 public @interface StarStyle {} 59 60 /** 61 * Indicates a rating style is not supported. A Rating2 will never have this 62 * type, but can be used by other classes to indicate they do not support 63 * Rating2. 64 */ 65 public static final int RATING_NONE = 0; 66 67 /** 68 * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to 69 * indicate the content referred to is a favorite (or not). 70 */ 71 public static final int RATING_HEART = 1; 72 73 /** 74 * A rating style for "thumb up" vs "thumb down". 75 */ 76 public static final int RATING_THUMB_UP_DOWN = 2; 77 78 /** 79 * A rating style with 0 to 3 stars. 80 */ 81 public static final int RATING_3_STARS = 3; 82 83 /** 84 * A rating style with 0 to 4 stars. 85 */ 86 public static final int RATING_4_STARS = 4; 87 88 /** 89 * A rating style with 0 to 5 stars. 90 */ 91 public static final int RATING_5_STARS = 5; 92 93 /** 94 * A rating style expressed as a percentage. 95 */ 96 public static final int RATING_PERCENTAGE = 6; 97 98 private static final String TAG = "Rating2"; 99 100 private static final float RATING_NOT_RATED = -1.0f; 101 private static final String KEY_STYLE = "android.media.rating2.style"; 102 private static final String KEY_VALUE = "android.media.rating2.value"; 103 104 private final int mRatingStyle; 105 private final float mRatingValue; 106 107 private Rating2(@Style int ratingStyle, float rating) { 108 mRatingStyle = ratingStyle; 109 mRatingValue = rating; 110 } 111 112 @Override 113 public String toString() { 114 return "Rating2:style=" + mRatingStyle + " rating=" 115 + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue)); 116 } 117 118 @Override 119 public boolean equals(Object obj) { 120 if (!(obj instanceof Rating2)) { 121 return false; 122 } 123 Rating2 other = (Rating2) obj; 124 return mRatingStyle == other.mRatingStyle && mRatingValue == other.mRatingValue; 125 } 126 127 @Override 128 public int hashCode() { 129 return ObjectsCompat.hash(mRatingStyle, mRatingValue); 130 } 131 132 /** 133 * Create an instance from bundle object, previously created by {@link #toBundle()} 134 * 135 * @param bundle bundle 136 * @return new Rating2 instance or {@code null} for error 137 */ 138 public static Rating2 fromBundle(@Nullable Bundle bundle) { 139 if (bundle == null) { 140 return null; 141 } 142 return new Rating2(bundle.getInt(KEY_STYLE), bundle.getFloat(KEY_VALUE)); 143 } 144 145 /** 146 * Return bundle for this object to share across the process. 147 * @return bundle of this object 148 */ 149 public Bundle toBundle() { 150 Bundle bundle = new Bundle(); 151 bundle.putInt(KEY_STYLE, mRatingStyle); 152 bundle.putFloat(KEY_VALUE, mRatingValue); 153 return bundle; 154 } 155 156 /** 157 * Return a Rating2 instance with no rating. 158 * Create and return a new Rating2 instance with no rating known for the given 159 * rating style. 160 * 161 * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN}, 162 * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS}, 163 * or {@link #RATING_PERCENTAGE}. 164 * @return null if an invalid rating style is passed, a new Rating2 instance otherwise. 165 */ 166 public static @Nullable Rating2 newUnratedRating(@Style int ratingStyle) { 167 switch(ratingStyle) { 168 case RATING_HEART: 169 case RATING_THUMB_UP_DOWN: 170 case RATING_3_STARS: 171 case RATING_4_STARS: 172 case RATING_5_STARS: 173 case RATING_PERCENTAGE: 174 return new Rating2(ratingStyle, RATING_NOT_RATED); 175 default: 176 return null; 177 } 178 } 179 180 /** 181 * Return a Rating2 instance with a heart-based rating. 182 * Create and return a new Rating2 instance with a rating style of {@link #RATING_HEART}, 183 * and a heart-based rating. 184 * 185 * @param hasHeart true for a "heart selected" rating, false for "heart unselected". 186 * @return a new Rating2 instance. 187 */ 188 public static @Nullable Rating2 newHeartRating(boolean hasHeart) { 189 return new Rating2(RATING_HEART, hasHeart ? 1.0f : 0.0f); 190 } 191 192 /** 193 * Return a Rating2 instance with a thumb-based rating. 194 * Create and return a new Rating2 instance with a {@link #RATING_THUMB_UP_DOWN} 195 * rating style, and a "thumb up" or "thumb down" rating. 196 * 197 * @param thumbIsUp true for a "thumb up" rating, false for "thumb down". 198 * @return a new Rating2 instance. 199 */ 200 public static @Nullable Rating2 newThumbRating(boolean thumbIsUp) { 201 return new Rating2(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f); 202 } 203 204 /** 205 * Return a Rating2 instance with a star-based rating. 206 * Create and return a new Rating2 instance with one of the star-base rating styles 207 * and the given integer or fractional number of stars. Non integer values can for instance 208 * be used to represent an average rating value, which might not be an integer number of stars. 209 * 210 * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, 211 * {@link #RATING_5_STARS}. 212 * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to 213 * the rating style. 214 * @return null if the rating style is invalid, or the rating is out of range, 215 * a new Rating2 instance otherwise. 216 */ 217 public static @Nullable Rating2 newStarRating(@StarStyle int starRatingStyle, 218 float starRating) { 219 float maxRating; 220 switch(starRatingStyle) { 221 case RATING_3_STARS: 222 maxRating = 3.0f; 223 break; 224 case RATING_4_STARS: 225 maxRating = 4.0f; 226 break; 227 case RATING_5_STARS: 228 maxRating = 5.0f; 229 break; 230 default: 231 Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating"); 232 return null; 233 } 234 if ((starRating < 0.0f) || (starRating > maxRating)) { 235 Log.e(TAG, "Trying to set out of range star-based rating"); 236 return null; 237 } 238 return new Rating2(starRatingStyle, starRating); 239 } 240 241 /** 242 * Return a Rating2 instance with a percentage-based rating. 243 * Create and return a new Rating2 instance with a {@link #RATING_PERCENTAGE} 244 * rating style, and a rating of the given percentage. 245 * 246 * @param percent the value of the rating 247 * @return null if the rating is out of range, a new Rating2 instance otherwise. 248 */ 249 public static @Nullable Rating2 newPercentageRating(float percent) { 250 if ((percent < 0.0f) || (percent > 100.0f)) { 251 Log.e(TAG, "Invalid percentage-based rating value"); 252 return null; 253 } else { 254 return new Rating2(RATING_PERCENTAGE, percent); 255 } 256 } 257 258 /** 259 * Return whether there is a rating value available. 260 * @return true if the instance was not created with {@link #newUnratedRating(int)}. 261 */ 262 public boolean isRated() { 263 return mRatingValue >= 0.0f; 264 } 265 266 /** 267 * Return the rating style. 268 * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN}, 269 * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS}, 270 * or {@link #RATING_PERCENTAGE}. 271 */ 272 public @Style int getRatingStyle() { 273 return mRatingStyle; 274 } 275 276 /** 277 * Return whether the rating is "heart selected". 278 * @return true if the rating is "heart selected", false if the rating is "heart unselected", 279 * if the rating style is not {@link #RATING_HEART} or if it is unrated. 280 */ 281 public boolean hasHeart() { 282 return mRatingStyle == RATING_HEART && mRatingValue == 1.0f; 283 } 284 285 /** 286 * Return whether the rating is "thumb up". 287 * @return true if the rating is "thumb up", false if the rating is "thumb down", 288 * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated. 289 */ 290 public boolean isThumbUp() { 291 return mRatingStyle == RATING_THUMB_UP_DOWN && mRatingValue == 1.0f; 292 } 293 294 /** 295 * Return the star-based rating value. 296 * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is 297 * not star-based, or if it is unrated. 298 */ 299 public float getStarRating() { 300 switch (mRatingStyle) { 301 case RATING_3_STARS: 302 case RATING_4_STARS: 303 case RATING_5_STARS: 304 if (isRated()) { 305 return mRatingValue; 306 } 307 // Fall through 308 default: 309 return -1.0f; 310 } 311 } 312 313 /** 314 * Return the percentage-based rating value. 315 * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is 316 * not percentage-based, or if it is unrated. 317 */ 318 public float getPercentRating() { 319 if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) { 320 return -1.0f; 321 } else { 322 return mRatingValue; 323 } 324 } 325} 326