summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/Controller2Link.java28
-rw-r--r--media/java/android/media/IMediaController2.aidl2
-rw-r--r--media/java/android/media/IMediaSession2.aidl3
-rw-r--r--media/java/android/media/MediaConstants.java1
-rw-r--r--media/java/android/media/MediaController2.java117
-rw-r--r--media/java/android/media/MediaSession2.java141
-rw-r--r--media/java/android/media/Session2Command.java139
-rw-r--r--media/java/android/media/Session2Link.java28
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);
+ }
}
}