Make AdsLoader.State implement Bundleable

This allows the AdsLoader.State to be stored in savedInstanceState

#minor-release

PiperOrigin-RevId: 429057697
This commit is contained in:
bachinger 2022-02-16 16:45:46 +00:00 committed by Ian Baker
parent ccfb126b8a
commit 899d458c7b
2 changed files with 138 additions and 2 deletions

View File

@ -28,17 +28,22 @@ import static androidx.media3.exoplayer.ima.ImaUtil.updateAdDurationAndPropagate
import static androidx.media3.exoplayer.ima.ImaUtil.updateAdDurationInAdGroup;
import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState;
import static java.lang.Math.min;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Pair;
import android.view.ViewGroup;
import androidx.annotation.IntDef;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.AdOverlayInfo;
import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.AdViewProvider;
import androidx.media3.common.Bundleable;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Metadata;
@ -88,6 +93,10 @@ import com.google.ads.interactivemedia.v3.api.player.VideoStreamPlayer;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -285,13 +294,67 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
}
/** The state of the {@link AdsLoader}. */
public static class State {
public static class State implements Bundleable {
private final ImmutableMap<String, AdPlaybackState> adPlaybackStates;
private State(ImmutableMap<String, AdPlaybackState> adPlaybackStates) {
@VisibleForTesting
/* package */ State(ImmutableMap<String, AdPlaybackState> adPlaybackStates) {
this.adPlaybackStates = adPlaybackStates;
}
@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (!(o instanceof State)) {
return false;
}
State state = (State) o;
return adPlaybackStates.equals(state.adPlaybackStates);
}
@Override
public int hashCode() {
return adPlaybackStates.hashCode();
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_AD_PLAYBACK_STATES})
private @interface FieldNumber {}
private static final int FIELD_AD_PLAYBACK_STATES = 1;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putSerializable(keyForField(FIELD_AD_PLAYBACK_STATES), adPlaybackStates);
return bundle;
}
/** Object that can restore {@link AdsLoader.State} from a {@link Bundle}. */
public static final Bundleable.Creator<State> CREATOR = State::fromBundle;
@SuppressWarnings("unchecked")
private static State fromBundle(Bundle bundle) {
@Nullable
Map<String, AdPlaybackState> adPlaybackStateMap =
(Map<String, AdPlaybackState>)
bundle.getSerializable(keyForField(FIELD_AD_PLAYBACK_STATES));
return new State(
adPlaybackStateMap != null
? ImmutableMap.copyOf(adPlaybackStateMap)
: ImmutableMap.of());
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}
private final ImaUtil.ServerSideAdInsertionConfiguration configuration;

View File

@ -0,0 +1,73 @@
/*
* Copyright 2022 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 androidx.media3.exoplayer.ima;
import static com.google.common.truth.Truth.assertThat;
import androidx.media3.common.AdPlaybackState;
import androidx.media3.common.C;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource.AdsLoader.State;
import androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link ImaServerSideAdInsertionMediaSource}. */
@RunWith(AndroidJUnit4.class)
public class ImaServerSideAdInsertionMediaSourceTest {
@Test
public void adsLoaderStateToBundle_marshallAndUnmarshalling_resultIsEqual() {
AdPlaybackState firstAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
new AdPlaybackState("adsId1"),
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 5_000_000,
10_000_000,
20_000_000);
AdPlaybackState secondAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
new AdPlaybackState("adsId2"),
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000)
.withPlayedAd(/* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0);
AdPlaybackState thirdAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
new AdPlaybackState("adsId3"),
/* fromPositionUs= */ C.TIME_END_OF_SOURCE,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000);
thirdAdPlaybackState =
ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState(
thirdAdPlaybackState,
/* fromPositionUs= */ 0,
/* contentResumeOffsetUs= */ 10,
/* adDurationsUs...= */ 10_000_000)
.withRemovedAdGroupCount(1);
State state =
new State(
ImmutableMap.<String, AdPlaybackState>builder()
.put("adsId1", firstAdPlaybackState)
.put("adsId2", secondAdPlaybackState)
.put("adsId3", thirdAdPlaybackState)
.buildOrThrow());
assertThat(State.CREATOR.fromBundle(state.toBundle())).isEqualTo(state);
}
}