From d4e5ab2c4d0c2d5c32b13a3f3910364ab59093c8 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 2 Nov 2023 03:15:08 -0700 Subject: [PATCH] Make BundleableUtil more generic by taking Function parameters BundleableUtil is the only class that really depends on the type inheritence from Bundleable. However, it only needs this as a way to define Function and Function, which could just be passed in as parameters as it's already done for some of these methods. Also rename the class to BundleCollectionUtil accordingly. PiperOrigin-RevId: 578791946 --- .../java/androidx/media3/common/Format.java | 8 +- .../androidx/media3/common/MediaItem.java | 34 ++++-- .../media3/common/PlaybackException.java | 2 +- .../java/androidx/media3/common/Timeline.java | 18 ++-- .../androidx/media3/common/TrackGroup.java | 24 +++-- .../media3/common/TrackSelectionOverride.java | 17 +-- .../common/TrackSelectionParameters.java | 13 ++- .../java/androidx/media3/common/Tracks.java | 38 +++---- .../java/androidx/media3/common/text/Cue.java | 4 +- .../androidx/media3/common/text/CueGroup.java | 7 +- ...bleUtil.java => BundleCollectionUtil.java} | 101 ++++++++++-------- .../media3/common/TrackGroupTest.java | 2 +- ...est.java => BundleCollectionUtilTest.java} | 20 ++-- .../exoplayer/source/TrackGroupArray.java | 28 ++--- .../trackselection/DefaultTrackSelector.java | 35 +++--- .../exoplayer/source/TrackGroupArrayTest.java | 2 +- .../DefaultTrackSelectorTest.java | 8 +- .../media3/extractor/text/CueDecoder.java | 4 +- .../media3/extractor/text/CueEncoder.java | 4 +- .../media3/session/CommandButton.java | 6 +- .../media3/session/ConnectionState.java | 7 +- .../media3/session/LibraryResult.java | 10 +- .../session/MediaControllerImplBase.java | 14 +-- .../media3/session/MediaControllerStub.java | 5 +- .../media3/session/MediaSessionStub.java | 25 ++--- .../MediaControllerProviderService.java | 22 ++-- .../media3/session/RemoteMediaController.java | 35 ++++-- 27 files changed, 281 insertions(+), 212 deletions(-) rename libraries/common/src/main/java/androidx/media3/common/util/{BundleableUtil.java => BundleCollectionUtil.java} (51%) rename libraries/common/src/test/java/androidx/media3/common/util/{BundleableUtilTest.java => BundleCollectionUtilTest.java} (78%) diff --git a/libraries/common/src/main/java/androidx/media3/common/Format.java b/libraries/common/src/main/java/androidx/media3/common/Format.java index ad2b579743..7c7ffafaeb 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Format.java +++ b/libraries/common/src/main/java/androidx/media3/common/Format.java @@ -20,7 +20,7 @@ import static java.lang.annotation.ElementType.TYPE_USE; import android.os.Bundle; import androidx.annotation.IntDef; import androidx.annotation.Nullable; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.base.Joiner; @@ -1450,9 +1450,11 @@ public final class Format implements Bundleable { /** Object that can restore {@code Format} from a {@link Bundle}. */ @UnstableApi public static final Creator CREATOR = Format::fromBundle; - private static Format fromBundle(Bundle bundle) { + /** Restores a {@code Format} from a {@link Bundle}. */ + @UnstableApi + public static Format fromBundle(Bundle bundle) { Builder builder = new Builder(); - BundleableUtil.ensureClassLoader(bundle); + BundleCollectionUtil.ensureClassLoader(bundle); builder .setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id)) .setLabel(defaultIfNull(bundle.getString(FIELD_LABEL), DEFAULT.label)) 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 926dde3a42..9880bcec64 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MediaItem.java +++ b/libraries/common/src/main/java/androidx/media3/common/MediaItem.java @@ -24,7 +24,7 @@ import android.os.Bundle; import androidx.annotation.IntRange; import androidx.annotation.Nullable; import androidx.media3.common.util.Assertions; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.collect.ImmutableList; @@ -929,15 +929,16 @@ public final class MediaItem implements Bundleable { UUID scheme = UUID.fromString(checkNotNull(bundle.getString(FIELD_SCHEME))); @Nullable Uri licenseUri = bundle.getParcelable(FIELD_LICENSE_URI); Bundle licenseMapAsBundle = - BundleableUtil.getBundleWithDefault(bundle, FIELD_LICENSE_REQUEST_HEADERS, Bundle.EMPTY); + BundleCollectionUtil.getBundleWithDefault( + bundle, FIELD_LICENSE_REQUEST_HEADERS, Bundle.EMPTY); ImmutableMap licenseRequestHeaders = - BundleableUtil.bundleToStringImmutableMap(licenseMapAsBundle); + BundleCollectionUtil.bundleToStringImmutableMap(licenseMapAsBundle); boolean multiSession = bundle.getBoolean(FIELD_MULTI_SESSION, false); boolean playClearContentWithoutKey = bundle.getBoolean(FIELD_PLAY_CLEAR_CONTENT_WITHOUT_KEY, false); boolean forceDefaultLicenseUri = bundle.getBoolean(FIELD_FORCE_DEFAULT_LICENSE_URI, false); ArrayList<@C.TrackType Integer> forcedSessionTrackTypesArray = - BundleableUtil.getIntegerArrayListWithDefault( + BundleCollectionUtil.getIntegerArrayListWithDefault( bundle, FIELD_FORCED_SESSION_TRACK_TYPES, new ArrayList<>()); ImmutableList<@C.TrackType Integer> forcedSessionTrackTypes = ImmutableList.copyOf(forcedSessionTrackTypesArray); @@ -965,7 +966,8 @@ public final class MediaItem implements Bundleable { } if (!licenseRequestHeaders.isEmpty()) { bundle.putBundle( - FIELD_LICENSE_REQUEST_HEADERS, BundleableUtil.stringMapToBundle(licenseRequestHeaders)); + FIELD_LICENSE_REQUEST_HEADERS, + BundleCollectionUtil.stringMapToBundle(licenseRequestHeaders)); } if (multiSession) { bundle.putBoolean(FIELD_MULTI_SESSION, multiSession); @@ -1246,14 +1248,17 @@ public final class MediaItem implements Bundleable { } if (!streamKeys.isEmpty()) { bundle.putParcelableArrayList( - FIELD_STREAM_KEYS, BundleableUtil.toBundleArrayList(streamKeys)); + FIELD_STREAM_KEYS, + BundleCollectionUtil.toBundleArrayList(streamKeys, StreamKey::toBundle)); } if (customCacheKey != null) { bundle.putString(FIELD_CUSTOM_CACHE_KEY, customCacheKey); } if (!subtitleConfigurations.isEmpty()) { bundle.putParcelableArrayList( - FIELD_SUBTITLE_CONFIGURATION, BundleableUtil.toBundleArrayList(subtitleConfigurations)); + FIELD_SUBTITLE_CONFIGURATION, + BundleCollectionUtil.toBundleArrayList( + subtitleConfigurations, SubtitleConfiguration::toBundle)); } if (imageDurationMs != C.TIME_UNSET) { bundle.putLong(FIELD_IMAGE_DURATION_MS, imageDurationMs); @@ -1277,13 +1282,14 @@ public final class MediaItem implements Bundleable { List streamKeys = streamKeysBundles == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles); + : BundleCollectionUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles); @Nullable List subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION); ImmutableList subtitleConfiguration = subtitleBundles == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(SubtitleConfiguration.CREATOR, subtitleBundles); + : BundleCollectionUtil.fromBundleList( + SubtitleConfiguration::fromBundle, subtitleBundles); long imageDurationMs = bundle.getLong(FIELD_IMAGE_DURATION_MS, C.TIME_UNSET); return new LocalConfiguration( @@ -2337,14 +2343,20 @@ public final class MediaItem implements Bundleable { } /** - * An object that can restore {@link MediaItem} from a {@link Bundle}. + * An object that can restore {@code MediaItem} from a {@link Bundle}. * *

The {@link #localConfiguration} of a restored instance will always be {@code null}. */ @UnstableApi public static final Creator CREATOR = MediaItem::fromBundle; + /** + * Restores a {@code MediaItem} from a {@link Bundle}. + * + *

The {@link #localConfiguration} of a restored instance will always be {@code null}. + */ + @UnstableApi @SuppressWarnings("deprecation") // Unbundling to ClippingProperties while it still exists. - private static MediaItem fromBundle(Bundle bundle) { + public static MediaItem fromBundle(Bundle bundle) { String mediaId = checkNotNull(bundle.getString(FIELD_MEDIA_ID, DEFAULT_MEDIA_ID)); @Nullable Bundle liveConfigurationBundle = bundle.getBundle(FIELD_LIVE_CONFIGURATION); LiveConfiguration liveConfiguration; diff --git a/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java b/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java index 44ff185d4e..ca2facab59 100644 --- a/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java +++ b/libraries/common/src/main/java/androidx/media3/common/PlaybackException.java @@ -455,7 +455,7 @@ public class PlaybackException extends Exception implements Bundleable { /** * Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()} - * and {@link Bundleable.Creator}. + * and delegating to {@link #PlaybackException(Bundle)}. * *

Subclasses should obtain their {@link Bundle Bundle's} field keys by applying a non-negative * offset on this constant and passing the result to {@link Util#intToStringMaxRadix(int)}. diff --git a/libraries/common/src/main/java/androidx/media3/common/Timeline.java b/libraries/common/src/main/java/androidx/media3/common/Timeline.java index 4b338ee44b..2bd7d09bc5 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Timeline.java +++ b/libraries/common/src/main/java/androidx/media3/common/Timeline.java @@ -28,14 +28,17 @@ import android.os.SystemClock; import android.util.Pair; import androidx.annotation.Nullable; import androidx.media3.common.util.Assertions; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.BundleUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; +import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.InlineMe; import java.util.ArrayList; import java.util.List; +import org.checkerframework.checker.nullness.qual.NonNull; // TODO: b/288080357 - Replace developer.android.com fully-qualified SVG URLs below with relative // URLs once we stop publishing exoplayer2 javadoc. @@ -1479,9 +1482,9 @@ public abstract class Timeline implements Bundleable { private static Timeline fromBundle(Bundle bundle) { ImmutableList windows = - fromBundleListRetriever(Window.CREATOR, BundleUtil.getBinder(bundle, FIELD_WINDOWS)); + fromBundleListRetriever(Window::fromBundle, BundleUtil.getBinder(bundle, FIELD_WINDOWS)); ImmutableList periods = - fromBundleListRetriever(Period.CREATOR, BundleUtil.getBinder(bundle, FIELD_PERIODS)); + fromBundleListRetriever(Period::fromBundle, BundleUtil.getBinder(bundle, FIELD_PERIODS)); @Nullable int[] shuffledWindowIndices = bundle.getIntArray(FIELD_SHUFFLED_WINDOW_INDICES); return new RemotableTimeline( windows, @@ -1491,17 +1494,12 @@ public abstract class Timeline implements Bundleable { : shuffledWindowIndices); } - private static ImmutableList fromBundleListRetriever( - Creator creator, @Nullable IBinder binder) { + private static ImmutableList fromBundleListRetriever( + Function fromBundleFunc, @Nullable IBinder binder) { if (binder == null) { return ImmutableList.of(); } - ImmutableList.Builder builder = new ImmutableList.Builder<>(); - List bundleList = BundleListRetriever.getList(binder); - for (int i = 0; i < bundleList.size(); i++) { - builder.add(creator.fromBundle(bundleList.get(i))); - } - return builder.build(); + return BundleCollectionUtil.fromBundleList(fromBundleFunc, BundleListRetriever.getList(binder)); } private static int[] generateUnshuffledIndices(int n) { diff --git a/libraries/common/src/main/java/androidx/media3/common/TrackGroup.java b/libraries/common/src/main/java/androidx/media3/common/TrackGroup.java index 6a19c28ea6..beea4a3519 100644 --- a/libraries/common/src/main/java/androidx/media3/common/TrackGroup.java +++ b/libraries/common/src/main/java/androidx/media3/common/TrackGroup.java @@ -20,7 +20,7 @@ import static androidx.media3.common.util.Assertions.checkArgument; import android.os.Bundle; import androidx.annotation.CheckResult; import androidx.annotation.Nullable; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -179,17 +179,19 @@ public final class TrackGroup implements Bundleable { } /** Object that can restore {@code TrackGroup} from a {@link Bundle}. */ + @UnstableApi public static final Creator CREATOR = TrackGroup::fromBundle; + + /** Restores a {@code TrackGroup} from a {@link Bundle}. */ @UnstableApi - public static final Creator CREATOR = - bundle -> { - @Nullable List formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS); - List formats = - formatBundles == null - ? ImmutableList.of() - : BundleableUtil.fromBundleList(Format.CREATOR, formatBundles); - String id = bundle.getString(FIELD_ID, /* defaultValue= */ ""); - return new TrackGroup(id, formats.toArray(new Format[0])); - }; + public static TrackGroup fromBundle(Bundle bundle) { + @Nullable List formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS); + List formats = + formatBundles == null + ? ImmutableList.of() + : BundleCollectionUtil.fromBundleList(Format::fromBundle, formatBundles); + String id = bundle.getString(FIELD_ID, /* defaultValue= */ ""); + return new TrackGroup(id, formats.toArray(new Format[0])); + } private void verifyCorrectness() { // TrackGroups should only contain tracks with exactly the same content (but in different diff --git a/libraries/common/src/main/java/androidx/media3/common/TrackSelectionOverride.java b/libraries/common/src/main/java/androidx/media3/common/TrackSelectionOverride.java index f7b08bacb0..7667697662 100644 --- a/libraries/common/src/main/java/androidx/media3/common/TrackSelectionOverride.java +++ b/libraries/common/src/main/java/androidx/media3/common/TrackSelectionOverride.java @@ -116,11 +116,14 @@ public final class TrackSelectionOverride implements Bundleable { /** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */ @UnstableApi - public static final Creator CREATOR = - bundle -> { - Bundle trackGroupBundle = checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP)); - TrackGroup mediaTrackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle); - int[] tracks = checkNotNull(bundle.getIntArray(FIELD_TRACKS)); - return new TrackSelectionOverride(mediaTrackGroup, Ints.asList(tracks)); - }; + public static final Creator CREATOR = TrackSelectionOverride::fromBundle; + + /** Restores a {@code TrackSelectionOverride} from a {@link Bundle}. */ + @UnstableApi + public static TrackSelectionOverride fromBundle(Bundle bundle) { + Bundle trackGroupBundle = checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP)); + TrackGroup mediaTrackGroup = TrackGroup.fromBundle(trackGroupBundle); + int[] tracks = checkNotNull(bundle.getIntArray(FIELD_TRACKS)); + return new TrackSelectionOverride(mediaTrackGroup, Ints.asList(tracks)); + } } diff --git a/libraries/common/src/main/java/androidx/media3/common/TrackSelectionParameters.java b/libraries/common/src/main/java/androidx/media3/common/TrackSelectionParameters.java index f7e5711d07..89e6acf057 100644 --- a/libraries/common/src/main/java/androidx/media3/common/TrackSelectionParameters.java +++ b/libraries/common/src/main/java/androidx/media3/common/TrackSelectionParameters.java @@ -16,7 +16,7 @@ package androidx.media3.common; import static androidx.media3.common.util.Assertions.checkNotNull; -import static androidx.media3.common.util.BundleableUtil.toBundleArrayList; +import static androidx.media3.common.util.BundleCollectionUtil.toBundleArrayList; import static com.google.common.base.MoreObjects.firstNonNull; import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -29,7 +29,7 @@ import android.view.accessibility.CaptioningManager; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.collect.ImmutableList; @@ -245,7 +245,8 @@ public class TrackSelectionParameters implements Bundleable { List overrideList = overrideBundleList == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(TrackSelectionOverride.CREATOR, overrideBundleList); + : BundleCollectionUtil.fromBundleList( + TrackSelectionOverride::fromBundle, overrideBundleList); overrides = new HashMap<>(); for (int i = 0; i < overrideList.size(); i++) { TrackSelectionOverride override = overrideList.get(i); @@ -1424,7 +1425,7 @@ public class TrackSelectionParameters implements Bundleable { /** * Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()} - * and {@link Bundleable.Creator}. + * and delegating to {@link Builder#Builder(Bundle)}. * *

Subclasses should obtain keys for their {@link Bundle} representation by applying a * non-negative offset on this constant and passing the result to {@link @@ -1477,7 +1478,9 @@ public class TrackSelectionParameters implements Bundleable { // General bundle.putBoolean(FIELD_FORCE_LOWEST_BITRATE, forceLowestBitrate); bundle.putBoolean(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE, forceHighestSupportedBitrate); - bundle.putParcelableArrayList(FIELD_SELECTION_OVERRIDES, toBundleArrayList(overrides.values())); + bundle.putParcelableArrayList( + FIELD_SELECTION_OVERRIDES, + toBundleArrayList(overrides.values(), TrackSelectionOverride::toBundle)); bundle.putIntArray(FIELD_DISABLED_TRACK_TYPE, Ints.toArray(disabledTrackTypes)); return bundle; diff --git a/libraries/common/src/main/java/androidx/media3/common/Tracks.java b/libraries/common/src/main/java/androidx/media3/common/Tracks.java index 86a73170df..00175f3213 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Tracks.java +++ b/libraries/common/src/main/java/androidx/media3/common/Tracks.java @@ -17,11 +17,11 @@ package androidx.media3.common; import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; -import static androidx.media3.common.util.BundleableUtil.toBundleArrayList; +import static androidx.media3.common.util.BundleCollectionUtil.toBundleArrayList; import android.os.Bundle; import androidx.annotation.Nullable; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.base.MoreObjects; @@ -245,21 +245,23 @@ public final class Tracks implements Bundleable { } /** Object that can restore a group of tracks from a {@link Bundle}. */ + @UnstableApi public static final Creator CREATOR = Group::fromBundle; + + /** Restores a group of tracks from a {@link Bundle}. */ @UnstableApi - public static final Creator CREATOR = - bundle -> { - // Can't create a Tracks.Group without a TrackGroup - TrackGroup trackGroup = - TrackGroup.CREATOR.fromBundle(checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP))); - final @C.FormatSupport int[] trackSupport = - MoreObjects.firstNonNull( - bundle.getIntArray(FIELD_TRACK_SUPPORT), new int[trackGroup.length]); - boolean[] selected = - MoreObjects.firstNonNull( - bundle.getBooleanArray(FIELD_TRACK_SELECTED), new boolean[trackGroup.length]); - boolean adaptiveSupported = bundle.getBoolean(FIELD_ADAPTIVE_SUPPORTED, false); - return new Group(trackGroup, adaptiveSupported, trackSupport, selected); - }; + public static Group fromBundle(Bundle bundle) { + // Can't create a Tracks.Group without a TrackGroup + TrackGroup trackGroup = + TrackGroup.fromBundle(checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP))); + final @C.FormatSupport int[] trackSupport = + MoreObjects.firstNonNull( + bundle.getIntArray(FIELD_TRACK_SUPPORT), new int[trackGroup.length]); + boolean[] selected = + MoreObjects.firstNonNull( + bundle.getBooleanArray(FIELD_TRACK_SELECTED), new boolean[trackGroup.length]); + boolean adaptiveSupported = bundle.getBoolean(FIELD_ADAPTIVE_SUPPORTED, false); + return new Group(trackGroup, adaptiveSupported, trackSupport, selected); + } } /** Empty tracks. */ @@ -383,7 +385,7 @@ public final class Tracks implements Bundleable { @Override public Bundle toBundle() { Bundle bundle = new Bundle(); - bundle.putParcelableArrayList(FIELD_TRACK_GROUPS, toBundleArrayList(groups)); + bundle.putParcelableArrayList(FIELD_TRACK_GROUPS, toBundleArrayList(groups, Group::toBundle)); return bundle; } @@ -395,7 +397,7 @@ public final class Tracks implements Bundleable { List groups = groupBundles == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(Group.CREATOR, groupBundles); + : BundleCollectionUtil.fromBundleList(Group::fromBundle, groupBundles); return new Tracks(groups); }; } diff --git a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java index d5d4b0148f..a8155c43fe 100644 --- a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java +++ b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java @@ -869,7 +869,9 @@ public final class Cue implements Bundleable { @UnstableApi public static final Creator CREATOR = Cue::fromBundle; - private static final Cue fromBundle(Bundle bundle) { + /** Restores a cue from a {@link Bundle}. */ + @UnstableApi + public static Cue fromBundle(Bundle bundle) { Builder builder = new Builder(); @Nullable CharSequence text = bundle.getCharSequence(FIELD_TEXT); if (text != null) { diff --git a/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java b/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java index c8aa409d73..ecafd16f9f 100644 --- a/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java +++ b/libraries/common/src/main/java/androidx/media3/common/text/CueGroup.java @@ -20,7 +20,7 @@ import android.os.Bundle; import androidx.annotation.Nullable; import androidx.media3.common.Bundleable; import androidx.media3.common.Timeline; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.collect.ImmutableList; @@ -69,7 +69,8 @@ public final class CueGroup implements Bundleable { public Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putParcelableArrayList( - FIELD_CUES, BundleableUtil.toBundleArrayList(filterOutBitmapCues(cues))); + FIELD_CUES, + BundleCollectionUtil.toBundleArrayList(filterOutBitmapCues(cues), Cue::toBundle)); bundle.putLong(FIELD_PRESENTATION_TIME_US, presentationTimeUs); return bundle; } @@ -81,7 +82,7 @@ public final class CueGroup implements Bundleable { List cues = cueBundles == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(Cue.CREATOR, cueBundles); + : BundleCollectionUtil.fromBundleList(Cue::fromBundle, cueBundles); long presentationTimeUs = bundle.getLong(FIELD_PRESENTATION_TIME_US); return new CueGroup(cues, presentationTimeUs); } diff --git a/libraries/common/src/main/java/androidx/media3/common/util/BundleableUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/BundleCollectionUtil.java similarity index 51% rename from libraries/common/src/main/java/androidx/media3/common/util/BundleableUtil.java rename to libraries/common/src/main/java/androidx/media3/common/util/BundleCollectionUtil.java index 7049542c1b..11dee1c837 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/BundleableUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/BundleCollectionUtil.java @@ -21,7 +21,6 @@ import static androidx.media3.common.util.Util.castNonNull; import android.os.Bundle; import android.util.SparseArray; import androidx.annotation.Nullable; -import androidx.media3.common.Bundleable; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -30,81 +29,97 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.checkerframework.checker.nullness.qual.NonNull; -/** Utilities for {@link Bundleable}. */ +/** Utilities for converting collections to and from {@link Bundle} instances. */ @UnstableApi -public final class BundleableUtil { - - /** Converts a list of {@link Bundleable} to a list {@link Bundle}. */ - public static ImmutableList toBundleList(List bundleableList) { - return toBundleList(bundleableList, Bundleable::toBundle); - } +public final class BundleCollectionUtil { /** - * Converts a list of {@link Bundleable} to a list {@link Bundle} + * Bundles a list of objects to a list of {@link Bundle} instances. * - * @param bundleableList list of Bundleable items to be converted - * @param customToBundleFunc function that specifies how to bundle up each {@link Bundleable} + * @param list List of items to be bundled. + * @param toBundleFunc Function that specifies how to bundle each item. + * @return The {@link ImmutableList} of bundled items. */ - public static ImmutableList toBundleList( - List bundleableList, Function customToBundleFunc) { + public static ImmutableList toBundleList( + List list, Function toBundleFunc) { ImmutableList.Builder builder = ImmutableList.builder(); - for (int i = 0; i < bundleableList.size(); i++) { - T bundleable = bundleableList.get(i); - builder.add(customToBundleFunc.apply(bundleable)); + for (int i = 0; i < list.size(); i++) { + T item = list.get(i); + builder.add(toBundleFunc.apply(item)); } return builder.build(); } - /** Converts a list of {@link Bundle} to a list of {@link Bundleable}. */ - public static ImmutableList fromBundleList( - Bundleable.Creator creator, List bundleList) { + /** + * Unbundles a list of {@link Bundle} instances to a list of objects. + * + * @param fromBundleFunc Function that specified how to unbundle each item. + * @param bundleList List of {@link Bundle} instances to be unbundled. + * @return The {@link ImmutableList} of unbundled items. + */ + public static ImmutableList fromBundleList( + Function fromBundleFunc, List bundleList) { ImmutableList.Builder builder = ImmutableList.builder(); for (int i = 0; i < bundleList.size(); i++) { Bundle bundle = checkNotNull(bundleList.get(i)); // Fail fast during parsing. - T bundleable = creator.fromBundle(bundle); - builder.add(bundleable); + T item = fromBundleFunc.apply(bundle); + builder.add(item); } return builder.build(); } /** - * Converts a collection of {@link Bundleable} to an {@link ArrayList} of {@link Bundle} so that - * the returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList} + * Bundles a collection of objects to an {@link ArrayList} of {@link Bundle} instances so that the + * returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList} * conveniently. + * + * @param items Collection of items to be bundled. + * @param toBundleFunc Function that specifies how to bundle each item. + * @return The {@link ArrayList} of bundled items. */ - public static ArrayList toBundleArrayList( - Collection bundleables) { - ArrayList arrayList = new ArrayList<>(bundleables.size()); - for (T element : bundleables) { - arrayList.add(element.toBundle()); + @SuppressWarnings("NonApiType") // Intentionally using ArrayList for putParcelableArrayList. + public static ArrayList toBundleArrayList( + Collection items, Function toBundleFunc) { + ArrayList arrayList = new ArrayList<>(items.size()); + for (T item : items) { + arrayList.add(toBundleFunc.apply(item)); } return arrayList; } /** - * Converts a {@link SparseArray} of {@link Bundle} to a {@link SparseArray} of {@link - * Bundleable}. + * Unbundles a {@link SparseArray} of {@link Bundle} instances to a {@link SparseArray} of + * objects. + * + * @param fromBundleFunc Function that specified how to unbundle each item. + * @param bundleSparseArray {@link SparseArray} of {@link Bundle} instances to be unbundled. + * @return The {@link SparseArray} of unbundled items. */ - public static SparseArray fromBundleSparseArray( - Bundleable.Creator creator, SparseArray bundleSparseArray) { + public static SparseArray fromBundleSparseArray( + Function fromBundleFunc, SparseArray bundleSparseArray) { SparseArray result = new SparseArray<>(bundleSparseArray.size()); for (int i = 0; i < bundleSparseArray.size(); i++) { - result.put(bundleSparseArray.keyAt(i), creator.fromBundle(bundleSparseArray.valueAt(i))); + result.put(bundleSparseArray.keyAt(i), fromBundleFunc.apply(bundleSparseArray.valueAt(i))); } return result; } /** - * Converts a {@link SparseArray} of {@link Bundleable} to an {@link SparseArray} of {@link - * Bundle} so that the returned {@link SparseArray} can be put to {@link Bundle} using {@link + * Bundles a {@link SparseArray} of objects to a {@link SparseArray} of {@link Bundle} instances + * so that the returned {@link SparseArray} can be put to {@link Bundle} using {@link * Bundle#putSparseParcelableArray} conveniently. + * + * @param items Collection of items to be bundled. + * @param toBundleFunc Function that specifies how to bundle each item. + * @return The {@link SparseArray} of bundled items. */ - public static SparseArray toBundleSparseArray( - SparseArray bundleableSparseArray) { - SparseArray sparseArray = new SparseArray<>(bundleableSparseArray.size()); - for (int i = 0; i < bundleableSparseArray.size(); i++) { - sparseArray.put(bundleableSparseArray.keyAt(i), bundleableSparseArray.valueAt(i).toBundle()); + public static SparseArray toBundleSparseArray( + SparseArray items, Function toBundleFunc) { + SparseArray sparseArray = new SparseArray<>(items.size()); + for (int i = 0; i < items.size(); i++) { + sparseArray.put(items.keyAt(i), toBundleFunc.apply(items.valueAt(i))); } return sparseArray; } @@ -154,13 +169,13 @@ public final class BundleableUtil { * Sets the application class loader to the given {@link Bundle} if no class loader is present. * *

This assumes that all classes unparceled from {@code bundle} are sharing the class loader of - * {@code BundleableUtils}. + * {@code BundleCollectionUtil}. */ public static void ensureClassLoader(@Nullable Bundle bundle) { if (bundle != null) { - bundle.setClassLoader(castNonNull(BundleableUtil.class.getClassLoader())); + bundle.setClassLoader(castNonNull(BundleCollectionUtil.class.getClassLoader())); } } - private BundleableUtil() {} + private BundleCollectionUtil() {} } diff --git a/libraries/common/src/test/java/androidx/media3/common/TrackGroupTest.java b/libraries/common/src/test/java/androidx/media3/common/TrackGroupTest.java index bd4075a60a..e59a857540 100644 --- a/libraries/common/src/test/java/androidx/media3/common/TrackGroupTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/TrackGroupTest.java @@ -34,7 +34,7 @@ public final class TrackGroupTest { TrackGroup trackGroupToBundle = new TrackGroup(id, format1, format2); - TrackGroup trackGroupFromBundle = TrackGroup.CREATOR.fromBundle(trackGroupToBundle.toBundle()); + TrackGroup trackGroupFromBundle = TrackGroup.fromBundle(trackGroupToBundle.toBundle()); assertThat(trackGroupFromBundle).isEqualTo(trackGroupToBundle); } diff --git a/libraries/common/src/test/java/androidx/media3/common/util/BundleableUtilTest.java b/libraries/common/src/test/java/androidx/media3/common/util/BundleCollectionUtilTest.java similarity index 78% rename from libraries/common/src/test/java/androidx/media3/common/util/BundleableUtilTest.java rename to libraries/common/src/test/java/androidx/media3/common/util/BundleCollectionUtilTest.java index 239485e3c1..93d8eeed34 100644 --- a/libraries/common/src/test/java/androidx/media3/common/util/BundleableUtilTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/util/BundleCollectionUtilTest.java @@ -25,9 +25,9 @@ import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; -/** Unit tests for {@link BundleableUtil}. */ +/** Unit tests for {@link BundleCollectionUtil}. */ @RunWith(AndroidJUnit4.class) -public class BundleableUtilTest { +public class BundleCollectionUtilTest { @Test public void testStringMapToBundle() { @@ -37,8 +37,8 @@ public class BundleableUtilTest { originalMap.put("thirdKey", "repeatedValue"); originalMap.put("", "valueOfEmptyKey"); - Bundle mapAsBundle = BundleableUtil.stringMapToBundle(originalMap); - Map restoredMap = BundleableUtil.bundleToStringHashMap(mapAsBundle); + Bundle mapAsBundle = BundleCollectionUtil.stringMapToBundle(originalMap); + Map restoredMap = BundleCollectionUtil.bundleToStringHashMap(mapAsBundle); assertThat(restoredMap).isEqualTo(originalMap); } @@ -57,11 +57,11 @@ public class BundleableUtilTest { outerBundle.putBundle("2", null); Bundle restoredInnerBundle = - BundleableUtil.getBundleWithDefault(outerBundle, "0", defaultBundle); + BundleCollectionUtil.getBundleWithDefault(outerBundle, "0", defaultBundle); Bundle restoredEmptyBundle = - BundleableUtil.getBundleWithDefault(outerBundle, "1", defaultBundle); + BundleCollectionUtil.getBundleWithDefault(outerBundle, "1", defaultBundle); Bundle restoredNullBundle = - BundleableUtil.getBundleWithDefault(outerBundle, "2", defaultBundle); + BundleCollectionUtil.getBundleWithDefault(outerBundle, "2", defaultBundle); assertThat(restoredInnerBundle).isEqualTo(fullInnerBundle); assertThat(restoredEmptyBundle).isEqualTo(Bundle.EMPTY); @@ -83,11 +83,11 @@ public class BundleableUtilTest { bundle.putIntegerArrayList("2", null); ArrayList restoredIntegerArray = - BundleableUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray); + BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray); ArrayList restoredEmptyIntegerArray = - BundleableUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray); + BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray); ArrayList restoredNullIntegerArray = - BundleableUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray); + BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray); assertThat(restoredIntegerArray).isEqualTo(normalArray); assertThat(restoredEmptyIntegerArray).isEqualTo(emptyArray); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/TrackGroupArray.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/TrackGroupArray.java index befc158d25..3256caeab0 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/TrackGroupArray.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/TrackGroupArray.java @@ -20,7 +20,7 @@ import androidx.annotation.Nullable; import androidx.media3.common.Bundleable; import androidx.media3.common.C; import androidx.media3.common.TrackGroup; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -118,22 +118,24 @@ public final class TrackGroupArray implements Bundleable { public Bundle toBundle() { Bundle bundle = new Bundle(); bundle.putParcelableArrayList( - FIELD_TRACK_GROUPS, BundleableUtil.toBundleArrayList(trackGroups)); + FIELD_TRACK_GROUPS, + BundleCollectionUtil.toBundleArrayList(trackGroups, TrackGroup::toBundle)); return bundle; } /** Object that can restores a TrackGroupArray from a {@link Bundle}. */ - public static final Creator CREATOR = - bundle -> { - @Nullable - List trackGroupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS); - if (trackGroupBundles == null) { - return new TrackGroupArray(); - } - return new TrackGroupArray( - BundleableUtil.fromBundleList(TrackGroup.CREATOR, trackGroupBundles) - .toArray(new TrackGroup[0])); - }; + public static final Creator CREATOR = TrackGroupArray::fromBundle; + + /** Restores a {@code TrackGroupArray} from a {@link Bundle}. */ + public static TrackGroupArray fromBundle(Bundle bundle) { + @Nullable List trackGroupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS); + if (trackGroupBundles == null) { + return new TrackGroupArray(); + } + return new TrackGroupArray( + BundleCollectionUtil.fromBundleList(TrackGroup::fromBundle, trackGroupBundles) + .toArray(new TrackGroup[0])); + } private void verifyCorrectness() { for (int i = 0; i < trackGroups.size(); i++) { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.java index 34c732b992..966995854a 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelector.java @@ -55,7 +55,7 @@ import androidx.media3.common.TrackSelectionOverride; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences; import androidx.media3.common.util.Assertions; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.common.util.NullableType; import androidx.media3.common.util.UnstableApi; @@ -1646,15 +1646,16 @@ public class DefaultTrackSelector extends MappingTrackSelector List trackGroupArrays = trackGroupArrayBundles == null ? ImmutableList.of() - : BundleableUtil.fromBundleList(TrackGroupArray.CREATOR, trackGroupArrayBundles); + : BundleCollectionUtil.fromBundleList( + TrackGroupArray::fromBundle, trackGroupArrayBundles); @Nullable SparseArray selectionOverrideBundles = bundle.getSparseParcelableArray(Parameters.FIELD_SELECTION_OVERRIDES); SparseArray selectionOverrides = selectionOverrideBundles == null ? new SparseArray<>() - : BundleableUtil.fromBundleSparseArray( - SelectionOverride.CREATOR, selectionOverrideBundles); + : BundleCollectionUtil.fromBundleSparseArray( + SelectionOverride::fromBundle, selectionOverrideBundles); if (rendererIndices == null || rendererIndices.length != trackGroupArrays.size()) { return; // Incorrect format, ignore all overrides. @@ -2091,9 +2092,10 @@ public class DefaultTrackSelector extends MappingTrackSelector FIELD_SELECTION_OVERRIDES_RENDERER_INDICES, Ints.toArray(rendererIndices)); bundle.putParcelableArrayList( FIELD_SELECTION_OVERRIDES_TRACK_GROUP_ARRAYS, - BundleableUtil.toBundleArrayList(trackGroupArrays)); + BundleCollectionUtil.toBundleArrayList(trackGroupArrays, TrackGroupArray::toBundle)); bundle.putSparseParcelableArray( - FIELD_SELECTION_OVERRIDES, BundleableUtil.toBundleSparseArray(selections)); + FIELD_SELECTION_OVERRIDES, + BundleCollectionUtil.toBundleSparseArray(selections, SelectionOverride::toBundle)); } } @@ -2238,15 +2240,18 @@ public class DefaultTrackSelector extends MappingTrackSelector /** Object that can restore {@code SelectionOverride} from a {@link Bundle}. */ @UnstableApi - public static final Creator CREATOR = - bundle -> { - int groupIndex = bundle.getInt(FIELD_GROUP_INDEX, -1); - @Nullable int[] tracks = bundle.getIntArray(FIELD_TRACKS); - int trackType = bundle.getInt(FIELD_TRACK_TYPE, -1); - Assertions.checkArgument(groupIndex >= 0 && trackType >= 0); - Assertions.checkNotNull(tracks); - return new SelectionOverride(groupIndex, tracks, trackType); - }; + public static final Creator CREATOR = SelectionOverride::fromBundle; + + /** Restores a {@code SelectionOverride} from a {@link Bundle}. */ + @UnstableApi + public static SelectionOverride fromBundle(Bundle bundle) { + int groupIndex = bundle.getInt(FIELD_GROUP_INDEX, -1); + @Nullable int[] tracks = bundle.getIntArray(FIELD_TRACKS); + int trackType = bundle.getInt(FIELD_TRACK_TYPE, -1); + Assertions.checkArgument(groupIndex >= 0 && trackType >= 0); + Assertions.checkNotNull(tracks); + return new SelectionOverride(groupIndex, tracks, trackType); + } } /** diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/TrackGroupArrayTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/TrackGroupArrayTest.java index 4557f251b9..3d09048471 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/TrackGroupArrayTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/TrackGroupArrayTest.java @@ -41,7 +41,7 @@ public final class TrackGroupArrayTest { TrackGroupArray trackGroupArrayToBundle = new TrackGroupArray(trackGroup1, trackGroup2); TrackGroupArray trackGroupArrayFromBundle = - TrackGroupArray.CREATOR.fromBundle(trackGroupArrayToBundle.toBundle()); + TrackGroupArray.fromBundle(trackGroupArrayToBundle.toBundle()); assertThat(trackGroupArrayFromBundle).isEqualTo(trackGroupArrayToBundle); } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java index 3c1cf49c86..2ea08255bc 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/trackselection/DefaultTrackSelectorTest.java @@ -45,7 +45,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.media.Spatializer; -import androidx.media3.common.Bundleable; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; @@ -181,7 +180,7 @@ public final class DefaultTrackSelectorTest { assertThat(parameters.buildUpon().build()).isEqualTo(parameters); } - /** Tests {@link Parameters} {@link Bundleable} implementation. */ + /** Tests {@link Parameters} bundle implementation. */ @Test public void roundTripViaBundle_ofParameters_yieldsEqualInstance() { Parameters parametersToBundle = buildParametersForEqualsTest(); @@ -2841,15 +2840,14 @@ public final class DefaultTrackSelectorTest { assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED); } - /** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */ + /** Tests {@link SelectionOverride}'s bundle implementation. */ @Test public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() { SelectionOverride selectionOverrideToBundle = new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3); SelectionOverride selectionOverrideFromBundle = - DefaultTrackSelector.SelectionOverride.CREATOR.fromBundle( - selectionOverrideToBundle.toBundle()); + DefaultTrackSelector.SelectionOverride.fromBundle(selectionOverrideToBundle.toBundle()); assertThat(selectionOverrideFromBundle).isEqualTo(selectionOverrideToBundle); } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueDecoder.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueDecoder.java index fcda2ed1f5..e64f9d8308 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueDecoder.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueDecoder.java @@ -19,7 +19,7 @@ import android.os.Bundle; import android.os.Parcel; import androidx.media3.common.text.Cue; import androidx.media3.common.util.Assertions; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import java.util.ArrayList; import java.util.List; @@ -65,7 +65,7 @@ public final class CueDecoder { ArrayList bundledCues = Assertions.checkNotNull(bundle.getParcelableArrayList(BUNDLE_FIELD_CUES)); return new CuesWithTiming( - BundleableUtil.fromBundleList(Cue.CREATOR, bundledCues), + BundleCollectionUtil.fromBundleList(Cue::fromBundle, bundledCues), startTimeUs, bundle.getLong(BUNDLE_FIELD_DURATION_US)); } diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueEncoder.java b/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueEncoder.java index 8519b8b32e..9439b98441 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueEncoder.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/text/CueEncoder.java @@ -18,7 +18,7 @@ package androidx.media3.extractor.text; import android.os.Bundle; import android.os.Parcel; import androidx.media3.common.text.Cue; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import java.util.ArrayList; import java.util.List; @@ -36,7 +36,7 @@ public final class CueEncoder { * @return The serialized byte array. */ public byte[] encode(List cues, long durationUs) { - ArrayList bundledCues = BundleableUtil.toBundleArrayList(cues); + ArrayList bundledCues = BundleCollectionUtil.toBundleArrayList(cues, Cue::toBundle); Bundle allCuesBundle = new Bundle(); allCuesBundle.putParcelableArrayList(CueDecoder.BUNDLE_FIELD_CUES, bundledCues); allCuesBundle.putLong(CueDecoder.BUNDLE_FIELD_DURATION_US, durationUs); diff --git a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java index 2a03eb4d4d..3a55d51432 100644 --- a/libraries/session/src/main/java/androidx/media3/session/CommandButton.java +++ b/libraries/session/src/main/java/androidx/media3/session/CommandButton.java @@ -294,10 +294,12 @@ public final class CommandButton implements Bundleable { return bundle; } - /** Object that can restore {@link CommandButton} from a {@link Bundle}. */ + /** Object that can restore {@code CommandButton} from a {@link Bundle}. */ @UnstableApi public static final Creator CREATOR = CommandButton::fromBundle; - private static CommandButton fromBundle(Bundle bundle) { + /** Restores a {@code CommandButton} from a {@link Bundle}. */ + @UnstableApi + public static CommandButton fromBundle(Bundle bundle) { @Nullable Bundle sessionCommandBundle = bundle.getBundle(FIELD_SESSION_COMMAND); @Nullable SessionCommand sessionCommand = diff --git a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java index bf928cd1f0..a7eb3143db 100644 --- a/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java +++ b/libraries/session/src/main/java/androidx/media3/session/ConnectionState.java @@ -25,8 +25,8 @@ import androidx.annotation.Nullable; import androidx.core.app.BundleCompat; import androidx.media3.common.Bundleable; import androidx.media3.common.Player; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.BundleUtil; -import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.Util; import com.google.common.collect.ImmutableList; import java.util.List; @@ -108,7 +108,8 @@ import java.util.List; bundle.putParcelable(FIELD_SESSION_ACTIVITY, sessionActivity); if (!customLayout.isEmpty()) { bundle.putParcelableArrayList( - FIELD_CUSTOM_LAYOUT, BundleableUtil.toBundleArrayList(customLayout)); + FIELD_CUSTOM_LAYOUT, + BundleCollectionUtil.toBundleArrayList(customLayout, CommandButton::toBundle)); } bundle.putBundle(FIELD_SESSION_COMMANDS, sessionCommands.toBundle()); bundle.putBundle(FIELD_PLAYER_COMMANDS_FROM_SESSION, playerCommandsFromSession.toBundle()); @@ -153,7 +154,7 @@ import java.util.List; List commandButtonArrayList = bundle.getParcelableArrayList(FIELD_CUSTOM_LAYOUT); ImmutableList customLayout = commandButtonArrayList != null - ? BundleableUtil.fromBundleList(CommandButton.CREATOR, commandButtonArrayList) + ? BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonArrayList) : ImmutableList.of(); @Nullable Bundle sessionCommandsBundle = bundle.getBundle(FIELD_SESSION_COMMANDS); SessionCommands sessionCommands = diff --git a/libraries/session/src/main/java/androidx/media3/session/LibraryResult.java b/libraries/session/src/main/java/androidx/media3/session/LibraryResult.java index 4310bf697e..a1972522d5 100644 --- a/libraries/session/src/main/java/androidx/media3/session/LibraryResult.java +++ b/libraries/session/src/main/java/androidx/media3/session/LibraryResult.java @@ -32,7 +32,7 @@ import androidx.media3.common.BundleListRetriever; import androidx.media3.common.Bundleable; import androidx.media3.common.MediaItem; import androidx.media3.common.MediaMetadata; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.session.MediaLibraryService.LibraryParams; @@ -292,7 +292,9 @@ public final class LibraryResult implements Bundleable { BundleCompat.putBinder( bundle, FIELD_VALUE, - new BundleListRetriever(BundleableUtil.toBundleList((ImmutableList) value))); + new BundleListRetriever( + BundleCollectionUtil.toBundleList( + (ImmutableList) value, MediaItem::toBundle))); break; case VALUE_TYPE_VOID: case VALUE_TYPE_ERROR: @@ -376,8 +378,8 @@ public final class LibraryResult implements Bundleable { value = valueRetriever == null ? null - : BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(valueRetriever)); + : BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(valueRetriever)); break; case VALUE_TYPE_VOID: case VALUE_TYPE_ERROR: diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java index febd4e485d..70172f8a54 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerImplBase.java @@ -73,7 +73,7 @@ import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.VideoSize; import androidx.media3.common.text.CueGroup; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Clock; import androidx.media3.common.util.ListenerSet; import androidx.media3.common.util.Log; @@ -801,7 +801,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; controllerStub, seq, new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); setMediaItemsInternal( @@ -823,7 +823,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; controllerStub, seq, new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)), resetPosition)); @@ -846,7 +846,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; controllerStub, seq, new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)), startIndex, startPositionMs)); @@ -921,7 +921,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; controllerStub, seq, new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); addMediaItemsInternal(getCurrentTimeline().getWindowCount(), mediaItems); @@ -941,7 +941,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; seq, index, new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); addMediaItemsInternal(index, mediaItems); @@ -1254,7 +1254,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; (iSession, seq) -> { IBinder mediaItemsBundleBinder = new BundleListRetriever( - BundleableUtil.toBundleList( + BundleCollectionUtil.toBundleList( mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) { iSession.replaceMediaItems( diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java index 9c4dc73119..636532cd7d 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaControllerStub.java @@ -25,7 +25,7 @@ import android.os.RemoteException; import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.media3.common.Player.Commands; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.session.MediaLibraryService.LibraryParams; import androidx.media3.session.PlayerInfo.BundlingExclusions; @@ -100,7 +100,8 @@ import org.checkerframework.checker.nullness.qual.NonNull; public void onSetCustomLayout(int seq, List commandButtonBundleList) { List layout; try { - layout = BundleableUtil.fromBundleList(CommandButton.CREATOR, commandButtonBundleList); + layout = + BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonBundleList); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for CommandButton", e); return; diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java index 5bde573e57..5f61a9ccf0 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionStub.java @@ -80,7 +80,7 @@ import androidx.media3.common.TrackSelectionOverride; import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.Tracks; import androidx.media3.common.util.Assertions; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Consumer; import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; @@ -1045,8 +1045,8 @@ import java.util.concurrent.ExecutionException; List mediaItemList; try { mediaItemList = - BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); + BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever)); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); return; @@ -1083,8 +1083,8 @@ import java.util.concurrent.ExecutionException; List mediaItemList; try { mediaItemList = - BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); + BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever)); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); return; @@ -1192,8 +1192,8 @@ import java.util.concurrent.ExecutionException; List mediaItems; try { mediaItems = - BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); + BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever)); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); return; @@ -1221,8 +1221,8 @@ import java.util.concurrent.ExecutionException; List mediaItems; try { mediaItems = - BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); + BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever)); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); return; @@ -1360,8 +1360,8 @@ import java.util.concurrent.ExecutionException; ImmutableList mediaItems; try { mediaItems = - BundleableUtil.fromBundleList( - MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); + BundleCollectionUtil.fromBundleList( + MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever)); } catch (RuntimeException e) { Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); return; @@ -2006,7 +2006,8 @@ import java.util.concurrent.ExecutionException; @Override public void setCustomLayout(int sequenceNumber, List layout) throws RemoteException { - iController.onSetCustomLayout(sequenceNumber, BundleableUtil.toBundleList(layout)); + iController.onSetCustomLayout( + sequenceNumber, BundleCollectionUtil.toBundleList(layout, CommandButton::toBundle)); } @Override diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java index 7bc0a320d0..07d656cb47 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaControllerProviderService.java @@ -34,7 +34,7 @@ import androidx.media3.common.MediaMetadata; import androidx.media3.common.PlaybackParameters; import androidx.media3.common.Rating; import androidx.media3.common.TrackSelectionParameters; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.test.session.common.IRemoteMediaController; import androidx.media3.test.session.common.TestHandler; @@ -325,7 +325,7 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.setMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles)); + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles)); }); } @@ -337,7 +337,8 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.setMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles), resetPosition); + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles), + resetPosition); }); } @@ -349,7 +350,7 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.setMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles), + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles), startIndex, startPositionMs); }); @@ -407,7 +408,7 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.addMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles)); + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles)); }); } @@ -418,7 +419,8 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.addMediaItems( - index, BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles)); + index, + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles)); }); } @@ -488,7 +490,9 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.replaceMediaItems( - fromIndex, toIndex, BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItems)); + fromIndex, + toIndex, + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItems)); }); } @@ -753,11 +757,11 @@ public class MediaControllerProviderService extends Service { () -> { MediaController controller = mediaControllerMap.get(controllerId); controller.setMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, initialMediaItems)); + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, initialMediaItems)); controller.prepare(); controller.play(); controller.addMediaItems( - BundleableUtil.fromBundleList(MediaItem.CREATOR, addedMediaItems)); + BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, addedMediaItems)); controller.seekTo(seekIndex, /* positionMs= */ 0); }); } diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java index 22b4727f28..d49ff24192 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/RemoteMediaController.java @@ -39,7 +39,7 @@ import androidx.media3.common.Player; import androidx.media3.common.Player.RepeatMode; import androidx.media3.common.Rating; import androidx.media3.common.TrackSelectionParameters; -import androidx.media3.common.util.BundleableUtil; +import androidx.media3.common.util.BundleCollectionUtil; import androidx.media3.common.util.Log; import androidx.media3.test.session.common.IRemoteMediaController; import androidx.media3.test.session.common.TestUtils; @@ -162,26 +162,33 @@ public class RemoteMediaController { } public void setMediaItems(List mediaItems) throws RemoteException { - binder.setMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems)); + binder.setMediaItems( + controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle)); } public void setMediaItemsIncludeLocalConfiguration(List mediaItems) throws RemoteException { binder.setMediaItems( controllerId, - BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); + BundleCollectionUtil.toBundleList( + mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); } public void setMediaItems(List mediaItems, boolean resetPosition) throws RemoteException { binder.setMediaItemsWithResetPosition( - controllerId, BundleableUtil.toBundleList(mediaItems), resetPosition); + controllerId, + BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle), + resetPosition); } public void setMediaItems(List mediaItems, int startIndex, long startPositionMs) throws RemoteException { binder.setMediaItemsWithStartIndex( - controllerId, BundleableUtil.toBundleList(mediaItems), startIndex, startPositionMs); + controllerId, + BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle), + startIndex, + startPositionMs); } /** @@ -211,18 +218,21 @@ public class RemoteMediaController { } public void addMediaItems(List mediaItems) throws RemoteException { - binder.addMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems)); + binder.addMediaItems( + controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle)); } public void addMediaItemsIncludeLocalConfiguration(List mediaItems) throws RemoteException { binder.addMediaItems( controllerId, - BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); + BundleCollectionUtil.toBundleList( + mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); } public void addMediaItems(int index, List mediaItems) throws RemoteException { - binder.addMediaItemsWithIndex(controllerId, index, BundleableUtil.toBundleList(mediaItems)); + binder.addMediaItemsWithIndex( + controllerId, index, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle)); } public void removeMediaItem(int index) throws RemoteException { @@ -252,7 +262,10 @@ public class RemoteMediaController { public void replaceMediaItems(int fromIndex, int toIndex, List mediaItems) throws RemoteException { binder.replaceMediaItems( - controllerId, fromIndex, toIndex, BundleableUtil.toBundleList(mediaItems)); + controllerId, + fromIndex, + toIndex, + BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle)); } public void seekToPreviousMediaItem() throws RemoteException { @@ -354,8 +367,8 @@ public class RemoteMediaController { throws RemoteException { binder.setMediaItemsPreparePlayAddItemsSeek( controllerId, - BundleableUtil.toBundleList(initialMediaItems), - BundleableUtil.toBundleList(addedMediaItems), + BundleCollectionUtil.toBundleList(initialMediaItems, MediaItem::toBundle), + BundleCollectionUtil.toBundleList(addedMediaItems, MediaItem::toBundle), seekIndex); }