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<T, Bundle> and Function<Bundle, T>, 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
This commit is contained in:
tonihei 2023-11-02 03:15:08 -07:00 committed by Copybara-Service
parent de82aa93f0
commit d4e5ab2c4d
27 changed files with 281 additions and 212 deletions

View File

@ -20,7 +20,7 @@ import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.base.Joiner; 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}. */ /** Object that can restore {@code Format} from a {@link Bundle}. */
@UnstableApi public static final Creator<Format> CREATOR = Format::fromBundle; @UnstableApi public static final Creator<Format> 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(); Builder builder = new Builder();
BundleableUtil.ensureClassLoader(bundle); BundleCollectionUtil.ensureClassLoader(bundle);
builder builder
.setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id)) .setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id))
.setLabel(defaultIfNull(bundle.getString(FIELD_LABEL), DEFAULT.label)) .setLabel(defaultIfNull(bundle.getString(FIELD_LABEL), DEFAULT.label))

View File

@ -24,7 +24,7 @@ import android.os.Bundle;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.Assertions; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; 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))); UUID scheme = UUID.fromString(checkNotNull(bundle.getString(FIELD_SCHEME)));
@Nullable Uri licenseUri = bundle.getParcelable(FIELD_LICENSE_URI); @Nullable Uri licenseUri = bundle.getParcelable(FIELD_LICENSE_URI);
Bundle licenseMapAsBundle = Bundle licenseMapAsBundle =
BundleableUtil.getBundleWithDefault(bundle, FIELD_LICENSE_REQUEST_HEADERS, Bundle.EMPTY); BundleCollectionUtil.getBundleWithDefault(
bundle, FIELD_LICENSE_REQUEST_HEADERS, Bundle.EMPTY);
ImmutableMap<String, String> licenseRequestHeaders = ImmutableMap<String, String> licenseRequestHeaders =
BundleableUtil.bundleToStringImmutableMap(licenseMapAsBundle); BundleCollectionUtil.bundleToStringImmutableMap(licenseMapAsBundle);
boolean multiSession = bundle.getBoolean(FIELD_MULTI_SESSION, false); boolean multiSession = bundle.getBoolean(FIELD_MULTI_SESSION, false);
boolean playClearContentWithoutKey = boolean playClearContentWithoutKey =
bundle.getBoolean(FIELD_PLAY_CLEAR_CONTENT_WITHOUT_KEY, false); bundle.getBoolean(FIELD_PLAY_CLEAR_CONTENT_WITHOUT_KEY, false);
boolean forceDefaultLicenseUri = bundle.getBoolean(FIELD_FORCE_DEFAULT_LICENSE_URI, false); boolean forceDefaultLicenseUri = bundle.getBoolean(FIELD_FORCE_DEFAULT_LICENSE_URI, false);
ArrayList<@C.TrackType Integer> forcedSessionTrackTypesArray = ArrayList<@C.TrackType Integer> forcedSessionTrackTypesArray =
BundleableUtil.getIntegerArrayListWithDefault( BundleCollectionUtil.getIntegerArrayListWithDefault(
bundle, FIELD_FORCED_SESSION_TRACK_TYPES, new ArrayList<>()); bundle, FIELD_FORCED_SESSION_TRACK_TYPES, new ArrayList<>());
ImmutableList<@C.TrackType Integer> forcedSessionTrackTypes = ImmutableList<@C.TrackType Integer> forcedSessionTrackTypes =
ImmutableList.copyOf(forcedSessionTrackTypesArray); ImmutableList.copyOf(forcedSessionTrackTypesArray);
@ -965,7 +966,8 @@ public final class MediaItem implements Bundleable {
} }
if (!licenseRequestHeaders.isEmpty()) { if (!licenseRequestHeaders.isEmpty()) {
bundle.putBundle( bundle.putBundle(
FIELD_LICENSE_REQUEST_HEADERS, BundleableUtil.stringMapToBundle(licenseRequestHeaders)); FIELD_LICENSE_REQUEST_HEADERS,
BundleCollectionUtil.stringMapToBundle(licenseRequestHeaders));
} }
if (multiSession) { if (multiSession) {
bundle.putBoolean(FIELD_MULTI_SESSION, multiSession); bundle.putBoolean(FIELD_MULTI_SESSION, multiSession);
@ -1246,14 +1248,17 @@ public final class MediaItem implements Bundleable {
} }
if (!streamKeys.isEmpty()) { if (!streamKeys.isEmpty()) {
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_STREAM_KEYS, BundleableUtil.toBundleArrayList(streamKeys)); FIELD_STREAM_KEYS,
BundleCollectionUtil.toBundleArrayList(streamKeys, StreamKey::toBundle));
} }
if (customCacheKey != null) { if (customCacheKey != null) {
bundle.putString(FIELD_CUSTOM_CACHE_KEY, customCacheKey); bundle.putString(FIELD_CUSTOM_CACHE_KEY, customCacheKey);
} }
if (!subtitleConfigurations.isEmpty()) { if (!subtitleConfigurations.isEmpty()) {
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_SUBTITLE_CONFIGURATION, BundleableUtil.toBundleArrayList(subtitleConfigurations)); FIELD_SUBTITLE_CONFIGURATION,
BundleCollectionUtil.toBundleArrayList(
subtitleConfigurations, SubtitleConfiguration::toBundle));
} }
if (imageDurationMs != C.TIME_UNSET) { if (imageDurationMs != C.TIME_UNSET) {
bundle.putLong(FIELD_IMAGE_DURATION_MS, imageDurationMs); bundle.putLong(FIELD_IMAGE_DURATION_MS, imageDurationMs);
@ -1277,13 +1282,14 @@ public final class MediaItem implements Bundleable {
List<StreamKey> streamKeys = List<StreamKey> streamKeys =
streamKeysBundles == null streamKeysBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles); : BundleCollectionUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles);
@Nullable @Nullable
List<Bundle> subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION); List<Bundle> subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION);
ImmutableList<SubtitleConfiguration> subtitleConfiguration = ImmutableList<SubtitleConfiguration> subtitleConfiguration =
subtitleBundles == null subtitleBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(SubtitleConfiguration.CREATOR, subtitleBundles); : BundleCollectionUtil.fromBundleList(
SubtitleConfiguration::fromBundle, subtitleBundles);
long imageDurationMs = bundle.getLong(FIELD_IMAGE_DURATION_MS, C.TIME_UNSET); long imageDurationMs = bundle.getLong(FIELD_IMAGE_DURATION_MS, C.TIME_UNSET);
return new LocalConfiguration( 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}.
* *
* <p>The {@link #localConfiguration} of a restored instance will always be {@code null}. * <p>The {@link #localConfiguration} of a restored instance will always be {@code null}.
*/ */
@UnstableApi public static final Creator<MediaItem> CREATOR = MediaItem::fromBundle; @UnstableApi public static final Creator<MediaItem> CREATOR = MediaItem::fromBundle;
/**
* Restores a {@code MediaItem} from a {@link Bundle}.
*
* <p>The {@link #localConfiguration} of a restored instance will always be {@code null}.
*/
@UnstableApi
@SuppressWarnings("deprecation") // Unbundling to ClippingProperties while it still exists. @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)); String mediaId = checkNotNull(bundle.getString(FIELD_MEDIA_ID, DEFAULT_MEDIA_ID));
@Nullable Bundle liveConfigurationBundle = bundle.getBundle(FIELD_LIVE_CONFIGURATION); @Nullable Bundle liveConfigurationBundle = bundle.getBundle(FIELD_LIVE_CONFIGURATION);
LiveConfiguration liveConfiguration; LiveConfiguration liveConfiguration;

View File

@ -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()} * Defines a minimum field ID value for subclasses to use when implementing {@link #toBundle()}
* and {@link Bundleable.Creator}. * and delegating to {@link #PlaybackException(Bundle)}.
* *
* <p>Subclasses should obtain their {@link Bundle Bundle's} field keys by applying a non-negative * <p>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)}. * offset on this constant and passing the result to {@link Util#intToStringMaxRadix(int)}.

View File

@ -28,14 +28,17 @@ import android.os.SystemClock;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.BundleCollectionUtil;
import androidx.media3.common.util.BundleUtil; import androidx.media3.common.util.BundleUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.InlineMe; import com.google.errorprone.annotations.InlineMe;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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 // TODO: b/288080357 - Replace developer.android.com fully-qualified SVG URLs below with relative
// URLs once we stop publishing exoplayer2 javadoc. // URLs once we stop publishing exoplayer2 javadoc.
@ -1479,9 +1482,9 @@ public abstract class Timeline implements Bundleable {
private static Timeline fromBundle(Bundle bundle) { private static Timeline fromBundle(Bundle bundle) {
ImmutableList<Window> windows = ImmutableList<Window> windows =
fromBundleListRetriever(Window.CREATOR, BundleUtil.getBinder(bundle, FIELD_WINDOWS)); fromBundleListRetriever(Window::fromBundle, BundleUtil.getBinder(bundle, FIELD_WINDOWS));
ImmutableList<Period> periods = ImmutableList<Period> 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); @Nullable int[] shuffledWindowIndices = bundle.getIntArray(FIELD_SHUFFLED_WINDOW_INDICES);
return new RemotableTimeline( return new RemotableTimeline(
windows, windows,
@ -1491,17 +1494,12 @@ public abstract class Timeline implements Bundleable {
: shuffledWindowIndices); : shuffledWindowIndices);
} }
private static <T extends Bundleable> ImmutableList<T> fromBundleListRetriever( private static <T extends @NonNull Object> ImmutableList<T> fromBundleListRetriever(
Creator<T> creator, @Nullable IBinder binder) { Function<Bundle, T> fromBundleFunc, @Nullable IBinder binder) {
if (binder == null) { if (binder == null) {
return ImmutableList.of(); return ImmutableList.of();
} }
ImmutableList.Builder<T> builder = new ImmutableList.Builder<>(); return BundleCollectionUtil.fromBundleList(fromBundleFunc, BundleListRetriever.getList(binder));
List<Bundle> bundleList = BundleListRetriever.getList(binder);
for (int i = 0; i < bundleList.size(); i++) {
builder.add(creator.fromBundle(bundleList.get(i)));
}
return builder.build();
} }
private static int[] generateUnshuffledIndices(int n) { private static int[] generateUnshuffledIndices(int n) {

View File

@ -20,7 +20,7 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.CheckResult; import androidx.annotation.CheckResult;
import androidx.annotation.Nullable; 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.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; 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}. */ /** Object that can restore {@code TrackGroup} from a {@link Bundle}. */
@UnstableApi public static final Creator<TrackGroup> CREATOR = TrackGroup::fromBundle;
/** Restores a {@code TrackGroup} from a {@link Bundle}. */
@UnstableApi @UnstableApi
public static final Creator<TrackGroup> CREATOR = public static TrackGroup fromBundle(Bundle bundle) {
bundle -> { @Nullable List<Bundle> formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS);
@Nullable List<Bundle> formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS); List<Format> formats =
List<Format> formats = formatBundles == null
formatBundles == null ? ImmutableList.of()
? ImmutableList.of() : BundleCollectionUtil.fromBundleList(Format::fromBundle, formatBundles);
: BundleableUtil.fromBundleList(Format.CREATOR, formatBundles); String id = bundle.getString(FIELD_ID, /* defaultValue= */ "");
String id = bundle.getString(FIELD_ID, /* defaultValue= */ ""); return new TrackGroup(id, formats.toArray(new Format[0]));
return new TrackGroup(id, formats.toArray(new Format[0])); }
};
private void verifyCorrectness() { private void verifyCorrectness() {
// TrackGroups should only contain tracks with exactly the same content (but in different // TrackGroups should only contain tracks with exactly the same content (but in different

View File

@ -116,11 +116,14 @@ public final class TrackSelectionOverride implements Bundleable {
/** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */ /** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */
@UnstableApi @UnstableApi
public static final Creator<TrackSelectionOverride> CREATOR = public static final Creator<TrackSelectionOverride> CREATOR = TrackSelectionOverride::fromBundle;
bundle -> {
Bundle trackGroupBundle = checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP)); /** Restores a {@code TrackSelectionOverride} from a {@link Bundle}. */
TrackGroup mediaTrackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle); @UnstableApi
int[] tracks = checkNotNull(bundle.getIntArray(FIELD_TRACKS)); public static TrackSelectionOverride fromBundle(Bundle bundle) {
return new TrackSelectionOverride(mediaTrackGroup, Ints.asList(tracks)); 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));
}
} }

View File

@ -16,7 +16,7 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkNotNull; 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 com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
@ -29,7 +29,7 @@ import android.view.accessibility.CaptioningManager;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -245,7 +245,8 @@ public class TrackSelectionParameters implements Bundleable {
List<TrackSelectionOverride> overrideList = List<TrackSelectionOverride> overrideList =
overrideBundleList == null overrideBundleList == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(TrackSelectionOverride.CREATOR, overrideBundleList); : BundleCollectionUtil.fromBundleList(
TrackSelectionOverride::fromBundle, overrideBundleList);
overrides = new HashMap<>(); overrides = new HashMap<>();
for (int i = 0; i < overrideList.size(); i++) { for (int i = 0; i < overrideList.size(); i++) {
TrackSelectionOverride override = overrideList.get(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()} * 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)}.
* *
* <p>Subclasses should obtain keys for their {@link Bundle} representation by applying a * <p>Subclasses should obtain keys for their {@link Bundle} representation by applying a
* non-negative offset on this constant and passing the result to {@link * non-negative offset on this constant and passing the result to {@link
@ -1477,7 +1478,9 @@ public class TrackSelectionParameters implements Bundleable {
// General // General
bundle.putBoolean(FIELD_FORCE_LOWEST_BITRATE, forceLowestBitrate); bundle.putBoolean(FIELD_FORCE_LOWEST_BITRATE, forceLowestBitrate);
bundle.putBoolean(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE, forceHighestSupportedBitrate); 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)); bundle.putIntArray(FIELD_DISABLED_TRACK_TYPE, Ints.toArray(disabledTrackTypes));
return bundle; return bundle;

View File

@ -17,11 +17,11 @@ package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; 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 android.os.Bundle;
import androidx.annotation.Nullable; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.base.MoreObjects; 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}. */ /** Object that can restore a group of tracks from a {@link Bundle}. */
@UnstableApi public static final Creator<Group> CREATOR = Group::fromBundle;
/** Restores a group of tracks from a {@link Bundle}. */
@UnstableApi @UnstableApi
public static final Creator<Group> CREATOR = public static Group fromBundle(Bundle bundle) {
bundle -> { // Can't create a Tracks.Group without a TrackGroup
// Can't create a Tracks.Group without a TrackGroup TrackGroup trackGroup =
TrackGroup trackGroup = TrackGroup.fromBundle(checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP)));
TrackGroup.CREATOR.fromBundle(checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP))); final @C.FormatSupport int[] trackSupport =
final @C.FormatSupport int[] trackSupport = MoreObjects.firstNonNull(
MoreObjects.firstNonNull( bundle.getIntArray(FIELD_TRACK_SUPPORT), new int[trackGroup.length]);
bundle.getIntArray(FIELD_TRACK_SUPPORT), new int[trackGroup.length]); boolean[] selected =
boolean[] selected = MoreObjects.firstNonNull(
MoreObjects.firstNonNull( bundle.getBooleanArray(FIELD_TRACK_SELECTED), new boolean[trackGroup.length]);
bundle.getBooleanArray(FIELD_TRACK_SELECTED), new boolean[trackGroup.length]); boolean adaptiveSupported = bundle.getBoolean(FIELD_ADAPTIVE_SUPPORTED, false);
boolean adaptiveSupported = bundle.getBoolean(FIELD_ADAPTIVE_SUPPORTED, false); return new Group(trackGroup, adaptiveSupported, trackSupport, selected);
return new Group(trackGroup, adaptiveSupported, trackSupport, selected); }
};
} }
/** Empty tracks. */ /** Empty tracks. */
@ -383,7 +385,7 @@ public final class Tracks implements Bundleable {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList(FIELD_TRACK_GROUPS, toBundleArrayList(groups)); bundle.putParcelableArrayList(FIELD_TRACK_GROUPS, toBundleArrayList(groups, Group::toBundle));
return bundle; return bundle;
} }
@ -395,7 +397,7 @@ public final class Tracks implements Bundleable {
List<Group> groups = List<Group> groups =
groupBundles == null groupBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(Group.CREATOR, groupBundles); : BundleCollectionUtil.fromBundleList(Group::fromBundle, groupBundles);
return new Tracks(groups); return new Tracks(groups);
}; };
} }

View File

@ -869,7 +869,9 @@ public final class Cue implements Bundleable {
@UnstableApi public static final Creator<Cue> CREATOR = Cue::fromBundle; @UnstableApi public static final Creator<Cue> 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(); Builder builder = new Builder();
@Nullable CharSequence text = bundle.getCharSequence(FIELD_TEXT); @Nullable CharSequence text = bundle.getCharSequence(FIELD_TEXT);
if (text != null) { if (text != null) {

View File

@ -20,7 +20,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.Timeline; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -69,7 +69,8 @@ public final class CueGroup implements Bundleable {
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_CUES, BundleableUtil.toBundleArrayList(filterOutBitmapCues(cues))); FIELD_CUES,
BundleCollectionUtil.toBundleArrayList(filterOutBitmapCues(cues), Cue::toBundle));
bundle.putLong(FIELD_PRESENTATION_TIME_US, presentationTimeUs); bundle.putLong(FIELD_PRESENTATION_TIME_US, presentationTimeUs);
return bundle; return bundle;
} }
@ -81,7 +82,7 @@ public final class CueGroup implements Bundleable {
List<Cue> cues = List<Cue> cues =
cueBundles == null cueBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(Cue.CREATOR, cueBundles); : BundleCollectionUtil.fromBundleList(Cue::fromBundle, cueBundles);
long presentationTimeUs = bundle.getLong(FIELD_PRESENTATION_TIME_US); long presentationTimeUs = bundle.getLong(FIELD_PRESENTATION_TIME_US);
return new CueGroup(cues, presentationTimeUs); return new CueGroup(cues, presentationTimeUs);
} }

View File

@ -21,7 +21,6 @@ import static androidx.media3.common.util.Util.castNonNull;
import android.os.Bundle; import android.os.Bundle;
import android.util.SparseArray; import android.util.SparseArray;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -30,81 +29,97 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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 @UnstableApi
public final class BundleableUtil { public final class BundleCollectionUtil {
/** Converts a list of {@link Bundleable} to a list {@link Bundle}. */
public static <T extends Bundleable> ImmutableList<Bundle> toBundleList(List<T> bundleableList) {
return toBundleList(bundleableList, Bundleable::toBundle);
}
/** /**
* 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 list List of items to be bundled.
* @param customToBundleFunc function that specifies how to bundle up each {@link Bundleable} * @param toBundleFunc Function that specifies how to bundle each item.
* @return The {@link ImmutableList} of bundled items.
*/ */
public static <T extends Bundleable> ImmutableList<Bundle> toBundleList( public static <T extends @NonNull Object> ImmutableList<Bundle> toBundleList(
List<T> bundleableList, Function<T, Bundle> customToBundleFunc) { List<T> list, Function<T, Bundle> toBundleFunc) {
ImmutableList.Builder<Bundle> builder = ImmutableList.builder(); ImmutableList.Builder<Bundle> builder = ImmutableList.builder();
for (int i = 0; i < bundleableList.size(); i++) { for (int i = 0; i < list.size(); i++) {
T bundleable = bundleableList.get(i); T item = list.get(i);
builder.add(customToBundleFunc.apply(bundleable)); builder.add(toBundleFunc.apply(item));
} }
return builder.build(); return builder.build();
} }
/** Converts a list of {@link Bundle} to a list of {@link Bundleable}. */ /**
public static <T extends Bundleable> ImmutableList<T> fromBundleList( * Unbundles a list of {@link Bundle} instances to a list of objects.
Bundleable.Creator<T> creator, List<Bundle> bundleList) { *
* @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 <T extends @NonNull Object> ImmutableList<T> fromBundleList(
Function<Bundle, T> fromBundleFunc, List<Bundle> bundleList) {
ImmutableList.Builder<T> builder = ImmutableList.builder(); ImmutableList.Builder<T> builder = ImmutableList.builder();
for (int i = 0; i < bundleList.size(); i++) { for (int i = 0; i < bundleList.size(); i++) {
Bundle bundle = checkNotNull(bundleList.get(i)); // Fail fast during parsing. Bundle bundle = checkNotNull(bundleList.get(i)); // Fail fast during parsing.
T bundleable = creator.fromBundle(bundle); T item = fromBundleFunc.apply(bundle);
builder.add(bundleable); builder.add(item);
} }
return builder.build(); return builder.build();
} }
/** /**
* Converts a collection of {@link Bundleable} to an {@link ArrayList} of {@link Bundle} so that * Bundles a collection of objects to an {@link ArrayList} of {@link Bundle} instances so that the
* the returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList} * returned list can be put to {@link Bundle} using {@link Bundle#putParcelableArrayList}
* conveniently. * 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 <T extends Bundleable> ArrayList<Bundle> toBundleArrayList( @SuppressWarnings("NonApiType") // Intentionally using ArrayList for putParcelableArrayList.
Collection<T> bundleables) { public static <T extends @NonNull Object> ArrayList<Bundle> toBundleArrayList(
ArrayList<Bundle> arrayList = new ArrayList<>(bundleables.size()); Collection<T> items, Function<T, Bundle> toBundleFunc) {
for (T element : bundleables) { ArrayList<Bundle> arrayList = new ArrayList<>(items.size());
arrayList.add(element.toBundle()); for (T item : items) {
arrayList.add(toBundleFunc.apply(item));
} }
return arrayList; return arrayList;
} }
/** /**
* Converts a {@link SparseArray} of {@link Bundle} to a {@link SparseArray} of {@link * Unbundles a {@link SparseArray} of {@link Bundle} instances to a {@link SparseArray} of
* Bundleable}. * 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 <T extends Bundleable> SparseArray<T> fromBundleSparseArray( public static <T extends @NonNull Object> SparseArray<T> fromBundleSparseArray(
Bundleable.Creator<T> creator, SparseArray<Bundle> bundleSparseArray) { Function<Bundle, T> fromBundleFunc, SparseArray<Bundle> bundleSparseArray) {
SparseArray<T> result = new SparseArray<>(bundleSparseArray.size()); SparseArray<T> result = new SparseArray<>(bundleSparseArray.size());
for (int i = 0; i < bundleSparseArray.size(); i++) { 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; return result;
} }
/** /**
* Converts a {@link SparseArray} of {@link Bundleable} to an {@link SparseArray} of {@link * Bundles a {@link SparseArray} of objects to a {@link SparseArray} of {@link Bundle} instances
* Bundle} so that the returned {@link SparseArray} can be put to {@link Bundle} using {@link * so that the returned {@link SparseArray} can be put to {@link Bundle} using {@link
* Bundle#putSparseParcelableArray} conveniently. * 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 <T extends Bundleable> SparseArray<Bundle> toBundleSparseArray( public static <T extends @NonNull Object> SparseArray<Bundle> toBundleSparseArray(
SparseArray<T> bundleableSparseArray) { SparseArray<T> items, Function<T, Bundle> toBundleFunc) {
SparseArray<Bundle> sparseArray = new SparseArray<>(bundleableSparseArray.size()); SparseArray<Bundle> sparseArray = new SparseArray<>(items.size());
for (int i = 0; i < bundleableSparseArray.size(); i++) { for (int i = 0; i < items.size(); i++) {
sparseArray.put(bundleableSparseArray.keyAt(i), bundleableSparseArray.valueAt(i).toBundle()); sparseArray.put(items.keyAt(i), toBundleFunc.apply(items.valueAt(i)));
} }
return sparseArray; 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. * Sets the application class loader to the given {@link Bundle} if no class loader is present.
* *
* <p>This assumes that all classes unparceled from {@code bundle} are sharing the class loader of * <p>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) { public static void ensureClassLoader(@Nullable Bundle bundle) {
if (bundle != null) { if (bundle != null) {
bundle.setClassLoader(castNonNull(BundleableUtil.class.getClassLoader())); bundle.setClassLoader(castNonNull(BundleCollectionUtil.class.getClassLoader()));
} }
} }
private BundleableUtil() {} private BundleCollectionUtil() {}
} }

View File

@ -34,7 +34,7 @@ public final class TrackGroupTest {
TrackGroup trackGroupToBundle = new TrackGroup(id, format1, format2); TrackGroup trackGroupToBundle = new TrackGroup(id, format1, format2);
TrackGroup trackGroupFromBundle = TrackGroup.CREATOR.fromBundle(trackGroupToBundle.toBundle()); TrackGroup trackGroupFromBundle = TrackGroup.fromBundle(trackGroupToBundle.toBundle());
assertThat(trackGroupFromBundle).isEqualTo(trackGroupToBundle); assertThat(trackGroupFromBundle).isEqualTo(trackGroupToBundle);
} }

View File

@ -25,9 +25,9 @@ import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Unit tests for {@link BundleableUtil}. */ /** Unit tests for {@link BundleCollectionUtil}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class BundleableUtilTest { public class BundleCollectionUtilTest {
@Test @Test
public void testStringMapToBundle() { public void testStringMapToBundle() {
@ -37,8 +37,8 @@ public class BundleableUtilTest {
originalMap.put("thirdKey", "repeatedValue"); originalMap.put("thirdKey", "repeatedValue");
originalMap.put("", "valueOfEmptyKey"); originalMap.put("", "valueOfEmptyKey");
Bundle mapAsBundle = BundleableUtil.stringMapToBundle(originalMap); Bundle mapAsBundle = BundleCollectionUtil.stringMapToBundle(originalMap);
Map<String, String> restoredMap = BundleableUtil.bundleToStringHashMap(mapAsBundle); Map<String, String> restoredMap = BundleCollectionUtil.bundleToStringHashMap(mapAsBundle);
assertThat(restoredMap).isEqualTo(originalMap); assertThat(restoredMap).isEqualTo(originalMap);
} }
@ -57,11 +57,11 @@ public class BundleableUtilTest {
outerBundle.putBundle("2", null); outerBundle.putBundle("2", null);
Bundle restoredInnerBundle = Bundle restoredInnerBundle =
BundleableUtil.getBundleWithDefault(outerBundle, "0", defaultBundle); BundleCollectionUtil.getBundleWithDefault(outerBundle, "0", defaultBundle);
Bundle restoredEmptyBundle = Bundle restoredEmptyBundle =
BundleableUtil.getBundleWithDefault(outerBundle, "1", defaultBundle); BundleCollectionUtil.getBundleWithDefault(outerBundle, "1", defaultBundle);
Bundle restoredNullBundle = Bundle restoredNullBundle =
BundleableUtil.getBundleWithDefault(outerBundle, "2", defaultBundle); BundleCollectionUtil.getBundleWithDefault(outerBundle, "2", defaultBundle);
assertThat(restoredInnerBundle).isEqualTo(fullInnerBundle); assertThat(restoredInnerBundle).isEqualTo(fullInnerBundle);
assertThat(restoredEmptyBundle).isEqualTo(Bundle.EMPTY); assertThat(restoredEmptyBundle).isEqualTo(Bundle.EMPTY);
@ -83,11 +83,11 @@ public class BundleableUtilTest {
bundle.putIntegerArrayList("2", null); bundle.putIntegerArrayList("2", null);
ArrayList<Integer> restoredIntegerArray = ArrayList<Integer> restoredIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray); BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray);
ArrayList<Integer> restoredEmptyIntegerArray = ArrayList<Integer> restoredEmptyIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray); BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray);
ArrayList<Integer> restoredNullIntegerArray = ArrayList<Integer> restoredNullIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray); BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray);
assertThat(restoredIntegerArray).isEqualTo(normalArray); assertThat(restoredIntegerArray).isEqualTo(normalArray);
assertThat(restoredEmptyIntegerArray).isEqualTo(emptyArray); assertThat(restoredEmptyIntegerArray).isEqualTo(emptyArray);

View File

@ -20,7 +20,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.TrackGroup; 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.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -118,22 +118,24 @@ public final class TrackGroupArray implements Bundleable {
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_TRACK_GROUPS, BundleableUtil.toBundleArrayList(trackGroups)); FIELD_TRACK_GROUPS,
BundleCollectionUtil.toBundleArrayList(trackGroups, TrackGroup::toBundle));
return bundle; return bundle;
} }
/** Object that can restores a TrackGroupArray from a {@link Bundle}. */ /** Object that can restores a TrackGroupArray from a {@link Bundle}. */
public static final Creator<TrackGroupArray> CREATOR = public static final Creator<TrackGroupArray> CREATOR = TrackGroupArray::fromBundle;
bundle -> {
@Nullable /** Restores a {@code TrackGroupArray} from a {@link Bundle}. */
List<Bundle> trackGroupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS); public static TrackGroupArray fromBundle(Bundle bundle) {
if (trackGroupBundles == null) { @Nullable List<Bundle> trackGroupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS);
return new TrackGroupArray(); if (trackGroupBundles == null) {
} return new TrackGroupArray();
return new TrackGroupArray( }
BundleableUtil.fromBundleList(TrackGroup.CREATOR, trackGroupBundles) return new TrackGroupArray(
.toArray(new TrackGroup[0])); BundleCollectionUtil.fromBundleList(TrackGroup::fromBundle, trackGroupBundles)
}; .toArray(new TrackGroup[0]));
}
private void verifyCorrectness() { private void verifyCorrectness() {
for (int i = 0; i < trackGroups.size(); i++) { for (int i = 0; i < trackGroups.size(); i++) {

View File

@ -55,7 +55,7 @@ import androidx.media3.common.TrackSelectionOverride;
import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences; import androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences;
import androidx.media3.common.util.Assertions; 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.Log;
import androidx.media3.common.util.NullableType; import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
@ -1646,15 +1646,16 @@ public class DefaultTrackSelector extends MappingTrackSelector
List<TrackGroupArray> trackGroupArrays = List<TrackGroupArray> trackGroupArrays =
trackGroupArrayBundles == null trackGroupArrayBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(TrackGroupArray.CREATOR, trackGroupArrayBundles); : BundleCollectionUtil.fromBundleList(
TrackGroupArray::fromBundle, trackGroupArrayBundles);
@Nullable @Nullable
SparseArray<Bundle> selectionOverrideBundles = SparseArray<Bundle> selectionOverrideBundles =
bundle.getSparseParcelableArray(Parameters.FIELD_SELECTION_OVERRIDES); bundle.getSparseParcelableArray(Parameters.FIELD_SELECTION_OVERRIDES);
SparseArray<SelectionOverride> selectionOverrides = SparseArray<SelectionOverride> selectionOverrides =
selectionOverrideBundles == null selectionOverrideBundles == null
? new SparseArray<>() ? new SparseArray<>()
: BundleableUtil.fromBundleSparseArray( : BundleCollectionUtil.fromBundleSparseArray(
SelectionOverride.CREATOR, selectionOverrideBundles); SelectionOverride::fromBundle, selectionOverrideBundles);
if (rendererIndices == null || rendererIndices.length != trackGroupArrays.size()) { if (rendererIndices == null || rendererIndices.length != trackGroupArrays.size()) {
return; // Incorrect format, ignore all overrides. return; // Incorrect format, ignore all overrides.
@ -2091,9 +2092,10 @@ public class DefaultTrackSelector extends MappingTrackSelector
FIELD_SELECTION_OVERRIDES_RENDERER_INDICES, Ints.toArray(rendererIndices)); FIELD_SELECTION_OVERRIDES_RENDERER_INDICES, Ints.toArray(rendererIndices));
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
FIELD_SELECTION_OVERRIDES_TRACK_GROUP_ARRAYS, FIELD_SELECTION_OVERRIDES_TRACK_GROUP_ARRAYS,
BundleableUtil.toBundleArrayList(trackGroupArrays)); BundleCollectionUtil.toBundleArrayList(trackGroupArrays, TrackGroupArray::toBundle));
bundle.putSparseParcelableArray( 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}. */ /** Object that can restore {@code SelectionOverride} from a {@link Bundle}. */
@UnstableApi @UnstableApi
public static final Creator<SelectionOverride> CREATOR = public static final Creator<SelectionOverride> CREATOR = SelectionOverride::fromBundle;
bundle -> {
int groupIndex = bundle.getInt(FIELD_GROUP_INDEX, -1); /** Restores a {@code SelectionOverride} from a {@link Bundle}. */
@Nullable int[] tracks = bundle.getIntArray(FIELD_TRACKS); @UnstableApi
int trackType = bundle.getInt(FIELD_TRACK_TYPE, -1); public static SelectionOverride fromBundle(Bundle bundle) {
Assertions.checkArgument(groupIndex >= 0 && trackType >= 0); int groupIndex = bundle.getInt(FIELD_GROUP_INDEX, -1);
Assertions.checkNotNull(tracks); @Nullable int[] tracks = bundle.getIntArray(FIELD_TRACKS);
return new SelectionOverride(groupIndex, tracks, trackType); int trackType = bundle.getInt(FIELD_TRACK_TYPE, -1);
}; Assertions.checkArgument(groupIndex >= 0 && trackType >= 0);
Assertions.checkNotNull(tracks);
return new SelectionOverride(groupIndex, tracks, trackType);
}
} }
/** /**

View File

@ -41,7 +41,7 @@ public final class TrackGroupArrayTest {
TrackGroupArray trackGroupArrayToBundle = new TrackGroupArray(trackGroup1, trackGroup2); TrackGroupArray trackGroupArrayToBundle = new TrackGroupArray(trackGroup1, trackGroup2);
TrackGroupArray trackGroupArrayFromBundle = TrackGroupArray trackGroupArrayFromBundle =
TrackGroupArray.CREATOR.fromBundle(trackGroupArrayToBundle.toBundle()); TrackGroupArray.fromBundle(trackGroupArrayToBundle.toBundle());
assertThat(trackGroupArrayFromBundle).isEqualTo(trackGroupArrayToBundle); assertThat(trackGroupArrayFromBundle).isEqualTo(trackGroupArrayToBundle);
} }

View File

@ -45,7 +45,6 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.media.Spatializer; import android.media.Spatializer;
import androidx.media3.common.Bundleable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
@ -181,7 +180,7 @@ public final class DefaultTrackSelectorTest {
assertThat(parameters.buildUpon().build()).isEqualTo(parameters); assertThat(parameters.buildUpon().build()).isEqualTo(parameters);
} }
/** Tests {@link Parameters} {@link Bundleable} implementation. */ /** Tests {@link Parameters} bundle implementation. */
@Test @Test
public void roundTripViaBundle_ofParameters_yieldsEqualInstance() { public void roundTripViaBundle_ofParameters_yieldsEqualInstance() {
Parameters parametersToBundle = buildParametersForEqualsTest(); Parameters parametersToBundle = buildParametersForEqualsTest();
@ -2841,15 +2840,14 @@ public final class DefaultTrackSelectorTest {
assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED); assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
} }
/** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */ /** Tests {@link SelectionOverride}'s bundle implementation. */
@Test @Test
public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() { public void roundTripViaBundle_ofSelectionOverride_yieldsEqualInstance() {
SelectionOverride selectionOverrideToBundle = SelectionOverride selectionOverrideToBundle =
new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3); new SelectionOverride(/* groupIndex= */ 1, /* tracks...= */ 2, 3);
SelectionOverride selectionOverrideFromBundle = SelectionOverride selectionOverrideFromBundle =
DefaultTrackSelector.SelectionOverride.CREATOR.fromBundle( DefaultTrackSelector.SelectionOverride.fromBundle(selectionOverrideToBundle.toBundle());
selectionOverrideToBundle.toBundle());
assertThat(selectionOverrideFromBundle).isEqualTo(selectionOverrideToBundle); assertThat(selectionOverrideFromBundle).isEqualTo(selectionOverrideToBundle);
} }

View File

@ -19,7 +19,7 @@ import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import androidx.media3.common.text.Cue; import androidx.media3.common.text.Cue;
import androidx.media3.common.util.Assertions; 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.UnstableApi;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -65,7 +65,7 @@ public final class CueDecoder {
ArrayList<Bundle> bundledCues = ArrayList<Bundle> bundledCues =
Assertions.checkNotNull(bundle.getParcelableArrayList(BUNDLE_FIELD_CUES)); Assertions.checkNotNull(bundle.getParcelableArrayList(BUNDLE_FIELD_CUES));
return new CuesWithTiming( return new CuesWithTiming(
BundleableUtil.fromBundleList(Cue.CREATOR, bundledCues), BundleCollectionUtil.fromBundleList(Cue::fromBundle, bundledCues),
startTimeUs, startTimeUs,
bundle.getLong(BUNDLE_FIELD_DURATION_US)); bundle.getLong(BUNDLE_FIELD_DURATION_US));
} }

View File

@ -18,7 +18,7 @@ package androidx.media3.extractor.text;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import androidx.media3.common.text.Cue; 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 androidx.media3.common.util.UnstableApi;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -36,7 +36,7 @@ public final class CueEncoder {
* @return The serialized byte array. * @return The serialized byte array.
*/ */
public byte[] encode(List<Cue> cues, long durationUs) { public byte[] encode(List<Cue> cues, long durationUs) {
ArrayList<Bundle> bundledCues = BundleableUtil.toBundleArrayList(cues); ArrayList<Bundle> bundledCues = BundleCollectionUtil.toBundleArrayList(cues, Cue::toBundle);
Bundle allCuesBundle = new Bundle(); Bundle allCuesBundle = new Bundle();
allCuesBundle.putParcelableArrayList(CueDecoder.BUNDLE_FIELD_CUES, bundledCues); allCuesBundle.putParcelableArrayList(CueDecoder.BUNDLE_FIELD_CUES, bundledCues);
allCuesBundle.putLong(CueDecoder.BUNDLE_FIELD_DURATION_US, durationUs); allCuesBundle.putLong(CueDecoder.BUNDLE_FIELD_DURATION_US, durationUs);

View File

@ -294,10 +294,12 @@ public final class CommandButton implements Bundleable {
return bundle; 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<CommandButton> CREATOR = CommandButton::fromBundle; @UnstableApi public static final Creator<CommandButton> 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 Bundle sessionCommandBundle = bundle.getBundle(FIELD_SESSION_COMMAND);
@Nullable @Nullable
SessionCommand sessionCommand = SessionCommand sessionCommand =

View File

@ -25,8 +25,8 @@ import androidx.annotation.Nullable;
import androidx.core.app.BundleCompat; import androidx.core.app.BundleCompat;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.BundleCollectionUtil;
import androidx.media3.common.util.BundleUtil; import androidx.media3.common.util.BundleUtil;
import androidx.media3.common.util.BundleableUtil;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.List; import java.util.List;
@ -108,7 +108,8 @@ import java.util.List;
bundle.putParcelable(FIELD_SESSION_ACTIVITY, sessionActivity); bundle.putParcelable(FIELD_SESSION_ACTIVITY, sessionActivity);
if (!customLayout.isEmpty()) { if (!customLayout.isEmpty()) {
bundle.putParcelableArrayList( 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_SESSION_COMMANDS, sessionCommands.toBundle());
bundle.putBundle(FIELD_PLAYER_COMMANDS_FROM_SESSION, playerCommandsFromSession.toBundle()); bundle.putBundle(FIELD_PLAYER_COMMANDS_FROM_SESSION, playerCommandsFromSession.toBundle());
@ -153,7 +154,7 @@ import java.util.List;
List<Bundle> commandButtonArrayList = bundle.getParcelableArrayList(FIELD_CUSTOM_LAYOUT); List<Bundle> commandButtonArrayList = bundle.getParcelableArrayList(FIELD_CUSTOM_LAYOUT);
ImmutableList<CommandButton> customLayout = ImmutableList<CommandButton> customLayout =
commandButtonArrayList != null commandButtonArrayList != null
? BundleableUtil.fromBundleList(CommandButton.CREATOR, commandButtonArrayList) ? BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonArrayList)
: ImmutableList.of(); : ImmutableList.of();
@Nullable Bundle sessionCommandsBundle = bundle.getBundle(FIELD_SESSION_COMMANDS); @Nullable Bundle sessionCommandsBundle = bundle.getBundle(FIELD_SESSION_COMMANDS);
SessionCommands sessionCommands = SessionCommands sessionCommands =

View File

@ -32,7 +32,7 @@ import androidx.media3.common.BundleListRetriever;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata; 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.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.session.MediaLibraryService.LibraryParams; import androidx.media3.session.MediaLibraryService.LibraryParams;
@ -292,7 +292,9 @@ public final class LibraryResult<V> implements Bundleable {
BundleCompat.putBinder( BundleCompat.putBinder(
bundle, bundle,
FIELD_VALUE, FIELD_VALUE,
new BundleListRetriever(BundleableUtil.toBundleList((ImmutableList<MediaItem>) value))); new BundleListRetriever(
BundleCollectionUtil.toBundleList(
(ImmutableList<MediaItem>) value, MediaItem::toBundle)));
break; break;
case VALUE_TYPE_VOID: case VALUE_TYPE_VOID:
case VALUE_TYPE_ERROR: case VALUE_TYPE_ERROR:
@ -376,8 +378,8 @@ public final class LibraryResult<V> implements Bundleable {
value = value =
valueRetriever == null valueRetriever == null
? null ? null
: BundleableUtil.fromBundleList( : BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(valueRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(valueRetriever));
break; break;
case VALUE_TYPE_VOID: case VALUE_TYPE_VOID:
case VALUE_TYPE_ERROR: case VALUE_TYPE_ERROR:

View File

@ -73,7 +73,7 @@ import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.Tracks; import androidx.media3.common.Tracks;
import androidx.media3.common.VideoSize; import androidx.media3.common.VideoSize;
import androidx.media3.common.text.CueGroup; 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.Clock;
import androidx.media3.common.util.ListenerSet; import androidx.media3.common.util.ListenerSet;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
@ -801,7 +801,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
controllerStub, controllerStub,
seq, seq,
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
setMediaItemsInternal( setMediaItemsInternal(
@ -823,7 +823,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
controllerStub, controllerStub,
seq, seq,
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)), mediaItems, MediaItem::toBundleIncludeLocalConfiguration)),
resetPosition)); resetPosition));
@ -846,7 +846,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
controllerStub, controllerStub,
seq, seq,
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)), mediaItems, MediaItem::toBundleIncludeLocalConfiguration)),
startIndex, startIndex,
startPositionMs)); startPositionMs));
@ -921,7 +921,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
controllerStub, controllerStub,
seq, seq,
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
addMediaItemsInternal(getCurrentTimeline().getWindowCount(), mediaItems); addMediaItemsInternal(getCurrentTimeline().getWindowCount(), mediaItems);
@ -941,7 +941,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
seq, seq,
index, index,
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)))); mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
addMediaItemsInternal(index, mediaItems); addMediaItemsInternal(index, mediaItems);
@ -1254,7 +1254,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
(iSession, seq) -> { (iSession, seq) -> {
IBinder mediaItemsBundleBinder = IBinder mediaItemsBundleBinder =
new BundleListRetriever( new BundleListRetriever(
BundleableUtil.toBundleList( BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) { if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) {
iSession.replaceMediaItems( iSession.replaceMediaItems(

View File

@ -25,7 +25,7 @@ import android.os.RemoteException;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Player.Commands; 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.common.util.Log;
import androidx.media3.session.MediaLibraryService.LibraryParams; import androidx.media3.session.MediaLibraryService.LibraryParams;
import androidx.media3.session.PlayerInfo.BundlingExclusions; import androidx.media3.session.PlayerInfo.BundlingExclusions;
@ -100,7 +100,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
public void onSetCustomLayout(int seq, List<Bundle> commandButtonBundleList) { public void onSetCustomLayout(int seq, List<Bundle> commandButtonBundleList) {
List<CommandButton> layout; List<CommandButton> layout;
try { try {
layout = BundleableUtil.fromBundleList(CommandButton.CREATOR, commandButtonBundleList); layout =
BundleCollectionUtil.fromBundleList(CommandButton::fromBundle, commandButtonBundleList);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for CommandButton", e); Log.w(TAG, "Ignoring malformed Bundle for CommandButton", e);
return; return;

View File

@ -80,7 +80,7 @@ import androidx.media3.common.TrackSelectionOverride;
import androidx.media3.common.TrackSelectionParameters; import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.Tracks; import androidx.media3.common.Tracks;
import androidx.media3.common.util.Assertions; 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.Consumer;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
@ -1045,8 +1045,8 @@ import java.util.concurrent.ExecutionException;
List<MediaItem> mediaItemList; List<MediaItem> mediaItemList;
try { try {
mediaItemList = mediaItemList =
BundleableUtil.fromBundleList( BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
return; return;
@ -1083,8 +1083,8 @@ import java.util.concurrent.ExecutionException;
List<MediaItem> mediaItemList; List<MediaItem> mediaItemList;
try { try {
mediaItemList = mediaItemList =
BundleableUtil.fromBundleList( BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
return; return;
@ -1192,8 +1192,8 @@ import java.util.concurrent.ExecutionException;
List<MediaItem> mediaItems; List<MediaItem> mediaItems;
try { try {
mediaItems = mediaItems =
BundleableUtil.fromBundleList( BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
return; return;
@ -1221,8 +1221,8 @@ import java.util.concurrent.ExecutionException;
List<MediaItem> mediaItems; List<MediaItem> mediaItems;
try { try {
mediaItems = mediaItems =
BundleableUtil.fromBundleList( BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
return; return;
@ -1360,8 +1360,8 @@ import java.util.concurrent.ExecutionException;
ImmutableList<MediaItem> mediaItems; ImmutableList<MediaItem> mediaItems;
try { try {
mediaItems = mediaItems =
BundleableUtil.fromBundleList( BundleCollectionUtil.fromBundleList(
MediaItem.CREATOR, BundleListRetriever.getList(mediaItemsRetriever)); MediaItem::fromBundle, BundleListRetriever.getList(mediaItemsRetriever));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e); Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
return; return;
@ -2006,7 +2006,8 @@ import java.util.concurrent.ExecutionException;
@Override @Override
public void setCustomLayout(int sequenceNumber, List<CommandButton> layout) public void setCustomLayout(int sequenceNumber, List<CommandButton> layout)
throws RemoteException { throws RemoteException {
iController.onSetCustomLayout(sequenceNumber, BundleableUtil.toBundleList(layout)); iController.onSetCustomLayout(
sequenceNumber, BundleCollectionUtil.toBundleList(layout, CommandButton::toBundle));
} }
@Override @Override

View File

@ -34,7 +34,7 @@ import androidx.media3.common.MediaMetadata;
import androidx.media3.common.PlaybackParameters; import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Rating; import androidx.media3.common.Rating;
import androidx.media3.common.TrackSelectionParameters; 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.common.util.Log;
import androidx.media3.test.session.common.IRemoteMediaController; import androidx.media3.test.session.common.IRemoteMediaController;
import androidx.media3.test.session.common.TestHandler; import androidx.media3.test.session.common.TestHandler;
@ -325,7 +325,7 @@ public class MediaControllerProviderService extends Service {
() -> { () -> {
MediaController controller = mediaControllerMap.get(controllerId); MediaController controller = mediaControllerMap.get(controllerId);
controller.setMediaItems( 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); MediaController controller = mediaControllerMap.get(controllerId);
controller.setMediaItems( 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); MediaController controller = mediaControllerMap.get(controllerId);
controller.setMediaItems( controller.setMediaItems(
BundleableUtil.fromBundleList(MediaItem.CREATOR, mediaItemBundles), BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, mediaItemBundles),
startIndex, startIndex,
startPositionMs); startPositionMs);
}); });
@ -407,7 +408,7 @@ public class MediaControllerProviderService extends Service {
() -> { () -> {
MediaController controller = mediaControllerMap.get(controllerId); MediaController controller = mediaControllerMap.get(controllerId);
controller.addMediaItems( 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); MediaController controller = mediaControllerMap.get(controllerId);
controller.addMediaItems( 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); MediaController controller = mediaControllerMap.get(controllerId);
controller.replaceMediaItems( 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); MediaController controller = mediaControllerMap.get(controllerId);
controller.setMediaItems( controller.setMediaItems(
BundleableUtil.fromBundleList(MediaItem.CREATOR, initialMediaItems)); BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, initialMediaItems));
controller.prepare(); controller.prepare();
controller.play(); controller.play();
controller.addMediaItems( controller.addMediaItems(
BundleableUtil.fromBundleList(MediaItem.CREATOR, addedMediaItems)); BundleCollectionUtil.fromBundleList(MediaItem::fromBundle, addedMediaItems));
controller.seekTo(seekIndex, /* positionMs= */ 0); controller.seekTo(seekIndex, /* positionMs= */ 0);
}); });
} }

View File

@ -39,7 +39,7 @@ import androidx.media3.common.Player;
import androidx.media3.common.Player.RepeatMode; import androidx.media3.common.Player.RepeatMode;
import androidx.media3.common.Rating; import androidx.media3.common.Rating;
import androidx.media3.common.TrackSelectionParameters; 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.common.util.Log;
import androidx.media3.test.session.common.IRemoteMediaController; import androidx.media3.test.session.common.IRemoteMediaController;
import androidx.media3.test.session.common.TestUtils; import androidx.media3.test.session.common.TestUtils;
@ -162,26 +162,33 @@ public class RemoteMediaController {
} }
public void setMediaItems(List<MediaItem> mediaItems) throws RemoteException { public void setMediaItems(List<MediaItem> mediaItems) throws RemoteException {
binder.setMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems)); binder.setMediaItems(
controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle));
} }
public void setMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems) public void setMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
throws RemoteException { throws RemoteException {
binder.setMediaItems( binder.setMediaItems(
controllerId, controllerId,
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
} }
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition) public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition)
throws RemoteException { throws RemoteException {
binder.setMediaItemsWithResetPosition( binder.setMediaItemsWithResetPosition(
controllerId, BundleableUtil.toBundleList(mediaItems), resetPosition); controllerId,
BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle),
resetPosition);
} }
public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs) public void setMediaItems(List<MediaItem> mediaItems, int startIndex, long startPositionMs)
throws RemoteException { throws RemoteException {
binder.setMediaItemsWithStartIndex( 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<MediaItem> mediaItems) throws RemoteException { public void addMediaItems(List<MediaItem> mediaItems) throws RemoteException {
binder.addMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems)); binder.addMediaItems(
controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle));
} }
public void addMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems) public void addMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
throws RemoteException { throws RemoteException {
binder.addMediaItems( binder.addMediaItems(
controllerId, controllerId,
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration)); BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
} }
public void addMediaItems(int index, List<MediaItem> mediaItems) throws RemoteException { public void addMediaItems(int index, List<MediaItem> 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 { public void removeMediaItem(int index) throws RemoteException {
@ -252,7 +262,10 @@ public class RemoteMediaController {
public void replaceMediaItems(int fromIndex, int toIndex, List<MediaItem> mediaItems) public void replaceMediaItems(int fromIndex, int toIndex, List<MediaItem> mediaItems)
throws RemoteException { throws RemoteException {
binder.replaceMediaItems( binder.replaceMediaItems(
controllerId, fromIndex, toIndex, BundleableUtil.toBundleList(mediaItems)); controllerId,
fromIndex,
toIndex,
BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle));
} }
public void seekToPreviousMediaItem() throws RemoteException { public void seekToPreviousMediaItem() throws RemoteException {
@ -354,8 +367,8 @@ public class RemoteMediaController {
throws RemoteException { throws RemoteException {
binder.setMediaItemsPreparePlayAddItemsSeek( binder.setMediaItemsPreparePlayAddItemsSeek(
controllerId, controllerId,
BundleableUtil.toBundleList(initialMediaItems), BundleCollectionUtil.toBundleList(initialMediaItems, MediaItem::toBundle),
BundleableUtil.toBundleList(addedMediaItems), BundleCollectionUtil.toBundleList(addedMediaItems, MediaItem::toBundle),
seekIndex); seekIndex);
} }