Loading packages/MediaComponents/src/com/android/media/IMediaSession2.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ interface IMediaSession2 { void connect(String callingPackage, IMediaSession2Callback callback); void release(IMediaSession2Callback caller); void setVolumeTo(IMediaSession2Callback caller, int value, int flags); void adjustVolume(IMediaSession2Callback caller, int direction, int flags); ////////////////////////////////////////////////////////////////////////////////////////////// // send command ////////////////////////////////////////////////////////////////////////////////////////////// Loading packages/MediaComponents/src/com/android/media/MediaController2Impl.java +22 −2 Original line number Diff line number Diff line Loading @@ -286,12 +286,32 @@ public class MediaController2Impl implements MediaController2Provider { @Override public void setVolumeTo_impl(int value, int flags) { // TODO(jaewan): Implement // TODO(hdmoon): sanity check final IMediaSession2 binder = mSessionBinder; if (binder != null) { try { binder.setVolumeTo(mSessionCallbackStub, value, flags); } 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()); } } @Override public void adjustVolume_impl(int direction, int flags) { // TODO(jaewan): Implement // TODO(hdmoon): sanity check final IMediaSession2 binder = mSessionBinder; if (binder != null) { try { binder.adjustVolume(mSessionCallbackStub, direction, flags); } 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()); } } @Override Loading packages/MediaComponents/src/com/android/media/MediaSession2Impl.java +4 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,10 @@ public class MediaSession2Impl implements MediaSession2Provider { return mCallback; } VolumeProvider2 getVolumeProvider() { return mVolumeProvider; } private static class MyPlaybackListener implements MediaPlayerInterface.PlaybackListener { private final WeakReference<MediaSession2Impl> mSession; private final MediaPlayerInterface mPlayer; Loading packages/MediaComponents/src/com/android/media/MediaSession2Stub.java +77 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.media.MediaSession2.CommandGroup; import android.media.MediaSession2.ControllerInfo; import android.media.MediaSession2.PlaylistParams; import android.media.PlaybackState2; import android.media.VolumeProvider2; import android.media.update.MediaSession2Provider.CommandButtonProvider; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -161,6 +162,82 @@ public class MediaSession2Stub extends IMediaSession2.Stub { } } @Override public void setVolumeTo(IMediaSession2Callback caller, int value, int flags) throws RuntimeException { final MediaSession2Impl sessionImpl = getSession(); final ControllerInfo controller = getController(caller); if (controller == null) { if (DEBUG) { Log.d(TAG, "Command from a controller that hasn't connected. Ignore"); } return; } sessionImpl.getCallbackExecutor().execute(() -> { final MediaSession2Impl session = mSession.get(); if (session == null) { return; } // TODO(jaewan): Sanity check. Command command = new Command( session.getContext(), MediaSession2.COMMAND_CODE_SET_VOLUME); boolean accepted = session.getCallback().onCommandRequest(controller, command); if (!accepted) { // Don't run rejected command. if (DEBUG) { Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_SET_VOLUME + " from " + controller + " was rejected by " + session); } return; } VolumeProvider2 volumeProvider = session.getVolumeProvider(); if (volumeProvider == null) { // TODO(jaewan): Set local stream volume } else { volumeProvider.onSetVolumeTo(value); } }); } @Override public void adjustVolume(IMediaSession2Callback caller, int direction, int flags) throws RuntimeException { final MediaSession2Impl sessionImpl = getSession(); final ControllerInfo controller = getController(caller); if (controller == null) { if (DEBUG) { Log.d(TAG, "Command from a controller that hasn't connected. Ignore"); } return; } sessionImpl.getCallbackExecutor().execute(() -> { final MediaSession2Impl session = mSession.get(); if (session == null) { return; } // TODO(jaewan): Sanity check. Command command = new Command( session.getContext(), MediaSession2.COMMAND_CODE_SET_VOLUME); boolean accepted = session.getCallback().onCommandRequest(controller, command); if (!accepted) { // Don't run rejected command. if (DEBUG) { Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_SET_VOLUME + " from " + controller + " was rejected by " + session); } return; } VolumeProvider2 volumeProvider = session.getVolumeProvider(); if (volumeProvider == null) { // TODO(jaewan): Adjust local stream volume } else { volumeProvider.onAdjustVolume(direction); } }); } @Override public void sendCommand(IMediaSession2Callback caller, Bundle command, Bundle args) throws RuntimeException { Loading packages/MediaComponents/test/src/android/media/MediaController2Test.java +64 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.media; import android.media.MediaController2.ControllerCallback; import android.content.Context; import android.media.MediaPlayerInterface.PlaybackListener; import android.media.MediaSession2.Command; import android.media.MediaSession2.ControllerInfo; Loading Loading @@ -223,6 +223,42 @@ public class MediaController2Test extends MediaSession2TestBase { ensurePlaylistParamsModeEquals(params, controller.getPlaylistParams()); } @Test public void testSetVolumeTo() throws Exception { final int maxVolume = 100; final int currentVolume = 23; final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE; TestVolumeProvider volumeProvider = new TestVolumeProvider(mContext, volumeControlType, maxVolume, currentVolume); mSession.setPlayer(new MockPlayer(0), volumeProvider); final MediaController2 controller = createController(mSession.getToken(), true, null); final int targetVolume = 50; controller.setVolumeTo(targetVolume, 0 /* flags */); assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); assertTrue(volumeProvider.mSetVolumeToCalled); assertEquals(targetVolume, volumeProvider.mVolume); } @Test public void testAdjustVolume() throws Exception { final int maxVolume = 100; final int currentVolume = 23; final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE; TestVolumeProvider volumeProvider = new TestVolumeProvider(mContext, volumeControlType, maxVolume, currentVolume); mSession.setPlayer(new MockPlayer(0), volumeProvider); final MediaController2 controller = createController(mSession.getToken(), true, null); final int direction = AudioManager.ADJUST_RAISE; controller.adjustVolume(direction, 0 /* flags */); assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); assertTrue(volumeProvider.mAdjustVolumeCalled); assertEquals(direction, volumeProvider.mDirection); } @Test public void testGetPackageName() { assertEquals(mContext.getPackageName(), mController.getSessionToken().getPackageName()); Loading Loading @@ -570,4 +606,31 @@ public class MediaController2Test extends MediaSession2TestBase { // TODO(jaewan): Add test for service connect rejection, when we differentiate session // active/inactive and connection accept/refuse class TestVolumeProvider extends VolumeProvider2 { final CountDownLatch mLatch = new CountDownLatch(1); boolean mSetVolumeToCalled; boolean mAdjustVolumeCalled; int mVolume; int mDirection; public TestVolumeProvider(Context context, int controlType, int maxVolume, int currentVolume) { super(context, controlType, maxVolume, currentVolume); } @Override public void onSetVolumeTo(int volume) { mSetVolumeToCalled = true; mVolume = volume; mLatch.countDown(); } @Override public void onAdjustVolume(int direction) { mAdjustVolumeCalled = true; mDirection = direction; mLatch.countDown(); } } } Loading
packages/MediaComponents/src/com/android/media/IMediaSession2.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ interface IMediaSession2 { void connect(String callingPackage, IMediaSession2Callback callback); void release(IMediaSession2Callback caller); void setVolumeTo(IMediaSession2Callback caller, int value, int flags); void adjustVolume(IMediaSession2Callback caller, int direction, int flags); ////////////////////////////////////////////////////////////////////////////////////////////// // send command ////////////////////////////////////////////////////////////////////////////////////////////// Loading
packages/MediaComponents/src/com/android/media/MediaController2Impl.java +22 −2 Original line number Diff line number Diff line Loading @@ -286,12 +286,32 @@ public class MediaController2Impl implements MediaController2Provider { @Override public void setVolumeTo_impl(int value, int flags) { // TODO(jaewan): Implement // TODO(hdmoon): sanity check final IMediaSession2 binder = mSessionBinder; if (binder != null) { try { binder.setVolumeTo(mSessionCallbackStub, value, flags); } 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()); } } @Override public void adjustVolume_impl(int direction, int flags) { // TODO(jaewan): Implement // TODO(hdmoon): sanity check final IMediaSession2 binder = mSessionBinder; if (binder != null) { try { binder.adjustVolume(mSessionCallbackStub, direction, flags); } 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()); } } @Override Loading
packages/MediaComponents/src/com/android/media/MediaSession2Impl.java +4 −0 Original line number Diff line number Diff line Loading @@ -559,6 +559,10 @@ public class MediaSession2Impl implements MediaSession2Provider { return mCallback; } VolumeProvider2 getVolumeProvider() { return mVolumeProvider; } private static class MyPlaybackListener implements MediaPlayerInterface.PlaybackListener { private final WeakReference<MediaSession2Impl> mSession; private final MediaPlayerInterface mPlayer; Loading
packages/MediaComponents/src/com/android/media/MediaSession2Stub.java +77 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.media.MediaSession2.CommandGroup; import android.media.MediaSession2.ControllerInfo; import android.media.MediaSession2.PlaylistParams; import android.media.PlaybackState2; import android.media.VolumeProvider2; import android.media.update.MediaSession2Provider.CommandButtonProvider; import android.os.Binder; import android.os.Bundle; Loading Loading @@ -161,6 +162,82 @@ public class MediaSession2Stub extends IMediaSession2.Stub { } } @Override public void setVolumeTo(IMediaSession2Callback caller, int value, int flags) throws RuntimeException { final MediaSession2Impl sessionImpl = getSession(); final ControllerInfo controller = getController(caller); if (controller == null) { if (DEBUG) { Log.d(TAG, "Command from a controller that hasn't connected. Ignore"); } return; } sessionImpl.getCallbackExecutor().execute(() -> { final MediaSession2Impl session = mSession.get(); if (session == null) { return; } // TODO(jaewan): Sanity check. Command command = new Command( session.getContext(), MediaSession2.COMMAND_CODE_SET_VOLUME); boolean accepted = session.getCallback().onCommandRequest(controller, command); if (!accepted) { // Don't run rejected command. if (DEBUG) { Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_SET_VOLUME + " from " + controller + " was rejected by " + session); } return; } VolumeProvider2 volumeProvider = session.getVolumeProvider(); if (volumeProvider == null) { // TODO(jaewan): Set local stream volume } else { volumeProvider.onSetVolumeTo(value); } }); } @Override public void adjustVolume(IMediaSession2Callback caller, int direction, int flags) throws RuntimeException { final MediaSession2Impl sessionImpl = getSession(); final ControllerInfo controller = getController(caller); if (controller == null) { if (DEBUG) { Log.d(TAG, "Command from a controller that hasn't connected. Ignore"); } return; } sessionImpl.getCallbackExecutor().execute(() -> { final MediaSession2Impl session = mSession.get(); if (session == null) { return; } // TODO(jaewan): Sanity check. Command command = new Command( session.getContext(), MediaSession2.COMMAND_CODE_SET_VOLUME); boolean accepted = session.getCallback().onCommandRequest(controller, command); if (!accepted) { // Don't run rejected command. if (DEBUG) { Log.d(TAG, "Command " + MediaSession2.COMMAND_CODE_SET_VOLUME + " from " + controller + " was rejected by " + session); } return; } VolumeProvider2 volumeProvider = session.getVolumeProvider(); if (volumeProvider == null) { // TODO(jaewan): Adjust local stream volume } else { volumeProvider.onAdjustVolume(direction); } }); } @Override public void sendCommand(IMediaSession2Callback caller, Bundle command, Bundle args) throws RuntimeException { Loading
packages/MediaComponents/test/src/android/media/MediaController2Test.java +64 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package android.media; import android.media.MediaController2.ControllerCallback; import android.content.Context; import android.media.MediaPlayerInterface.PlaybackListener; import android.media.MediaSession2.Command; import android.media.MediaSession2.ControllerInfo; Loading Loading @@ -223,6 +223,42 @@ public class MediaController2Test extends MediaSession2TestBase { ensurePlaylistParamsModeEquals(params, controller.getPlaylistParams()); } @Test public void testSetVolumeTo() throws Exception { final int maxVolume = 100; final int currentVolume = 23; final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE; TestVolumeProvider volumeProvider = new TestVolumeProvider(mContext, volumeControlType, maxVolume, currentVolume); mSession.setPlayer(new MockPlayer(0), volumeProvider); final MediaController2 controller = createController(mSession.getToken(), true, null); final int targetVolume = 50; controller.setVolumeTo(targetVolume, 0 /* flags */); assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); assertTrue(volumeProvider.mSetVolumeToCalled); assertEquals(targetVolume, volumeProvider.mVolume); } @Test public void testAdjustVolume() throws Exception { final int maxVolume = 100; final int currentVolume = 23; final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE; TestVolumeProvider volumeProvider = new TestVolumeProvider(mContext, volumeControlType, maxVolume, currentVolume); mSession.setPlayer(new MockPlayer(0), volumeProvider); final MediaController2 controller = createController(mSession.getToken(), true, null); final int direction = AudioManager.ADJUST_RAISE; controller.adjustVolume(direction, 0 /* flags */); assertTrue(volumeProvider.mLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)); assertTrue(volumeProvider.mAdjustVolumeCalled); assertEquals(direction, volumeProvider.mDirection); } @Test public void testGetPackageName() { assertEquals(mContext.getPackageName(), mController.getSessionToken().getPackageName()); Loading Loading @@ -570,4 +606,31 @@ public class MediaController2Test extends MediaSession2TestBase { // TODO(jaewan): Add test for service connect rejection, when we differentiate session // active/inactive and connection accept/refuse class TestVolumeProvider extends VolumeProvider2 { final CountDownLatch mLatch = new CountDownLatch(1); boolean mSetVolumeToCalled; boolean mAdjustVolumeCalled; int mVolume; int mDirection; public TestVolumeProvider(Context context, int controlType, int maxVolume, int currentVolume) { super(context, controlType, maxVolume, currentVolume); } @Override public void onSetVolumeTo(int volume) { mSetVolumeToCalled = true; mVolume = volume; mLatch.countDown(); } @Override public void onAdjustVolume(int direction) { mAdjustVolumeCalled = true; mDirection = direction; mLatch.countDown(); } } }