Loading api/system-current.txt +10 −8 Original line number Diff line number Diff line Loading @@ -4195,18 +4195,20 @@ package android.media.audiopolicy { package android.media.session { public final class MediaSessionManager { method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener); method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback); } public abstract static class MediaSessionManager.Callback { ctor public MediaSessionManager.Callback(); method public abstract void onAddressedPlayerChanged(android.media.session.MediaSession.Token); method public abstract void onAddressedPlayerChanged(android.content.ComponentName); method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token); method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName); public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener { method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @NonNull android.media.session.MediaSession.Token); } public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener { method public default void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token); } public static interface MediaSessionManager.OnMediaKeyListener { Loading media/java/android/media/session/ICallback.aidl→media/java/android/media/session/IOnMediaKeyEventDispatchedListener.aidl +4 −11 Original line number Diff line number Diff line /* Copyright (C) 2016 The Android Open Source Project /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -15,21 +16,13 @@ package android.media.session; import android.app.PendingIntent; import android.content.ComponentName; import android.media.session.MediaSession; import android.view.KeyEvent; /** * @hide */ oneway interface ICallback { void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event, oneway interface IOnMediaKeyEventDispatchedListener { void onMediaKeyEventDispatched(in KeyEvent event, in String packageName, in MediaSession.Token sessionToken); void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event, in ComponentName mediaButtonReceiver); void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken); void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver); } media/java/android/media/session/IOnMediaKeyEventSessionChangedListener.aidl 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media.session; import android.media.session.MediaSession; /** * @hide */ oneway interface IOnMediaKeyEventSessionChangedListener { void onMediaKeyEventSessionChanged(in String packageName, in MediaSession.Token mediaKeyEventSessionToken); } media/java/android/media/session/ISessionManager.aidl +8 −3 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ import android.content.pm.ParceledListSlice; import android.media.IRemoteVolumeController; import android.media.Session2Token; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyEventDispatchedListener; import android.media.session.IOnMediaKeyEventSessionChangedListener; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; import android.media.session.ISession; Loading Loading @@ -62,8 +63,12 @@ interface ISessionManager { // For PhoneWindowManager to precheck media keys boolean isGlobalPriorityActive(); void registerCallback(in ICallback callback); void unregisterCallback(in ICallback callback); void addOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener); void removeOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener); void addOnMediaKeyEventSessionChangedListener( in IOnMediaKeyEventSessionChangedListener listener); void removeOnMediaKeyEventSessionChangedListener( in IOnMediaKeyEventSessionChangedListener listener); void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener); void setOnMediaKeyListener(in IOnMediaKeyListener listener); Loading media/java/android/media/session/MediaSessionManager.java +131 −122 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.media.MediaSession2; import android.media.Session2Token; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; Loading Loading @@ -78,29 +77,33 @@ public final class MediaSessionManager { */ public static final int RESULT_MEDIA_KEY_HANDLED = 1; private final ISessionManager mService; private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub = new OnMediaKeyEventDispatchedListenerStub(); private final OnMediaKeyEventSessionChangedListenerStub mOnMediaKeyEventSessionChangedListenerStub = new OnMediaKeyEventSessionChangedListenerStub(); private final Object mLock = new Object(); @GuardedBy("mLock") private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); @GuardedBy("mLock") private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper> mSession2TokensListeners = new ArrayMap<>(); @GuardedBy("mLock") private final CallbackStub mCbStub = new CallbackStub(); private final Map<OnMediaKeyEventDispatchedListener, Executor> mOnMediaKeyEventDispatchedListeners = new HashMap<>(); @GuardedBy("mLock") private final Map<Callback, Executor> mCallbacks = new HashMap<>(); private final Map<OnMediaKeyEventSessionChangedListener, Executor> mMediaKeyEventSessionChangedCallbacks = new HashMap<>(); @GuardedBy("mLock") private MediaSession.Token mCurMediaButtonSession; private String mCurMediaKeyEventSessionPackage; @GuardedBy("mLock") private ComponentName mCurMediaButtonReceiver; private MediaSession.Token mCurMediaKeyEventSession; private Context mContext; private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener; private OnMediaKeyListenerImpl mOnMediaKeyListener; // TODO: Remove mLegacyCallback once Bluetooth app stop calling setCallback() method. @GuardedBy("mLock") private Callback mLegacyCallback; /** * @hide Loading Loading @@ -756,89 +759,118 @@ public final class MediaSessionManager { } /** * Set a {@link Callback}. * Add a {@link OnMediaKeyEventDispatchedListener}. * * <p>System can only have a single callback, and the callback can only be set by * Bluetooth service process. * @param executor The executor on which the callback should be invoked * @param listener A {@link OnMediaKeyEventDispatchedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnMediaKeyEventDispatchedListener listener) { if (executor == null) { throw new NullPointerException("executor shouldn't be null"); } if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mOnMediaKeyEventDispatchedListeners.put(listener, executor); if (mOnMediaKeyEventDispatchedListeners.size() == 1) { mService.addOnMediaKeyEventDispatchedListener( mOnMediaKeyEventDispatchedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key listener", e); } } } /** * Remove a {@link OnMediaKeyEventDispatchedListener}. * * @param callback A {@link Callback}. {@code null} to reset. * @param handler The handler on which the callback should be invoked, or {@code null} * if the callback should be invoked on the calling thread's looper. * @param listener A {@link OnMediaKeyEventDispatchedListener}. * @hide */ // TODO: Remove this method once Bluetooth app stop calling it. public void setCallback(@Nullable Callback callback, @Nullable Handler handler) { if (handler == null) { handler = new Handler(); @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener( @NonNull OnMediaKeyEventDispatchedListener listener) { if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { if (mLegacyCallback != null) { unregisterCallback(mLegacyCallback); try { mOnMediaKeyEventDispatchedListeners.remove(listener); if (mOnMediaKeyEventDispatchedListeners.size() == 0) { mService.removeOnMediaKeyEventDispatchedListener( mOnMediaKeyEventDispatchedListenerStub); } mLegacyCallback = callback; if (callback != null) { registerCallback(new HandlerExecutor(handler), callback); } catch (RemoteException e) { Log.e(TAG, "Failed to set media key event dispatched listener", e); } } } /** * Register a {@link Callback}. * Add a {@link OnMediaKeyEventDispatchedListener}. * * @param executor The executor on which the callback should be invoked * @param callback A {@link Callback}. * @param listener A {@link OnMediaKeyEventSessionChangedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) { public void addOnMediaKeyEventSessionChangedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnMediaKeyEventSessionChangedListener listener) { if (executor == null) { throw new NullPointerException("executor shouldn't be null"); } if (callback == null) { throw new NullPointerException("callback shouldn't be null"); if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mCallbacks.put(callback, executor); if (mCurMediaButtonSession != null) { executor.execute( () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession)); } else if (mCurMediaButtonReceiver != null) { mMediaKeyEventSessionChangedCallbacks.put(listener, executor); executor.execute( () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver)); } if (mCallbacks.size() == 1) { mService.registerCallback(mCbStub); () -> listener.onMediaKeyEventSessionChanged( mCurMediaKeyEventSessionPackage, mCurMediaKeyEventSession)); if (mMediaKeyEventSessionChangedCallbacks.size() == 1) { mService.addOnMediaKeyEventSessionChangedListener( mOnMediaKeyEventSessionChangedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key callback", e); Log.e(TAG, "Failed to set media key listener", e); } } } /** * Unregister a {@link Callback}. * Remove a {@link OnMediaKeyEventSessionChangedListener}. * * @param callback A {@link Callback}. * @param listener A {@link OnMediaKeyEventSessionChangedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull Callback callback) { if (callback == null) { throw new NullPointerException("callback shouldn't be null"); public void removeOnMediaKeyEventSessionChangedListener( @NonNull OnMediaKeyEventSessionChangedListener listener) { if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mCallbacks.remove(callback); if (mCallbacks.size() == 0) { mService.unregisterCallback(mCbStub); mMediaKeyEventSessionChangedCallbacks.remove(listener); if (mMediaKeyEventSessionChangedCallbacks.size() == 0) { mService.removeOnMediaKeyEventSessionChangedListener( mOnMediaKeyEventSessionChangedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key callback", e); Log.e(TAG, "Failed to set media key listener", e); } } } Loading Loading @@ -900,54 +932,46 @@ public final class MediaSessionManager { } /** * Callbacks for the media session service. * * <p>Called when a media key event is dispatched or the addressed player is changed. * The addressed player is either the media session or the media button receiver that will * receive media key events. * Listener to receive when the media session service * @hide */ @SystemApi public static abstract class Callback { public interface OnMediaKeyEventDispatchedListener { /** * Called when a media key event is dispatched to the media session * through the media session service. * Called when a media key event is dispatched through the media session service. The * session token can be {@link null} if the framework has sent the media key event to the * media button receiver to revive the media app's playback. * * @param event Dispatched media key event. * @param sessionToken The media session's token. */ public abstract void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token sessionToken); /** * Called when a media key event is dispatched to the media button receiver * through the media session service. * <p>MediaSessionService may broadcast key events to the media button receiver * when reviving playback after the media session is released. * the session is dead when , but the framework sent * * @param event Dispatched media key event. * @param mediaButtonReceiver The media button receiver. * @param packageName Package * @param sessionToken The media session's token. Can be {@code null}. */ public abstract void onMediaKeyEventDispatched(KeyEvent event, ComponentName mediaButtonReceiver); default void onMediaKeyEventDispatched(@NonNull KeyEvent event, @NonNull String packageName, @NonNull MediaSession.Token sessionToken) { } } /** * Called when the addressed player is changed to a media session. * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after * {@link #registerCallback} if the addressed player exists. * * @param sessionToken The media session's token. * Listener to receive changes in the media key event session, which would receive the media key * event unless specified. * @hide */ public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken); @SystemApi public interface OnMediaKeyEventSessionChangedListener { /** * Called when the addressed player is changed to the media button receiver. * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after * {@link #registerCallback} if the addressed player exists. * Called when the media key session is changed to the given media session. The key event * session is the media session which would receive key event by default, unless the caller * has specified the target. * <p> * The session token can be {@link null} if the media button session is unset. In that case, * framework would dispatch to the last sessions's media button receiver. * * @param mediaButtonReceiver The media button receiver. * @param packageName The package name who would receive the media key event. Can be empty. * @param sessionToken The media session's token. Can be {@code null.} */ public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver); default void onMediaKeyEventSessionChanged(@NonNull String packageName, @Nullable MediaSession.Token sessionToken) { } } /** Loading Loading @@ -1149,50 +1173,35 @@ public final class MediaSessionManager { } } private final class CallbackStub extends ICallback.Stub { private final class OnMediaKeyEventDispatchedListenerStub extends IOnMediaKeyEventDispatchedListener.Stub { @Override public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event, public void onMediaKeyEventDispatched(KeyEvent event, String packageName, MediaSession.Token sessionToken) { synchronized (mLock) { for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken)); } } } @Override public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event, ComponentName mediaButtonReceiver) { synchronized (mLock) { for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { for (Map.Entry<OnMediaKeyEventDispatchedListener, Executor> e : mOnMediaKeyEventDispatchedListeners.entrySet()) { e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver)); () -> e.getKey().onMediaKeyEventDispatched(event, packageName, sessionToken)); } } } @Override public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) { synchronized (mLock) { mCurMediaButtonSession = sessionToken; mCurMediaButtonReceiver = null; for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken)); } } } private final class OnMediaKeyEventSessionChangedListenerStub extends IOnMediaKeyEventSessionChangedListener.Stub { @Override public void onAddressedPlayerChangedToMediaButtonReceiver( ComponentName mediaButtonReceiver) { public void onMediaKeyEventSessionChanged(String packageName, MediaSession.Token sessionToken) { synchronized (mLock) { mCurMediaButtonSession = null; mCurMediaButtonReceiver = mediaButtonReceiver; for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged( mediaButtonReceiver)); mCurMediaKeyEventSessionPackage = packageName; mCurMediaKeyEventSession = sessionToken; for (Map.Entry<OnMediaKeyEventSessionChangedListener, Executor> e : mMediaKeyEventSessionChangedCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onMediaKeyEventSessionChanged(packageName, sessionToken)); } } } Loading Loading
api/system-current.txt +10 −8 Original line number Diff line number Diff line Loading @@ -4195,18 +4195,20 @@ package android.media.audiopolicy { package android.media.session { public final class MediaSessionManager { method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.Callback); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener); method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback); } public abstract static class MediaSessionManager.Callback { ctor public MediaSessionManager.Callback(); method public abstract void onAddressedPlayerChanged(android.media.session.MediaSession.Token); method public abstract void onAddressedPlayerChanged(android.content.ComponentName); method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token); method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName); public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener { method public default void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @NonNull android.media.session.MediaSession.Token); } public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener { method public default void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token); } public static interface MediaSessionManager.OnMediaKeyListener { Loading
media/java/android/media/session/ICallback.aidl→media/java/android/media/session/IOnMediaKeyEventDispatchedListener.aidl +4 −11 Original line number Diff line number Diff line /* Copyright (C) 2016 The Android Open Source Project /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. Loading @@ -15,21 +16,13 @@ package android.media.session; import android.app.PendingIntent; import android.content.ComponentName; import android.media.session.MediaSession; import android.view.KeyEvent; /** * @hide */ oneway interface ICallback { void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event, oneway interface IOnMediaKeyEventDispatchedListener { void onMediaKeyEventDispatched(in KeyEvent event, in String packageName, in MediaSession.Token sessionToken); void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event, in ComponentName mediaButtonReceiver); void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken); void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver); }
media/java/android/media/session/IOnMediaKeyEventSessionChangedListener.aidl 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media.session; import android.media.session.MediaSession; /** * @hide */ oneway interface IOnMediaKeyEventSessionChangedListener { void onMediaKeyEventSessionChanged(in String packageName, in MediaSession.Token mediaKeyEventSessionToken); }
media/java/android/media/session/ISessionManager.aidl +8 −3 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ import android.content.pm.ParceledListSlice; import android.media.IRemoteVolumeController; import android.media.Session2Token; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyEventDispatchedListener; import android.media.session.IOnMediaKeyEventSessionChangedListener; import android.media.session.IOnMediaKeyListener; import android.media.session.IOnVolumeKeyLongPressListener; import android.media.session.ISession; Loading Loading @@ -62,8 +63,12 @@ interface ISessionManager { // For PhoneWindowManager to precheck media keys boolean isGlobalPriorityActive(); void registerCallback(in ICallback callback); void unregisterCallback(in ICallback callback); void addOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener); void removeOnMediaKeyEventDispatchedListener(in IOnMediaKeyEventDispatchedListener listener); void addOnMediaKeyEventSessionChangedListener( in IOnMediaKeyEventSessionChangedListener listener); void removeOnMediaKeyEventSessionChangedListener( in IOnMediaKeyEventSessionChangedListener listener); void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener); void setOnMediaKeyListener(in IOnMediaKeyListener listener); Loading
media/java/android/media/session/MediaSessionManager.java +131 −122 Original line number Diff line number Diff line Loading @@ -32,7 +32,6 @@ import android.media.MediaSession2; import android.media.Session2Token; import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; Loading Loading @@ -78,29 +77,33 @@ public final class MediaSessionManager { */ public static final int RESULT_MEDIA_KEY_HANDLED = 1; private final ISessionManager mService; private final OnMediaKeyEventDispatchedListenerStub mOnMediaKeyEventDispatchedListenerStub = new OnMediaKeyEventDispatchedListenerStub(); private final OnMediaKeyEventSessionChangedListenerStub mOnMediaKeyEventSessionChangedListenerStub = new OnMediaKeyEventSessionChangedListenerStub(); private final Object mLock = new Object(); @GuardedBy("mLock") private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); @GuardedBy("mLock") private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper> mSession2TokensListeners = new ArrayMap<>(); @GuardedBy("mLock") private final CallbackStub mCbStub = new CallbackStub(); private final Map<OnMediaKeyEventDispatchedListener, Executor> mOnMediaKeyEventDispatchedListeners = new HashMap<>(); @GuardedBy("mLock") private final Map<Callback, Executor> mCallbacks = new HashMap<>(); private final Map<OnMediaKeyEventSessionChangedListener, Executor> mMediaKeyEventSessionChangedCallbacks = new HashMap<>(); @GuardedBy("mLock") private MediaSession.Token mCurMediaButtonSession; private String mCurMediaKeyEventSessionPackage; @GuardedBy("mLock") private ComponentName mCurMediaButtonReceiver; private MediaSession.Token mCurMediaKeyEventSession; private Context mContext; private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener; private OnMediaKeyListenerImpl mOnMediaKeyListener; // TODO: Remove mLegacyCallback once Bluetooth app stop calling setCallback() method. @GuardedBy("mLock") private Callback mLegacyCallback; /** * @hide Loading Loading @@ -756,89 +759,118 @@ public final class MediaSessionManager { } /** * Set a {@link Callback}. * Add a {@link OnMediaKeyEventDispatchedListener}. * * <p>System can only have a single callback, and the callback can only be set by * Bluetooth service process. * @param executor The executor on which the callback should be invoked * @param listener A {@link OnMediaKeyEventDispatchedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnMediaKeyEventDispatchedListener listener) { if (executor == null) { throw new NullPointerException("executor shouldn't be null"); } if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mOnMediaKeyEventDispatchedListeners.put(listener, executor); if (mOnMediaKeyEventDispatchedListeners.size() == 1) { mService.addOnMediaKeyEventDispatchedListener( mOnMediaKeyEventDispatchedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key listener", e); } } } /** * Remove a {@link OnMediaKeyEventDispatchedListener}. * * @param callback A {@link Callback}. {@code null} to reset. * @param handler The handler on which the callback should be invoked, or {@code null} * if the callback should be invoked on the calling thread's looper. * @param listener A {@link OnMediaKeyEventDispatchedListener}. * @hide */ // TODO: Remove this method once Bluetooth app stop calling it. public void setCallback(@Nullable Callback callback, @Nullable Handler handler) { if (handler == null) { handler = new Handler(); @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener( @NonNull OnMediaKeyEventDispatchedListener listener) { if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { if (mLegacyCallback != null) { unregisterCallback(mLegacyCallback); try { mOnMediaKeyEventDispatchedListeners.remove(listener); if (mOnMediaKeyEventDispatchedListeners.size() == 0) { mService.removeOnMediaKeyEventDispatchedListener( mOnMediaKeyEventDispatchedListenerStub); } mLegacyCallback = callback; if (callback != null) { registerCallback(new HandlerExecutor(handler), callback); } catch (RemoteException e) { Log.e(TAG, "Failed to set media key event dispatched listener", e); } } } /** * Register a {@link Callback}. * Add a {@link OnMediaKeyEventDispatchedListener}. * * @param executor The executor on which the callback should be invoked * @param callback A {@link Callback}. * @param listener A {@link OnMediaKeyEventSessionChangedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) { public void addOnMediaKeyEventSessionChangedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnMediaKeyEventSessionChangedListener listener) { if (executor == null) { throw new NullPointerException("executor shouldn't be null"); } if (callback == null) { throw new NullPointerException("callback shouldn't be null"); if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mCallbacks.put(callback, executor); if (mCurMediaButtonSession != null) { executor.execute( () -> callback.onAddressedPlayerChanged(mCurMediaButtonSession)); } else if (mCurMediaButtonReceiver != null) { mMediaKeyEventSessionChangedCallbacks.put(listener, executor); executor.execute( () -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver)); } if (mCallbacks.size() == 1) { mService.registerCallback(mCbStub); () -> listener.onMediaKeyEventSessionChanged( mCurMediaKeyEventSessionPackage, mCurMediaKeyEventSession)); if (mMediaKeyEventSessionChangedCallbacks.size() == 1) { mService.addOnMediaKeyEventSessionChangedListener( mOnMediaKeyEventSessionChangedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key callback", e); Log.e(TAG, "Failed to set media key listener", e); } } } /** * Unregister a {@link Callback}. * Remove a {@link OnMediaKeyEventSessionChangedListener}. * * @param callback A {@link Callback}. * @param listener A {@link OnMediaKeyEventSessionChangedListener}. * @hide */ @SystemApi @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull Callback callback) { if (callback == null) { throw new NullPointerException("callback shouldn't be null"); public void removeOnMediaKeyEventSessionChangedListener( @NonNull OnMediaKeyEventSessionChangedListener listener) { if (listener == null) { throw new NullPointerException("listener shouldn't be null"); } synchronized (mLock) { try { mCallbacks.remove(callback); if (mCallbacks.size() == 0) { mService.unregisterCallback(mCbStub); mMediaKeyEventSessionChangedCallbacks.remove(listener); if (mMediaKeyEventSessionChangedCallbacks.size() == 0) { mService.removeOnMediaKeyEventSessionChangedListener( mOnMediaKeyEventSessionChangedListenerStub); } } catch (RemoteException e) { Log.e(TAG, "Failed to set media key callback", e); Log.e(TAG, "Failed to set media key listener", e); } } } Loading Loading @@ -900,54 +932,46 @@ public final class MediaSessionManager { } /** * Callbacks for the media session service. * * <p>Called when a media key event is dispatched or the addressed player is changed. * The addressed player is either the media session or the media button receiver that will * receive media key events. * Listener to receive when the media session service * @hide */ @SystemApi public static abstract class Callback { public interface OnMediaKeyEventDispatchedListener { /** * Called when a media key event is dispatched to the media session * through the media session service. * Called when a media key event is dispatched through the media session service. The * session token can be {@link null} if the framework has sent the media key event to the * media button receiver to revive the media app's playback. * * @param event Dispatched media key event. * @param sessionToken The media session's token. */ public abstract void onMediaKeyEventDispatched(KeyEvent event, MediaSession.Token sessionToken); /** * Called when a media key event is dispatched to the media button receiver * through the media session service. * <p>MediaSessionService may broadcast key events to the media button receiver * when reviving playback after the media session is released. * the session is dead when , but the framework sent * * @param event Dispatched media key event. * @param mediaButtonReceiver The media button receiver. * @param packageName Package * @param sessionToken The media session's token. Can be {@code null}. */ public abstract void onMediaKeyEventDispatched(KeyEvent event, ComponentName mediaButtonReceiver); default void onMediaKeyEventDispatched(@NonNull KeyEvent event, @NonNull String packageName, @NonNull MediaSession.Token sessionToken) { } } /** * Called when the addressed player is changed to a media session. * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after * {@link #registerCallback} if the addressed player exists. * * @param sessionToken The media session's token. * Listener to receive changes in the media key event session, which would receive the media key * event unless specified. * @hide */ public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken); @SystemApi public interface OnMediaKeyEventSessionChangedListener { /** * Called when the addressed player is changed to the media button receiver. * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after * {@link #registerCallback} if the addressed player exists. * Called when the media key session is changed to the given media session. The key event * session is the media session which would receive key event by default, unless the caller * has specified the target. * <p> * The session token can be {@link null} if the media button session is unset. In that case, * framework would dispatch to the last sessions's media button receiver. * * @param mediaButtonReceiver The media button receiver. * @param packageName The package name who would receive the media key event. Can be empty. * @param sessionToken The media session's token. Can be {@code null.} */ public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver); default void onMediaKeyEventSessionChanged(@NonNull String packageName, @Nullable MediaSession.Token sessionToken) { } } /** Loading Loading @@ -1149,50 +1173,35 @@ public final class MediaSessionManager { } } private final class CallbackStub extends ICallback.Stub { private final class OnMediaKeyEventDispatchedListenerStub extends IOnMediaKeyEventDispatchedListener.Stub { @Override public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event, public void onMediaKeyEventDispatched(KeyEvent event, String packageName, MediaSession.Token sessionToken) { synchronized (mLock) { for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken)); } } } @Override public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event, ComponentName mediaButtonReceiver) { synchronized (mLock) { for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { for (Map.Entry<OnMediaKeyEventDispatchedListener, Executor> e : mOnMediaKeyEventDispatchedListeners.entrySet()) { e.getValue().execute( () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver)); () -> e.getKey().onMediaKeyEventDispatched(event, packageName, sessionToken)); } } } @Override public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) { synchronized (mLock) { mCurMediaButtonSession = sessionToken; mCurMediaButtonReceiver = null; for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged(sessionToken)); } } } private final class OnMediaKeyEventSessionChangedListenerStub extends IOnMediaKeyEventSessionChangedListener.Stub { @Override public void onAddressedPlayerChangedToMediaButtonReceiver( ComponentName mediaButtonReceiver) { public void onMediaKeyEventSessionChanged(String packageName, MediaSession.Token sessionToken) { synchronized (mLock) { mCurMediaButtonSession = null; mCurMediaButtonReceiver = mediaButtonReceiver; for (Map.Entry<Callback, Executor> e : mCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onAddressedPlayerChanged( mediaButtonReceiver)); mCurMediaKeyEventSessionPackage = packageName; mCurMediaKeyEventSession = sessionToken; for (Map.Entry<OnMediaKeyEventSessionChangedListener, Executor> e : mMediaKeyEventSessionChangedCallbacks.entrySet()) { e.getValue().execute(() -> e.getKey().onMediaKeyEventSessionChanged(packageName, sessionToken)); } } } Loading