MediaSession2: Last changes before API unhide

This CL includes
- Rename SessionToken to SessionToken2
- Add repeat/shuffle mode support in PlaylistParam
- Add Executor params in session builder
- Add more APIs for MediaPlayerBase

Test: Run all MediaComponents tests once
Change-Id: I7b74897c4bec377107eb040f950679d59e61f2bf
gugelfrei
Jaewan Kim 7 years ago
parent bbcbbe4fa3
commit 7027e8019a

@ -21,7 +21,7 @@ import android.media.IMediaSession2;
import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
import android.media.MediaSession2.CommandButton;
import android.media.SessionToken;
import android.media.SessionToken2;
import android.media.update.MediaBrowser2Provider;
import android.os.Bundle;
import android.os.RemoteException;
@ -37,7 +37,7 @@ public class MediaBrowser2Impl extends MediaController2Impl implements MediaBrow
private final MediaBrowser2 mInstance;
private final MediaBrowser2.BrowserCallback mCallback;
public MediaBrowser2Impl(MediaBrowser2 instance, Context context, SessionToken token,
public MediaBrowser2Impl(MediaBrowser2 instance, Context context, SessionToken2 token,
BrowserCallback callback, Executor executor) {
super(instance, context, token, callback, executor);
mInstance = instance;

@ -31,17 +31,15 @@ import android.media.MediaSession2.CommandButton;
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.SessionToken2;
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;
@ -70,7 +68,7 @@ public class MediaController2Impl implements MediaController2Provider {
private final Context mContext;
private final MediaSession2CallbackStub mSessionCallbackStub;
private final SessionToken mToken;
private final SessionToken2 mToken;
private final ControllerCallback mCallback;
private final Executor mCallbackExecutor;
private final IBinder.DeathRecipient mDeathRecipient;
@ -92,7 +90,7 @@ public class MediaController2Impl implements MediaController2Provider {
// TODO(jaewan): Require session activeness changed listener, because controller can be
// available when the session's player is null.
public MediaController2Impl(MediaController2 instance, Context context, SessionToken token,
public MediaController2Impl(MediaController2 instance, Context context, SessionToken2 token,
ControllerCallback callback, Executor executor) {
mInstance = instance;
@ -213,7 +211,7 @@ public class MediaController2Impl implements MediaController2Provider {
}
@Override
public SessionToken getSessionToken_impl() {
public SessionToken2 getSessionToken_impl() {
return mToken;
}
@ -405,7 +403,7 @@ public class MediaController2Impl implements MediaController2Provider {
}
}
private void pushPlaybackStateChanges(final PlaybackState state) {
private void pushPlaybackStateChanges(final PlaybackState2 state) {
synchronized (mLock) {
for (int i = 0; i < mPlaybackListeners.size(); i++) {
mPlaybackListeners.get(i).postPlaybackChange(state);
@ -500,9 +498,9 @@ public class MediaController2Impl implements MediaController2Provider {
}
@Override
public void onPlaybackStateChanged(PlaybackState state) throws RuntimeException {
public void onPlaybackStateChanged(Bundle state) throws RuntimeException {
final MediaController2Impl controller = getController();
controller.pushPlaybackStateChanges(state);
controller.pushPlaybackStateChanges(PlaybackState2.fromBundle(state));
}
@Override

@ -31,6 +31,8 @@ import android.media.VolumeProvider;
import android.media.update.MediaLibraryService2Provider;
import android.os.Bundle;
import java.util.concurrent.Executor;
public class MediaLibraryService2Impl extends MediaSessionService2Impl implements
MediaLibraryService2Provider {
private final MediaSessionService2 mInstance;
@ -66,11 +68,11 @@ public class MediaLibraryService2Impl extends MediaSessionService2Impl implement
private final MediaLibrarySessionCallback mCallback;
public MediaLibrarySessionImpl(MediaLibrarySession instance, Context context,
MediaPlayerBase player, String id,
MediaPlayerBase player, String id, Executor callbackExecutor,
MediaLibrarySessionCallback callback, VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
super(instance, context, player, id, callback, volumeProvider, ratingType,
sessionActivity);
super(instance, context, player, id, callbackExecutor, callback, volumeProvider,
ratingType, sessionActivity);
mInstance = instance;
mCallback = callback;
}

@ -33,7 +33,8 @@ 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.PlaybackState2;
import android.media.SessionToken2;
import android.media.VolumeProvider;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
@ -47,6 +48,7 @@ import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
public class MediaSession2Impl implements MediaSession2Provider {
private static final String TAG = "MediaSession2";
@ -57,8 +59,9 @@ public class MediaSession2Impl implements MediaSession2Provider {
private final Context mContext;
private final String mId;
private final Handler mHandler;
private final Executor mCallbackExecutor;
private final MediaSession2Stub mSessionStub;
private final SessionToken mSessionToken;
private final SessionToken2 mSessionToken;
private MediaPlayerBase mPlayer;
@ -79,8 +82,8 @@ public class MediaSession2Impl implements MediaSession2Provider {
* @param sessionActivity
*/
public MediaSession2Impl(MediaSession2 instance, Context context, MediaPlayerBase player,
String id, SessionCallback callback, VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
String id, Executor callbackExecutor, SessionCallback callback,
VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity) {
mInstance = instance;
// TODO(jaewan): Keep other params.
@ -89,6 +92,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
mContext = context;
mId = id;
mHandler = new Handler(Looper.myLooper());
mCallbackExecutor = callbackExecutor;
mSessionStub = new MediaSession2Stub(this, callback);
// Ask server to create session token for following reasons.
// 1. Make session ID unique per package.
@ -128,13 +132,14 @@ public class MediaSession2Impl implements MediaSession2Provider {
// Player didn't changed. No-op.
return;
}
mHandler.removeCallbacksAndMessages(null);
// TODO(jaewan): Find equivalent for the executor
//mHandler.removeCallbacksAndMessages(null);
if (mPlayer != null && mListener != null) {
// This might not work for a poorly implemented player.
mPlayer.removePlaybackListener(mListener);
}
mListener = new MyPlaybackListener(this, player);
player.addPlaybackListener(mListener, mHandler);
player.addPlaybackListener(mCallbackExecutor, mListener);
notifyPlaybackStateChanged(player.getPlaybackState());
mPlayer = player;
}
@ -159,7 +164,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
// TODO(jaewan): Change this to @NonNull
@Override
public SessionToken getToken_impl() {
public SessionToken2 getToken_impl() {
return mSessionToken;
}
@ -300,13 +305,15 @@ public class MediaSession2Impl implements MediaSession2Provider {
// 1. Allow calls from random threads for all methods.
// 2. Allow calls from random threads for all methods, except for the
// {@link #setPlayer()}.
// TODO(jaewan): Should we pend command instead of exception?
private void ensureCallingThread() {
// TODO(jaewan): Uncomment or remove
/*
if (mHandler.getLooper() != Looper.myLooper()) {
throw new IllegalStateException("Run this on the given thread");
}
}*/
}
private void ensurePlayer() {
// TODO(jaewan): Should we pend command instead? Follow the decision from MP2.
// Alternatively we can add a API like setAcceptsPendingCommands(boolean).
@ -319,7 +326,7 @@ public class MediaSession2Impl implements MediaSession2Provider {
return mHandler;
}
private void notifyPlaybackStateChanged(PlaybackState state) {
private void notifyPlaybackStateChanged(PlaybackState2 state) {
// Notify to listeners added directly to this session
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).postPlaybackChange(state);
@ -350,10 +357,9 @@ public class MediaSession2Impl implements MediaSession2Provider {
}
@Override
public void onPlaybackChanged(PlaybackState state) {
public void onPlaybackChanged(PlaybackState2 state) {
MediaSession2Impl session = mSession.get();
if (session == null || session.getHandler().getLooper() != Looper.myLooper()
|| mPlayer != session.mInstance.getPlayer()) {
if (mPlayer != session.mInstance.getPlayer()) {
Log.w(TAG, "Unexpected playback state change notifications. Ignoring.",
new IllegalStateException());
return;

@ -29,6 +29,7 @@ import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.SessionCallback;
import android.media.PlaybackState2;
import android.media.session.PlaybackState;
import android.os.Binder;
import android.os.Bundle;
@ -152,10 +153,10 @@ public class MediaSession2Stub extends IMediaSession2.Stub {
@Deprecated
@Override
public PlaybackState getPlaybackState() throws RemoteException {
public Bundle getPlaybackState() throws RemoteException {
MediaSession2Impl session = getSession();
// TODO(jaewan): Check if mPlayer.getPlaybackState() is safe here.
return session.getInstance().getPlayer().getPlaybackState();
return session.getInstance().getPlayer().getPlaybackState().toBundle();
}
@Deprecated
@ -216,13 +217,13 @@ public class MediaSession2Stub extends IMediaSession2.Stub {
}
// Should be used without a lock to prevent potential deadlock.
public void notifyPlaybackStateChangedNotLocked(PlaybackState state) {
public void notifyPlaybackStateChangedNotLocked(PlaybackState2 state) {
final List<ControllerInfo> list = getControllersWithFlag(CALLBACK_FLAG_PLAYBACK);
for (int i = 0; i < list.size(); i++) {
IMediaSession2Callback callbackBinder =
ControllerInfoImpl.from(list.get(i)).getControllerBinder();
try {
callbackBinder.onPlaybackStateChanged(state);
callbackBinder.onPlaybackStateChanged(state.toBundle());
} catch (RemoteException e) {
Log.w(TAG, "Controller is gone", e);
// TODO(jaewan): What to do when the controller is gone?

@ -26,6 +26,7 @@ import android.media.MediaPlayerBase.PlaybackListener;
import android.media.MediaSession2;
import android.media.MediaSessionService2;
import android.media.MediaSessionService2.MediaNotification;
import android.media.PlaybackState2;
import android.media.session.PlaybackState;
import android.media.update.MediaSessionService2Provider;
import android.os.IBinder;
@ -70,7 +71,7 @@ public class MediaSessionService2Impl implements MediaSessionService2Provider {
}
@Override
public MediaNotification onUpdateNotification_impl(PlaybackState state) {
public MediaNotification onUpdateNotification_impl(PlaybackState2 state) {
// Provide default notification UI later.
return null;
}
@ -118,7 +119,7 @@ public class MediaSessionService2Impl implements MediaSessionService2Provider {
return null;
}
private void updateNotification(PlaybackState state) {
private void updateNotification(PlaybackState2 state) {
MediaNotification mediaNotification = mInstance.onUpdateNotification(state);
if (mediaNotification == null) {
return;
@ -145,7 +146,7 @@ public class MediaSessionService2Impl implements MediaSessionService2Provider {
private class SessionServicePlaybackListener implements PlaybackListener {
@Override
public void onPlaybackChanged(PlaybackState state) {
public void onPlaybackChanged(PlaybackState2 state) {
if (state == null) {
Log.w(TAG, "Ignoring null playback state");
return;

@ -16,39 +16,30 @@
package com.android.media;
import android.media.MediaPlayerBase;
import android.media.MediaPlayerBase.PlaybackListener;
import android.media.PlaybackState2;
import android.media.session.PlaybackState;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Holds {@link android.media.MediaPlayerBase.PlaybackListener} with the {@link Handler}.
* Holds {@link PlaybackListener} with the {@link Handler}.
*/
public class PlaybackListenerHolder extends Handler {
private static final int ON_PLAYBACK_CHANGED = 1;
public final MediaPlayerBase.PlaybackListener listener;
public class PlaybackListenerHolder {
public final Executor executor;
public final PlaybackListener listener;
public PlaybackListenerHolder(
@NonNull MediaPlayerBase.PlaybackListener listener, @NonNull Handler handler) {
super(handler.getLooper());
public PlaybackListenerHolder(Executor executor, @NonNull PlaybackListener listener) {
this.executor = executor;
this.listener = listener;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ON_PLAYBACK_CHANGED:
listener.onPlaybackChanged((PlaybackState) msg.obj);
break;
}
}
public void postPlaybackChange(PlaybackState state) {
obtainMessage(ON_PLAYBACK_CHANGED, state).sendToTarget();
public void postPlaybackChange(final PlaybackState2 state) {
executor.execute(() -> listener.onPlaybackChanged(state));
}
/**

@ -32,7 +32,7 @@ import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.IMediaSession2Callback;
import android.media.SessionToken;
import android.media.SessionToken2;
import android.media.VolumeProvider;
import android.media.update.MediaBrowser2Provider;
import android.media.update.MediaControlView2Provider;
@ -68,23 +68,23 @@ public class ApiFactory implements StaticProvider {
@Override
public MediaController2Provider createMediaController2(
MediaController2 instance, Context context, SessionToken token,
MediaController2 instance, Context context, SessionToken2 token,
MediaController2.ControllerCallback callback, Executor executor) {
return new MediaController2Impl(instance, context, token, callback, executor);
}
@Override
public MediaBrowser2Provider createMediaBrowser2(MediaBrowser2 instance, Context context,
SessionToken token, BrowserCallback callback, Executor executor) {
SessionToken2 token, BrowserCallback callback, Executor executor) {
return new MediaBrowser2Impl(instance, context, token, callback, executor);
}
@Override
public MediaSession2Provider createMediaSession2(MediaSession2 instance, Context context,
MediaPlayerBase player, String id, SessionCallback callback,
MediaPlayerBase player, String id, Executor callbackExecutor, SessionCallback callback,
VolumeProvider volumeProvider, int ratingType,
PendingIntent sessionActivity) {
return new MediaSession2Impl(instance, context, player, id, callback,
return new MediaSession2Impl(instance, context, player, id, callbackExecutor, callback,
volumeProvider, ratingType, sessionActivity);
}
@ -111,10 +111,10 @@ public class ApiFactory implements StaticProvider {
@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);
Executor callbackExecutor, MediaLibrarySessionCallback callback,
VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity) {
return new MediaLibrarySessionImpl(instance, context, player, id, callbackExecutor,
callback, volumeProvider, ratingType, sessionActivity);
}
@Override

@ -48,7 +48,7 @@ public class MediaBrowser2Test extends MediaController2Test {
private static final String TAG = "MediaBrowser2Test";
@Override
TestControllerInterface onCreateController(@NonNull SessionToken token,
TestControllerInterface onCreateController(@NonNull SessionToken2 token,
@NonNull TestControllerCallbackInterface callback) {
return new TestMediaBrowser(mContext, token, new TestBrowserCallback(callback));
}
@ -69,7 +69,7 @@ public class MediaBrowser2Test extends MediaController2Test {
}
};
final SessionToken token = MockMediaLibraryService2.getToken(mContext);
final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
MediaBrowser2 browser =
(MediaBrowser2) createController(token,true, callback);
browser.getBrowserRoot(param);
@ -127,7 +127,7 @@ public class MediaBrowser2Test extends MediaController2Test {
public class TestMediaBrowser extends MediaBrowser2 implements TestControllerInterface {
private final BrowserCallback mCallback;
public TestMediaBrowser(@NonNull Context context, @NonNull SessionToken token,
public TestMediaBrowser(@NonNull Context context, @NonNull SessionToken2 token,
@NonNull ControllerCallback callback) {
super(context, token, (BrowserCallback) callback, sHandlerExecutor);
mCallback = (BrowserCallback) callback;

@ -218,7 +218,7 @@ public class MediaController2Test extends MediaSession2TestBase {
sHandler.postAndSync(() -> {
mSession.close();
mSession = new MediaSession2.Builder(mContext, mPlayer)
.setSessionCallback(sessionCallback).build();
.setSessionCallback(sHandlerExecutor, sessionCallback).build();
});
MediaController2 controller =
createController(mSession.getToken(), false, null);
@ -279,7 +279,7 @@ public class MediaController2Test extends MediaSession2TestBase {
});
final MediaController2 controller = createController(mSession.getToken());
testHandler.post(() -> {
final PlaybackState state = createPlaybackState(PlaybackState.STATE_ERROR);
final PlaybackState2 state = createPlaybackState(PlaybackState.STATE_ERROR);
for (int i = 0; i < 100; i++) {
// triggers call from session to controller.
player.notifyPlaybackState(state);
@ -320,15 +320,15 @@ public class MediaController2Test extends MediaSession2TestBase {
@Ignore
@Test
public void testGetServiceToken() {
SessionToken token = TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID);
SessionToken2 token = TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID);
assertNotNull(token);
assertEquals(mContext.getPackageName(), token.getPackageName());
assertEquals(MockMediaSessionService2.ID, token.getId());
assertNull(token.getSessionBinder());
assertEquals(SessionToken.TYPE_SESSION_SERVICE, token.getType());
assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
}
private void connectToService(SessionToken token) throws InterruptedException {
private void connectToService(SessionToken2 token) throws InterruptedException {
mController = createController(token);
mSession = TestServiceRegistry.getInstance().getServiceInstance().getSession();
mPlayer = (MockPlayer) mSession.getPlayer();

@ -208,7 +208,7 @@ public class MediaSession2Test extends MediaSession2TestBase {
mSession.close();
mPlayer = new MockPlayer(1);
mSession = new MediaSession2.Builder(mContext, mPlayer)
.setSessionCallback(callback).build();
.setSessionCallback(sHandlerExecutor, callback).build();
});
MediaController2 controller = createController(mSession.getToken());
controller.pause();
@ -232,7 +232,7 @@ public class MediaSession2Test extends MediaSession2TestBase {
sHandler.postAndSync(() -> {
mSession.close();
mSession = new MediaSession2.Builder(mContext, mPlayer)
.setSessionCallback(sessionCallback).build();
.setSessionCallback(sHandlerExecutor, sessionCallback).build();
});
MediaController2 controller =
createController(mSession.getToken(), false, null);

@ -101,11 +101,11 @@ abstract class MediaSession2TestBase {
}
}
final MediaController2 createController(SessionToken token) throws InterruptedException {
final MediaController2 createController(SessionToken2 token) throws InterruptedException {
return createController(token, true, null);
}
final MediaController2 createController(@NonNull SessionToken token,
final MediaController2 createController(@NonNull SessionToken2 token,
boolean waitForConnect, @Nullable TestControllerCallbackInterface callback)
throws InterruptedException {
TestControllerInterface instance = onCreateController(token, callback);
@ -145,7 +145,7 @@ abstract class MediaSession2TestBase {
getWaitForConnectionInterface(controller).waitForDisconnect(expected);
}
TestControllerInterface onCreateController(@NonNull SessionToken token,
TestControllerInterface onCreateController(@NonNull SessionToken2 token,
@NonNull TestControllerCallbackInterface callback) {
return new TestMediaController(mContext, token, new TestControllerCallback(callback));
}
@ -196,7 +196,7 @@ abstract class MediaSession2TestBase {
public class TestMediaController extends MediaController2 implements TestControllerInterface {
private final ControllerCallback mCallback;
public TestMediaController(@NonNull Context context, @NonNull SessionToken token,
public TestMediaController(@NonNull Context context, @NonNull SessionToken2 token,
@NonNull ControllerCallback callback) {
super(context, token, callback, sHandlerExecutor);
mCallback = callback;

@ -82,10 +82,10 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
player.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_STOPPED));
MediaController2 controller = null;
List<SessionToken> tokens = mManager.getActiveSessionTokens();
List<SessionToken2> tokens = mManager.getActiveSessionTokens();
assertNotNull(tokens);
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
if (mContext.getPackageName().equals(token.getPackageName())
&& TAG.equals(token.getId())) {
assertNotNull(token.getSessionBinder());
@ -113,7 +113,7 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
sHandler.postAndSync(() -> {
mSession.close();
mSession = new MediaSession2.Builder(mContext, new MockPlayer(0)).setId(TAG)
.setSessionCallback(new SessionCallback() {
.setSessionCallback(sHandlerExecutor, new SessionCallback() {
@Override
public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
// Reject all connection request.
@ -124,10 +124,10 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
ensureChangeInSession();
boolean foundSession = false;
List<SessionToken> tokens = mManager.getActiveSessionTokens();
List<SessionToken2> tokens = mManager.getActiveSessionTokens();
assertNotNull(tokens);
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
if (mContext.getPackageName().equals(token.getPackageName())
&& TAG.equals(token.getId())) {
assertFalse(foundSession);
@ -147,9 +147,9 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
// When the mSession's player becomes null, it should lose binder connection between server.
// So server will forget the session.
List<SessionToken> tokens = mManager.getActiveSessionTokens();
List<SessionToken2> tokens = mManager.getActiveSessionTokens();
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
assertFalse(mContext.getPackageName().equals(token.getPackageName())
&& TAG.equals(token.getId()));
}
@ -159,19 +159,19 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
public void testGetMediaSessionService2Token() throws InterruptedException {
boolean foundTestSessionService = false;
boolean foundTestLibraryService = false;
List<SessionToken> tokens = mManager.getSessionServiceTokens();
List<SessionToken2> tokens = mManager.getSessionServiceTokens();
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
if (mContext.getPackageName().equals(token.getPackageName())
&& MockMediaSessionService2.ID.equals(token.getId())) {
assertFalse(foundTestSessionService);
assertEquals(SessionToken.TYPE_SESSION_SERVICE, token.getType());
assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
assertNull(token.getSessionBinder());
foundTestSessionService = true;
} else if (mContext.getPackageName().equals(token.getPackageName())
&& MockMediaLibraryService2.ID.equals(token.getId())) {
assertFalse(foundTestLibraryService);
assertEquals(SessionToken.TYPE_LIBRARY_SERVICE, token.getType());
assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
assertNull(token.getSessionBinder());
foundTestLibraryService = true;
}
@ -185,9 +185,9 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
boolean foundTestSession = false;
boolean foundTestSessionService = false;
boolean foundTestLibraryService = false;
List<SessionToken> tokens = mManager.getAllSessionTokens();
List<SessionToken2> tokens = mManager.getAllSessionTokens();
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
if (!mContext.getPackageName().equals(token.getPackageName())) {
continue;
}
@ -199,11 +199,11 @@ public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
case MockMediaSessionService2.ID:
assertFalse(foundTestSessionService);
foundTestSessionService = true;
assertEquals(SessionToken.TYPE_SESSION_SERVICE, token.getType());
assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
break;
case MockMediaLibraryService2.ID:
assertFalse(foundTestLibraryService);
assertEquals(SessionToken.TYPE_LIBRARY_SERVICE, token.getType());
assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
foundTestLibraryService = true;
break;
default:

@ -40,19 +40,19 @@ public class MockMediaLibraryService2 extends MediaLibraryService2 {
EXTRA.putString(ROOT_ID, ROOT_ID);
}
@GuardedBy("MockMediaLibraryService2.class")
private static SessionToken sToken;
private static SessionToken2 sToken;
private MediaLibrarySession mSession;
@Override
public MediaLibrarySession onCreateSession(String sessionId) {
final MockPlayer player = new MockPlayer(1);
SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
try {
handler.postAndSync(() -> {
TestLibrarySessionCallback callback = new TestLibrarySessionCallback();
mSession = new MediaLibrarySessionBuilder(
MockMediaLibraryService2.this, player, callback)
mSession = new MediaLibrarySessionBuilder(MockMediaLibraryService2.this,
player, (runnable) -> handler.post(runnable), callback)
.setId(sessionId).build();
});
} catch (InterruptedException e) {
@ -67,10 +67,10 @@ public class MockMediaLibraryService2 extends MediaLibraryService2 {
super.onDestroy();
}
public static SessionToken getToken(Context context) {
public static SessionToken2 getToken(Context context) {
synchronized (MockMediaLibraryService2.class) {
if (sToken == null) {
sToken = new SessionToken(SessionToken.TYPE_LIBRARY_SERVICE,
sToken = new SessionToken2(SessionToken2.TYPE_LIBRARY_SERVICE,
context.getPackageName(), ID,
MockMediaLibraryService2.class.getName(), null);
}

@ -45,11 +45,12 @@ public class MockMediaSessionService2 extends MediaSessionService2 {
@Override
public MediaSession2 onCreateSession(String sessionId) {
final MockPlayer player = new MockPlayer(1);
SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
try {
handler.postAndSync(() -> {
mSession = new MediaSession2.Builder(MockMediaSessionService2.this, player)
.setId(sessionId).setSessionCallback(new MySessionCallback()).build();
.setId(sessionId).setSessionCallback((runnable)->handler.post(runnable),
new MySessionCallback()).build();
});
} catch (InterruptedException e) {
fail(e.toString());
@ -70,7 +71,7 @@ public class MockMediaSessionService2 extends MediaSessionService2 {
}
@Override
public MediaNotification onUpdateNotification(PlaybackState state) {
public MediaNotification onUpdateNotification(PlaybackState2 state) {
if (mDefaultNotificationChannel == null) {
mDefaultNotificationChannel = new NotificationChannel(
DEFAULT_MEDIA_NOTIFICATION_CHANNEL_ID,

@ -16,6 +16,7 @@
package android.media;
import android.media.MediaSession2.PlaylistParam;
import android.media.session.PlaybackState;
import android.os.Handler;
import android.support.annotation.NonNull;
@ -24,6 +25,7 @@ import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
/**
* A mock implementation of {@link MediaPlayerBase} for testing.
@ -37,7 +39,7 @@ public class MockPlayer extends MediaPlayerBase {
public boolean mSkipToPreviousCalled;
public boolean mSkipToNextCalled;
public List<PlaybackListenerHolder> mListeners = new ArrayList<>();
private PlaybackState mLastPlaybackState;
private PlaybackState2 mLastPlaybackState;
public MockPlayer(int count) {
mCountDownLatch = (count > 0) ? new CountDownLatch(count) : null;
@ -83,16 +85,18 @@ public class MockPlayer extends MediaPlayerBase {
}
}
@Nullable
@Override
public PlaybackState getPlaybackState() {
public PlaybackState2 getPlaybackState() {
return mLastPlaybackState;
}
@Override
public void addPlaybackListener(
@NonNull PlaybackListener listener, @NonNull Handler handler) {
mListeners.add(new PlaybackListenerHolder(listener, handler));
public void addPlaybackListener(@NonNull Executor executor,
@NonNull PlaybackListener listener) {
mListeners.add(new PlaybackListenerHolder(executor, listener));
}
@Override
@ -103,10 +107,40 @@ public class MockPlayer extends MediaPlayerBase {
}
}
public void notifyPlaybackState(final PlaybackState state) {
public void notifyPlaybackState(final PlaybackState2 state) {
mLastPlaybackState = state;
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).postPlaybackChange(state);
}
}
// No-op. Should be added for test later.
@Override
public void prepare() {
}
@Override
public void seekTo(long pos) {
}
@Override
public void fastFoward() {
}
@Override
public void rewind() {
}
@Override
public AudioAttributes getAudioAttributes() {
return null;
}
@Override
public void setPlaylist(List<MediaItem2> item, PlaylistParam param) {
}
@Override
public void setCurrentPlaylistItem(int index) {
}
}

@ -23,32 +23,22 @@ import android.os.Message;
import android.support.annotation.NonNull;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Holds {@link PlaybackListener} with the {@link Handler}.
*/
public class PlaybackListenerHolder extends Handler {
private static final int ON_PLAYBACK_CHANGED = 1;
public class PlaybackListenerHolder {
public final Executor executor;
public final PlaybackListener listener;
public PlaybackListenerHolder(
@NonNull PlaybackListener listener, @NonNull Handler handler) {
super(handler.getLooper());
public PlaybackListenerHolder(Executor executor, @NonNull PlaybackListener listener) {
this.executor = executor;
this.listener = listener;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ON_PLAYBACK_CHANGED:
listener.onPlaybackChanged((PlaybackState) msg.obj);
break;
}
}
public void postPlaybackChange(PlaybackState state) {
obtainMessage(ON_PLAYBACK_CHANGED, state).sendToTarget();
public void postPlaybackChange(final PlaybackState2 state) {
executor.execute(() -> listener.onPlaybackChanged(state));
}
/**

@ -45,8 +45,9 @@ public final class TestUtils {
* @param state one of the PlaybackState.STATE_xxx.
* @return a PlaybackState
*/
public static PlaybackState createPlaybackState(int state) {
return new PlaybackState.Builder().setState(state, 0, 1.0f).build();
public static PlaybackState2 createPlaybackState(int state) {
return new PlaybackState2(state, 0, 0, 1.0f,
0, 0, null);
}
/**
@ -57,12 +58,12 @@ public final class TestUtils {
* @return
*/
// TODO(jaewan): Currently not working.
public static SessionToken getServiceToken(Context context, String id) {
public static SessionToken2 getServiceToken(Context context, String id) {
MediaSessionManager manager =
(MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
List<SessionToken> tokens = manager.getSessionServiceTokens();
List<SessionToken2> tokens = manager.getSessionServiceTokens();
for (int i = 0; i < tokens.size(); i++) {
SessionToken token = tokens.get(i);
SessionToken2 token = tokens.get(i);
if (context.getPackageName().equals(token.getPackageName())
&& id.equals(token.getId())) {
return token;

Loading…
Cancel
Save