diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java index d6a6e1442fa5f..77e96b95ac1a1 100644 --- a/media/java/android/media/Controller2Link.java +++ b/media/java/android/media/Controller2Link.java @@ -21,6 +21,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import java.util.Objects; + /** * Handles incoming commands from {@link MediaSession2} and {@link MediaLibrarySession} * to both {@link MediaController2} and {@link MediaBrowser2}. @@ -68,6 +70,20 @@ public final class Controller2Link implements Parcelable { dest.writeStrongBinder(mIController.asBinder()); } + @Override + public int hashCode() { + return mIController.asBinder().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Controller2Link)) { + return false; + } + Controller2Link other = (Controller2Link) obj; + return Objects.equals(mIController.asBinder(), other.mIController.asBinder()); + } + /** Interface method for IMediaController2.notifyConnected */ public void notifyConnected(int seq, Bundle connectionResult) { try { diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java index 6a089ecc59eab..3894e75630d0b 100644 --- a/media/java/android/media/MediaController2.java +++ b/media/java/android/media/MediaController2.java @@ -98,7 +98,6 @@ public class MediaController2 implements AutoCloseable { mNextSeqNumber = 0; - Session2Link sessionBinder = token.getSessionLink(); if (token.getType() == TYPE_SESSION) { connectToSession(); } else { @@ -120,9 +119,11 @@ public class MediaController2 implements AutoCloseable { mCallbackExecutor.execute(() -> { mCallback.onDisconnected(MediaController2.this); }); + mSessionBinder = null; } } + // Called by Controller2Link.onConnected void onConnected(int seq, Bundle connectionResult) { final long token = Binder.clearCallingIdentity(); try { @@ -155,10 +156,18 @@ public class MediaController2 implements AutoCloseable { } } + // Called by Controller2Link.onDisconnected void onDisconnected(int seq) { - // TODO: Implement this + final long token = Binder.clearCallingIdentity(); + try { + // close() will call mCallback.onDisconnected + close(); + } finally { + Binder.restoreCallingIdentity(token); + } } + // Called by Controller2Link.onSessionCommand void onSessionCommand(int seq, Session2Command command, Bundle args) { // TODO: Implement this } diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java index 4ef5810471ee5..52e607d07f85c 100644 --- a/media/java/android/media/MediaSession2.java +++ b/media/java/android/media/MediaSession2.java @@ -35,6 +35,7 @@ import android.os.Process; import android.util.Log; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -107,7 +108,13 @@ public class MediaSession2 implements AutoCloseable { synchronized (MediaSession2.class) { SESSION_ID_LIST.remove(mSessionId); } - // TODO: Implement this + Collection controllerInfos; + synchronized (mLock) { + controllerInfos = mConnectedControllers.values(); + } + for (ControllerInfo info : controllerInfos) { + info.notifyDisconnected(); + } } catch (Exception e) { // Should not be here. } @@ -118,6 +125,7 @@ public class MediaSession2 implements AutoCloseable { return true; } + // Called by Session2Link.onConnect void onConnect(final Controller2Link controller, int seq, Bundle connectionRequest) { if (controller == null || connectionRequest == null) { return; @@ -173,21 +181,12 @@ public class MediaSession2 implements AutoCloseable { if (isClosed()) { return; } - try { - controller.notifyConnected( - controllerInfo.mNextSeqNumber++, connectionResult); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } + controllerInfo.notifyConnected(connectionResult); } else { if (DEBUG) { Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo); } - try { - controller.notifyDisconnected(controllerInfo.mNextSeqNumber++); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } + controllerInfo.notifyDisconnected(); } }); } finally { @@ -195,20 +194,24 @@ public class MediaSession2 implements AutoCloseable { } } + // Called by Session2Link.onDisconnect void onDisconnect(final Controller2Link controller, int seq) { if (controller == null) { return; } + final ControllerInfo controllerInfo; + synchronized (mLock) { + controllerInfo = mConnectedControllers.get(controller); + } + if (controllerInfo == null) { + return; + } + final long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { - final ControllerInfo controllerInfo = mConnectedControllers.get(controller); mCallbackExecutor.execute(() -> { - try { - controller.notifyDisconnected(controllerInfo.mNextSeqNumber++); - } catch (RuntimeException e) { - // Controller may be died prematurely. - } + mCallback.onDisconnected(MediaSession2.this, controllerInfo); }); mConnectedControllers.remove(controller); } @@ -217,6 +220,7 @@ public class MediaSession2 implements AutoCloseable { } } + // Called by Session2Link.onSessionCommand void onSessionCommand(final Controller2Link controller, final int seq, final Session2Command command, final Bundle args) { // TODO: Implement this @@ -323,13 +327,12 @@ public class MediaSession2 implements AutoCloseable { *

* This API is not generally intended for third party application developers. */ - public static final class ControllerInfo { + static final class ControllerInfo { private final RemoteUserInfo mRemoteUserInfo; private final boolean mIsTrusted; private final Controller2Link mControllerBinder; + private int mNextSeqNumber; - @SuppressWarnings("WeakerAccess") /* synthetic access */ - int mNextSeqNumber; @SuppressWarnings("WeakerAccess") /* synthetic access */ Session2CommandGroup mAllowedCommands; @@ -348,7 +351,7 @@ public class MediaSession2 implements AutoCloseable { } /** - * @hide + * @return remote user info of the controller. */ @NonNull public RemoteUserInfo getRemoteUserInfo() { @@ -370,6 +373,36 @@ public class MediaSession2 implements AutoCloseable { return mRemoteUserInfo.getUid(); } + public void notifyConnected(Bundle connectionResult) { + if (mControllerBinder != null) { + try { + mControllerBinder.notifyConnected(getNextSeqNumber(), connectionResult); + } catch (RuntimeException e) { + // Controller may be died prematurely. + } + } + } + + public void notifyDisconnected() { + if (mControllerBinder != null) { + try { + mControllerBinder.notifyDisconnected(getNextSeqNumber()); + } catch (RuntimeException e) { + // Controller may be died prematurely. + } + } + } + + public void sendSessionCommand(Session2Command command, Bundle args) { + if (mControllerBinder != null) { + try { + mControllerBinder.sendSessionCommand(getNextSeqNumber(), command, args); + } catch (RuntimeException e) { + // Controller may be died prematurely. + } + } + } + /** * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or * has a enabled notification listener so can be trusted to accept connection and incoming @@ -407,6 +440,10 @@ public class MediaSession2 implements AutoCloseable { return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid=" + mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})"; } + + private synchronized int getNextSeqNumber() { + return mNextSeqNumber++; + } } /**