diff --git a/libraries/common/src/main/java/androidx/media3/common/MediaItem.java b/libraries/common/src/main/java/androidx/media3/common/MediaItem.java index 166a60a6a92..f9868881df8 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MediaItem.java +++ b/libraries/common/src/main/java/androidx/media3/common/MediaItem.java @@ -1215,7 +1215,8 @@ public Bundle toBundle() { bundle.putBundle(FIELD_ADS_CONFIGURATION, adsConfiguration.toBundle()); } if (!streamKeys.isEmpty()) { - bundle.putParcelableArrayList(FIELD_STREAM_KEYS, new ArrayList<>(streamKeys)); + bundle.putParcelableArrayList( + FIELD_STREAM_KEYS, BundleableUtil.toBundleArrayList(streamKeys)); } if (customCacheKey != null) { bundle.putString(FIELD_CUSTOM_CACHE_KEY, customCacheKey); @@ -1239,9 +1240,11 @@ private static LocalConfiguration fromBundle(Bundle bundle) { @Nullable Bundle adsBundle = bundle.getBundle(FIELD_ADS_CONFIGURATION); AdsConfiguration adsConfiguration = adsBundle == null ? null : AdsConfiguration.CREATOR.fromBundle(adsBundle); - @Nullable List streamKeysList = bundle.getParcelableArrayList(FIELD_STREAM_KEYS); + @Nullable List streamKeysBundles = bundle.getParcelableArrayList(FIELD_STREAM_KEYS); List streamKeys = - streamKeysList == null ? ImmutableList.of() : ImmutableList.copyOf(streamKeysList); + streamKeysBundles == null + ? ImmutableList.of() + : BundleableUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles); @Nullable List subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION); ImmutableList subtitleConfiguration = diff --git a/libraries/common/src/main/java/androidx/media3/common/StreamKey.java b/libraries/common/src/main/java/androidx/media3/common/StreamKey.java index 939575b562c..263909c9d77 100644 --- a/libraries/common/src/main/java/androidx/media3/common/StreamKey.java +++ b/libraries/common/src/main/java/androidx/media3/common/StreamKey.java @@ -15,10 +15,12 @@ */ package androidx.media3.common; +import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.Nullable; import androidx.media3.common.util.UnstableApi; +import androidx.media3.common.util.Util; /** * A key for a subset of media that can be separately loaded (a "stream"). @@ -35,7 +37,7 @@ * particular track selection. */ @UnstableApi -public final class StreamKey implements Comparable, Parcelable { +public final class StreamKey implements Comparable, Parcelable, Bundleable { /** The period index. */ public final int periodIndex; @@ -44,11 +46,6 @@ public final class StreamKey implements Comparable, Parcelable { /** The stream index. */ public final int streamIndex; - /** - * @deprecated Use {@link #streamIndex}. - */ - @Deprecated public final int trackIndex; - /** * Creates an instance with {@link #periodIndex} set to 0. * @@ -60,26 +57,22 @@ public StreamKey(int groupIndex, int streamIndex) { } /** - * Creates an instance. + * Creates an instance of {@link StreamKey} using 3 indices. * * @param periodIndex The period index. * @param groupIndex The group index. * @param streamIndex The stream index. */ - @SuppressWarnings("deprecation") public StreamKey(int periodIndex, int groupIndex, int streamIndex) { this.periodIndex = periodIndex; this.groupIndex = groupIndex; this.streamIndex = streamIndex; - trackIndex = streamIndex; } - @SuppressWarnings("deprecation") /* package */ StreamKey(Parcel in) { periodIndex = in.readInt(); groupIndex = in.readInt(); streamIndex = in.readInt(); - trackIndex = streamIndex; } @Override @@ -151,4 +144,36 @@ public StreamKey[] newArray(int size) { return new StreamKey[size]; } }; + + // Bundleable implementation. + + private static final String FIELD_PERIOD_INDEX = Util.intToStringMaxRadix(0); + private static final String FIELD_GROUP_INDEX = Util.intToStringMaxRadix(1); + private static final String FIELD_STREAM_INDEX = Util.intToStringMaxRadix(2); + + @Override + public Bundle toBundle() { + Bundle bundle = new Bundle(); + if (periodIndex != 0) { + bundle.putInt(FIELD_PERIOD_INDEX, periodIndex); + } + if (groupIndex != 0) { + bundle.putInt(FIELD_GROUP_INDEX, groupIndex); + } + if (streamIndex != 0) { + bundle.putInt(FIELD_STREAM_INDEX, streamIndex); + } + return bundle; + } + + /** + * Constructs an instance of {@link StreamKey} from a {@link Bundle} produced by {@link + * #toBundle()}. + */ + public static StreamKey fromBundle(Bundle bundle) { + return new StreamKey( + bundle.getInt(FIELD_PERIOD_INDEX, /* defaultValue= */ 0), + bundle.getInt(FIELD_GROUP_INDEX, /* defaultValue= */ 0), + bundle.getInt(FIELD_STREAM_INDEX, /* defaultValue= */ 0)); + } } diff --git a/libraries/common/src/test/java/androidx/media3/common/StreamKeyTest.java b/libraries/common/src/test/java/androidx/media3/common/StreamKeyTest.java index 8ca8bfc70d7..1c254300ff7 100644 --- a/libraries/common/src/test/java/androidx/media3/common/StreamKeyTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/StreamKeyTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; +import android.os.Bundle; import android.os.Parcel; import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; @@ -28,7 +29,8 @@ public class StreamKeyTest { @Test public void parcelable() { - StreamKey streamKeyToParcel = new StreamKey(1, 2, 3); + StreamKey streamKeyToParcel = + new StreamKey(/* periodIndex= */ 1, /* groupIndex= */ 2, /* streamIndex= */ 3); Parcel parcel = Parcel.obtain(); streamKeyToParcel.writeToParcel(parcel, 0); parcel.setDataPosition(0); @@ -38,4 +40,36 @@ public void parcelable() { parcel.recycle(); } + + @Test + public void roundTripViaBundle_withDefaultPeriodIndex_yieldsEqualInstance() { + StreamKey originalStreamKey = new StreamKey(/* groupIndex= */ 1, /* streamIndex= */ 2); + + StreamKey streamKeyFromBundle = StreamKey.fromBundle(originalStreamKey.toBundle()); + + assertThat(originalStreamKey).isEqualTo(streamKeyFromBundle); + } + + @Test + public void roundTripViaBundle_toBundleSkipsDefaultValues_fromBundleRestoresThem() { + StreamKey originalStreamKey = new StreamKey(/* groupIndex= */ 0, /* streamIndex= */ 0); + + Bundle streamKeyBundle = originalStreamKey.toBundle(); + + assertThat(streamKeyBundle.keySet()).isEmpty(); + + StreamKey streamKeyFromBundle = StreamKey.fromBundle(streamKeyBundle); + + assertThat(originalStreamKey).isEqualTo(streamKeyFromBundle); + } + + @Test + public void roundTripViaBundle_yieldsEqualInstance() { + StreamKey originalStreamKey = + new StreamKey(/* periodIndex= */ 10, /* groupIndex= */ 11, /* streamIndex= */ 12); + + StreamKey streamKeyFromBundle = StreamKey.fromBundle(originalStreamKey.toBundle()); + + assertThat(originalStreamKey).isEqualTo(streamKeyFromBundle); + } } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DefaultDownloadIndexTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DefaultDownloadIndexTest.java index f5863a77c9a..314d5c3bac4 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DefaultDownloadIndexTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DefaultDownloadIndexTest.java @@ -102,8 +102,8 @@ public void addAndGetDownload_existingId_returnsUpdatedDownload() throws Databas .setStartTimeMs(10) .setUpdateTimeMs(20) .setStreamKeys( - new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 2), - new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* trackIndex= */ 5)) + new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* streamIndex= */ 2), + new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* streamIndex= */ 5)) .setCustomMetadata(new byte[] {0, 1, 2, 3, 7, 8, 9, 10}) .setKeySetId(new byte[] {0, 1, 2, 3}) .build(); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DownloadManagerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DownloadManagerTest.java index 858d98f2eb1..337736d9e30 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DownloadManagerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/offline/DownloadManagerTest.java @@ -302,13 +302,13 @@ public void removeAllDownloads_removesAllDownloads() throws Throwable { @Test public void downloads_withSameIdsAndDifferentStreamKeys_areMerged() throws Throwable { - StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0); + StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* streamIndex= */ 0); postDownloadRequest(ID1, streamKey1); FakeDownloader downloader0 = getDownloaderAt(0); downloader0.assertId(ID1); downloader0.assertDownloadStarted(); - StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1); + StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* streamIndex= */ 1); postDownloadRequest(ID1, streamKey2); // The request for streamKey2 will cause the downloader for streamKey1 to be canceled and // replaced with a new downloader for both keys.