Add MediaSession.getControllerForCurrentRequest
This is a helper method that can used to obtain information about the controller that is currently calling a Player method. PiperOrigin-RevId: 527268994
This commit is contained in:
parent
fab134f0b3
commit
3693ca4bbb
@ -53,11 +53,17 @@
|
||||
* Fix issue where `MediaController` doesn't update its available commands
|
||||
when connected to a legacy `MediaSessionCompat` that updates its
|
||||
actions.
|
||||
* Add helper method `MediaSession.getControllerForCurrentRequest` to
|
||||
obtain information about the controller that is currently calling
|
||||
a`Player` method.
|
||||
* UI:
|
||||
|
||||
* Add Util methods `shouldShowPlayButton` and
|
||||
`handlePlayPauseButtonAction` to write custom UI elements with a
|
||||
play/pause button.
|
||||
|
||||
* Audio:
|
||||
|
||||
* Fix bug where some playbacks fail when tunneling is enabled and
|
||||
`AudioProcessors` are active, e.g. for gapless trimming
|
||||
([#10847](https://github.com/google/ExoPlayer/issues/10847)).
|
||||
@ -76,10 +82,14 @@
|
||||
`onRendererCapabilitiesChanged` events.
|
||||
* Add `ChannelMixingAudioProcessor` for applying scaling/mixing to audio
|
||||
channels.
|
||||
|
||||
* Metadata:
|
||||
|
||||
* Deprecate `MediaMetadata.folderType` in favor of `isBrowsable` and
|
||||
`mediaType`.
|
||||
|
||||
* DRM:
|
||||
|
||||
* Reduce the visibility of several internal-only methods on
|
||||
`DefaultDrmSession` that aren't expected to be called from outside the
|
||||
DRM package:
|
||||
@ -87,7 +97,9 @@
|
||||
* `void provision()`
|
||||
* `void onProvisionCompleted()`
|
||||
* `onProvisionError(Exception, boolean)`
|
||||
|
||||
* Transformer:
|
||||
|
||||
* Remove `Transformer.Builder.setMediaSourceFactory(MediaSource.Factory)`.
|
||||
Use `ExoPlayerAssetLoader.Factory(MediaSource.Factory)` and
|
||||
`Transformer.Builder.setAssetLoaderFactory(AssetLoader.Factory)`
|
||||
@ -99,20 +111,30 @@
|
||||
an input frame was pending processing.
|
||||
* Query codecs via `MediaCodecList` instead of using
|
||||
`findDecoder/EncoderForFormat` utilities, to expand support.
|
||||
|
||||
* Muxer:
|
||||
|
||||
* Add a new muxer library which can be used to create an MP4 container
|
||||
file.
|
||||
|
||||
* DASH:
|
||||
|
||||
* Remove the media time offset from `MediaLoadData.startTimeMs` and
|
||||
`MediaLoadData.endTimeMs` for multi period DASH streams.
|
||||
|
||||
* RTSP:
|
||||
|
||||
* For MPEG4-LATM, use default profile-level-id value if absent in Describe
|
||||
Response SDP message
|
||||
([#302](https://github.com/androidx/media/issues/302)).
|
||||
|
||||
* IMA DAI extension:
|
||||
|
||||
* Fix a bug where a new ad group is inserted in live streams because the
|
||||
calculated content position in consecutive timelines varies slightly.
|
||||
|
||||
* Remove deprecated symbols:
|
||||
|
||||
* Remove `DefaultAudioSink` constructors, use `DefaultAudioSink.Builder`
|
||||
instead.
|
||||
* Remove `HlsMasterPlaylist`, use `HlsMultivariantPlaylist` instead.
|
||||
|
1
api.txt
1
api.txt
@ -1704,6 +1704,7 @@ package androidx.media3.session {
|
||||
@com.google.errorprone.annotations.DoNotMock public class MediaSession {
|
||||
method public final void broadcastCustomCommand(androidx.media3.session.SessionCommand, android.os.Bundle);
|
||||
method public final java.util.List<androidx.media3.session.MediaSession.ControllerInfo> getConnectedControllers();
|
||||
method @Nullable public final androidx.media3.session.MediaSession.ControllerInfo getControllerForCurrentRequest();
|
||||
method public final String getId();
|
||||
method public final androidx.media3.common.Player getPlayer();
|
||||
method @Nullable public final android.app.PendingIntent getSessionActivity();
|
||||
|
@ -259,6 +259,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
AtomicBoolean commandExecuting = new AtomicBoolean(true);
|
||||
postOrRun(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
sessionImpl.callWithControllerForCurrentRequestSet(
|
||||
getController(info.controllerKey),
|
||||
() ->
|
||||
asyncCommand
|
||||
.run()
|
||||
@ -272,7 +274,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
}
|
||||
}
|
||||
},
|
||||
MoreExecutors.directExecutor()));
|
||||
MoreExecutors.directExecutor())));
|
||||
commandExecuting.set(false);
|
||||
}
|
||||
}
|
||||
|
@ -660,6 +660,28 @@ public class MediaSession {
|
||||
return impl.getConnectedControllers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ControllerInfo} for the controller that sent the current request for a
|
||||
* {@link Player} method.
|
||||
*
|
||||
* <p>This method will return a non-null value while {@link Player} methods triggered by a
|
||||
* controller are executed.
|
||||
*
|
||||
* <p>Note: If you want to prevent a controller from calling a method, specify the {@link
|
||||
* ConnectionResult#availablePlayerCommands available commands} in {@link Callback#onConnect} or
|
||||
* set them via {@link #setAvailableCommands}.
|
||||
*
|
||||
* <p>This method must be called on the {@linkplain Player#getApplicationLooper() application
|
||||
* thread} of the underlying player.
|
||||
*
|
||||
* @return The {@link ControllerInfo} of the controller that sent the current request, or {@code
|
||||
* null} if not applicable.
|
||||
*/
|
||||
@Nullable
|
||||
public final ControllerInfo getControllerForCurrentRequest() {
|
||||
return impl.getControllerForCurrentRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that controllers set the ordered list of {@link CommandButton} to build UI with it.
|
||||
*
|
||||
|
@ -39,6 +39,7 @@ import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.FloatRange;
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -123,6 +124,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
|
||||
private PlayerInfo playerInfo;
|
||||
private PlayerWrapper playerWrapper;
|
||||
@Nullable private ControllerInfo controllerForCurrentRequest;
|
||||
|
||||
@GuardedBy("lock")
|
||||
@Nullable
|
||||
@ -278,6 +280,16 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
return playerWrapper;
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
public Runnable callWithControllerForCurrentRequestSet(
|
||||
@Nullable ControllerInfo controllerForCurrentRequest, Runnable runnable) {
|
||||
return () -> {
|
||||
this.controllerForCurrentRequest = controllerForCurrentRequest;
|
||||
runnable.run();
|
||||
this.controllerForCurrentRequest = null;
|
||||
};
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return sessionId;
|
||||
}
|
||||
@ -298,6 +310,11 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
return controllers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ControllerInfo getControllerForCurrentRequest() {
|
||||
return controllerForCurrentRequest;
|
||||
}
|
||||
|
||||
public boolean isConnected(ControllerInfo controller) {
|
||||
return sessionStub.getConnectedControllersManager().isConnected(controller)
|
||||
|| sessionLegacyStub.getConnectedControllersManager().isConnected(controller);
|
||||
|
@ -655,6 +655,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
return;
|
||||
}
|
||||
|
||||
sessionImpl
|
||||
.callWithControllerForCurrentRequestSet(
|
||||
controller,
|
||||
() -> {
|
||||
try {
|
||||
task.run(controller);
|
||||
} catch (RemoteException e) {
|
||||
@ -665,6 +669,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
// - DeadSystemException means that errors around it can be ignored.
|
||||
Log.w(TAG, "Exception in " + controller, e);
|
||||
}
|
||||
})
|
||||
.run();
|
||||
});
|
||||
}
|
||||
|
||||
@ -788,6 +794,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
public void onSuccess(MediaItemsWithStartPosition mediaItemsWithStartPosition) {
|
||||
postOrRun(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
sessionImpl.callWithControllerForCurrentRequestSet(
|
||||
controller,
|
||||
() -> {
|
||||
PlayerWrapper player = sessionImpl.getPlayerWrapper();
|
||||
MediaUtils.setMediaItemsWithStartIndexAndPosition(
|
||||
@ -801,7 +809,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
if (play) {
|
||||
player.playIfCommandAvailable();
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -836,13 +844,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
public void onSuccess(List<MediaItem> mediaItems) {
|
||||
postOrRun(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
sessionImpl.callWithControllerForCurrentRequestSet(
|
||||
controller,
|
||||
() -> {
|
||||
if (index == C.INDEX_UNSET) {
|
||||
sessionImpl.getPlayerWrapper().addMediaItems(mediaItems);
|
||||
} else {
|
||||
sessionImpl.getPlayerWrapper().addMediaItems(index, mediaItems);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -204,12 +204,14 @@ import java.util.concurrent.ExecutionException;
|
||||
mediaItems ->
|
||||
postOrRunWithCompletion(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
sessionImpl.callWithControllerForCurrentRequestSet(
|
||||
controller,
|
||||
() -> {
|
||||
if (!sessionImpl.isReleased()) {
|
||||
mediaItemPlayerTask.run(
|
||||
sessionImpl.getPlayerWrapper(), controller, mediaItems);
|
||||
}
|
||||
},
|
||||
}),
|
||||
new SessionResult(SessionResult.RESULT_SUCCESS)));
|
||||
};
|
||||
}
|
||||
@ -228,12 +230,14 @@ import java.util.concurrent.ExecutionException;
|
||||
mediaItemsWithStartPosition ->
|
||||
postOrRunWithCompletion(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
sessionImpl.callWithControllerForCurrentRequestSet(
|
||||
controller,
|
||||
() -> {
|
||||
if (!sessionImpl.isReleased()) {
|
||||
mediaItemPlayerTask.run(
|
||||
sessionImpl.getPlayerWrapper(), mediaItemsWithStartPosition);
|
||||
}
|
||||
},
|
||||
}),
|
||||
new SessionResult(SessionResult.RESULT_SUCCESS)));
|
||||
};
|
||||
}
|
||||
@ -305,7 +309,10 @@ import java.util.concurrent.ExecutionException;
|
||||
return;
|
||||
}
|
||||
if (command == COMMAND_SET_VIDEO_SURFACE) {
|
||||
task.run(sessionImpl, controller, sequenceNumber);
|
||||
sessionImpl
|
||||
.callWithControllerForCurrentRequestSet(
|
||||
controller, () -> task.run(sessionImpl, controller, sequenceNumber))
|
||||
.run();
|
||||
} else {
|
||||
connectedControllersManager.addToCommandQueue(
|
||||
controller, () -> task.run(sessionImpl, controller, sequenceNumber));
|
||||
|
@ -19,13 +19,20 @@ import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PA
|
||||
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.support.v4.media.MediaDescriptionCompat;
|
||||
import android.support.v4.media.session.MediaControllerCompat;
|
||||
import androidx.media3.common.DeviceInfo;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.common.PlaybackParameters;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.SimpleBasePlayer;
|
||||
import androidx.media3.common.TrackSelectionParameters;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
||||
@ -38,6 +45,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
@ -836,6 +845,318 @@ public class MediaSessionPlayerTest {
|
||||
assertThat(player.seekMediaItemIndex).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerAndSimplePlayerMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(new Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session = new MediaSession.Builder(context, player).setId("test").build();
|
||||
sessionReference.set(session);
|
||||
Bundle controllerHints = new Bundle();
|
||||
controllerHints.putString("key", "value");
|
||||
MediaController controller =
|
||||
new MediaController.Builder(context, session.getToken())
|
||||
.setConnectionHints(controllerHints)
|
||||
.buildAsync()
|
||||
.get();
|
||||
|
||||
MainLooperTestRule.runOnMainSync(controller::play);
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getConnectionHints().getString("key"))
|
||||
.isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerAndAsyncSetMediaItemMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(
|
||||
new Commands.Builder().add(Player.COMMAND_SET_MEDIA_ITEM).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleSetMediaItems(
|
||||
List<MediaItem> mediaItems, int startIndex, long startPositionMs) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("test")
|
||||
.setCallback(
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession,
|
||||
MediaSession.ControllerInfo controller,
|
||||
List<MediaItem> mediaItems) {
|
||||
// Resolve media items asynchronously.
|
||||
return Util.postOrRunWithCompletion(
|
||||
threadTestRule.getHandler(), () -> {}, mediaItems);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
sessionReference.set(session);
|
||||
Bundle controllerHints = new Bundle();
|
||||
controllerHints.putString("key", "value");
|
||||
MediaController controller =
|
||||
new MediaController.Builder(context, session.getToken())
|
||||
.setConnectionHints(controllerHints)
|
||||
.buildAsync()
|
||||
.get();
|
||||
|
||||
MainLooperTestRule.runOnMainSync(() -> controller.setMediaItem(MediaItem.fromUri("test://")));
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getConnectionHints().getString("key"))
|
||||
.isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerAndAsyncAddMediaItemMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(
|
||||
new Commands.Builder().add(Player.COMMAND_CHANGE_MEDIA_ITEMS).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleAddMediaItems(int index, List<MediaItem> mediaItems) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("test")
|
||||
.setCallback(
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession,
|
||||
MediaSession.ControllerInfo controller,
|
||||
List<MediaItem> mediaItems) {
|
||||
// Resolve media items asynchronously.
|
||||
return Util.postOrRunWithCompletion(
|
||||
threadTestRule.getHandler(), () -> {}, mediaItems);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
sessionReference.set(session);
|
||||
Bundle controllerHints = new Bundle();
|
||||
controllerHints.putString("key", "value");
|
||||
MediaController controller =
|
||||
new MediaController.Builder(context, session.getToken())
|
||||
.setConnectionHints(controllerHints)
|
||||
.buildAsync()
|
||||
.get();
|
||||
|
||||
MainLooperTestRule.runOnMainSync(() -> controller.addMediaItem(MediaItem.fromUri("test://")));
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getConnectionHints().getString("key"))
|
||||
.isEqualTo("value");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerCompatAndSimplePlayerMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(new Commands.Builder().add(Player.COMMAND_PLAY_PAUSE).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleSetPlayWhenReady(boolean playWhenReady) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session = new MediaSession.Builder(context, player).setId("test").build();
|
||||
sessionReference.set(session);
|
||||
MediaControllerCompat controller = session.getSessionCompat().getController();
|
||||
|
||||
controller.getTransportControls().play();
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getInterfaceVersion()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerCompatAndAsyncPlayFromMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(
|
||||
new Commands.Builder().add(Player.COMMAND_SET_MEDIA_ITEM).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleSetMediaItems(
|
||||
List<MediaItem> mediaItems, int startIndex, long startPositionMs) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("test")
|
||||
.setCallback(
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession,
|
||||
MediaSession.ControllerInfo controller,
|
||||
List<MediaItem> mediaItems) {
|
||||
// Resolve media items asynchronously.
|
||||
return Util.postOrRunWithCompletion(
|
||||
threadTestRule.getHandler(), () -> {}, mediaItems);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
sessionReference.set(session);
|
||||
MediaControllerCompat controller = session.getSessionCompat().getController();
|
||||
|
||||
controller.getTransportControls().playFromUri(Uri.parse("test://"), Bundle.EMPTY);
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getInterfaceVersion()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
getControllerForCurrentRequest_withMediaControllerCompatAndAsyncAddToQueueMethod_returnsControllerFromPlayerMethod()
|
||||
throws Exception {
|
||||
AtomicReference<MediaSession.ControllerInfo> controllerInfoFromPlayerMethod =
|
||||
new AtomicReference<>();
|
||||
AtomicReference<MediaSession> sessionReference = new AtomicReference<>();
|
||||
CountDownLatch eventHandled = new CountDownLatch(1);
|
||||
Player player =
|
||||
new SimpleBasePlayer(Looper.getMainLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return new State.Builder()
|
||||
.setAvailableCommands(
|
||||
new Commands.Builder().add(Player.COMMAND_CHANGE_MEDIA_ITEMS).build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handleAddMediaItems(int index, List<MediaItem> mediaItems) {
|
||||
controllerInfoFromPlayerMethod.set(
|
||||
sessionReference.get().getControllerForCurrentRequest());
|
||||
eventHandled.countDown();
|
||||
return Futures.immediateVoidFuture();
|
||||
}
|
||||
};
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
MediaSession session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("test")
|
||||
.setCallback(
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession,
|
||||
MediaSession.ControllerInfo controller,
|
||||
List<MediaItem> mediaItems) {
|
||||
// Resolve media items asynchronously.
|
||||
return Util.postOrRunWithCompletion(
|
||||
threadTestRule.getHandler(), () -> {}, mediaItems);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
sessionReference.set(session);
|
||||
|
||||
MainLooperTestRule.runOnMainSync(
|
||||
() -> {
|
||||
MediaControllerCompat controller = session.getSessionCompat().getController();
|
||||
controller.addQueueItem(new MediaDescriptionCompat.Builder().setMediaId("id").build());
|
||||
});
|
||||
eventHandled.await();
|
||||
session.release();
|
||||
|
||||
assertThat(controllerInfoFromPlayerMethod.get().getInterfaceVersion()).isEqualTo(0);
|
||||
}
|
||||
|
||||
private void changePlaybackTypeToRemote() throws Exception {
|
||||
threadTestRule
|
||||
.getHandler()
|
||||
|
Loading…
x
Reference in New Issue
Block a user