diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java index 7e6aaece17..5ced18a108 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2; +import android.os.Bundle; import android.os.Looper; import android.view.Surface; import android.view.SurfaceHolder; @@ -529,7 +530,7 @@ public interface Player { } /** Position info describing a playback position involved in a discontinuity. */ - final class PositionInfo { + final class PositionInfo implements Bundleable { /** * The UID of the window, or {@code null}, if the timeline is {@link Timeline#isEmpty() empty}. @@ -614,6 +615,75 @@ public interface Player { adGroupIndex, adIndexInAdGroup); } + + // Bundleable implementation. + @Documented + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + FIELD_WINDOW_INDEX, + FIELD_PERIOD_INDEX, + FIELD_POSITION_MS, + FIELD_CONTENT_POSITION_MS, + FIELD_AD_GROUP_INDEX, + FIELD_AD_INDEX_IN_AD_GROUP + }) + private @interface FieldNumber {} + + private static final int FIELD_WINDOW_INDEX = 0; + private static final int FIELD_PERIOD_INDEX = 1; + private static final int FIELD_POSITION_MS = 2; + private static final int FIELD_CONTENT_POSITION_MS = 3; + private static final int FIELD_AD_GROUP_INDEX = 4; + private static final int FIELD_AD_INDEX_IN_AD_GROUP = 5; + + /** + * {@inheritDoc} + * + *

It omits the {@link #windowUid} and {@link #periodUid} fields. The {@link #windowUid} and + * {@link #periodUid} of an instance restored by {@link #CREATOR} will always be {@code null}. + */ + @Override + public Bundle toBundle() { + Bundle bundle = new Bundle(); + bundle.putInt(keyForField(FIELD_WINDOW_INDEX), windowIndex); + bundle.putInt(keyForField(FIELD_PERIOD_INDEX), periodIndex); + bundle.putLong(keyForField(FIELD_POSITION_MS), positionMs); + bundle.putLong(keyForField(FIELD_CONTENT_POSITION_MS), contentPositionMs); + bundle.putInt(keyForField(FIELD_AD_GROUP_INDEX), adGroupIndex); + bundle.putInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), adIndexInAdGroup); + return bundle; + } + + /** Object that can restore {@link PositionInfo} from a {@link Bundle}. */ + public static final Creator CREATOR = PositionInfo::fromBundle; + + private static PositionInfo fromBundle(Bundle bundle) { + int windowIndex = + bundle.getInt(keyForField(FIELD_WINDOW_INDEX), /* defaultValue= */ C.INDEX_UNSET); + int periodIndex = + bundle.getInt(keyForField(FIELD_PERIOD_INDEX), /* defaultValue= */ C.INDEX_UNSET); + long positionMs = + bundle.getLong(keyForField(FIELD_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); + long contentPositionMs = + bundle.getLong(keyForField(FIELD_CONTENT_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); + int adGroupIndex = + bundle.getInt(keyForField(FIELD_AD_GROUP_INDEX), /* defaultValue= */ C.INDEX_UNSET); + int adIndexInAdGroup = + bundle.getInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), /* defaultValue= */ C.INDEX_UNSET); + return new PositionInfo( + /* windowUid= */ null, + windowIndex, + /* periodUid= */ null, + periodIndex, + positionMs, + contentPositionMs, + adGroupIndex, + adIndexInAdGroup); + } + + private static String keyForField(@FieldNumber int field) { + return Integer.toString(field, Character.MAX_RADIX); + } } /** diff --git a/library/common/src/test/java/com/google/android/exoplayer2/PositionInfoTest.java b/library/common/src/test/java/com/google/android/exoplayer2/PositionInfoTest.java new file mode 100644 index 0000000000..c86bd0ae38 --- /dev/null +++ b/library/common/src/test/java/com/google/android/exoplayer2/PositionInfoTest.java @@ -0,0 +1,78 @@ +/* + * 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 com.google.android.exoplayer2.Player.PositionInfo; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Unit tests for {@link Player.PositionInfo}. */ +@RunWith(AndroidJUnit4.class) +public class PositionInfoTest { + + @Test + public void roundtripViaBundle_ofPositionInfoWithoutObjectFields_yieldsEqualInstance() { + PositionInfo positionInfo = + new PositionInfo( + /* windowUid= */ null, + /* windowIndex= */ 23, + /* periodUid= */ null, + /* periodIndex= */ 11, + /* positionMs= */ 8787L, + /* contentPositionMs= */ 12L, + /* adGroupIndex= */ 2, + /* adIndexInAdGroup= */ 444); + + assertThat(PositionInfo.CREATOR.fromBundle(positionInfo.toBundle())).isEqualTo(positionInfo); + } + + @Test + public void roundtripViaBundle_ofPositionInfoWithWindowUid_yieldsNullWindowUid() { + PositionInfo positionInfo = + new PositionInfo( + /* windowUid= */ new Object(), + /* windowIndex= */ 23, + /* periodUid= */ null, + /* periodIndex= */ 11, + /* positionMs= */ 8787L, + /* contentPositionMs= */ 12L, + /* adGroupIndex= */ 2, + /* adIndexInAdGroup= */ 444); + + PositionInfo positionInfoFromBundle = PositionInfo.CREATOR.fromBundle(positionInfo.toBundle()); + assertThat(positionInfoFromBundle.windowUid).isNull(); + } + + @Test + public void roundtripViaBundle_ofPositionInfoWithPeriodUid_yieldsNullPeriodUid() { + PositionInfo positionInfo = + new PositionInfo( + /* windowUid= */ null, + /* windowIndex= */ 23, + /* periodUid= */ new Object(), + /* periodIndex= */ 11, + /* positionMs= */ 8787L, + /* contentPositionMs= */ 12L, + /* adGroupIndex= */ 2, + /* adIndexInAdGroup= */ 444); + + PositionInfo positionInfoFromBundle = PositionInfo.CREATOR.fromBundle(positionInfo.toBundle()); + assertThat(positionInfoFromBundle.periodUid).isNull(); + } +}