Replace MediaItemFiller by asynchronous callback.
The MediaItemFiller is not flexible enough for most realworld usages because: - it doesn't allow asynchronous resolution of MediaItems (e.g. to look up URIs from a database) - it doesn't allow to batch updates for multiple items or do more advanced customizations (e.g. expanding a mediaId representing a playlist to multiple items). Both issues can be solved by passing in a list of items and returning a ListenableFuture. The callback itself can also move into MediaSession.Callback for consistency with the other callbacks. PiperOrigin-RevId: 451857319
This commit is contained in:
parent
342be88d81
commit
6b782d1011
@ -129,6 +129,9 @@
|
|||||||
`MediaLibrarySession.MediaLibrarySessionCallback` to
|
`MediaLibrarySession.MediaLibrarySessionCallback` to
|
||||||
`MediaLibrarySession.Callback` and
|
`MediaLibrarySession.Callback` and
|
||||||
`MediaSession.Builder.setSessionCallback` to `setCallback`.
|
`MediaSession.Builder.setSessionCallback` to `setCallback`.
|
||||||
|
* Replace `MediaSession.MediaItemFiler` with
|
||||||
|
`MediaSession.Callback.onAddMediaItems` to allow asynchronous resolution
|
||||||
|
of requests.
|
||||||
* Data sources:
|
* Data sources:
|
||||||
* Rename `DummyDataSource` to `PlaceHolderDataSource`.
|
* Rename `DummyDataSource` to `PlaceHolderDataSource`.
|
||||||
* Workaround OkHttp interrupt handling.
|
* Workaround OkHttp interrupt handling.
|
||||||
|
@ -202,6 +202,16 @@ class PlaybackService : MediaLibraryService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAddMediaItems(
|
||||||
|
mediaSession: MediaSession,
|
||||||
|
controller: MediaSession.ControllerInfo,
|
||||||
|
mediaItems: List<MediaItem>
|
||||||
|
): ListenableFuture<List<MediaItem>> {
|
||||||
|
val updatedMediaItems: List<MediaItem> =
|
||||||
|
mediaItems.map { mediaItem -> MediaItemTree.getItem(mediaItem.mediaId) ?: mediaItem }
|
||||||
|
return Futures.immediateFuture(updatedMediaItems)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setMediaItemFromSearchQuery(query: String) {
|
private fun setMediaItemFromSearchQuery(query: String) {
|
||||||
// Only accept query with pattern "play [Title]" or "[Title]"
|
// Only accept query with pattern "play [Title]" or "[Title]"
|
||||||
// Where [Title]: must be exactly matched
|
// Where [Title]: must be exactly matched
|
||||||
@ -236,7 +246,6 @@ class PlaybackService : MediaLibraryService() {
|
|||||||
|
|
||||||
mediaLibrarySession =
|
mediaLibrarySession =
|
||||||
MediaLibrarySession.Builder(this, player, librarySessionCallback)
|
MediaLibrarySession.Builder(this, player, librarySessionCallback)
|
||||||
.setMediaItemFiller(CustomMediaItemFiller())
|
|
||||||
.setSessionActivity(sessionActivityPendingIntent)
|
.setSessionActivity(sessionActivityPendingIntent)
|
||||||
.build()
|
.build()
|
||||||
if (!customLayout.isEmpty()) {
|
if (!customLayout.isEmpty()) {
|
||||||
@ -262,14 +271,4 @@ class PlaybackService : MediaLibraryService() {
|
|||||||
private fun ignoreFuture(customLayout: ListenableFuture<SessionResult>) {
|
private fun ignoreFuture(customLayout: ListenableFuture<SessionResult>) {
|
||||||
/* Do nothing. */
|
/* Do nothing. */
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CustomMediaItemFiller : MediaSession.MediaItemFiller {
|
|
||||||
override fun fillInLocalConfiguration(
|
|
||||||
session: MediaSession,
|
|
||||||
controller: ControllerInfo,
|
|
||||||
mediaItem: MediaItem
|
|
||||||
): MediaItem {
|
|
||||||
return MediaItemTree.getItem(mediaItem.mediaId) ?: mediaItem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -406,17 +406,6 @@ public abstract class MediaLibraryService extends MediaSessionService {
|
|||||||
return super.setId(id);
|
return super.setId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the logic used to fill in the fields of a {@link MediaItem}.
|
|
||||||
*
|
|
||||||
* @param mediaItemFiller The filler.
|
|
||||||
* @return The builder to allow chaining.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Builder setMediaItemFiller(MediaItemFiller mediaItemFiller) {
|
|
||||||
return super.setMediaItemFiller(mediaItemFiller);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an extra {@link Bundle} for the {@link MediaLibrarySession}. The {@link
|
* Sets an extra {@link Bundle} for the {@link MediaLibrarySession}. The {@link
|
||||||
* MediaLibrarySession#getToken()} session token} will have the {@link
|
* MediaLibrarySession#getToken()} session token} will have the {@link
|
||||||
@ -439,8 +428,7 @@ public abstract class MediaLibraryService extends MediaSessionService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MediaLibrarySession build() {
|
public MediaLibrarySession build() {
|
||||||
return new MediaLibrarySession(
|
return new MediaLibrarySession(context, id, player, sessionActivity, callback, extras);
|
||||||
context, id, player, sessionActivity, callback, mediaItemFiller, extras);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,9 +438,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
MediaSession.Callback callback,
|
MediaSession.Callback callback,
|
||||||
MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
super(context, id, player, sessionActivity, callback, mediaItemFiller, tokenExtras);
|
super(context, id, player, sessionActivity, callback, tokenExtras);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -462,17 +449,9 @@ public abstract class MediaLibraryService extends MediaSessionService {
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
MediaSession.Callback callback,
|
MediaSession.Callback callback,
|
||||||
MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
return new MediaLibrarySessionImpl(
|
return new MediaLibrarySessionImpl(
|
||||||
this,
|
this, context, id, player, sessionActivity, (Callback) callback, tokenExtras);
|
||||||
context,
|
|
||||||
id,
|
|
||||||
player,
|
|
||||||
sessionActivity,
|
|
||||||
(Callback) callback,
|
|
||||||
mediaItemFiller,
|
|
||||||
tokenExtras);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,9 +63,8 @@ import java.util.concurrent.Future;
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
MediaLibrarySession.Callback callback,
|
MediaLibrarySession.Callback callback,
|
||||||
MediaSession.MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
super(instance, context, id, player, sessionActivity, callback, mediaItemFiller, tokenExtras);
|
super(instance, context, id, player, sessionActivity, callback, tokenExtras);
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
subscriptions = new ArrayMap<>();
|
subscriptions = new ArrayMap<>();
|
||||||
|
@ -293,18 +293,6 @@ public class MediaSession {
|
|||||||
return super.setCallback(callback);
|
return super.setCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the logic used to fill in the fields of a {@link MediaItem} from {@link
|
|
||||||
* MediaController}.
|
|
||||||
*
|
|
||||||
* @param mediaItemFiller The filler.
|
|
||||||
* @return The builder to allow chaining.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Builder setMediaItemFiller(MediaItemFiller mediaItemFiller) {
|
|
||||||
return super.setMediaItemFiller(mediaItemFiller);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an extra {@link Bundle} for the {@link MediaSession}. The {@link
|
* Sets an extra {@link Bundle} for the {@link MediaSession}. The {@link
|
||||||
* MediaSession#getToken()} session token} will have the {@link SessionToken#getExtras()
|
* MediaSession#getToken()} session token} will have the {@link SessionToken#getExtras()
|
||||||
@ -327,8 +315,7 @@ public class MediaSession {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MediaSession build() {
|
public MediaSession build() {
|
||||||
return new MediaSession(
|
return new MediaSession(context, id, player, sessionActivity, callback, extras);
|
||||||
context, id, player, sessionActivity, callback, mediaItemFiller, extras);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,7 +471,6 @@ public class MediaSession {
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
synchronized (STATIC_LOCK) {
|
synchronized (STATIC_LOCK) {
|
||||||
if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) {
|
if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) {
|
||||||
@ -492,7 +478,7 @@ public class MediaSession {
|
|||||||
}
|
}
|
||||||
SESSION_ID_TO_SESSION_MAP.put(id, this);
|
SESSION_ID_TO_SESSION_MAP.put(id, this);
|
||||||
}
|
}
|
||||||
impl = createImpl(context, id, player, sessionActivity, callback, mediaItemFiller, tokenExtras);
|
impl = createImpl(context, id, player, sessionActivity, callback, tokenExtras);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ MediaSessionImpl createImpl(
|
/* package */ MediaSessionImpl createImpl(
|
||||||
@ -501,10 +487,8 @@ public class MediaSession {
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
Callback callback,
|
Callback callback,
|
||||||
MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
return new MediaSessionImpl(
|
return new MediaSessionImpl(this, context, id, player, sessionActivity, callback, tokenExtras);
|
||||||
this, context, id, player, sessionActivity, callback, mediaItemFiller, tokenExtras);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ MediaSessionImpl getImpl() {
|
/* package */ MediaSessionImpl getImpl() {
|
||||||
@ -1041,23 +1025,29 @@ public class MediaSession {
|
|||||||
Bundle args) {
|
Bundle args) {
|
||||||
return Futures.immediateFuture(new SessionResult(RESULT_ERROR_NOT_SUPPORTED));
|
return Futures.immediateFuture(new SessionResult(RESULT_ERROR_NOT_SUPPORTED));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** An object which fills in the fields of a {@link MediaItem} from {@link MediaController}. */
|
|
||||||
public interface MediaItemFiller {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to fill in the {@link MediaItem#localConfiguration} of the media item from
|
* Called when a controller requested to add new {@linkplain MediaItem media items} to the
|
||||||
* controllers.
|
* playlist.
|
||||||
*
|
*
|
||||||
* @param session The session for this event.
|
* <p>Note that the requested {@linkplain MediaItem media items} don't have a {@link
|
||||||
|
* MediaItem.LocalConfiguration} (for example, a URI) and need to be updated to make them
|
||||||
|
* playable by the underlying {@link Player}. Typically, this implementation should be able to
|
||||||
|
* identify the correct item by its {@link MediaItem#mediaId} and/or the {@link
|
||||||
|
* MediaItem#requestMetadata}.
|
||||||
|
*
|
||||||
|
* <p>Return a {@link ListenableFuture} with the resolved {@link MediaItem media items}. You can
|
||||||
|
* also return the items directly by using Guava's {@link Futures#immediateFuture(Object)}.
|
||||||
|
*
|
||||||
|
* @param mediaSession The session for this event.
|
||||||
* @param controller The controller information.
|
* @param controller The controller information.
|
||||||
* @param mediaItem The media item whose local configuration will be filled in.
|
* @param mediaItems The list of requested {@link MediaItem media items}.
|
||||||
* @return A media item with filled local configuration.
|
* @return A {@link ListenableFuture} for the list of resolved {@link MediaItem media items}
|
||||||
|
* that are playable by the underlying {@link Player}.
|
||||||
*/
|
*/
|
||||||
default MediaItem fillInLocalConfiguration(
|
default ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
MediaSession session, MediaSession.ControllerInfo controller, MediaItem mediaItem) {
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
return mediaItem;
|
return Futures.immediateFailedFuture(new UnsupportedOperationException());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,7 +1220,6 @@ public class MediaSession {
|
|||||||
/* package */ final Player player;
|
/* package */ final Player player;
|
||||||
/* package */ String id;
|
/* package */ String id;
|
||||||
/* package */ C callback;
|
/* package */ C callback;
|
||||||
/* package */ MediaItemFiller mediaItemFiller;
|
|
||||||
/* package */ @Nullable PendingIntent sessionActivity;
|
/* package */ @Nullable PendingIntent sessionActivity;
|
||||||
/* package */ Bundle extras;
|
/* package */ Bundle extras;
|
||||||
|
|
||||||
@ -1240,7 +1229,6 @@ public class MediaSession {
|
|||||||
checkArgument(player.canAdvertiseSession());
|
checkArgument(player.canAdvertiseSession());
|
||||||
id = "";
|
id = "";
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.mediaItemFiller = new MediaItemFiller() {};
|
|
||||||
extras = Bundle.EMPTY;
|
extras = Bundle.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1262,12 +1250,6 @@ public class MediaSession {
|
|||||||
return (U) this;
|
return (U) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
/* package */ U setMediaItemFiller(MediaItemFiller mediaItemFiller) {
|
|
||||||
this.mediaItemFiller = checkNotNull(mediaItemFiller);
|
|
||||||
return (U) this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public U setExtras(Bundle extras) {
|
public U setExtras(Bundle extras) {
|
||||||
this.extras = new Bundle(checkNotNull(extras));
|
this.extras = new Bundle(checkNotNull(extras));
|
||||||
|
@ -67,7 +67,6 @@ import androidx.media3.common.util.Log;
|
|||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.session.MediaSession.ControllerCb;
|
import androidx.media3.session.MediaSession.ControllerCb;
|
||||||
import androidx.media3.session.MediaSession.ControllerInfo;
|
import androidx.media3.session.MediaSession.ControllerInfo;
|
||||||
import androidx.media3.session.MediaSession.MediaItemFiller;
|
|
||||||
import androidx.media3.session.SequencedFutureManager.SequencedFuture;
|
import androidx.media3.session.SequencedFutureManager.SequencedFuture;
|
||||||
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;
|
||||||
@ -104,12 +103,8 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
|
||||||
private final Uri sessionUri;
|
private final Uri sessionUri;
|
||||||
|
|
||||||
private final PlayerInfoChangedHandler onPlayerInfoChangedHandler;
|
private final PlayerInfoChangedHandler onPlayerInfoChangedHandler;
|
||||||
|
|
||||||
private final MediaSession.Callback callback;
|
private final MediaSession.Callback callback;
|
||||||
private final MediaItemFiller mediaItemFiller;
|
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MediaSessionStub sessionStub;
|
private final MediaSessionStub sessionStub;
|
||||||
private final MediaSessionLegacyStub sessionLegacyStub;
|
private final MediaSessionLegacyStub sessionLegacyStub;
|
||||||
@ -143,7 +138,6 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
Player player,
|
Player player,
|
||||||
@Nullable PendingIntent sessionActivity,
|
@Nullable PendingIntent sessionActivity,
|
||||||
MediaSession.Callback callback,
|
MediaSession.Callback callback,
|
||||||
MediaItemFiller mediaItemFiller,
|
|
||||||
Bundle tokenExtras) {
|
Bundle tokenExtras) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
@ -157,7 +151,6 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
|
|
||||||
applicationHandler = new Handler(player.getApplicationLooper());
|
applicationHandler = new Handler(player.getApplicationLooper());
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.mediaItemFiller = mediaItemFiller;
|
|
||||||
|
|
||||||
playerInfo = PlayerInfo.DEFAULT;
|
playerInfo = PlayerInfo.DEFAULT;
|
||||||
onPlayerInfoChangedHandler = new PlayerInfoChangedHandler(player.getApplicationLooper());
|
onPlayerInfoChangedHandler = new PlayerInfoChangedHandler(player.getApplicationLooper());
|
||||||
@ -495,9 +488,11 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||||||
return applicationHandler;
|
return applicationHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MediaItem fillInLocalConfiguration(
|
protected ListenableFuture<List<MediaItem>> onAddMediaItemsOnHandler(
|
||||||
MediaSession.ControllerInfo controller, MediaItem mediaItem) {
|
ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
return mediaItemFiller.fillInLocalConfiguration(instance, controller, mediaItem);
|
return checkNotNull(
|
||||||
|
callback.onAddMediaItems(instance, controller, mediaItems),
|
||||||
|
"onAddMediaItems must return a non-null future");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isReleased() {
|
protected boolean isReleased() {
|
||||||
|
@ -147,6 +147,36 @@ import java.util.concurrent.ExecutionException;
|
|||||||
MoreExecutors.directExecutor());
|
MoreExecutors.directExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <K extends MediaSessionImpl> void handleMediaItemsWhenReady(
|
||||||
|
K sessionImpl,
|
||||||
|
ControllerInfo controller,
|
||||||
|
int seq,
|
||||||
|
ListenableFuture<List<MediaItem>> future,
|
||||||
|
MediaItemPlayerTask mediaItemPlayerTask) {
|
||||||
|
future.addListener(
|
||||||
|
() -> {
|
||||||
|
SessionResult result;
|
||||||
|
try {
|
||||||
|
List<MediaItem> mediaItems =
|
||||||
|
checkNotNull(future.get(), "MediaItem list must not be null");
|
||||||
|
postOrRun(
|
||||||
|
sessionImpl.getApplicationHandler(),
|
||||||
|
() -> mediaItemPlayerTask.run(sessionImpl.getPlayerWrapper(), mediaItems));
|
||||||
|
result = new SessionResult(SessionResult.RESULT_SUCCESS);
|
||||||
|
} catch (CancellationException unused) {
|
||||||
|
result = new SessionResult(SessionResult.RESULT_INFO_SKIPPED);
|
||||||
|
} catch (ExecutionException | InterruptedException exception) {
|
||||||
|
result =
|
||||||
|
new SessionResult(
|
||||||
|
exception.getCause() instanceof UnsupportedOperationException
|
||||||
|
? SessionResult.RESULT_ERROR_NOT_SUPPORTED
|
||||||
|
: SessionResult.RESULT_ERROR_UNKNOWN);
|
||||||
|
}
|
||||||
|
sendSessionResult(sessionImpl, controller, seq, result);
|
||||||
|
},
|
||||||
|
MoreExecutors.directExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
private static void sendLibraryResult(
|
private static void sendLibraryResult(
|
||||||
ControllerInfo controller, int seq, LibraryResult<?> result) {
|
ControllerInfo controller, int seq, LibraryResult<?> result) {
|
||||||
try {
|
try {
|
||||||
@ -816,13 +846,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)),
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
(sessionImpl, controller, sequence, future) ->
|
||||||
sessionImpl.getPlayerWrapper().setMediaItem(mediaItemWithPlaybackProperties);
|
handleMediaItemsWhenReady(
|
||||||
return SessionResult.RESULT_SUCCESS;
|
sessionImpl, controller, sequence, future, Player::setMediaItems));
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -845,15 +873,16 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)),
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
(sessionImpl, controller, sequence, future) ->
|
||||||
sessionImpl
|
handleMediaItemsWhenReady(
|
||||||
.getPlayerWrapper()
|
sessionImpl,
|
||||||
.setMediaItem(mediaItemWithPlaybackProperties, startPositionMs);
|
controller,
|
||||||
return SessionResult.RESULT_SUCCESS;
|
sequence,
|
||||||
},
|
future,
|
||||||
MediaSessionStub::sendSessionResult);
|
(player, mediaItems) ->
|
||||||
|
player.setMediaItems(mediaItems, /* startIndex= */ 0, startPositionMs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -876,15 +905,15 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)),
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
(sessionImpl, controller, sequence, future) ->
|
||||||
sessionImpl
|
handleMediaItemsWhenReady(
|
||||||
.getPlayerWrapper()
|
sessionImpl,
|
||||||
.setMediaItem(mediaItemWithPlaybackProperties, resetPosition);
|
controller,
|
||||||
return SessionResult.RESULT_SUCCESS;
|
sequence,
|
||||||
},
|
future,
|
||||||
MediaSessionStub::sendSessionResult);
|
(player, mediaItems) -> player.setMediaItems(mediaItems, resetPosition)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -907,20 +936,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
ImmutableList.Builder<MediaItem> mediaItemWithPlaybackPropertiesListBuilder =
|
sessionImpl.onAddMediaItemsOnHandler(controller, mediaItemList),
|
||||||
ImmutableList.builder();
|
(sessionImpl, controller, sequence, future) ->
|
||||||
for (MediaItem mediaItem : mediaItemList) {
|
handleMediaItemsWhenReady(
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl, controller, sequence, future, Player::setMediaItems));
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
|
||||||
mediaItemWithPlaybackPropertiesListBuilder.add(mediaItemWithPlaybackProperties);
|
|
||||||
}
|
|
||||||
sessionImpl
|
|
||||||
.getPlayerWrapper()
|
|
||||||
.setMediaItems(mediaItemWithPlaybackPropertiesListBuilder.build());
|
|
||||||
return SessionResult.RESULT_SUCCESS;
|
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -945,20 +965,15 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
ImmutableList.Builder<MediaItem> mediaItemWithPlaybackPropertiesListBuilder =
|
sessionImpl.onAddMediaItemsOnHandler(controller, mediaItemList),
|
||||||
ImmutableList.builder();
|
(sessionImpl, controller, sequence, future) ->
|
||||||
for (MediaItem mediaItem : mediaItemList) {
|
handleMediaItemsWhenReady(
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl,
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
controller,
|
||||||
mediaItemWithPlaybackPropertiesListBuilder.add(mediaItemWithPlaybackProperties);
|
sequence,
|
||||||
}
|
future,
|
||||||
sessionImpl
|
(player, mediaItems) -> player.setMediaItems(mediaItems, resetPosition)));
|
||||||
.getPlayerWrapper()
|
|
||||||
.setMediaItems(mediaItemWithPlaybackPropertiesListBuilder.build(), resetPosition);
|
|
||||||
return SessionResult.RESULT_SUCCESS;
|
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -984,22 +999,16 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
ImmutableList.Builder<MediaItem> mediaItemWithPlaybackPropertiesListBuilder =
|
sessionImpl.onAddMediaItemsOnHandler(controller, mediaItemList),
|
||||||
ImmutableList.builder();
|
(sessionImpl, controller, sequence, future) ->
|
||||||
for (MediaItem mediaItem : mediaItemList) {
|
handleMediaItemsWhenReady(
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl,
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
controller,
|
||||||
mediaItemWithPlaybackPropertiesListBuilder.add(mediaItemWithPlaybackProperties);
|
sequence,
|
||||||
}
|
future,
|
||||||
|
(player, mediaItems) ->
|
||||||
sessionImpl
|
player.setMediaItems(mediaItems, startIndex, startPositionMs)));
|
||||||
.getPlayerWrapper()
|
|
||||||
.setMediaItems(
|
|
||||||
mediaItemWithPlaybackPropertiesListBuilder.build(), startIndex, startPositionMs);
|
|
||||||
return SessionResult.RESULT_SUCCESS;
|
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1057,13 +1066,11 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)),
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
(sessionImpl, controller, sequence, future) ->
|
||||||
sessionImpl.getPlayerWrapper().addMediaItem(mediaItemWithPlaybackProperties);
|
handleMediaItemsWhenReady(
|
||||||
return SessionResult.RESULT_SUCCESS;
|
sessionImpl, controller, sequence, future, Player::addMediaItems));
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1083,13 +1090,15 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) ->
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
sessionImpl.onAddMediaItemsOnHandler(controller, ImmutableList.of(mediaItem)),
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
(sessionImpl, controller, sequence, future) ->
|
||||||
sessionImpl.getPlayerWrapper().addMediaItem(index, mediaItemWithPlaybackProperties);
|
handleMediaItemsWhenReady(
|
||||||
return SessionResult.RESULT_SUCCESS;
|
sessionImpl,
|
||||||
},
|
controller,
|
||||||
MediaSessionStub::sendSessionResult);
|
sequence,
|
||||||
|
future,
|
||||||
|
(player, mediaItems) -> player.addMediaItems(index, mediaItems)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1111,21 +1120,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) -> sessionImpl.onAddMediaItemsOnHandler(controller, mediaItems),
|
||||||
ImmutableList.Builder<MediaItem> mediaItemsWithPlaybackPropertiesBuilder =
|
(sessionImpl, controller, sequence, future) ->
|
||||||
ImmutableList.builder();
|
handleMediaItemsWhenReady(
|
||||||
for (MediaItem mediaItem : mediaItems) {
|
sessionImpl, controller, sequence, future, Player::addMediaItems));
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
|
||||||
mediaItemsWithPlaybackPropertiesBuilder.add(mediaItemWithPlaybackProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionImpl
|
|
||||||
.getPlayerWrapper()
|
|
||||||
.addMediaItems(mediaItemsWithPlaybackPropertiesBuilder.build());
|
|
||||||
return SessionResult.RESULT_SUCCESS;
|
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1150,21 +1148,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
(sessionImpl, controller) -> {
|
(sessionImpl, controller) -> sessionImpl.onAddMediaItemsOnHandler(controller, mediaItems),
|
||||||
ImmutableList.Builder<MediaItem> mediaItemsWithPlaybackPropertiesBuilder =
|
(sessionImpl, controller, sequence, future) ->
|
||||||
ImmutableList.builder();
|
handleMediaItemsWhenReady(
|
||||||
for (MediaItem mediaItem : mediaItems) {
|
sessionImpl,
|
||||||
MediaItem mediaItemWithPlaybackProperties =
|
controller,
|
||||||
sessionImpl.fillInLocalConfiguration(controller, mediaItem);
|
sequence,
|
||||||
mediaItemsWithPlaybackPropertiesBuilder.add(mediaItemWithPlaybackProperties);
|
future,
|
||||||
}
|
(player, items) -> player.addMediaItems(index, items)));
|
||||||
|
|
||||||
sessionImpl
|
|
||||||
.getPlayerWrapper()
|
|
||||||
.addMediaItems(index, mediaItemsWithPlaybackPropertiesBuilder.build());
|
|
||||||
return SessionResult.RESULT_SUCCESS;
|
|
||||||
},
|
|
||||||
MediaSessionStub::sendSessionResult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1709,6 +1700,10 @@ import java.util.concurrent.ExecutionException;
|
|||||||
void run(K sessionImpl, ControllerInfo controller, int seq, T result);
|
void run(K sessionImpl, ControllerInfo controller, int seq, T result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface MediaItemPlayerTask {
|
||||||
|
void run(PlayerWrapper player, List<MediaItem> mediaItems);
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ static final class Controller2Cb implements ControllerCb {
|
/* package */ static final class Controller2Cb implements ControllerCb {
|
||||||
|
|
||||||
private final IMediaController iController;
|
private final IMediaController iController;
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.session;
|
package androidx.media3.session;
|
||||||
|
|
||||||
|
import static androidx.media3.session.MediaTestUtils.createMediaItem;
|
||||||
import static androidx.media3.session.SessionResult.RESULT_ERROR_INVALID_STATE;
|
import static androidx.media3.session.SessionResult.RESULT_ERROR_INVALID_STATE;
|
||||||
import static androidx.media3.session.SessionResult.RESULT_INFO_SKIPPED;
|
import static androidx.media3.session.SessionResult.RESULT_INFO_SKIPPED;
|
||||||
import static androidx.media3.session.SessionResult.RESULT_SUCCESS;
|
import static androidx.media3.session.SessionResult.RESULT_SUCCESS;
|
||||||
|
import static androidx.media3.test.session.common.CommonConstants.METADATA_MEDIA_URI;
|
||||||
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
|
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
|
||||||
import static androidx.media3.test.session.common.TestUtils.NO_RESPONSE_TIMEOUT_MS;
|
import static androidx.media3.test.session.common.TestUtils.NO_RESPONSE_TIMEOUT_MS;
|
||||||
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
||||||
@ -39,12 +41,18 @@ import androidx.media3.test.session.common.TestUtils;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
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.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@ -68,6 +76,7 @@ public class MediaSessionCallbackTest {
|
|||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private MockPlayer player;
|
private MockPlayer player;
|
||||||
|
private ListeningExecutorService executorService;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -76,6 +85,14 @@ public class MediaSessionCallbackTest {
|
|||||||
new MockPlayer.Builder()
|
new MockPlayer.Builder()
|
||||||
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
||||||
.build();
|
.build();
|
||||||
|
// Intentionally use an Executor with another thread to test asynchronous workflows involving
|
||||||
|
// background tasks.
|
||||||
|
executorService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
executorService.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -335,168 +352,301 @@ public class MediaSessionCallbackTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItem() throws Exception {
|
public void onAddMediaItems_withSetMediaItem() throws Exception {
|
||||||
MediaItem mediaItem = MediaTestUtils.createMediaItem("mediaId");
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
MockFillInLocalConfigurationCallback callback =
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 1);
|
MediaSession.Callback callback =
|
||||||
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItem(mediaItem);
|
controller.setMediaItem(mediaItem);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactly(mediaItem);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactly(mediaItem);
|
||||||
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItemWithIndex() throws Exception {
|
public void onAddMediaItems_withSetMediaItemWithIndex() throws Exception {
|
||||||
MediaItem mediaItem = MediaTestUtils.createMediaItem("mediaId");
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
MockFillInLocalConfigurationCallback callback =
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 1);
|
MediaSession.Callback callback =
|
||||||
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItem(mediaItem, /* startPositionMs= */ 0);
|
controller.setMediaItem(mediaItem, /* startPositionMs= */ 1234);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_START_INDEX, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactly(mediaItem);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactly(mediaItem);
|
||||||
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
|
assertThat(player.startMediaItemIndex).isEqualTo(0);
|
||||||
|
assertThat(player.startPositionMs).isEqualTo(1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItemWithResetPosition() throws Exception {
|
public void onAddMediaItems_withSetMediaItemWithResetPosition() throws Exception {
|
||||||
MediaItem mediaItem = MediaTestUtils.createMediaItem("mediaId");
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
MockFillInLocalConfigurationCallback callback =
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 1);
|
MediaSession.Callback callback =
|
||||||
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItem(mediaItem, /* resetPosition= */ true);
|
controller.setMediaItem(mediaItem, /* resetPosition= */ true);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactly(mediaItem);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactly(mediaItem);
|
||||||
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
|
assertThat(player.resetPosition).isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItems() throws Exception {
|
public void onAddMediaItems_withSetMediaItems() throws Exception {
|
||||||
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaSession.Callback callback =
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 3);
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItems(mediaItems);
|
controller.setMediaItems(mediaItems);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactlyElementsIn(mediaItems);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactlyElementsIn(updateMediaItemsWithLocalConfiguration(mediaItems))
|
||||||
|
.inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItemsWithStartPosition() throws Exception {
|
public void onAddMediaItems_withSetMediaItemsWithStartPosition() throws Exception {
|
||||||
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaSession.Callback callback =
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 3);
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItems(mediaItems, /* startWindowIndex= */ 0, /* startPositionMs= */ 0);
|
controller.setMediaItems(mediaItems, /* startWindowIndex= */ 1, /* startPositionMs= */ 1234);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_START_INDEX, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactlyElementsIn(mediaItems);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactlyElementsIn(updateMediaItemsWithLocalConfiguration(mediaItems))
|
||||||
|
.inOrder();
|
||||||
|
assertThat(player.startMediaItemIndex).isEqualTo(1);
|
||||||
|
assertThat(player.startPositionMs).isEqualTo(1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_setMediaItemsWithResetPosition() throws Exception {
|
public void onAddMediaItems_withSetMediaItemsWithResetPosition() throws Exception {
|
||||||
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaSession.Callback callback =
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 3);
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.setMediaItems(mediaItems, /* resetPosition= */ true);
|
controller.setMediaItems(mediaItems, /* resetPosition= */ true);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS_WITH_RESET_POSITION, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactlyElementsIn(mediaItems);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactlyElementsIn(updateMediaItemsWithLocalConfiguration(mediaItems))
|
||||||
|
.inOrder();
|
||||||
|
assertThat(player.resetPosition).isEqualTo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_addMediaItem() throws Exception {
|
public void onAddMediaItems_withAddMediaItem() throws Exception {
|
||||||
MediaItem mediaItem = MediaTestUtils.createMediaItem("mediaId");
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
MockFillInLocalConfigurationCallback callback =
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 1);
|
MediaSession.Callback callback =
|
||||||
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.addMediaItem(mediaItem);
|
controller.addMediaItem(mediaItem);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactly(mediaItem);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactly(mediaItem);
|
||||||
|
assertThat(player.mediaItems).containsExactly(updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_addMediaItemWithIndex() throws Exception {
|
public void onAddMediaItems_withAddMediaItemWithIndex() throws Exception {
|
||||||
MediaItem mediaItem = MediaTestUtils.createMediaItem("mediaId");
|
MediaItem existingItem = createMediaItem("existingItem");
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaItem mediaItem = createMediaItem("mediaId");
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 1);
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
|
MediaSession.Callback callback =
|
||||||
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
controller.setMediaItem(existingItem);
|
||||||
|
|
||||||
controller.addMediaItem(/* index= */ 0, mediaItem);
|
controller.addMediaItem(/* index= */ 1, mediaItem);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS_WITH_INDEX, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactly(mediaItem);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactly(mediaItem);
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactly(
|
||||||
|
updateMediaItemWithLocalConfiguration(existingItem),
|
||||||
|
updateMediaItemWithLocalConfiguration(mediaItem));
|
||||||
|
assertThat(player.index).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_addMediaItems() throws Exception {
|
public void onAddMediaItems_withAddMediaItems() throws Exception {
|
||||||
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaSession.Callback callback =
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 3);
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
|
||||||
controller.addMediaItems(mediaItems);
|
controller.addMediaItems(mediaItems);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactlyElementsIn(mediaItems);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactlyElementsIn(updateMediaItemsWithLocalConfiguration(mediaItems))
|
||||||
|
.inOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onFillInPlaybackProperties_addMediaItemsWithIndex() throws Exception {
|
public void onAddMediaItems_withAddMediaItemsWithIndex() throws Exception {
|
||||||
|
MediaItem existingItem = createMediaItem("existingItem");
|
||||||
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
List<MediaItem> mediaItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
AtomicReference<List<MediaItem>> requestedMediaItems = new AtomicReference<>();
|
||||||
MockFillInLocalConfigurationCallback callback =
|
MediaSession.Callback callback =
|
||||||
new MockFillInLocalConfigurationCallback(/* latchCount= */ 3);
|
new MediaSession.Callback() {
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||||
|
requestedMediaItems.set(mediaItems);
|
||||||
|
// Resolve MediaItems asynchronously to test correct threading logic.
|
||||||
|
return executorService.submit(() -> updateMediaItemsWithLocalConfiguration(mediaItems));
|
||||||
|
}
|
||||||
|
};
|
||||||
MediaSession session =
|
MediaSession session =
|
||||||
sessionTestRule.ensureReleaseAfterTest(
|
sessionTestRule.ensureReleaseAfterTest(
|
||||||
new MediaSession.Builder(context, player).setMediaItemFiller(callback).build());
|
new MediaSession.Builder(context, player).setCallback(callback).build());
|
||||||
RemoteMediaController controller =
|
RemoteMediaController controller =
|
||||||
controllerTestRule.createRemoteController(session.getToken());
|
controllerTestRule.createRemoteController(session.getToken());
|
||||||
|
controller.setMediaItem(existingItem);
|
||||||
|
|
||||||
controller.addMediaItems(/* index= */ 0, mediaItems);
|
controller.addMediaItems(/* index= */ 1, mediaItems);
|
||||||
assertThat(callback.latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS_WITH_INDEX, TIMEOUT_MS);
|
||||||
assertThat(callback.mediaItemsFromParam).containsExactlyElementsIn(mediaItems);
|
|
||||||
|
assertThat(requestedMediaItems.get()).containsExactlyElementsIn(mediaItems).inOrder();
|
||||||
|
assertThat(player.mediaItems)
|
||||||
|
.containsExactlyElementsIn(
|
||||||
|
Iterables.concat(
|
||||||
|
ImmutableList.of(updateMediaItemWithLocalConfiguration(existingItem)),
|
||||||
|
updateMediaItemsWithLocalConfiguration(mediaItems)))
|
||||||
|
.inOrder();
|
||||||
|
assertThat(player.index).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -556,22 +706,16 @@ public class MediaSessionCallbackTest {
|
|||||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockFillInLocalConfigurationCallback
|
private static MediaItem updateMediaItemWithLocalConfiguration(MediaItem mediaItem) {
|
||||||
implements MediaSession.MediaItemFiller {
|
return mediaItem.buildUpon().setUri(METADATA_MEDIA_URI).build();
|
||||||
|
|
||||||
public final List<MediaItem> mediaItemsFromParam = new ArrayList<>();
|
|
||||||
public CountDownLatch latch;
|
|
||||||
|
|
||||||
public MockFillInLocalConfigurationCallback(int latchCount) {
|
|
||||||
this.latch = new CountDownLatch(latchCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static List<MediaItem> updateMediaItemsWithLocalConfiguration(
|
||||||
public MediaItem fillInLocalConfiguration(
|
List<MediaItem> mediaItems) {
|
||||||
MediaSession session, ControllerInfo controllerInfo, MediaItem mediaItem) {
|
ImmutableList.Builder<MediaItem> listBuilder = ImmutableList.builder();
|
||||||
mediaItemsFromParam.add(mediaItem);
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
latch.countDown();
|
listBuilder.add(updateMediaItemWithLocalConfiguration(mediaItems.get(i)));
|
||||||
return mediaItem;
|
|
||||||
}
|
}
|
||||||
|
return listBuilder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@ import androidx.media3.test.session.common.TestUtils;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -76,6 +78,14 @@ public class MediaSessionPlayerTest {
|
|||||||
}
|
}
|
||||||
return MediaSession.ConnectionResult.reject();
|
return MediaSession.ConnectionResult.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||||
|
MediaSession mediaSession,
|
||||||
|
MediaSession.ControllerInfo controller,
|
||||||
|
List<MediaItem> mediaItems) {
|
||||||
|
return Futures.immediateFuture(mediaItems);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -197,7 +207,7 @@ public class MediaSessionPlayerTest {
|
|||||||
|
|
||||||
controller.setMediaItem(item);
|
controller.setMediaItem(item);
|
||||||
|
|
||||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEM, TIMEOUT_MS);
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(player.mediaItems).containsExactly(item);
|
assertThat(player.mediaItems).containsExactly(item);
|
||||||
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
||||||
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
||||||
@ -213,7 +223,7 @@ public class MediaSessionPlayerTest {
|
|||||||
|
|
||||||
controller.setMediaItem(item);
|
controller.setMediaItem(item);
|
||||||
|
|
||||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEM, TIMEOUT_MS);
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(player.mediaItems).containsExactly(item);
|
assertThat(player.mediaItems).containsExactly(item);
|
||||||
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
||||||
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
||||||
@ -229,7 +239,7 @@ public class MediaSessionPlayerTest {
|
|||||||
|
|
||||||
controller.setMediaItem(item);
|
controller.setMediaItem(item);
|
||||||
|
|
||||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEM, TIMEOUT_MS);
|
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(player.mediaItems).containsExactly(item);
|
assertThat(player.mediaItems).containsExactly(item);
|
||||||
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
assertThat(player.startPositionMs).isEqualTo(startPositionMs);
|
||||||
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
assertThat(player.resetPosition).isEqualTo(resetPosition);
|
||||||
@ -317,7 +327,7 @@ public class MediaSessionPlayerTest {
|
|||||||
|
|
||||||
controller.addMediaItem(mediaItem);
|
controller.addMediaItem(mediaItem);
|
||||||
|
|
||||||
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEM, TIMEOUT_MS);
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS, TIMEOUT_MS);
|
||||||
assertThat(player.mediaItems).hasSize(6);
|
assertThat(player.mediaItems).hasSize(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +338,7 @@ public class MediaSessionPlayerTest {
|
|||||||
|
|
||||||
controller.addMediaItem(index, mediaItem);
|
controller.addMediaItem(index, mediaItem);
|
||||||
|
|
||||||
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEM_WITH_INDEX, TIMEOUT_MS);
|
player.awaitMethodCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS_WITH_INDEX, TIMEOUT_MS);
|
||||||
assertThat(player.index).isEqualTo(index);
|
assertThat(player.index).isEqualTo(index);
|
||||||
assertThat(player.mediaItems).hasSize(6);
|
assertThat(player.mediaItems).hasSize(6);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user