Commit 96eb8968 by rohks Committed by christosts

Initialise fields used for bundling as String directly

Initialising the fields as Integer and then getting a String on compute
time is slow. Instead we directly initialise these fields as String.
Improves the time taken in bundling PlayerInfo further to less than
200ms from ~300ms.

Also modified a test to improve productive coverage.

PiperOrigin-RevId: 500003935
(cherry picked from commit 578f2de4)
parent 2cfd05f1
Showing with 526 additions and 1168 deletions
...@@ -459,44 +459,29 @@ public final class AdPlaybackState implements Bundleable { ...@@ -459,44 +459,29 @@ public final class AdPlaybackState implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_TIME_US = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_COUNT = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_URIS = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_STATES = Util.intToStringMaxRadix(3);
FIELD_TIME_US, private static final String FIELD_DURATIONS_US = Util.intToStringMaxRadix(4);
FIELD_COUNT, private static final String FIELD_CONTENT_RESUME_OFFSET_US = Util.intToStringMaxRadix(5);
FIELD_URIS, private static final String FIELD_IS_SERVER_SIDE_INSERTED = Util.intToStringMaxRadix(6);
FIELD_STATES, private static final String FIELD_ORIGINAL_COUNT = Util.intToStringMaxRadix(7);
FIELD_DURATIONS_US,
FIELD_CONTENT_RESUME_OFFSET_US,
FIELD_IS_SERVER_SIDE_INSERTED,
FIELD_ORIGINAL_COUNT
})
private @interface FieldNumber {}
private static final int FIELD_TIME_US = 0;
private static final int FIELD_COUNT = 1;
private static final int FIELD_URIS = 2;
private static final int FIELD_STATES = 3;
private static final int FIELD_DURATIONS_US = 4;
private static final int FIELD_CONTENT_RESUME_OFFSET_US = 5;
private static final int FIELD_IS_SERVER_SIDE_INSERTED = 6;
private static final int FIELD_ORIGINAL_COUNT = 7;
// putParcelableArrayList actually supports null elements. // putParcelableArrayList actually supports null elements.
@SuppressWarnings("nullness:argument") @SuppressWarnings("nullness:argument")
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putLong(keyForField(FIELD_TIME_US), timeUs); bundle.putLong(FIELD_TIME_US, timeUs);
bundle.putInt(keyForField(FIELD_COUNT), count); bundle.putInt(FIELD_COUNT, count);
bundle.putInt(keyForField(FIELD_ORIGINAL_COUNT), originalCount); bundle.putInt(FIELD_ORIGINAL_COUNT, originalCount);
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
keyForField(FIELD_URIS), new ArrayList<@NullableType Uri>(Arrays.asList(uris))); FIELD_URIS, new ArrayList<@NullableType Uri>(Arrays.asList(uris)));
bundle.putIntArray(keyForField(FIELD_STATES), states); bundle.putIntArray(FIELD_STATES, states);
bundle.putLongArray(keyForField(FIELD_DURATIONS_US), durationsUs); bundle.putLongArray(FIELD_DURATIONS_US, durationsUs);
bundle.putLong(keyForField(FIELD_CONTENT_RESUME_OFFSET_US), contentResumeOffsetUs); bundle.putLong(FIELD_CONTENT_RESUME_OFFSET_US, contentResumeOffsetUs);
bundle.putBoolean(keyForField(FIELD_IS_SERVER_SIDE_INSERTED), isServerSideInserted); bundle.putBoolean(FIELD_IS_SERVER_SIDE_INSERTED, isServerSideInserted);
return bundle; return bundle;
} }
...@@ -506,17 +491,16 @@ public final class AdPlaybackState implements Bundleable { ...@@ -506,17 +491,16 @@ public final class AdPlaybackState implements Bundleable {
// getParcelableArrayList may have null elements. // getParcelableArrayList may have null elements.
@SuppressWarnings("nullness:type.argument") @SuppressWarnings("nullness:type.argument")
private static AdGroup fromBundle(Bundle bundle) { private static AdGroup fromBundle(Bundle bundle) {
long timeUs = bundle.getLong(keyForField(FIELD_TIME_US)); long timeUs = bundle.getLong(FIELD_TIME_US);
int count = bundle.getInt(keyForField(FIELD_COUNT)); int count = bundle.getInt(FIELD_COUNT);
int originalCount = bundle.getInt(keyForField(FIELD_ORIGINAL_COUNT)); int originalCount = bundle.getInt(FIELD_ORIGINAL_COUNT);
@Nullable @Nullable ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(FIELD_URIS);
ArrayList<@NullableType Uri> uriList = bundle.getParcelableArrayList(keyForField(FIELD_URIS));
@Nullable @Nullable
@AdState @AdState
int[] states = bundle.getIntArray(keyForField(FIELD_STATES)); int[] states = bundle.getIntArray(FIELD_STATES);
@Nullable long[] durationsUs = bundle.getLongArray(keyForField(FIELD_DURATIONS_US)); @Nullable long[] durationsUs = bundle.getLongArray(FIELD_DURATIONS_US);
long contentResumeOffsetUs = bundle.getLong(keyForField(FIELD_CONTENT_RESUME_OFFSET_US)); long contentResumeOffsetUs = bundle.getLong(FIELD_CONTENT_RESUME_OFFSET_US);
boolean isServerSideInserted = bundle.getBoolean(keyForField(FIELD_IS_SERVER_SIDE_INSERTED)); boolean isServerSideInserted = bundle.getBoolean(FIELD_IS_SERVER_SIDE_INSERTED);
return new AdGroup( return new AdGroup(
timeUs, timeUs,
count, count,
...@@ -527,10 +511,6 @@ public final class AdPlaybackState implements Bundleable { ...@@ -527,10 +511,6 @@ public final class AdPlaybackState implements Bundleable {
contentResumeOffsetUs, contentResumeOffsetUs,
isServerSideInserted); isServerSideInserted);
} }
private static String keyForField(@AdGroup.FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
/** /**
...@@ -1121,21 +1101,10 @@ public final class AdPlaybackState implements Bundleable { ...@@ -1121,21 +1101,10 @@ public final class AdPlaybackState implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_AD_GROUPS = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_AD_RESUME_POSITION_US = Util.intToStringMaxRadix(2);
@Target(TYPE_USE) private static final String FIELD_CONTENT_DURATION_US = Util.intToStringMaxRadix(3);
@IntDef({ private static final String FIELD_REMOVED_AD_GROUP_COUNT = Util.intToStringMaxRadix(4);
FIELD_AD_GROUPS,
FIELD_AD_RESUME_POSITION_US,
FIELD_CONTENT_DURATION_US,
FIELD_REMOVED_AD_GROUP_COUNT
})
private @interface FieldNumber {}
private static final int FIELD_AD_GROUPS = 1;
private static final int FIELD_AD_RESUME_POSITION_US = 2;
private static final int FIELD_CONTENT_DURATION_US = 3;
private static final int FIELD_REMOVED_AD_GROUP_COUNT = 4;
/** /**
* {@inheritDoc} * {@inheritDoc}
...@@ -1152,16 +1121,16 @@ public final class AdPlaybackState implements Bundleable { ...@@ -1152,16 +1121,16 @@ public final class AdPlaybackState implements Bundleable {
adGroupBundleList.add(adGroup.toBundle()); adGroupBundleList.add(adGroup.toBundle());
} }
if (!adGroupBundleList.isEmpty()) { if (!adGroupBundleList.isEmpty()) {
bundle.putParcelableArrayList(keyForField(FIELD_AD_GROUPS), adGroupBundleList); bundle.putParcelableArrayList(FIELD_AD_GROUPS, adGroupBundleList);
} }
if (adResumePositionUs != NONE.adResumePositionUs) { if (adResumePositionUs != NONE.adResumePositionUs) {
bundle.putLong(keyForField(FIELD_AD_RESUME_POSITION_US), adResumePositionUs); bundle.putLong(FIELD_AD_RESUME_POSITION_US, adResumePositionUs);
} }
if (contentDurationUs != NONE.contentDurationUs) { if (contentDurationUs != NONE.contentDurationUs) {
bundle.putLong(keyForField(FIELD_CONTENT_DURATION_US), contentDurationUs); bundle.putLong(FIELD_CONTENT_DURATION_US, contentDurationUs);
} }
if (removedAdGroupCount != NONE.removedAdGroupCount) { if (removedAdGroupCount != NONE.removedAdGroupCount) {
bundle.putInt(keyForField(FIELD_REMOVED_AD_GROUP_COUNT), removedAdGroupCount); bundle.putInt(FIELD_REMOVED_AD_GROUP_COUNT, removedAdGroupCount);
} }
return bundle; return bundle;
} }
...@@ -1174,9 +1143,7 @@ public final class AdPlaybackState implements Bundleable { ...@@ -1174,9 +1143,7 @@ public final class AdPlaybackState implements Bundleable {
public static final Bundleable.Creator<AdPlaybackState> CREATOR = AdPlaybackState::fromBundle; public static final Bundleable.Creator<AdPlaybackState> CREATOR = AdPlaybackState::fromBundle;
private static AdPlaybackState fromBundle(Bundle bundle) { private static AdPlaybackState fromBundle(Bundle bundle) {
@Nullable @Nullable ArrayList<Bundle> adGroupBundleList = bundle.getParcelableArrayList(FIELD_AD_GROUPS);
ArrayList<Bundle> adGroupBundleList =
bundle.getParcelableArrayList(keyForField(FIELD_AD_GROUPS));
@Nullable AdGroup[] adGroups; @Nullable AdGroup[] adGroups;
if (adGroupBundleList == null) { if (adGroupBundleList == null) {
adGroups = new AdGroup[0]; adGroups = new AdGroup[0];
...@@ -1187,23 +1154,15 @@ public final class AdPlaybackState implements Bundleable { ...@@ -1187,23 +1154,15 @@ public final class AdPlaybackState implements Bundleable {
} }
} }
long adResumePositionUs = long adResumePositionUs =
bundle.getLong( bundle.getLong(FIELD_AD_RESUME_POSITION_US, /* defaultValue= */ NONE.adResumePositionUs);
keyForField(FIELD_AD_RESUME_POSITION_US), /* defaultValue= */ NONE.adResumePositionUs);
long contentDurationUs = long contentDurationUs =
bundle.getLong( bundle.getLong(FIELD_CONTENT_DURATION_US, /* defaultValue= */ NONE.contentDurationUs);
keyForField(FIELD_CONTENT_DURATION_US), /* defaultValue= */ NONE.contentDurationUs);
int removedAdGroupCount = int removedAdGroupCount =
bundle.getInt( bundle.getInt(FIELD_REMOVED_AD_GROUP_COUNT, /* defaultValue= */ NONE.removedAdGroupCount);
keyForField(FIELD_REMOVED_AD_GROUP_COUNT),
/* defaultValue= */ NONE.removedAdGroupCount);
return new AdPlaybackState( return new AdPlaybackState(
/* adsId= */ null, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount); /* adsId= */ null, adGroups, adResumePositionUs, contentDurationUs, removedAdGroupCount);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
private static AdGroup[] createEmptyAdGroups(long[] adGroupTimesUs) { private static AdGroup[] createEmptyAdGroups(long[] adGroupTimesUs) {
AdGroup[] adGroups = new AdGroup[adGroupTimesUs.length]; AdGroup[] adGroups = new AdGroup[adGroupTimesUs.length];
for (int i = 0; i < adGroups.length; i++) { for (int i = 0; i < adGroups.length; i++) {
......
...@@ -15,20 +15,13 @@ ...@@ -15,20 +15,13 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.DoNotInline; import androidx.annotation.DoNotInline;
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.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Attributes for audio playback, which configure the underlying platform {@link * Attributes for audio playback, which configure the underlying platform {@link
...@@ -205,33 +198,21 @@ public final class AudioAttributes implements Bundleable { ...@@ -205,33 +198,21 @@ public final class AudioAttributes implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_CONTENT_TYPE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_FLAGS = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_USAGE = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_ALLOWED_CAPTURE_POLICY = Util.intToStringMaxRadix(3);
FIELD_CONTENT_TYPE, private static final String FIELD_SPATIALIZATION_BEHAVIOR = Util.intToStringMaxRadix(4);
FIELD_FLAGS,
FIELD_USAGE,
FIELD_ALLOWED_CAPTURE_POLICY,
FIELD_SPATIALIZATION_BEHAVIOR
})
private @interface FieldNumber {}
private static final int FIELD_CONTENT_TYPE = 0;
private static final int FIELD_FLAGS = 1;
private static final int FIELD_USAGE = 2;
private static final int FIELD_ALLOWED_CAPTURE_POLICY = 3;
private static final int FIELD_SPATIALIZATION_BEHAVIOR = 4;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_CONTENT_TYPE), contentType); bundle.putInt(FIELD_CONTENT_TYPE, contentType);
bundle.putInt(keyForField(FIELD_FLAGS), flags); bundle.putInt(FIELD_FLAGS, flags);
bundle.putInt(keyForField(FIELD_USAGE), usage); bundle.putInt(FIELD_USAGE, usage);
bundle.putInt(keyForField(FIELD_ALLOWED_CAPTURE_POLICY), allowedCapturePolicy); bundle.putInt(FIELD_ALLOWED_CAPTURE_POLICY, allowedCapturePolicy);
bundle.putInt(keyForField(FIELD_SPATIALIZATION_BEHAVIOR), spatializationBehavior); bundle.putInt(FIELD_SPATIALIZATION_BEHAVIOR, spatializationBehavior);
return bundle; return bundle;
} }
...@@ -240,29 +221,24 @@ public final class AudioAttributes implements Bundleable { ...@@ -240,29 +221,24 @@ public final class AudioAttributes implements Bundleable {
public static final Creator<AudioAttributes> CREATOR = public static final Creator<AudioAttributes> CREATOR =
bundle -> { bundle -> {
Builder builder = new Builder(); Builder builder = new Builder();
if (bundle.containsKey(keyForField(FIELD_CONTENT_TYPE))) { if (bundle.containsKey(FIELD_CONTENT_TYPE)) {
builder.setContentType(bundle.getInt(keyForField(FIELD_CONTENT_TYPE))); builder.setContentType(bundle.getInt(FIELD_CONTENT_TYPE));
} }
if (bundle.containsKey(keyForField(FIELD_FLAGS))) { if (bundle.containsKey(FIELD_FLAGS)) {
builder.setFlags(bundle.getInt(keyForField(FIELD_FLAGS))); builder.setFlags(bundle.getInt(FIELD_FLAGS));
} }
if (bundle.containsKey(keyForField(FIELD_USAGE))) { if (bundle.containsKey(FIELD_USAGE)) {
builder.setUsage(bundle.getInt(keyForField(FIELD_USAGE))); builder.setUsage(bundle.getInt(FIELD_USAGE));
} }
if (bundle.containsKey(keyForField(FIELD_ALLOWED_CAPTURE_POLICY))) { if (bundle.containsKey(FIELD_ALLOWED_CAPTURE_POLICY)) {
builder.setAllowedCapturePolicy(bundle.getInt(keyForField(FIELD_ALLOWED_CAPTURE_POLICY))); builder.setAllowedCapturePolicy(bundle.getInt(FIELD_ALLOWED_CAPTURE_POLICY));
} }
if (bundle.containsKey(keyForField(FIELD_SPATIALIZATION_BEHAVIOR))) { if (bundle.containsKey(FIELD_SPATIALIZATION_BEHAVIOR)) {
builder.setSpatializationBehavior( builder.setSpatializationBehavior(bundle.getInt(FIELD_SPATIALIZATION_BEHAVIOR));
bundle.getInt(keyForField(FIELD_SPATIALIZATION_BEHAVIOR)));
} }
return builder.build(); return builder.build();
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
@RequiresApi(29) @RequiresApi(29)
private static final class Api29 { private static final class Api29 {
@DoNotInline @DoNotInline
......
...@@ -15,16 +15,10 @@ ...@@ -15,16 +15,10 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented; import androidx.media3.common.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays; import java.util.Arrays;
import org.checkerframework.dataflow.qual.Pure; import org.checkerframework.dataflow.qual.Pure;
...@@ -183,41 +177,26 @@ public final class ColorInfo implements Bundleable { ...@@ -183,41 +177,26 @@ public final class ColorInfo implements Bundleable {
// Bundleable implementation // Bundleable implementation
@Documented private static final String FIELD_COLOR_SPACE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_COLOR_RANGE = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_COLOR_TRANSFER = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_HDR_STATIC_INFO = Util.intToStringMaxRadix(3);
FIELD_COLOR_SPACE,
FIELD_COLOR_RANGE,
FIELD_COLOR_TRANSFER,
FIELD_HDR_STATIC_INFO,
})
private @interface FieldNumber {}
private static final int FIELD_COLOR_SPACE = 0;
private static final int FIELD_COLOR_RANGE = 1;
private static final int FIELD_COLOR_TRANSFER = 2;
private static final int FIELD_HDR_STATIC_INFO = 3;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_COLOR_SPACE), colorSpace); bundle.putInt(FIELD_COLOR_SPACE, colorSpace);
bundle.putInt(keyForField(FIELD_COLOR_RANGE), colorRange); bundle.putInt(FIELD_COLOR_RANGE, colorRange);
bundle.putInt(keyForField(FIELD_COLOR_TRANSFER), colorTransfer); bundle.putInt(FIELD_COLOR_TRANSFER, colorTransfer);
bundle.putByteArray(keyForField(FIELD_HDR_STATIC_INFO), hdrStaticInfo); bundle.putByteArray(FIELD_HDR_STATIC_INFO, hdrStaticInfo);
return bundle; return bundle;
} }
public static final Creator<ColorInfo> CREATOR = public static final Creator<ColorInfo> CREATOR =
bundle -> bundle ->
new ColorInfo( new ColorInfo(
bundle.getInt(keyForField(FIELD_COLOR_SPACE), Format.NO_VALUE), bundle.getInt(FIELD_COLOR_SPACE, Format.NO_VALUE),
bundle.getInt(keyForField(FIELD_COLOR_RANGE), Format.NO_VALUE), bundle.getInt(FIELD_COLOR_RANGE, Format.NO_VALUE),
bundle.getInt(keyForField(FIELD_COLOR_TRANSFER), Format.NO_VALUE), bundle.getInt(FIELD_COLOR_TRANSFER, Format.NO_VALUE),
bundle.getByteArray(keyForField(FIELD_HDR_STATIC_INFO))); bundle.getByteArray(FIELD_HDR_STATIC_INFO));
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -21,6 +21,7 @@ import android.os.Bundle; ...@@ -21,6 +21,7 @@ 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.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -87,23 +88,17 @@ public final class DeviceInfo implements Bundleable { ...@@ -87,23 +88,17 @@ public final class DeviceInfo implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_PLAYBACK_TYPE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_MIN_VOLUME = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_MAX_VOLUME = Util.intToStringMaxRadix(2);
@IntDef({FIELD_PLAYBACK_TYPE, FIELD_MIN_VOLUME, FIELD_MAX_VOLUME})
private @interface FieldNumber {}
private static final int FIELD_PLAYBACK_TYPE = 0;
private static final int FIELD_MIN_VOLUME = 1;
private static final int FIELD_MAX_VOLUME = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_PLAYBACK_TYPE), playbackType); bundle.putInt(FIELD_PLAYBACK_TYPE, playbackType);
bundle.putInt(keyForField(FIELD_MIN_VOLUME), minVolume); bundle.putInt(FIELD_MIN_VOLUME, minVolume);
bundle.putInt(keyForField(FIELD_MAX_VOLUME), maxVolume); bundle.putInt(FIELD_MAX_VOLUME, maxVolume);
return bundle; return bundle;
} }
...@@ -112,14 +107,9 @@ public final class DeviceInfo implements Bundleable { ...@@ -112,14 +107,9 @@ public final class DeviceInfo implements Bundleable {
public static final Creator<DeviceInfo> CREATOR = public static final Creator<DeviceInfo> CREATOR =
bundle -> { bundle -> {
int playbackType = int playbackType =
bundle.getInt( bundle.getInt(FIELD_PLAYBACK_TYPE, /* defaultValue= */ PLAYBACK_TYPE_LOCAL);
keyForField(FIELD_PLAYBACK_TYPE), /* defaultValue= */ PLAYBACK_TYPE_LOCAL); int minVolume = bundle.getInt(FIELD_MIN_VOLUME, /* defaultValue= */ 0);
int minVolume = bundle.getInt(keyForField(FIELD_MIN_VOLUME), /* defaultValue= */ 0); int maxVolume = bundle.getInt(FIELD_MAX_VOLUME, /* defaultValue= */ 0);
int maxVolume = bundle.getInt(keyForField(FIELD_MAX_VOLUME), /* defaultValue= */ 0);
return new DeviceInfo(playbackType, minVolume, maxVolume); return new DeviceInfo(playbackType, minVolume, maxVolume);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,17 +16,12 @@ ...@@ -16,17 +16,12 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* A rating expressed as "heart" or "no heart". It can be used to indicate whether the content is a * A rating expressed as "heart" or "no heart". It can be used to indicate whether the content is a
...@@ -81,22 +76,16 @@ public final class HeartRating extends Rating { ...@@ -81,22 +76,16 @@ public final class HeartRating extends Rating {
private static final @RatingType int TYPE = RATING_TYPE_HEART; private static final @RatingType int TYPE = RATING_TYPE_HEART;
@Documented private static final String FIELD_RATED = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_IS_HEART = Util.intToStringMaxRadix(2);
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_RATED, FIELD_IS_HEART})
private @interface FieldNumber {}
private static final int FIELD_RATED = 1;
private static final int FIELD_IS_HEART = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE); bundle.putInt(FIELD_RATING_TYPE, TYPE);
bundle.putBoolean(keyForField(FIELD_RATED), rated); bundle.putBoolean(FIELD_RATED, rated);
bundle.putBoolean(keyForField(FIELD_IS_HEART), isHeart); bundle.putBoolean(FIELD_IS_HEART, isHeart);
return bundle; return bundle;
} }
...@@ -104,16 +93,10 @@ public final class HeartRating extends Rating { ...@@ -104,16 +93,10 @@ public final class HeartRating extends Rating {
@UnstableApi public static final Creator<HeartRating> CREATOR = HeartRating::fromBundle; @UnstableApi public static final Creator<HeartRating> CREATOR = HeartRating::fromBundle;
private static HeartRating fromBundle(Bundle bundle) { private static HeartRating fromBundle(Bundle bundle) {
checkArgument( checkArgument(bundle.getInt(FIELD_RATING_TYPE, /* defaultValue= */ RATING_TYPE_UNSET) == TYPE);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET) boolean isRated = bundle.getBoolean(FIELD_RATED, /* defaultValue= */ false);
== TYPE);
boolean isRated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return isRated return isRated
? new HeartRating(bundle.getBoolean(keyForField(FIELD_IS_HEART), /* defaultValue= */ false)) ? new HeartRating(bundle.getBoolean(FIELD_IS_HEART, /* defaultValue= */ false))
: new HeartRating(); : new HeartRating();
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,18 +16,13 @@ ...@@ -16,18 +16,13 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as a percentage. */ /** A rating expressed as a percentage. */
public final class PercentageRating extends Rating { public final class PercentageRating extends Rating {
...@@ -79,20 +74,14 @@ public final class PercentageRating extends Rating { ...@@ -79,20 +74,14 @@ public final class PercentageRating extends Rating {
private static final @RatingType int TYPE = RATING_TYPE_PERCENTAGE; private static final @RatingType int TYPE = RATING_TYPE_PERCENTAGE;
@Documented private static final String FIELD_PERCENT = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_PERCENT})
private @interface FieldNumber {}
private static final int FIELD_PERCENT = 1;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE); bundle.putInt(FIELD_RATING_TYPE, TYPE);
bundle.putFloat(keyForField(FIELD_PERCENT), percent); bundle.putFloat(FIELD_PERCENT, percent);
return bundle; return bundle;
} }
...@@ -100,14 +89,8 @@ public final class PercentageRating extends Rating { ...@@ -100,14 +89,8 @@ public final class PercentageRating extends Rating {
@UnstableApi public static final Creator<PercentageRating> CREATOR = PercentageRating::fromBundle; @UnstableApi public static final Creator<PercentageRating> CREATOR = PercentageRating::fromBundle;
private static PercentageRating fromBundle(Bundle bundle) { private static PercentageRating fromBundle(Bundle bundle) {
checkArgument( checkArgument(bundle.getInt(FIELD_RATING_TYPE, /* defaultValue= */ RATING_TYPE_UNSET) == TYPE);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET) float percent = bundle.getFloat(FIELD_PERCENT, /* defaultValue= */ RATING_UNSET);
== TYPE);
float percent = bundle.getFloat(keyForField(FIELD_PERCENT), /* defaultValue= */ RATING_UNSET);
return percent == RATING_UNSET ? new PercentageRating() : new PercentageRating(percent); return percent == RATING_UNSET ? new PercentageRating() : new PercentageRating(percent);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -346,13 +346,12 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -346,13 +346,12 @@ public class PlaybackException extends Exception implements Bundleable {
@UnstableApi @UnstableApi
protected PlaybackException(Bundle bundle) { protected PlaybackException(Bundle bundle) {
this( this(
/* message= */ bundle.getString(keyForField(FIELD_STRING_MESSAGE)), /* message= */ bundle.getString(FIELD_STRING_MESSAGE),
/* cause= */ getCauseFromBundle(bundle), /* cause= */ getCauseFromBundle(bundle),
/* errorCode= */ bundle.getInt( /* errorCode= */ bundle.getInt(
keyForField(FIELD_INT_ERROR_CODE), /* defaultValue= */ ERROR_CODE_UNSPECIFIED), FIELD_INT_ERROR_CODE, /* defaultValue= */ ERROR_CODE_UNSPECIFIED),
/* timestampMs= */ bundle.getLong( /* timestampMs= */ bundle.getLong(
keyForField(FIELD_LONG_TIMESTAMP_MS), FIELD_LONG_TIMESTAMP_MS, /* defaultValue= */ SystemClock.elapsedRealtime()));
/* defaultValue= */ SystemClock.elapsedRealtime()));
} }
/** Creates a new instance using the given values. */ /** Creates a new instance using the given values. */
...@@ -401,18 +400,18 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -401,18 +400,18 @@ public class PlaybackException extends Exception implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
private static final int FIELD_INT_ERROR_CODE = 0; private static final String FIELD_INT_ERROR_CODE = Util.intToStringMaxRadix(0);
private static final int FIELD_LONG_TIMESTAMP_MS = 1; private static final String FIELD_LONG_TIMESTAMP_MS = Util.intToStringMaxRadix(1);
private static final int FIELD_STRING_MESSAGE = 2; private static final String FIELD_STRING_MESSAGE = Util.intToStringMaxRadix(2);
private static final int FIELD_STRING_CAUSE_CLASS_NAME = 3; private static final String FIELD_STRING_CAUSE_CLASS_NAME = Util.intToStringMaxRadix(3);
private static final int FIELD_STRING_CAUSE_MESSAGE = 4; private static final String FIELD_STRING_CAUSE_MESSAGE = Util.intToStringMaxRadix(4);
/** /**
* 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 {@link Bundleable.Creator}.
* *
* <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 #keyForField(int)}. * offset on this constant and passing the result to {@link Util#intToStringMaxRadix(int)}.
*/ */
@UnstableApi protected static final int FIELD_CUSTOM_ID_BASE = 1000; @UnstableApi protected static final int FIELD_CUSTOM_ID_BASE = 1000;
...@@ -424,29 +423,17 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -424,29 +423,17 @@ public class PlaybackException extends Exception implements Bundleable {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_INT_ERROR_CODE), errorCode); bundle.putInt(FIELD_INT_ERROR_CODE, errorCode);
bundle.putLong(keyForField(FIELD_LONG_TIMESTAMP_MS), timestampMs); bundle.putLong(FIELD_LONG_TIMESTAMP_MS, timestampMs);
bundle.putString(keyForField(FIELD_STRING_MESSAGE), getMessage()); bundle.putString(FIELD_STRING_MESSAGE, getMessage());
@Nullable Throwable cause = getCause(); @Nullable Throwable cause = getCause();
if (cause != null) { if (cause != null) {
bundle.putString(keyForField(FIELD_STRING_CAUSE_CLASS_NAME), cause.getClass().getName()); bundle.putString(FIELD_STRING_CAUSE_CLASS_NAME, cause.getClass().getName());
bundle.putString(keyForField(FIELD_STRING_CAUSE_MESSAGE), cause.getMessage()); bundle.putString(FIELD_STRING_CAUSE_MESSAGE, cause.getMessage());
} }
return bundle; return bundle;
} }
/**
* Converts the given field number to a string which can be used as a field key when implementing
* {@link #toBundle()} and {@link Bundleable.Creator}.
*
* <p>Subclasses should use {@code field} values greater than or equal to {@link
* #FIELD_CUSTOM_ID_BASE}.
*/
@UnstableApi
protected static String keyForField(int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
// Creates a new {@link Throwable} with possibly {@code null} message. // Creates a new {@link Throwable} with possibly {@code null} message.
@SuppressWarnings("nullness:argument") @SuppressWarnings("nullness:argument")
private static Throwable createThrowable(Class<?> clazz, @Nullable String message) private static Throwable createThrowable(Class<?> clazz, @Nullable String message)
...@@ -462,8 +449,8 @@ public class PlaybackException extends Exception implements Bundleable { ...@@ -462,8 +449,8 @@ public class PlaybackException extends Exception implements Bundleable {
@Nullable @Nullable
private static Throwable getCauseFromBundle(Bundle bundle) { private static Throwable getCauseFromBundle(Bundle bundle) {
@Nullable String causeClassName = bundle.getString(keyForField(FIELD_STRING_CAUSE_CLASS_NAME)); @Nullable String causeClassName = bundle.getString(FIELD_STRING_CAUSE_CLASS_NAME);
@Nullable String causeMessage = bundle.getString(keyForField(FIELD_STRING_CAUSE_MESSAGE)); @Nullable String causeMessage = bundle.getString(FIELD_STRING_CAUSE_MESSAGE);
@Nullable Throwable cause = null; @Nullable Throwable cause = null;
if (!TextUtils.isEmpty(causeClassName)) { if (!TextUtils.isEmpty(causeClassName)) {
try { try {
......
...@@ -15,20 +15,13 @@ ...@@ -15,20 +15,13 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.CheckResult; import androidx.annotation.CheckResult;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
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.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Parameters that apply to playback, including speed setting. */ /** Parameters that apply to playback, including speed setting. */
public final class PlaybackParameters implements Bundleable { public final class PlaybackParameters implements Bundleable {
...@@ -122,21 +115,15 @@ public final class PlaybackParameters implements Bundleable { ...@@ -122,21 +115,15 @@ public final class PlaybackParameters implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_SPEED = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_PITCH = Util.intToStringMaxRadix(1);
@Target(TYPE_USE)
@IntDef({FIELD_SPEED, FIELD_PITCH})
private @interface FieldNumber {}
private static final int FIELD_SPEED = 0;
private static final int FIELD_PITCH = 1;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putFloat(keyForField(FIELD_SPEED), speed); bundle.putFloat(FIELD_SPEED, speed);
bundle.putFloat(keyForField(FIELD_PITCH), pitch); bundle.putFloat(FIELD_PITCH, pitch);
return bundle; return bundle;
} }
...@@ -144,12 +131,8 @@ public final class PlaybackParameters implements Bundleable { ...@@ -144,12 +131,8 @@ public final class PlaybackParameters implements Bundleable {
@UnstableApi @UnstableApi
public static final Creator<PlaybackParameters> CREATOR = public static final Creator<PlaybackParameters> CREATOR =
bundle -> { bundle -> {
float speed = bundle.getFloat(keyForField(FIELD_SPEED), /* defaultValue= */ 1f); float speed = bundle.getFloat(FIELD_SPEED, /* defaultValue= */ 1f);
float pitch = bundle.getFloat(keyForField(FIELD_PITCH), /* defaultValue= */ 1f); float pitch = bundle.getFloat(FIELD_PITCH, /* defaultValue= */ 1f);
return new PlaybackParameters(speed, pitch); return new PlaybackParameters(speed, pitch);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -268,27 +268,14 @@ public interface Player { ...@@ -268,27 +268,14 @@ public interface Player {
} }
// Bundleable implementation. // Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_MEDIA_ITEM_INDEX = Util.intToStringMaxRadix(0);
@Target(TYPE_USE) private static final String FIELD_MEDIA_ITEM = Util.intToStringMaxRadix(1);
@IntDef({ private static final String FIELD_PERIOD_INDEX = Util.intToStringMaxRadix(2);
FIELD_MEDIA_ITEM_INDEX, private static final String FIELD_POSITION_MS = Util.intToStringMaxRadix(3);
FIELD_MEDIA_ITEM, private static final String FIELD_CONTENT_POSITION_MS = Util.intToStringMaxRadix(4);
FIELD_PERIOD_INDEX, private static final String FIELD_AD_GROUP_INDEX = Util.intToStringMaxRadix(5);
FIELD_POSITION_MS, private static final String FIELD_AD_INDEX_IN_AD_GROUP = Util.intToStringMaxRadix(6);
FIELD_CONTENT_POSITION_MS,
FIELD_AD_GROUP_INDEX,
FIELD_AD_INDEX_IN_AD_GROUP
})
private @interface FieldNumber {}
private static final int FIELD_MEDIA_ITEM_INDEX = 0;
private static final int FIELD_MEDIA_ITEM = 1;
private static final int FIELD_PERIOD_INDEX = 2;
private static final int FIELD_POSITION_MS = 3;
private static final int FIELD_CONTENT_POSITION_MS = 4;
private static final int FIELD_AD_GROUP_INDEX = 5;
private static final int FIELD_AD_INDEX_IN_AD_GROUP = 6;
/** /**
* {@inheritDoc} * {@inheritDoc}
...@@ -300,15 +287,15 @@ public interface Player { ...@@ -300,15 +287,15 @@ public interface Player {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_MEDIA_ITEM_INDEX), mediaItemIndex); bundle.putInt(FIELD_MEDIA_ITEM_INDEX, mediaItemIndex);
if (mediaItem != null) { if (mediaItem != null) {
bundle.putBundle(keyForField(FIELD_MEDIA_ITEM), mediaItem.toBundle()); bundle.putBundle(FIELD_MEDIA_ITEM, mediaItem.toBundle());
} }
bundle.putInt(keyForField(FIELD_PERIOD_INDEX), periodIndex); bundle.putInt(FIELD_PERIOD_INDEX, periodIndex);
bundle.putLong(keyForField(FIELD_POSITION_MS), positionMs); bundle.putLong(FIELD_POSITION_MS, positionMs);
bundle.putLong(keyForField(FIELD_CONTENT_POSITION_MS), contentPositionMs); bundle.putLong(FIELD_CONTENT_POSITION_MS, contentPositionMs);
bundle.putInt(keyForField(FIELD_AD_GROUP_INDEX), adGroupIndex); bundle.putInt(FIELD_AD_GROUP_INDEX, adGroupIndex);
bundle.putInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), adIndexInAdGroup); bundle.putInt(FIELD_AD_INDEX_IN_AD_GROUP, adIndexInAdGroup);
return bundle; return bundle;
} }
...@@ -316,22 +303,18 @@ public interface Player { ...@@ -316,22 +303,18 @@ public interface Player {
@UnstableApi public static final Creator<PositionInfo> CREATOR = PositionInfo::fromBundle; @UnstableApi public static final Creator<PositionInfo> CREATOR = PositionInfo::fromBundle;
private static PositionInfo fromBundle(Bundle bundle) { private static PositionInfo fromBundle(Bundle bundle) {
int mediaItemIndex = int mediaItemIndex = bundle.getInt(FIELD_MEDIA_ITEM_INDEX, /* defaultValue= */ C.INDEX_UNSET);
bundle.getInt(keyForField(FIELD_MEDIA_ITEM_INDEX), /* defaultValue= */ C.INDEX_UNSET); @Nullable Bundle mediaItemBundle = bundle.getBundle(FIELD_MEDIA_ITEM);
@Nullable Bundle mediaItemBundle = bundle.getBundle(keyForField(FIELD_MEDIA_ITEM));
@Nullable @Nullable
MediaItem mediaItem = MediaItem mediaItem =
mediaItemBundle == null ? null : MediaItem.CREATOR.fromBundle(mediaItemBundle); mediaItemBundle == null ? null : MediaItem.CREATOR.fromBundle(mediaItemBundle);
int periodIndex = int periodIndex = bundle.getInt(FIELD_PERIOD_INDEX, /* defaultValue= */ C.INDEX_UNSET);
bundle.getInt(keyForField(FIELD_PERIOD_INDEX), /* defaultValue= */ C.INDEX_UNSET); long positionMs = bundle.getLong(FIELD_POSITION_MS, /* defaultValue= */ C.TIME_UNSET);
long positionMs =
bundle.getLong(keyForField(FIELD_POSITION_MS), /* defaultValue= */ C.TIME_UNSET);
long contentPositionMs = long contentPositionMs =
bundle.getLong(keyForField(FIELD_CONTENT_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); bundle.getLong(FIELD_CONTENT_POSITION_MS, /* defaultValue= */ C.TIME_UNSET);
int adGroupIndex = int adGroupIndex = bundle.getInt(FIELD_AD_GROUP_INDEX, /* defaultValue= */ C.INDEX_UNSET);
bundle.getInt(keyForField(FIELD_AD_GROUP_INDEX), /* defaultValue= */ C.INDEX_UNSET);
int adIndexInAdGroup = int adIndexInAdGroup =
bundle.getInt(keyForField(FIELD_AD_INDEX_IN_AD_GROUP), /* defaultValue= */ C.INDEX_UNSET); bundle.getInt(FIELD_AD_INDEX_IN_AD_GROUP, /* defaultValue= */ C.INDEX_UNSET);
return new PositionInfo( return new PositionInfo(
/* windowUid= */ null, /* windowUid= */ null,
mediaItemIndex, mediaItemIndex,
...@@ -343,10 +326,6 @@ public interface Player { ...@@ -343,10 +326,6 @@ public interface Player {
adGroupIndex, adGroupIndex,
adIndexInAdGroup); adIndexInAdGroup);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
/** /**
...@@ -581,13 +560,7 @@ public interface Player { ...@@ -581,13 +560,7 @@ public interface Player {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_COMMANDS = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_COMMANDS})
private @interface FieldNumber {}
private static final int FIELD_COMMANDS = 0;
@UnstableApi @UnstableApi
@Override @Override
...@@ -597,7 +570,7 @@ public interface Player { ...@@ -597,7 +570,7 @@ public interface Player {
for (int i = 0; i < flags.size(); i++) { for (int i = 0; i < flags.size(); i++) {
commandsBundle.add(flags.get(i)); commandsBundle.add(flags.get(i));
} }
bundle.putIntegerArrayList(keyForField(FIELD_COMMANDS), commandsBundle); bundle.putIntegerArrayList(FIELD_COMMANDS, commandsBundle);
return bundle; return bundle;
} }
...@@ -605,8 +578,7 @@ public interface Player { ...@@ -605,8 +578,7 @@ public interface Player {
@UnstableApi public static final Creator<Commands> CREATOR = Commands::fromBundle; @UnstableApi public static final Creator<Commands> CREATOR = Commands::fromBundle;
private static Commands fromBundle(Bundle bundle) { private static Commands fromBundle(Bundle bundle) {
@Nullable @Nullable ArrayList<Integer> commands = bundle.getIntegerArrayList(FIELD_COMMANDS);
ArrayList<Integer> commands = bundle.getIntegerArrayList(keyForField(FIELD_COMMANDS));
if (commands == null) { if (commands == null) {
return Commands.EMPTY; return Commands.EMPTY;
} }
...@@ -616,10 +588,6 @@ public interface Player { ...@@ -616,10 +588,6 @@ public interface Player {
} }
return builder.build(); return builder.build();
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
/** /**
......
...@@ -20,6 +20,7 @@ import static java.lang.annotation.ElementType.TYPE_USE; ...@@ -20,6 +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.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
...@@ -60,21 +61,14 @@ public abstract class Rating implements Bundleable { ...@@ -60,21 +61,14 @@ public abstract class Rating implements Bundleable {
/* package */ static final int RATING_TYPE_STAR = 2; /* package */ static final int RATING_TYPE_STAR = 2;
/* package */ static final int RATING_TYPE_THUMB = 3; /* package */ static final int RATING_TYPE_THUMB = 3;
@Documented /* package */ static final String FIELD_RATING_TYPE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE})
private @interface FieldNumber {}
/* package */ static final int FIELD_RATING_TYPE = 0;
/** Object that can restore a {@link Rating} from a {@link Bundle}. */ /** Object that can restore a {@link Rating} from a {@link Bundle}. */
@UnstableApi public static final Creator<Rating> CREATOR = Rating::fromBundle; @UnstableApi public static final Creator<Rating> CREATOR = Rating::fromBundle;
private static Rating fromBundle(Bundle bundle) { private static Rating fromBundle(Bundle bundle) {
@RatingType @RatingType
int ratingType = int ratingType = bundle.getInt(FIELD_RATING_TYPE, /* defaultValue= */ RATING_TYPE_UNSET);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET);
switch (ratingType) { switch (ratingType) {
case RATING_TYPE_HEART: case RATING_TYPE_HEART:
return HeartRating.CREATOR.fromBundle(bundle); return HeartRating.CREATOR.fromBundle(bundle);
...@@ -89,8 +83,4 @@ public abstract class Rating implements Bundleable { ...@@ -89,8 +83,4 @@ public abstract class Rating implements Bundleable {
throw new IllegalArgumentException("Unknown RatingType: " + ratingType); throw new IllegalArgumentException("Unknown RatingType: " + ratingType);
} }
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,19 +16,14 @@ ...@@ -16,19 +16,14 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as a fractional number of stars. */ /** A rating expressed as a fractional number of stars. */
public final class StarRating extends Rating { public final class StarRating extends Rating {
...@@ -106,22 +101,16 @@ public final class StarRating extends Rating { ...@@ -106,22 +101,16 @@ public final class StarRating extends Rating {
private static final @RatingType int TYPE = RATING_TYPE_STAR; private static final @RatingType int TYPE = RATING_TYPE_STAR;
private static final int MAX_STARS_DEFAULT = 5; private static final int MAX_STARS_DEFAULT = 5;
@Documented private static final String FIELD_MAX_STARS = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_STAR_RATING = Util.intToStringMaxRadix(2);
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_MAX_STARS, FIELD_STAR_RATING})
private @interface FieldNumber {}
private static final int FIELD_MAX_STARS = 1;
private static final int FIELD_STAR_RATING = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE); bundle.putInt(FIELD_RATING_TYPE, TYPE);
bundle.putInt(keyForField(FIELD_MAX_STARS), maxStars); bundle.putInt(FIELD_MAX_STARS, maxStars);
bundle.putFloat(keyForField(FIELD_STAR_RATING), starRating); bundle.putFloat(FIELD_STAR_RATING, starRating);
return bundle; return bundle;
} }
...@@ -129,19 +118,11 @@ public final class StarRating extends Rating { ...@@ -129,19 +118,11 @@ public final class StarRating extends Rating {
@UnstableApi public static final Creator<StarRating> CREATOR = StarRating::fromBundle; @UnstableApi public static final Creator<StarRating> CREATOR = StarRating::fromBundle;
private static StarRating fromBundle(Bundle bundle) { private static StarRating fromBundle(Bundle bundle) {
checkArgument( checkArgument(bundle.getInt(FIELD_RATING_TYPE, /* defaultValue= */ RATING_TYPE_UNSET) == TYPE);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET) int maxStars = bundle.getInt(FIELD_MAX_STARS, /* defaultValue= */ MAX_STARS_DEFAULT);
== TYPE); float starRating = bundle.getFloat(FIELD_STAR_RATING, /* defaultValue= */ RATING_UNSET);
int maxStars =
bundle.getInt(keyForField(FIELD_MAX_STARS), /* defaultValue= */ MAX_STARS_DEFAULT);
float starRating =
bundle.getFloat(keyForField(FIELD_STAR_RATING), /* defaultValue= */ RATING_UNSET);
return starRating == RATING_UNSET return starRating == RATING_UNSET
? new StarRating(maxStars) ? new StarRating(maxStars)
: new StarRating(maxStars, starRating); : new StarRating(maxStars, starRating);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,17 +16,12 @@ ...@@ -16,17 +16,12 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** A rating expressed as "thumbs up" or "thumbs down". */ /** A rating expressed as "thumbs up" or "thumbs down". */
public final class ThumbRating extends Rating { public final class ThumbRating extends Rating {
...@@ -78,22 +73,16 @@ public final class ThumbRating extends Rating { ...@@ -78,22 +73,16 @@ public final class ThumbRating extends Rating {
private static final @RatingType int TYPE = RATING_TYPE_THUMB; private static final @RatingType int TYPE = RATING_TYPE_THUMB;
@Documented private static final String FIELD_RATED = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_IS_THUMBS_UP = Util.intToStringMaxRadix(2);
@Target(TYPE_USE)
@IntDef({FIELD_RATING_TYPE, FIELD_RATED, FIELD_IS_THUMBS_UP})
private @interface FieldNumber {}
private static final int FIELD_RATED = 1;
private static final int FIELD_IS_THUMBS_UP = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RATING_TYPE), TYPE); bundle.putInt(FIELD_RATING_TYPE, TYPE);
bundle.putBoolean(keyForField(FIELD_RATED), rated); bundle.putBoolean(FIELD_RATED, rated);
bundle.putBoolean(keyForField(FIELD_IS_THUMBS_UP), isThumbsUp); bundle.putBoolean(FIELD_IS_THUMBS_UP, isThumbsUp);
return bundle; return bundle;
} }
...@@ -101,17 +90,10 @@ public final class ThumbRating extends Rating { ...@@ -101,17 +90,10 @@ public final class ThumbRating extends Rating {
@UnstableApi public static final Creator<ThumbRating> CREATOR = ThumbRating::fromBundle; @UnstableApi public static final Creator<ThumbRating> CREATOR = ThumbRating::fromBundle;
private static ThumbRating fromBundle(Bundle bundle) { private static ThumbRating fromBundle(Bundle bundle) {
checkArgument( checkArgument(bundle.getInt(FIELD_RATING_TYPE, /* defaultValue= */ RATING_TYPE_UNSET) == TYPE);
bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET) boolean rated = bundle.getBoolean(FIELD_RATED, /* defaultValue= */ false);
== TYPE);
boolean rated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return rated return rated
? new ThumbRating( ? new ThumbRating(bundle.getBoolean(FIELD_IS_THUMBS_UP, /* defaultValue= */ false))
bundle.getBoolean(keyForField(FIELD_IS_THUMBS_UP), /* defaultValue= */ false))
: new ThumbRating(); : new ThumbRating();
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,20 +16,15 @@ ...@@ -16,20 +16,15 @@
package androidx.media3.common; package androidx.media3.common;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.CheckResult; import androidx.annotation.CheckResult;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.BundleableUtil;
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 com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -165,15 +160,8 @@ public final class TrackGroup implements Bundleable { ...@@ -165,15 +160,8 @@ public final class TrackGroup implements Bundleable {
} }
// Bundleable implementation. // Bundleable implementation.
private static final String FIELD_FORMATS = Util.intToStringMaxRadix(0);
@Documented private static final String FIELD_ID = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_FORMATS, FIELD_ID})
private @interface FieldNumber {}
private static final int FIELD_FORMATS = 0;
private static final int FIELD_ID = 1;
@UnstableApi @UnstableApi
@Override @Override
...@@ -183,8 +171,8 @@ public final class TrackGroup implements Bundleable { ...@@ -183,8 +171,8 @@ public final class TrackGroup implements Bundleable {
for (Format format : formats) { for (Format format : formats) {
arrayList.add(format.toBundle(/* excludeMetadata= */ true)); arrayList.add(format.toBundle(/* excludeMetadata= */ true));
} }
bundle.putParcelableArrayList(keyForField(FIELD_FORMATS), arrayList); bundle.putParcelableArrayList(FIELD_FORMATS, arrayList);
bundle.putString(keyForField(FIELD_ID), id); bundle.putString(FIELD_ID, id);
return bundle; return bundle;
} }
...@@ -192,20 +180,15 @@ public final class TrackGroup implements Bundleable { ...@@ -192,20 +180,15 @@ public final class TrackGroup implements Bundleable {
@UnstableApi @UnstableApi
public static final Creator<TrackGroup> CREATOR = public static final Creator<TrackGroup> CREATOR =
bundle -> { bundle -> {
@Nullable @Nullable List<Bundle> formatBundles = bundle.getParcelableArrayList(FIELD_FORMATS);
List<Bundle> formatBundles = bundle.getParcelableArrayList(keyForField(FIELD_FORMATS));
List<Format> formats = List<Format> formats =
formatBundles == null formatBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(Format.CREATOR, formatBundles); : BundleableUtil.fromBundleList(Format.CREATOR, formatBundles);
String id = bundle.getString(keyForField(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 static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
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
// qualities). We only log an error instead of throwing to not break backwards-compatibility for // qualities). We only log an error instead of throwing to not break backwards-compatibility for
......
...@@ -20,14 +20,11 @@ import static java.util.Collections.max; ...@@ -20,14 +20,11 @@ import static java.util.Collections.max;
import static java.util.Collections.min; import static java.util.Collections.min;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;
/** /**
...@@ -54,16 +51,8 @@ public final class TrackSelectionOverride implements Bundleable { ...@@ -54,16 +51,8 @@ public final class TrackSelectionOverride implements Bundleable {
/** The indices of tracks in a {@link TrackGroup} to be selected. */ /** The indices of tracks in a {@link TrackGroup} to be selected. */
public final ImmutableList<Integer> trackIndices; public final ImmutableList<Integer> trackIndices;
@Documented private static final String FIELD_TRACK_GROUP = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_TRACKS = Util.intToStringMaxRadix(1);
@IntDef({
FIELD_TRACK_GROUP,
FIELD_TRACKS,
})
private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUP = 0;
private static final int FIELD_TRACKS = 1;
/** /**
* Constructs an instance to force {@code trackIndex} in {@code trackGroup} to be selected. * Constructs an instance to force {@code trackIndex} in {@code trackGroup} to be selected.
...@@ -119,8 +108,8 @@ public final class TrackSelectionOverride implements Bundleable { ...@@ -119,8 +108,8 @@ public final class TrackSelectionOverride implements Bundleable {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putBundle(keyForField(FIELD_TRACK_GROUP), mediaTrackGroup.toBundle()); bundle.putBundle(FIELD_TRACK_GROUP, mediaTrackGroup.toBundle());
bundle.putIntArray(keyForField(FIELD_TRACKS), Ints.toArray(trackIndices)); bundle.putIntArray(FIELD_TRACKS, Ints.toArray(trackIndices));
return bundle; return bundle;
} }
...@@ -128,13 +117,9 @@ public final class TrackSelectionOverride implements Bundleable { ...@@ -128,13 +117,9 @@ public final class TrackSelectionOverride implements Bundleable {
@UnstableApi @UnstableApi
public static final Creator<TrackSelectionOverride> CREATOR = public static final Creator<TrackSelectionOverride> CREATOR =
bundle -> { bundle -> {
Bundle trackGroupBundle = checkNotNull(bundle.getBundle(keyForField(FIELD_TRACK_GROUP))); Bundle trackGroupBundle = checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP));
TrackGroup mediaTrackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle); TrackGroup mediaTrackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle);
int[] tracks = checkNotNull(bundle.getIntArray(keyForField(FIELD_TRACKS))); int[] tracks = checkNotNull(bundle.getIntArray(FIELD_TRACKS));
return new TrackSelectionOverride(mediaTrackGroup, Ints.asList(tracks)); return new TrackSelectionOverride(mediaTrackGroup, Ints.asList(tracks));
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -18,20 +18,15 @@ package androidx.media3.common; ...@@ -18,20 +18,15 @@ 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.BundleableUtil.toBundleArrayList;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.BundleableUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Booleans; import com.google.common.primitives.Booleans;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -221,29 +216,19 @@ public final class Tracks implements Bundleable { ...@@ -221,29 +216,19 @@ public final class Tracks implements Bundleable {
} }
// Bundleable implementation. // Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_TRACK_GROUP = Util.intToStringMaxRadix(0);
@Target(TYPE_USE) private static final String FIELD_TRACK_SUPPORT = Util.intToStringMaxRadix(1);
@IntDef({ private static final String FIELD_TRACK_SELECTED = Util.intToStringMaxRadix(3);
FIELD_TRACK_GROUP, private static final String FIELD_ADAPTIVE_SUPPORTED = Util.intToStringMaxRadix(4);
FIELD_TRACK_SUPPORT,
FIELD_TRACK_SELECTED,
FIELD_ADAPTIVE_SUPPORTED,
})
private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUP = 0;
private static final int FIELD_TRACK_SUPPORT = 1;
private static final int FIELD_TRACK_SELECTED = 3;
private static final int FIELD_ADAPTIVE_SUPPORTED = 4;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putBundle(keyForField(FIELD_TRACK_GROUP), mediaTrackGroup.toBundle()); bundle.putBundle(FIELD_TRACK_GROUP, mediaTrackGroup.toBundle());
bundle.putIntArray(keyForField(FIELD_TRACK_SUPPORT), trackSupport); bundle.putIntArray(FIELD_TRACK_SUPPORT, trackSupport);
bundle.putBooleanArray(keyForField(FIELD_TRACK_SELECTED), trackSelected); bundle.putBooleanArray(FIELD_TRACK_SELECTED, trackSelected);
bundle.putBoolean(keyForField(FIELD_ADAPTIVE_SUPPORTED), adaptiveSupported); bundle.putBoolean(FIELD_ADAPTIVE_SUPPORTED, adaptiveSupported);
return bundle; return bundle;
} }
...@@ -253,23 +238,16 @@ public final class Tracks implements Bundleable { ...@@ -253,23 +238,16 @@ public final class Tracks implements Bundleable {
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.CREATOR.fromBundle( TrackGroup.CREATOR.fromBundle(checkNotNull(bundle.getBundle(FIELD_TRACK_GROUP)));
checkNotNull(bundle.getBundle(keyForField(FIELD_TRACK_GROUP))));
final @C.FormatSupport int[] trackSupport = final @C.FormatSupport int[] trackSupport =
MoreObjects.firstNonNull( MoreObjects.firstNonNull(
bundle.getIntArray(keyForField(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(keyForField(FIELD_TRACK_SELECTED)), bundle.getBooleanArray(FIELD_TRACK_SELECTED), new boolean[trackGroup.length]);
new boolean[trackGroup.length]); boolean adaptiveSupported = bundle.getBoolean(FIELD_ADAPTIVE_SUPPORTED, false);
boolean adaptiveSupported =
bundle.getBoolean(keyForField(FIELD_ADAPTIVE_SUPPORTED), false);
return new Group(trackGroup, adaptiveSupported, trackSupport, selected); return new Group(trackGroup, adaptiveSupported, trackSupport, selected);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
/** Empty tracks. */ /** Empty tracks. */
...@@ -385,21 +363,13 @@ public final class Tracks implements Bundleable { ...@@ -385,21 +363,13 @@ public final class Tracks implements Bundleable {
} }
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_TRACK_GROUPS = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TRACK_GROUPS,
})
private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUPS = 0;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList(keyForField(FIELD_TRACK_GROUPS), toBundleArrayList(groups)); bundle.putParcelableArrayList(FIELD_TRACK_GROUPS, toBundleArrayList(groups));
return bundle; return bundle;
} }
...@@ -407,16 +377,11 @@ public final class Tracks implements Bundleable { ...@@ -407,16 +377,11 @@ public final class Tracks implements Bundleable {
@UnstableApi @UnstableApi
public static final Creator<Tracks> CREATOR = public static final Creator<Tracks> CREATOR =
bundle -> { bundle -> {
@Nullable @Nullable List<Bundle> groupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS);
List<Bundle> groupBundles = bundle.getParcelableArrayList(keyForField(FIELD_TRACK_GROUPS));
List<Group> groups = List<Group> groups =
groupBundles == null groupBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(Group.CREATOR, groupBundles); : BundleableUtil.fromBundleList(Group.CREATOR, groupBundles);
return new Tracks(groups); return new Tracks(groups);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -15,18 +15,12 @@ ...@@ -15,18 +15,12 @@
*/ */
package androidx.media3.common; package androidx.media3.common;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import java.lang.annotation.Documented; import androidx.media3.common.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Represents the video size. */ /** Represents the video size. */
public final class VideoSize implements Bundleable { public final class VideoSize implements Bundleable {
...@@ -132,48 +126,32 @@ public final class VideoSize implements Bundleable { ...@@ -132,48 +126,32 @@ public final class VideoSize implements Bundleable {
} }
// Bundleable implementation. // Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_WIDTH = Util.intToStringMaxRadix(0);
@Target(TYPE_USE) private static final String FIELD_HEIGHT = Util.intToStringMaxRadix(1);
@IntDef({ private static final String FIELD_UNAPPLIED_ROTATION_DEGREES = Util.intToStringMaxRadix(2);
FIELD_WIDTH, private static final String FIELD_PIXEL_WIDTH_HEIGHT_RATIO = Util.intToStringMaxRadix(3);
FIELD_HEIGHT,
FIELD_UNAPPLIED_ROTATION_DEGREES,
FIELD_PIXEL_WIDTH_HEIGHT_RATIO,
})
private @interface FieldNumber {}
private static final int FIELD_WIDTH = 0;
private static final int FIELD_HEIGHT = 1;
private static final int FIELD_UNAPPLIED_ROTATION_DEGREES = 2;
private static final int FIELD_PIXEL_WIDTH_HEIGHT_RATIO = 3;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_WIDTH), width); bundle.putInt(FIELD_WIDTH, width);
bundle.putInt(keyForField(FIELD_HEIGHT), height); bundle.putInt(FIELD_HEIGHT, height);
bundle.putInt(keyForField(FIELD_UNAPPLIED_ROTATION_DEGREES), unappliedRotationDegrees); bundle.putInt(FIELD_UNAPPLIED_ROTATION_DEGREES, unappliedRotationDegrees);
bundle.putFloat(keyForField(FIELD_PIXEL_WIDTH_HEIGHT_RATIO), pixelWidthHeightRatio); bundle.putFloat(FIELD_PIXEL_WIDTH_HEIGHT_RATIO, pixelWidthHeightRatio);
return bundle; return bundle;
} }
@UnstableApi @UnstableApi
public static final Creator<VideoSize> CREATOR = public static final Creator<VideoSize> CREATOR =
bundle -> { bundle -> {
int width = bundle.getInt(keyForField(FIELD_WIDTH), DEFAULT_WIDTH); int width = bundle.getInt(FIELD_WIDTH, DEFAULT_WIDTH);
int height = bundle.getInt(keyForField(FIELD_HEIGHT), DEFAULT_HEIGHT); int height = bundle.getInt(FIELD_HEIGHT, DEFAULT_HEIGHT);
int unappliedRotationDegrees = int unappliedRotationDegrees =
bundle.getInt( bundle.getInt(FIELD_UNAPPLIED_ROTATION_DEGREES, DEFAULT_UNAPPLIED_ROTATION_DEGREES);
keyForField(FIELD_UNAPPLIED_ROTATION_DEGREES), DEFAULT_UNAPPLIED_ROTATION_DEGREES);
float pixelWidthHeightRatio = float pixelWidthHeightRatio =
bundle.getFloat( bundle.getFloat(FIELD_PIXEL_WIDTH_HEIGHT_RATIO, DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO);
keyForField(FIELD_PIXEL_WIDTH_HEIGHT_RATIO), DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO);
return new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio); return new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -35,6 +35,7 @@ import androidx.annotation.Nullable; ...@@ -35,6 +35,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
...@@ -977,69 +978,45 @@ public final class Cue implements Bundleable { ...@@ -977,69 +978,45 @@ public final class Cue implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_TEXT = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_TEXT_ALIGNMENT = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_MULTI_ROW_ALIGNMENT = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_BITMAP = Util.intToStringMaxRadix(3);
FIELD_TEXT, private static final String FIELD_LINE = Util.intToStringMaxRadix(4);
FIELD_TEXT_ALIGNMENT, private static final String FIELD_LINE_TYPE = Util.intToStringMaxRadix(5);
FIELD_MULTI_ROW_ALIGNMENT, private static final String FIELD_LINE_ANCHOR = Util.intToStringMaxRadix(6);
FIELD_BITMAP, private static final String FIELD_POSITION = Util.intToStringMaxRadix(7);
FIELD_LINE, private static final String FIELD_POSITION_ANCHOR = Util.intToStringMaxRadix(8);
FIELD_LINE_TYPE, private static final String FIELD_TEXT_SIZE_TYPE = Util.intToStringMaxRadix(9);
FIELD_LINE_ANCHOR, private static final String FIELD_TEXT_SIZE = Util.intToStringMaxRadix(10);
FIELD_POSITION, private static final String FIELD_SIZE = Util.intToStringMaxRadix(11);
FIELD_POSITION_ANCHOR, private static final String FIELD_BITMAP_HEIGHT = Util.intToStringMaxRadix(12);
FIELD_TEXT_SIZE_TYPE, private static final String FIELD_WINDOW_COLOR = Util.intToStringMaxRadix(13);
FIELD_TEXT_SIZE, private static final String FIELD_WINDOW_COLOR_SET = Util.intToStringMaxRadix(14);
FIELD_SIZE, private static final String FIELD_VERTICAL_TYPE = Util.intToStringMaxRadix(15);
FIELD_BITMAP_HEIGHT, private static final String FIELD_SHEAR_DEGREES = Util.intToStringMaxRadix(16);
FIELD_WINDOW_COLOR,
FIELD_WINDOW_COLOR_SET,
FIELD_VERTICAL_TYPE,
FIELD_SHEAR_DEGREES
})
private @interface FieldNumber {}
private static final int FIELD_TEXT = 0;
private static final int FIELD_TEXT_ALIGNMENT = 1;
private static final int FIELD_MULTI_ROW_ALIGNMENT = 2;
private static final int FIELD_BITMAP = 3;
private static final int FIELD_LINE = 4;
private static final int FIELD_LINE_TYPE = 5;
private static final int FIELD_LINE_ANCHOR = 6;
private static final int FIELD_POSITION = 7;
private static final int FIELD_POSITION_ANCHOR = 8;
private static final int FIELD_TEXT_SIZE_TYPE = 9;
private static final int FIELD_TEXT_SIZE = 10;
private static final int FIELD_SIZE = 11;
private static final int FIELD_BITMAP_HEIGHT = 12;
private static final int FIELD_WINDOW_COLOR = 13;
private static final int FIELD_WINDOW_COLOR_SET = 14;
private static final int FIELD_VERTICAL_TYPE = 15;
private static final int FIELD_SHEAR_DEGREES = 16;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putCharSequence(keyForField(FIELD_TEXT), text); bundle.putCharSequence(FIELD_TEXT, text);
bundle.putSerializable(keyForField(FIELD_TEXT_ALIGNMENT), textAlignment); bundle.putSerializable(FIELD_TEXT_ALIGNMENT, textAlignment);
bundle.putSerializable(keyForField(FIELD_MULTI_ROW_ALIGNMENT), multiRowAlignment); bundle.putSerializable(FIELD_MULTI_ROW_ALIGNMENT, multiRowAlignment);
bundle.putParcelable(keyForField(FIELD_BITMAP), bitmap); bundle.putParcelable(FIELD_BITMAP, bitmap);
bundle.putFloat(keyForField(FIELD_LINE), line); bundle.putFloat(FIELD_LINE, line);
bundle.putInt(keyForField(FIELD_LINE_TYPE), lineType); bundle.putInt(FIELD_LINE_TYPE, lineType);
bundle.putInt(keyForField(FIELD_LINE_ANCHOR), lineAnchor); bundle.putInt(FIELD_LINE_ANCHOR, lineAnchor);
bundle.putFloat(keyForField(FIELD_POSITION), position); bundle.putFloat(FIELD_POSITION, position);
bundle.putInt(keyForField(FIELD_POSITION_ANCHOR), positionAnchor); bundle.putInt(FIELD_POSITION_ANCHOR, positionAnchor);
bundle.putInt(keyForField(FIELD_TEXT_SIZE_TYPE), textSizeType); bundle.putInt(FIELD_TEXT_SIZE_TYPE, textSizeType);
bundle.putFloat(keyForField(FIELD_TEXT_SIZE), textSize); bundle.putFloat(FIELD_TEXT_SIZE, textSize);
bundle.putFloat(keyForField(FIELD_SIZE), size); bundle.putFloat(FIELD_SIZE, size);
bundle.putFloat(keyForField(FIELD_BITMAP_HEIGHT), bitmapHeight); bundle.putFloat(FIELD_BITMAP_HEIGHT, bitmapHeight);
bundle.putBoolean(keyForField(FIELD_WINDOW_COLOR_SET), windowColorSet); bundle.putBoolean(FIELD_WINDOW_COLOR_SET, windowColorSet);
bundle.putInt(keyForField(FIELD_WINDOW_COLOR), windowColor); bundle.putInt(FIELD_WINDOW_COLOR, windowColor);
bundle.putInt(keyForField(FIELD_VERTICAL_TYPE), verticalType); bundle.putInt(FIELD_VERTICAL_TYPE, verticalType);
bundle.putFloat(keyForField(FIELD_SHEAR_DEGREES), shearDegrees); bundle.putFloat(FIELD_SHEAR_DEGREES, shearDegrees);
return bundle; return bundle;
} }
...@@ -1047,67 +1024,56 @@ public final class Cue implements Bundleable { ...@@ -1047,67 +1024,56 @@ public final class Cue implements Bundleable {
private static final Cue fromBundle(Bundle bundle) { private static final Cue fromBundle(Bundle bundle) {
Builder builder = new Builder(); Builder builder = new Builder();
@Nullable CharSequence text = bundle.getCharSequence(keyForField(FIELD_TEXT)); @Nullable CharSequence text = bundle.getCharSequence(FIELD_TEXT);
if (text != null) { if (text != null) {
builder.setText(text); builder.setText(text);
} }
@Nullable @Nullable Alignment textAlignment = (Alignment) bundle.getSerializable(FIELD_TEXT_ALIGNMENT);
Alignment textAlignment = (Alignment) bundle.getSerializable(keyForField(FIELD_TEXT_ALIGNMENT));
if (textAlignment != null) { if (textAlignment != null) {
builder.setTextAlignment(textAlignment); builder.setTextAlignment(textAlignment);
} }
@Nullable @Nullable
Alignment multiRowAlignment = Alignment multiRowAlignment = (Alignment) bundle.getSerializable(FIELD_MULTI_ROW_ALIGNMENT);
(Alignment) bundle.getSerializable(keyForField(FIELD_MULTI_ROW_ALIGNMENT));
if (multiRowAlignment != null) { if (multiRowAlignment != null) {
builder.setMultiRowAlignment(multiRowAlignment); builder.setMultiRowAlignment(multiRowAlignment);
} }
@Nullable Bitmap bitmap = bundle.getParcelable(keyForField(FIELD_BITMAP)); @Nullable Bitmap bitmap = bundle.getParcelable(FIELD_BITMAP);
if (bitmap != null) { if (bitmap != null) {
builder.setBitmap(bitmap); builder.setBitmap(bitmap);
} }
if (bundle.containsKey(keyForField(FIELD_LINE)) if (bundle.containsKey(FIELD_LINE) && bundle.containsKey(FIELD_LINE_TYPE)) {
&& bundle.containsKey(keyForField(FIELD_LINE_TYPE))) { builder.setLine(bundle.getFloat(FIELD_LINE), bundle.getInt(FIELD_LINE_TYPE));
builder.setLine(
bundle.getFloat(keyForField(FIELD_LINE)), bundle.getInt(keyForField(FIELD_LINE_TYPE)));
} }
if (bundle.containsKey(keyForField(FIELD_LINE_ANCHOR))) { if (bundle.containsKey(FIELD_LINE_ANCHOR)) {
builder.setLineAnchor(bundle.getInt(keyForField(FIELD_LINE_ANCHOR))); builder.setLineAnchor(bundle.getInt(FIELD_LINE_ANCHOR));
} }
if (bundle.containsKey(keyForField(FIELD_POSITION))) { if (bundle.containsKey(FIELD_POSITION)) {
builder.setPosition(bundle.getFloat(keyForField(FIELD_POSITION))); builder.setPosition(bundle.getFloat(FIELD_POSITION));
} }
if (bundle.containsKey(keyForField(FIELD_POSITION_ANCHOR))) { if (bundle.containsKey(FIELD_POSITION_ANCHOR)) {
builder.setPositionAnchor(bundle.getInt(keyForField(FIELD_POSITION_ANCHOR))); builder.setPositionAnchor(bundle.getInt(FIELD_POSITION_ANCHOR));
} }
if (bundle.containsKey(keyForField(FIELD_TEXT_SIZE)) if (bundle.containsKey(FIELD_TEXT_SIZE) && bundle.containsKey(FIELD_TEXT_SIZE_TYPE)) {
&& bundle.containsKey(keyForField(FIELD_TEXT_SIZE_TYPE))) { builder.setTextSize(bundle.getFloat(FIELD_TEXT_SIZE), bundle.getInt(FIELD_TEXT_SIZE_TYPE));
builder.setTextSize(
bundle.getFloat(keyForField(FIELD_TEXT_SIZE)),
bundle.getInt(keyForField(FIELD_TEXT_SIZE_TYPE)));
} }
if (bundle.containsKey(keyForField(FIELD_SIZE))) { if (bundle.containsKey(FIELD_SIZE)) {
builder.setSize(bundle.getFloat(keyForField(FIELD_SIZE))); builder.setSize(bundle.getFloat(FIELD_SIZE));
} }
if (bundle.containsKey(keyForField(FIELD_BITMAP_HEIGHT))) { if (bundle.containsKey(FIELD_BITMAP_HEIGHT)) {
builder.setBitmapHeight(bundle.getFloat(keyForField(FIELD_BITMAP_HEIGHT))); builder.setBitmapHeight(bundle.getFloat(FIELD_BITMAP_HEIGHT));
} }
if (bundle.containsKey(keyForField(FIELD_WINDOW_COLOR))) { if (bundle.containsKey(FIELD_WINDOW_COLOR)) {
builder.setWindowColor(bundle.getInt(keyForField(FIELD_WINDOW_COLOR))); builder.setWindowColor(bundle.getInt(FIELD_WINDOW_COLOR));
} }
if (!bundle.getBoolean(keyForField(FIELD_WINDOW_COLOR_SET), /* defaultValue= */ false)) { if (!bundle.getBoolean(FIELD_WINDOW_COLOR_SET, /* defaultValue= */ false)) {
builder.clearWindowColor(); builder.clearWindowColor();
} }
if (bundle.containsKey(keyForField(FIELD_VERTICAL_TYPE))) { if (bundle.containsKey(FIELD_VERTICAL_TYPE)) {
builder.setVerticalType(bundle.getInt(keyForField(FIELD_VERTICAL_TYPE))); builder.setVerticalType(bundle.getInt(FIELD_VERTICAL_TYPE));
} }
if (bundle.containsKey(keyForField(FIELD_SHEAR_DEGREES))) { if (bundle.containsKey(FIELD_SHEAR_DEGREES)) {
builder.setShearDegrees(bundle.getFloat(keyForField(FIELD_SHEAR_DEGREES))); builder.setShearDegrees(bundle.getFloat(FIELD_SHEAR_DEGREES));
} }
return builder.build(); return builder.build();
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -15,21 +15,15 @@ ...@@ -15,21 +15,15 @@
*/ */
package androidx.media3.common.text; package androidx.media3.common.text;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
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.BundleableUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -66,41 +60,31 @@ public final class CueGroup implements Bundleable { ...@@ -66,41 +60,31 @@ public final class CueGroup implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_CUES = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_PRESENTATION_TIME_US = Util.intToStringMaxRadix(1);
@Target(TYPE_USE)
@IntDef({FIELD_CUES, FIELD_PRESENTATION_TIME_US})
private @interface FieldNumber {}
private static final int FIELD_CUES = 0;
private static final int FIELD_PRESENTATION_TIME_US = 1;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
keyForField(FIELD_CUES), BundleableUtil.toBundleArrayList(filterOutBitmapCues(cues))); FIELD_CUES, BundleableUtil.toBundleArrayList(filterOutBitmapCues(cues)));
bundle.putLong(keyForField(FIELD_PRESENTATION_TIME_US), presentationTimeUs); bundle.putLong(FIELD_PRESENTATION_TIME_US, presentationTimeUs);
return bundle; return bundle;
} }
@UnstableApi public static final Creator<CueGroup> CREATOR = CueGroup::fromBundle; @UnstableApi public static final Creator<CueGroup> CREATOR = CueGroup::fromBundle;
private static final CueGroup fromBundle(Bundle bundle) { private static final CueGroup fromBundle(Bundle bundle) {
@Nullable ArrayList<Bundle> cueBundles = bundle.getParcelableArrayList(keyForField(FIELD_CUES)); @Nullable ArrayList<Bundle> cueBundles = bundle.getParcelableArrayList(FIELD_CUES);
List<Cue> cues = List<Cue> cues =
cueBundles == null cueBundles == null
? ImmutableList.of() ? ImmutableList.of()
: BundleableUtil.fromBundleList(Cue.CREATOR, cueBundles); : BundleableUtil.fromBundleList(Cue.CREATOR, cueBundles);
long presentationTimeUs = bundle.getLong(keyForField(FIELD_PRESENTATION_TIME_US)); long presentationTimeUs = bundle.getLong(FIELD_PRESENTATION_TIME_US);
return new CueGroup(cues, presentationTimeUs); return new CueGroup(cues, presentationTimeUs);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
/** /**
* Filters out {@link Cue} objects containing {@link Bitmap}. It is used when transferring cues * Filters out {@link Cue} objects containing {@link Bitmap}. It is used when transferring cues
* between processes to prevent transferring too much data. * between processes to prevent transferring too much data.
......
...@@ -2884,6 +2884,16 @@ public final class Util { ...@@ -2884,6 +2884,16 @@ public final class Util {
: resources.getDrawable(drawableRes); : resources.getDrawable(drawableRes);
} }
/**
* Returns a string representation of the integer using radix value {@link Character#MAX_RADIX}.
*
* @param i An integer to be converted to String.
*/
@UnstableApi
public static String intToStringMaxRadix(int i) {
return Integer.toString(i, Character.MAX_RADIX);
}
@Nullable @Nullable
private static String getSystemProperty(String name) { private static String getSystemProperty(String name) {
try { try {
......
...@@ -859,6 +859,8 @@ public class MediaItemTest { ...@@ -859,6 +859,8 @@ public class MediaItemTest {
@Test @Test
public void createMediaItemInstance_roundTripViaBundle_yieldsEqualInstance() { public void createMediaItemInstance_roundTripViaBundle_yieldsEqualInstance() {
Bundle extras = new Bundle();
extras.putString("key", "value");
// Creates instance by setting some non-default values // Creates instance by setting some non-default values
MediaItem mediaItem = MediaItem mediaItem =
new MediaItem.Builder() new MediaItem.Builder()
...@@ -874,11 +876,14 @@ public class MediaItemTest { ...@@ -874,11 +876,14 @@ public class MediaItemTest {
new RequestMetadata.Builder() new RequestMetadata.Builder()
.setMediaUri(Uri.parse("http://test.test")) .setMediaUri(Uri.parse("http://test.test"))
.setSearchQuery("search") .setSearchQuery("search")
.setExtras(extras)
.build()) .build())
.build(); .build();
MediaItem mediaItemFromBundle = MediaItem.CREATOR.fromBundle(mediaItem.toBundle()); MediaItem mediaItemFromBundle = MediaItem.CREATOR.fromBundle(mediaItem.toBundle());
assertThat(mediaItemFromBundle).isEqualTo(mediaItem); assertThat(mediaItemFromBundle).isEqualTo(mediaItem);
assertThat(mediaItemFromBundle.requestMetadata.extras)
.isEqualTo(mediaItem.requestMetadata.extras);
} }
} }
...@@ -250,17 +250,15 @@ public final class ExoPlaybackException extends PlaybackException { ...@@ -250,17 +250,15 @@ public final class ExoPlaybackException extends PlaybackException {
private ExoPlaybackException(Bundle bundle) { private ExoPlaybackException(Bundle bundle) {
super(bundle); super(bundle);
type = bundle.getInt(keyForField(FIELD_TYPE), /* defaultValue= */ TYPE_UNEXPECTED); type = bundle.getInt(FIELD_TYPE, /* defaultValue= */ TYPE_UNEXPECTED);
rendererName = bundle.getString(keyForField(FIELD_RENDERER_NAME)); rendererName = bundle.getString(FIELD_RENDERER_NAME);
rendererIndex = rendererIndex = bundle.getInt(FIELD_RENDERER_INDEX, /* defaultValue= */ C.INDEX_UNSET);
bundle.getInt(keyForField(FIELD_RENDERER_INDEX), /* defaultValue= */ C.INDEX_UNSET); @Nullable Bundle rendererFormatBundle = bundle.getBundle(FIELD_RENDERER_FORMAT);
@Nullable Bundle rendererFormatBundle = bundle.getBundle(keyForField(FIELD_RENDERER_FORMAT));
rendererFormat = rendererFormat =
rendererFormatBundle == null ? null : Format.CREATOR.fromBundle(rendererFormatBundle); rendererFormatBundle == null ? null : Format.CREATOR.fromBundle(rendererFormatBundle);
rendererFormatSupport = rendererFormatSupport =
bundle.getInt( bundle.getInt(FIELD_RENDERER_FORMAT_SUPPORT, /* defaultValue= */ C.FORMAT_HANDLED);
keyForField(FIELD_RENDERER_FORMAT_SUPPORT), /* defaultValue= */ C.FORMAT_HANDLED); isRecoverable = bundle.getBoolean(FIELD_IS_RECOVERABLE, /* defaultValue= */ false);
isRecoverable = bundle.getBoolean(keyForField(FIELD_IS_RECOVERABLE), /* defaultValue= */ false);
mediaPeriodId = null; mediaPeriodId = null;
} }
...@@ -403,12 +401,17 @@ public final class ExoPlaybackException extends PlaybackException { ...@@ -403,12 +401,17 @@ public final class ExoPlaybackException extends PlaybackException {
@UnstableApi @UnstableApi
public static final Creator<ExoPlaybackException> CREATOR = ExoPlaybackException::new; public static final Creator<ExoPlaybackException> CREATOR = ExoPlaybackException::new;
private static final int FIELD_TYPE = FIELD_CUSTOM_ID_BASE + 1; private static final String FIELD_TYPE = Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 1);
private static final int FIELD_RENDERER_NAME = FIELD_CUSTOM_ID_BASE + 2; private static final String FIELD_RENDERER_NAME =
private static final int FIELD_RENDERER_INDEX = FIELD_CUSTOM_ID_BASE + 3; Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 2);
private static final int FIELD_RENDERER_FORMAT = FIELD_CUSTOM_ID_BASE + 4; private static final String FIELD_RENDERER_INDEX =
private static final int FIELD_RENDERER_FORMAT_SUPPORT = FIELD_CUSTOM_ID_BASE + 5; Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 3);
private static final int FIELD_IS_RECOVERABLE = FIELD_CUSTOM_ID_BASE + 6; private static final String FIELD_RENDERER_FORMAT =
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 4);
private static final String FIELD_RENDERER_FORMAT_SUPPORT =
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 5);
private static final String FIELD_IS_RECOVERABLE =
Util.intToStringMaxRadix(FIELD_CUSTOM_ID_BASE + 6);
/** /**
* {@inheritDoc} * {@inheritDoc}
...@@ -420,14 +423,14 @@ public final class ExoPlaybackException extends PlaybackException { ...@@ -420,14 +423,14 @@ public final class ExoPlaybackException extends PlaybackException {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = super.toBundle(); Bundle bundle = super.toBundle();
bundle.putInt(keyForField(FIELD_TYPE), type); bundle.putInt(FIELD_TYPE, type);
bundle.putString(keyForField(FIELD_RENDERER_NAME), rendererName); bundle.putString(FIELD_RENDERER_NAME, rendererName);
bundle.putInt(keyForField(FIELD_RENDERER_INDEX), rendererIndex); bundle.putInt(FIELD_RENDERER_INDEX, rendererIndex);
if (rendererFormat != null) { if (rendererFormat != null) {
bundle.putBundle(keyForField(FIELD_RENDERER_FORMAT), rendererFormat.toBundle()); bundle.putBundle(FIELD_RENDERER_FORMAT, rendererFormat.toBundle());
} }
bundle.putInt(keyForField(FIELD_RENDERER_FORMAT_SUPPORT), rendererFormatSupport); bundle.putInt(FIELD_RENDERER_FORMAT_SUPPORT, rendererFormatSupport);
bundle.putBoolean(keyForField(FIELD_IS_RECOVERABLE), isRecoverable); bundle.putBoolean(FIELD_IS_RECOVERABLE, isRecoverable);
return bundle; return bundle;
} }
} }
...@@ -15,10 +15,7 @@ ...@@ -15,10 +15,7 @@
*/ */
package androidx.media3.exoplayer.source; package androidx.media3.exoplayer.source;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.C; import androidx.media3.common.C;
...@@ -26,11 +23,8 @@ import androidx.media3.common.TrackGroup; ...@@ -26,11 +23,8 @@ import androidx.media3.common.TrackGroup;
import androidx.media3.common.util.BundleableUtil; import androidx.media3.common.util.BundleableUtil;
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 com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List; import java.util.List;
/** /**
...@@ -118,21 +112,13 @@ public final class TrackGroupArray implements Bundleable { ...@@ -118,21 +112,13 @@ public final class TrackGroupArray implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_TRACK_GROUPS = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
FIELD_TRACK_GROUPS,
})
private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUPS = 0;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList( bundle.putParcelableArrayList(
keyForField(FIELD_TRACK_GROUPS), BundleableUtil.toBundleArrayList(trackGroups)); FIELD_TRACK_GROUPS, BundleableUtil.toBundleArrayList(trackGroups));
return bundle; return bundle;
} }
...@@ -140,8 +126,7 @@ public final class TrackGroupArray implements Bundleable { ...@@ -140,8 +126,7 @@ public final class TrackGroupArray implements Bundleable {
public static final Creator<TrackGroupArray> CREATOR = public static final Creator<TrackGroupArray> CREATOR =
bundle -> { bundle -> {
@Nullable @Nullable
List<Bundle> trackGroupBundles = List<Bundle> trackGroupBundles = bundle.getParcelableArrayList(FIELD_TRACK_GROUPS);
bundle.getParcelableArrayList(keyForField(FIELD_TRACK_GROUPS));
if (trackGroupBundles == null) { if (trackGroupBundles == null) {
return new TrackGroupArray(); return new TrackGroupArray();
} }
...@@ -163,8 +148,4 @@ public final class TrackGroupArray implements Bundleable { ...@@ -163,8 +148,4 @@ public final class TrackGroupArray implements Bundleable {
} }
} }
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -30,7 +30,6 @@ import static androidx.media3.exoplayer.ima.ImaUtil.splitAdGroup; ...@@ -30,7 +30,6 @@ import static androidx.media3.exoplayer.ima.ImaUtil.splitAdGroup;
import static androidx.media3.exoplayer.ima.ImaUtil.splitAdPlaybackStateForPeriods; import static androidx.media3.exoplayer.ima.ImaUtil.splitAdPlaybackStateForPeriods;
import static androidx.media3.exoplayer.ima.ImaUtil.updateAdDurationInAdGroup; import static androidx.media3.exoplayer.ima.ImaUtil.updateAdDurationInAdGroup;
import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState; import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
...@@ -39,7 +38,6 @@ import android.os.Handler; ...@@ -39,7 +38,6 @@ import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Pair; import android.util.Pair;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.IntDef;
import androidx.annotation.MainThread; import androidx.annotation.MainThread;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
...@@ -98,10 +96,6 @@ import com.google.common.collect.ImmutableList; ...@@ -98,10 +96,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
...@@ -328,13 +322,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou ...@@ -328,13 +322,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_AD_PLAYBACK_STATES = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_AD_PLAYBACK_STATES})
private @interface FieldNumber {}
private static final int FIELD_AD_PLAYBACK_STATES = 1;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
...@@ -343,7 +331,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou ...@@ -343,7 +331,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
for (Map.Entry<String, AdPlaybackState> entry : adPlaybackStates.entrySet()) { for (Map.Entry<String, AdPlaybackState> entry : adPlaybackStates.entrySet()) {
adPlaybackStatesBundle.putBundle(entry.getKey(), entry.getValue().toBundle()); adPlaybackStatesBundle.putBundle(entry.getKey(), entry.getValue().toBundle());
} }
bundle.putBundle(keyForField(FIELD_AD_PLAYBACK_STATES), adPlaybackStatesBundle); bundle.putBundle(FIELD_AD_PLAYBACK_STATES, adPlaybackStatesBundle);
return bundle; return bundle;
} }
...@@ -354,8 +342,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou ...@@ -354,8 +342,7 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
@Nullable @Nullable
ImmutableMap.Builder<String, AdPlaybackState> adPlaybackStateMap = ImmutableMap.Builder<String, AdPlaybackState> adPlaybackStateMap =
new ImmutableMap.Builder<>(); new ImmutableMap.Builder<>();
Bundle adPlaybackStateBundle = Bundle adPlaybackStateBundle = checkNotNull(bundle.getBundle(FIELD_AD_PLAYBACK_STATES));
checkNotNull(bundle.getBundle(keyForField(FIELD_AD_PLAYBACK_STATES)));
for (String key : adPlaybackStateBundle.keySet()) { for (String key : adPlaybackStateBundle.keySet()) {
AdPlaybackState adPlaybackState = AdPlaybackState adPlaybackState =
AdPlaybackState.CREATOR.fromBundle( AdPlaybackState.CREATOR.fromBundle(
...@@ -365,10 +352,6 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou ...@@ -365,10 +352,6 @@ public final class ImaServerSideAdInsertionMediaSource extends CompositeMediaSou
} }
return new State(adPlaybackStateMap.buildOrThrow()); return new State(adPlaybackStateMap.buildOrThrow());
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
private final ImaUtil.ServerSideAdInsertionConfiguration configuration; private final ImaUtil.ServerSideAdInsertionConfiguration configuration;
......
...@@ -17,20 +17,15 @@ package androidx.media3.session; ...@@ -17,20 +17,15 @@ package androidx.media3.session;
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 java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
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.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List; import java.util.List;
/** /**
...@@ -201,38 +196,25 @@ public final class CommandButton implements Bundleable { ...@@ -201,38 +196,25 @@ public final class CommandButton implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_SESSION_COMMAND = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_PLAYER_COMMAND = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_ICON_RES_ID = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_DISPLAY_NAME = Util.intToStringMaxRadix(3);
FIELD_SESSION_COMMAND, private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(4);
FIELD_PLAYER_COMMAND, private static final String FIELD_ENABLED = Util.intToStringMaxRadix(5);
FIELD_ICON_RES_ID,
FIELD_DISPLAY_NAME,
FIELD_EXTRAS,
FIELD_ENABLED
})
private @interface FieldNumber {}
private static final int FIELD_SESSION_COMMAND = 0;
private static final int FIELD_PLAYER_COMMAND = 1;
private static final int FIELD_ICON_RES_ID = 2;
private static final int FIELD_DISPLAY_NAME = 3;
private static final int FIELD_EXTRAS = 4;
private static final int FIELD_ENABLED = 5;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
if (sessionCommand != null) { if (sessionCommand != null) {
bundle.putBundle(keyForField(FIELD_SESSION_COMMAND), sessionCommand.toBundle()); bundle.putBundle(FIELD_SESSION_COMMAND, sessionCommand.toBundle());
} }
bundle.putInt(keyForField(FIELD_PLAYER_COMMAND), playerCommand); bundle.putInt(FIELD_PLAYER_COMMAND, playerCommand);
bundle.putInt(keyForField(FIELD_ICON_RES_ID), iconResId); bundle.putInt(FIELD_ICON_RES_ID, iconResId);
bundle.putCharSequence(keyForField(FIELD_DISPLAY_NAME), displayName); bundle.putCharSequence(FIELD_DISPLAY_NAME, displayName);
bundle.putBundle(keyForField(FIELD_EXTRAS), extras); bundle.putBundle(FIELD_EXTRAS, extras);
bundle.putBoolean(keyForField(FIELD_ENABLED), isEnabled); bundle.putBoolean(FIELD_ENABLED, isEnabled);
return bundle; return bundle;
} }
...@@ -240,7 +222,7 @@ public final class CommandButton implements Bundleable { ...@@ -240,7 +222,7 @@ public final class CommandButton implements Bundleable {
@UnstableApi public static final Creator<CommandButton> CREATOR = CommandButton::fromBundle; @UnstableApi public static final Creator<CommandButton> CREATOR = CommandButton::fromBundle;
private static CommandButton fromBundle(Bundle bundle) { private static CommandButton fromBundle(Bundle bundle) {
@Nullable Bundle sessionCommandBundle = bundle.getBundle(keyForField(FIELD_SESSION_COMMAND)); @Nullable Bundle sessionCommandBundle = bundle.getBundle(FIELD_SESSION_COMMAND);
@Nullable @Nullable
SessionCommand sessionCommand = SessionCommand sessionCommand =
sessionCommandBundle == null sessionCommandBundle == null
...@@ -248,13 +230,11 @@ public final class CommandButton implements Bundleable { ...@@ -248,13 +230,11 @@ public final class CommandButton implements Bundleable {
: SessionCommand.CREATOR.fromBundle(sessionCommandBundle); : SessionCommand.CREATOR.fromBundle(sessionCommandBundle);
@Player.Command @Player.Command
int playerCommand = int playerCommand =
bundle.getInt( bundle.getInt(FIELD_PLAYER_COMMAND, /* defaultValue= */ Player.COMMAND_INVALID);
keyForField(FIELD_PLAYER_COMMAND), /* defaultValue= */ Player.COMMAND_INVALID); int iconResId = bundle.getInt(FIELD_ICON_RES_ID, /* defaultValue= */ 0);
int iconResId = bundle.getInt(keyForField(FIELD_ICON_RES_ID), /* defaultValue= */ 0); CharSequence displayName = bundle.getCharSequence(FIELD_DISPLAY_NAME, /* defaultValue= */ "");
CharSequence displayName = @Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
bundle.getCharSequence(keyForField(FIELD_DISPLAY_NAME), /* defaultValue= */ ""); boolean enabled = bundle.getBoolean(FIELD_ENABLED, /* defaultValue= */ false);
@Nullable Bundle extras = bundle.getBundle(keyForField(FIELD_EXTRAS));
boolean enabled = bundle.getBoolean(keyForField(FIELD_ENABLED), /* defaultValue= */ false);
Builder builder = new Builder(); Builder builder = new Builder();
if (sessionCommand != null) { if (sessionCommand != null) {
builder.setSessionCommand(sessionCommand); builder.setSessionCommand(sessionCommand);
...@@ -269,8 +249,4 @@ public final class CommandButton implements Bundleable { ...@@ -269,8 +249,4 @@ public final class CommandButton implements Bundleable {
.setEnabled(enabled) .setEnabled(enabled)
.build(); .build();
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -17,17 +17,12 @@ package androidx.media3.session; ...@@ -17,17 +17,12 @@ package androidx.media3.session;
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 java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.MediaLibraryInfo; import androidx.media3.common.MediaLibraryInfo;
import java.lang.annotation.Documented; import androidx.media3.common.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Created by {@link MediaController} to send its state to the {@link MediaSession} to request to * Created by {@link MediaController} to send its state to the {@link MediaSession} to request to
...@@ -69,47 +64,34 @@ import java.lang.annotation.Target; ...@@ -69,47 +64,34 @@ import java.lang.annotation.Target;
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_LIBRARY_VERSION = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_PACKAGE_NAME = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_PID = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_CONNECTION_HINTS = Util.intToStringMaxRadix(3);
FIELD_LIBRARY_VERSION, private static final String FIELD_CONTROLLER_INTERFACE_VERSION = Util.intToStringMaxRadix(4);
FIELD_PACKAGE_NAME,
FIELD_PID,
FIELD_CONNECTION_HINTS,
FIELD_CONTROLLER_INTERFACE_VERSION
})
private @interface FieldNumber {}
private static final int FIELD_LIBRARY_VERSION = 0;
private static final int FIELD_PACKAGE_NAME = 1;
private static final int FIELD_PID = 2;
private static final int FIELD_CONNECTION_HINTS = 3;
private static final int FIELD_CONTROLLER_INTERFACE_VERSION = 4;
// Next id: 5 // Next id: 5
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_LIBRARY_VERSION), libraryVersion); bundle.putInt(FIELD_LIBRARY_VERSION, libraryVersion);
bundle.putString(keyForField(FIELD_PACKAGE_NAME), packageName); bundle.putString(FIELD_PACKAGE_NAME, packageName);
bundle.putInt(keyForField(FIELD_PID), pid); bundle.putInt(FIELD_PID, pid);
bundle.putBundle(keyForField(FIELD_CONNECTION_HINTS), connectionHints); bundle.putBundle(FIELD_CONNECTION_HINTS, connectionHints);
bundle.putInt(keyForField(FIELD_CONTROLLER_INTERFACE_VERSION), controllerInterfaceVersion); bundle.putInt(FIELD_CONTROLLER_INTERFACE_VERSION, controllerInterfaceVersion);
return bundle; return bundle;
} }
/** Object that can restore {@link ConnectionRequest} from a {@link Bundle}. */ /** Object that can restore {@link ConnectionRequest} from a {@link Bundle}. */
public static final Creator<ConnectionRequest> CREATOR = public static final Creator<ConnectionRequest> CREATOR =
bundle -> { bundle -> {
int libraryVersion = int libraryVersion = bundle.getInt(FIELD_LIBRARY_VERSION, /* defaultValue= */ 0);
bundle.getInt(keyForField(FIELD_LIBRARY_VERSION), /* defaultValue= */ 0);
int controllerInterfaceVersion = int controllerInterfaceVersion =
bundle.getInt(keyForField(FIELD_CONTROLLER_INTERFACE_VERSION), /* defaultValue= */ 0); bundle.getInt(FIELD_CONTROLLER_INTERFACE_VERSION, /* defaultValue= */ 0);
String packageName = checkNotNull(bundle.getString(keyForField(FIELD_PACKAGE_NAME))); String packageName = checkNotNull(bundle.getString(FIELD_PACKAGE_NAME));
int pid = bundle.getInt(keyForField(FIELD_PID), /* defaultValue= */ 0); int pid = bundle.getInt(FIELD_PID, /* defaultValue= */ 0);
checkArgument(pid != 0); checkArgument(pid != 0);
@Nullable Bundle connectionHints = bundle.getBundle(keyForField(FIELD_CONNECTION_HINTS)); @Nullable Bundle connectionHints = bundle.getBundle(FIELD_CONNECTION_HINTS);
return new ConnectionRequest( return new ConnectionRequest(
libraryVersion, libraryVersion,
controllerInterfaceVersion, controllerInterfaceVersion,
...@@ -117,8 +99,4 @@ import java.lang.annotation.Target; ...@@ -117,8 +99,4 @@ import java.lang.annotation.Target;
pid, pid,
connectionHints == null ? Bundle.EMPTY : connectionHints); connectionHints == null ? Bundle.EMPTY : connectionHints);
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,20 +16,15 @@ ...@@ -16,20 +16,15 @@
package androidx.media3.session; package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; 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 java.lang.annotation.Documented; import androidx.media3.common.util.Util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Created by {@link MediaSession} to send its state to the {@link MediaController} when the * Created by {@link MediaSession} to send its state to the {@link MediaController} when the
...@@ -78,47 +73,29 @@ import java.lang.annotation.Target; ...@@ -78,47 +73,29 @@ import java.lang.annotation.Target;
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_LIBRARY_VERSION = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_SESSION_BINDER = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_SESSION_ACTIVITY = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_SESSION_COMMANDS = Util.intToStringMaxRadix(3);
FIELD_LIBRARY_VERSION, private static final String FIELD_PLAYER_COMMANDS_FROM_SESSION = Util.intToStringMaxRadix(4);
FIELD_SESSION_BINDER, private static final String FIELD_PLAYER_COMMANDS_FROM_PLAYER = Util.intToStringMaxRadix(5);
FIELD_SESSION_ACTIVITY, private static final String FIELD_TOKEN_EXTRAS = Util.intToStringMaxRadix(6);
FIELD_SESSION_COMMANDS, private static final String FIELD_PLAYER_INFO = Util.intToStringMaxRadix(7);
FIELD_PLAYER_COMMANDS_FROM_SESSION, private static final String FIELD_SESSION_INTERFACE_VERSION = Util.intToStringMaxRadix(8);
FIELD_PLAYER_COMMANDS_FROM_PLAYER,
FIELD_TOKEN_EXTRAS,
FIELD_PLAYER_INFO,
FIELD_SESSION_INTERFACE_VERSION,
})
private @interface FieldNumber {}
private static final int FIELD_LIBRARY_VERSION = 0;
private static final int FIELD_SESSION_BINDER = 1;
private static final int FIELD_SESSION_ACTIVITY = 2;
private static final int FIELD_SESSION_COMMANDS = 3;
private static final int FIELD_PLAYER_COMMANDS_FROM_SESSION = 4;
private static final int FIELD_PLAYER_COMMANDS_FROM_PLAYER = 5;
private static final int FIELD_TOKEN_EXTRAS = 6;
private static final int FIELD_PLAYER_INFO = 7;
private static final int FIELD_SESSION_INTERFACE_VERSION = 8;
// Next field key = 9 // Next field key = 9
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_LIBRARY_VERSION), libraryVersion); bundle.putInt(FIELD_LIBRARY_VERSION, libraryVersion);
BundleCompat.putBinder(bundle, keyForField(FIELD_SESSION_BINDER), sessionBinder.asBinder()); BundleCompat.putBinder(bundle, FIELD_SESSION_BINDER, sessionBinder.asBinder());
bundle.putParcelable(keyForField(FIELD_SESSION_ACTIVITY), sessionActivity); bundle.putParcelable(FIELD_SESSION_ACTIVITY, sessionActivity);
bundle.putBundle(keyForField(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_PLAYER, playerCommandsFromPlayer.toBundle());
bundle.putBundle(FIELD_TOKEN_EXTRAS, tokenExtras);
bundle.putBundle( bundle.putBundle(
keyForField(FIELD_PLAYER_COMMANDS_FROM_SESSION), playerCommandsFromSession.toBundle()); FIELD_PLAYER_INFO,
bundle.putBundle(
keyForField(FIELD_PLAYER_COMMANDS_FROM_PLAYER), playerCommandsFromPlayer.toBundle());
bundle.putBundle(keyForField(FIELD_TOKEN_EXTRAS), tokenExtras);
bundle.putBundle(
keyForField(FIELD_PLAYER_INFO),
playerInfo.toBundle( playerInfo.toBundle(
/* excludeMediaItems= */ !playerCommandsFromPlayer.contains(Player.COMMAND_GET_TIMELINE) /* excludeMediaItems= */ !playerCommandsFromPlayer.contains(Player.COMMAND_GET_TIMELINE)
|| !playerCommandsFromSession.contains(Player.COMMAND_GET_TIMELINE), || !playerCommandsFromSession.contains(Player.COMMAND_GET_TIMELINE),
...@@ -130,7 +107,7 @@ import java.lang.annotation.Target; ...@@ -130,7 +107,7 @@ import java.lang.annotation.Target;
/* excludeTimeline= */ false, /* excludeTimeline= */ false,
/* excludeTracks= */ !playerCommandsFromPlayer.contains(Player.COMMAND_GET_TRACKS) /* excludeTracks= */ !playerCommandsFromPlayer.contains(Player.COMMAND_GET_TRACKS)
|| !playerCommandsFromSession.contains(Player.COMMAND_GET_TRACKS))); || !playerCommandsFromSession.contains(Player.COMMAND_GET_TRACKS)));
bundle.putInt(keyForField(FIELD_SESSION_INTERFACE_VERSION), sessionInterfaceVersion); bundle.putInt(FIELD_SESSION_INTERFACE_VERSION, sessionInterfaceVersion);
return bundle; return bundle;
} }
...@@ -138,34 +115,30 @@ import java.lang.annotation.Target; ...@@ -138,34 +115,30 @@ import java.lang.annotation.Target;
public static final Creator<ConnectionState> CREATOR = ConnectionState::fromBundle; public static final Creator<ConnectionState> CREATOR = ConnectionState::fromBundle;
private static ConnectionState fromBundle(Bundle bundle) { private static ConnectionState fromBundle(Bundle bundle) {
int libraryVersion = bundle.getInt(keyForField(FIELD_LIBRARY_VERSION), /* defaultValue= */ 0); int libraryVersion = bundle.getInt(FIELD_LIBRARY_VERSION, /* defaultValue= */ 0);
int sessionInterfaceVersion = int sessionInterfaceVersion =
bundle.getInt(keyForField(FIELD_SESSION_INTERFACE_VERSION), /* defaultValue= */ 0); bundle.getInt(FIELD_SESSION_INTERFACE_VERSION, /* defaultValue= */ 0);
IBinder sessionBinder = IBinder sessionBinder = checkNotNull(BundleCompat.getBinder(bundle, FIELD_SESSION_BINDER));
checkNotNull(BundleCompat.getBinder(bundle, keyForField(FIELD_SESSION_BINDER))); @Nullable PendingIntent sessionActivity = bundle.getParcelable(FIELD_SESSION_ACTIVITY);
@Nullable @Nullable Bundle sessionCommandsBundle = bundle.getBundle(FIELD_SESSION_COMMANDS);
PendingIntent sessionActivity = bundle.getParcelable(keyForField(FIELD_SESSION_ACTIVITY));
@Nullable Bundle sessionCommandsBundle = bundle.getBundle(keyForField(FIELD_SESSION_COMMANDS));
SessionCommands sessionCommands = SessionCommands sessionCommands =
sessionCommandsBundle == null sessionCommandsBundle == null
? SessionCommands.EMPTY ? SessionCommands.EMPTY
: SessionCommands.CREATOR.fromBundle(sessionCommandsBundle); : SessionCommands.CREATOR.fromBundle(sessionCommandsBundle);
@Nullable @Nullable
Bundle playerCommandsFromPlayerBundle = Bundle playerCommandsFromPlayerBundle = bundle.getBundle(FIELD_PLAYER_COMMANDS_FROM_PLAYER);
bundle.getBundle(keyForField(FIELD_PLAYER_COMMANDS_FROM_PLAYER));
Player.Commands playerCommandsFromPlayer = Player.Commands playerCommandsFromPlayer =
playerCommandsFromPlayerBundle == null playerCommandsFromPlayerBundle == null
? Player.Commands.EMPTY ? Player.Commands.EMPTY
: Player.Commands.CREATOR.fromBundle(playerCommandsFromPlayerBundle); : Player.Commands.CREATOR.fromBundle(playerCommandsFromPlayerBundle);
@Nullable @Nullable
Bundle playerCommandsFromSessionBundle = Bundle playerCommandsFromSessionBundle = bundle.getBundle(FIELD_PLAYER_COMMANDS_FROM_SESSION);
bundle.getBundle(keyForField(FIELD_PLAYER_COMMANDS_FROM_SESSION));
Player.Commands playerCommandsFromSession = Player.Commands playerCommandsFromSession =
playerCommandsFromSessionBundle == null playerCommandsFromSessionBundle == null
? Player.Commands.EMPTY ? Player.Commands.EMPTY
: Player.Commands.CREATOR.fromBundle(playerCommandsFromSessionBundle); : Player.Commands.CREATOR.fromBundle(playerCommandsFromSessionBundle);
@Nullable Bundle tokenExtras = bundle.getBundle(keyForField(FIELD_TOKEN_EXTRAS)); @Nullable Bundle tokenExtras = bundle.getBundle(FIELD_TOKEN_EXTRAS);
@Nullable Bundle playerInfoBundle = bundle.getBundle(keyForField(FIELD_PLAYER_INFO)); @Nullable Bundle playerInfoBundle = bundle.getBundle(FIELD_PLAYER_INFO);
PlayerInfo playerInfo = PlayerInfo playerInfo =
playerInfoBundle == null playerInfoBundle == null
? PlayerInfo.DEFAULT ? PlayerInfo.DEFAULT
...@@ -181,8 +154,4 @@ import java.lang.annotation.Target; ...@@ -181,8 +154,4 @@ import java.lang.annotation.Target;
tokenExtras == null ? Bundle.EMPTY : tokenExtras, tokenExtras == null ? Bundle.EMPTY : tokenExtras,
playerInfo); playerInfo);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -34,6 +34,7 @@ import androidx.media3.common.MediaItem; ...@@ -34,6 +34,7 @@ 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.BundleableUtil;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.session.MediaLibraryService.LibraryParams; import androidx.media3.session.MediaLibraryService.LibraryParams;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
...@@ -262,23 +263,11 @@ public final class LibraryResult<V> implements Bundleable { ...@@ -262,23 +263,11 @@ public final class LibraryResult<V> implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_RESULT_CODE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_COMPLETION_TIME_MS = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_PARAMS = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_VALUE = Util.intToStringMaxRadix(3);
FIELD_RESULT_CODE, private static final String FIELD_VALUE_TYPE = Util.intToStringMaxRadix(4);
FIELD_COMPLETION_TIME_MS,
FIELD_PARAMS,
FIELD_VALUE,
FIELD_VALUE_TYPE
})
private @interface FieldNumber {}
private static final int FIELD_RESULT_CODE = 0;
private static final int FIELD_COMPLETION_TIME_MS = 1;
private static final int FIELD_PARAMS = 2;
private static final int FIELD_VALUE = 3;
private static final int FIELD_VALUE_TYPE = 4;
// Casting V to ImmutableList<MediaItem> is safe if valueType == VALUE_TYPE_ITEM_LIST. // Casting V to ImmutableList<MediaItem> is safe if valueType == VALUE_TYPE_ITEM_LIST.
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -286,24 +275,24 @@ public final class LibraryResult<V> implements Bundleable { ...@@ -286,24 +275,24 @@ public final class LibraryResult<V> implements Bundleable {
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RESULT_CODE), resultCode); bundle.putInt(FIELD_RESULT_CODE, resultCode);
bundle.putLong(keyForField(FIELD_COMPLETION_TIME_MS), completionTimeMs); bundle.putLong(FIELD_COMPLETION_TIME_MS, completionTimeMs);
if (params != null) { if (params != null) {
bundle.putBundle(keyForField(FIELD_PARAMS), params.toBundle()); bundle.putBundle(FIELD_PARAMS, params.toBundle());
} }
bundle.putInt(keyForField(FIELD_VALUE_TYPE), valueType); bundle.putInt(FIELD_VALUE_TYPE, valueType);
if (value == null) { if (value == null) {
return bundle; return bundle;
} }
switch (valueType) { switch (valueType) {
case VALUE_TYPE_ITEM: case VALUE_TYPE_ITEM:
bundle.putBundle(keyForField(FIELD_VALUE), ((MediaItem) value).toBundle()); bundle.putBundle(FIELD_VALUE, ((MediaItem) value).toBundle());
break; break;
case VALUE_TYPE_ITEM_LIST: case VALUE_TYPE_ITEM_LIST:
BundleCompat.putBinder( BundleCompat.putBinder(
bundle, bundle,
keyForField(FIELD_VALUE), FIELD_VALUE,
new BundleListRetriever(BundleableUtil.toBundleList((ImmutableList<MediaItem>) value))); new BundleListRetriever(BundleableUtil.toBundleList((ImmutableList<MediaItem>) value)));
break; break;
case VALUE_TYPE_VOID: case VALUE_TYPE_VOID:
...@@ -367,27 +356,24 @@ public final class LibraryResult<V> implements Bundleable { ...@@ -367,27 +356,24 @@ public final class LibraryResult<V> implements Bundleable {
*/ */
private static LibraryResult<?> fromBundle( private static LibraryResult<?> fromBundle(
Bundle bundle, @Nullable @ValueType Integer expectedType) { Bundle bundle, @Nullable @ValueType Integer expectedType) {
int resultCode = int resultCode = bundle.getInt(FIELD_RESULT_CODE, /* defaultValue= */ RESULT_SUCCESS);
bundle.getInt(keyForField(FIELD_RESULT_CODE), /* defaultValue= */ RESULT_SUCCESS);
long completionTimeMs = long completionTimeMs =
bundle.getLong( bundle.getLong(FIELD_COMPLETION_TIME_MS, /* defaultValue= */ SystemClock.elapsedRealtime());
keyForField(FIELD_COMPLETION_TIME_MS), @Nullable Bundle paramsBundle = bundle.getBundle(FIELD_PARAMS);
/* defaultValue= */ SystemClock.elapsedRealtime());
@Nullable Bundle paramsBundle = bundle.getBundle(keyForField(FIELD_PARAMS));
@Nullable @Nullable
MediaLibraryService.LibraryParams params = MediaLibraryService.LibraryParams params =
paramsBundle == null ? null : LibraryParams.CREATOR.fromBundle(paramsBundle); paramsBundle == null ? null : LibraryParams.CREATOR.fromBundle(paramsBundle);
@ValueType int valueType = bundle.getInt(keyForField(FIELD_VALUE_TYPE)); @ValueType int valueType = bundle.getInt(FIELD_VALUE_TYPE);
@Nullable Object value; @Nullable Object value;
switch (valueType) { switch (valueType) {
case VALUE_TYPE_ITEM: case VALUE_TYPE_ITEM:
checkState(expectedType == null || expectedType == VALUE_TYPE_ITEM); checkState(expectedType == null || expectedType == VALUE_TYPE_ITEM);
@Nullable Bundle valueBundle = bundle.getBundle(keyForField(FIELD_VALUE)); @Nullable Bundle valueBundle = bundle.getBundle(FIELD_VALUE);
value = valueBundle == null ? null : MediaItem.CREATOR.fromBundle(valueBundle); value = valueBundle == null ? null : MediaItem.CREATOR.fromBundle(valueBundle);
break; break;
case VALUE_TYPE_ITEM_LIST: case VALUE_TYPE_ITEM_LIST:
checkState(expectedType == null || expectedType == VALUE_TYPE_ITEM_LIST); checkState(expectedType == null || expectedType == VALUE_TYPE_ITEM_LIST);
@Nullable IBinder valueRetriever = BundleCompat.getBinder(bundle, keyForField(FIELD_VALUE)); @Nullable IBinder valueRetriever = BundleCompat.getBinder(bundle, FIELD_VALUE);
value = value =
valueRetriever == null valueRetriever == null
? null ? null
...@@ -405,10 +391,6 @@ public final class LibraryResult<V> implements Bundleable { ...@@ -405,10 +391,6 @@ public final class LibraryResult<V> implements Bundleable {
return new LibraryResult<>(resultCode, completionTimeMs, params, value, VALUE_TYPE_ITEM_LIST); return new LibraryResult<>(resultCode, completionTimeMs, params, value, VALUE_TYPE_ITEM_LIST);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE) @Target(TYPE_USE)
......
...@@ -19,7 +19,6 @@ import static androidx.media3.common.util.Assertions.checkArgument; ...@@ -19,7 +19,6 @@ import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotEmpty; import static androidx.media3.common.util.Assertions.checkNotEmpty;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.session.LibraryResult.RESULT_ERROR_NOT_SUPPORTED; import static androidx.media3.session.LibraryResult.RESULT_ERROR_NOT_SUPPORTED;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
...@@ -27,7 +26,6 @@ import android.content.Intent; ...@@ -27,7 +26,6 @@ import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media.MediaSessionManager.RemoteUserInfo; import androidx.media.MediaSessionManager.RemoteUserInfo;
...@@ -36,15 +34,12 @@ import androidx.media3.common.MediaItem; ...@@ -36,15 +34,12 @@ import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata; import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player; import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.session.MediaSession.ControllerInfo; import androidx.media3.session.MediaSession.ControllerInfo;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Superclass to be extended by services hosting {@link MediaLibrarySession media library sessions}. * Superclass to be extended by services hosting {@link MediaLibrarySession media library sessions}.
...@@ -666,30 +661,19 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -666,30 +661,19 @@ public abstract class MediaLibraryService extends MediaSessionService {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_RECENT = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_OFFLINE = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_SUGGESTED = Util.intToStringMaxRadix(3);
FIELD_EXTRAS,
FIELD_RECENT,
FIELD_OFFLINE,
FIELD_SUGGESTED,
})
private @interface FieldNumber {}
private static final int FIELD_EXTRAS = 0;
private static final int FIELD_RECENT = 1;
private static final int FIELD_OFFLINE = 2;
private static final int FIELD_SUGGESTED = 3;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putBundle(keyForField(FIELD_EXTRAS), extras); bundle.putBundle(FIELD_EXTRAS, extras);
bundle.putBoolean(keyForField(FIELD_RECENT), isRecent); bundle.putBoolean(FIELD_RECENT, isRecent);
bundle.putBoolean(keyForField(FIELD_OFFLINE), isOffline); bundle.putBoolean(FIELD_OFFLINE, isOffline);
bundle.putBoolean(keyForField(FIELD_SUGGESTED), isSuggested); bundle.putBoolean(FIELD_SUGGESTED, isSuggested);
return bundle; return bundle;
} }
...@@ -697,17 +681,12 @@ public abstract class MediaLibraryService extends MediaSessionService { ...@@ -697,17 +681,12 @@ public abstract class MediaLibraryService extends MediaSessionService {
@UnstableApi public static final Creator<LibraryParams> CREATOR = LibraryParams::fromBundle; @UnstableApi public static final Creator<LibraryParams> CREATOR = LibraryParams::fromBundle;
private static LibraryParams fromBundle(Bundle bundle) { private static LibraryParams fromBundle(Bundle bundle) {
@Nullable Bundle extras = bundle.getBundle(keyForField(FIELD_EXTRAS)); @Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
boolean recent = bundle.getBoolean(keyForField(FIELD_RECENT), /* defaultValue= */ false); boolean recent = bundle.getBoolean(FIELD_RECENT, /* defaultValue= */ false);
boolean offline = bundle.getBoolean(keyForField(FIELD_OFFLINE), /* defaultValue= */ false); boolean offline = bundle.getBoolean(FIELD_OFFLINE, /* defaultValue= */ false);
boolean suggested = boolean suggested = bundle.getBoolean(FIELD_SUGGESTED, /* defaultValue= */ false);
bundle.getBoolean(keyForField(FIELD_SUGGESTED), /* defaultValue= */ false);
return new LibraryParams(extras == null ? Bundle.EMPTY : extras, recent, offline, suggested); return new LibraryParams(extras == null ? Bundle.EMPTY : extras, recent, offline, suggested);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
@Override @Override
......
...@@ -26,6 +26,7 @@ import androidx.annotation.Nullable; ...@@ -26,6 +26,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.Rating; import androidx.media3.common.Rating;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.session.MediaLibraryService.LibraryParams; import androidx.media3.session.MediaLibraryService.LibraryParams;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
...@@ -165,24 +166,17 @@ public final class SessionCommand implements Bundleable { ...@@ -165,24 +166,17 @@ public final class SessionCommand implements Bundleable {
} }
// Bundleable implementation. // Bundleable implementation.
private static final String FIELD_COMMAND_CODE = Util.intToStringMaxRadix(0);
@Documented private static final String FIELD_CUSTOM_ACTION = Util.intToStringMaxRadix(1);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_CUSTOM_EXTRAS = Util.intToStringMaxRadix(2);
@Target(TYPE_USE)
@IntDef({FIELD_COMMAND_CODE, FIELD_CUSTOM_ACTION, FIELD_CUSTOM_EXTRAS})
private @interface FieldNumber {}
private static final int FIELD_COMMAND_CODE = 0;
private static final int FIELD_CUSTOM_ACTION = 1;
private static final int FIELD_CUSTOM_EXTRAS = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_COMMAND_CODE), commandCode); bundle.putInt(FIELD_COMMAND_CODE, commandCode);
bundle.putString(keyForField(FIELD_CUSTOM_ACTION), customAction); bundle.putString(FIELD_CUSTOM_ACTION, customAction);
bundle.putBundle(keyForField(FIELD_CUSTOM_EXTRAS), customExtras); bundle.putBundle(FIELD_CUSTOM_EXTRAS, customExtras);
return bundle; return bundle;
} }
...@@ -191,18 +185,14 @@ public final class SessionCommand implements Bundleable { ...@@ -191,18 +185,14 @@ public final class SessionCommand implements Bundleable {
public static final Creator<SessionCommand> CREATOR = public static final Creator<SessionCommand> CREATOR =
bundle -> { bundle -> {
int commandCode = int commandCode =
bundle.getInt(keyForField(FIELD_COMMAND_CODE), /* defaultValue= */ COMMAND_CODE_CUSTOM); bundle.getInt(FIELD_COMMAND_CODE, /* defaultValue= */ COMMAND_CODE_CUSTOM);
if (commandCode != COMMAND_CODE_CUSTOM) { if (commandCode != COMMAND_CODE_CUSTOM) {
return new SessionCommand(commandCode); return new SessionCommand(commandCode);
} else { } else {
String customAction = checkNotNull(bundle.getString(keyForField(FIELD_CUSTOM_ACTION))); String customAction = checkNotNull(bundle.getString(FIELD_CUSTOM_ACTION));
@Nullable Bundle customExtras = bundle.getBundle(keyForField(FIELD_CUSTOM_EXTRAS)); @Nullable Bundle customExtras = bundle.getBundle(FIELD_CUSTOM_EXTRAS);
return new SessionCommand( return new SessionCommand(
customAction, customExtras == null ? Bundle.EMPTY : customExtras); customAction, customExtras == null ? Bundle.EMPTY : customExtras);
} }
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -18,22 +18,17 @@ package androidx.media3.session; ...@@ -18,22 +18,17 @@ package androidx.media3.session;
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.session.SessionCommand.COMMAND_CODE_CUSTOM; import static androidx.media3.session.SessionCommand.COMMAND_CODE_CUSTOM;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.util.ObjectsCompat; import androidx.core.util.ObjectsCompat;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
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.session.SessionCommand.CommandCode; import androidx.media3.session.SessionCommand.CommandCode;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
...@@ -235,13 +230,7 @@ public final class SessionCommands implements Bundleable { ...@@ -235,13 +230,7 @@ public final class SessionCommands implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_SESSION_COMMANDS = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({FIELD_SESSION_COMMANDS})
private @interface FieldNumber {}
private static final int FIELD_SESSION_COMMANDS = 0;
@UnstableApi @UnstableApi
@Override @Override
...@@ -251,7 +240,7 @@ public final class SessionCommands implements Bundleable { ...@@ -251,7 +240,7 @@ public final class SessionCommands implements Bundleable {
for (SessionCommand command : commands) { for (SessionCommand command : commands) {
sessionCommandBundleList.add(command.toBundle()); sessionCommandBundleList.add(command.toBundle());
} }
bundle.putParcelableArrayList(keyForField(FIELD_SESSION_COMMANDS), sessionCommandBundleList); bundle.putParcelableArrayList(FIELD_SESSION_COMMANDS, sessionCommandBundleList);
return bundle; return bundle;
} }
...@@ -261,7 +250,7 @@ public final class SessionCommands implements Bundleable { ...@@ -261,7 +250,7 @@ public final class SessionCommands implements Bundleable {
bundle -> { bundle -> {
@Nullable @Nullable
ArrayList<Bundle> sessionCommandBundleList = ArrayList<Bundle> sessionCommandBundleList =
bundle.getParcelableArrayList(keyForField(FIELD_SESSION_COMMANDS)); bundle.getParcelableArrayList(FIELD_SESSION_COMMANDS);
if (sessionCommandBundleList == null) { if (sessionCommandBundleList == null) {
Log.w(TAG, "Missing commands. Creating an empty SessionCommands"); Log.w(TAG, "Missing commands. Creating an empty SessionCommands");
return SessionCommands.EMPTY; return SessionCommands.EMPTY;
...@@ -273,8 +262,4 @@ public final class SessionCommands implements Bundleable { ...@@ -273,8 +262,4 @@ public final class SessionCommands implements Bundleable {
} }
return builder.build(); return builder.build();
}; };
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -16,19 +16,14 @@ ...@@ -16,19 +16,14 @@
package androidx.media3.session; package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; 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.Player.PositionInfo; import androidx.media3.common.Player.PositionInfo;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Position information to be shared between session and controller. * Position information to be shared between session and controller.
...@@ -162,47 +157,30 @@ import java.lang.annotation.Target; ...@@ -162,47 +157,30 @@ import java.lang.annotation.Target;
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_POSITION_INFO = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_IS_PLAYING_AD = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_EVENT_TIME_MS = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_DURATION_MS = Util.intToStringMaxRadix(3);
FIELD_POSITION_INFO, private static final String FIELD_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(4);
FIELD_IS_PLAYING_AD, private static final String FIELD_BUFFERED_PERCENTAGE = Util.intToStringMaxRadix(5);
FIELD_EVENT_TIME_MS, private static final String FIELD_TOTAL_BUFFERED_DURATION_MS = Util.intToStringMaxRadix(6);
FIELD_DURATION_MS, private static final String FIELD_CURRENT_LIVE_OFFSET_MS = Util.intToStringMaxRadix(7);
FIELD_BUFFERED_POSITION_MS, private static final String FIELD_CONTENT_DURATION_MS = Util.intToStringMaxRadix(8);
FIELD_BUFFERED_PERCENTAGE, private static final String FIELD_CONTENT_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(9);
FIELD_TOTAL_BUFFERED_DURATION_MS,
FIELD_CURRENT_LIVE_OFFSET_MS,
FIELD_CONTENT_DURATION_MS,
FIELD_CONTENT_BUFFERED_POSITION_MS
})
private @interface FieldNumber {}
private static final int FIELD_POSITION_INFO = 0;
private static final int FIELD_IS_PLAYING_AD = 1;
private static final int FIELD_EVENT_TIME_MS = 2;
private static final int FIELD_DURATION_MS = 3;
private static final int FIELD_BUFFERED_POSITION_MS = 4;
private static final int FIELD_BUFFERED_PERCENTAGE = 5;
private static final int FIELD_TOTAL_BUFFERED_DURATION_MS = 6;
private static final int FIELD_CURRENT_LIVE_OFFSET_MS = 7;
private static final int FIELD_CONTENT_DURATION_MS = 8;
private static final int FIELD_CONTENT_BUFFERED_POSITION_MS = 9;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putBundle(keyForField(FIELD_POSITION_INFO), positionInfo.toBundle()); bundle.putBundle(FIELD_POSITION_INFO, positionInfo.toBundle());
bundle.putBoolean(keyForField(FIELD_IS_PLAYING_AD), isPlayingAd); bundle.putBoolean(FIELD_IS_PLAYING_AD, isPlayingAd);
bundle.putLong(keyForField(FIELD_EVENT_TIME_MS), eventTimeMs); bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs);
bundle.putLong(keyForField(FIELD_DURATION_MS), durationMs); bundle.putLong(FIELD_DURATION_MS, durationMs);
bundle.putLong(keyForField(FIELD_BUFFERED_POSITION_MS), bufferedPositionMs); bundle.putLong(FIELD_BUFFERED_POSITION_MS, bufferedPositionMs);
bundle.putInt(keyForField(FIELD_BUFFERED_PERCENTAGE), bufferedPercentage); bundle.putInt(FIELD_BUFFERED_PERCENTAGE, bufferedPercentage);
bundle.putLong(keyForField(FIELD_TOTAL_BUFFERED_DURATION_MS), totalBufferedDurationMs); bundle.putLong(FIELD_TOTAL_BUFFERED_DURATION_MS, totalBufferedDurationMs);
bundle.putLong(keyForField(FIELD_CURRENT_LIVE_OFFSET_MS), currentLiveOffsetMs); bundle.putLong(FIELD_CURRENT_LIVE_OFFSET_MS, currentLiveOffsetMs);
bundle.putLong(keyForField(FIELD_CONTENT_DURATION_MS), contentDurationMs); bundle.putLong(FIELD_CONTENT_DURATION_MS, contentDurationMs);
bundle.putLong(keyForField(FIELD_CONTENT_BUFFERED_POSITION_MS), contentBufferedPositionMs); bundle.putLong(FIELD_CONTENT_BUFFERED_POSITION_MS, contentBufferedPositionMs);
return bundle; return bundle;
} }
...@@ -210,30 +188,25 @@ import java.lang.annotation.Target; ...@@ -210,30 +188,25 @@ import java.lang.annotation.Target;
public static final Creator<SessionPositionInfo> CREATOR = SessionPositionInfo::fromBundle; public static final Creator<SessionPositionInfo> CREATOR = SessionPositionInfo::fromBundle;
private static SessionPositionInfo fromBundle(Bundle bundle) { private static SessionPositionInfo fromBundle(Bundle bundle) {
@Nullable Bundle positionInfoBundle = bundle.getBundle(keyForField(FIELD_POSITION_INFO)); @Nullable Bundle positionInfoBundle = bundle.getBundle(FIELD_POSITION_INFO);
PositionInfo positionInfo = PositionInfo positionInfo =
positionInfoBundle == null positionInfoBundle == null
? DEFAULT_POSITION_INFO ? DEFAULT_POSITION_INFO
: PositionInfo.CREATOR.fromBundle(positionInfoBundle); : PositionInfo.CREATOR.fromBundle(positionInfoBundle);
boolean isPlayingAd = boolean isPlayingAd = bundle.getBoolean(FIELD_IS_PLAYING_AD, /* defaultValue= */ false);
bundle.getBoolean(keyForField(FIELD_IS_PLAYING_AD), /* defaultValue= */ false); long eventTimeMs = bundle.getLong(FIELD_EVENT_TIME_MS, /* defaultValue= */ C.TIME_UNSET);
long eventTimeMs = long durationMs = bundle.getLong(FIELD_DURATION_MS, /* defaultValue= */ C.TIME_UNSET);
bundle.getLong(keyForField(FIELD_EVENT_TIME_MS), /* defaultValue= */ C.TIME_UNSET);
long durationMs =
bundle.getLong(keyForField(FIELD_DURATION_MS), /* defaultValue= */ C.TIME_UNSET);
long bufferedPositionMs = long bufferedPositionMs =
bundle.getLong(keyForField(FIELD_BUFFERED_POSITION_MS), /* defaultValue= */ C.TIME_UNSET); bundle.getLong(FIELD_BUFFERED_POSITION_MS, /* defaultValue= */ C.TIME_UNSET);
int bufferedPercentage = int bufferedPercentage = bundle.getInt(FIELD_BUFFERED_PERCENTAGE, /* defaultValue= */ 0);
bundle.getInt(keyForField(FIELD_BUFFERED_PERCENTAGE), /* defaultValue= */ 0);
long totalBufferedDurationMs = long totalBufferedDurationMs =
bundle.getLong(keyForField(FIELD_TOTAL_BUFFERED_DURATION_MS), /* defaultValue= */ 0); bundle.getLong(FIELD_TOTAL_BUFFERED_DURATION_MS, /* defaultValue= */ 0);
long currentLiveOffsetMs = long currentLiveOffsetMs =
bundle.getLong(keyForField(FIELD_CURRENT_LIVE_OFFSET_MS), /* defaultValue= */ C.TIME_UNSET); bundle.getLong(FIELD_CURRENT_LIVE_OFFSET_MS, /* defaultValue= */ C.TIME_UNSET);
long contentDurationMs = long contentDurationMs =
bundle.getLong(keyForField(FIELD_CONTENT_DURATION_MS), /* defaultValue= */ C.TIME_UNSET); bundle.getLong(FIELD_CONTENT_DURATION_MS, /* defaultValue= */ C.TIME_UNSET);
long contentBufferedPositionMs = long contentBufferedPositionMs =
bundle.getLong( bundle.getLong(FIELD_CONTENT_BUFFERED_POSITION_MS, /* defaultValue= */ C.TIME_UNSET);
keyForField(FIELD_CONTENT_BUFFERED_POSITION_MS), /* defaultValue= */ C.TIME_UNSET);
return new SessionPositionInfo( return new SessionPositionInfo(
positionInfo, positionInfo,
...@@ -247,8 +220,4 @@ import java.lang.annotation.Target; ...@@ -247,8 +220,4 @@ import java.lang.annotation.Target;
contentDurationMs, contentDurationMs,
contentBufferedPositionMs); contentBufferedPositionMs);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -25,6 +25,7 @@ import androidx.annotation.IntDef; ...@@ -25,6 +25,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -175,23 +176,17 @@ public final class SessionResult implements Bundleable { ...@@ -175,23 +176,17 @@ public final class SessionResult implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_RESULT_CODE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_COMPLETION_TIME_MS = Util.intToStringMaxRadix(2);
@IntDef({FIELD_RESULT_CODE, FIELD_EXTRAS, FIELD_COMPLETION_TIME_MS})
private @interface FieldNumber {}
private static final int FIELD_RESULT_CODE = 0;
private static final int FIELD_EXTRAS = 1;
private static final int FIELD_COMPLETION_TIME_MS = 2;
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_RESULT_CODE), resultCode); bundle.putInt(FIELD_RESULT_CODE, resultCode);
bundle.putBundle(keyForField(FIELD_EXTRAS), extras); bundle.putBundle(FIELD_EXTRAS, extras);
bundle.putLong(keyForField(FIELD_COMPLETION_TIME_MS), completionTimeMs); bundle.putLong(FIELD_COMPLETION_TIME_MS, completionTimeMs);
return bundle; return bundle;
} }
...@@ -199,17 +194,10 @@ public final class SessionResult implements Bundleable { ...@@ -199,17 +194,10 @@ public final class SessionResult implements Bundleable {
@UnstableApi public static final Creator<SessionResult> CREATOR = SessionResult::fromBundle; @UnstableApi public static final Creator<SessionResult> CREATOR = SessionResult::fromBundle;
private static SessionResult fromBundle(Bundle bundle) { private static SessionResult fromBundle(Bundle bundle) {
int resultCode = int resultCode = bundle.getInt(FIELD_RESULT_CODE, /* defaultValue= */ RESULT_ERROR_UNKNOWN);
bundle.getInt(keyForField(FIELD_RESULT_CODE), /* defaultValue= */ RESULT_ERROR_UNKNOWN); @Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
@Nullable Bundle extras = bundle.getBundle(keyForField(FIELD_EXTRAS));
long completionTimeMs = long completionTimeMs =
bundle.getLong( bundle.getLong(FIELD_COMPLETION_TIME_MS, /* defaultValue= */ SystemClock.elapsedRealtime());
keyForField(FIELD_COMPLETION_TIME_MS),
/* defaultValue= */ SystemClock.elapsedRealtime());
return new SessionResult(resultCode, extras == null ? Bundle.EMPTY : extras, completionTimeMs); return new SessionResult(resultCode, extras == null ? Bundle.EMPTY : extras, completionTimeMs);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -41,6 +41,7 @@ import androidx.media3.common.Bundleable; ...@@ -41,6 +41,7 @@ import androidx.media3.common.Bundleable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaLibraryInfo; import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
...@@ -153,9 +154,9 @@ public final class SessionToken implements Bundleable { ...@@ -153,9 +154,9 @@ public final class SessionToken implements Bundleable {
} }
private SessionToken(Bundle bundle) { private SessionToken(Bundle bundle) {
checkArgument(bundle.containsKey(keyForField(FIELD_IMPL_TYPE)), "Impl type needs to be set."); checkArgument(bundle.containsKey(FIELD_IMPL_TYPE), "Impl type needs to be set.");
@SessionTokenImplType int implType = bundle.getInt(keyForField(FIELD_IMPL_TYPE)); @SessionTokenImplType int implType = bundle.getInt(FIELD_IMPL_TYPE);
Bundle implBundle = checkNotNull(bundle.getBundle(keyForField(FIELD_IMPL))); Bundle implBundle = checkNotNull(bundle.getBundle(FIELD_IMPL));
if (implType == IMPL_TYPE_BASE) { if (implType == IMPL_TYPE_BASE) {
impl = SessionTokenImplBase.CREATOR.fromBundle(implBundle); impl = SessionTokenImplBase.CREATOR.fromBundle(implBundle);
} else { } else {
...@@ -481,14 +482,8 @@ public final class SessionToken implements Bundleable { ...@@ -481,14 +482,8 @@ public final class SessionToken implements Bundleable {
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_IMPL_TYPE = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_IMPL = Util.intToStringMaxRadix(1);
@Target(TYPE_USE)
@IntDef({FIELD_IMPL_TYPE, FIELD_IMPL})
private @interface FieldNumber {}
private static final int FIELD_IMPL_TYPE = 0;
private static final int FIELD_IMPL = 1;
/** Types of {@link SessionTokenImpl} */ /** Types of {@link SessionTokenImpl} */
@Documented @Documented
...@@ -505,11 +500,11 @@ public final class SessionToken implements Bundleable { ...@@ -505,11 +500,11 @@ public final class SessionToken implements Bundleable {
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
if (impl instanceof SessionTokenImplBase) { if (impl instanceof SessionTokenImplBase) {
bundle.putInt(keyForField(FIELD_IMPL_TYPE), IMPL_TYPE_BASE); bundle.putInt(FIELD_IMPL_TYPE, IMPL_TYPE_BASE);
} else { } else {
bundle.putInt(keyForField(FIELD_IMPL_TYPE), IMPL_TYPE_LEGACY); bundle.putInt(FIELD_IMPL_TYPE, IMPL_TYPE_LEGACY);
} }
bundle.putBundle(keyForField(FIELD_IMPL), impl.toBundle()); bundle.putBundle(FIELD_IMPL, impl.toBundle());
return bundle; return bundle;
} }
...@@ -519,8 +514,4 @@ public final class SessionToken implements Bundleable { ...@@ -519,8 +514,4 @@ public final class SessionToken implements Bundleable {
private static SessionToken fromBundle(Bundle bundle) { private static SessionToken fromBundle(Bundle bundle) {
return new SessionToken(bundle); return new SessionToken(bundle);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -18,21 +18,15 @@ package androidx.media3.session; ...@@ -18,21 +18,15 @@ package androidx.media3.session;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotEmpty; import static androidx.media3.common.util.Assertions.checkNotEmpty;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.ComponentName; import android.content.ComponentName;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.BundleCompat; import androidx.core.app.BundleCompat;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/* package */ final class SessionTokenImplBase implements SessionToken.SessionTokenImpl { /* package */ final class SessionTokenImplBase implements SessionToken.SessionTokenImpl {
...@@ -211,45 +205,29 @@ import java.lang.annotation.Target; ...@@ -211,45 +205,29 @@ import java.lang.annotation.Target;
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_UID = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_TYPE = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_LIBRARY_VERSION = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_PACKAGE_NAME = Util.intToStringMaxRadix(3);
FIELD_UID, private static final String FIELD_SERVICE_NAME = Util.intToStringMaxRadix(4);
FIELD_TYPE, private static final String FIELD_COMPONENT_NAME = Util.intToStringMaxRadix(5);
FIELD_LIBRARY_VERSION, private static final String FIELD_ISESSION = Util.intToStringMaxRadix(6);
FIELD_PACKAGE_NAME, private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(7);
FIELD_SERVICE_NAME, private static final String FIELD_INTERFACE_VERSION = Util.intToStringMaxRadix(8);
FIELD_ISESSION,
FIELD_COMPONENT_NAME,
FIELD_EXTRAS,
FIELD_INTERFACE_VERSION
})
private @interface FieldNumber {}
private static final int FIELD_UID = 0;
private static final int FIELD_TYPE = 1;
private static final int FIELD_LIBRARY_VERSION = 2;
private static final int FIELD_PACKAGE_NAME = 3;
private static final int FIELD_SERVICE_NAME = 4;
private static final int FIELD_COMPONENT_NAME = 5;
private static final int FIELD_ISESSION = 6;
private static final int FIELD_EXTRAS = 7;
private static final int FIELD_INTERFACE_VERSION = 8;
// Next field key = 9 // Next field key = 9
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(keyForField(FIELD_UID), uid); bundle.putInt(FIELD_UID, uid);
bundle.putInt(keyForField(FIELD_TYPE), type); bundle.putInt(FIELD_TYPE, type);
bundle.putInt(keyForField(FIELD_LIBRARY_VERSION), libraryVersion); bundle.putInt(FIELD_LIBRARY_VERSION, libraryVersion);
bundle.putString(keyForField(FIELD_PACKAGE_NAME), packageName); bundle.putString(FIELD_PACKAGE_NAME, packageName);
bundle.putString(keyForField(FIELD_SERVICE_NAME), serviceName); bundle.putString(FIELD_SERVICE_NAME, serviceName);
BundleCompat.putBinder(bundle, keyForField(FIELD_ISESSION), iSession); BundleCompat.putBinder(bundle, FIELD_ISESSION, iSession);
bundle.putParcelable(keyForField(FIELD_COMPONENT_NAME), componentName); bundle.putParcelable(FIELD_COMPONENT_NAME, componentName);
bundle.putBundle(keyForField(FIELD_EXTRAS), extras); bundle.putBundle(FIELD_EXTRAS, extras);
bundle.putInt(keyForField(FIELD_INTERFACE_VERSION), interfaceVersion); bundle.putInt(FIELD_INTERFACE_VERSION, interfaceVersion);
return bundle; return bundle;
} }
...@@ -257,20 +235,18 @@ import java.lang.annotation.Target; ...@@ -257,20 +235,18 @@ import java.lang.annotation.Target;
public static final Creator<SessionTokenImplBase> CREATOR = SessionTokenImplBase::fromBundle; public static final Creator<SessionTokenImplBase> CREATOR = SessionTokenImplBase::fromBundle;
private static SessionTokenImplBase fromBundle(Bundle bundle) { private static SessionTokenImplBase fromBundle(Bundle bundle) {
checkArgument(bundle.containsKey(keyForField(FIELD_UID)), "uid should be set."); checkArgument(bundle.containsKey(FIELD_UID), "uid should be set.");
int uid = bundle.getInt(keyForField(FIELD_UID)); int uid = bundle.getInt(FIELD_UID);
checkArgument(bundle.containsKey(keyForField(FIELD_TYPE)), "type should be set."); checkArgument(bundle.containsKey(FIELD_TYPE), "type should be set.");
int type = bundle.getInt(keyForField(FIELD_TYPE)); int type = bundle.getInt(FIELD_TYPE);
int libraryVersion = bundle.getInt(keyForField(FIELD_LIBRARY_VERSION), /* defaultValue= */ 0); int libraryVersion = bundle.getInt(FIELD_LIBRARY_VERSION, /* defaultValue= */ 0);
int interfaceVersion = int interfaceVersion = bundle.getInt(FIELD_INTERFACE_VERSION, /* defaultValue= */ 0);
bundle.getInt(keyForField(FIELD_INTERFACE_VERSION), /* defaultValue= */ 0);
String packageName = String packageName =
checkNotEmpty( checkNotEmpty(bundle.getString(FIELD_PACKAGE_NAME), "package name should be set.");
bundle.getString(keyForField(FIELD_PACKAGE_NAME)), "package name should be set."); String serviceName = bundle.getString(FIELD_SERVICE_NAME, /* defaultValue= */ "");
String serviceName = bundle.getString(keyForField(FIELD_SERVICE_NAME), /* defaultValue= */ ""); @Nullable IBinder iSession = BundleCompat.getBinder(bundle, FIELD_ISESSION);
@Nullable IBinder iSession = BundleCompat.getBinder(bundle, keyForField(FIELD_ISESSION)); @Nullable ComponentName componentName = bundle.getParcelable(FIELD_COMPONENT_NAME);
@Nullable ComponentName componentName = bundle.getParcelable(keyForField(FIELD_COMPONENT_NAME)); @Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
@Nullable Bundle extras = bundle.getBundle(keyForField(FIELD_EXTRAS));
return new SessionTokenImplBase( return new SessionTokenImplBase(
uid, uid,
type, type,
...@@ -282,8 +258,4 @@ import java.lang.annotation.Target; ...@@ -282,8 +258,4 @@ import java.lang.annotation.Target;
iSession, iSession,
extras == null ? Bundle.EMPTY : extras); extras == null ? Bundle.EMPTY : extras);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
...@@ -22,20 +22,14 @@ import static androidx.media3.session.SessionToken.TYPE_BROWSER_SERVICE_LEGACY; ...@@ -22,20 +22,14 @@ import static androidx.media3.session.SessionToken.TYPE_BROWSER_SERVICE_LEGACY;
import static androidx.media3.session.SessionToken.TYPE_LIBRARY_SERVICE; import static androidx.media3.session.SessionToken.TYPE_LIBRARY_SERVICE;
import static androidx.media3.session.SessionToken.TYPE_SESSION; import static androidx.media3.session.SessionToken.TYPE_SESSION;
import static androidx.media3.session.SessionToken.TYPE_SESSION_LEGACY; import static androidx.media3.session.SessionToken.TYPE_SESSION_LEGACY;
import static java.lang.annotation.ElementType.TYPE_USE;
import android.content.ComponentName; import android.content.ComponentName;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.MediaSessionCompat;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.session.SessionToken.SessionTokenImpl; import androidx.media3.session.SessionToken.SessionTokenImpl;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/* package */ final class SessionTokenImplLegacy implements SessionTokenImpl { /* package */ final class SessionTokenImplLegacy implements SessionTokenImpl {
...@@ -176,36 +170,22 @@ import java.lang.annotation.Target; ...@@ -176,36 +170,22 @@ import java.lang.annotation.Target;
// Bundleable implementation. // Bundleable implementation.
@Documented private static final String FIELD_LEGACY_TOKEN = Util.intToStringMaxRadix(0);
@Retention(RetentionPolicy.SOURCE) private static final String FIELD_UID = Util.intToStringMaxRadix(1);
@Target(TYPE_USE) private static final String FIELD_TYPE = Util.intToStringMaxRadix(2);
@IntDef({ private static final String FIELD_COMPONENT_NAME = Util.intToStringMaxRadix(3);
FIELD_LEGACY_TOKEN, private static final String FIELD_PACKAGE_NAME = Util.intToStringMaxRadix(4);
FIELD_UID, private static final String FIELD_EXTRAS = Util.intToStringMaxRadix(5);
FIELD_TYPE,
FIELD_COMPONENT_NAME,
FIELD_PACKAGE_NAME,
FIELD_EXTRAS
})
private @interface FieldNumber {}
private static final int FIELD_LEGACY_TOKEN = 0;
private static final int FIELD_UID = 1;
private static final int FIELD_TYPE = 2;
private static final int FIELD_COMPONENT_NAME = 3;
private static final int FIELD_PACKAGE_NAME = 4;
private static final int FIELD_EXTRAS = 5;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putBundle( bundle.putBundle(FIELD_LEGACY_TOKEN, legacyToken == null ? null : legacyToken.toBundle());
keyForField(FIELD_LEGACY_TOKEN), legacyToken == null ? null : legacyToken.toBundle()); bundle.putInt(FIELD_UID, uid);
bundle.putInt(keyForField(FIELD_UID), uid); bundle.putInt(FIELD_TYPE, type);
bundle.putInt(keyForField(FIELD_TYPE), type); bundle.putParcelable(FIELD_COMPONENT_NAME, componentName);
bundle.putParcelable(keyForField(FIELD_COMPONENT_NAME), componentName); bundle.putString(FIELD_PACKAGE_NAME, packageName);
bundle.putString(keyForField(FIELD_PACKAGE_NAME), packageName); bundle.putBundle(FIELD_EXTRAS, extras);
bundle.putBundle(keyForField(FIELD_EXTRAS), extras);
return bundle; return bundle;
} }
...@@ -213,24 +193,19 @@ import java.lang.annotation.Target; ...@@ -213,24 +193,19 @@ import java.lang.annotation.Target;
public static final Creator<SessionTokenImplLegacy> CREATOR = SessionTokenImplLegacy::fromBundle; public static final Creator<SessionTokenImplLegacy> CREATOR = SessionTokenImplLegacy::fromBundle;
private static SessionTokenImplLegacy fromBundle(Bundle bundle) { private static SessionTokenImplLegacy fromBundle(Bundle bundle) {
@Nullable Bundle legacyTokenBundle = bundle.getBundle(keyForField(FIELD_LEGACY_TOKEN)); @Nullable Bundle legacyTokenBundle = bundle.getBundle(FIELD_LEGACY_TOKEN);
@Nullable @Nullable
MediaSessionCompat.Token legacyToken = MediaSessionCompat.Token legacyToken =
legacyTokenBundle == null ? null : MediaSessionCompat.Token.fromBundle(legacyTokenBundle); legacyTokenBundle == null ? null : MediaSessionCompat.Token.fromBundle(legacyTokenBundle);
checkArgument(bundle.containsKey(keyForField(FIELD_UID)), "uid should be set."); checkArgument(bundle.containsKey(FIELD_UID), "uid should be set.");
int uid = bundle.getInt(keyForField(FIELD_UID)); int uid = bundle.getInt(FIELD_UID);
checkArgument(bundle.containsKey(keyForField(FIELD_TYPE)), "type should be set."); checkArgument(bundle.containsKey(FIELD_TYPE), "type should be set.");
int type = bundle.getInt(keyForField(FIELD_TYPE)); int type = bundle.getInt(FIELD_TYPE);
@Nullable ComponentName componentName = bundle.getParcelable(keyForField(FIELD_COMPONENT_NAME)); @Nullable ComponentName componentName = bundle.getParcelable(FIELD_COMPONENT_NAME);
String packageName = String packageName =
checkNotEmpty( checkNotEmpty(bundle.getString(FIELD_PACKAGE_NAME), "package name should be set.");
bundle.getString(keyForField(FIELD_PACKAGE_NAME)), "package name should be set."); @Nullable Bundle extras = bundle.getBundle(FIELD_EXTRAS);
@Nullable Bundle extras = bundle.getBundle(keyForField(FIELD_EXTRAS));
return new SessionTokenImplLegacy( return new SessionTokenImplLegacy(
legacyToken, uid, type, componentName, packageName, extras == null ? Bundle.EMPTY : extras); legacyToken, uid, type, componentName, packageName, extras == null ? Bundle.EMPTY : extras);
} }
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment