Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eae45a74 authored by Kyunglyul Hyun's avatar Kyunglyul Hyun Committed by Android (Google) Code Review
Browse files

Merge "Add MCM#dispatchMediaKeyEvent"

parents 81d4066f 4e05164e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.media;
import android.media.Session2Token;
import android.media.IMediaCommunicationServiceCallback;
import android.media.MediaParceledListSlice;
import android.view.KeyEvent;

/** {@hide} */
interface IMediaCommunicationService {
@@ -25,6 +26,8 @@ interface IMediaCommunicationService {
    boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
    MediaParceledListSlice getSession2Tokens(int userId);

   void dispatchMediaKeyEvent(String packageName, in KeyEvent keyEvent, boolean asSystemService);

    void registerCallback(IMediaCommunicationServiceCallback callback, String packageName);
    void unregisterCallback(IMediaCommunicationServiceCallback callback);
}
+1 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
package android.media {

  public class MediaCommunicationManager {
    method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
    method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaCommunicationManager.SessionCallback);
    method public void unregisterSessionCallback(@NonNull android.media.MediaCommunicationManager.SessionCallback);
  }
+37 −10
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.service.media.MediaBrowserService;
import android.util.Log;
import android.view.KeyEvent;

import com.android.internal.annotations.GuardedBy;
import com.android.modules.annotation.MinSdk;
@@ -63,7 +64,8 @@ public class MediaCommunicationManager {
    private static final int CURRENT_VERSION = VERSION_1;

    private final Context mContext;
    private final IMediaCommunicationService mService;
    // Do not access directly use getService().
    private IMediaCommunicationService mService;

    private final Object mLock = new Object();
    private final CopyOnWriteArrayList<SessionCallbackRecord> mTokenCallbackRecords =
@@ -80,10 +82,6 @@ public class MediaCommunicationManager {
            throw new UnsupportedOperationException("Android version must be S or greater.");
        }
        mContext = context;
        mService = IMediaCommunicationService.Stub.asInterface(
                MediaFrameworkInitializer.getMediaServiceManager()
                        .getMediaCommunicationServiceRegisterer()
                        .get());
    }

    /**
@@ -105,7 +103,7 @@ public class MediaCommunicationManager {
            throw new IllegalArgumentException("token's type should be TYPE_SESSION");
        }
        try {
            mService.notifySession2Created(token);
            getService().notifySession2Created(token);
        } catch (RemoteException e) {
            e.rethrowFromSystemServer();
        }
@@ -130,7 +128,7 @@ public class MediaCommunicationManager {
            return false;
        }
        try {
            return mService.isTrusted(
            return getService().isTrusted(
                    userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot communicate with the service.", e);
@@ -182,7 +180,7 @@ public class MediaCommunicationManager {
                MediaCommunicationServiceCallbackStub callbackStub =
                        new MediaCommunicationServiceCallbackStub();
                try {
                    mService.registerCallback(callbackStub, mContext.getPackageName());
                    getService().registerCallback(callbackStub, mContext.getPackageName());
                    mCallbackStub = callbackStub;
                } catch (RemoteException ex) {
                    Log.e(TAG, "Failed to register callback.", ex);
@@ -205,7 +203,7 @@ public class MediaCommunicationManager {
        synchronized (mLock) {
            if (mCallbackStub != null && mTokenCallbackRecords.isEmpty()) {
                try {
                    mService.unregisterCallback(mCallbackStub);
                    getService().unregisterCallback(mCallbackStub);
                } catch (RemoteException ex) {
                    Log.e(TAG, "Failed to unregister callback.", ex);
                }
@@ -214,9 +212,19 @@ public class MediaCommunicationManager {
        }
    }

    private IMediaCommunicationService getService() {
        if (mService == null) {
            mService = IMediaCommunicationService.Stub.asInterface(
                    MediaFrameworkInitializer.getMediaServiceManager()
                            .getMediaCommunicationServiceRegisterer()
                            .get());
        }
        return mService;
    }

    private List<Session2Token> getSession2Tokens(int userId) {
        try {
            MediaParceledListSlice slice = mService.getSession2Tokens(userId);
            MediaParceledListSlice slice = getService().getSession2Tokens(userId);
            return slice == null ? Collections.emptyList() : slice.getList();
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to get session tokens", e);
@@ -224,6 +232,25 @@ public class MediaCommunicationManager {
        return Collections.emptyList();
    }

    /**
     * Sends a media key event. The receiver will be selected automatically.
     *
     * @param keyEvent the key event to send
     * @param asSystemService if {@code true}, the event sent to the session as if it was come from
     *                        the system service instead of the app process.
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean asSystemService) {
        Objects.requireNonNull(keyEvent, "keyEvent shouldn't be null");
        try {
            getService().dispatchMediaKeyEvent(mContext.getPackageName(),
                    keyEvent, asSystemService);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to send key event.", e);
        }
    }

    /**
     * Callback for listening to changes to the sessions.
     * @see #registerSessionCallback(Executor, SessionCallback)
+56 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.media.MediaController2;
import android.media.MediaParceledListSlice;
import android.media.Session2CommandGroup;
import android.media.Session2Token;
import android.media.session.MediaSessionManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -42,6 +43,7 @@ import android.os.UserManager;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.KeyEvent;

import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
@@ -60,7 +62,7 @@ import java.util.stream.Collectors;
 * @hide
 */
public class MediaCommunicationService extends SystemService {
    private static final String TAG = "MediaCommunicationService";
    private static final String TAG = "MediaCommunicationSrv";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    final Context mContext;
@@ -77,6 +79,7 @@ public class MediaCommunicationService extends SystemService {
    @GuardedBy("mLock")
    final List<CallbackRecord> mCallbackRecords = new ArrayList<>();
    final NotificationManager mNotificationManager;
    MediaSessionManager mSessionManager;

    public MediaCommunicationService(Context context) {
        super(context);
@@ -90,6 +93,17 @@ public class MediaCommunicationService extends SystemService {
        updateUser();
    }

    @Override
    public void onBootPhase(int phase) {
        super.onBootPhase(phase);
        switch (phase) {
            // This ensures MediaSessionService is started
            case PHASE_BOOT_COMPLETED:
                mSessionManager = mContext.getSystemService(MediaSessionManager.class);
                break;
        }
    }

    @Override
    public void onUserStarting(@NonNull TargetUser user) {
        if (DEBUG) Log.d(TAG, "onUserStarting: " + user);
@@ -267,6 +281,24 @@ public class MediaCommunicationService extends SystemService {
        session.close();
    }

    static boolean isMediaSessionKey(int keyCode) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_MEDIA_PLAY:
            case KeyEvent.KEYCODE_MEDIA_PAUSE:
            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
            case KeyEvent.KEYCODE_MUTE:
            case KeyEvent.KEYCODE_HEADSETHOOK:
            case KeyEvent.KEYCODE_MEDIA_STOP:
            case KeyEvent.KEYCODE_MEDIA_NEXT:
            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
            case KeyEvent.KEYCODE_MEDIA_REWIND:
            case KeyEvent.KEYCODE_MEDIA_RECORD:
            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
                return true;
        }
        return false;
    }

    private class Stub extends IMediaCommunicationService.Stub {
        @Override
        public void notifySession2Created(Session2Token sessionToken) {
@@ -350,6 +382,29 @@ public class MediaCommunicationService extends SystemService {
            }
        }

        @Override
        public void dispatchMediaKeyEvent(String packageName, KeyEvent keyEvent,
                boolean asSystemService) {
            if (keyEvent == null || !isMediaSessionKey(keyEvent.getKeyCode())) {
                Log.w(TAG, "Attempted to dispatch null or non-media key event.");
                return;
            }

            final int pid = Binder.getCallingPid();
            final int uid = Binder.getCallingUid();
            final long token = Binder.clearCallingIdentity();
            try {
                //TODO: Dispatch key event to media session 2 if required
                if (asSystemService) {
                    mSessionManager.dispatchMediaKeyEventAsSystemService(keyEvent);
                } else {
                    mSessionManager.dispatchMediaKeyEvent(keyEvent, false);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
        public void registerCallback(IMediaCommunicationServiceCallback callback,
                String packageName) throws RemoteException {
+4 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.media.MediaCommunicationManager;
import android.media.MediaMetadata;
import android.media.MediaMetadataEditor;
import android.media.MediaMetadataRetriever;
@@ -53,6 +54,7 @@ public class MediaSessionLegacyHelper {

    private Context mContext;
    private MediaSessionManager mSessionManager;
    private MediaCommunicationManager mCommunicationManager;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    // The legacy APIs use PendingIntents to register/unregister media button
    // receivers and these are associated with RCC.
@@ -63,6 +65,7 @@ public class MediaSessionLegacyHelper {
        mContext = context;
        mSessionManager = (MediaSessionManager) context
                .getSystemService(Context.MEDIA_SESSION_SERVICE);
        mCommunicationManager = context.getSystemService(MediaCommunicationManager.class);
    }

    @UnsupportedAppUsage
@@ -171,7 +174,7 @@ public class MediaSessionLegacyHelper {
            Log.w(TAG, "Tried to send a null key event. Ignoring.");
            return;
        }
        mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
        mCommunicationManager.dispatchMediaKeyEvent(keyEvent, needWakeLock);
        if (DEBUG) {
            Log.d(TAG, "dispatched media key " + keyEvent);
        }