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 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<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();
BundleableUtil.ensureClassLoader(bundle);
BundleCollectionUtil.ensureClassLoader(bundle);
builder
.setId(defaultIfNull(bundle.getString(FIELD_ID), DEFAULT.id))
.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.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<String, String> 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<StreamKey> streamKeys =
streamKeysBundles == null
? ImmutableList.of()
: BundleableUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles);
: BundleCollectionUtil.fromBundleList(StreamKey::fromBundle, streamKeysBundles);
@Nullable
List<Bundle> subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION);
ImmutableList<SubtitleConfiguration> 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}.
*
* <p>The {@link #localConfiguration} of a restored instance will always be {@code null}.
*/
@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.
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;

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()}
* 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
* 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 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<Window> windows =
fromBundleListRetriever(Window.CREATOR, BundleUtil.getBinder(bundle, FIELD_WINDOWS));
fromBundleListRetriever(Window::fromBundle, BundleUtil.getBinder(bundle, FIELD_WINDOWS));
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);
return new RemotableTimeline(
windows,
@ -1491,17 +1494,12 @@ public abstract class Timeline implements Bundleable {
: shuffledWindowIndices);
}
private static <T extends Bundleable> ImmutableList<T> fromBundleListRetriever(
Creator<T> creator, @Nullable IBinder binder) {
private static <T extends @NonNull Object> ImmutableList<T> fromBundleListRetriever(
Function<Bundle, T> fromBundleFunc, @Nullable IBinder binder) {
if (binder == null) {
return ImmutableList.of();
}
ImmutableList.Builder<T> builder = new ImmutableList.Builder<>();
List<Bundle> 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) {

View File

@ -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<TrackGroup> CREATOR = TrackGroup::fromBundle;
/** Restores a {@code TrackGroup} from a {@link Bundle}. */
@UnstableApi
public static final Creator<TrackGroup> CREATOR =
bundle -> {
@Nullable List<Bundle> formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS);
List<Format> 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<Bundle> formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS);
List<Format> 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

View File

@ -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<TrackSelectionOverride> 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<TrackSelectionOverride> 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));
}
}

View File

@ -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<TrackSelectionOverride> 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)}.
*
* <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
@ -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;

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.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<Group> CREATOR = Group::fromBundle;
/** Restores a group of tracks from a {@link Bundle}. */
@UnstableApi
public static final Creator<Group> 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<Group> groups =
groupBundles == null
? ImmutableList.of()
: BundleableUtil.fromBundleList(Group.CREATOR, groupBundles);
: BundleCollectionUtil.fromBundleList(Group::fromBundle, groupBundles);
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;
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) {

View File

@ -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<Cue> 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);
}

View File

@ -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 <T extends Bundleable> ImmutableList<Bundle> toBundleList(List<T> 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 <T extends Bundleable> ImmutableList<Bundle> toBundleList(
List<T> bundleableList, Function<T, Bundle> customToBundleFunc) {
public static <T extends @NonNull Object> ImmutableList<Bundle> toBundleList(
List<T> list, Function<T, Bundle> toBundleFunc) {
ImmutableList.Builder<Bundle> 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 <T extends Bundleable> ImmutableList<T> fromBundleList(
Bundleable.Creator<T> creator, List<Bundle> 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 <T extends @NonNull Object> ImmutableList<T> fromBundleList(
Function<Bundle, T> fromBundleFunc, List<Bundle> bundleList) {
ImmutableList.Builder<T> 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 <T extends Bundleable> ArrayList<Bundle> toBundleArrayList(
Collection<T> bundleables) {
ArrayList<Bundle> arrayList = new ArrayList<>(bundleables.size());
for (T element : bundleables) {
arrayList.add(element.toBundle());
@SuppressWarnings("NonApiType") // Intentionally using ArrayList for putParcelableArrayList.
public static <T extends @NonNull Object> ArrayList<Bundle> toBundleArrayList(
Collection<T> items, Function<T, Bundle> toBundleFunc) {
ArrayList<Bundle> 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 <T extends Bundleable> SparseArray<T> fromBundleSparseArray(
Bundleable.Creator<T> creator, SparseArray<Bundle> bundleSparseArray) {
public static <T extends @NonNull Object> SparseArray<T> fromBundleSparseArray(
Function<Bundle, T> fromBundleFunc, SparseArray<Bundle> bundleSparseArray) {
SparseArray<T> 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 <T extends Bundleable> SparseArray<Bundle> toBundleSparseArray(
SparseArray<T> bundleableSparseArray) {
SparseArray<Bundle> sparseArray = new SparseArray<>(bundleableSparseArray.size());
for (int i = 0; i < bundleableSparseArray.size(); i++) {
sparseArray.put(bundleableSparseArray.keyAt(i), bundleableSparseArray.valueAt(i).toBundle());
public static <T extends @NonNull Object> SparseArray<Bundle> toBundleSparseArray(
SparseArray<T> items, Function<T, Bundle> toBundleFunc) {
SparseArray<Bundle> 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.
*
* <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) {
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 trackGroupFromBundle = TrackGroup.CREATOR.fromBundle(trackGroupToBundle.toBundle());
TrackGroup trackGroupFromBundle = TrackGroup.fromBundle(trackGroupToBundle.toBundle());
assertThat(trackGroupFromBundle).isEqualTo(trackGroupToBundle);
}

View File

@ -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<String, String> restoredMap = BundleableUtil.bundleToStringHashMap(mapAsBundle);
Bundle mapAsBundle = BundleCollectionUtil.stringMapToBundle(originalMap);
Map<String, String> 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<Integer> restoredIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray);
BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "0", defaultIntegerArray);
ArrayList<Integer> restoredEmptyIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray);
BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "1", defaultIntegerArray);
ArrayList<Integer> restoredNullIntegerArray =
BundleableUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray);
BundleCollectionUtil.getIntegerArrayListWithDefault(bundle, "2", defaultIntegerArray);
assertThat(restoredIntegerArray).isEqualTo(normalArray);
assertThat(restoredEmptyIntegerArray).isEqualTo(emptyArray);

View File

@ -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<TrackGroupArray> CREATOR =
bundle -> {
@Nullable
List<Bundle> 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<TrackGroupArray> CREATOR = TrackGroupArray::fromBundle;
/** Restores a {@code TrackGroupArray} from a {@link Bundle}. */
public static TrackGroupArray fromBundle(Bundle bundle) {
@Nullable List<Bundle> 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++) {

View File

@ -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<TrackGroupArray> trackGroupArrays =
trackGroupArrayBundles == null
? ImmutableList.of()
: BundleableUtil.fromBundleList(TrackGroupArray.CREATOR, trackGroupArrayBundles);
: BundleCollectionUtil.fromBundleList(
TrackGroupArray::fromBundle, trackGroupArrayBundles);
@Nullable
SparseArray<Bundle> selectionOverrideBundles =
bundle.getSparseParcelableArray(Parameters.FIELD_SELECTION_OVERRIDES);
SparseArray<SelectionOverride> 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<SelectionOverride> 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<SelectionOverride> 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);
}
}
/**

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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<Bundle> 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));
}

View File

@ -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<Cue> cues, long durationUs) {
ArrayList<Bundle> bundledCues = BundleableUtil.toBundleArrayList(cues);
ArrayList<Bundle> 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);

View File

@ -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<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
SessionCommand sessionCommand =

View File

@ -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<Bundle> commandButtonArrayList = bundle.getParcelableArrayList(FIELD_CUSTOM_LAYOUT);
ImmutableList<CommandButton> 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 =

View File

@ -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<V> implements Bundleable {
BundleCompat.putBinder(
bundle,
FIELD_VALUE,
new BundleListRetriever(BundleableUtil.toBundleList((ImmutableList<MediaItem>) value)));
new BundleListRetriever(
BundleCollectionUtil.toBundleList(
(ImmutableList<MediaItem>) value, MediaItem::toBundle)));
break;
case VALUE_TYPE_VOID:
case VALUE_TYPE_ERROR:
@ -376,8 +378,8 @@ public final class LibraryResult<V> 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:

View File

@ -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(

View File

@ -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<Bundle> commandButtonBundleList) {
List<CommandButton> 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;

View File

@ -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<MediaItem> 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<MediaItem> 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<MediaItem> 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<MediaItem> 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<MediaItem> 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<CommandButton> layout)
throws RemoteException {
iController.onSetCustomLayout(sequenceNumber, BundleableUtil.toBundleList(layout));
iController.onSetCustomLayout(
sequenceNumber, BundleCollectionUtil.toBundleList(layout, CommandButton::toBundle));
}
@Override

View File

@ -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);
});
}

View File

@ -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<MediaItem> mediaItems) throws RemoteException {
binder.setMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
binder.setMediaItems(
controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle));
}
public void setMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
throws RemoteException {
binder.setMediaItems(
controllerId,
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
}
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition)
throws RemoteException {
binder.setMediaItemsWithResetPosition(
controllerId, BundleableUtil.toBundleList(mediaItems), resetPosition);
controllerId,
BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle),
resetPosition);
}
public void setMediaItems(List<MediaItem> 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<MediaItem> mediaItems) throws RemoteException {
binder.addMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
binder.addMediaItems(
controllerId, BundleCollectionUtil.toBundleList(mediaItems, MediaItem::toBundle));
}
public void addMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
throws RemoteException {
binder.addMediaItems(
controllerId,
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
BundleCollectionUtil.toBundleList(
mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
}
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 {
@ -252,7 +262,10 @@ public class RemoteMediaController {
public void replaceMediaItems(int fromIndex, int toIndex, List<MediaItem> 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);
}