[go: nahoru, domu]

blob: 575f96fcfe53041844e49fdccdedda8d6646b740 [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media2.widget;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.ObjectsCompat;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
/** Wrapper for androidx.media2.session.MediaController and androidx.media2.common.SessionPlayer */
@SuppressWarnings("deprecation")
class PlayerWrapper {
final androidx.media2.session.MediaController mController;
final androidx.media2.common.SessionPlayer mPlayer;
private final Executor mCallbackExecutor;
@SuppressWarnings("WeakerAccess") /* synthetic access */
final PlayerCallback mWrapperCallback;
private final MediaControllerCallback mControllerCallback;
private final SessionPlayerCallback mPlayerCallback;
private boolean mCallbackAttached;
// cached states
@SuppressWarnings("WeakerAccess") /* synthetic access */
int mSavedPlayerState = androidx.media2.common.SessionPlayer.PLAYER_STATE_IDLE;
@SuppressWarnings("WeakerAccess") /* synthetic access */
androidx.media2.session.SessionCommandGroup mAllowedCommands;
@SuppressWarnings("WeakerAccess") /* synthetic access */
androidx.media2.common.MediaMetadata mMediaMetadata;
private final androidx.media2.session.SessionCommandGroup mAllCommands;
PlayerWrapper(
@NonNull androidx.media2.session.MediaController controller,
@NonNull Executor executor,
@NonNull PlayerCallback callback) {
if (controller == null) throw new NullPointerException("controller must not be null");
if (executor == null) throw new NullPointerException("executor must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
mController = controller;
mCallbackExecutor = executor;
mWrapperCallback = callback;
mControllerCallback = new MediaControllerCallback();
mPlayer = null;
mPlayerCallback = null;
mAllCommands = null;
}
PlayerWrapper(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull Executor executor,
@NonNull PlayerCallback callback) {
if (player == null) throw new NullPointerException("player must not be null");
if (executor == null) throw new NullPointerException("executor must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
mPlayer = player;
mCallbackExecutor = executor;
mWrapperCallback = callback;
mPlayerCallback = new SessionPlayerCallback();
mController = null;
mControllerCallback = null;
mAllCommands =
new androidx.media2.session.SessionCommandGroup.Builder()
.addAllPredefinedCommands(
androidx.media2.session.SessionCommand.COMMAND_VERSION_1)
.build();
}
boolean hasDisconnectedController() {
return mController != null && !mController.isConnected();
}
void attachCallback() {
if (mCallbackAttached) return;
if (mController != null) {
mController.registerExtraCallback(mCallbackExecutor, mControllerCallback);
} else if (mPlayer != null) {
mPlayer.registerPlayerCallback(mCallbackExecutor, mPlayerCallback);
}
updateAndNotifyCachedStates();
mCallbackAttached = true;
}
void detachCallback() {
if (!mCallbackAttached) return;
if (mController != null) {
mController.unregisterExtraCallback(mControllerCallback);
} else if (mPlayer != null) {
mPlayer.unregisterPlayerCallback(mPlayerCallback);
}
mCallbackAttached = false;
}
boolean isPlaying() {
return mSavedPlayerState == androidx.media2.common.SessionPlayer.PLAYER_STATE_PLAYING;
}
long getCurrentPosition() {
if (mSavedPlayerState == androidx.media2.common.SessionPlayer.PLAYER_STATE_IDLE) {
return 0;
}
long position = 0;
if (mController != null) {
position = mController.getCurrentPosition();
} else if (mPlayer != null) {
position = mPlayer.getCurrentPosition();
}
return (position < 0) ? 0 : position;
}
long getBufferPercentage() {
if (mSavedPlayerState == androidx.media2.common.SessionPlayer.PLAYER_STATE_IDLE) {
return 0;
}
long duration = getDurationMs();
if (duration == 0) return 0;
long bufferedPos = 0;
if (mController != null) {
bufferedPos = mController.getBufferedPosition();
} else if (mPlayer != null) {
bufferedPos = mPlayer.getBufferedPosition();
}
return (bufferedPos < 0) ? 0 : (bufferedPos * 100 / duration);
}
int getPlayerState() {
if (mController != null) {
return mController.getPlayerState();
} else if (mPlayer != null) {
return mPlayer.getPlayerState();
}
return androidx.media2.common.SessionPlayer.PLAYER_STATE_IDLE;
}
boolean canPause() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_PAUSE);
}
boolean canSeekBackward() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_SESSION_REWIND);
}
boolean canSeekForward() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_SESSION_FAST_FORWARD);
}
boolean canSkipToNext() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand
.COMMAND_CODE_PLAYER_SKIP_TO_NEXT_PLAYLIST_ITEM);
}
boolean canSkipToPrevious() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand
.COMMAND_CODE_PLAYER_SKIP_TO_PREVIOUS_PLAYLIST_ITEM);
}
boolean canSeekTo() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_SEEK_TO);
}
boolean canSelectDeselectTrack() {
return mAllowedCommands != null
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_SELECT_TRACK)
&& mAllowedCommands.hasCommand(
androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_DESELECT_TRACK);
}
@SuppressWarnings("FutureReturnValueIgnored")
void pause() {
if (mController != null) {
mController.pause();
} else if (mPlayer != null) {
mPlayer.pause();
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void play() {
if (mController != null) {
mController.play();
} else if (mPlayer != null) {
mPlayer.play();
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void seekTo(long posMs) {
if (mController != null) {
mController.seekTo(posMs);
} else if (mPlayer != null) {
mPlayer.seekTo(posMs);
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void skipToNextItem() {
if (mController != null) {
mController.skipToNextPlaylistItem();
} else if (mPlayer != null) {
mPlayer.skipToNextPlaylistItem();
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void skipToPreviousItem() {
if (mController != null) {
mController.skipToPreviousPlaylistItem();
} else if (mPlayer != null) {
mPlayer.skipToPreviousPlaylistItem();
}
}
private float getPlaybackSpeed() {
if (mController != null) {
return mController.getPlaybackSpeed();
} else if (mPlayer != null) {
return mPlayer.getPlaybackSpeed();
}
return 1f;
}
@SuppressWarnings("FutureReturnValueIgnored")
void setPlaybackSpeed(float speed) {
if (mController != null) {
mController.setPlaybackSpeed(speed);
} else if (mPlayer != null) {
mPlayer.setPlaybackSpeed(speed);
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void selectTrack(androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
if (mController != null) {
mController.selectTrack(trackInfo);
} else if (mPlayer != null) {
mPlayer.selectTrack(trackInfo);
}
}
@SuppressWarnings("FutureReturnValueIgnored")
void deselectTrack(androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
if (mController != null) {
mController.deselectTrack(trackInfo);
} else if (mPlayer != null) {
mPlayer.deselectTrack(trackInfo);
}
}
long getDurationMs() {
if (mSavedPlayerState == androidx.media2.common.SessionPlayer.PLAYER_STATE_IDLE) {
return 0;
}
long duration = 0;
if (mController != null) {
duration = mController.getDuration();
} else if (mPlayer != null) {
duration = mPlayer.getDuration();
}
return (duration < 0) ? 0 : duration;
}
CharSequence getTitle() {
if (mMediaMetadata != null) {
if (mMediaMetadata.containsKey(
androidx.media2.common.MediaMetadata.METADATA_KEY_TITLE)) {
return mMediaMetadata.getText(
androidx.media2.common.MediaMetadata.METADATA_KEY_TITLE);
}
}
return null;
}
CharSequence getArtistText() {
if (mMediaMetadata != null) {
if (mMediaMetadata.containsKey(
androidx.media2.common.MediaMetadata.METADATA_KEY_ARTIST)) {
return mMediaMetadata.getText(
androidx.media2.common.MediaMetadata.METADATA_KEY_ARTIST);
}
}
return null;
}
@Nullable
androidx.media2.common.MediaItem getCurrentMediaItem() {
if (mController != null) {
return mController.getCurrentMediaItem();
} else if (mPlayer != null) {
return mPlayer.getCurrentMediaItem();
}
return null;
}
@Nullable
private androidx.media2.session.SessionCommandGroup getAllowedCommands() {
if (mController != null) {
return mController.getAllowedCommands();
} else if (mPlayer != null) {
// We can assume direct players allow all commands since no MediaSession is involved.
return mAllCommands;
}
return null;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void updateAndNotifyCachedStates() {
boolean playerStateChanged = false;
int playerState = getPlayerState();
if (mSavedPlayerState != playerState) {
mSavedPlayerState = playerState;
playerStateChanged = true;
}
boolean allowedCommandsChanged = false;
androidx.media2.session.SessionCommandGroup allowedCommands = getAllowedCommands();
if (!ObjectsCompat.equals(mAllowedCommands, allowedCommands)) {
mAllowedCommands = allowedCommands;
allowedCommandsChanged = true;
}
androidx.media2.common.MediaItem item = getCurrentMediaItem();
mMediaMetadata = item == null ? null : item.getMetadata();
if (playerStateChanged) {
mWrapperCallback.onPlayerStateChanged(this, playerState);
}
if (allowedCommands != null && allowedCommandsChanged) {
mWrapperCallback.onAllowedCommandsChanged(this, allowedCommands);
}
mWrapperCallback.onCurrentMediaItemChanged(this, item);
notifyNonCachedStates();
}
@NonNull
androidx.media2.common.VideoSize getVideoSize() {
if (mController != null) {
return mController.getVideoSize();
} else if (mPlayer != null) {
return mPlayer.getVideoSize();
}
return new androidx.media2.common.VideoSize(0, 0);
}
@NonNull
List<androidx.media2.common.SessionPlayer.TrackInfo> getTracks() {
if (mController != null) {
return mController.getTracks();
} else if (mPlayer != null) {
return mPlayer.getTracks();
}
return Collections.emptyList();
}
@Nullable
androidx.media2.common.SessionPlayer.TrackInfo getSelectedTrack(int trackType) {
if (mController != null) {
return mController.getSelectedTrack(trackType);
} else if (mPlayer != null) {
return mPlayer.getSelectedTrack(trackType);
}
return null;
}
ListenableFuture<? extends androidx.media2.common.BaseResult> setSurface(Surface surface) {
if (mController != null) {
return mController.setSurface(surface);
} else if (mPlayer != null) {
return mPlayer.setSurface(surface);
}
return null;
}
int getCurrentMediaItemIndex() {
if (mController != null) {
return mController.getCurrentMediaItemIndex();
} else if (mPlayer != null) {
return mPlayer.getCurrentMediaItemIndex();
}
return androidx.media2.common.SessionPlayer.INVALID_ITEM_INDEX;
}
int getPreviousMediaItemIndex() {
if (mController != null) {
return mController.getPreviousMediaItemIndex();
} else if (mPlayer != null) {
return mPlayer.getPreviousMediaItemIndex();
}
return androidx.media2.common.SessionPlayer.INVALID_ITEM_INDEX;
}
int getNextMediaItemIndex() {
if (mController != null) {
return mController.getNextMediaItemIndex();
} else if (mPlayer != null) {
return mPlayer.getNextMediaItemIndex();
}
return androidx.media2.common.SessionPlayer.INVALID_ITEM_INDEX;
}
private class MediaControllerCallback
extends androidx.media2.session.MediaController.ControllerCallback {
MediaControllerCallback() {
}
@Override
public void onConnected(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.session.SessionCommandGroup allowedCommands) {
mWrapperCallback.onConnected(PlayerWrapper.this);
updateAndNotifyCachedStates();
}
@Override
public void onAllowedCommandsChanged(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.session.SessionCommandGroup commands) {
if (ObjectsCompat.equals(mAllowedCommands, commands)) return;
mAllowedCommands = commands;
mWrapperCallback.onAllowedCommandsChanged(PlayerWrapper.this, commands);
}
@Override
public void onPlayerStateChanged(
@NonNull androidx.media2.session.MediaController controller, int state) {
if (mSavedPlayerState == state) return;
mSavedPlayerState = state;
mWrapperCallback.onPlayerStateChanged(PlayerWrapper.this, state);
}
@Override
public void onPlaybackSpeedChanged(
@NonNull androidx.media2.session.MediaController controller, float speed) {
mWrapperCallback.onPlaybackSpeedChanged(PlayerWrapper.this, speed);
}
@Override
public void onSeekCompleted(
@NonNull androidx.media2.session.MediaController controller, long position) {
mWrapperCallback.onSeekCompleted(PlayerWrapper.this, position);
}
@Override
public void onCurrentMediaItemChanged(
@NonNull androidx.media2.session.MediaController controller,
@Nullable androidx.media2.common.MediaItem item) {
mMediaMetadata = item == null ? null : item.getMetadata();
mWrapperCallback.onCurrentMediaItemChanged(PlayerWrapper.this, item);
}
@Override
public void onPlaylistChanged(
@NonNull androidx.media2.session.MediaController controller,
@Nullable List<androidx.media2.common.MediaItem> list,
@Nullable androidx.media2.common.MediaMetadata metadata) {
mWrapperCallback.onPlaylistChanged(PlayerWrapper.this, list, metadata);
}
@Override
public void onPlaybackCompleted(
@NonNull androidx.media2.session.MediaController controller) {
mWrapperCallback.onPlaybackCompleted(PlayerWrapper.this);
}
@Override
public void onVideoSizeChanged(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.common.VideoSize videoSize) {
mWrapperCallback.onVideoSizeChanged(PlayerWrapper.this, videoSize);
}
@Override
public void onSubtitleData(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.common.MediaItem item,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo track,
@NonNull androidx.media2.common.SubtitleData data) {
mWrapperCallback.onSubtitleData(PlayerWrapper.this, item, track, data);
}
@Override
public void onTracksChanged(
@NonNull androidx.media2.session.MediaController controller,
@NonNull List<androidx.media2.common.SessionPlayer.TrackInfo> tracks) {
mWrapperCallback.onTracksChanged(PlayerWrapper.this, tracks);
}
@Override
public void onTrackSelected(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
mWrapperCallback.onTrackSelected(PlayerWrapper.this, trackInfo);
}
@Override
public void onTrackDeselected(
@NonNull androidx.media2.session.MediaController controller,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
mWrapperCallback.onTrackDeselected(PlayerWrapper.this, trackInfo);
}
}
private void notifyNonCachedStates() {
mWrapperCallback.onPlaybackSpeedChanged(this, getPlaybackSpeed());
List<androidx.media2.common.SessionPlayer.TrackInfo> trackInfos = getTracks();
if (trackInfos != null) {
mWrapperCallback.onTracksChanged(PlayerWrapper.this, trackInfos);
}
androidx.media2.common.MediaItem item = getCurrentMediaItem();
if (item != null) {
mWrapperCallback.onVideoSizeChanged(PlayerWrapper.this, getVideoSize());
}
}
private class SessionPlayerCallback
extends androidx.media2.common.SessionPlayer.PlayerCallback {
SessionPlayerCallback() {
}
@Override
public void onPlayerStateChanged(
@NonNull androidx.media2.common.SessionPlayer player, int playerState) {
if (mSavedPlayerState == playerState) return;
mSavedPlayerState = playerState;
mWrapperCallback.onPlayerStateChanged(PlayerWrapper.this, playerState);
}
@Override
public void onPlaybackSpeedChanged(
@NonNull androidx.media2.common.SessionPlayer player, float playbackSpeed) {
mWrapperCallback.onPlaybackSpeedChanged(PlayerWrapper.this, playbackSpeed);
}
@Override
public void onSeekCompleted(
@NonNull androidx.media2.common.SessionPlayer player, long position) {
mWrapperCallback.onSeekCompleted(PlayerWrapper.this, position);
}
@Override
public void onCurrentMediaItemChanged(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull androidx.media2.common.MediaItem item) {
mMediaMetadata = item == null ? null : item.getMetadata();
mWrapperCallback.onCurrentMediaItemChanged(PlayerWrapper.this, item);
}
@Override
public void onPlaylistChanged(
@NonNull androidx.media2.common.SessionPlayer player,
@Nullable List<androidx.media2.common.MediaItem> list,
@Nullable androidx.media2.common.MediaMetadata metadata) {
mWrapperCallback.onPlaylistChanged(PlayerWrapper.this, list, metadata);
}
@Override
public void onPlaybackCompleted(@NonNull androidx.media2.common.SessionPlayer player) {
mWrapperCallback.onPlaybackCompleted(PlayerWrapper.this);
}
@Override
public void onVideoSizeChanged(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull androidx.media2.common.VideoSize size) {
mWrapperCallback.onVideoSizeChanged(PlayerWrapper.this, size);
}
@Override
public void onSubtitleData(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull androidx.media2.common.MediaItem item,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo track,
@NonNull androidx.media2.common.SubtitleData data) {
mWrapperCallback.onSubtitleData(PlayerWrapper.this, item, track, data);
}
@Override
public void onTracksChanged(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull List<androidx.media2.common.SessionPlayer.TrackInfo> tracks) {
mWrapperCallback.onTracksChanged(PlayerWrapper.this, tracks);
}
@Override
public void onTrackSelected(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
mWrapperCallback.onTrackSelected(PlayerWrapper.this, trackInfo);
}
@Override
public void onTrackDeselected(
@NonNull androidx.media2.common.SessionPlayer player,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {
mWrapperCallback.onTrackDeselected(PlayerWrapper.this, trackInfo);
}
}
abstract static class PlayerCallback {
void onConnected(@NonNull PlayerWrapper player) {
}
void onAllowedCommandsChanged(
@NonNull PlayerWrapper player,
@NonNull androidx.media2.session.SessionCommandGroup commands) {}
void onCurrentMediaItemChanged(
@NonNull PlayerWrapper player, @Nullable androidx.media2.common.MediaItem item) {}
void onPlaylistChanged(
@NonNull PlayerWrapper player,
@Nullable List<androidx.media2.common.MediaItem> list,
@Nullable androidx.media2.common.MediaMetadata metadata) {}
void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
}
void onPlaybackSpeedChanged(@NonNull PlayerWrapper player, float speed) {
}
void onSeekCompleted(@NonNull PlayerWrapper player, long position) {
}
void onPlaybackCompleted(@NonNull PlayerWrapper player) {
}
void onVideoSizeChanged(
@NonNull PlayerWrapper player,
@NonNull androidx.media2.common.VideoSize videoSize) {}
void onTracksChanged(
@NonNull PlayerWrapper player,
@NonNull List<androidx.media2.common.SessionPlayer.TrackInfo> tracks) {}
void onTrackSelected(
@NonNull PlayerWrapper player,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {}
void onTrackDeselected(
@NonNull PlayerWrapper player,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo trackInfo) {}
void onSubtitleData(
@NonNull PlayerWrapper player,
@NonNull androidx.media2.common.MediaItem item,
@NonNull androidx.media2.common.SessionPlayer.TrackInfo track,
@NonNull androidx.media2.common.SubtitleData data) {}
}
}