Allow playback of MediaItems
with LocalConfiguration
When initiated by MediaController, it should be possible for `MediaSession` to pass `MediaItems` to the `Player` if they have `LocalConfiguration`. In such case, it is not required to override `MediaSession.Callback.onAddMediaItems`, because the new current default implementation will handle it. However, in other cases, MediaItem.toBundle() will continue to strip the LocalConfiguration information. Issue: androidx/media#282 #minor-release PiperOrigin-RevId: 537993460
This commit is contained in:
parent
7956c80f73
commit
d9764c18ad
@ -48,6 +48,10 @@
|
|||||||
* Muxers:
|
* Muxers:
|
||||||
* IMA extension:
|
* IMA extension:
|
||||||
* Session:
|
* Session:
|
||||||
|
* Add default implementation to `MediaSession.Callback.onAddMediaItems` to
|
||||||
|
allow requested `MediaItems` to be passed onto `Player` if they have
|
||||||
|
`LocalConfiguration` (e.g. URI)
|
||||||
|
([#282](https://github.com/androidx/media/issues/282)).
|
||||||
* UI:
|
* UI:
|
||||||
* Downloads:
|
* Downloads:
|
||||||
* OkHttp Extension:
|
* OkHttp Extension:
|
||||||
|
@ -1087,7 +1087,7 @@ public final class MediaItem implements Bundleable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Properties for local playback. */
|
/** Properties for local playback. */
|
||||||
public static final class LocalConfiguration {
|
public static final class LocalConfiguration implements Bundleable {
|
||||||
|
|
||||||
/** The {@link Uri}. */
|
/** The {@link Uri}. */
|
||||||
public final Uri uri;
|
public final Uri uri;
|
||||||
@ -1183,6 +1183,82 @@ public final class MediaItem implements Bundleable {
|
|||||||
result = 31 * result + (tag == null ? 0 : tag.hashCode());
|
result = 31 * result + (tag == null ? 0 : tag.hashCode());
|
||||||
return result;
|
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_DRM_CONFIGURATION = Util.intToStringMaxRadix(2);
|
||||||
|
private static final String FIELD_ADS_CONFIGURATION = Util.intToStringMaxRadix(3);
|
||||||
|
private static final String FIELD_STREAM_KEYS = Util.intToStringMaxRadix(4);
|
||||||
|
private static final String FIELD_CUSTOM_CACHE_KEY = Util.intToStringMaxRadix(5);
|
||||||
|
private static final String FIELD_SUBTITLE_CONFIGURATION = Util.intToStringMaxRadix(6);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>It omits the {@link #tag} field. The {@link #tag} of an instance restored from such a
|
||||||
|
* bundle by {@link #CREATOR} will be {@code null}.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putParcelable(FIELD_URI, uri);
|
||||||
|
if (mimeType != null) {
|
||||||
|
bundle.putString(FIELD_MIME_TYPE, mimeType);
|
||||||
|
}
|
||||||
|
if (drmConfiguration != null) {
|
||||||
|
bundle.putBundle(FIELD_DRM_CONFIGURATION, drmConfiguration.toBundle());
|
||||||
|
}
|
||||||
|
if (adsConfiguration != null) {
|
||||||
|
bundle.putBundle(FIELD_ADS_CONFIGURATION, adsConfiguration.toBundle());
|
||||||
|
}
|
||||||
|
if (!streamKeys.isEmpty()) {
|
||||||
|
bundle.putParcelableArrayList(FIELD_STREAM_KEYS, new ArrayList<>(streamKeys));
|
||||||
|
}
|
||||||
|
if (customCacheKey != null) {
|
||||||
|
bundle.putString(FIELD_CUSTOM_CACHE_KEY, customCacheKey);
|
||||||
|
}
|
||||||
|
if (!subtitleConfigurations.isEmpty()) {
|
||||||
|
bundle.putParcelableArrayList(
|
||||||
|
FIELD_SUBTITLE_CONFIGURATION, BundleableUtil.toBundleArrayList(subtitleConfigurations));
|
||||||
|
}
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Object that can restore {@link LocalConfiguration} from a {@link Bundle}. */
|
||||||
|
@UnstableApi
|
||||||
|
public static final Creator<LocalConfiguration> CREATOR = LocalConfiguration::fromBundle;
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
|
private static LocalConfiguration fromBundle(Bundle bundle) {
|
||||||
|
@Nullable Bundle drmBundle = bundle.getBundle(FIELD_DRM_CONFIGURATION);
|
||||||
|
DrmConfiguration drmConfiguration =
|
||||||
|
drmBundle == null ? null : DrmConfiguration.CREATOR.fromBundle(drmBundle);
|
||||||
|
@Nullable Bundle adsBundle = bundle.getBundle(FIELD_ADS_CONFIGURATION);
|
||||||
|
AdsConfiguration adsConfiguration =
|
||||||
|
adsBundle == null ? null : AdsConfiguration.CREATOR.fromBundle(adsBundle);
|
||||||
|
@Nullable List<StreamKey> streamKeysList = bundle.getParcelableArrayList(FIELD_STREAM_KEYS);
|
||||||
|
List<StreamKey> streamKeys =
|
||||||
|
streamKeysList == null ? ImmutableList.of() : ImmutableList.copyOf(streamKeysList);
|
||||||
|
@Nullable
|
||||||
|
List<Bundle> subtitleBundles = bundle.getParcelableArrayList(FIELD_SUBTITLE_CONFIGURATION);
|
||||||
|
ImmutableList<SubtitleConfiguration> subtitleConfiguration =
|
||||||
|
subtitleBundles == null
|
||||||
|
? ImmutableList.of()
|
||||||
|
: BundleableUtil.fromBundleList(SubtitleConfiguration.CREATOR, subtitleBundles);
|
||||||
|
|
||||||
|
return new LocalConfiguration(
|
||||||
|
checkNotNull(bundle.getParcelable(FIELD_URI)),
|
||||||
|
bundle.getString(FIELD_MIME_TYPE),
|
||||||
|
drmConfiguration,
|
||||||
|
adsConfiguration,
|
||||||
|
streamKeys,
|
||||||
|
bundle.getString(FIELD_CUSTOM_CACHE_KEY),
|
||||||
|
subtitleConfiguration,
|
||||||
|
/* tag= */ null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Live playback configuration. */
|
/** Live playback configuration. */
|
||||||
@ -2167,16 +2243,10 @@ public final class MediaItem implements Bundleable {
|
|||||||
private static final String FIELD_MEDIA_METADATA = Util.intToStringMaxRadix(2);
|
private static final String FIELD_MEDIA_METADATA = Util.intToStringMaxRadix(2);
|
||||||
private static final String FIELD_CLIPPING_PROPERTIES = Util.intToStringMaxRadix(3);
|
private static final String FIELD_CLIPPING_PROPERTIES = Util.intToStringMaxRadix(3);
|
||||||
private static final String FIELD_REQUEST_METADATA = Util.intToStringMaxRadix(4);
|
private static final String FIELD_REQUEST_METADATA = Util.intToStringMaxRadix(4);
|
||||||
|
private static final String FIELD_LOCAL_CONFIGURATION = Util.intToStringMaxRadix(5);
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>It omits the {@link #localConfiguration} field. The {@link #localConfiguration} of an
|
|
||||||
* instance restored by {@link #CREATOR} will always be {@code null}.
|
|
||||||
*/
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
@Override
|
private Bundle toBundle(boolean includeLocalConfiguration) {
|
||||||
public Bundle toBundle() {
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
if (!mediaId.equals(DEFAULT_MEDIA_ID)) {
|
if (!mediaId.equals(DEFAULT_MEDIA_ID)) {
|
||||||
bundle.putString(FIELD_MEDIA_ID, mediaId);
|
bundle.putString(FIELD_MEDIA_ID, mediaId);
|
||||||
@ -2193,9 +2263,33 @@ public final class MediaItem implements Bundleable {
|
|||||||
if (!requestMetadata.equals(RequestMetadata.EMPTY)) {
|
if (!requestMetadata.equals(RequestMetadata.EMPTY)) {
|
||||||
bundle.putBundle(FIELD_REQUEST_METADATA, requestMetadata.toBundle());
|
bundle.putBundle(FIELD_REQUEST_METADATA, requestMetadata.toBundle());
|
||||||
}
|
}
|
||||||
|
if (includeLocalConfiguration && localConfiguration != null) {
|
||||||
|
bundle.putBundle(FIELD_LOCAL_CONFIGURATION, localConfiguration.toBundle());
|
||||||
|
}
|
||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>It omits the {@link #localConfiguration} field. The {@link #localConfiguration} of an
|
||||||
|
* instance restored from such a bundle by {@link #CREATOR} will be {@code null}.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
@Override
|
||||||
|
public Bundle toBundle() {
|
||||||
|
return toBundle(/* includeLocalConfiguration= */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link Bundle} representing the information stored in this {@link #MediaItem} object,
|
||||||
|
* while including the {@link #localConfiguration} field if it is not null (otherwise skips it).
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public Bundle toBundleIncludeLocalConfiguration() {
|
||||||
|
return toBundle(/* includeLocalConfiguration= */ true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that can restore {@link MediaItem} from a {@link Bundle}.
|
* An object that can restore {@link MediaItem} from a {@link Bundle}.
|
||||||
*
|
*
|
||||||
@ -2234,10 +2328,17 @@ public final class MediaItem implements Bundleable {
|
|||||||
} else {
|
} else {
|
||||||
requestMetadata = RequestMetadata.CREATOR.fromBundle(requestMetadataBundle);
|
requestMetadata = RequestMetadata.CREATOR.fromBundle(requestMetadataBundle);
|
||||||
}
|
}
|
||||||
|
@Nullable Bundle localConfigurationBundle = bundle.getBundle(FIELD_LOCAL_CONFIGURATION);
|
||||||
|
LocalConfiguration localConfiguration;
|
||||||
|
if (localConfigurationBundle == null) {
|
||||||
|
localConfiguration = null;
|
||||||
|
} else {
|
||||||
|
localConfiguration = LocalConfiguration.CREATOR.fromBundle(localConfigurationBundle);
|
||||||
|
}
|
||||||
return new MediaItem(
|
return new MediaItem(
|
||||||
mediaId,
|
mediaId,
|
||||||
clippingConfiguration,
|
clippingConfiguration,
|
||||||
/* localConfiguration= */ null,
|
localConfiguration,
|
||||||
liveConfiguration,
|
liveConfiguration,
|
||||||
mediaMetadata,
|
mediaMetadata,
|
||||||
requestMetadata);
|
requestMetadata);
|
||||||
|
@ -22,6 +22,7 @@ import android.os.Bundle;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.Bundleable;
|
import androidx.media3.common.Bundleable;
|
||||||
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -36,10 +37,21 @@ public final class BundleableUtil {
|
|||||||
|
|
||||||
/** Converts a list of {@link Bundleable} to a list {@link Bundle}. */
|
/** Converts a list of {@link Bundleable} to a list {@link Bundle}. */
|
||||||
public static <T extends Bundleable> ImmutableList<Bundle> toBundleList(List<T> bundleableList) {
|
public static <T extends Bundleable> ImmutableList<Bundle> toBundleList(List<T> bundleableList) {
|
||||||
|
return toBundleList(bundleableList, Bundleable::toBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a list of {@link Bundleable} to a list {@link Bundle}
|
||||||
|
*
|
||||||
|
* @param bundleableList list of Bundleable items to be converted
|
||||||
|
* @param customToBundleFunc function that specifies how to bundle up each {@link Bundleable}
|
||||||
|
*/
|
||||||
|
public static <T extends Bundleable> ImmutableList<Bundle> toBundleList(
|
||||||
|
List<T> bundleableList, Function<T, Bundle> customToBundleFunc) {
|
||||||
ImmutableList.Builder<Bundle> builder = ImmutableList.builder();
|
ImmutableList.Builder<Bundle> builder = ImmutableList.builder();
|
||||||
for (int i = 0; i < bundleableList.size(); i++) {
|
for (int i = 0; i < bundleableList.size(); i++) {
|
||||||
Bundleable bundleable = bundleableList.get(i);
|
T bundleable = bundleableList.get(i);
|
||||||
builder.add(bundleable.toBundle());
|
builder.add(customToBundleFunc.apply(bundleable));
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
@ -665,6 +665,68 @@ public class MediaItemTest {
|
|||||||
assertThat(liveConfigurationFromBundle).isEqualTo(liveConfiguration);
|
assertThat(liveConfigurationFromBundle).isEqualTo(liveConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
createDefaultLocalConfigurationInstance_toBundleSkipsDefaultValues_fromBundleRestoresThem() {
|
||||||
|
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
|
||||||
|
|
||||||
|
Bundle localConfigurationBundle = mediaItem.localConfiguration.toBundle();
|
||||||
|
|
||||||
|
// Check that default values are skipped when bundling, only Uri field (="0") is present
|
||||||
|
assertThat(localConfigurationBundle.keySet()).containsExactly("0");
|
||||||
|
|
||||||
|
MediaItem.LocalConfiguration restoredLocalConfiguration =
|
||||||
|
MediaItem.LocalConfiguration.CREATOR.fromBundle(localConfigurationBundle);
|
||||||
|
|
||||||
|
assertThat(restoredLocalConfiguration).isEqualTo(mediaItem.localConfiguration);
|
||||||
|
assertThat(restoredLocalConfiguration.streamKeys).isEmpty();
|
||||||
|
assertThat(restoredLocalConfiguration.subtitleConfigurations).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createLocalConfigurationInstance_roundTripViaBundle_yieldsEqualInstance() {
|
||||||
|
Map<String, String> requestHeaders = new HashMap<>();
|
||||||
|
requestHeaders.put("Referer", "http://www.google.com");
|
||||||
|
MediaItem mediaItem =
|
||||||
|
new MediaItem.Builder()
|
||||||
|
.setUri(URI_STRING)
|
||||||
|
.setMimeType(MimeTypes.APPLICATION_MP4)
|
||||||
|
.setCustomCacheKey("key")
|
||||||
|
.setSubtitleConfigurations(
|
||||||
|
ImmutableList.of(
|
||||||
|
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()))
|
||||||
|
.setDrmConfiguration(
|
||||||
|
new MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
|
||||||
|
.setLicenseUri(Uri.parse(URI_STRING))
|
||||||
|
.setLicenseRequestHeaders(requestHeaders)
|
||||||
|
.setMultiSession(true)
|
||||||
|
.setForceDefaultLicenseUri(true)
|
||||||
|
.setPlayClearContentWithoutKey(true)
|
||||||
|
.setForcedSessionTrackTypes(ImmutableList.of(C.TRACK_TYPE_AUDIO))
|
||||||
|
.setKeySetId(new byte[] {1, 2, 3})
|
||||||
|
.build())
|
||||||
|
.setAdsConfiguration(
|
||||||
|
new MediaItem.AdsConfiguration.Builder(Uri.parse(URI_STRING)).build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
MediaItem.LocalConfiguration localConfiguration = mediaItem.localConfiguration;
|
||||||
|
MediaItem.LocalConfiguration localConfigurationFromBundle =
|
||||||
|
MediaItem.LocalConfiguration.CREATOR.fromBundle(localConfiguration.toBundle());
|
||||||
|
MediaItem.LocalConfiguration localConfigurationFromMediaItemBundle =
|
||||||
|
MediaItem.CREATOR.fromBundle(mediaItem.toBundleIncludeLocalConfiguration())
|
||||||
|
.localConfiguration;
|
||||||
|
|
||||||
|
assertThat(localConfigurationFromBundle).isEqualTo(localConfiguration);
|
||||||
|
assertThat(localConfigurationFromMediaItemBundle).isEqualTo(localConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void builderSetLiveConfiguration() {
|
public void builderSetLiveConfiguration() {
|
||||||
MediaItem mediaItem =
|
MediaItem mediaItem =
|
||||||
@ -892,13 +954,25 @@ public class MediaItemTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void roundTripViaBundle_withLocalConfiguration_dropsLocalConfiguration() {
|
public void
|
||||||
|
roundTripViaDefaultBundle_mediaItemContainsLocalConfiguration_dropsLocalConfiguration() {
|
||||||
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
|
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
|
||||||
|
|
||||||
assertThat(mediaItem.localConfiguration).isNotNull();
|
assertThat(mediaItem.localConfiguration).isNotNull();
|
||||||
assertThat(MediaItem.CREATOR.fromBundle(mediaItem.toBundle()).localConfiguration).isNull();
|
assertThat(MediaItem.CREATOR.fromBundle(mediaItem.toBundle()).localConfiguration).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
roundTripViaBundleIncludeLocalConfiguration_mediaItemContainsLocalConfiguration_restoresLocalConfiguration() {
|
||||||
|
MediaItem mediaItem = new MediaItem.Builder().setUri(URI_STRING).build();
|
||||||
|
MediaItem restoredMediaItem =
|
||||||
|
MediaItem.CREATOR.fromBundle(mediaItem.toBundleIncludeLocalConfiguration());
|
||||||
|
|
||||||
|
assertThat(mediaItem.localConfiguration).isNotNull();
|
||||||
|
assertThat(restoredMediaItem.localConfiguration).isEqualTo(mediaItem.localConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createDefaultMediaItemInstance_checksDefaultValues() {
|
public void createDefaultMediaItemInstance_checksDefaultValues() {
|
||||||
MediaItem mediaItem = new MediaItem.Builder().build();
|
MediaItem mediaItem = new MediaItem.Builder().build();
|
||||||
|
@ -724,7 +724,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) -> iSession.setMediaItem(controllerStub, seq, mediaItem.toBundle()));
|
(iSession, seq) ->
|
||||||
|
iSession.setMediaItem(
|
||||||
|
controllerStub, seq, mediaItem.toBundleIncludeLocalConfiguration()));
|
||||||
|
|
||||||
setMediaItemsInternal(
|
setMediaItemsInternal(
|
||||||
Collections.singletonList(mediaItem),
|
Collections.singletonList(mediaItem),
|
||||||
@ -742,7 +744,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) ->
|
(iSession, seq) ->
|
||||||
iSession.setMediaItemWithStartPosition(
|
iSession.setMediaItemWithStartPosition(
|
||||||
controllerStub, seq, mediaItem.toBundle(), startPositionMs));
|
controllerStub,
|
||||||
|
seq,
|
||||||
|
mediaItem.toBundleIncludeLocalConfiguration(),
|
||||||
|
startPositionMs));
|
||||||
|
|
||||||
setMediaItemsInternal(
|
setMediaItemsInternal(
|
||||||
Collections.singletonList(mediaItem),
|
Collections.singletonList(mediaItem),
|
||||||
@ -760,7 +765,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) ->
|
(iSession, seq) ->
|
||||||
iSession.setMediaItemWithResetPosition(
|
iSession.setMediaItemWithResetPosition(
|
||||||
controllerStub, seq, mediaItem.toBundle(), resetPosition));
|
controllerStub, seq, mediaItem.toBundleIncludeLocalConfiguration(), resetPosition));
|
||||||
|
|
||||||
setMediaItemsInternal(
|
setMediaItemsInternal(
|
||||||
Collections.singletonList(mediaItem),
|
Collections.singletonList(mediaItem),
|
||||||
@ -780,7 +785,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
iSession.setMediaItems(
|
iSession.setMediaItems(
|
||||||
controllerStub,
|
controllerStub,
|
||||||
seq,
|
seq,
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems))));
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
|
||||||
|
|
||||||
setMediaItemsInternal(
|
setMediaItemsInternal(
|
||||||
mediaItems,
|
mediaItems,
|
||||||
@ -800,7 +807,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
iSession.setMediaItemsWithResetPosition(
|
iSession.setMediaItemsWithResetPosition(
|
||||||
controllerStub,
|
controllerStub,
|
||||||
seq,
|
seq,
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems)),
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)),
|
||||||
resetPosition));
|
resetPosition));
|
||||||
|
|
||||||
setMediaItemsInternal(
|
setMediaItemsInternal(
|
||||||
@ -821,7 +830,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
iSession.setMediaItemsWithStartIndex(
|
iSession.setMediaItemsWithStartIndex(
|
||||||
controllerStub,
|
controllerStub,
|
||||||
seq,
|
seq,
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems)),
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration)),
|
||||||
startIndex,
|
startIndex,
|
||||||
startPositionMs));
|
startPositionMs));
|
||||||
|
|
||||||
@ -860,7 +871,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) -> iSession.addMediaItem(controllerStub, seq, mediaItem.toBundle()));
|
(iSession, seq) ->
|
||||||
|
iSession.addMediaItem(
|
||||||
|
controllerStub, seq, mediaItem.toBundleIncludeLocalConfiguration()));
|
||||||
|
|
||||||
addMediaItemsInternal(
|
addMediaItemsInternal(
|
||||||
getCurrentTimeline().getWindowCount(), Collections.singletonList(mediaItem));
|
getCurrentTimeline().getWindowCount(), Collections.singletonList(mediaItem));
|
||||||
@ -875,7 +888,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
|
|
||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) ->
|
(iSession, seq) ->
|
||||||
iSession.addMediaItemWithIndex(controllerStub, seq, index, mediaItem.toBundle()));
|
iSession.addMediaItemWithIndex(
|
||||||
|
controllerStub, seq, index, mediaItem.toBundleIncludeLocalConfiguration()));
|
||||||
|
|
||||||
addMediaItemsInternal(index, Collections.singletonList(mediaItem));
|
addMediaItemsInternal(index, Collections.singletonList(mediaItem));
|
||||||
}
|
}
|
||||||
@ -891,7 +905,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
iSession.addMediaItems(
|
iSession.addMediaItems(
|
||||||
controllerStub,
|
controllerStub,
|
||||||
seq,
|
seq,
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems))));
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
|
||||||
|
|
||||||
addMediaItemsInternal(getCurrentTimeline().getWindowCount(), mediaItems);
|
addMediaItemsInternal(getCurrentTimeline().getWindowCount(), mediaItems);
|
||||||
}
|
}
|
||||||
@ -909,7 +925,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
controllerStub,
|
controllerStub,
|
||||||
seq,
|
seq,
|
||||||
index,
|
index,
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems))));
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration))));
|
||||||
|
|
||||||
addMediaItemsInternal(index, mediaItems);
|
addMediaItemsInternal(index, mediaItems);
|
||||||
}
|
}
|
||||||
@ -1193,9 +1211,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) -> {
|
(iSession, seq) -> {
|
||||||
if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) {
|
if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) {
|
||||||
iSession.replaceMediaItem(controllerStub, seq, index, mediaItem.toBundle());
|
iSession.replaceMediaItem(
|
||||||
|
controllerStub, seq, index, mediaItem.toBundleIncludeLocalConfiguration());
|
||||||
} else {
|
} else {
|
||||||
iSession.addMediaItemWithIndex(controllerStub, seq, index + 1, mediaItem.toBundle());
|
iSession.addMediaItemWithIndex(
|
||||||
|
controllerStub, seq, index + 1, mediaItem.toBundleIncludeLocalConfiguration());
|
||||||
iSession.removeMediaItem(controllerStub, seq, index);
|
iSession.removeMediaItem(controllerStub, seq, index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1213,7 +1233,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
dispatchRemoteSessionTaskWithPlayerCommand(
|
dispatchRemoteSessionTaskWithPlayerCommand(
|
||||||
(iSession, seq) -> {
|
(iSession, seq) -> {
|
||||||
IBinder mediaItemsBundleBinder =
|
IBinder mediaItemsBundleBinder =
|
||||||
new BundleListRetriever(BundleableUtil.toBundleList(mediaItems));
|
new BundleListRetriever(
|
||||||
|
BundleableUtil.toBundleList(
|
||||||
|
mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
|
||||||
if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) {
|
if (checkNotNull(connectedToken).getInterfaceVersion() >= 2) {
|
||||||
iSession.replaceMediaItems(
|
iSession.replaceMediaItems(
|
||||||
controllerStub, seq, fromIndex, toIndex, mediaItemsBundleBinder);
|
controllerStub, seq, fromIndex, toIndex, mediaItemsBundleBinder);
|
||||||
|
@ -1129,10 +1129,15 @@ public class MediaSession {
|
|||||||
* prepare or play media (for instance when browsing the catalogue and then selecting an item
|
* prepare or play media (for instance when browsing the catalogue and then selecting an item
|
||||||
* for preparation from Android Auto that is using the legacy Media1 library).
|
* for preparation from Android Auto that is using the legacy Media1 library).
|
||||||
*
|
*
|
||||||
* <p>Note that the requested {@linkplain MediaItem media items} don't have a {@link
|
* <p>By default, if and only if each of the provided {@linkplain MediaItem media items} has a
|
||||||
* MediaItem.LocalConfiguration} (for example, a URI) and need to be updated to make them
|
* set {@link MediaItem.LocalConfiguration} (for example, a URI), then the callback returns the
|
||||||
* playable by the underlying {@link Player}. Typically, this implementation should be able to
|
* list unaltered. Otherwise, the default implementation returns an {@link
|
||||||
* identify the correct item by its {@link MediaItem#mediaId} and/or the {@link
|
* UnsupportedOperationException}.
|
||||||
|
*
|
||||||
|
* <p>If the requested {@linkplain MediaItem media items} don't have a {@link
|
||||||
|
* MediaItem.LocalConfiguration}, they need to be updated to make them playable by the
|
||||||
|
* underlying {@link Player}. Typically, this callback would be overridden with implementation
|
||||||
|
* that identifies the correct item by its {@link MediaItem#mediaId} and/or the {@link
|
||||||
* MediaItem#requestMetadata}.
|
* MediaItem#requestMetadata}.
|
||||||
*
|
*
|
||||||
* <p>Return a {@link ListenableFuture} with the resolved {@link MediaItem media items}. You can
|
* <p>Return a {@link ListenableFuture} with the resolved {@link MediaItem media items}. You can
|
||||||
@ -1167,7 +1172,12 @@ public class MediaSession {
|
|||||||
*/
|
*/
|
||||||
default ListenableFuture<List<MediaItem>> onAddMediaItems(
|
default ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
return Futures.immediateFailedFuture(new UnsupportedOperationException());
|
for (MediaItem mediaItem : mediaItems) {
|
||||||
|
if (mediaItem.localConfiguration == null) {
|
||||||
|
return Futures.immediateFailedFuture(new UnsupportedOperationException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Futures.immediateFuture(mediaItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1181,11 +1191,16 @@ public class MediaSession {
|
|||||||
* the catalogue and then selecting an item for preparation from Android Auto that is using the
|
* the catalogue and then selecting an item for preparation from Android Auto that is using the
|
||||||
* legacy Media1 library).
|
* legacy Media1 library).
|
||||||
*
|
*
|
||||||
* <p>Note that the requested {@linkplain MediaItem media items} in the
|
* <p>By default, if and only if each of the provided {@linkplain MediaItem media items} has a
|
||||||
* MediaItemsWithStartPosition don't have a {@link MediaItem.LocalConfiguration} (for example, a
|
* set {@link MediaItem.LocalConfiguration} (for example, a URI), then the callback returns the
|
||||||
* URI) and need to be updated to make them playable by the underlying {@link Player}.
|
* list unaltered. Otherwise, the default implementation returns an {@link
|
||||||
* Typically, this implementation should be able to identify the correct item by its {@link
|
* UnsupportedOperationException}.
|
||||||
* MediaItem#mediaId} and/or the {@link MediaItem#requestMetadata}.
|
*
|
||||||
|
* <p>If the requested {@linkplain MediaItem media items} don't have a {@link
|
||||||
|
* MediaItem.LocalConfiguration}, they need to be updated to make them playable by the
|
||||||
|
* underlying {@link Player}. Typically, this callback would be overridden with implementation
|
||||||
|
* that identifies the correct item by its {@link MediaItem#mediaId} and/or the {@link
|
||||||
|
* MediaItem#requestMetadata}.
|
||||||
*
|
*
|
||||||
* <p>Return a {@link ListenableFuture} with the resolved {@linkplain
|
* <p>Return a {@link ListenableFuture} with the resolved {@linkplain
|
||||||
* MediaItemsWithStartPosition media items and starting index and position}. You can also return
|
* MediaItemsWithStartPosition media items and starting index and position}. You can also return
|
||||||
|
@ -377,6 +377,85 @@ public class MediaSessionCallbackTest {
|
|||||||
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItemsDefault_withSetMediaItemIncludeLocalConfiguration_mediaItemDoesntContainLocalConfiguration_noItemsSet()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration = createMediaItem("mediaId");
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.setMediaItemIncludeLocalConfiguration(mediaItemWithoutLocalConfiguration);
|
||||||
|
|
||||||
|
Thread.sleep(NO_RESPONSE_TIMEOUT_MS);
|
||||||
|
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(player.mediaItems).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItemsDefault_withSetMediaItemsIncludeLocalConfiguration_mediaItemsDontContainLocalConfiguration_noItemsSet()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration1 = createMediaItem("mediaId1");
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration2 = createMediaItem("mediaId2");
|
||||||
|
List<MediaItem> mediaItemsWithoutLocalConfiguration =
|
||||||
|
ImmutableList.of(mediaItemWithoutLocalConfiguration1, mediaItemWithoutLocalConfiguration2);
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.setMediaItemsIncludeLocalConfiguration(mediaItemsWithoutLocalConfiguration);
|
||||||
|
|
||||||
|
Thread.sleep(NO_RESPONSE_TIMEOUT_MS);
|
||||||
|
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION))
|
||||||
|
.isFalse();
|
||||||
|
assertThat(player.mediaItems).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItemsDefault_withSetMediaItemIncludeLocalConfiguration_mediaItemContainsLocalConfiguration_itemSet()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
|
MediaItem mediaItemWithLocalConfiguration = updateMediaItemWithLocalConfiguration(mediaItem);
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.setMediaItemIncludeLocalConfiguration(mediaItemWithLocalConfiguration);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION, TIMEOUT_MS);
|
||||||
|
|
||||||
|
assertThat(player.mediaItems).containsExactly(mediaItemWithLocalConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItemsDefault_withSetMediaItemsIncludeLocalConfiguration_mediaItemsContainLocalConfiguration_itemsSet()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItem1 = createMediaItem("mediaId1");
|
||||||
|
MediaItem mediaItem2 = createMediaItem("mediaId2");
|
||||||
|
List<MediaItem> fullMediaItems =
|
||||||
|
updateMediaItemsWithLocalConfiguration(ImmutableList.of(mediaItem1, mediaItem2));
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.setMediaItemsIncludeLocalConfiguration(fullMediaItems);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION, TIMEOUT_MS);
|
||||||
|
|
||||||
|
assertThat(player.mediaItems).containsExactlyElementsIn(fullMediaItems).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onAddMediaItems_withSetMediaItemWithStartPosition() throws Exception {
|
public void onAddMediaItems_withSetMediaItemWithStartPosition() throws Exception {
|
||||||
MediaItem mediaItem = createMediaItem("mediaId");
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
@ -551,6 +630,83 @@ public class MediaSessionCallbackTest {
|
|||||||
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItems_withAddMediaItemIncludeLocalConfiguration_mediaItemDoesntContainLocalConfiguration_noItemsAdded()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration = createMediaItem("mediaId");
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.addMediaItemIncludeLocalConfiguration(mediaItemWithoutLocalConfiguration);
|
||||||
|
|
||||||
|
Thread.sleep(NO_RESPONSE_TIMEOUT_MS);
|
||||||
|
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS)).isFalse();
|
||||||
|
assertThat(player.mediaItems).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItems_withAddMediaItemsIncludeLocalConfiguration_mediaItemsDontContainLocalConfiguration_noItemsAdded()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration1 = createMediaItem("mediaId1");
|
||||||
|
MediaItem mediaItemWithoutLocalConfiguration2 = createMediaItem("mediaId2");
|
||||||
|
List<MediaItem> mediaItemsWithoutLocalConfiguration =
|
||||||
|
ImmutableList.of(mediaItemWithoutLocalConfiguration1, mediaItemWithoutLocalConfiguration2);
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.addMediaItemsIncludeLocalConfiguration(mediaItemsWithoutLocalConfiguration);
|
||||||
|
|
||||||
|
Thread.sleep(NO_RESPONSE_TIMEOUT_MS);
|
||||||
|
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS)).isFalse();
|
||||||
|
assertThat(player.mediaItems).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItems_withAddMediaItemIncludeLocalConfiguration_mediaItemContainsLocalConfiguration_itemAdded()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
|
MediaItem mediaItemWithLocalConfiguration = updateMediaItemWithLocalConfiguration(mediaItem);
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.addMediaItemIncludeLocalConfiguration(mediaItemWithLocalConfiguration);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
|
|
||||||
|
assertThat(player.mediaItems).containsExactly(mediaItemWithLocalConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
onAddMediaItems_withAddMediaItemsIncludeLocalConfiguration_mediaItemsContainLocalConfiguration_itemsAdded()
|
||||||
|
throws Exception {
|
||||||
|
MediaItem mediaItem1 = createMediaItem("mediaId1");
|
||||||
|
MediaItem mediaItem2 = createMediaItem("mediaId2");
|
||||||
|
List<MediaItem> fullMediaItems =
|
||||||
|
updateMediaItemsWithLocalConfiguration(ImmutableList.of(mediaItem1, mediaItem2));
|
||||||
|
MediaSession session =
|
||||||
|
sessionTestRule.ensureReleaseAfterTest(new MediaSession.Builder(context, player).build());
|
||||||
|
RemoteMediaController controller =
|
||||||
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
|
// Default MediaSession.Callback.onAddMediaItems will be called
|
||||||
|
controller.addMediaItemsIncludeLocalConfiguration(fullMediaItems);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
|
|
||||||
|
assertThat(player.mediaItems).containsAtLeastElementsIn(fullMediaItems).inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onAddMediaItems_withAddMediaItemWithIndex() throws Exception {
|
public void onAddMediaItems_withAddMediaItemWithIndex() throws Exception {
|
||||||
MediaItem existingItem = createMediaItem("existingItem");
|
MediaItem existingItem = createMediaItem("existingItem");
|
||||||
|
@ -144,6 +144,10 @@ public class RemoteMediaController {
|
|||||||
binder.setMediaItem(controllerId, mediaItem.toBundle());
|
binder.setMediaItem(controllerId, mediaItem.toBundle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMediaItemIncludeLocalConfiguration(MediaItem mediaItem) throws RemoteException {
|
||||||
|
binder.setMediaItem(controllerId, mediaItem.toBundleIncludeLocalConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
public void setMediaItem(MediaItem mediaItem, long startPositionMs) throws RemoteException {
|
public void setMediaItem(MediaItem mediaItem, long startPositionMs) throws RemoteException {
|
||||||
binder.setMediaItemWithStartPosition(controllerId, mediaItem.toBundle(), startPositionMs);
|
binder.setMediaItemWithStartPosition(controllerId, mediaItem.toBundle(), startPositionMs);
|
||||||
}
|
}
|
||||||
@ -156,6 +160,13 @@ public class RemoteMediaController {
|
|||||||
binder.setMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
|
binder.setMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
|
||||||
|
throws RemoteException {
|
||||||
|
binder.setMediaItems(
|
||||||
|
controllerId,
|
||||||
|
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
|
||||||
|
}
|
||||||
|
|
||||||
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition)
|
public void setMediaItems(List<MediaItem> mediaItems, boolean resetPosition)
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
binder.setMediaItemsWithResetPosition(
|
binder.setMediaItemsWithResetPosition(
|
||||||
@ -186,6 +197,10 @@ public class RemoteMediaController {
|
|||||||
binder.addMediaItem(controllerId, mediaItem.toBundle());
|
binder.addMediaItem(controllerId, mediaItem.toBundle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addMediaItemIncludeLocalConfiguration(MediaItem mediaItem) throws RemoteException {
|
||||||
|
binder.addMediaItem(controllerId, mediaItem.toBundleIncludeLocalConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
public void addMediaItem(int index, MediaItem mediaItem) throws RemoteException {
|
public void addMediaItem(int index, MediaItem mediaItem) throws RemoteException {
|
||||||
binder.addMediaItemWithIndex(controllerId, index, mediaItem.toBundle());
|
binder.addMediaItemWithIndex(controllerId, index, mediaItem.toBundle());
|
||||||
}
|
}
|
||||||
@ -194,6 +209,13 @@ public class RemoteMediaController {
|
|||||||
binder.addMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
|
binder.addMediaItems(controllerId, BundleableUtil.toBundleList(mediaItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addMediaItemsIncludeLocalConfiguration(List<MediaItem> mediaItems)
|
||||||
|
throws RemoteException {
|
||||||
|
binder.addMediaItems(
|
||||||
|
controllerId,
|
||||||
|
BundleableUtil.toBundleList(mediaItems, MediaItem::toBundleIncludeLocalConfiguration));
|
||||||
|
}
|
||||||
|
|
||||||
public void addMediaItems(int index, List<MediaItem> mediaItems) throws RemoteException {
|
public void addMediaItems(int index, List<MediaItem> mediaItems) throws RemoteException {
|
||||||
binder.addMediaItemsWithIndex(controllerId, index, BundleableUtil.toBundleList(mediaItems));
|
binder.addMediaItemsWithIndex(controllerId, index, BundleableUtil.toBundleList(mediaItems));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user