diff options
| -rw-r--r-- | media/java/android/media/Controller2Link.java | 28 | ||||
| -rw-r--r-- | media/java/android/media/IMediaController2.aidl | 2 | ||||
| -rw-r--r-- | media/java/android/media/IMediaSession2.aidl | 3 | ||||
| -rw-r--r-- | media/java/android/media/MediaConstants.java | 1 | ||||
| -rw-r--r-- | media/java/android/media/MediaController2.java | 117 | ||||
| -rw-r--r-- | media/java/android/media/MediaSession2.java | 141 | ||||
| -rw-r--r-- | media/java/android/media/Session2Command.java | 139 | ||||
| -rw-r--r-- | media/java/android/media/Session2Link.java | 28 |
8 files changed, 404 insertions, 55 deletions
diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java index 2601ff733546..a62db5f1fb20 100644 --- a/media/java/android/media/Controller2Link.java +++ b/media/java/android/media/Controller2Link.java @@ -25,8 +25,7 @@ import android.os.ResultReceiver; import java.util.Objects; /** - * Handles incoming commands from {@link MediaSession2} and {@link MediaLibrarySession} - * to both {@link MediaController2} and {@link MediaBrowser2}. + * Handles incoming commands from {@link MediaSession2} to both {@link MediaController2}. * @hide */ // @SystemApi @@ -90,7 +89,7 @@ public final class Controller2Link implements Parcelable { try { mIController.notifyConnected(seq, connectionResult); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); } } @@ -99,7 +98,7 @@ public final class Controller2Link implements Parcelable { try { mIController.notifyDisconnected(seq); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); } } @@ -109,7 +108,16 @@ public final class Controller2Link implements Parcelable { try { mIController.sendSessionCommand(seq, command, args, resultReceiver); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); + } + } + + /** Interface method for IMediaController2.cancelSessionCommand */ + public void cancelSessionCommand(int seq) { + try { + mIController.cancelSessionCommand(seq); + } catch (RemoteException e) { + throw new RuntimeException(e); } } @@ -133,6 +141,11 @@ public final class Controller2Link implements Parcelable { mController.onSessionCommand(seq, command, args, resultReceiver); } + /** Stub implementation for IMediaController2.cancelSessionCommand */ + public void onCancelCommand(int seq) { + mController.onCancelCommand(seq); + } + private class Controller2Stub extends IMediaController2.Stub { @Override public void notifyConnected(int seq, Bundle connectionResult) { @@ -149,5 +162,10 @@ public final class Controller2Link implements Parcelable { ResultReceiver resultReceiver) { Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver); } + + @Override + public void cancelSessionCommand(int seq) { + Controller2Link.this.onCancelCommand(seq); + } } } diff --git a/media/java/android/media/IMediaController2.aidl b/media/java/android/media/IMediaController2.aidl index df34a11a67e3..ca5394f504cb 100644 --- a/media/java/android/media/IMediaController2.aidl +++ b/media/java/android/media/IMediaController2.aidl @@ -33,4 +33,6 @@ oneway interface IMediaController2 { void notifyDisconnected(int seq) = 1; void sendSessionCommand(int seq, in Session2Command command, in Bundle args, in ResultReceiver resultReceiver) = 2; + void cancelSessionCommand(int seq) = 3; + // Next Id : 4 } diff --git a/media/java/android/media/IMediaSession2.aidl b/media/java/android/media/IMediaSession2.aidl index f6e74cfb242c..26e717b39afc 100644 --- a/media/java/android/media/IMediaSession2.aidl +++ b/media/java/android/media/IMediaSession2.aidl @@ -34,5 +34,6 @@ oneway interface IMediaSession2 { void disconnect(in Controller2Link caller, int seq) = 1; void sendSessionCommand(in Controller2Link caller, int seq, in Session2Command sessionCommand, in Bundle args, in ResultReceiver resultReceiver) = 2; - // Next Id : 3 + void cancelSessionCommand(in Controller2Link caller, int seq) = 3; + // Next Id : 4 } diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java index ffdca16d84e8..275b0acd8ad6 100644 --- a/media/java/android/media/MediaConstants.java +++ b/media/java/android/media/MediaConstants.java @@ -16,7 +16,6 @@ package android.media; -// Code for AML only class MediaConstants { // Bundle key for int static final String KEY_PID = "android.media.key.PID"; diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java index 4ef56c8d8caf..7665c92f9264 100644 --- a/media/java/android/media/MediaController2.java +++ b/media/java/android/media/MediaController2.java @@ -20,6 +20,8 @@ import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; import static android.media.MediaConstants.KEY_SESSION2_STUB; +import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR; +import static android.media.Session2Command.RESULT_INFO_SKIPPED; import static android.media.Session2Token.TYPE_SESSION; import android.annotation.NonNull; @@ -31,6 +33,8 @@ import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.ResultReceiver; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import java.util.concurrent.Executor; @@ -69,6 +73,21 @@ public class MediaController2 implements AutoCloseable { private Session2CommandGroup mAllowedCommands; //@GuardedBy("mLock") private Session2Token mConnectedToken; + //@GuardedBy("mLock") + private ArrayMap<ResultReceiver, Integer> mPendingCommands; + //@GuardedBy("mLock") + private ArraySet<Integer> mRequestedCommandSeqNumbers; + + /** + * Create a {@link MediaController2} from the {@link Session2Token}. + * This connects to the session and may wake up the service if it's not available. + * + * @param context Context + * @param token token to connect to + */ + public MediaController2(@NonNull Context context, @NonNull Session2Token token) { + this(context, token, context.getMainExecutor(), new ControllerCallback() {}); + } /** * Create a {@link MediaController2} from the {@link Session2Token}. @@ -77,31 +96,27 @@ public class MediaController2 implements AutoCloseable { * @param context Context * @param token token to connect to * @param executor executor to run callbacks on. - * @param callback controller callback to receive changes in + * @param callback controller callback to receive changes in. */ - public MediaController2(@NonNull final Context context, @NonNull final Session2Token token, - @NonNull final Executor executor, @NonNull final ControllerCallback callback) { + public MediaController2(@NonNull Context context, @NonNull Session2Token token, + @NonNull Executor executor, @NonNull ControllerCallback callback) { if (context == null) { throw new IllegalArgumentException("context shouldn't be null"); } if (token == null) { throw new IllegalArgumentException("token shouldn't be null"); } - if (callback == null) { - throw new IllegalArgumentException("callback shouldn't be null"); - } - if (executor == null) { - throw new IllegalArgumentException("executor shouldn't be null"); - } mContext = context; mSessionToken = token; - mCallbackExecutor = executor; - mCallback = callback; + mCallbackExecutor = (executor == null) ? context.getMainExecutor() : executor; + mCallback = (callback == null) ? new ControllerCallback() { } : callback; mControllerStub = new Controller2Link(this); // NOTE: mResultHandler uses main looper, so this MUST NOT be blocked. mResultHandler = new Handler(context.getMainLooper()); mNextSeqNumber = 0; + mPendingCommands = new ArrayMap<>(); + mRequestedCommandSeqNumbers = new ArraySet<>(); if (token.getType() == TYPE_SESSION) { connectToSession(); @@ -116,11 +131,13 @@ public class MediaController2 implements AutoCloseable { if (mSessionBinder != null) { try { mSessionBinder.unlinkToDeath(mDeathRecipient, 0); - mSessionBinder.disconnect(mControllerStub, mNextSeqNumber++); + mSessionBinder.disconnect(mControllerStub, getNextSeqNumber()); } catch (RuntimeException e) { // No-op } } + mPendingCommands.clear(); + mRequestedCommandSeqNumbers.clear(); mCallbackExecutor.execute(() -> { mCallback.onDisconnected(MediaController2.this); }); @@ -134,9 +151,8 @@ public class MediaController2 implements AutoCloseable { * @param command the session command * @param args optional arguments * @return a token which will be sent together in {@link ControllerCallback#onCommandResult} - * when its result is received. + * when its result is received. */ - // TODO: make cancelable. public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) { if (command == null) { throw new IllegalArgumentException("command shouldn't be null"); @@ -144,26 +160,50 @@ public class MediaController2 implements AutoCloseable { ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) { protected void onReceiveResult(int resultCode, Bundle resultData) { + synchronized (mLock) { + mPendingCommands.remove(this); + } mCallbackExecutor.execute(() -> { mCallback.onCommandResult(MediaController2.this, this, - command, resultData); + command, new Session2Command.Result(resultCode, resultData)); }); } }; synchronized (mLock) { if (mSessionBinder != null) { + int seq = getNextSeqNumber(); + mPendingCommands.put(resultReceiver, seq); try { - mSessionBinder.sendSessionCommand(mControllerStub, mNextSeqNumber++, - command, args, resultReceiver); + mSessionBinder.sendSessionCommand(mControllerStub, seq, command, args, + resultReceiver); } catch (RuntimeException e) { - // No-op + mPendingCommands.remove(resultReceiver); + resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null); } } } return resultReceiver; } + /** + * Cancels the session command previously sent. + * + * @param token the token which is returned from {@link #sendSessionCommand}. + */ + public void cancelSessionCommand(@NonNull Object token) { + if (token == null) { + throw new IllegalArgumentException("token shouldn't be null"); + } + synchronized (mLock) { + if (mSessionBinder == null) return; + Integer seq = mPendingCommands.remove(token); + if (seq != null) { + mSessionBinder.cancelSessionCommand(mControllerStub, seq); + } + } + } + // Called by Controller2Link.onConnected void onConnected(int seq, Bundle connectionResult) { final long token = Binder.clearCallingIdentity(); @@ -213,10 +253,26 @@ public class MediaController2 implements AutoCloseable { @Nullable ResultReceiver resultReceiver) { final long token = Binder.clearCallingIdentity(); try { + synchronized (mLock) { + mRequestedCommandSeqNumbers.add(seq); + } mCallbackExecutor.execute(() -> { - Bundle result = mCallback.onSessionCommand(MediaController2.this, command, args); + boolean isCanceled; + synchronized (mLock) { + isCanceled = !mRequestedCommandSeqNumbers.remove(seq); + } + if (isCanceled) { + resultReceiver.send(RESULT_INFO_SKIPPED, null); + return; + } + Session2Command.Result result = mCallback.onSessionCommand( + MediaController2.this, command, args); if (resultReceiver != null) { - resultReceiver.send(0, result); + if (result == null) { + throw new RuntimeException("onSessionCommand shouldn't return null"); + } else { + resultReceiver.send(result.getResultCode(), result.getResultData()); + } } }); } finally { @@ -224,6 +280,18 @@ public class MediaController2 implements AutoCloseable { } } + // Called by Controller2Link.onSessionCommand + void onCancelCommand(int seq) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + mRequestedCommandSeqNumbers.remove(seq); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + private int getNextSeqNumber() { synchronized (mLock) { return mNextSeqNumber++; @@ -278,9 +346,11 @@ public class MediaController2 implements AutoCloseable { * @param controller the controller for this event * @param command the session command * @param args optional arguments - * @return the result for the session command + * @return the result for the session command. A runtime exception will be thrown if null + * is returned. */ - public Bundle onSessionCommand(@NonNull MediaController2 controller, + @NonNull + public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller, @NonNull Session2Command command, @Nullable Bundle args) { return null; } @@ -294,7 +364,6 @@ public class MediaController2 implements AutoCloseable { * @param result the result of the session command */ public void onCommandResult(@NonNull MediaController2 controller, @NonNull Object token, - @NonNull Session2Command command, @Nullable Bundle result) { - } + @NonNull Session2Command command, @NonNull Session2Command.Result result) { } } } diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java index d67c66254b0c..b874ba461c2b 100644 --- a/media/java/android/media/MediaSession2.java +++ b/media/java/android/media/MediaSession2.java @@ -20,6 +20,8 @@ import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; import static android.media.MediaConstants.KEY_SESSION2_STUB; +import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR; +import static android.media.Session2Command.RESULT_INFO_SKIPPED; import static android.media.Session2Token.TYPE_SESSION; import android.annotation.NonNull; @@ -34,6 +36,8 @@ import android.os.Bundle; import android.os.Handler; import android.os.Process; import android.os.ResultReceiver; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import java.util.ArrayList; @@ -112,7 +116,7 @@ public class MediaSession2 implements AutoCloseable { } @Override - public void close() throws Exception { + public void close() { try { synchronized (MediaSession2.class) { SESSION_ID_LIST.remove(mSessionId); @@ -120,6 +124,7 @@ public class MediaSession2 implements AutoCloseable { Collection<ControllerInfo> controllerInfos; synchronized (mLock) { controllerInfos = mConnectedControllers.values(); + mConnectedControllers.clear(); mClosed = true; } for (ControllerInfo info : controllerInfos) { @@ -131,6 +136,22 @@ public class MediaSession2 implements AutoCloseable { } /** + * Returns the session ID + */ + @NonNull + public String getSessionId() { + return mSessionId; + } + + /** + * Returns the {@link Session2Token} for creating {@link MediaController2}. + */ + @NonNull + public Session2Token getSessionToken() { + return mSessionToken; + } + + /** * Broadcasts a session command to all the connected controllers * <p> * @param command the session command @@ -158,7 +179,6 @@ public class MediaSession2 implements AutoCloseable { * @return a token which will be sent together in {@link SessionCallback#onCommandResult} * when its result is received. */ - // TODO: make cancelable. public Object sendSessionCommand(@NonNull ControllerInfo controller, @NonNull Session2Command command, @Nullable Bundle args) { if (controller == null) { @@ -169,9 +189,10 @@ public class MediaSession2 implements AutoCloseable { } ResultReceiver resultReceiver = new ResultReceiver(mResultHandler) { protected void onReceiveResult(int resultCode, Bundle resultData) { + controller.receiveCommandResult(this); mCallbackExecutor.execute(() -> { mCallback.onCommandResult(MediaSession2.this, controller, this, - command, resultData); + command, new Session2Command.Result(resultCode, resultData)); }); } }; @@ -179,6 +200,19 @@ public class MediaSession2 implements AutoCloseable { return resultReceiver; } + /** + * Cancels the session command previously sent. + * + * @param controller the controller to get the session command + * @param token the token which is returned from {@link #sendSessionCommand}. + */ + public void cancelSessionCommand(ControllerInfo controller, Object token) { + if (token == null) { + throw new IllegalArgumentException("token shouldn't be null"); + } + controller.cancelSessionCommand(token); + } + boolean isClosed() { synchronized (mLock) { return mClosed; @@ -296,15 +330,23 @@ public class MediaSession2 implements AutoCloseable { // TODO: check allowed commands. final long token = Binder.clearCallingIdentity(); try { + synchronized (mLock) { + controllerInfo.addRequestedCommandSeqNumber(seq); + } + mCallbackExecutor.execute(() -> { - try { - Bundle result = mCallback.onSessionCommand( - MediaSession2.this, controllerInfo, command, args); - if (resultReceiver != null) { - resultReceiver.send(0, result); + if (!controllerInfo.removeRequestedCommandSeqNumber(seq)) { + resultReceiver.send(RESULT_INFO_SKIPPED, null); + return; + } + Session2Command.Result result = mCallback.onSessionCommand( + MediaSession2.this, controllerInfo, command, args); + if (resultReceiver != null) { + if (result == null) { + throw new RuntimeException("onSessionCommand shouldn't return null"); + } else { + resultReceiver.send(result.getResultCode(), result.getResultData()); } - } catch (RuntimeException e) { - // Controller may be died prematurely. } }); } finally { @@ -312,6 +354,24 @@ public class MediaSession2 implements AutoCloseable { } } + // Called by Session2Link.onCancelCommand + void onCancelCommand(final Controller2Link controller, final int seq) { + final ControllerInfo controllerInfo; + synchronized (mLock) { + controllerInfo = mConnectedControllers.get(controller); + } + if (controllerInfo == null) { + return; + } + + final long token = Binder.clearCallingIdentity(); + try { + controllerInfo.removeRequestedCommandSeqNumber(seq); + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * Builder for {@link MediaSession2}. * <p> @@ -417,7 +477,13 @@ public class MediaSession2 implements AutoCloseable { private final RemoteUserInfo mRemoteUserInfo; private final boolean mIsTrusted; private final Controller2Link mControllerBinder; + private final Object mLock = new Object(); + //@GuardedBy("mLock") private int mNextSeqNumber; + //@GuardedBy("mLock") + private ArrayMap<ResultReceiver, Integer> mPendingCommands; + //@GuardedBy("mLock") + private ArraySet<Integer> mRequestedCommandSeqNumbers; @SuppressWarnings("WeakerAccess") /* synthetic access */ Session2CommandGroup mAllowedCommands; @@ -425,15 +491,15 @@ public class MediaSession2 implements AutoCloseable { /** * @param remoteUserInfo remote user info * @param trusted {@code true} if trusted, {@code false} otherwise - * @param controllerBinder Controller2Link. Can be {@code null} only when a - * MediaBrowserCompat connects to MediaSessionService and ControllerInfo is - * needed for SessionCallback#onConnected(). + * @param controllerBinder Controller2Link for the connected controller. */ ControllerInfo(@NonNull RemoteUserInfo remoteUserInfo, boolean trusted, @Nullable Controller2Link controllerBinder) { mRemoteUserInfo = remoteUserInfo; mIsTrusted = trusted; mControllerBinder = controllerBinder; + mPendingCommands = new ArrayMap<>(); + mRequestedCommandSeqNumbers = new ArraySet<>(); } /** @@ -517,16 +583,53 @@ public class MediaSession2 implements AutoCloseable { void sendSessionCommand(Session2Command command, Bundle args, ResultReceiver resultReceiver) { if (mControllerBinder == null) return; + try { int seq = getNextSeqNumber(); + synchronized (mLock) { + mPendingCommands.put(resultReceiver, seq); + } mControllerBinder.sendSessionCommand(seq, command, args, resultReceiver); } catch (RuntimeException e) { // Controller may be died prematurely. + synchronized (mLock) { + mPendingCommands.remove(resultReceiver); + } + resultReceiver.send(RESULT_ERROR_UNKNOWN_ERROR, null); + } + } + + void cancelSessionCommand(@NonNull Object token) { + if (mControllerBinder == null) return; + Integer seq; + synchronized (mLock) { + seq = mPendingCommands.remove(token); + } + if (seq != null) { + mControllerBinder.cancelSessionCommand(seq); + } + } + + void receiveCommandResult(ResultReceiver resultReceiver) { + synchronized (mLock) { + mPendingCommands.remove(resultReceiver); + } + } + + void addRequestedCommandSeqNumber(int seq) { + synchronized (mLock) { + mRequestedCommandSeqNumbers.add(seq); + } + } + + boolean removeRequestedCommandSeqNumber(int seq) { + synchronized (mLock) { + return mRequestedCommandSeqNumbers.remove(seq); } } private int getNextSeqNumber() { - synchronized (this) { + synchronized (mLock) { return mNextSeqNumber++; } } @@ -575,9 +678,11 @@ public class MediaSession2 implements AutoCloseable { * @param controller controller information * @param command the session command * @param args optional arguments - * @return The result for the session command + * @return the result for the session command. A runtime exception will be thrown if null + * is returned. */ - public Bundle onSessionCommand(@NonNull MediaSession2 session, + @NonNull + public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull Session2Command command, @Nullable Bundle args) { return null; @@ -594,8 +699,6 @@ public class MediaSession2 implements AutoCloseable { */ public void onCommandResult(@NonNull MediaSession2 session, @NonNull ControllerInfo controller, @NonNull Object token, - @NonNull Session2Command command, @Nullable Bundle result) { - } + @NonNull Session2Command command, @NonNull Session2Command.Result result) { } } } - diff --git a/media/java/android/media/Session2Command.java b/media/java/android/media/Session2Command.java index a5e2ae4488a9..e46e64eb1a5c 100644 --- a/media/java/android/media/Session2Command.java +++ b/media/java/android/media/Session2Command.java @@ -409,6 +409,112 @@ public final class Session2Command implements Parcelable { */ public static final int COMMAND_CODE_SESSION_SET_RATING = 40010; + /** + * @hide + */ + @IntDef(flag = false, /*prefix = "RESULT_CODE",*/ value = { + RESULT_SUCCESS, + RESULT_ERROR_UNKNOWN_ERROR, + RESULT_ERROR_INVALID_STATE, + RESULT_ERROR_BAD_VALUE, + RESULT_ERROR_PERMISSION_DENIED, + RESULT_ERROR_IO_ERROR, + RESULT_INFO_SKIPPED, + RESULT_ERROR_SESSION_DISCONNECTED, + RESULT_ERROR_NOT_SUPPORTED, + RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED, + RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED, + RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT, + RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED, + RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION, + RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED, + RESULT_ERROR_SESSION_SETUP_REQUIRED}) + @Retention(RetentionPolicy.SOURCE) + public @interface ResultCode {} + + /** + * Result code representing that the command is skipped or canceled. For an example, a seek + * command can be skipped if it is followed by another seek command. + */ + public static final int RESULT_INFO_SKIPPED = 1; + + /** + * Result code representing that the command is successfully completed. + */ + public static final int RESULT_SUCCESS = 0; + + /** + * Result code represents that call is ended with an unknown error. + */ + public static final int RESULT_ERROR_UNKNOWN_ERROR = -1; + + /** + * Result code representing that the command cannot be completed because the current state is + * not valid for the command. + */ + public static final int RESULT_ERROR_INVALID_STATE = -2; + + /** + * Result code representing that an argument is illegal. + */ + public static final int RESULT_ERROR_BAD_VALUE = -3; + + /** + * Result code representing that the command is not allowed. + */ + public static final int RESULT_ERROR_PERMISSION_DENIED = -4; + + /** + * Result code representing a file or network related command error. + */ + public static final int RESULT_ERROR_IO_ERROR = -5; + + /** + * Result code representing that the command is not supported nor implemented. + */ + public static final int RESULT_ERROR_NOT_SUPPORTED = -6; + + /** + * Result code representing that the session and controller were disconnected. + */ + public static final int RESULT_ERROR_SESSION_DISCONNECTED = -100; + + /** + * Result code representing that the authentication has expired. + */ + public static final int RESULT_ERROR_SESSION_AUTHENTICATION_EXPIRED = -102; + + /** + * Result code representing that a premium account is required. + */ + public static final int RESULT_ERROR_SESSION_PREMIUM_ACCOUNT_REQUIRED = -103; + + /** + * Result code representing that too many concurrent streams are detected. + */ + public static final int RESULT_ERROR_SESSION_CONCURRENT_STREAM_LIMIT = -104; + + /** + * Result code representing that the content is blocked due to parental controls. + */ + public static final int RESULT_ERROR_SESSION_PARENTAL_CONTROL_RESTRICTED = -105; + + /** + * Result code representing that the content is blocked due to being regionally unavailable. + */ + public static final int RESULT_ERROR_SESSION_NOT_AVAILABLE_IN_REGION = -106; + + /** + * Result code representing that the application cannot skip any more because the skip limit is + * reached. + */ + public static final int RESULT_ERROR_SESSION_SKIP_LIMIT_REACHED = -107; + + /** + * Result code representing that the session needs user's manual intervention. + */ + public static final int RESULT_ERROR_SESSION_SETUP_REQUIRED = -108; + public static final Parcelable.Creator<Session2Command> CREATOR = new Parcelable.Creator<Session2Command>() { @Override @@ -582,6 +688,39 @@ public final class Session2Command implements Parcelable { return Objects.hash(mCustomCommand, mCommandCode); } + /** + * Contains the result of {@link Session2Command}. + */ + public static final class Result { + private final int mResultCode; + private final Bundle mResultData; + + /** + * Constructor of {@link Result}. + * + * @param resultCode result code + * @param resultData result data + */ + public Result(int resultCode, Bundle resultData) { + mResultCode = resultCode; + mResultData = resultData; + } + + /** + * Returns the result code. + */ + public int getResultCode() { + return mResultCode; + } + + /** + * Returns the result data. + */ + public Bundle getResultData() { + return mResultData; + } + } + @SuppressWarnings("WeakerAccess") /* synthetic access */ static final class Range { public final int lower; diff --git a/media/java/android/media/Session2Link.java b/media/java/android/media/Session2Link.java index 57c58dc3b2ed..5fe558da12f5 100644 --- a/media/java/android/media/Session2Link.java +++ b/media/java/android/media/Session2Link.java @@ -28,8 +28,7 @@ import android.util.Log; import java.util.Objects; /** - * Handles incoming commands from {@link MediaController2} and {@link MediaBrowser2} - * to both {@link MediaSession2} and {@link MediaLibrarySession}. + * Handles incoming commands from {@link MediaController2} to {@link MediaSession2}. * @hide */ // @SystemApi @@ -113,7 +112,7 @@ public final class Session2Link implements Parcelable { try { mISession.connect(caller, seq, connectionRequest); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); } } @@ -122,7 +121,7 @@ public final class Session2Link implements Parcelable { try { mISession.disconnect(caller, seq); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); } } @@ -132,7 +131,16 @@ public final class Session2Link implements Parcelable { try { mISession.sendSessionCommand(caller, seq, command, args, resultReceiver); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw new RuntimeException(e); + } + } + + /** Interface method for IMediaSession2.sendSessionCommand */ + public void cancelSessionCommand(final Controller2Link caller, final int seq) { + try { + mISession.cancelSessionCommand(caller, seq); + } catch (RemoteException e) { + throw new RuntimeException(e); } } @@ -152,6 +160,11 @@ public final class Session2Link implements Parcelable { mSession.onSessionCommand(caller, seq, command, args, resultReceiver); } + /** Stub implementation for IMediaSession2.cancelSessionCommand */ + public void onCancelCommand(final Controller2Link caller, final int seq) { + mSession.onCancelCommand(caller, seq); + } + private class Session2Stub extends IMediaSession2.Stub { @Override public void connect(final Controller2Link caller, int seq, Bundle connectionRequest) { @@ -168,5 +181,10 @@ public final class Session2Link implements Parcelable { final Session2Command command, final Bundle args, ResultReceiver resultReceiver) { Session2Link.this.onSessionCommand(caller, seq, command, args, resultReceiver); } + + @Override + public void cancelSessionCommand(final Controller2Link caller, final int seq) { + Session2Link.this.onCancelCommand(caller, seq); + } } } |