diff --git a/libraries/common/src/main/java/androidx/media3/common/MediaItem.java b/libraries/common/src/main/java/androidx/media3/common/MediaItem.java index 0ffcec8749..c87a1b6619 100644 --- a/libraries/common/src/main/java/androidx/media3/common/MediaItem.java +++ b/libraries/common/src/main/java/androidx/media3/common/MediaItem.java @@ -889,7 +889,7 @@ public final class MediaItem implements Bundleable { return result; } - // Bundleable implementation + // Bundleable implementation. private static final String FIELD_SCHEME = Util.intToStringMaxRadix(0); private static final String FIELD_LICENSE_URI = Util.intToStringMaxRadix(1); @@ -1419,7 +1419,7 @@ public final class MediaItem implements Bundleable { /** Properties for a text track. */ // TODO: Mark this final when Subtitle is deleted. - public static class SubtitleConfiguration { + public static class SubtitleConfiguration implements Bundleable { /** Builder for {@link SubtitleConfiguration} instances. */ public static final class Builder { @@ -1590,6 +1590,67 @@ public final class MediaItem implements Bundleable { result = 31 * result + (id == null ? 0 : id.hashCode()); return result; } + + // Bundleable implementation. + + private static final String FIELD_URI = Util.intToStringMaxRadix(0); + private static final String FIELD_MIME_TYPE = Util.intToStringMaxRadix(1); + private static final String FIELD_LANGUAGE = Util.intToStringMaxRadix(2); + private static final String FIELD_SELECTION_FLAGS = Util.intToStringMaxRadix(3); + private static final String FIELD_ROLE_FLAGS = Util.intToStringMaxRadix(4); + private static final String FIELD_LABEL = Util.intToStringMaxRadix(5); + private static final String FIELD_ID = Util.intToStringMaxRadix(6); + + /** Object that can restore {@link SubtitleConfiguration} from a {@link Bundle}. */ + @UnstableApi + public static final Creator CREATOR = SubtitleConfiguration::fromBundle; + + @UnstableApi + private static SubtitleConfiguration fromBundle(Bundle bundle) { + Uri uri = checkNotNull(bundle.getParcelable(FIELD_URI)); + @Nullable String mimeType = bundle.getString(FIELD_MIME_TYPE); + @Nullable String language = bundle.getString(FIELD_LANGUAGE); + @C.SelectionFlags int selectionFlags = bundle.getInt(FIELD_SELECTION_FLAGS, 0); + @C.RoleFlags int roleFlags = bundle.getInt(FIELD_ROLE_FLAGS, 0); + @Nullable String label = bundle.getString(FIELD_LABEL); + @Nullable String id = bundle.getString(FIELD_ID); + + SubtitleConfiguration.Builder builder = new SubtitleConfiguration.Builder(uri); + return builder + .setMimeType(mimeType) + .setLanguage(language) + .setSelectionFlags(selectionFlags) + .setRoleFlags(roleFlags) + .setLabel(label) + .setId(id) + .build(); + } + + @UnstableApi + @Override + public Bundle toBundle() { + Bundle bundle = new Bundle(); + bundle.putParcelable(FIELD_URI, uri); + if (mimeType != null) { + bundle.putString(FIELD_MIME_TYPE, mimeType); + } + if (language != null) { + bundle.putString(FIELD_LANGUAGE, language); + } + if (selectionFlags != 0) { + bundle.putInt(FIELD_SELECTION_FLAGS, selectionFlags); + } + if (roleFlags != 0) { + bundle.putInt(FIELD_ROLE_FLAGS, roleFlags); + } + if (label != null) { + bundle.putString(FIELD_LABEL, label); + } + if (id != null) { + bundle.putString(FIELD_ID, id); + } + return bundle; + } } /** diff --git a/libraries/common/src/test/java/androidx/media3/common/MediaItemTest.java b/libraries/common/src/test/java/androidx/media3/common/MediaItemTest.java index c8bfd2d11c..cb48c4b1cb 100644 --- a/libraries/common/src/test/java/androidx/media3/common/MediaItemTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/MediaItemTest.java @@ -338,6 +338,42 @@ public class MediaItemTest { assertThat(mediaItem.localConfiguration.subtitles).isEqualTo(subtitles); } + @Test + public void + createDefaultSubtitleConfigurationInstance_toBundleSkipsDefaultValues_fromBundleRestoresThem() { + MediaItem.SubtitleConfiguration subtitleConfiguration = + new MediaItem.SubtitleConfiguration.Builder(Uri.parse(URI_STRING + "/en")).build(); + + Bundle subtitleConfigurationBundle = subtitleConfiguration.toBundle(); + + // Check that default values are skipped when bundling, only Uri field (="0") is present + assertThat(subtitleConfigurationBundle.keySet()).containsExactly("0"); + + MediaItem.SubtitleConfiguration subtitleConfigurationFromBundle = + MediaItem.SubtitleConfiguration.CREATOR.fromBundle(subtitleConfigurationBundle); + + assertThat(subtitleConfigurationFromBundle).isEqualTo(subtitleConfiguration); + } + + @Test + public void createSubtitleConfigurationInstance_roundTripViaBundle_yieldsEqualInstance() { + // Creates instance by setting some non-default values + MediaItem.SubtitleConfiguration subtitleConfiguration = + new MediaItem.SubtitleConfiguration.Builder(Uri.parse(URI_STRING + "/en")) + .setMimeType(MimeTypes.APPLICATION_TTML) + .setLanguage("en") + .setSelectionFlags(C.SELECTION_FLAG_FORCED) + .setRoleFlags(C.ROLE_FLAG_ALTERNATE) + .setLabel("label") + .setId("id") + .build(); + + MediaItem.SubtitleConfiguration subtitleConfigurationFromBundle = + MediaItem.SubtitleConfiguration.CREATOR.fromBundle(subtitleConfiguration.toBundle()); + + assertThat(subtitleConfigurationFromBundle).isEqualTo(subtitleConfiguration); + } + @Test public void builderSetTag_isNullByDefault() { MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();