mirror of
https://github.com/samsonjs/media.git
synced 2026-03-25 09:25:53 +00:00
Add missing command checks to MediaSessionLegacyStub and PlayerWrapper
This player didn't fully check all player commands before calling the respective methods. PiperOrigin-RevId: 502353704
This commit is contained in:
parent
664ab72d09
commit
a2a44cdc02
7 changed files with 638 additions and 57 deletions
|
|
@ -1290,7 +1290,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
|||
if (msg.what == MSG_PLAYER_INFO_CHANGED) {
|
||||
playerInfo =
|
||||
playerInfo.copyWithTimelineAndSessionPositionInfo(
|
||||
getPlayerWrapper().getCurrentTimeline(),
|
||||
getPlayerWrapper().getCurrentTimelineWithCommandCheck(),
|
||||
getPlayerWrapper().createSessionPositionInfoForBundling());
|
||||
dispatchOnPlayerInfoChanged(playerInfo, excludeTimeline, excludeTracks);
|
||||
excludeTimeline = true;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ import static androidx.media3.common.Player.COMMAND_SEEK_FORWARD;
|
|||
import static androidx.media3.common.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
|
||||
import static androidx.media3.common.Player.COMMAND_SEEK_TO_MEDIA_ITEM;
|
||||
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT;
|
||||
import static androidx.media3.common.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
|
||||
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS;
|
||||
import static androidx.media3.common.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
|
||||
import static androidx.media3.common.Player.COMMAND_SET_MEDIA_ITEM;
|
||||
import static androidx.media3.common.Player.COMMAND_SET_REPEAT_MODE;
|
||||
import static androidx.media3.common.Player.COMMAND_SET_SHUFFLE_MODE;
|
||||
|
|
@ -256,10 +258,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
|| playbackState == STATE_ENDED
|
||||
|| playbackState == STATE_IDLE) {
|
||||
if (playbackState == STATE_IDLE) {
|
||||
playerWrapper.prepare();
|
||||
playerWrapper.prepareIfCommandAvailable();
|
||||
} else if (playbackState == STATE_ENDED) {
|
||||
playerWrapper.seekTo(
|
||||
playerWrapper.getCurrentMediaItemIndex(), /* positionMs= */ C.TIME_UNSET);
|
||||
playerWrapper.seekToDefaultPositionIfCommandAvailable();
|
||||
}
|
||||
playerWrapper.play();
|
||||
} else {
|
||||
|
|
@ -308,10 +309,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
PlayerWrapper playerWrapper = sessionImpl.getPlayerWrapper();
|
||||
@Player.State int playbackState = playerWrapper.getPlaybackState();
|
||||
if (playbackState == Player.STATE_IDLE) {
|
||||
playerWrapper.prepare();
|
||||
playerWrapper.prepareIfCommandAvailable();
|
||||
} else if (playbackState == Player.STATE_ENDED) {
|
||||
playerWrapper.seekTo(
|
||||
playerWrapper.getCurrentMediaItemIndex(), /* positionMs= */ C.TIME_UNSET);
|
||||
playerWrapper.seekToDefaultPositionIfCommandAvailable();
|
||||
}
|
||||
if (sessionImpl.onPlayRequested()) {
|
||||
playerWrapper.play();
|
||||
|
|
@ -369,18 +369,32 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
|
||||
@Override
|
||||
public void onSkipToNext() {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_NEXT,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToNext(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
if (sessionImpl.getPlayerWrapper().isCommandAvailable(COMMAND_SEEK_TO_NEXT)) {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_NEXT,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToNext(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
} else {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToNextMediaItem(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipToPrevious() {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_PREVIOUS,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToPrevious(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
if (sessionImpl.getPlayerWrapper().isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS)) {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_PREVIOUS,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToPrevious(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
} else {
|
||||
dispatchSessionTaskWithPlayerCommand(
|
||||
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
||||
controller -> sessionImpl.getPlayerWrapper().seekToPreviousMediaItem(),
|
||||
sessionCompat.getCurrentControllerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -435,7 +449,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
dispatchSessionTaskWithSessionCommand(
|
||||
SessionCommand.COMMAND_CODE_SESSION_SET_RATING,
|
||||
controller -> {
|
||||
@Nullable MediaItem currentItem = sessionImpl.getPlayerWrapper().getCurrentMediaItem();
|
||||
@Nullable
|
||||
MediaItem currentItem =
|
||||
sessionImpl.getPlayerWrapper().getCurrentMediaItemWithCommandCheck();
|
||||
if (currentItem == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -494,12 +510,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
Log.w(TAG, "onRemoveQueueItem(): Media ID shouldn't be null");
|
||||
return;
|
||||
}
|
||||
Timeline timeline = sessionImpl.getPlayerWrapper().getCurrentTimeline();
|
||||
PlayerWrapper player = sessionImpl.getPlayerWrapper();
|
||||
if (!player.isCommandAvailable(Player.COMMAND_GET_TIMELINE)) {
|
||||
Log.w(TAG, "Can't remove item by id without availabe COMMAND_GET_TIMELINE");
|
||||
return;
|
||||
}
|
||||
Timeline timeline = player.getCurrentTimeline();
|
||||
Timeline.Window window = new Timeline.Window();
|
||||
for (int i = 0; i < timeline.getWindowCount(); i++) {
|
||||
MediaItem mediaItem = timeline.getWindow(i, window).mediaItem;
|
||||
if (TextUtils.equals(mediaItem.mediaId, mediaId)) {
|
||||
sessionImpl.getPlayerWrapper().removeMediaItem(i);
|
||||
player.removeMediaItem(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -700,16 +721,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
postOrRun(
|
||||
sessionImpl.getApplicationHandler(),
|
||||
() -> {
|
||||
Player player = sessionImpl.getPlayerWrapper();
|
||||
PlayerWrapper player = sessionImpl.getPlayerWrapper();
|
||||
player.setMediaItems(mediaItems);
|
||||
@Player.State int playbackState = player.getPlaybackState();
|
||||
if (playbackState == Player.STATE_IDLE) {
|
||||
player.prepare();
|
||||
player.prepareIfCommandAvailable();
|
||||
} else if (playbackState == Player.STATE_ENDED) {
|
||||
player.seekTo(/* positionMs= */ C.TIME_UNSET);
|
||||
player.seekToDefaultPositionIfCommandAvailable();
|
||||
}
|
||||
if (play) {
|
||||
player.play();
|
||||
player.playIfCommandAvailable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -875,19 +896,21 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
throws RemoteException {
|
||||
// Tells the playlist change first, so current media item index change notification
|
||||
// can point to the valid current media item in the playlist.
|
||||
Timeline newTimeline = newPlayerWrapper.getCurrentTimeline();
|
||||
Timeline newTimeline = newPlayerWrapper.getCurrentTimelineWithCommandCheck();
|
||||
if (oldPlayerWrapper == null
|
||||
|| !Util.areEqual(oldPlayerWrapper.getCurrentTimeline(), newTimeline)) {
|
||||
|| !Util.areEqual(oldPlayerWrapper.getCurrentTimelineWithCommandCheck(), newTimeline)) {
|
||||
onTimelineChanged(seq, newTimeline, Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED);
|
||||
}
|
||||
MediaMetadata newPlaylistMetadata = newPlayerWrapper.getPlaylistMetadata();
|
||||
MediaMetadata newPlaylistMetadata = newPlayerWrapper.getPlaylistMetadataWithCommandCheck();
|
||||
if (oldPlayerWrapper == null
|
||||
|| !Util.areEqual(oldPlayerWrapper.getPlaylistMetadata(), newPlaylistMetadata)) {
|
||||
|| !Util.areEqual(
|
||||
oldPlayerWrapper.getPlaylistMetadataWithCommandCheck(), newPlaylistMetadata)) {
|
||||
onPlaylistMetadataChanged(seq, newPlaylistMetadata);
|
||||
}
|
||||
MediaMetadata newMediaMetadata = newPlayerWrapper.getMediaMetadata();
|
||||
MediaMetadata newMediaMetadata = newPlayerWrapper.getMediaMetadataWithCommandCheck();
|
||||
if (oldPlayerWrapper == null
|
||||
|| !Util.areEqual(oldPlayerWrapper.getMediaMetadata(), newMediaMetadata)) {
|
||||
|| !Util.areEqual(
|
||||
oldPlayerWrapper.getMediaMetadataWithCommandCheck(), newMediaMetadata)) {
|
||||
onMediaMetadataChanged(seq, newMediaMetadata);
|
||||
}
|
||||
if (oldPlayerWrapper == null
|
||||
|
|
@ -904,9 +927,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
onDeviceInfoChanged(seq, newPlayerWrapper.getDeviceInfo());
|
||||
|
||||
// Rest of changes are all notified via PlaybackStateCompat.
|
||||
@Nullable MediaItem newMediaItem = newPlayerWrapper.getCurrentMediaItem();
|
||||
@Nullable MediaItem newMediaItem = newPlayerWrapper.getCurrentMediaItemWithCommandCheck();
|
||||
if (oldPlayerWrapper == null
|
||||
|| !Util.areEqual(oldPlayerWrapper.getCurrentMediaItem(), newMediaItem)) {
|
||||
|| !Util.areEqual(oldPlayerWrapper.getCurrentMediaItemWithCommandCheck(), newMediaItem)) {
|
||||
// Note: This will update both PlaybackStateCompat and metadata.
|
||||
onMediaItemTransition(
|
||||
seq, newMediaItem, Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||
|
|
@ -1135,7 +1158,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
PlayerWrapper player = sessionImpl.getPlayerWrapper();
|
||||
volumeProviderCompat = player.createVolumeProviderCompat();
|
||||
if (volumeProviderCompat == null) {
|
||||
int streamType = MediaUtils.getLegacyStreamType(player.getAudioAttributes());
|
||||
int streamType =
|
||||
MediaUtils.getLegacyStreamType(player.getAudioAttributesWithCommandCheck());
|
||||
sessionCompat.setPlaybackToLocal(streamType);
|
||||
} else {
|
||||
sessionCompat.setPlaybackToRemote(volumeProviderCompat);
|
||||
|
|
@ -1158,10 +1182,10 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
}
|
||||
|
||||
private void updateMetadataIfChanged() {
|
||||
Player player = sessionImpl.getPlayerWrapper();
|
||||
@Nullable MediaItem currentMediaItem = player.getCurrentMediaItem();
|
||||
MediaMetadata newMediaMetadata = player.getMediaMetadata();
|
||||
long newDurationMs = player.getDuration();
|
||||
PlayerWrapper player = sessionImpl.getPlayerWrapper();
|
||||
@Nullable MediaItem currentMediaItem = player.getCurrentMediaItemWithCommandCheck();
|
||||
MediaMetadata newMediaMetadata = player.getMediaMetadataWithCommandCheck();
|
||||
long newDurationMs = player.getDurationWithCommandCheck();
|
||||
String newMediaId =
|
||||
currentMediaItem != null ? currentMediaItem.mediaId : MediaItem.DEFAULT_MEDIA_ID;
|
||||
@Nullable
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
|
@ -34,6 +35,7 @@ import android.view.TextureView;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.media.VolumeProviderCompat;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.DeviceInfo;
|
||||
import androidx.media3.common.ForwardingPlayer;
|
||||
import androidx.media3.common.MediaItem;
|
||||
|
|
@ -43,9 +45,11 @@ import androidx.media3.common.PlaybackParameters;
|
|||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.TrackSelectionParameters;
|
||||
import androidx.media3.common.Tracks;
|
||||
import androidx.media3.common.VideoSize;
|
||||
import androidx.media3.common.text.CueGroup;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.Size;
|
||||
import androidx.media3.common.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.List;
|
||||
|
|
@ -133,6 +137,12 @@ import java.util.List;
|
|||
super.play();
|
||||
}
|
||||
|
||||
public void playIfCommandAvailable() {
|
||||
if (isCommandAvailable(COMMAND_PLAY_PAUSE)) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -145,6 +155,12 @@ import java.util.List;
|
|||
super.prepare();
|
||||
}
|
||||
|
||||
public void prepareIfCommandAvailable() {
|
||||
if (isCommandAvailable(COMMAND_PREPARE)) {
|
||||
prepare();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -163,6 +179,18 @@ import java.util.List;
|
|||
super.seekToDefaultPosition(mediaItemIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToDefaultPosition() {
|
||||
verifyApplicationThread();
|
||||
super.seekToDefaultPosition();
|
||||
}
|
||||
|
||||
public void seekToDefaultPositionIfCommandAvailable() {
|
||||
if (isCommandAvailable(Player.COMMAND_SEEK_TO_DEFAULT_POSITION)) {
|
||||
seekToDefaultPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekTo(long positionMs) {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -223,6 +251,10 @@ import java.util.List;
|
|||
return super.getDuration();
|
||||
}
|
||||
|
||||
public long getDurationWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM) ? getDuration() : C.TIME_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBufferedPosition() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -355,6 +387,12 @@ import java.util.List;
|
|||
return super.getAudioAttributes();
|
||||
}
|
||||
|
||||
public AudioAttributes getAudioAttributesWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_AUDIO_ATTRIBUTES)
|
||||
? getAudioAttributes()
|
||||
: AudioAttributes.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMediaItem(MediaItem mediaItem) {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -549,12 +587,22 @@ import java.util.List;
|
|||
return super.getCurrentTimeline();
|
||||
}
|
||||
|
||||
public Timeline getCurrentTimelineWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_TIMELINE) ? getCurrentTimeline() : Timeline.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaMetadata getPlaylistMetadata() {
|
||||
verifyApplicationThread();
|
||||
return super.getPlaylistMetadata();
|
||||
}
|
||||
|
||||
public MediaMetadata getPlaylistMetadataWithCommandCheck() {
|
||||
return isCommandAvailable(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)
|
||||
? getPlaylistMetadata()
|
||||
: MediaMetadata.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRepeatMode() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -574,6 +622,11 @@ import java.util.List;
|
|||
return super.getCurrentMediaItem();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MediaItem getCurrentMediaItemWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM) ? getCurrentMediaItem() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMediaItemCount() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -631,6 +684,10 @@ import java.util.List;
|
|||
return super.getVolume();
|
||||
}
|
||||
|
||||
public float getVolumeWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_VOLUME) ? getVolume() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -643,6 +700,10 @@ import java.util.List;
|
|||
return super.getCurrentCues();
|
||||
}
|
||||
|
||||
public CueGroup getCurrentCuesWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_TEXT) ? getCurrentCues() : CueGroup.EMPTY_TIME_ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceInfo getDeviceInfo() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -655,18 +716,32 @@ import java.util.List;
|
|||
return super.getDeviceVolume();
|
||||
}
|
||||
|
||||
public int getDeviceVolumeWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_DEVICE_VOLUME) ? getDeviceVolume() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeviceMuted() {
|
||||
verifyApplicationThread();
|
||||
return super.isDeviceMuted();
|
||||
}
|
||||
|
||||
public boolean isDeviceMutedWithCommandCheck() {
|
||||
return isCommandAvailable(Player.COMMAND_GET_DEVICE_VOLUME) && isDeviceMuted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeviceVolume(int volume) {
|
||||
verifyApplicationThread();
|
||||
super.setDeviceVolume(volume);
|
||||
}
|
||||
|
||||
public void setDeviceVolumeIfCommandAvailable(int volume) {
|
||||
if (isCommandAvailable(COMMAND_SET_DEVICE_VOLUME)) {
|
||||
setDeviceVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increaseDeviceVolume() {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -729,6 +804,12 @@ import java.util.List;
|
|||
return super.getMediaMetadata();
|
||||
}
|
||||
|
||||
public MediaMetadata getMediaMetadataWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_MEDIA_ITEMS_METADATA)
|
||||
? getMediaMetadata()
|
||||
: MediaMetadata.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommandAvailable(@Command int command) {
|
||||
verifyApplicationThread();
|
||||
|
|
@ -753,6 +834,71 @@ import java.util.List;
|
|||
super.setTrackSelectionParameters(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToPrevious() {
|
||||
verifyApplicationThread();
|
||||
super.seekToPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxSeekToPreviousPosition() {
|
||||
verifyApplicationThread();
|
||||
return super.getMaxSeekToPreviousPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToNext() {
|
||||
verifyApplicationThread();
|
||||
super.seekToNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracks getCurrentTracks() {
|
||||
verifyApplicationThread();
|
||||
return super.getCurrentTracks();
|
||||
}
|
||||
|
||||
public Tracks getCurrentTracksWithCommandCheck() {
|
||||
return isCommandAvailable(COMMAND_GET_TRACKS) ? getCurrentTracks() : Tracks.EMPTY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getCurrentManifest() {
|
||||
verifyApplicationThread();
|
||||
return super.getCurrentManifest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentPeriodIndex() {
|
||||
verifyApplicationThread();
|
||||
return super.getCurrentPeriodIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentMediaItemDynamic() {
|
||||
verifyApplicationThread();
|
||||
return super.isCurrentMediaItemDynamic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentMediaItemLive() {
|
||||
verifyApplicationThread();
|
||||
return super.isCurrentMediaItemLive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentMediaItemSeekable() {
|
||||
verifyApplicationThread();
|
||||
return super.isCurrentMediaItemSeekable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Size getSurfaceSize() {
|
||||
verifyApplicationThread();
|
||||
return super.getSurfaceSize();
|
||||
}
|
||||
|
||||
public PlaybackStateCompat createPlaybackStateCompat() {
|
||||
if (legacyStatusCode != STATUS_CODE_SUCCESS_COMPAT) {
|
||||
return new PlaybackStateCompat.Builder()
|
||||
|
|
@ -799,22 +945,28 @@ import java.util.List;
|
|||
|| getAvailableCommands().contains(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)) {
|
||||
allActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
|
||||
}
|
||||
long queueItemId = MediaUtils.convertToQueueItemId(getCurrentMediaItemIndex());
|
||||
long queueItemId =
|
||||
isCommandAvailable(COMMAND_GET_TIMELINE)
|
||||
? MediaUtils.convertToQueueItemId(getCurrentMediaItemIndex())
|
||||
: MediaSessionCompat.QueueItem.UNKNOWN_ID;
|
||||
float playbackSpeed = getPlaybackParameters().speed;
|
||||
float sessionPlaybackSpeed = isPlaying() ? playbackSpeed : 0f;
|
||||
Bundle extras = new Bundle();
|
||||
extras.putFloat(EXTRAS_KEY_PLAYBACK_SPEED_COMPAT, playbackSpeed);
|
||||
@Nullable MediaItem currentMediaItem = getCurrentMediaItem();
|
||||
@Nullable MediaItem currentMediaItem = getCurrentMediaItemWithCommandCheck();
|
||||
if (currentMediaItem != null && !MediaItem.DEFAULT_MEDIA_ID.equals(currentMediaItem.mediaId)) {
|
||||
extras.putString(EXTRAS_KEY_MEDIA_ID_COMPAT, currentMediaItem.mediaId);
|
||||
}
|
||||
boolean canReadPositions = isCommandAvailable(Player.COMMAND_GET_CURRENT_MEDIA_ITEM);
|
||||
long compatPosition =
|
||||
canReadPositions ? getCurrentPosition() : PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN;
|
||||
long compatBufferedPosition = canReadPositions ? getBufferedPosition() : 0;
|
||||
PlaybackStateCompat.Builder builder =
|
||||
new PlaybackStateCompat.Builder()
|
||||
.setState(
|
||||
state, getCurrentPosition(), sessionPlaybackSpeed, SystemClock.elapsedRealtime())
|
||||
.setState(state, compatPosition, sessionPlaybackSpeed, SystemClock.elapsedRealtime())
|
||||
.setActions(allActions)
|
||||
.setActiveQueueItemId(queueItemId)
|
||||
.setBufferedPosition(getBufferedPosition())
|
||||
.setBufferedPosition(compatBufferedPosition)
|
||||
.setExtras(extras);
|
||||
|
||||
for (int i = 0; i < customLayout.size(); i++) {
|
||||
|
|
@ -853,11 +1005,11 @@ import java.util.List;
|
|||
}
|
||||
}
|
||||
Handler handler = new Handler(getApplicationLooper());
|
||||
return new VolumeProviderCompat(
|
||||
volumeControlType, getDeviceInfo().maxVolume, getDeviceVolume()) {
|
||||
int currentVolume = getDeviceVolumeWithCommandCheck();
|
||||
return new VolumeProviderCompat(volumeControlType, getDeviceInfo().maxVolume, currentVolume) {
|
||||
@Override
|
||||
public void onSetVolumeTo(int volume) {
|
||||
postOrRun(handler, () -> setDeviceVolume(volume));
|
||||
postOrRun(handler, () -> setDeviceVolumeIfCommandAvailable(volume));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -865,6 +1017,9 @@ import java.util.List;
|
|||
postOrRun(
|
||||
handler,
|
||||
() -> {
|
||||
if (!isCommandAvailable(COMMAND_ADJUST_DEVICE_VOLUME)) {
|
||||
return;
|
||||
}
|
||||
switch (direction) {
|
||||
case AudioManager.ADJUST_RAISE:
|
||||
increaseDeviceVolume();
|
||||
|
|
@ -879,7 +1034,7 @@ import java.util.List;
|
|||
setDeviceMuted(false);
|
||||
break;
|
||||
case AudioManager.ADJUST_TOGGLE_MUTE:
|
||||
setDeviceMuted(!isDeviceMuted());
|
||||
setDeviceMuted(!isDeviceMutedWithCommandCheck());
|
||||
break;
|
||||
default:
|
||||
Log.w(
|
||||
|
|
@ -898,6 +1053,9 @@ import java.util.List;
|
|||
* <p>This excludes window uid and period uid that wouldn't be preserved when bundling.
|
||||
*/
|
||||
public PositionInfo createPositionInfoForBundling() {
|
||||
if (!isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)) {
|
||||
return SessionPositionInfo.DEFAULT_POSITION_INFO;
|
||||
}
|
||||
return new PositionInfo(
|
||||
/* windowUid= */ null,
|
||||
getCurrentMediaItemIndex(),
|
||||
|
|
@ -916,6 +1074,9 @@ import java.util.List;
|
|||
* <p>This excludes window uid and period uid that wouldn't be preserved when bundling.
|
||||
*/
|
||||
public SessionPositionInfo createSessionPositionInfoForBundling() {
|
||||
if (!isCommandAvailable(COMMAND_GET_CURRENT_MEDIA_ITEM)) {
|
||||
return SessionPositionInfo.DEFAULT;
|
||||
}
|
||||
return new SessionPositionInfo(
|
||||
createPositionInfoForBundling(),
|
||||
isPlayingAd(),
|
||||
|
|
@ -941,25 +1102,25 @@ import java.util.List;
|
|||
getRepeatMode(),
|
||||
getShuffleModeEnabled(),
|
||||
getVideoSize(),
|
||||
getCurrentTimeline(),
|
||||
getPlaylistMetadata(),
|
||||
getVolume(),
|
||||
getAudioAttributes(),
|
||||
getCurrentCues(),
|
||||
getCurrentTimelineWithCommandCheck(),
|
||||
getPlaylistMetadataWithCommandCheck(),
|
||||
getVolumeWithCommandCheck(),
|
||||
getAudioAttributesWithCommandCheck(),
|
||||
getCurrentCuesWithCommandCheck(),
|
||||
getDeviceInfo(),
|
||||
getDeviceVolume(),
|
||||
isDeviceMuted(),
|
||||
getDeviceVolumeWithCommandCheck(),
|
||||
isDeviceMutedWithCommandCheck(),
|
||||
getPlayWhenReady(),
|
||||
PlayerInfo.PLAY_WHEN_READY_CHANGE_REASON_DEFAULT,
|
||||
getPlaybackSuppressionReason(),
|
||||
getPlaybackState(),
|
||||
isPlaying(),
|
||||
isLoading(),
|
||||
getMediaMetadata(),
|
||||
getMediaMetadataWithCommandCheck(),
|
||||
getSeekBackIncrement(),
|
||||
getSeekForwardIncrement(),
|
||||
getMaxSeekToPreviousPosition(),
|
||||
getCurrentTracks(),
|
||||
getCurrentTracksWithCommandCheck(),
|
||||
getTrackSelectionParameters());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package androidx.media3.session;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.Looper;
|
||||
|
|
@ -42,6 +43,7 @@ public class PlayerWrapperTest {
|
|||
@Before
|
||||
public void setUp() {
|
||||
playerWrapper = new PlayerWrapper(player);
|
||||
when(player.isCommandAvailable(anyInt())).thenReturn(true);
|
||||
when(player.getApplicationLooper()).thenReturn(Looper.myLooper());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ package androidx.media3.session;
|
|||
import static androidx.media.MediaSessionManager.RemoteUserInfo.LEGACY_CONTROLLER;
|
||||
import static androidx.media3.common.Player.COMMAND_PLAY_PAUSE;
|
||||
import static androidx.media3.common.Player.COMMAND_PREPARE;
|
||||
import static androidx.media3.common.Player.STATE_ENDED;
|
||||
import static androidx.media3.common.Player.STATE_IDLE;
|
||||
import static androidx.media3.common.Player.STATE_READY;
|
||||
import static androidx.media3.session.SessionResult.RESULT_ERROR_INVALID_STATE;
|
||||
import static androidx.media3.session.SessionResult.RESULT_SUCCESS;
|
||||
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
|
||||
|
|
@ -204,7 +206,8 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void play() throws Exception {
|
||||
public void play_whileReady_callsPlay() throws Exception {
|
||||
player.playbackState = STATE_READY;
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("play")
|
||||
|
|
@ -217,6 +220,92 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
controller.getTransportControls().play();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void play_whileIdle_callsPrepareAndPlay() throws Exception {
|
||||
player.playbackState = STATE_IDLE;
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("play")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().play();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PREPARE, TIMEOUT_MS);
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void play_whileIdleWithoutPrepareCommandAvailable_callsJustPlay() throws Exception {
|
||||
player.playbackState = STATE_IDLE;
|
||||
player.commands =
|
||||
new Player.Commands.Builder().addAllCommands().remove(Player.COMMAND_PREPARE).build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("play")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().play();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void play_whileEnded_callsSeekToDefaultPositionAndPlay() throws Exception {
|
||||
player.playbackState = STATE_ENDED;
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("play")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().play();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION, TIMEOUT_MS);
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void play_whileEndedWithoutSeekToDefaultPositionCommandAvailable_callsJustPlay()
|
||||
throws Exception {
|
||||
player.playbackState = STATE_ENDED;
|
||||
player.commands =
|
||||
new Player.Commands.Builder()
|
||||
.addAllCommands()
|
||||
.remove(Player.COMMAND_SEEK_TO_DEFAULT_POSITION)
|
||||
.build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("play")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().play();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION)).isFalse();
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -428,7 +517,7 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void skipToPrevious() throws Exception {
|
||||
public void skipToPrevious_withAllCommandsAvailable_callsSeekToPrevious() throws Exception {
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("skipToPrevious")
|
||||
|
|
@ -444,7 +533,29 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void skipToNext() throws Exception {
|
||||
public void skipToPrevious_withoutSeekToPreviousCommandAvailable_callsSeekToPreviousMediaItem()
|
||||
throws Exception {
|
||||
player.commands =
|
||||
new Player.Commands.Builder()
|
||||
.addAllCommands()
|
||||
.remove(Player.COMMAND_SEEK_TO_PREVIOUS)
|
||||
.build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("skipToPrevious")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().skipToPrevious();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_PREVIOUS_MEDIA_ITEM, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipToNext_withAllCommandsAvailable_callsSeekToNext() throws Exception {
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("skipToNext")
|
||||
|
|
@ -459,6 +570,25 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_NEXT, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipToNext_withoutSeekToNextCommandAvailable_callsSeekToNextMediaItem()
|
||||
throws Exception {
|
||||
player.commands =
|
||||
new Player.Commands.Builder().addAllCommands().remove(Player.COMMAND_SEEK_TO_NEXT).build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("skipToNext")
|
||||
.setCallback(new TestSessionCallback())
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().skipToNext();
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_NEXT_MEDIA_ITEM, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipToQueueItem() throws Exception {
|
||||
session =
|
||||
|
|
@ -1049,6 +1179,101 @@ public class MediaSessionCallbackWithMediaControllerCompatTest {
|
|||
assertThat(player.mediaItems).containsExactly(resolvedMediaItem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prepareFromMediaUri_withoutAvailablePrepareCommand_justCallsSetMediaItems()
|
||||
throws Exception {
|
||||
MediaItem resolvedMediaItem = MediaItem.fromUri(TEST_URI);
|
||||
MediaSession.Callback callback =
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||
return Futures.immediateFuture(ImmutableList.of(resolvedMediaItem));
|
||||
}
|
||||
};
|
||||
player.commands =
|
||||
new Player.Commands.Builder().addAllCommands().remove(COMMAND_PREPARE).build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("prepareFromMediaUri")
|
||||
.setCallback(callback)
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().prepareFromUri(Uri.parse("foo://bar"), Bundle.EMPTY);
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
assertThat(player.mediaItems).containsExactly(resolvedMediaItem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playFromMediaUri_withoutAvailablePrepareCommand_justCallsSetMediaItemsAndPlay()
|
||||
throws Exception {
|
||||
MediaItem resolvedMediaItem = MediaItem.fromUri(TEST_URI);
|
||||
MediaSession.Callback callback =
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||
return Futures.immediateFuture(ImmutableList.of(resolvedMediaItem));
|
||||
}
|
||||
};
|
||||
player.commands =
|
||||
new Player.Commands.Builder().addAllCommands().remove(COMMAND_PREPARE).build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("prepareFromMediaUri")
|
||||
.setCallback(callback)
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().playFromUri(Uri.parse("foo://bar"), Bundle.EMPTY);
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
assertThat(player.mediaItems).containsExactly(resolvedMediaItem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void playFromMediaUri_withoutAvailablePrepareAndPlayCommand_justCallsSetMediaItems()
|
||||
throws Exception {
|
||||
MediaItem resolvedMediaItem = MediaItem.fromUri(TEST_URI);
|
||||
MediaSession.Callback callback =
|
||||
new MediaSession.Callback() {
|
||||
@Override
|
||||
public ListenableFuture<List<MediaItem>> onAddMediaItems(
|
||||
MediaSession mediaSession, ControllerInfo controller, List<MediaItem> mediaItems) {
|
||||
return Futures.immediateFuture(ImmutableList.of(resolvedMediaItem));
|
||||
}
|
||||
};
|
||||
player.commands =
|
||||
new Player.Commands.Builder()
|
||||
.addAllCommands()
|
||||
.removeAll(COMMAND_PREPARE, COMMAND_PLAY_PAUSE)
|
||||
.build();
|
||||
session =
|
||||
new MediaSession.Builder(context, player)
|
||||
.setId("prepareFromMediaUri")
|
||||
.setCallback(callback)
|
||||
.build();
|
||||
controller =
|
||||
new RemoteMediaControllerCompat(
|
||||
context, session.getSessionCompat().getSessionToken(), /* waitForConnection= */ true);
|
||||
|
||||
controller.getTransportControls().playFromUri(Uri.parse("foo://bar"), Bundle.EMPTY);
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SET_MEDIA_ITEMS, TIMEOUT_MS);
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PREPARE)).isFalse();
|
||||
assertThat(player.hasMethodBeenCalled(MockPlayer.METHOD_PLAY)).isFalse();
|
||||
assertThat(player.mediaItems).containsExactly(resolvedMediaItem);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRating() throws Exception {
|
||||
int ratingType = RatingCompat.RATING_5_STARS;
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ public class MediaSessionKeyEventTest {
|
|||
|
||||
dispatchMediaKeyEvent(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, false);
|
||||
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_WITH_MEDIA_ITEM_INDEX, TIMEOUT_MS);
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_SEEK_TO_DEFAULT_POSITION, TIMEOUT_MS);
|
||||
player.awaitMethodCalled(MockPlayer.METHOD_PLAY, TIMEOUT_MS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,12 +38,19 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.DeviceInfo;
|
||||
import androidx.media3.common.ForwardingPlayer;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MediaMetadata;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.Rating;
|
||||
import androidx.media3.common.StarRating;
|
||||
import androidx.media3.common.Timeline;
|
||||
import androidx.media3.common.TrackSelectionParameters;
|
||||
import androidx.media3.common.Tracks;
|
||||
import androidx.media3.common.text.CueGroup;
|
||||
import androidx.media3.session.MediaSession.ControllerInfo;
|
||||
import androidx.media3.test.session.common.HandlerThreadTestRule;
|
||||
import androidx.media3.test.session.common.MainLooperTestRule;
|
||||
|
|
@ -262,6 +269,168 @@ public class MediaSessionPermissionTest {
|
|||
TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPlayer_withoutAvailableCommands_doesNotCallProtectedPlayerGetters()
|
||||
throws Exception {
|
||||
MockPlayer mockPlayer =
|
||||
new MockPlayer.Builder()
|
||||
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
||||
.build();
|
||||
// Set remote device info to ensure we also cover the volume provider compat setup.
|
||||
mockPlayer.deviceInfo =
|
||||
new DeviceInfo(DeviceInfo.PLAYBACK_TYPE_REMOTE, /* minVolume= */ 0, /* maxVolume= */ 100);
|
||||
Player player =
|
||||
new ForwardingPlayer(mockPlayer) {
|
||||
@Override
|
||||
public boolean isCommandAvailable(int command) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tracks getCurrentTracks() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaMetadata getMediaMetadata() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaMetadata getPlaylistMetadata() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timeline getCurrentTimeline() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentPeriodIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentMediaItemIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextMediaItemIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousMediaItemIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MediaItem getCurrentMediaItem() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDuration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrentPosition() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getBufferedPosition() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBufferedDuration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentMediaItemDynamic() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentMediaItemLive() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayingAd() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentAdGroupIndex() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentAdIndexInAdGroup() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentDuration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentPosition() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getContentBufferedPosition() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AudioAttributes getAudioAttributes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CueGroup getCurrentCues() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceVolume() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeviceMuted() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
MediaSession session = new MediaSession.Builder(context, player).setId(SESSION_ID).build();
|
||||
|
||||
MediaController controller =
|
||||
new MediaController.Builder(context, session.getToken())
|
||||
.setApplicationLooper(threadTestRule.getHandler().getLooper())
|
||||
.buildAsync()
|
||||
.get();
|
||||
|
||||
// Test passes if none of the protected player getters have been called.
|
||||
threadTestRule
|
||||
.getHandler()
|
||||
.postAndSync(
|
||||
() -> {
|
||||
controller.release();
|
||||
session.release();
|
||||
player.release();
|
||||
});
|
||||
}
|
||||
|
||||
private ControllerInfo getTestControllerInfo() {
|
||||
List<ControllerInfo> controllers = session.getConnectedControllers();
|
||||
assertThat(controllers).isNotNull();
|
||||
|
|
|
|||
Loading…
Reference in a new issue