MediaSession2: Introduce MediaSession2.Command / CommandGroup
Test: Run all tests once
Change-Id: I67d2b09a68bc47a3c9b09be146e8fca6584e5755
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index d7364da..1a27056 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -22,6 +22,9 @@
import android.content.ServiceConnection;
import android.media.IMediaSession2;
import android.media.IMediaSession2Callback;
+import android.media.MediaSession2;
+import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaController2;
import android.media.MediaController2.ControllerCallback;
import android.media.MediaPlayerBase;
@@ -29,6 +32,7 @@
import android.media.SessionToken;
import android.media.session.PlaybackState;
import android.media.update.MediaController2Provider;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -197,66 +201,38 @@
@Override
public void play_impl() {
- final IMediaSession2 binder = mSessionBinder;
- if (binder != null) {
- try {
- binder.play(mSessionCallbackStub);
- } 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());
- }
+ sendCommand(MediaSession2.COMMAND_CODE_PLAYBACK_START);
}
@Override
public void pause_impl() {
- final IMediaSession2 binder = mSessionBinder;
- if (binder != null) {
- try {
- binder.pause(mSessionCallbackStub);
- } 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());
- }
+ sendCommand(MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE);
}
@Override
public void stop_impl() {
- final IMediaSession2 binder = mSessionBinder;
- if (binder != null) {
- try {
- binder.stop(mSessionCallbackStub);
- } 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());
- }
+ sendCommand(MediaSession2.COMMAND_CODE_PLAYBACK_STOP);
}
@Override
public void skipToPrevious_impl() {
- final IMediaSession2 binder = mSessionBinder;
- if (binder != null) {
- try {
- binder.skipToPrevious(mSessionCallbackStub);
- } 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());
- }
+ sendCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM);
}
@Override
public void skipToNext_impl() {
+ sendCommand(MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM);
+ }
+
+ private void sendCommand(int code) {
+ // TODO(jaewan): optimization) Cache Command objects?
+ Command command = new Command(code);
+ // TODO(jaewan): Check if the command is in the allowed group.
+
final IMediaSession2 binder = mSessionBinder;
if (binder != null) {
try {
- binder.skipToNext(mSessionCallbackStub);
+ binder.sendCommand(mSessionCallbackStub, command.toBundle(), null);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to the service or the session is gone", e);
}
@@ -356,13 +332,14 @@
// Called when the result for connecting to the session was delivered.
// Should be used without a lock to prevent potential deadlock.
- private void onConnectionChangedNotLocked(IMediaSession2 sessionBinder, long commands) {
+ private void onConnectionChangedNotLocked(IMediaSession2 sessionBinder,
+ CommandGroup commandGroup) {
if (DEBUG) {
Log.d(TAG, "onConnectionChangedNotLocked sessionBinder=" + sessionBinder);
}
boolean release = false;
try {
- if (sessionBinder == null) {
+ if (sessionBinder == null || commandGroup == null) {
// Connection rejected.
release = true;
return;
@@ -391,7 +368,7 @@
}
// TODO(jaewan): Keep commands to prevents illegal API calls.
mCallbackExecutor.execute(() -> {
- mCallback.onConnected(commands);
+ mCallback.onConnected(commandGroup);
});
if (registerCallbackForPlaybackNeeded) {
registerCallbackForPlaybackNotLocked();
@@ -431,7 +408,7 @@
}
@Override
- public void onConnectionChanged(IMediaSession2 sessionBinder, long commands)
+ public void onConnectionChanged(IMediaSession2 sessionBinder, Bundle commandGroup)
throws RuntimeException {
final MediaController2Impl controller;
try {
@@ -440,7 +417,8 @@
Log.w(TAG, "Don't fail silently here. Highly likely a bug");
return;
}
- controller.onConnectionChangedNotLocked(sessionBinder, commands);
+ controller.onConnectionChangedNotLocked(
+ sessionBinder, CommandGroup.fromBundle(commandGroup));
}
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 20e493e..bae02e5 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -22,10 +22,12 @@
import android.media.IMediaSession2;
import android.media.IMediaSession2Callback;
import android.media.MediaSession2;
-import android.media.MediaSession2.CommandFlags;
+import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
import android.media.session.PlaybackState;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -73,7 +75,7 @@
((ControllerInfoImpl) list.get(i).getProvider()).getControllerBinder();
try {
// Should be used without a lock hold to prevent potential deadlock.
- callbackBinder.onConnectionChanged(null, 0);
+ callbackBinder.onConnectionChanged(null, null);
} catch (RemoteException e) {
// Controller is gone. Should be fine because we're destroying.
}
@@ -110,32 +112,8 @@
}
@Override
- public void play(IMediaSession2Callback caller) throws RemoteException {
- onCommand(caller, MediaSession2.COMMAND_FLAG_PLAYBACK_START);
- }
-
- @Override
- public void pause(IMediaSession2Callback caller) throws RemoteException {
- onCommand(caller, MediaSession2.COMMAND_FLAG_PLAYBACK_PAUSE);
- }
-
- @Override
- public void stop(IMediaSession2Callback caller) throws RemoteException {
- onCommand(caller, MediaSession2.COMMAND_FLAG_PLAYBACK_STOP);
- }
-
- @Override
- public void skipToPrevious(IMediaSession2Callback caller) throws RemoteException {
- onCommand(caller, MediaSession2.COMMAND_FLAG_PLAYBACK_SKIP_PREV_ITEM);
- }
-
- @Override
- public void skipToNext(IMediaSession2Callback caller) throws RemoteException {
- onCommand(caller, MediaSession2.COMMAND_FLAG_PLAYBACK_SKIP_NEXT_ITEM);
- }
-
- private void onCommand(IMediaSession2Callback caller, @CommandFlags long command)
- throws IllegalArgumentException {
+ public void sendCommand(IMediaSession2Callback caller, Bundle command, Bundle args)
+ throws RuntimeException {
ControllerInfo controller = getController(caller);
if (controller == null) {
if (DEBUG) {
@@ -143,7 +121,7 @@
}
return;
}
- mCommandHandler.postCommand(controller, command);
+ mCommandHandler.postCommand(controller, Command.fromBundle(command), args);
}
@Deprecated
@@ -247,13 +225,12 @@
switch (msg.what) {
case MSG_CONNECT:
ControllerInfo request = (ControllerInfo) msg.obj;
- long allowedCommands = session.getCallback().onConnect(request);
+ CommandGroup allowedCommands = session.getCallback().onConnect(request);
// Don't reject connection for the request from trusted app.
// Otherwise server will fail to retrieve session's information to dispatch
// media keys to.
- boolean accept = (allowedCommands != 0) || request.isTrusted();
- ControllerInfoImpl impl =
- (ControllerInfoImpl) request.getProvider();
+ boolean accept = allowedCommands != null || request.isTrusted();
+ ControllerInfoImpl impl = (ControllerInfoImpl) request.getProvider();
if (accept) {
synchronized (mLock) {
mControllers.put(impl.getId(), request);
@@ -266,15 +243,16 @@
try {
impl.getControllerBinder().onConnectionChanged(
accept ? MediaSession2Stub.this : null,
- allowedCommands);
+ allowedCommands == null ? null : allowedCommands.toBundle());
} catch (RemoteException e) {
// Controller may be died prematurely.
}
break;
case MSG_COMMAND:
CommandParam param = (CommandParam) msg.obj;
- long command = param.command;
- boolean accepted = session.getCallback().onCommand(param.controller, command);
+ Command command = param.command;
+ boolean accepted = session.getCallback().onCommandRequest(
+ param.controller, command);
if (!accepted) {
// Don't run rejected command.
if (DEBUG) {
@@ -284,19 +262,24 @@
return;
}
- // Switch cannot be used because command is long, but switch only supports
- // int.
- // TODO(jaewan): Replace this with the switch
- if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_START) {
- session.getInstance().play();
- } else if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_PAUSE) {
- session.getInstance().pause();
- } else if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_STOP) {
- session.getInstance().stop();
- } else if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_SKIP_PREV_ITEM) {
- session.getInstance().skipToPrevious();
- } else if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_SKIP_NEXT_ITEM) {
- session.getInstance().skipToNext();
+ switch (param.command.getCommandCode()) {
+ case MediaSession2.COMMAND_CODE_PLAYBACK_START:
+ session.getInstance().play();
+ break;
+ case MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE:
+ session.getInstance().pause();
+ break;
+ case MediaSession2.COMMAND_CODE_PLAYBACK_STOP:
+ session.getInstance().stop();
+ break;
+ case MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM:
+ session.getInstance().skipToPrevious();
+ break;
+ case MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM:
+ session.getInstance().skipToNext();
+ break;
+ default:
+ // TODO(jaewan): Handle custom command.
}
break;
}
@@ -306,19 +289,21 @@
obtainMessage(MSG_CONNECT, request).sendToTarget();
}
- public void postCommand(ControllerInfo controller, @CommandFlags long command) {
- CommandParam param = new CommandParam(controller, command);
+ public void postCommand(ControllerInfo controller, Command command, Bundle args) {
+ CommandParam param = new CommandParam(controller, command, args);
obtainMessage(MSG_COMMAND, param).sendToTarget();
}
}
private static class CommandParam {
public final ControllerInfo controller;
- public final @CommandFlags long command;
+ public final Command command;
+ public final Bundle args;
- private CommandParam(ControllerInfo controller, long command) {
+ private CommandParam(ControllerInfo controller, Command command, Bundle args) {
this.controller = controller;
this.command = command;
+ this.args = args;
}
}
}
diff --git a/packages/MediaComponents/test/runtest.sh b/packages/MediaComponents/test/runtest.sh
index bda48b0..5c0ef51 100644
--- a/packages/MediaComponents/test/runtest.sh
+++ b/packages/MediaComponents/test/runtest.sh
@@ -124,7 +124,7 @@
if [[ "${OPTION_MIN}" != "true" ]]; then
build_targets="${build_targets} droid"
fi
- m ${build_targets} -j || (echo "Build failed. stop" ; break)
+ m ${build_targets} -j || break
${adb} root
${adb} remount
diff --git a/packages/MediaComponents/test/src/android/media/MediaController2Test.java b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
index 161a463..38d34cc 100644
--- a/packages/MediaComponents/test/src/android/media/MediaController2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
@@ -205,8 +205,8 @@
public void testControllerCallback_sessionRejects() throws InterruptedException {
final MediaSession2.SessionCallback sessionCallback = new SessionCallback() {
@Override
- public long onConnect(ControllerInfo controller) {
- return 0;
+ public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
+ return null;
}
};
sHandler.postAndSync(() -> {
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index a77fd63..f7224ea 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -209,15 +209,15 @@
assertFalse(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
assertFalse(mPlayer.mPauseCalled);
assertEquals(1, callback.commands.size());
- assertEquals(MediaSession2.COMMAND_FLAG_PLAYBACK_PAUSE,
- (long) callback.commands.get(0));
+ assertEquals(MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE,
+ (long) callback.commands.get(0).getCommandCode());
controller.skipToNext();
assertTrue(mPlayer.mCountDownLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
assertTrue(mPlayer.mSkipToNextCalled);
assertFalse(mPlayer.mPauseCalled);
assertEquals(2, callback.commands.size());
- assertEquals(MediaSession2.COMMAND_FLAG_PLAYBACK_SKIP_NEXT_ITEM,
- (long) callback.commands.get(1));
+ assertEquals(MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM,
+ (long) callback.commands.get(1).getCommandCode());
}
@Test
@@ -236,28 +236,28 @@
public class MockOnConnectCallback extends SessionCallback {
@Override
- public long onConnect(ControllerInfo controllerInfo) {
+ public MediaSession2.CommandGroup onConnect(ControllerInfo controllerInfo) {
if (Process.myUid() != controllerInfo.getUid()) {
- return 0;
+ return null;
}
assertEquals(mContext.getPackageName(), controllerInfo.getPackageName());
assertEquals(Process.myUid(), controllerInfo.getUid());
assertFalse(controllerInfo.isTrusted());
// Reject all
- return 0;
+ return null;
}
}
public class MockOnCommandCallback extends SessionCallback {
- public final ArrayList<Long> commands = new ArrayList<>();
+ public final ArrayList<MediaSession2.Command> commands = new ArrayList<>();
@Override
- public boolean onCommand(ControllerInfo controllerInfo, long command) {
+ public boolean onCommandRequest(ControllerInfo controllerInfo, MediaSession2.Command command) {
assertEquals(mContext.getPackageName(), controllerInfo.getPackageName());
assertEquals(Process.myUid(), controllerInfo.getUid());
assertFalse(controllerInfo.isTrusted());
commands.add(command);
- if (command == MediaSession2.COMMAND_FLAG_PLAYBACK_PAUSE) {
+ if (command.getCommandCode() == MediaSession2.COMMAND_CODE_PLAYBACK_PAUSE) {
return false;
}
return true;
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 80b8b79..ab842c4 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -20,6 +20,7 @@
import static junit.framework.Assert.assertTrue;
import android.content.Context;
+import android.media.MediaSession2.CommandGroup;
import android.os.HandlerThread;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
@@ -106,7 +107,7 @@
@CallSuper
@Override
- public void onConnected(long commands) {
+ public void onConnected(CommandGroup commands) {
super.onConnected(commands);
connectLatch.countDown();
}
diff --git a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
index 552f0a6..0ee37b1 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
@@ -115,9 +115,9 @@
mSession = new MediaSession2.Builder(mContext, new MockPlayer(0)).setId(TAG)
.setSessionCallback(new SessionCallback() {
@Override
- public long onConnect(ControllerInfo controller) {
+ public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
// Reject all connection request.
- return 0;
+ return null;
}
}).build();
});
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
index 0fa2f52..e4a7485 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
@@ -59,7 +59,7 @@
private class MySessionCallback extends SessionCallback {
@Override
- public long onConnect(ControllerInfo controller) {
+ public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
if (Process.myUid() != controller.getUid()) {
// It's system app wants to listen changes. Ignore.
return super.onConnect(controller);