Merge "Remove MediaController2 usages in MediaSessionServiceImpl"
This commit is contained in:
committed by
Android (Google) Code Review
commit
471530dd56
@@ -25948,7 +25948,6 @@ package android.media {
|
||||
method @NonNull public abstract android.media.MediaSession2 onGetPrimarySession();
|
||||
method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2);
|
||||
method public final void removeSession(@NonNull android.media.MediaSession2);
|
||||
field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
|
||||
}
|
||||
|
||||
public static class MediaSession2Service.MediaNotification {
|
||||
@@ -27471,6 +27470,7 @@ package android.media.session {
|
||||
method @NonNull public java.util.List<android.media.Session2Token> getSession2Tokens();
|
||||
method public boolean isTrustedForMediaControl(@NonNull android.media.session.MediaSessionManager.RemoteUserInfo);
|
||||
method public void notifySession2Created(@NonNull android.media.Session2Token);
|
||||
method public void notifySession2Destroyed(@NonNull android.media.Session2Token);
|
||||
method public void removeOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
|
||||
method public void removeOnSession2TokensChangedListener(@NonNull android.media.session.MediaSessionManager.OnSession2TokensChangedListener);
|
||||
}
|
||||
|
||||
@@ -3414,6 +3414,15 @@ package android.media {
|
||||
method public void stop();
|
||||
}
|
||||
|
||||
public final class Session2Token implements android.os.Parcelable {
|
||||
ctor public Session2Token(@NonNull android.content.Context, @NonNull String, @Nullable android.os.Bundle);
|
||||
method public void destroy();
|
||||
method @NonNull public android.os.Bundle getExtras();
|
||||
method public int getPid();
|
||||
method public boolean isDestroyed();
|
||||
field public static final String SESSION_SERVICE_INTERFACE = "android.media.MediaSession2Service";
|
||||
}
|
||||
|
||||
public static class SubtitleData.Builder {
|
||||
ctor public SubtitleData.Builder();
|
||||
ctor public SubtitleData.Builder(@NonNull android.media.SubtitleData);
|
||||
|
||||
@@ -132,7 +132,6 @@ filegroup {
|
||||
"apex/java/android/media/Session2Command.java",
|
||||
"apex/java/android/media/Session2CommandGroup.java",
|
||||
"apex/java/android/media/Session2Link.java",
|
||||
"apex/java/android/media/Session2Token.java",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ class MediaConstants {
|
||||
static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
|
||||
|
||||
// Bundle key for Parcelable
|
||||
static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
|
||||
static final String KEY_SESSION2_TOKEN = "android.media.key.SESSION2_TOKEN";
|
||||
static final String KEY_SESSION2_LINK = "android.media.key.SESSION2_LINK";
|
||||
static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
|
||||
static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE";
|
||||
|
||||
|
||||
@@ -20,9 +20,11 @@ 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_PLAYBACK_ACTIVE;
|
||||
import static android.media.MediaConstants.KEY_SESSION2LINK;
|
||||
import static android.media.MediaConstants.KEY_SESSION2_LINK;
|
||||
import static android.media.MediaConstants.KEY_SESSION2_TOKEN;
|
||||
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
|
||||
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
|
||||
import static android.media.Session2Token.SESSION_SERVICE_INTERFACE;
|
||||
import static android.media.Session2Token.TYPE_SESSION;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -260,7 +262,8 @@ public class MediaController2 implements AutoCloseable {
|
||||
|
||||
// Called by Controller2Link.onConnected
|
||||
void onConnected(int seq, Bundle connectionResult) {
|
||||
Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK);
|
||||
Session2Token token = connectionResult.getParcelable(KEY_SESSION2_TOKEN);
|
||||
Session2Link sessionBinder = token.getExtras().getParcelable(KEY_SESSION2_LINK);
|
||||
Session2CommandGroup allowedCommands =
|
||||
connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
|
||||
boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
|
||||
@@ -281,8 +284,7 @@ public class MediaController2 implements AutoCloseable {
|
||||
// Implementation for the local binder is no-op,
|
||||
// so can be used without worrying about deadlock.
|
||||
sessionBinder.linkToDeath(mDeathRecipient, 0);
|
||||
mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
|
||||
mSessionToken.getPackageName(), sessionBinder);
|
||||
mConnectedToken = token;
|
||||
}
|
||||
mCallbackExecutor.execute(() -> {
|
||||
mCallback.onConnected(MediaController2.this, allowedCommands);
|
||||
@@ -353,7 +355,7 @@ public class MediaController2 implements AutoCloseable {
|
||||
}
|
||||
|
||||
private boolean requestConnectToSession() {
|
||||
Session2Link sessionBinder = mSessionToken.getSessionLink();
|
||||
Session2Link sessionBinder = mSessionToken.getExtras().getParcelable(KEY_SESSION2_LINK);
|
||||
Bundle connectionRequest = createConnectionRequest();
|
||||
try {
|
||||
sessionBinder.connect(mControllerStub, getNextSeqNumber(), connectionRequest);
|
||||
@@ -366,7 +368,7 @@ public class MediaController2 implements AutoCloseable {
|
||||
|
||||
private boolean requestConnectToService() {
|
||||
// Service. Needs to get fresh binder whenever connection is needed.
|
||||
final Intent intent = new Intent(MediaSession2Service.SERVICE_INTERFACE);
|
||||
final Intent intent = new Intent(SESSION_SERVICE_INTERFACE);
|
||||
intent.setClassName(mSessionToken.getPackageName(), mSessionToken.getServiceName());
|
||||
|
||||
// Use bindService() instead of startForegroundService() to start session service for three
|
||||
|
||||
@@ -20,10 +20,10 @@ 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_PLAYBACK_ACTIVE;
|
||||
import static android.media.MediaConstants.KEY_SESSION2LINK;
|
||||
import static android.media.MediaConstants.KEY_SESSION2_LINK;
|
||||
import static android.media.MediaConstants.KEY_SESSION2_TOKEN;
|
||||
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;
|
||||
import android.annotation.Nullable;
|
||||
@@ -34,7 +34,6 @@ import android.media.session.MediaSessionManager;
|
||||
import android.media.session.MediaSessionManager.RemoteUserInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -108,8 +107,10 @@ public class MediaSession2 implements AutoCloseable {
|
||||
mCallbackExecutor = callbackExecutor;
|
||||
mCallback = callback;
|
||||
mSessionStub = new Session2Link(this);
|
||||
mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
|
||||
mSessionStub);
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(KEY_SESSION2_LINK, mSessionStub);
|
||||
mSessionToken = new Session2Token(context, id, extras);
|
||||
mSessionManager = (MediaSessionManager) mContext.getSystemService(
|
||||
Context.MEDIA_SESSION_SERVICE);
|
||||
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
|
||||
@@ -141,6 +142,8 @@ public class MediaSession2 implements AutoCloseable {
|
||||
for (ControllerInfo info : controllerInfos) {
|
||||
info.notifyDisconnected();
|
||||
}
|
||||
mSessionToken.destroy();
|
||||
mSessionManager.notifySession2Destroyed(mSessionToken);
|
||||
} catch (Exception e) {
|
||||
// Should not be here.
|
||||
}
|
||||
@@ -328,7 +331,7 @@ public class MediaSession2 implements AutoCloseable {
|
||||
// It's needed because we cannot call synchronous calls between
|
||||
// session/controller.
|
||||
Bundle connectionResult = new Bundle();
|
||||
connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
|
||||
connectionResult.putParcelable(KEY_SESSION2_TOKEN, mSessionToken);
|
||||
connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
|
||||
controllerInfo.mAllowedCommands);
|
||||
connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive());
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.media;
|
||||
|
||||
import static android.media.Session2Token.SESSION_SERVICE_INTERFACE;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -45,10 +47,6 @@ import java.util.Map;
|
||||
* for consistent behavior across all devices.
|
||||
*/
|
||||
public abstract class MediaSession2Service extends Service {
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
|
||||
|
||||
private static final String TAG = "MediaSession2Service";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
@@ -100,7 +98,7 @@ public abstract class MediaSession2Service extends Service {
|
||||
@Override
|
||||
@Nullable
|
||||
public IBinder onBind(@NonNull Intent intent) {
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
if (SESSION_SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
synchronized (mLock) {
|
||||
return mStub;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,17 @@ package android.media;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.media.session.MediaSessionManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -35,7 +39,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
|
||||
* Represents an ongoing MediaSession2 or a MediaSession2Service.
|
||||
* If it's representing a session service, it may not be ongoing.
|
||||
* <p>
|
||||
* This API is not generally intended for third party application developers.
|
||||
@@ -44,7 +48,7 @@ import java.util.Objects;
|
||||
* for consistent behavior across all devices.
|
||||
* <p>
|
||||
* This may be passed to apps by the session owner to allow them to create a
|
||||
* {@link MediaController2} to communicate with the session.
|
||||
* MediaController2 to communicate with the session.
|
||||
* <p>
|
||||
* It can be also obtained by {@link android.media.session.MediaSessionManager}.
|
||||
*/
|
||||
@@ -63,6 +67,13 @@ public final class Session2Token implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared for the session service.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String SESSION_SERVICE_INTERFACE = "android.media.MediaSession2Service";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -72,22 +83,26 @@ public final class Session2Token implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Type for {@link MediaSession2}.
|
||||
* Type for MediaSession2.
|
||||
*/
|
||||
public static final int TYPE_SESSION = 0;
|
||||
|
||||
/**
|
||||
* Type for {@link MediaSession2Service}.
|
||||
* Type for MediaSession2Service.
|
||||
*/
|
||||
public static final int TYPE_SESSION_SERVICE = 1;
|
||||
|
||||
private final String mSessionId;
|
||||
private final int mPid;
|
||||
private final int mUid;
|
||||
@TokenType
|
||||
private final int mType;
|
||||
private final String mPackageName;
|
||||
private final String mServiceName;
|
||||
private final Session2Link mSessionLink;
|
||||
private final ComponentName mComponentName;
|
||||
private final Bundle mExtras;
|
||||
|
||||
private boolean mDestroyed = false;
|
||||
|
||||
/**
|
||||
* Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
|
||||
@@ -106,44 +121,67 @@ public final class Session2Token implements Parcelable {
|
||||
final PackageManager manager = context.getPackageManager();
|
||||
final int uid = getUid(manager, serviceComponent.getPackageName());
|
||||
|
||||
if (!isInterfaceDeclared(manager, MediaSession2Service.SERVICE_INTERFACE,
|
||||
serviceComponent)) {
|
||||
if (!isInterfaceDeclared(manager, SESSION_SERVICE_INTERFACE, serviceComponent)) {
|
||||
Log.w(TAG, serviceComponent + " doesn't implement MediaSession2Service.");
|
||||
}
|
||||
mSessionId = null;
|
||||
mComponentName = serviceComponent;
|
||||
mPackageName = serviceComponent.getPackageName();
|
||||
mServiceName = serviceComponent.getClassName();
|
||||
mPid = -1;
|
||||
mUid = uid;
|
||||
mType = TYPE_SESSION_SERVICE;
|
||||
mSessionLink = null;
|
||||
mExtras = null;
|
||||
}
|
||||
|
||||
Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
|
||||
mUid = uid;
|
||||
mType = type;
|
||||
mPackageName = packageName;
|
||||
/**
|
||||
* Constructor for the token with type {@link #TYPE_SESSION}.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param sessionId The ID of the session. Should be unique.
|
||||
* @param extras The extras.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Session2Token(@NonNull Context context, @NonNull String sessionId,
|
||||
@Nullable Bundle extras) {
|
||||
if (sessionId == null) {
|
||||
throw new IllegalArgumentException("sessionId shouldn't be null");
|
||||
}
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("context shouldn't be null");
|
||||
}
|
||||
mSessionId = sessionId;
|
||||
mPid = Process.myPid();
|
||||
mUid = Process.myUid();
|
||||
mType = TYPE_SESSION;
|
||||
mPackageName = context.getPackageName();
|
||||
mExtras = extras;
|
||||
mServiceName = null;
|
||||
mComponentName = null;
|
||||
mSessionLink = sessionLink;
|
||||
}
|
||||
|
||||
Session2Token(Parcel in) {
|
||||
mSessionId = in.readString();
|
||||
mPid = in.readInt();
|
||||
mUid = in.readInt();
|
||||
mType = in.readInt();
|
||||
mPackageName = in.readString();
|
||||
mServiceName = in.readString();
|
||||
mSessionLink = in.readParcelable(null);
|
||||
mComponentName = ComponentName.unflattenFromString(in.readString());
|
||||
mExtras = in.readParcelable(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mSessionId);
|
||||
dest.writeInt(mPid);
|
||||
dest.writeInt(mUid);
|
||||
dest.writeInt(mType);
|
||||
dest.writeString(mPackageName);
|
||||
dest.writeString(mServiceName);
|
||||
dest.writeParcelable(mSessionLink, flags);
|
||||
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
|
||||
dest.writeParcelable(mExtras, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -153,7 +191,7 @@ public final class Session2Token implements Parcelable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mType, mUid, mPackageName, mServiceName, mSessionLink);
|
||||
return Objects.hash(mSessionId, mPid, mUid, mType, mPackageName, mServiceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,17 +200,27 @@ public final class Session2Token implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
Session2Token other = (Session2Token) obj;
|
||||
return mUid == other.mUid
|
||||
&& TextUtils.equals(mPackageName, other.mPackageName)
|
||||
&& TextUtils.equals(mServiceName, other.mServiceName)
|
||||
return TextUtils.equals(mSessionId, other.mSessionId)
|
||||
&& mPid == other.mPid
|
||||
&& mUid == other.mUid
|
||||
&& mType == other.mType
|
||||
&& Objects.equals(mSessionLink, other.mSessionLink);
|
||||
&& TextUtils.equals(mPackageName, other.mPackageName)
|
||||
&& TextUtils.equals(mServiceName, other.mServiceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Session2Token {pkg=" + mPackageName + " type=" + mType
|
||||
+ " service=" + mServiceName + " Session2Link=" + mSessionLink + "}";
|
||||
+ " service=" + mServiceName + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return pid of the session
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public int getPid() {
|
||||
return mPid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,8 +255,36 @@ public final class Session2Token implements Parcelable {
|
||||
return mType;
|
||||
}
|
||||
|
||||
Session2Link getSessionLink() {
|
||||
return mSessionLink;
|
||||
/**
|
||||
* @return extras
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public Bundle getExtras() {
|
||||
return mExtras == null ? new Bundle() : new Bundle(mExtras);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this session token. After this method is called,
|
||||
* {@link MediaSessionManager#notifySession2Created(Session2Token)} should not be called
|
||||
* with this token.
|
||||
*
|
||||
* @see MediaSessionManager#notifySession2Created(Session2Token)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void destroy() {
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether this token is destroyed
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isDestroyed() {
|
||||
return mDestroyed;
|
||||
}
|
||||
|
||||
private static boolean isInterfaceDeclared(PackageManager manager, String serviceInterface,
|
||||
@@ -37,6 +37,7 @@ interface ISessionManager {
|
||||
SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
|
||||
int userId);
|
||||
void notifySession2Created(in Session2Token sessionToken);
|
||||
void notifySession2Destroyed(in Session2Token sessionToken);
|
||||
List<ControllerLink> getSessions(in ComponentName compName, int userId);
|
||||
List<Session2Token> getSession2Tokens(int userId);
|
||||
void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.IRemoteVolumeController;
|
||||
import android.media.MediaSession2;
|
||||
import android.media.Session2Token;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -115,11 +114,11 @@ public final class MediaSessionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
|
||||
* Notifies that a new MediaSession2 with type {@link Session2Token#TYPE_SESSION} is
|
||||
* created.
|
||||
* <p>
|
||||
* Do not use this API directly, but create a new instance through the
|
||||
* {@link MediaSession2.Builder} instead.
|
||||
* MediaSession2.Builder instead.
|
||||
*
|
||||
* @param token newly created session2 token
|
||||
*/
|
||||
@@ -130,6 +129,9 @@ public final class MediaSessionManager {
|
||||
if (token.getType() != Session2Token.TYPE_SESSION) {
|
||||
throw new IllegalArgumentException("token's type should be TYPE_SESSION");
|
||||
}
|
||||
if (token.isDestroyed()) {
|
||||
throw new IllegalArgumentException("token is already destroyed");
|
||||
}
|
||||
try {
|
||||
mService.notifySession2Created(token);
|
||||
} catch (RemoteException e) {
|
||||
@@ -137,6 +139,31 @@ public final class MediaSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that a new MediaSession2 with type {@link Session2Token#TYPE_SESSION} is
|
||||
* destroyed.
|
||||
* <p>
|
||||
* Do not use this API directly, but close a session with MediaSession2#close() instead.
|
||||
*
|
||||
* @param token destroyed session2 token
|
||||
*/
|
||||
public void notifySession2Destroyed(@NonNull Session2Token token) {
|
||||
if (token == null) {
|
||||
throw new IllegalArgumentException("token shouldn't be null");
|
||||
}
|
||||
if (token.getType() != Session2Token.TYPE_SESSION) {
|
||||
throw new IllegalArgumentException("token's type should be TYPE_SESSION");
|
||||
}
|
||||
if (!token.isDestroyed()) {
|
||||
throw new IllegalArgumentException("token should have been destroyed");
|
||||
}
|
||||
try {
|
||||
mService.notifySession2Destroyed(token);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of controllers for all ongoing sessions. The controllers will
|
||||
* be provided in priority order with the most important controller at index
|
||||
@@ -192,7 +219,7 @@ public final class MediaSessionManager {
|
||||
* current user.
|
||||
* <p>
|
||||
* Although this API can be used without any restriction, each session owners can accept or
|
||||
* reject your uses of {@link MediaSession2}.
|
||||
* reject your uses of MediaSession2.
|
||||
*
|
||||
* @return A list of {@link Session2Token}.
|
||||
*/
|
||||
|
||||
@@ -42,8 +42,6 @@ import android.media.AudioPlaybackConfiguration;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.IAudioService;
|
||||
import android.media.IRemoteVolumeController;
|
||||
import android.media.MediaController2;
|
||||
import android.media.Session2CommandGroup;
|
||||
import android.media.Session2Token;
|
||||
import android.media.session.ControllerLink;
|
||||
import android.media.session.IActiveSessionsListener;
|
||||
@@ -60,7 +58,6 @@ import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
@@ -1007,17 +1004,50 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Session2 is created " + sessionToken);
|
||||
}
|
||||
if (pid != sessionToken.getPid()) {
|
||||
throw new SecurityException("Unexpected Session2Token's PID, expected=" + pid
|
||||
+ " but actually=" + sessionToken.getPid());
|
||||
}
|
||||
if (uid != sessionToken.getUid()) {
|
||||
throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
|
||||
+ " but actually=" + sessionToken.getUid());
|
||||
}
|
||||
Controller2Callback callback = new Controller2Callback(sessionToken);
|
||||
// Note: It's safe not to keep controller here because it wouldn't be GC'ed until
|
||||
// it's closed.
|
||||
// TODO: Keep controller as well for better readability
|
||||
// because the GC behavior isn't straightforward.
|
||||
MediaController2 controller = new MediaController2(mContext, sessionToken,
|
||||
new HandlerExecutor(mHandler), callback);
|
||||
int userId = UserHandle.getUserId(uid);
|
||||
List<Session2Token> session2Tokens = mSession2TokensPerUser.get(userId);
|
||||
if (session2Tokens.contains(sessionToken)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "notifySession2Created(): Ignoring already existing token "
|
||||
+ sessionToken);
|
||||
}
|
||||
return;
|
||||
}
|
||||
session2Tokens.add(sessionToken);
|
||||
pushSession2TokensChangedLocked(userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySession2Destroyed(Session2Token sessionToken) throws RemoteException {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final int uid = Binder.getCallingUid();
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Session2 is destroyed " + sessionToken);
|
||||
}
|
||||
if (pid != sessionToken.getPid()) {
|
||||
throw new SecurityException("Unexpected Session2Token's PID, expected=" + pid
|
||||
+ " but actually=" + sessionToken.getPid());
|
||||
}
|
||||
if (uid != sessionToken.getUid()) {
|
||||
throw new SecurityException("Unexpected Session2Token's UID, expected=" + uid
|
||||
+ " but actually=" + sessionToken.getUid());
|
||||
}
|
||||
int userId = UserHandle.getUserId(uid);
|
||||
mSession2TokensPerUser.get(userId).remove(sessionToken);
|
||||
pushSession2TokensChangedLocked(userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -2114,30 +2144,4 @@ public class MediaSessionServiceImpl extends MediaSessionService.ServiceImpl {
|
||||
obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private class Controller2Callback extends MediaController2.ControllerCallback {
|
||||
private final Session2Token mToken;
|
||||
|
||||
Controller2Callback(Session2Token token) {
|
||||
mToken = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
|
||||
synchronized (mLock) {
|
||||
int userId = UserHandle.getUserId(mToken.getUid());
|
||||
mSession2TokensPerUser.get(userId).add(mToken);
|
||||
pushSession2TokensChangedLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(MediaController2 controller) {
|
||||
synchronized (mLock) {
|
||||
int userId = UserHandle.getUserId(mToken.getUid());
|
||||
mSession2TokensPerUser.get(userId).remove(mToken);
|
||||
pushSession2TokensChangedLocked(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user