Commit 6f9dbfe0 by gyumin Committed by Ian Baker

Implement Bundleable for AdPlaybackState

PiperOrigin-RevId: 361731578
parent bc9fb861
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.ads; package com.google.android.exoplayer2.source.ads;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static java.lang.Math.max; import static java.lang.Math.max;
import android.net.Uri; import android.net.Uri;
...@@ -24,7 +25,6 @@ import androidx.annotation.IntDef; ...@@ -24,7 +25,6 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Bundleable; import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -39,7 +39,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; ...@@ -39,7 +39,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* <p>Instances are immutable. Call the {@code with*} methods to get new instances that have the * <p>Instances are immutable. Call the {@code with*} methods to get new instances that have the
* required changes. * required changes.
*/ */
public final class AdPlaybackState { public final class AdPlaybackState implements Bundleable {
/** /**
* Represents a group of ads, with information about their states. * Represents a group of ads, with information about their states.
...@@ -69,7 +69,7 @@ public final class AdPlaybackState { ...@@ -69,7 +69,7 @@ public final class AdPlaybackState {
private AdGroup( private AdGroup(
int count, @AdState int[] states, @NullableType Uri[] uris, long[] durationsUs) { int count, @AdState int[] states, @NullableType Uri[] uris, long[] durationsUs) {
Assertions.checkArgument(states.length == uris.length); checkArgument(states.length == uris.length);
this.count = count; this.count = count;
this.states = states; this.states = states;
this.uris = uris; this.uris = uris;
...@@ -165,9 +165,9 @@ public final class AdPlaybackState { ...@@ -165,9 +165,9 @@ public final class AdPlaybackState {
*/ */
@CheckResult @CheckResult
public AdGroup withAdState(@AdState int state, int index) { public AdGroup withAdState(@AdState int state, int index) {
Assertions.checkArgument(count == C.LENGTH_UNSET || index < count); checkArgument(count == C.LENGTH_UNSET || index < count);
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, index + 1); @AdState int[] states = copyStatesWithSpaceForAdCount(this.states, index + 1);
Assertions.checkArgument( checkArgument(
states[index] == AD_STATE_UNAVAILABLE states[index] == AD_STATE_UNAVAILABLE
|| states[index] == AD_STATE_AVAILABLE || states[index] == AD_STATE_AVAILABLE
|| states[index] == state); || states[index] == state);
...@@ -260,17 +260,14 @@ public final class AdPlaybackState { ...@@ -260,17 +260,14 @@ public final class AdPlaybackState {
} }
/** Object that can restore {@link AdGroup} from a {@link Bundle}. */ /** Object that can restore {@link AdGroup} from a {@link Bundle}. */
public static final Creator<AdGroup> CREATOR = public static final Creator<AdGroup> CREATOR = AdGroup::fromBundle;
new Creator<AdGroup>() {
// getParcelableArrayList may have null elements. // getParcelableArrayList may have null elements.
@SuppressWarnings("nullness:type.argument.type.incompatible") @SuppressWarnings("nullness:type.argument.type.incompatible")
@Override private static AdGroup fromBundle(Bundle bundle) {
public AdGroup fromBundle(Bundle bundle) {
int count = bundle.getInt(keyForField(FIELD_COUNT), /* defaultValue= */ C.LENGTH_UNSET); int count = bundle.getInt(keyForField(FIELD_COUNT), /* defaultValue= */ C.LENGTH_UNSET);
@Nullable @Nullable
ArrayList<@NullableType Uri> uriList = ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(keyForField(FIELD_URIS));
bundle.getParcelableArrayList(keyForField(FIELD_URIS));
@Nullable @Nullable
@AdState @AdState
int[] states = bundle.getIntArray(keyForField(FIELD_STATES)); int[] states = bundle.getIntArray(keyForField(FIELD_STATES));
...@@ -281,7 +278,6 @@ public final class AdPlaybackState { ...@@ -281,7 +278,6 @@ public final class AdPlaybackState {
uriList == null ? new Uri[0] : uriList.toArray(new Uri[0]), uriList == null ? new Uri[0] : uriList.toArray(new Uri[0]),
durationsUs == null ? new long[0] : durationsUs); durationsUs == null ? new long[0] : durationsUs);
} }
};
private static String keyForField(@AdGroup.FieldNumber int field) { private static String keyForField(@AdGroup.FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX); return Integer.toString(field, Character.MAX_RADIX);
...@@ -368,6 +364,7 @@ public final class AdPlaybackState { ...@@ -368,6 +364,7 @@ public final class AdPlaybackState {
@Nullable AdGroup[] adGroups, @Nullable AdGroup[] adGroups,
long adResumePositionUs, long adResumePositionUs,
long contentDurationUs) { long contentDurationUs) {
checkArgument(adGroups == null || adGroups.length == adGroupTimesUs.length);
this.adsId = adsId; this.adsId = adsId;
this.adGroupTimesUs = adGroupTimesUs; this.adGroupTimesUs = adGroupTimesUs;
this.adResumePositionUs = adResumePositionUs; this.adResumePositionUs = adResumePositionUs;
...@@ -449,7 +446,7 @@ public final class AdPlaybackState { ...@@ -449,7 +446,7 @@ public final class AdPlaybackState {
*/ */
@CheckResult @CheckResult
public AdPlaybackState withAdCount(int adGroupIndex, int adCount) { public AdPlaybackState withAdCount(int adGroupIndex, int adCount) {
Assertions.checkArgument(adCount > 0); checkArgument(adCount > 0);
if (adGroups[adGroupIndex].count == adCount) { if (adGroups[adGroupIndex].count == adCount) {
return this; return this;
} }
...@@ -634,4 +631,79 @@ public final class AdPlaybackState { ...@@ -634,4 +631,79 @@ public final class AdPlaybackState {
return positionUs < adGroupPositionUs; return positionUs < adGroupPositionUs;
} }
} }
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FIELD_AD_GROUP_TIMES_US,
FIELD_AD_GROUPS,
FIELD_AD_RESUME_POSITION_US,
FIELD_CONTENT_DURATION_US
})
private @interface FieldNumber {}
private static final int FIELD_AD_GROUP_TIMES_US = 1;
private static final int FIELD_AD_GROUPS = 2;
private static final int FIELD_AD_RESUME_POSITION_US = 3;
private static final int FIELD_CONTENT_DURATION_US = 4;
/**
* {@inheritDoc}
*
* <p>It omits the {@link #adsId} field so the {@link #adsId} of instances restored by {@link
* #CREATOR} will always be {@code null}.
*/
// TODO(b/166765820): See if missing adsId would be okay and add adsId to the Bundle otherwise.
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putLongArray(keyForField(FIELD_AD_GROUP_TIMES_US), adGroupTimesUs);
ArrayList<Bundle> adGroupBundleList = new ArrayList<>();
for (AdGroup adGroup : adGroups) {
adGroupBundleList.add(adGroup.toBundle());
}
bundle.putParcelableArrayList(keyForField(FIELD_AD_GROUPS), adGroupBundleList);
bundle.putLong(keyForField(FIELD_AD_RESUME_POSITION_US), adResumePositionUs);
bundle.putLong(keyForField(FIELD_CONTENT_DURATION_US), contentDurationUs);
return bundle;
}
/**
* Object that can restore {@link AdPlaybackState} from a {@link Bundle}.
*
* <p>The {@link #adsId} of restored instances will always be {@code null}.
*/
public static final Bundleable.Creator<AdPlaybackState> CREATOR = AdPlaybackState::fromBundle;
private static AdPlaybackState fromBundle(Bundle bundle) {
@Nullable long[] adGroupTimesUs = bundle.getLongArray(keyForField(FIELD_AD_GROUP_TIMES_US));
@Nullable
ArrayList<Bundle> adGroupBundleList =
bundle.getParcelableArrayList(keyForField(FIELD_AD_GROUPS));
@Nullable AdGroup[] adGroups;
if (adGroupBundleList == null) {
adGroups = null;
} else {
adGroups = new AdGroup[adGroupBundleList.size()];
for (int i = 0; i < adGroupBundleList.size(); i++) {
adGroups[i] = AdGroup.CREATOR.fromBundle(adGroupBundleList.get(i));
}
}
long adResumePositionUs =
bundle.getLong(keyForField(FIELD_AD_RESUME_POSITION_US), /* defaultValue= */ 0);
long contentDurationUs =
bundle.getLong(keyForField(FIELD_CONTENT_DURATION_US), /* defaultValue= */ C.TIME_UNSET);
return new AdPlaybackState(
/* adsId= */ null,
adGroupTimesUs == null ? new long[0] : adGroupTimesUs,
adGroups,
adResumePositionUs,
contentDurationUs);
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -150,6 +150,32 @@ public class AdPlaybackStateTest { ...@@ -150,6 +150,32 @@ public class AdPlaybackStateTest {
} }
@Test @Test
public void roundtripViaBundle_yieldsEqualFieldsExceptAdsId() {
AdPlaybackState originalState =
state
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0)
.withAdUri(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, TEST_URI)
.withAdCount(/* adGroupIndex= */ 1, /* adCount= */ 2)
.withSkippedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0)
.withPlayedAd(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1)
.withAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 0, TEST_URI)
.withAdUri(/* adGroupIndex= */ 1, /* adIndexInAdGroup= */ 1, TEST_URI)
.withAdDurationsUs(new long[][] {{12}, {34, 56}})
.withAdResumePositionUs(123)
.withContentDurationUs(456);
AdPlaybackState restoredState = AdPlaybackState.CREATOR.fromBundle(originalState.toBundle());
assertThat(restoredState.adsId).isNull();
assertThat(restoredState.adGroupCount).isEqualTo(originalState.adGroupCount);
assertThat(restoredState.adGroupTimesUs).isEqualTo(originalState.adGroupTimesUs);
assertThat(restoredState.adGroups).isEqualTo(originalState.adGroups);
assertThat(restoredState.adResumePositionUs).isEqualTo(originalState.adResumePositionUs);
assertThat(restoredState.contentDurationUs).isEqualTo(originalState.contentDurationUs);
}
@Test
public void roundtripViaBundle_ofAdGroup_yieldsEqualInstance() { public void roundtripViaBundle_ofAdGroup_yieldsEqualInstance() {
AdPlaybackState.AdGroup adGroup = AdPlaybackState.AdGroup adGroup =
new AdPlaybackState.AdGroup() new AdPlaybackState.AdGroup()
......
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