Run MediaSessionStub commands in order
Some commands are run asynchronously and subsequent commands need to wait until the previous one finished. This can be supported by returning a Future for each command and using the existing command execution logic to wait for each Future to complete. As some MediaSessionStub code is now executed delayed to when it was originally created, we also need to check if the session is not released before triggering any actions or sending result codes. Issue: androidx/media#85 PiperOrigin-RevId: 462101136
This commit is contained in:
parent
45f1f5b378
commit
7cb7636ed9
@ -15,6 +15,10 @@
|
|||||||
`MetadataRenderer(MetadataOutput, Looper, MetadataDecoderFactory,
|
`MetadataRenderer(MetadataOutput, Looper, MetadataDecoderFactory,
|
||||||
boolean)` to specify whether the renderer will output metadata early or
|
boolean)` to specify whether the renderer will output metadata early or
|
||||||
in sync with the player position.
|
in sync with the player position.
|
||||||
|
* Session:
|
||||||
|
* Ensure commands are always executed in the correct order even if some
|
||||||
|
require asynchronous resolution
|
||||||
|
([#85](https://github.com/androidx/media/issues/85)).
|
||||||
|
|
||||||
### 1.0.0-beta02 (2022-07-15)
|
### 1.0.0-beta02 (2022-07-15)
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import androidx.collection.ArrayMap;
|
|||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.session.MediaSession.ControllerInfo;
|
import androidx.media3.session.MediaSession.ControllerInfo;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.Futures;
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
@ -227,15 +226,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addToCommandQueue(ControllerInfo controllerInfo, Runnable commandRunnable) {
|
public void addToCommandQueue(ControllerInfo controllerInfo, AsyncCommand asyncCommand) {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@Nullable ConnectedControllerRecord<T> info = controllerRecords.get(controllerInfo);
|
@Nullable ConnectedControllerRecord<T> info = controllerRecords.get(controllerInfo);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
info.commandQueue.add(
|
info.commandQueue.add(asyncCommand);
|
||||||
() -> {
|
|
||||||
commandRunnable.run();
|
|
||||||
return Futures.immediateVoidFuture();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,10 @@ import androidx.media3.session.MediaSession.ControllerCb;
|
|||||||
import androidx.media3.session.MediaSession.ControllerInfo;
|
import androidx.media3.session.MediaSession.ControllerInfo;
|
||||||
import androidx.media3.session.SessionCommand.CommandCode;
|
import androidx.media3.session.SessionCommand.CommandCode;
|
||||||
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.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -126,21 +128,29 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <K extends MediaSessionImpl> SessionTask<Void, K> sendSessionResultSuccess(
|
private static <K extends MediaSessionImpl>
|
||||||
|
SessionTask<ListenableFuture<Void>, K> sendSessionResultSuccess(
|
||||||
Consumer<PlayerWrapper> task) {
|
Consumer<PlayerWrapper> task) {
|
||||||
return (sessionImpl, controller, sequence) -> {
|
return (sessionImpl, controller, sequence) -> {
|
||||||
|
if (sessionImpl.isReleased()) {
|
||||||
|
return Futures.immediateVoidFuture();
|
||||||
|
}
|
||||||
task.accept(sessionImpl.getPlayerWrapper());
|
task.accept(sessionImpl.getPlayerWrapper());
|
||||||
sendSessionResult(controller, sequence, new SessionResult(SessionResult.RESULT_SUCCESS));
|
sendSessionResult(controller, sequence, new SessionResult(SessionResult.RESULT_SUCCESS));
|
||||||
return null;
|
return Futures.immediateVoidFuture();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <K extends MediaSessionImpl> SessionTask<Void, K> sendSessionResultWhenReady(
|
private static <K extends MediaSessionImpl>
|
||||||
|
SessionTask<ListenableFuture<Void>, K> sendSessionResultWhenReady(
|
||||||
SessionTask<ListenableFuture<SessionResult>, K> task) {
|
SessionTask<ListenableFuture<SessionResult>, K> task) {
|
||||||
return (sessionImpl, controller, sequence) -> {
|
return (sessionImpl, controller, sequence) ->
|
||||||
ListenableFuture<SessionResult> future = task.run(sessionImpl, controller, sequence);
|
handleSessionTaskWhenReady(
|
||||||
future.addListener(
|
sessionImpl,
|
||||||
() -> {
|
controller,
|
||||||
|
sequence,
|
||||||
|
task,
|
||||||
|
future -> {
|
||||||
SessionResult result;
|
SessionResult result;
|
||||||
try {
|
try {
|
||||||
result = checkNotNull(future.get(), "SessionResult must not be null");
|
result = checkNotNull(future.get(), "SessionResult must not be null");
|
||||||
@ -154,24 +164,30 @@ import java.util.concurrent.ExecutionException;
|
|||||||
: SessionResult.RESULT_ERROR_UNKNOWN);
|
: SessionResult.RESULT_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
sendSessionResult(controller, sequence, result);
|
sendSessionResult(controller, sequence, result);
|
||||||
},
|
});
|
||||||
MoreExecutors.directExecutor());
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <K extends MediaSessionImpl>
|
private static <K extends MediaSessionImpl>
|
||||||
SessionTask<ListenableFuture<SessionResult>, K> handleMediaItemsWhenReady(
|
SessionTask<ListenableFuture<SessionResult>, K> handleMediaItemsWhenReady(
|
||||||
SessionTask<ListenableFuture<List<MediaItem>>, K> mediaItemsTask,
|
SessionTask<ListenableFuture<List<MediaItem>>, K> mediaItemsTask,
|
||||||
MediaItemPlayerTask mediaItemPlayerTask) {
|
MediaItemPlayerTask mediaItemPlayerTask) {
|
||||||
return (sessionImpl, controller, sequence) ->
|
return (sessionImpl, controller, sequence) -> {
|
||||||
transformFutureAsync(
|
if (sessionImpl.isReleased()) {
|
||||||
|
return Futures.immediateFuture(
|
||||||
|
new SessionResult(SessionResult.RESULT_ERROR_SESSION_DISCONNECTED));
|
||||||
|
}
|
||||||
|
return transformFutureAsync(
|
||||||
mediaItemsTask.run(sessionImpl, controller, sequence),
|
mediaItemsTask.run(sessionImpl, controller, sequence),
|
||||||
mediaItems ->
|
mediaItems ->
|
||||||
postOrRunWithCompletion(
|
postOrRunWithCompletion(
|
||||||
sessionImpl.getApplicationHandler(),
|
sessionImpl.getApplicationHandler(),
|
||||||
() -> mediaItemPlayerTask.run(sessionImpl.getPlayerWrapper(), mediaItems),
|
() -> {
|
||||||
|
if (!sessionImpl.isReleased()) {
|
||||||
|
mediaItemPlayerTask.run(sessionImpl.getPlayerWrapper(), mediaItems);
|
||||||
|
}
|
||||||
|
},
|
||||||
new SessionResult(SessionResult.RESULT_SUCCESS)));
|
new SessionResult(SessionResult.RESULT_SUCCESS)));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendLibraryResult(
|
private static void sendLibraryResult(
|
||||||
@ -184,12 +200,15 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static <V, K extends MediaLibrarySessionImpl>
|
private static <V, K extends MediaLibrarySessionImpl>
|
||||||
SessionTask<Void, K> sendLibraryResultWhenReady(
|
SessionTask<ListenableFuture<Void>, K> sendLibraryResultWhenReady(
|
||||||
SessionTask<ListenableFuture<LibraryResult<V>>, K> task) {
|
SessionTask<ListenableFuture<LibraryResult<V>>, K> task) {
|
||||||
return (sessionImpl, controller, sequence) -> {
|
return (sessionImpl, controller, sequence) ->
|
||||||
ListenableFuture<LibraryResult<V>> future = task.run(sessionImpl, controller, sequence);
|
handleSessionTaskWhenReady(
|
||||||
future.addListener(
|
sessionImpl,
|
||||||
() -> {
|
controller,
|
||||||
|
sequence,
|
||||||
|
task,
|
||||||
|
future -> {
|
||||||
LibraryResult<V> result;
|
LibraryResult<V> result;
|
||||||
try {
|
try {
|
||||||
result = checkNotNull(future.get(), "LibraryResult must not be null");
|
result = checkNotNull(future.get(), "LibraryResult must not be null");
|
||||||
@ -199,14 +218,14 @@ import java.util.concurrent.ExecutionException;
|
|||||||
result = LibraryResult.ofError(LibraryResult.RESULT_ERROR_UNKNOWN);
|
result = LibraryResult.ofError(LibraryResult.RESULT_ERROR_UNKNOWN);
|
||||||
}
|
}
|
||||||
sendLibraryResult(controller, sequence, result);
|
sendLibraryResult(controller, sequence, result);
|
||||||
},
|
});
|
||||||
MoreExecutors.directExecutor());
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <K extends MediaSessionImpl> void dispatchSessionTaskWithPlayerCommand(
|
private <K extends MediaSessionImpl> void queueSessionTaskWithPlayerCommand(
|
||||||
IMediaController caller, int seq, @Player.Command int command, SessionTask<Void, K> task) {
|
IMediaController caller,
|
||||||
|
int seq,
|
||||||
|
@Player.Command int command,
|
||||||
|
SessionTask<ListenableFuture<Void>, K> task) {
|
||||||
long token = Binder.clearCallingIdentity();
|
long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings({"unchecked", "cast.unsafe"})
|
@SuppressWarnings({"unchecked", "cast.unsafe"})
|
||||||
@ -248,13 +267,19 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <K extends MediaSessionImpl> void dispatchSessionTaskWithSessionCommand(
|
private <K extends MediaSessionImpl> void dispatchSessionTaskWithSessionCommand(
|
||||||
IMediaController caller, int seq, @CommandCode int commandCode, SessionTask<Void, K> task) {
|
IMediaController caller,
|
||||||
|
int seq,
|
||||||
|
@CommandCode int commandCode,
|
||||||
|
SessionTask<ListenableFuture<Void>, K> task) {
|
||||||
dispatchSessionTaskWithSessionCommand(
|
dispatchSessionTaskWithSessionCommand(
|
||||||
caller, seq, /* sessionCommand= */ null, commandCode, task);
|
caller, seq, /* sessionCommand= */ null, commandCode, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <K extends MediaSessionImpl> void dispatchSessionTaskWithSessionCommand(
|
private <K extends MediaSessionImpl> void dispatchSessionTaskWithSessionCommand(
|
||||||
IMediaController caller, int seq, SessionCommand sessionCommand, SessionTask<Void, K> task) {
|
IMediaController caller,
|
||||||
|
int seq,
|
||||||
|
SessionCommand sessionCommand,
|
||||||
|
SessionTask<ListenableFuture<Void>, K> task) {
|
||||||
dispatchSessionTaskWithSessionCommand(caller, seq, sessionCommand, COMMAND_CODE_CUSTOM, task);
|
dispatchSessionTaskWithSessionCommand(caller, seq, sessionCommand, COMMAND_CODE_CUSTOM, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +288,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
int seq,
|
int seq,
|
||||||
@Nullable SessionCommand sessionCommand,
|
@Nullable SessionCommand sessionCommand,
|
||||||
@CommandCode int commandCode,
|
@CommandCode int commandCode,
|
||||||
SessionTask<Void, K> task) {
|
SessionTask<ListenableFuture<Void>, K> task) {
|
||||||
long token = Binder.clearCallingIdentity();
|
long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings({"unchecked", "cast.unsafe"})
|
@SuppressWarnings({"unchecked", "cast.unsafe"})
|
||||||
@ -308,6 +333,34 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T, K extends MediaSessionImpl> ListenableFuture<Void> handleSessionTaskWhenReady(
|
||||||
|
K sessionImpl,
|
||||||
|
ControllerInfo controller,
|
||||||
|
int sequence,
|
||||||
|
SessionTask<ListenableFuture<T>, K> task,
|
||||||
|
Consumer<ListenableFuture<T>> futureResultHandler) {
|
||||||
|
if (sessionImpl.isReleased()) {
|
||||||
|
return Futures.immediateVoidFuture();
|
||||||
|
}
|
||||||
|
ListenableFuture<T> future = task.run(sessionImpl, controller, sequence);
|
||||||
|
SettableFuture<Void> outputFuture = SettableFuture.create();
|
||||||
|
future.addListener(
|
||||||
|
() -> {
|
||||||
|
if (sessionImpl.isReleased()) {
|
||||||
|
outputFuture.set(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
futureResultHandler.accept(future);
|
||||||
|
outputFuture.set(null);
|
||||||
|
} catch (Throwable error) {
|
||||||
|
outputFuture.setException(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MoreExecutors.directExecutor());
|
||||||
|
return outputFuture;
|
||||||
|
}
|
||||||
|
|
||||||
public void connect(
|
public void connect(
|
||||||
IMediaController caller,
|
IMediaController caller,
|
||||||
int controllerVersion,
|
int controllerVersion,
|
||||||
@ -480,7 +533,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_STOP, sendSessionResultSuccess(Player::stop));
|
caller, seq, COMMAND_STOP, sendSessionResultSuccess(Player::stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +582,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_PLAY_PAUSE, sendSessionResultSuccess(Player::play));
|
caller, seq, COMMAND_PLAY_PAUSE, sendSessionResultSuccess(Player::play));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,7 +591,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_PLAY_PAUSE, sendSessionResultSuccess(Player::pause));
|
caller, seq, COMMAND_PLAY_PAUSE, sendSessionResultSuccess(Player::pause));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,7 +600,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_PREPARE, sendSessionResultSuccess(Player::prepare));
|
caller, seq, COMMAND_PREPARE, sendSessionResultSuccess(Player::prepare));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +609,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_TO_DEFAULT_POSITION,
|
COMMAND_SEEK_TO_DEFAULT_POSITION,
|
||||||
@ -569,7 +622,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_TO_MEDIA_ITEM,
|
COMMAND_SEEK_TO_MEDIA_ITEM,
|
||||||
@ -582,7 +635,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
|
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
|
||||||
@ -596,7 +649,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_TO_MEDIA_ITEM,
|
COMMAND_SEEK_TO_MEDIA_ITEM,
|
||||||
@ -608,7 +661,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_SEEK_BACK, sendSessionResultSuccess(Player::seekBack));
|
caller, seq, COMMAND_SEEK_BACK, sendSessionResultSuccess(Player::seekBack));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,7 +670,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_SEEK_FORWARD, sendSessionResultSuccess(Player::seekForward));
|
caller, seq, COMMAND_SEEK_FORWARD, sendSessionResultSuccess(Player::seekForward));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,7 +751,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_SPEED_AND_PITCH,
|
COMMAND_SET_SPEED_AND_PITCH,
|
||||||
@ -713,7 +766,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
}
|
}
|
||||||
PlaybackParameters playbackParameters =
|
PlaybackParameters playbackParameters =
|
||||||
PlaybackParameters.CREATOR.fromBundle(playbackParametersBundle);
|
PlaybackParameters.CREATOR.fromBundle(playbackParametersBundle);
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_SPEED_AND_PITCH,
|
COMMAND_SET_SPEED_AND_PITCH,
|
||||||
@ -733,7 +786,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_MEDIA_ITEM,
|
COMMAND_SET_MEDIA_ITEM,
|
||||||
@ -760,7 +813,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_MEDIA_ITEM,
|
COMMAND_SET_MEDIA_ITEM,
|
||||||
@ -788,7 +841,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_MEDIA_ITEM,
|
COMMAND_SET_MEDIA_ITEM,
|
||||||
@ -815,7 +868,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -844,7 +897,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -874,7 +927,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -899,7 +952,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaMetadata", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaMetadata", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_MEDIA_ITEMS_METADATA,
|
COMMAND_SET_MEDIA_ITEMS_METADATA,
|
||||||
@ -918,7 +971,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -942,7 +995,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -968,7 +1021,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -997,7 +1050,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
Log.w(TAG, "Ignoring malformed Bundle for MediaItem", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -1013,7 +1066,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -1026,7 +1079,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -1038,7 +1091,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_CHANGE_MEDIA_ITEMS, sendSessionResultSuccess(Player::clearMediaItems));
|
caller, seq, COMMAND_CHANGE_MEDIA_ITEMS, sendSessionResultSuccess(Player::clearMediaItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,7 +1101,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -1061,7 +1114,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_CHANGE_MEDIA_ITEMS,
|
COMMAND_CHANGE_MEDIA_ITEMS,
|
||||||
@ -1073,7 +1126,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
||||||
@ -1085,7 +1138,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||||
@ -1097,7 +1150,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_SEEK_TO_PREVIOUS, sendSessionResultSuccess(Player::seekToPrevious));
|
caller, seq, COMMAND_SEEK_TO_PREVIOUS, sendSessionResultSuccess(Player::seekToPrevious));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1106,7 +1159,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller, seq, COMMAND_SEEK_TO_NEXT, sendSessionResultSuccess(Player::seekToNext));
|
caller, seq, COMMAND_SEEK_TO_NEXT, sendSessionResultSuccess(Player::seekToNext));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,7 +1169,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_REPEAT_MODE,
|
COMMAND_SET_REPEAT_MODE,
|
||||||
@ -1129,7 +1182,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_SHUFFLE_MODE,
|
COMMAND_SET_SHUFFLE_MODE,
|
||||||
@ -1142,7 +1195,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_VIDEO_SURFACE,
|
COMMAND_SET_VIDEO_SURFACE,
|
||||||
@ -1154,7 +1207,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_VOLUME,
|
COMMAND_SET_VOLUME,
|
||||||
@ -1166,7 +1219,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_DEVICE_VOLUME,
|
COMMAND_SET_DEVICE_VOLUME,
|
||||||
@ -1178,7 +1231,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_ADJUST_DEVICE_VOLUME,
|
COMMAND_ADJUST_DEVICE_VOLUME,
|
||||||
@ -1190,7 +1243,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_ADJUST_DEVICE_VOLUME,
|
COMMAND_ADJUST_DEVICE_VOLUME,
|
||||||
@ -1202,7 +1255,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_DEVICE_VOLUME,
|
COMMAND_SET_DEVICE_VOLUME,
|
||||||
@ -1214,7 +1267,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
if (caller == null) {
|
if (caller == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_PLAY_PAUSE,
|
COMMAND_PLAY_PAUSE,
|
||||||
@ -1258,7 +1311,7 @@ import java.util.concurrent.ExecutionException;
|
|||||||
Log.w(TAG, "Ignoring malformed Bundle for TrackSelectionParameters", e);
|
Log.w(TAG, "Ignoring malformed Bundle for TrackSelectionParameters", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dispatchSessionTaskWithPlayerCommand(
|
queueSessionTaskWithPlayerCommand(
|
||||||
caller,
|
caller,
|
||||||
seq,
|
seq,
|
||||||
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
|
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
|
||||||
|
@ -81,6 +81,7 @@ interface IRemoteMediaController {
|
|||||||
void release(String controllerId);
|
void release(String controllerId);
|
||||||
void stop(String controllerId);
|
void stop(String controllerId);
|
||||||
void setTrackSelectionParameters(String controllerId, in Bundle parameters);
|
void setTrackSelectionParameters(String controllerId, in Bundle parameters);
|
||||||
|
void setMediaItemsPreparePlayAddItemsSeek(String controllerId, in List<Bundle> initialMediaItems, in List<Bundle> addedMediaItems, int seekIndex);
|
||||||
|
|
||||||
// MediaBrowser methods
|
// MediaBrowser methods
|
||||||
Bundle getLibraryRoot(String controllerId, in Bundle libraryParams);
|
Bundle getLibraryRoot(String controllerId, in Bundle libraryParams);
|
||||||
|
@ -19,19 +19,21 @@ import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PA
|
|||||||
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
import androidx.media3.common.DeviceInfo;
|
import androidx.media3.common.DeviceInfo;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MediaMetadata;
|
import androidx.media3.common.MediaMetadata;
|
||||||
import androidx.media3.common.PlaybackParameters;
|
import androidx.media3.common.PlaybackParameters;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.TrackSelectionParameters;
|
import androidx.media3.common.TrackSelectionParameters;
|
||||||
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
||||||
import androidx.media3.test.session.common.MainLooperTestRule;
|
import androidx.media3.test.session.common.MainLooperTestRule;
|
||||||
import androidx.media3.test.session.common.TestUtils;
|
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 com.google.common.util.concurrent.ListenableFuture;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@ -58,6 +60,7 @@ public class MediaSessionPlayerTest {
|
|||||||
private MediaSession session;
|
private MediaSession session;
|
||||||
private MockPlayer player;
|
private MockPlayer player;
|
||||||
private RemoteMediaController controller;
|
private RemoteMediaController controller;
|
||||||
|
private HandlerThread asyncHandlerThread;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@ -66,6 +69,9 @@ public class MediaSessionPlayerTest {
|
|||||||
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
||||||
.setMediaItems(/* itemCount= */ 5)
|
.setMediaItems(/* itemCount= */ 5)
|
||||||
.build();
|
.build();
|
||||||
|
asyncHandlerThread = new HandlerThread("AsyncHandlerThread");
|
||||||
|
asyncHandlerThread.start();
|
||||||
|
Handler asyncHandler = new Handler(asyncHandlerThread.getLooper());
|
||||||
session =
|
session =
|
||||||
new MediaSession.Builder(ApplicationProvider.getApplicationContext(), player)
|
new MediaSession.Builder(ApplicationProvider.getApplicationContext(), player)
|
||||||
.setCallback(
|
.setCallback(
|
||||||
@ -84,7 +90,9 @@ public class MediaSessionPlayerTest {
|
|||||||
MediaSession mediaSession,
|
MediaSession mediaSession,
|
||||||
MediaSession.ControllerInfo controller,
|
MediaSession.ControllerInfo controller,
|
||||||
List<MediaItem> mediaItems) {
|
List<MediaItem> mediaItems) {
|
||||||
return Futures.immediateFuture(mediaItems);
|
// Send empty message and return mediaItems once done to simulate asynchronous
|
||||||
|
// media item resolution.
|
||||||
|
return Util.postOrRunWithCompletion(asyncHandler, () -> {}, mediaItems);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
@ -97,6 +105,7 @@ public class MediaSessionPlayerTest {
|
|||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
controller.release();
|
controller.release();
|
||||||
session.release();
|
session.release();
|
||||||
|
asyncHandlerThread.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -544,6 +553,26 @@ public class MediaSessionPlayerTest {
|
|||||||
assertThat(player.trackSelectionParameters).isEqualTo(trackSelectionParameters);
|
assertThat(player.trackSelectionParameters).isEqualTo(trackSelectionParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mixedAsyncAndSyncCommands_calledInCorrectOrder() throws Exception {
|
||||||
|
List<MediaItem> initialItems = MediaTestUtils.createMediaItems(/* size= */ 2);
|
||||||
|
List<MediaItem> addedItems = MediaTestUtils.createMediaItems(/* size= */ 3);
|
||||||
|
|
||||||
|
controller.setMediaItemsPreparePlayAddItemsSeek(initialItems, addedItems, /* seekIndex= */ 3);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_PREPARE, TIMEOUT_MS);
|
||||||
|
boolean setMediaItemsCalledBeforePrepare =
|
||||||
|
player.hasMethodBeenCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS);
|
||||||
|
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_WITH_MEDIA_ITEM_INDEX, TIMEOUT_MS);
|
||||||
|
boolean addMediaItemsCalledBeforeSeek =
|
||||||
|
player.hasMethodBeenCalled(MockPlayer.METHOD_ADD_MEDIA_ITEMS);
|
||||||
|
|
||||||
|
assertThat(setMediaItemsCalledBeforePrepare).isTrue();
|
||||||
|
assertThat(addMediaItemsCalledBeforeSeek).isTrue();
|
||||||
|
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PLAY)).isTrue();
|
||||||
|
assertThat(player.mediaItems).hasSize(5);
|
||||||
|
assertThat(player.seekMediaItemIndex).isEqualTo(3);
|
||||||
|
}
|
||||||
|
|
||||||
private void changePlaybackTypeToRemote() throws Exception {
|
private void changePlaybackTypeToRemote() throws Exception {
|
||||||
threadTestRule
|
threadTestRule
|
||||||
.getHandler()
|
.getHandler()
|
||||||
|
@ -659,6 +659,26 @@ public class MediaControllerProviderService extends Service {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMediaItemsPreparePlayAddItemsSeek(
|
||||||
|
String controllerId,
|
||||||
|
List<Bundle> initialMediaItems,
|
||||||
|
List<Bundle> addedMediaItems,
|
||||||
|
int seekIndex)
|
||||||
|
throws RemoteException {
|
||||||
|
runOnHandler(
|
||||||
|
() -> {
|
||||||
|
MediaController controller = mediaControllerMap.get(controllerId);
|
||||||
|
controller.setMediaItems(
|
||||||
|
BundleableUtil.fromBundleList(MediaItem.CREATOR, initialMediaItems));
|
||||||
|
controller.prepare();
|
||||||
|
controller.play();
|
||||||
|
controller.addMediaItems(
|
||||||
|
BundleableUtil.fromBundleList(MediaItem.CREATOR, addedMediaItems));
|
||||||
|
controller.seekTo(seekIndex, /* positionMs= */ 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// MediaBrowser methods
|
// MediaBrowser methods
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -292,6 +292,16 @@ public class RemoteMediaController {
|
|||||||
binder.setTrackSelectionParameters(controllerId, parameters.toBundle());
|
binder.setTrackSelectionParameters(controllerId, parameters.toBundle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMediaItemsPreparePlayAddItemsSeek(
|
||||||
|
List<MediaItem> initialMediaItems, List<MediaItem> addedMediaItems, int seekIndex)
|
||||||
|
throws RemoteException {
|
||||||
|
binder.setMediaItemsPreparePlayAddItemsSeek(
|
||||||
|
controllerId,
|
||||||
|
BundleableUtil.toBundleList(initialMediaItems),
|
||||||
|
BundleableUtil.toBundleList(addedMediaItems),
|
||||||
|
seekIndex);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Non-public methods
|
// Non-public methods
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
x
Reference in New Issue
Block a user