blob: 2cfc5df0959e119022dff7442d2e599f30ca48cf [file] [log] [blame]
/*
* 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 com.android.media;
import android.app.PendingIntent;
import android.content.Context;
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.SessionCommand2;
import android.media.MediaSession2.CommandButton;
import android.media.SessionCommandGroup2;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.util.Log;
import com.android.media.MediaController2Impl.PlaybackInfoImpl;
import com.android.media.MediaSession2Impl.CommandButtonImpl;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class MediaController2Stub extends IMediaController2.Stub {
private static final String TAG = "MediaController2Stub";
private static final boolean DEBUG = true; // TODO(jaewan): Change
private final WeakReference<MediaController2Impl> mController;
MediaController2Stub(MediaController2Impl controller) {
mController = new WeakReference<>(controller);
}
private MediaController2Impl getController() throws IllegalStateException {
final MediaController2Impl controller = mController.get();
if (controller == null) {
throw new IllegalStateException("Controller is released");
}
return controller;
}
private MediaBrowser2Impl getBrowser() throws IllegalStateException {
final MediaController2Impl controller = getController();
if (controller instanceof MediaBrowser2Impl) {
return (MediaBrowser2Impl) controller;
}
return null;
}
public void destroy() {
mController.clear();
}
@Override
public void onPlayerStateChanged(int state) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
controller.pushPlayerStateChanges(state);
}
@Override
public void onPositionChanged(long eventTimeMs, long positionMs) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (eventTimeMs < 0) {
Log.w(TAG, "onPositionChanged(): Ignoring negative eventTimeMs");
return;
}
if (positionMs < 0) {
Log.w(TAG, "onPositionChanged(): Ignoring negative positionMs");
return;
}
controller.pushPositionChanges(eventTimeMs, positionMs);
}
@Override
public void onPlaybackSpeedChanged(float speed) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
controller.pushPlaybackSpeedChanges(speed);
}
@Override
public void onBufferedPositionChanged(long bufferedPositionMs) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (bufferedPositionMs < 0) {
Log.w(TAG, "onBufferedPositionChanged(): Ignoring negative bufferedPositionMs");
return;
}
controller.pushBufferedPositionChanges(bufferedPositionMs);
}
@Override
public void onPlaylistChanged(List<Bundle> playlistBundle, Bundle metadataBundle) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (playlistBundle == null) {
Log.w(TAG, "onPlaylistChanged(): Ignoring null playlist from " + controller);
return;
}
List<MediaItem2> playlist = new ArrayList<>();
for (Bundle bundle : playlistBundle) {
MediaItem2 item = MediaItem2.fromBundle(bundle);
if (item == null) {
Log.w(TAG, "onPlaylistChanged(): Ignoring null item in playlist");
} else {
playlist.add(item);
}
}
MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
controller.pushPlaylistChanges(playlist, metadata);
}
@Override
public void onPlaylistMetadataChanged(Bundle metadataBundle) throws RuntimeException {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle);
controller.pushPlaylistMetadataChanges(metadata);
}
@Override
public void onRepeatModeChanged(int repeatMode) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
controller.pushRepeatModeChanges(repeatMode);
}
@Override
public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
if (DEBUG) {
Log.d(TAG, "onPlaybackInfoChanged");
}
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
MediaController2.PlaybackInfo info = PlaybackInfoImpl.fromBundle(playbackInfo);
if (info == null) {
Log.w(TAG, "onPlaybackInfoChanged(): Ignoring null playbackInfo");
return;
}
controller.pushPlaybackInfoChanges(info);
}
@Override
public void onShuffleModeChanged(int shuffleMode) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
controller.pushShuffleModeChanges(shuffleMode);
}
@Override
public void onError(int errorCode, Bundle extras) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
controller.pushError(errorCode, extras);
}
@Override
public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
int playerState, long positionEventTimeMs, long positionMs, float playbackSpeed,
long bufferedPositionMs, Bundle playbackInfo, int shuffleMode, int repeatMode,
List<Bundle> itemBundleList, PendingIntent sessionActivity) {
final MediaController2Impl controller = mController.get();
if (controller == null) {
if (DEBUG) {
Log.d(TAG, "onConnected after MediaController2.close()");
}
return;
}
final Context context = controller.getContext();
List<MediaItem2> itemList = null;
if (itemBundleList != null) {
itemList = new ArrayList<>();
for (int i = 0; i < itemBundleList.size(); i++) {
MediaItem2 item = MediaItem2.fromBundle(itemBundleList.get(i));
if (item != null) {
itemList.add(item);
}
}
}
controller.onConnectedNotLocked(sessionBinder,
SessionCommandGroup2.fromBundle(commandGroup),
playerState, positionEventTimeMs, positionMs, playbackSpeed, bufferedPositionMs,
PlaybackInfoImpl.fromBundle(playbackInfo), repeatMode, shuffleMode,
itemList, sessionActivity);
}
@Override
public void onDisconnected() {
final MediaController2Impl controller = mController.get();
if (controller == null) {
if (DEBUG) {
Log.d(TAG, "onDisconnected after MediaController2.close()");
}
return;
}
controller.getInstance().close();
}
@Override
public void onCustomLayoutChanged(List<Bundle> commandButtonlist) {
if (commandButtonlist == null) {
Log.w(TAG, "onCustomLayoutChanged(): Ignoring null commandButtonlist");
return;
}
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (controller == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
List<CommandButton> layout = new ArrayList<>();
for (int i = 0; i < commandButtonlist.size(); i++) {
CommandButton button = CommandButtonImpl.fromBundle(commandButtonlist.get(i));
if (button != null) {
layout.add(button);
}
}
controller.onCustomLayoutChanged(layout);
}
@Override
public void onAllowedCommandsChanged(Bundle commandsBundle) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (controller == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
SessionCommandGroup2 commands = SessionCommandGroup2.fromBundle(commandsBundle);
if (commands == null) {
Log.w(TAG, "onAllowedCommandsChanged(): Ignoring null commands");
return;
}
controller.onAllowedCommandsChanged(commands);
}
@Override
public void onCustomCommand(Bundle commandBundle, Bundle args, ResultReceiver receiver) {
final MediaController2Impl controller;
try {
controller = getController();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
SessionCommand2 command = SessionCommand2.fromBundle(commandBundle);
if (command == null) {
Log.w(TAG, "onCustomCommand(): Ignoring null command");
return;
}
controller.onCustomCommand(command, args, receiver);
}
////////////////////////////////////////////////////////////////////////////////////////////
// MediaBrowser specific
////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onGetLibraryRootDone(Bundle rootHints, String rootMediaId, Bundle rootExtra)
throws RuntimeException {
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
browser.onGetLibraryRootDone(rootHints, rootMediaId, rootExtra);
}
@Override
public void onGetItemDone(String mediaId, Bundle itemBundle) throws RuntimeException {
if (mediaId == null) {
Log.w(TAG, "onGetItemDone(): Ignoring null mediaId");
return;
}
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
browser.onGetItemDone(mediaId, MediaItem2.fromBundle(itemBundle));
}
@Override
public void onGetChildrenDone(String parentId, int page, int pageSize,
List<Bundle> itemBundleList, Bundle extras) throws RuntimeException {
if (parentId == null) {
Log.w(TAG, "onGetChildrenDone(): Ignoring null parentId");
return;
}
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
List<MediaItem2> result = null;
if (itemBundleList != null) {
result = new ArrayList<>();
for (Bundle bundle : itemBundleList) {
result.add(MediaItem2.fromBundle(bundle));
}
}
browser.onGetChildrenDone(parentId, page, pageSize, result, extras);
}
@Override
public void onSearchResultChanged(String query, int itemCount, Bundle extras)
throws RuntimeException {
if (TextUtils.isEmpty(query)) {
Log.w(TAG, "onSearchResultChanged(): Ignoring empty query");
return;
}
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
browser.onSearchResultChanged(query, itemCount, extras);
}
@Override
public void onGetSearchResultDone(String query, int page, int pageSize,
List<Bundle> itemBundleList, Bundle extras) throws RuntimeException {
if (TextUtils.isEmpty(query)) {
Log.w(TAG, "onGetSearchResultDone(): Ignoring empty query");
return;
}
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
List<MediaItem2> result = null;
if (itemBundleList != null) {
result = new ArrayList<>();
for (Bundle bundle : itemBundleList) {
result.add(MediaItem2.fromBundle(bundle));
}
}
browser.onGetSearchResultDone(query, page, pageSize, result, extras);
}
@Override
public void onChildrenChanged(String parentId, int itemCount, Bundle extras) {
if (parentId == null) {
Log.w(TAG, "onChildrenChanged(): Ignoring null parentId");
return;
}
final MediaBrowser2Impl browser;
try {
browser = getBrowser();
} catch (IllegalStateException e) {
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
if (browser == null) {
// TODO(jaewan): Revisit here. Could be a bug
return;
}
browser.onChildrenChanged(parentId, itemCount, extras);
}
}