Commit 54440261 by jaewan Committed by bachinger

Move Rating class to library-common

Rating class should be in the same module as MediaMetadata.

Tested:
  $ ./gradlew --stacktrace :exo-library-common:tDUT
  $ ./gradlew --stacktrace :media2-session:tDUT
  $ ./gradlew --stacktrace :media2-session-vct-current:cAT
PiperOrigin-RevId: 370902917
parent 309fd20a
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* A class for rating with a single degree of rating, "heart" vs "no heart". This can be used to
* indicate the content referred to is a favorite (or not).
*/
public final class HeartRating extends Rating {
@RatingType private static final int TYPE = RATING_TYPE_HEART;
private final boolean isRated;
/** Whether the rating has a heart rating or not. */
public final boolean hasHeart;
/** Creates a unrated HeartRating instance. */
public HeartRating() {
isRated = false;
hasHeart = false;
}
/**
* Creates a HeartRating instance.
*
* @param hasHeart true for a "heart selected" rating, false for "heart unselected".
*/
public HeartRating(boolean hasHeart) {
isRated = true;
this.hasHeart = hasHeart;
}
@Override
public boolean isRated() {
return isRated;
}
@Override
public int hashCode() {
return Objects.hashCode(isRated, hasHeart);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof HeartRating)) {
return false;
}
HeartRating other = (HeartRating) obj;
return hasHeart == other.hasHeart && isRated == other.isRated;
}
@Override
public String toString() {
return "HeartRating: " + (isRated ? "hasHeart=" + hasHeart : "unrated");
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_RATING_TYPE, FIELD_IS_RATED, FIELD_HAS_HEART})
private @interface FieldNumber {}
private static final int FIELD_IS_RATED = 1;
private static final int FIELD_HAS_HEART = 2;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE);
bundle.putBoolean(keyForField(FIELD_IS_RATED), isRated);
bundle.putBoolean(keyForField(FIELD_HAS_HEART), hasHeart);
return bundle;
}
public static final Creator<HeartRating> CREATOR = HeartRating::fromBundle;
private static HeartRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
== TYPE);
boolean isRated = bundle.getBoolean(keyForField(FIELD_IS_RATED), /* defaultValue= */ false);
return isRated
? new HeartRating(
bundle.getBoolean(keyForField(FIELD_HAS_HEART), /* defaultValue= */ false))
: new HeartRating();
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** A class for rating expressed as a percentage. */
public final class PercentageRating extends Rating {
@RatingType private static final int TYPE = RATING_TYPE_PERCENTAGE;
/**
* The percent value of this rating. Will be greater or equal to 0.0f, or {@link #RATING_UNSET} if
* it is unrated.
*/
public final float percent;
/** Creates a unrated PercentageRating instance. */
public PercentageRating() {
percent = RATING_UNSET;
}
/**
* Creates a PercentageRating instance with the given percentage. If {@code percent} is less than
* 0f or greater than 100f, it will throw IllegalArgumentException.
*
* @param percent the value of the rating
*/
public PercentageRating(@FloatRange(from = 0, to = 100) float percent) {
checkArgument(percent >= 0.0f && percent <= 100.0f, "percent must be in the rage of [0, 100]");
this.percent = percent;
}
@Override
public boolean isRated() {
return percent != RATING_UNSET;
}
@Override
public int hashCode() {
return Objects.hashCode(percent);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof PercentageRating)) {
return false;
}
return percent == ((PercentageRating) obj).percent;
}
@Override
public String toString() {
return "PercentageRating: " + (isRated() ? "percentage=" + percent : "unrated");
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_RATING_TYPE, FIELD_PERCENT})
private @interface FieldNumber {}
private static final int FIELD_PERCENT = 1;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE);
bundle.putFloat(keyForField(FIELD_PERCENT), percent);
return bundle;
}
public static final Creator<PercentageRating> CREATOR = PercentageRating::fromBundle;
private static PercentageRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
== TYPE);
float percent = bundle.getFloat(keyForField(FIELD_PERCENT), /* defaultValue= */ RATING_UNSET);
return percent == RATING_UNSET ? new PercentageRating() : new PercentageRating(percent);
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import android.os.Bundle;
import androidx.annotation.IntDef;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** An abstract class to encapsulate rating information used as content metadata. */
public abstract class Rating implements Bundleable {
public static final float RATING_UNSET = -1.0f;
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
RATING_TYPE_DEFAULT,
RATING_TYPE_HEART,
RATING_TYPE_PERCENTAGE,
RATING_TYPE_STAR,
RATING_TYPE_THUMB
})
protected @interface RatingType {}
protected static final int RATING_TYPE_DEFAULT = -1;
protected static final int RATING_TYPE_HEART = 0;
protected static final int RATING_TYPE_PERCENTAGE = 1;
protected static final int RATING_TYPE_STAR = 2;
protected static final int RATING_TYPE_THUMB = 3;
// Default package-private constructor to prevent extending Rating class outside this package.
/* package */ Rating() {}
/** Whether rating exists or not. */
public abstract boolean isRated();
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_RATING_TYPE})
private @interface FieldNumber {}
protected static final int FIELD_RATING_TYPE = 0;
public static final Creator<Rating> CREATOR = Rating::fromBundle;
private static Rating fromBundle(Bundle bundle) {
@RatingType
int ratingType =
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT);
switch (ratingType) {
case RATING_TYPE_HEART:
return HeartRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_PERCENTAGE:
return PercentageRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_STAR:
return StarRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_THUMB:
return ThumbRating.CREATOR.fromBundle(bundle);
default:
throw new IllegalArgumentException("Encountered unknown rating type: " + ratingType);
}
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** A class for rating expressed as the number of stars. */
public final class StarRating extends Rating {
@RatingType private static final int TYPE = RATING_TYPE_STAR;
private static final int MAX_STARS_DEFAULT = 5;
/** The maximum number of stars for this rating. Must be a positive number. */
@IntRange(from = 1)
public final int maxStars;
/**
* The value of stars for this rating. Will range from 0.0f to {@link #maxStars}, or {@link
* #RATING_UNSET} if it is unrated.
*/
public final float starRating;
/**
* Creates a unrated StarRating instance with {@code maxStars}. If {@code maxStars} is not a
* positive integer, it will throw IllegalArgumentException.
*
* @param maxStars a range of this star rating from 0.0f to {@code maxStars}
*/
public StarRating(@IntRange(from = 1) int maxStars) {
checkArgument(maxStars > 0, "maxStars must be a positive integer");
this.maxStars = maxStars;
starRating = RATING_UNSET;
}
/**
* Creates a StarRating instance with {@code maxStars} and the given integer or fractional number
* of stars. Non-integer values can for instance be used to represent an average rating value,
* which might not be an integer number of stars. If {@code maxStars} is not a positive integer or
* {@code starRating} has invalid value, it will throw IllegalArgumentException.
*
* @param maxStars the maximum number of stars which this rating can have.
* @param starRating a number ranging from 0.0f to {@code maxStars}
*/
public StarRating(@IntRange(from = 1) int maxStars, @FloatRange(from = 0.0) float starRating) {
checkArgument(maxStars > 0, "maxStars must be a positive integer");
checkArgument(
starRating >= 0.0f && starRating <= maxStars, "starRating is out of range [0, maxStars]");
this.maxStars = maxStars;
this.starRating = starRating;
}
@Override
public boolean isRated() {
return starRating != RATING_UNSET;
}
@Override
public int hashCode() {
return Objects.hashCode(maxStars, starRating);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof StarRating)) {
return false;
}
StarRating other = (StarRating) obj;
return maxStars == other.maxStars && starRating == other.starRating;
}
@Override
public String toString() {
return "StarRating: maxStars="
+ maxStars
+ (isRated() ? ", starRating=" + starRating : ", unrated");
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_RATING_TYPE, FIELD_MAX_STARS, FIELD_STAR_RATING})
private @interface FieldNumber {}
private static final int FIELD_MAX_STARS = 1;
private static final int FIELD_STAR_RATING = 2;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE);
bundle.putInt(keyForField(FIELD_MAX_STARS), maxStars);
bundle.putFloat(keyForField(FIELD_STAR_RATING), starRating);
return bundle;
}
public static final Creator<StarRating> CREATOR = StarRating::fromBundle;
private static StarRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
== TYPE);
int maxStars =
bundle.getInt(keyForField(FIELD_MAX_STARS), /* defaultValue= */ MAX_STARS_DEFAULT);
float starRating =
bundle.getFloat(keyForField(FIELD_STAR_RATING), /* defaultValue= */ RATING_UNSET);
return starRating == RATING_UNSET
? new StarRating(maxStars)
: new StarRating(maxStars, starRating);
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** A class for rating with a single degree of rating, "thumb up" vs "thumb down". */
public final class ThumbRating extends Rating {
@RatingType private static final int TYPE = RATING_TYPE_THUMB;
private final boolean isRated;
/** Whether the rating has a thumb up or thumb down rating. */
public final boolean thumbUp;
/** Creates a unrated ThumbRating instance. */
public ThumbRating() {
isRated = false;
thumbUp = false;
}
/**
* Creates a ThumbRating instance.
*
* @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
*/
public ThumbRating(boolean thumbIsUp) {
isRated = true;
thumbUp = thumbIsUp;
}
@Override
public boolean isRated() {
return isRated;
}
@Override
public int hashCode() {
return Objects.hashCode(isRated, thumbUp);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ThumbRating)) {
return false;
}
ThumbRating other = (ThumbRating) obj;
return thumbUp == other.thumbUp && isRated == other.isRated;
}
@Override
public String toString() {
return "ThumbRating: " + (isRated ? "isThumbUp=" + thumbUp : "unrated");
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({FIELD_RATING_TYPE, FIELD_IS_RATED, FIELD_IS_THUMB_UP})
private @interface FieldNumber {}
private static final int FIELD_IS_RATED = 1;
private static final int FIELD_IS_THUMB_UP = 2;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE);
bundle.putBoolean(keyForField(FIELD_IS_RATED), isRated);
bundle.putBoolean(keyForField(FIELD_IS_THUMB_UP), thumbUp);
return bundle;
}
public static final Creator<ThumbRating> CREATOR = ThumbRating::fromBundle;
private static ThumbRating fromBundle(Bundle bundle) {
checkArgument(
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
== TYPE);
boolean isRated = bundle.getBoolean(keyForField(FIELD_IS_RATED), /* defaultValue= */ false);
return isRated
? new ThumbRating(
bundle.getBoolean(keyForField(FIELD_IS_THUMB_UP), /* defaultValue= */ false))
: new ThumbRating();
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.internal.DoNotInstrument;
/** Tests for {@link Rating} and its subclasses. */
@RunWith(AndroidJUnit4.class)
@DoNotInstrument
public class RatingTest {
@Test
public void unratedHeartRating() {
HeartRating rating = new HeartRating();
assertThat(rating.isRated()).isFalse();
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void ratedHeartRating() {
boolean hasHeart = true;
HeartRating rating = new HeartRating(hasHeart);
assertThat(rating.isRated()).isTrue();
assertThat(rating.hasHeart).isEqualTo(hasHeart);
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void unratedPercentageRating() {
PercentageRating rating = new PercentageRating();
assertThat(rating.isRated()).isFalse();
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void ratedPercentageRating() {
float percentage = 20.5f;
PercentageRating rating = new PercentageRating(percentage);
assertThat(rating.isRated()).isTrue();
assertThat(rating.percent).isEqualTo(percentage);
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void unratedThumbRating() {
ThumbRating rating = new ThumbRating();
assertThat(rating.isRated()).isFalse();
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void ratedThumbRating() {
boolean isThumbUp = true;
ThumbRating rating = new ThumbRating(isThumbUp);
assertThat(rating.isRated()).isTrue();
assertThat(rating.thumbUp).isEqualTo(isThumbUp);
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void unratedStarRating() {
int maxStars = 5;
StarRating rating = new StarRating(maxStars);
assertThat(rating.isRated()).isFalse();
assertThat(rating.maxStars).isEqualTo(maxStars);
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
@Test
public void ratedStarRating() {
int maxStars = 5;
float starRating = 3.1f;
StarRating rating = new StarRating(maxStars, starRating);
assertThat(rating.isRated()).isTrue();
assertThat(rating.maxStars).isEqualTo(maxStars);
assertThat(rating.starRating).isEqualTo(starRating);
assertThat(roundTripViaBundle(rating)).isEqualTo(rating);
}
private static Rating roundTripViaBundle(Rating rating) {
return Rating.CREATOR.fromBundle(rating.toBundle());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment