/*
* Copyright 2018 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;
import static androidx.media2.SessionCommand2.COMMAND_CODE_CUSTOM;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import androidx.media.MediaSessionManager;
import androidx.media.MediaSessionManager.RemoteUserInfo;
import androidx.media2.MediaController2.PlaybackInfo;
import androidx.media2.MediaSession2.CommandButton;
import androidx.media2.MediaSession2.ControllerCb;
import androidx.media2.MediaSession2.ControllerInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@TargetApi(Build.VERSION_CODES.KITKAT)
// Getting the commands from MediaControllerCompat'
class MediaSessionLegacyStub extends MediaSessionCompat.Callback {
private static final String TAG = "MediaSessionLegacyStub";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@SuppressWarnings("WeakerAccess") /* synthetic access */
static final SparseArray<SessionCommand2> sCommandsForOnCommandRequest =
new SparseArray<>();
static {
SessionCommandGroup2 group = new SessionCommandGroup2();
group.addAllPlaybackCommands();
group.addAllPlaylistCommands();
group.addAllVolumeCommands();
Set<SessionCommand2> commands = group.getCommands();
for (SessionCommand2 command : commands) {
sCommandsForOnCommandRequest.append(command.getCommandCode(), command);
}
}
final Object mLock = new Object();
final MediaSession2.SupportLibraryImpl mSession;
final MediaSessionManager mSessionManager;
final Context mContext;
final ControllerInfo mControllerInfoForAll;
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
final ArrayMap<RemoteUserInfo, ControllerInfo> mControllers = new ArrayMap<>();
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Set<IBinder> mConnectingControllers = new HashSet<>();
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
final ArrayMap<ControllerInfo, SessionCommandGroup2> mAllowedCommandGroupMap =
new ArrayMap<>();
@GuardedBy("mLock")
@SuppressWarnings("WeakerAccess") /* synthetic access */
PlaybackStateCompat mPlaybackState = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_NONE, 0, 1.0f)
.build();
MediaSessionLegacyStub(MediaSession2.SupportLibraryImpl session) {
mSession = session;
mContext = mSession.getContext();
mSessionManager = MediaSessionManager.getSessionManager(mContext);
mControllerInfoForAll = new ControllerInfo(
new RemoteUserInfo(
RemoteUserInfo.LEGACY_CONTROLLER, Process.myPid(), Process.myUid()),
false /* trusted */,
new ControllerLegacyCbForAll());
}
@Override
public void onCommand(@NonNull String command, @Nullable Bundle args,
@Nullable ResultReceiver cb) {
}
@Override
public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
return false;
}
@Override
public void onPrepare() {
onSessionCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE, new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.prepare();
}
});
}
@Override
public void onPrepareFromMediaId(final String mediaId, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPrepareFromMediaId(mSession.getInstance(),
controller, mediaId, extras);
}
});
}
@Override
public void onPrepareFromSearch(final String query, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPrepareFromSearch(mSession.getInstance(),
controller, query, extras);
}
});
}
@Override
public void onPrepareFromUri(final Uri uri, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPrepareFromUri(mSession.getInstance(),
controller, uri, extras);
}
});
}
@Override
public void onPlay() {
onSessionCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY, new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.play();
}
});
}
@Override
public void onPlayFromMediaId(final String mediaId, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPlayFromMediaId(mSession.getInstance(),
controller, mediaId, extras);
}
});
}
@Override
public void onPlayFromSearch(final String query, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPlayFromSearch(mSession.getInstance(),
controller, query, extras);
}
});
}
@Override
public void onPlayFromUri(final Uri uri, final Bundle extras) {
onSessionCommand(SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI,
new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.getCallback().onPlayFromUri(mSession.getInstance(),
controller, uri, extras);
}
});
}
@Override
public void onPause() {
onSessionCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE, new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.pause();
}
});
}
@Override
public void onStop() {
onSessionCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_RESET, new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.reset();
}
});
}
@Override
public void onSeekTo(final long pos) {
onSessionCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO, new SessionRunnable() {
@Override
public void run(ControllerInfo controller) throws RemoteException {
mSession.seekTo(pos);
}
});
}
@Override
public void onSkipToNext() {
}
@Override
public void onSkipToPrevious() {
}
@Override
public void onSkipToQueueItem(long id) {
}
@Override
public void onFastForward() {
}
@Override
public void onRewind() {
}
@Override
public void onSetRating(@NonNull RatingCompat rating) {
}
@Override
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
}
List<ControllerInfo> getConnectedControllers() {
ArrayList<ControllerInfo> controllers = new ArrayList<>();
synchronized (mLock) {
for (int i = 0; i < mControllers.size(); i++) {
controllers.add(mControllers.valueAt(i));
}
}
return controllers;
}
ControllerInfo getControllersForAll() {
return mControllerInfoForAll;
}
void setAllowedCommands(ControllerInfo controller, final SessionCommandGroup2 commands) {
synchronized (mLock) {
mAllowedCommandGroupMap.put(controller, commands);
}
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean isAllowedCommand(ControllerInfo controller, SessionCommand2 command) {
SessionCommandGroup2 allowedCommands;
synchronized (mLock) {
allowedCommands = mAllowedCommandGroupMap.get(controller);
}
return allowedCommands != null && allowedCommands.hasCommand(command);
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean isAllowedCommand(ControllerInfo controller, int commandCode) {
SessionCommandGroup2 allowedCommands;
synchronized (mLock) {
allowedCommands = mAllowedCommandGroupMap.get(controller);
}
return allowedCommands != null && allowedCommands.hasCommand(commandCode);
}
private void onSessionCommand(final int commandCode, @NonNull final SessionRunnable runnable) {
onSessionCommandInternal(null, commandCode, runnable);
}
private void onSessionCommand(@NonNull final SessionCommand2 sessionCommand,
@NonNull final SessionRunnable runnable) {
onSessionCommandInternal(sessionCommand, COMMAND_CODE_CUSTOM, runnable);
}
private void onSessionCommandInternal(@Nullable final SessionCommand2 sessionCommand,
final int commandCode, @NonNull final SessionRunnable runnable) {
if (mSession.isClosed()) {
return;
}
RemoteUserInfo remoteUserInfo = mSession.getSessionCompat().getCurrentControllerInfo();
final ControllerInfo controller;
synchronized (mLock) {
if (remoteUserInfo == null) {
controller = null;
} else if (mControllers.containsKey(remoteUserInfo)) {
controller = mControllers.get(remoteUserInfo);
} else {
controller = new ControllerInfo(
remoteUserInfo,
mSessionManager.isTrustedForMediaControl(remoteUserInfo),
new ControllerLegacyCb(remoteUserInfo));
connect(controller);
}
}
mSession.getCallbackExecutor().execute(new Runnable() {
@Override
public void run() {
synchronized (mLock) {
if (controller != null && !mControllers.containsValue(controller)) {
return;
}
}
SessionCommand2 command;
if (sessionCommand == null) {
if (!isAllowedCommand(controller, commandCode)) {
return;
}
command = sCommandsForOnCommandRequest.get(commandCode);
} else {
if (!isAllowedCommand(controller, sessionCommand)) {
return;
}
command = sessionCommand;
}
if (command == null) {
return;
}
boolean accepted = mSession.getCallback().onCommandRequest(
mSession.getInstance(), controller, command);
if (!accepted) {
// Don't run rejected command.
if (DEBUG) {
Log.d(TAG, "Command (" + command + ") from "
+ controller + " was rejected by " + mSession);
}
return;
}
try {
runnable.run(controller);
} catch (RemoteException e) {
// Currently it's TransactionTooLargeException or DeadSystemException.
// We'd better to leave log for those cases because
// - TransactionTooLargeException means that we may need to fix our code.
// (e.g. add pagination or special way to deliver Bitmap)
// - DeadSystemException means that errors around it can be ignored.
Log.w(TAG, "Exception in " + controller.toString(), e);
}
}
});
}
// private void onCommand2(@NonNull IBinder caller, final int commandCode,
// @NonNull final SessionRunnable runnable) {
// onCommand2Internal(caller, null, commandCode, runnable);
// }
//
// private void onCommand2(@NonNull IBinder caller,
// @NonNull final SessionCommand2 sessionCommand,
// @NonNull final SessionRunnable runnable) {
// onCommand2Internal(caller, sessionCommand, COMMGAND_CODE_CUSTOM, runnable);
// }
// private void onCommand2Internal(@NonNull IBinder caller,
// @Nullable final SessionCommand2 sessionCommand, final int commandCode,
// @NonNull final SessionRunnable runnable) {
// final ControllerInfo controller;
// synchronized (mLock) {
// controller = mControllers.get(caller);
// }
// if (mSession == null || controller == null) {
// return;
// }
// mSession.getCallbackExecutor().execute(new Runnable() {
// @Override
// public void run() {
// SessionCommand2 command;
// if (sessionCommand != null) {
// if (!isAllowedCommand(controller, sessionCommand)) {
// return;
// }
// command = sCommandsForOnCommandRequest.get(sessionCommand.getCommandCode());
// } else {
// if (!isAllowedCommand(controller, commandCode)) {
// return;
// }
// command = sCommandsForOnCommandRequest.get(commandCode);
// }
// if (command != null) {
// boolean accepted = mSession.getCallback().onCommandRequest(
// mSession.getInstance(), controller, command);
// if (!accepted) {
// // Don't run rejected command.
// if (DEBUG) {
// Log.d(TAG, "Command (" + command + ") from "
// + controller + " was rejected by " + mSession);
// }
// return;
// }
// }
// try {
// runnable.run(controller);
// } catch (RemoteException e) {
// // Currently it's TransactionTooLargeException or DeadSystemException.
// // We'd better to leave log for those cases because
// // - TransactionTooLargeException means that we may need to fix our code.
// // (e.g. add pagination or special way to deliver Bitmap)
// // - DeadSystemException means that errors around it can be ignored.
// Log.w(TAG, "Exception in " + controller.toString(), e);
// }
// }
// });
// }
// void removeControllerInfo(ControllerInfo controller) {
// synchronized (mLock) {
// controller = mControllers.remove(controller.getId());
// if (DEBUG) {
// Log.d(TAG, "releasing " + controller);
// }
// }
// }
//
// private ControllerInfo createControllerInfo(Context context, Bundle extras) {
// IMediaControllerCallback callback = IMediaControllerCallback.Stub.asInterface(
// BundleCompat.getBinder(extras, ARGUMENT_ICONTROLLER_CALLBACK));
// String packageName = extras.getString(ARGUMENT_PACKAGE_NAME);
// int uid = extras.getInt(ARGUMENT_UID);
// int pid = extras.getInt(ARGUMENT_PID);
// MediaSessionManager sessionManager = MediaSessionManager.getSessionManager(context);
// RemoteUserInfo remoteUserInfo = new RemoteUserInfo(packageName, pid, uid);
// return new ControllerInfo(remoteUserInfo,
// sessionManager.isTrustedForMediaControl(remoteUserInfo),
// new ControllerLegacyCb(callback));
// }
//
private void connect(final ControllerInfo controller) {
mSession.getCallbackExecutor().execute(new Runnable() {
@Override
public void run() {
if (mSession.isClosed()) {
return;
}
SessionCommandGroup2 allowedCommands = mSession.getCallback().onConnect(
mSession.getInstance(), controller);
if (allowedCommands == null) {
try {
controller.getControllerCb().onDisconnected();
} catch (RemoteException ex) {
// Controller may have died prematurely.
}
return;
}
synchronized (mLock) {
mControllers.put(controller.getRemoteUserInfo(), controller);
mAllowedCommandGroupMap.put(controller, allowedCommands);
}
}
});
}
// private void disconnect(Context context, Bundle extras) {
// final ControllerInfo controllerInfo = createControllerInfo(context, extras);
// mSession.getCallbackExecutor().execute(new Runnable() {
// @Override
// public void run() {
// if (mSession.isClosed()) {
// return;
// }
// mSession.getCallback().onDisconnected(mSession.getInstance(), controllerInfo);
// }
// });
// }
@FunctionalInterface
private interface SessionRunnable {
void run(ControllerInfo controller) throws RemoteException;
}
final class ControllerLegacyCb extends ControllerCb {
private final RemoteUserInfo mRemoteUserInfo;
ControllerLegacyCb(RemoteUserInfo remoteUserInfo) {
mRemoteUserInfo = remoteUserInfo;
}
@Override
void onCustomLayoutChanged(List<CommandButton> layout) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_COMMAND_BUTTONS,
// MediaUtils2.convertCommandButtonListToParcelableArray(layout));
// mIControllerCallback.onEvent(SESSION_EVENT_SET_CUSTOM_LAYOUT, bundle);
}
@Override
void onPlaybackInfoChanged(PlaybackInfo info) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_PLAYBACK_INFO, info.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED, bundle);
}
@Override
void onAllowedCommandsChanged(SessionCommandGroup2 commands) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_ALLOWED_COMMANDS, commands.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED, bundle);
}
@Override
void onCustomCommand(SessionCommand2 command, Bundle args, ResultReceiver receiver)
throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_CUSTOM_COMMAND, command.toBundle());
// bundle.putBundle(ARGUMENT_ARGUMENTS, args);
// bundle.putParcelable(ARGUMENT_RESULT_RECEIVER, receiver);
// mIControllerCallback.onEvent(SESSION_EVENT_SEND_CUSTOM_COMMAND, bundle);
}
@Override
void onPlayerStateChanged(long eventTimeMs, long positionMs, int playerState)
throws RemoteException {
final int state = MediaUtils2.convertToPlaybackStateCompatState(
playerState, mSession.getBufferingState());
// Note: current position should be also sent to the controller here for controller
// to calculate the position more correctly.
PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder()
.setState(state, positionMs, mSession.getPlaybackSpeed(), eventTimeMs)
.build();
synchronized (mLock) {
mPlaybackState = playbackState;
}
mSession.getSessionCompat().setPlaybackState(mRemoteUserInfo, playbackState);
}
@Override
void onPlaybackSpeedChanged(long eventTimeMs, long positionMs, float speed)
throws RemoteException {
// // Note: current position should be also sent to the controller here for controller
// // to calculate the position more correctly.
// Bundle bundle = new Bundle();
// bundle.putParcelable(
// ARGUMENT_PLAYBACK_STATE_COMPAT, mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYBACK_SPEED_CHANGED, bundle);
}
@Override
void onBufferingStateChanged(MediaItem2 item, int state, long bufferedPositionMs)
throws RemoteException {
// // Note: buffered position should be also sent to the controller here. It's to
// // follow the behavior of BaseMediaPlayer.PlayerEventCallback.
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_MEDIA_ITEM, item.toBundle());
// bundle.putInt(ARGUMENT_BUFFERING_STATE, state);
// bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
// mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_BUFFERING_STATE_CHANGED, bundle);
}
@Override
void onSeekCompleted(long eventTimeMs, long positionMs, long position)
throws RemoteException {
// // Note: current position should be also sent to the controller here because the
// // position here may refer to the parameter of the previous seek() API calls.
// Bundle bundle = new Bundle();
// bundle.putLong(ARGUMENT_SEEK_POSITION, position);
// bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
// mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_SEEK_COMPLETED, bundle);
}
@Override
void onError(int errorCode, Bundle extras) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putInt(ARGUMENT_ERROR_CODE, errorCode);
// bundle.putBundle(ARGUMENT_EXTRAS, extras);
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ERROR, bundle);
}
@Override
void onCurrentMediaItemChanged(MediaItem2 item) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_MEDIA_ITEM, (item == null) ? null : item.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_CURRENT_MEDIA_ITEM_CHANGED, bundle);
}
@Override
void onPlaylistChanged(List<MediaItem2> playlist, MediaMetadata2 metadata)
throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_PLAYLIST,
// MediaUtils2.convertMediaItem2ListToParcelableArray(playlist));
// bundle.putBundle(ARGUMENT_PLAYLIST_METADATA,
// metadata == null ? null : metadata.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYLIST_CHANGED, bundle);
}
@Override
void onPlaylistMetadataChanged(MediaMetadata2 metadata) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_PLAYLIST_METADATA,
// metadata == null ? null : metadata.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED, bundle);
}
@Override
void onShuffleModeChanged(int shuffleMode) throws RemoteException {
// no-op
}
@Override
void onRepeatModeChanged(int repeatMode) throws RemoteException {
// no-op
}
@Override
void onRoutesInfoChanged(List<Bundle> routes) throws RemoteException {
// Bundle bundle = null;
// if (routes != null) {
// bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_ROUTE_BUNDLE, routes.toArray(new Bundle[0]));
// }
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ROUTES_INFO_CHANGED, bundle);
}
@Override
void onGetLibraryRootDone(Bundle rootHints, String rootMediaId, Bundle rootExtra)
throws RemoteException {
// no-op
}
@Override
void onChildrenChanged(String parentId, int itemCount, Bundle extras)
throws RemoteException {
// no-op
}
@Override
void onGetChildrenDone(String parentId, int page, int pageSize, List<MediaItem2> result,
Bundle extras) throws RemoteException {
// no-op
}
@Override
void onGetItemDone(String mediaId, MediaItem2 result) throws RemoteException {
// no-op
}
@Override
void onSearchResultChanged(String query, int itemCount, Bundle extras)
throws RemoteException {
// no-op
}
@Override
void onGetSearchResultDone(String query, int page, int pageSize, List<MediaItem2> result,
Bundle extras) throws RemoteException {
// no-op
}
@Override
void onDisconnected() throws RemoteException {
// TODO: Find a way to disconnect a specific controller in MediaSessionCompat.
}
}
final class ControllerLegacyCbForAll extends ControllerCb {
ControllerLegacyCbForAll() {
}
@Override
void onCustomLayoutChanged(List<CommandButton> layout) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_COMMAND_BUTTONS,
// MediaUtils2.convertCommandButtonListToParcelableArray(layout));
// mIControllerCallback.onEvent(SESSION_EVENT_SET_CUSTOM_LAYOUT, bundle);
}
@Override
void onPlaybackInfoChanged(PlaybackInfo info) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_PLAYBACK_INFO, info.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYBACK_INFO_CHANGED, bundle);
}
@Override
void onAllowedCommandsChanged(SessionCommandGroup2 commands) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_ALLOWED_COMMANDS, commands.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ALLOWED_COMMANDS_CHANGED, bundle);
}
@Override
void onCustomCommand(SessionCommand2 command, Bundle args, ResultReceiver receiver)
throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_CUSTOM_COMMAND, command.toBundle());
// bundle.putBundle(ARGUMENT_ARGUMENTS, args);
// bundle.putParcelable(ARGUMENT_RESULT_RECEIVER, receiver);
// mIControllerCallback.onEvent(SESSION_EVENT_SEND_CUSTOM_COMMAND, bundle);
}
@Override
void onPlayerStateChanged(long eventTimeMs, long positionMs, int playerState)
throws RemoteException {
final int state = MediaUtils2.convertToPlaybackStateCompatState(
playerState, mSession.getBufferingState());
// Note: current position should be also sent to the controller here for controller
// to calculate the position more correctly.
PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder()
.setState(state, positionMs, mSession.getPlaybackSpeed(), eventTimeMs)
.build();
synchronized (mLock) {
mPlaybackState = playbackState;
}
mSession.getSessionCompat().setPlaybackState(playbackState);
}
@Override
void onPlaybackSpeedChanged(long eventTimeMs, long positionMs, float speed)
throws RemoteException {
// // Note: current position should be also sent to the controller here for controller
// // to calculate the position more correctly.
// Bundle bundle = new Bundle();
// bundle.putParcelable(
// ARGUMENT_PLAYBACK_STATE_COMPAT, mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYBACK_SPEED_CHANGED, bundle);
}
@Override
void onBufferingStateChanged(MediaItem2 item, int state, long bufferedPositionMs)
throws RemoteException {
// // Note: buffered position should be also sent to the controller here. It's to
// // follow the behavior of BaseMediaPlayer.PlayerEventCallback.
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_MEDIA_ITEM, item.toBundle());
// bundle.putInt(ARGUMENT_BUFFERING_STATE, state);
// bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
// mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_BUFFERING_STATE_CHANGED, bundle);
}
@Override
void onSeekCompleted(long eventTimeMs, long positionMs, long position)
throws RemoteException {
// // Note: current position should be also sent to the controller here because the
// // position here may refer to the parameter of the previous seek() API calls.
// Bundle bundle = new Bundle();
// bundle.putLong(ARGUMENT_SEEK_POSITION, position);
// bundle.putParcelable(ARGUMENT_PLAYBACK_STATE_COMPAT,
// mSession.getPlaybackStateCompat());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_SEEK_COMPLETED, bundle);
}
@Override
void onError(int errorCode, Bundle extras) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putInt(ARGUMENT_ERROR_CODE, errorCode);
// bundle.putBundle(ARGUMENT_EXTRAS, extras);
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ERROR, bundle);
}
@Override
void onCurrentMediaItemChanged(MediaItem2 item) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_MEDIA_ITEM, (item == null) ? null : item.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_CURRENT_MEDIA_ITEM_CHANGED, bundle);
}
@Override
void onPlaylistChanged(List<MediaItem2> playlist, MediaMetadata2 metadata)
throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_PLAYLIST,
// MediaUtils2.convertMediaItem2ListToParcelableArray(playlist));
// bundle.putBundle(ARGUMENT_PLAYLIST_METADATA,
// metadata == null ? null : metadata.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYLIST_CHANGED, bundle);
}
@Override
void onPlaylistMetadataChanged(MediaMetadata2 metadata) throws RemoteException {
// Bundle bundle = new Bundle();
// bundle.putBundle(ARGUMENT_PLAYLIST_METADATA,
// metadata == null ? null : metadata.toBundle());
// mIControllerCallback.onEvent(SESSION_EVENT_ON_PLAYLIST_METADATA_CHANGED, bundle);
}
@Override
void onShuffleModeChanged(int shuffleMode) throws RemoteException {
mSession.getSessionCompat().setShuffleMode(shuffleMode);
}
@Override
void onRepeatModeChanged(int repeatMode) throws RemoteException {
mSession.getSessionCompat().setRepeatMode(repeatMode);
}
@Override
void onRoutesInfoChanged(List<Bundle> routes) throws RemoteException {
// Bundle bundle = null;
// if (routes != null) {
// bundle = new Bundle();
// bundle.putParcelableArray(ARGUMENT_ROUTE_BUNDLE, routes.toArray(new Bundle[0]));
// }
// mIControllerCallback.onEvent(SESSION_EVENT_ON_ROUTES_INFO_CHANGED, bundle);
}
@Override
void onGetLibraryRootDone(Bundle rootHints, String rootMediaId, Bundle rootExtra)
throws RemoteException {
// no-op
}
@Override
void onChildrenChanged(String parentId, int itemCount, Bundle extras)
throws RemoteException {
// no-op
}
@Override
void onGetChildrenDone(String parentId, int page, int pageSize, List<MediaItem2> result,
Bundle extras) throws RemoteException {
// no-op
}
@Override
void onGetItemDone(String mediaId, MediaItem2 result) throws RemoteException {
// no-op
}
@Override
void onSearchResultChanged(String query, int itemCount, Bundle extras)
throws RemoteException {
// no-op
}
@Override
void onGetSearchResultDone(String query, int page, int pageSize, List<MediaItem2> result,
Bundle extras) throws RemoteException {
// no-op
}
@Override
void onDisconnected() throws RemoteException {
mSession.getSessionCompat().release();
}
}
}