From 11aee2c03a79edeb3e88cfa40ba112dc4d27dc74 Mon Sep 17 00:00:00 2001 From: Jin Seok Park Date: Thu, 4 Feb 2021 22:15:17 +0900 Subject: [PATCH] Change using Handler to using Executor Change addOnActiveSessionsChangedListener and other APIs to use Executor instead of Handler according to API council guideline. Also move the listener parameter to the end of the list of parameters to improve Kotlin-compatibility, since Kotlin allows SAM, or Single Abstract Method, to be expressed as a trailing lambda syntax. Bug: 174762061 Test: build && atest android.media.cts.MediaSessionManagerTest Change-Id: I556d400e86e4c05c6840e6835432a82ca3695774 --- core/api/module-lib-current.txt | 2 +- .../wm/shell/pip/PipMediaController.java | 7 +- .../media/session/MediaSessionManager.java | 104 +++++++++--------- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index bf70803fbc74f..946555e13f37e 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -129,7 +129,7 @@ package android.media.session { } public final class MediaSessionManager { - method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.os.Handler); + method public void addOnActiveSessionsChangedListener(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener); method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent); method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean); method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java index 1a4616c5f5910..6afcc06aa1ae0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java @@ -32,6 +32,7 @@ import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.UserHandle; import androidx.annotation.Nullable; @@ -76,6 +77,7 @@ public class PipMediaController { private final Context mContext; private final Handler mMainHandler; + private final HandlerExecutor mHandlerExecutor; private final MediaSessionManager mMediaSessionManager; private MediaController mMediaController; @@ -123,6 +125,7 @@ public class PipMediaController { public PipMediaController(Context context, Handler mainHandler) { mContext = context; mMainHandler = mainHandler; + mHandlerExecutor = new HandlerExecutor(mMainHandler); IntentFilter mediaControlFilter = new IntentFilter(); mediaControlFilter.addAction(ACTION_PLAY); mediaControlFilter.addAction(ACTION_PAUSE); @@ -247,8 +250,8 @@ public class PipMediaController { */ public void registerSessionListenerForCurrentUser() { mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionsChangedListener); - mMediaSessionManager.addOnActiveSessionsChangedListener(mSessionsChangedListener, null, - UserHandle.CURRENT, mMainHandler); + mMediaSessionManager.addOnActiveSessionsChangedListener(null, UserHandle.CURRENT, + mHandlerExecutor, mSessionsChangedListener); } /** diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index f580ea5d57de0..0cd3966e37eb2 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -34,6 +34,7 @@ import android.media.Session2Token; import android.media.VolumeProvider; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; @@ -321,7 +322,7 @@ public final class MediaSessionManager { @NonNull OnActiveSessionsChangedListener sessionListener, @Nullable ComponentName notificationListener, @Nullable Handler handler) { addOnActiveSessionsChangedListener(sessionListener, notificationListener, - UserHandle.myUserId(), handler); + UserHandle.myUserId(), handler == null ? null : new HandlerExecutor(handler)); } /** @@ -337,38 +338,40 @@ public final class MediaSessionManager { * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to * add listeners for user ids that do not belong to current process. * - * @param sessionListener The listener to add. * @param notificationListener The enabled notification listener component. May be null. * @param userHandle The user handle to listen for changes on. - * @param handler The handler to post updates on. + * @param executor The executor on which the listener should be invoked + * @param sessionListener The listener to add. * @hide */ - @SuppressLint({"ExecutorRegistration", "SamShouldBeLast", "UserHandle"}) + @SuppressLint("UserHandle") @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public void addOnActiveSessionsChangedListener( - @NonNull OnActiveSessionsChangedListener sessionListener, - @Nullable ComponentName notificationListener, @NonNull UserHandle userHandle, - @Nullable Handler handler) { + @Nullable ComponentName notificationListener, + @NonNull UserHandle userHandle, @NonNull Executor executor, + @NonNull OnActiveSessionsChangedListener sessionListener) { Objects.requireNonNull(userHandle, "userHandle shouldn't be null"); + Objects.requireNonNull(executor, "executor shouldn't be null"); addOnActiveSessionsChangedListener(sessionListener, notificationListener, - userHandle.getIdentifier(), handler); + userHandle.getIdentifier(), executor); } private void addOnActiveSessionsChangedListener( @NonNull OnActiveSessionsChangedListener sessionListener, @Nullable ComponentName notificationListener, int userId, - @Nullable Handler handler) { + @Nullable Executor executor) { Objects.requireNonNull(sessionListener, "sessionListener shouldn't be null"); - if (handler == null) { - handler = new Handler(); + if (executor == null) { + executor = new HandlerExecutor(new Handler()); } + synchronized (mLock) { if (mListeners.get(sessionListener) != null) { Log.w(TAG, "Attempted to add session listener twice, ignoring."); return; } SessionsChangedWrapper wrapper = new SessionsChangedWrapper(mContext, sessionListener, - handler); + executor); try { mService.addSessionsListener(wrapper.mStub, notificationListener, userId); mListeners.put(sessionListener, wrapper); @@ -412,7 +415,8 @@ public final class MediaSessionManager { */ public void addOnSession2TokensChangedListener( @NonNull OnSession2TokensChangedListener listener) { - addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, new Handler()); + addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, + new HandlerExecutor(new Handler())); } /** @@ -428,7 +432,9 @@ public final class MediaSessionManager { */ public void addOnSession2TokensChangedListener( @NonNull OnSession2TokensChangedListener listener, @NonNull Handler handler) { - addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, handler); + Objects.requireNonNull(handler, "handler shouldn't be null"); + addOnSession2TokensChangedListener(UserHandle.myUserId(), listener, + new HandlerExecutor(handler)); } /** @@ -445,20 +451,19 @@ public final class MediaSessionManager { * * @param userHandle The userHandle to listen for changes on * @param listener The listener to add - * @param handler The handler to call listener on. If {@code null}, calling thread's looper will - * be used. + * @param executor The executor on which the listener should be invoked * @hide */ @SuppressLint("UserHandle") public void addOnSession2TokensChangedListener(@NonNull UserHandle userHandle, - @NonNull OnSession2TokensChangedListener listener, @NonNull Handler handler) { + @NonNull OnSession2TokensChangedListener listener, @NonNull Executor executor) { Objects.requireNonNull(userHandle, "userHandle shouldn't be null"); - addOnSession2TokensChangedListener(userHandle.getIdentifier(), listener, handler); + Objects.requireNonNull(executor, "executor shouldn't be null"); + addOnSession2TokensChangedListener(userHandle.getIdentifier(), listener, executor); } private void addOnSession2TokensChangedListener(int userId, - OnSession2TokensChangedListener listener, Handler handler) { - Objects.requireNonNull(handler, "handler shouldn't be null"); + OnSession2TokensChangedListener listener, Executor executor) { Objects.requireNonNull(listener, "listener shouldn't be null"); synchronized (mLock) { if (mSession2TokensListeners.get(listener) != null) { @@ -466,7 +471,7 @@ public final class MediaSessionManager { return; } Session2TokensChangedWrapper wrapper = - new Session2TokensChangedWrapper(listener, handler); + new Session2TokensChangedWrapper(listener, executor); try { mService.addSession2TokensListener(wrapper.getStub(), userId); mSession2TokensListeners.put(listener, wrapper); @@ -847,7 +852,7 @@ public final class MediaSessionManager { /** * Add a {@link OnMediaKeyEventDispatchedListener}. * - * @param executor The executor on which the callback should be invoked + * @param executor The executor on which the listener should be invoked * @param listener A {@link OnMediaKeyEventDispatchedListener}. * @hide */ @@ -898,7 +903,7 @@ public final class MediaSessionManager { /** * Add a {@link OnMediaKeyEventDispatchedListener}. * - * @param executor The executor on which the callback should be invoked + * @param executor The executor on which the listener should be invoked * @param listener A {@link OnMediaKeyEventSessionChangedListener}. * @hide */ @@ -1220,62 +1225,61 @@ public final class MediaSessionManager { private static final class SessionsChangedWrapper { private Context mContext; private OnActiveSessionsChangedListener mListener; - private Handler mHandler; + private Executor mExecutor; public SessionsChangedWrapper(Context context, OnActiveSessionsChangedListener listener, - Handler handler) { + Executor executor) { mContext = context; mListener = listener; - mHandler = handler; + mExecutor = executor; } private final IActiveSessionsListener.Stub mStub = new IActiveSessionsListener.Stub() { @Override public void onActiveSessionsChanged(final List tokens) { - final Handler handler = mHandler; - if (handler != null) { - handler.post(new Runnable() { - @Override - public void run() { - final Context context = mContext; - if (context != null) { - ArrayList controllers = new ArrayList<>(); - int size = tokens.size(); - for (int i = 0; i < size; i++) { - controllers.add(new MediaController(context, tokens.get(i))); - } - final OnActiveSessionsChangedListener listener = mListener; - if (listener != null) { - listener.onActiveSessionsChanged(controllers); - } - } - } - }); + if (mExecutor != null) { + final Executor executor = mExecutor; + executor.execute(() -> callOnActiveSessionsChangedListener(tokens)); } } }; + private void callOnActiveSessionsChangedListener(final List tokens) { + final Context context = mContext; + if (context != null) { + ArrayList controllers = new ArrayList<>(); + int size = tokens.size(); + for (int i = 0; i < size; i++) { + controllers.add(new MediaController(context, tokens.get(i))); + } + final OnActiveSessionsChangedListener listener = mListener; + if (listener != null) { + listener.onActiveSessionsChanged(controllers); + } + } + } + private void release() { mListener = null; mContext = null; - mHandler = null; + mExecutor = null; } } private static final class Session2TokensChangedWrapper { private final OnSession2TokensChangedListener mListener; - private final Handler mHandler; + private final Executor mExecutor; private final ISession2TokensListener.Stub mStub = new ISession2TokensListener.Stub() { @Override public void onSession2TokensChanged(final List tokens) { - mHandler.post(() -> mListener.onSession2TokensChanged(tokens)); + mExecutor.execute(() -> mListener.onSession2TokensChanged(tokens)); } }; - Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Handler handler) { + Session2TokensChangedWrapper(OnSession2TokensChangedListener listener, Executor executor) { mListener = listener; - mHandler = (handler == null) ? new Handler() : new Handler(handler.getLooper()); + mExecutor = executor; } public ISession2TokensListener.Stub getStub() {