Merge changes from topics "public_browser2", "public_mediasession2"

* changes:
  MediaSession2: Public APIs for MediaBrowser2 and MediaLibraryService2
  MediaSession2: Public APIs for MediaSession2 and MediaController2
gugelfrei
Jaewan Kim 7 years ago committed by Android (Google) Code Review
commit 38428ce1b3

@ -61,6 +61,31 @@ public class MediaBrowser2Impl extends MediaController2Impl implements MediaBrow
}
}
@Override
public void subscribe_impl(String parentId, Bundle options) {
// TODO(jaewan): Implement
}
@Override
public void unsubscribe_impl(String parentId, Bundle options) {
// TODO(jaewan): Implement
}
@Override
public void getItem_impl(String mediaId) {
// TODO(jaewan): Implement
}
@Override
public void getChildren_impl(String parentId, int page, int pageSize, Bundle options) {
// TODO(jaewan): Implement
}
@Override
public void search_impl(String query, int page, int pageSize, Bundle extras) {
// TODO(jaewan): Implement
}
public void onGetRootResult(
final Bundle rootHints, final String rootMediaId, final Bundle rootExtra) {
getCallbackExecutor().execute(() -> {

@ -16,12 +16,15 @@
package com.android.media;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.IMediaSession2;
import android.media.IMediaSession2Callback;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
@ -29,14 +32,19 @@ import android.media.MediaSession2.CommandGroup;
import android.media.MediaController2;
import android.media.MediaController2.ControllerCallback;
import android.media.MediaPlayerBase;
import android.media.MediaSession2.PlaylistParam;
import android.media.MediaSessionService2;
import android.media.PlaybackState2;
import android.media.Rating2;
import android.media.SessionToken;
import android.media.session.PlaybackState;
import android.media.update.MediaController2Provider;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
import android.util.Log;
@ -257,69 +265,128 @@ public class MediaController2Impl implements MediaController2Provider {
}
}
//////////////////////////////////////////////////////////////////////////////////////
// TODO(jaewan): Implement follows
//////////////////////////////////////////////////////////////////////////////////////
@Override
public PlaybackState getPlaybackState_impl() {
final IMediaSession2 binder = mSessionBinder;
if (binder != null) {
try {
return binder.getPlaybackState();
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
} else {
Log.w(TAG, "Session isn't active", new IllegalStateException());
}
// TODO(jaewan): What to return for error case?
public PendingIntent getSessionActivity_impl() {
// TODO(jaewan): Implement
return null;
}
@Override
public void addPlaybackListener_impl(
MediaPlayerBase.PlaybackListener listener, Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener shouldn't be null");
}
if (handler == null) {
throw new IllegalArgumentException("handler shouldn't be null");
}
boolean registerCallback;
synchronized (mLock) {
if (PlaybackListenerHolder.contains(mPlaybackListeners, listener)) {
throw new IllegalArgumentException("listener is already added. Ignoring.");
}
registerCallback = mPlaybackListeners.isEmpty();
mPlaybackListeners.add(new PlaybackListenerHolder(listener, handler));
}
if (registerCallback) {
registerCallbackForPlaybackNotLocked();
}
public int getRatingType_impl() {
// TODO(jaewan): Implement
return 0;
}
@Override
public void removePlaybackListener_impl(MediaPlayerBase.PlaybackListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener shouldn't be null");
}
boolean unregisterCallback;
synchronized (mLock) {
int idx = PlaybackListenerHolder.indexOf(mPlaybackListeners, listener);
if (idx >= 0) {
mPlaybackListeners.get(idx).removeCallbacksAndMessages(null);
mPlaybackListeners.remove(idx);
}
unregisterCallback = mPlaybackListeners.isEmpty();
}
if (unregisterCallback) {
final IMediaSession2 binder = mSessionBinder;
if (binder != null) {
// Lazy unregister
try {
binder.unregisterCallback(mSessionCallbackStub, CALLBACK_FLAG_PLAYBACK);
} catch (RemoteException e) {
Log.e(TAG, "Cannot connect to the service or the session is gone", e);
}
}
}
public void setVolumeTo_impl(int value, int flags) {
// TODO(jaewan): Implement
}
@Override
public void adjustVolume_impl(int direction, int flags) {
// TODO(jaewan): Implement
}
@Override
public PlaybackInfo getPlaybackInfo_impl() {
// TODO(jaewan): Implement
return null;
}
@Override
public void prepareFromUri_impl(Uri uri, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void prepareFromSearch_impl(String query, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void prepareMediaId_impl(String mediaId, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void playFromSearch_impl(String query, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void playFromUri_impl(String uri, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void playFromMediaId_impl(String mediaId, Bundle extras) {
// TODO(jaewan): Implement
}
@Override
public void setRating_impl(Rating2 rating) {
// TODO(jaewan): Implement
}
@Override
public void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb) {
// TODO(jaewan): Implement
}
@Override
public List<MediaItem2> getPlaylist_impl() {
// TODO(jaewan): Implement
return null;
}
@Override
public void prepare_impl() {
// TODO(jaewan): Implement
}
@Override
public void fastForward_impl() {
// TODO(jaewan): Implement
}
@Override
public void rewind_impl() {
// TODO(jaewan): Implement
}
@Override
public void seekTo_impl(long pos) {
// TODO(jaewan): Implement
}
@Override
public void setCurrentPlaylistItem_impl(int index) {
// TODO(jaewan): Implement
}
@Override
public PlaybackState2 getPlaybackState_impl() {
// TODO(jaewan): Implement
return null;
}
@Override
public void removePlaylistItem_impl(MediaItem2 index) {
// TODO(jaewan): Implement
}
@Override
public void addPlaylistItem_impl(int index, MediaItem2 item) {
// TODO(jaewan): Implement
}
@Override
public PlaylistParam getPlaylistParam_impl() {
// TODO(jaewan): Implement
return null;
}
///////////////////////////////////////////////////

@ -16,12 +16,20 @@
package com.android.media;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.MediaLibraryService2;
import android.media.MediaLibraryService2.MediaLibrarySession;
import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
import android.media.MediaPlayerBase;
import android.media.MediaSession2;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.VolumeProvider;
import android.media.update.MediaLibraryService2Provider;
import android.os.Bundle;
public class MediaLibraryService2Impl extends MediaSessionService2Impl implements
MediaLibraryService2Provider {
@ -51,4 +59,31 @@ public class MediaLibraryService2Impl extends MediaSessionService2Impl implement
serviceIntent.setAction(MediaLibraryService2.SERVICE_INTERFACE);
return serviceIntent;
}
public static class MediaLibrarySessionImpl extends MediaSession2Impl
implements MediaLibrarySessionProvider {
private final MediaLibrarySession mInstance;
private final MediaLibrarySessionCallback mCallback;
public MediaLibrarySessionImpl(MediaLibrarySession instance, Context context,
MediaPlayerBase player, String id,
MediaLibrarySessionCallback callback, VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
super(instance, context, player, id, callback, volumeProvider, ratingType,
sessionActivity);
mInstance = instance;
mCallback = callback;
}
@Override
public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
Bundle options) {
// TODO(jaewan): Implements
}
@Override
public void notifyChildrenChanged_impl(String parentId, Bundle options) {
// TODO(jaewan): Implements
}
}
}

@ -17,25 +17,32 @@
package com.android.media;
import android.Manifest.permission;
import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.media.AudioAttributes;
import android.media.IMediaSession2Callback;
import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaPlayerBase;
import android.media.MediaSession2;
import android.media.MediaSession2.Builder;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.PlaylistParam;
import android.media.MediaSession2.SessionCallback;
import android.media.SessionToken;
import android.media.VolumeProvider;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.media.update.MediaSession2Provider;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@ -61,16 +68,21 @@ public class MediaSession2Impl implements MediaSession2Provider {
/**
* Can be only called by the {@link Builder#build()}.
*
*
* @param instance
* @param context
* @param player
* @param id
* @param callback
* @param volumeProvider
* @param ratingType
* @param sessionActivity
*/
public MediaSession2Impl(MediaSession2 instance, Context context, MediaPlayerBase player,
String id, SessionCallback callback) {
String id, SessionCallback callback, VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
mInstance = instance;
// TODO(jaewan): Keep other params.
// Argument checks are done by builder already.
// Initialize finals first.
@ -103,7 +115,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
// setPlayer(null). Token can be available when player is null, and
// controller can also attach to session.
@Override
public void setPlayer_impl(MediaPlayerBase player) throws IllegalArgumentException {
public void setPlayer_impl(MediaPlayerBase player, VolumeProvider volumeProvider) throws IllegalArgumentException {
ensureCallingThread();
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
@ -202,52 +214,74 @@ public class MediaSession2Impl implements MediaSession2Provider {
}
@Override
public PlaybackState getPlaybackState_impl() {
public void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout) {
ensureCallingThread();
ensurePlayer();
return mPlayer.getPlaybackState();
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
if (layout == null) {
throw new IllegalArgumentException("layout shouldn't be null");
}
mSessionStub.notifyCustomLayoutNotLocked(controller, layout);
}
//////////////////////////////////////////////////////////////////////////////////////
// TODO(jaewan): Implement follows
//////////////////////////////////////////////////////////////////////////////////////
@Override
public void addPlaybackListener_impl(
MediaPlayerBase.PlaybackListener listener, Handler handler) {
if (listener == null) {
throw new IllegalArgumentException("listener shouldn't be null");
}
if (handler == null) {
throw new IllegalArgumentException("handler shouldn't be null");
}
ensureCallingThread();
if (PlaybackListenerHolder.contains(mListeners, listener)) {
Log.w(TAG, "listener is already added. Ignoring.");
return;
}
mListeners.add(new PlaybackListenerHolder(listener, handler));
public void setPlayer_impl(MediaPlayerBase player) {
// TODO(jaewan): Implement
}
@Override
public void removePlaybackListener_impl(MediaPlayerBase.PlaybackListener listener) {
if (listener == null) {
throw new IllegalArgumentException("listener shouldn't be null");
}
ensureCallingThread();
int idx = PlaybackListenerHolder.indexOf(mListeners, listener);
if (idx >= 0) {
mListeners.get(idx).removeCallbacksAndMessages(null);
mListeners.remove(idx);
}
public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
// TODO(jaewan): Implement
}
@Override
public void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout) {
ensureCallingThread();
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
if (layout == null) {
throw new IllegalArgumentException("layout shouldn't be null");
}
mSessionStub.notifyCustomLayoutNotLocked(controller, layout);
public void notifyMetadataChanged_impl() {
// TODO(jaewan): Implement
}
@Override
public void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
ResultReceiver receiver) {
// TODO(jaewan): Implement
}
@Override
public void sendCustomCommand_impl(Command command, Bundle args) {
// TODO(jaewan): Implement
}
@Override
public void setPlaylist_impl(List<MediaItem2> playlist, PlaylistParam param) {
// TODO(jaewan): Implement
}
@Override
public void prepare_impl() {
// TODO(jaewan): Implement
}
@Override
public void fastForward_impl() {
// TODO(jaewan): Implement
}
@Override
public void rewind_impl() {
// TODO(jaewan): Implement
}
@Override
public void seekTo_impl(long pos) {
// TODO(jaewan): Implement
}
@Override
public void setCurrentPlaylistItem_impl(int index) {
// TODO(jaewan): Implement
}
///////////////////////////////////////////////////

@ -21,6 +21,7 @@ import static com.android.media.MediaController2Impl.CALLBACK_FLAG_PLAYBACK;
import android.content.Context;
import android.media.IMediaSession2;
import android.media.IMediaSession2Callback;
import android.media.MediaLibraryService2.BrowserRoot;
import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
import android.media.MediaSession2;
import android.media.MediaSession2.Command;
@ -36,7 +37,6 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.service.media.MediaBrowserService.BrowserRoot;
import android.support.annotation.GuardedBy;
import android.util.ArrayMap;
import android.util.Log;

@ -16,6 +16,7 @@
package com.android.media.update;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@ -23,6 +24,8 @@ import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
import android.media.MediaController2;
import android.media.MediaLibraryService2;
import android.media.MediaLibraryService2.MediaLibrarySession;
import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
import android.media.MediaPlayerBase;
import android.media.MediaSession2;
import android.media.MediaSession2.ControllerInfo;
@ -30,9 +33,11 @@ import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.IMediaSession2Callback;
import android.media.SessionToken;
import android.media.VolumeProvider;
import android.media.update.MediaBrowser2Provider;
import android.media.update.MediaControlView2Provider;
import android.media.update.MediaController2Provider;
import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSessionService2Provider;
import android.media.update.VideoView2Provider;
@ -46,6 +51,7 @@ import android.widget.VideoView2;
import com.android.media.MediaBrowser2Impl;
import com.android.media.MediaController2Impl;
import com.android.media.MediaLibraryService2Impl;
import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
import com.android.media.MediaSession2Impl;
import com.android.media.MediaSessionService2Impl;
import com.android.widget.MediaControlView2Impl;
@ -75,8 +81,11 @@ public class ApiFactory implements StaticProvider {
@Override
public MediaSession2Provider createMediaSession2(MediaSession2 instance, Context context,
MediaPlayerBase player, String id, SessionCallback callback) {
return new MediaSession2Impl(instance, context, player, id, callback);
MediaPlayerBase player, String id, SessionCallback callback,
VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
return new MediaSession2Impl(instance, context, player, id, callback,
volumeProvider, ratingType, sessionActivity);
}
@Override
@ -99,6 +108,15 @@ public class ApiFactory implements StaticProvider {
return new MediaLibraryService2Impl(instance);
}
@Override
public MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(
MediaLibrarySession instance, Context context, MediaPlayerBase player, String id,
MediaLibrarySessionCallback callback, VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
return new MediaLibrarySessionImpl(instance, context, player, id, callback, volumeProvider,
ratingType, sessionActivity);
}
@Override
public MediaControlView2Provider createMediaControlView2(
MediaControlView2 instance, ViewProvider superProvider) {

@ -144,6 +144,8 @@ public class MediaController2Test extends MediaSession2TestBase {
@Test
public void testGetPlaybackState() throws InterruptedException {
// TODO(jaewan): add equivalent test later
/*
final CountDownLatch latch = new CountDownLatch(1);
final MediaPlayerBase.PlaybackListener listener = (state) -> {
assertEquals(PlaybackState.STATE_BUFFERING, state.getState());
@ -155,8 +157,11 @@ public class MediaController2Test extends MediaSession2TestBase {
mPlayer.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_BUFFERING));
assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
assertEquals(PlaybackState.STATE_BUFFERING, mController.getPlaybackState().getState());
*/
}
// TODO(jaewan): add equivalent test later
/*
@Test
public void testAddPlaybackListener() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(2);
@ -192,6 +197,7 @@ public class MediaController2Test extends MediaSession2TestBase {
mPlayer.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PLAYING));
assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
*/
@Test
public void testControllerCallback_onConnected() throws InterruptedException {
@ -273,9 +279,6 @@ public class MediaController2Test extends MediaSession2TestBase {
});
final MediaController2 controller = createController(mSession.getToken());
testHandler.post(() -> {
controller.addPlaybackListener((state) -> {
// no-op. Just to set a binder call path from session to controller.
}, sessionHandler);
final PlaybackState state = createPlaybackState(PlaybackState.STATE_ERROR);
for (int i = 0; i < 100; i++) {
// triggers call from session to controller.
@ -360,6 +363,8 @@ public class MediaController2Test extends MediaSession2TestBase {
assertTrue(mPlayer.mPlayCalled);
// Test command from session service to controller
// TODO(jaewan): Add equivalent tests again
/*
final CountDownLatch latch = new CountDownLatch(1);
mController.addPlaybackListener((state) -> {
assertNotNull(state);
@ -369,6 +374,7 @@ public class MediaController2Test extends MediaSession2TestBase {
mPlayer.notifyPlaybackState(
TestUtils.createPlaybackState(PlaybackState.STATE_REWINDING));
assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
*/
}
@Test
@ -467,10 +473,13 @@ public class MediaController2Test extends MediaSession2TestBase {
fail("Controller shouldn't be notified about change in session after the close.");
latch.countDown();
};
// TODO(jaewan): Add equivalent tests again
/*
mController.addPlaybackListener(playbackListener, sHandler);
mPlayer.notifyPlaybackState(TestUtils.createPlaybackState(PlaybackState.STATE_BUFFERING));
assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
mController.removePlaybackListener(playbackListener);
*/
}
// TODO(jaewan): Add test for service connect rejection, when we differentiate session

@ -139,6 +139,8 @@ public class MediaSession2Test extends MediaSession2TestBase {
@Test
public void testPlaybackStateChangedListener() throws InterruptedException {
// TODO(jaewan): Add equivalent tests again
/*
final CountDownLatch latch = new CountDownLatch(2);
final MockPlayer player = new MockPlayer(0);
final PlaybackListener listener = (state) -> {
@ -164,10 +166,13 @@ public class MediaSession2Test extends MediaSession2TestBase {
});
player.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PAUSED));
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
*/
}
@Test
public void testBadPlayer() throws InterruptedException {
// TODO(jaewan): Add equivalent tests again
/*
final CountDownLatch latch = new CountDownLatch(3); // expected call + 1
final BadPlayer player = new BadPlayer(0);
sHandler.postAndSync(() -> {
@ -181,6 +186,7 @@ public class MediaSession2Test extends MediaSession2TestBase {
});
player.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PAUSED));
assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
*/
}
private static class BadPlayer extends MockPlayer {

@ -24,7 +24,6 @@ import android.media.MediaSession2.ControllerInfo;
import android.media.TestUtils.SyncHandler;
import android.os.Bundle;
import android.os.Process;
import android.service.media.MediaBrowserService.BrowserRoot;
import javax.annotation.concurrent.GuardedBy;

Loading…
Cancel
Save