Loading Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -419,9 +419,9 @@ java_library { "location/java/android/location/IGpsGeofenceHardware.aidl", "location/java/android/location/INetInitiatedListener.aidl", "location/java/com/android/internal/location/ILocationProvider.aidl", "media/java/android/media/IAudioService.aidl", "media/java/android/media/IAudioFocusDispatcher.aidl", "media/java/android/media/IAudioRoutesObserver.aidl", "media/java/android/media/IAudioService.aidl", "media/java/android/media/IMediaHTTPConnection.aidl", "media/java/android/media/IMediaHTTPService.aidl", "media/java/android/media/IMediaResourceMonitor.aidl", Loading @@ -432,6 +432,7 @@ java_library { "media/java/android/media/IMediaSession2.aidl", "media/java/android/media/IMediaSession2Callback.aidl", "media/java/android/media/IPlaybackConfigDispatcher.aidl", "media/java/android/media/ISessionTokensListener.aidl", ":libaudioclient_aidl", "media/java/android/media/IRecordingConfigDispatcher.aidl", "media/java/android/media/IRemoteDisplayCallback.aidl", Loading media/java/android/media/ISessionTokensListener.aidl 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright 2018 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; import android.os.Bundle; /** * Listens for changes to the list of session tokens. * @hide */ oneway interface ISessionTokensListener { void onSessionTokensChanged(in List<Bundle> tokens); } media/java/android/media/session/ISessionManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.media.session; import android.content.ComponentName; import android.media.IRemoteVolumeController; import android.media.IMediaSession2; import android.media.ISessionTokensListener; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; Loading Loading @@ -55,4 +56,8 @@ interface ISessionManager { boolean onSessionCreated(in Bundle sessionToken); void onSessionDestroyed(in Bundle sessionToken); List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly); void addSessionTokensListener(in ISessionTokensListener listener, int userId, String packageName); void removeSessionTokensListener(in ISessionTokensListener listener); } media/java/android/media/session/MediaSessionManager.java +139 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media.session; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -24,8 +25,8 @@ import android.annotation.SystemService; import android.content.ComponentName; import android.content.Context; import android.media.AudioManager; import android.media.IMediaSession2; import android.media.IRemoteVolumeController; import android.media.ISessionTokensListener; import android.media.MediaSession2; import android.media.MediaSessionService2; import android.media.SessionToken2; Loading @@ -44,6 +45,7 @@ import android.view.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; /** * Provides support for interacting with {@link MediaSession media sessions} Loading Loading @@ -71,6 +73,8 @@ public final class MediaSessionManager { private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); private final ArrayMap<OnSessionTokensChangedListener, SessionTokensChangedWrapper> mSessionTokensListener = new ArrayMap<>(); private final Object mLock = new Object(); private final ISessionManager mService; Loading Loading @@ -371,13 +375,15 @@ public final class MediaSessionManager { * Get {@link List} of {@link SessionToken2} whose sessions are active now. This list represents * active sessions regardless of whether they're {@link MediaSession2} or * {@link MediaSessionService2}. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewan): Protect this with permission. // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getActiveSessionTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -392,12 +398,15 @@ public final class MediaSessionManager { /** * Get {@link List} of {@link SessionToken2} for {@link MediaSessionService2} regardless of their * activeness. This list represents media apps that support background playback. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getSessionServiceTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -412,15 +421,17 @@ public final class MediaSessionManager { /** * Get all {@link SessionToken2}s. This is the combined list of {@link #getActiveSessionTokens()} * and {@link #getSessionServiceTokens}. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @see #getActiveSessionTokens * @see #getSessionServiceTokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewan): Protect this with permission. // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getAllSessionTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -432,6 +443,86 @@ public final class MediaSessionManager { } } /** * Add a listener to be notified when the {@link #getAllSessionTokens()} changes. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @param executor executor to run this command * @param listener The listener to add. * @hide */ // TODO(jaewan): Unhide public void addOnSessionTokensChangedListener(@NonNull @CallbackExecutor Executor executor, @NonNull OnSessionTokensChangedListener listener) { addOnSessionTokensChangedListener(UserHandle.myUserId(), executor, listener); } /** * Add a listener to be notified when the {@link #getAllSessionTokens()} changes. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @param userId The userId to listen for changes on. * @param executor executor to run this command * @param listener The listener to add. * @hide */ public void addOnSessionTokensChangedListener(int userId, @NonNull @CallbackExecutor Executor executor, @NonNull OnSessionTokensChangedListener listener) { if (executor == null) { throw new IllegalArgumentException("executor may not be null"); } if (listener == null) { throw new IllegalArgumentException("listener may not be null"); } synchronized (mLock) { if (mSessionTokensListener.get(listener) != null) { Log.w(TAG, "Attempted to add session listener twice, ignoring."); return; } SessionTokensChangedWrapper wrapper = new SessionTokensChangedWrapper( mContext, executor, listener); try { mService.addSessionTokensListener(wrapper.mStub, userId, mContext.getPackageName()); mSessionTokensListener.put(listener, wrapper); } catch (RemoteException e) { Log.e(TAG, "Error in addSessionTokensListener.", e); } } } /** * Stop receiving session token updates on the specified listener. * * @param listener The listener to remove. * @hide */ // TODO(jaewan): Unhide public void removeOnSessionTokensChangedListener( @NonNull OnSessionTokensChangedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener may not be null"); } synchronized (mLock) { SessionTokensChangedWrapper wrapper = mSessionTokensListener.remove(listener); if (wrapper != null) { try { mService.removeSessionTokensListener(wrapper.mStub); } catch (RemoteException e) { Log.e(TAG, "Error in removeSessionTokensListener.", e); } finally { wrapper.release(); } } } } private static List<SessionToken2> toTokenList(Context context, List<Bundle> bundles) { List<SessionToken2> tokens = new ArrayList<>(); if (bundles != null) { Loading Loading @@ -566,6 +657,16 @@ public final class MediaSessionManager { public void onActiveSessionsChanged(@Nullable List<MediaController> controllers); } /** * Listens for changes to the {@link #getAllSessionTokens()}. This can be added * using {@link #addOnActiveSessionsChangedListener}. * @hide */ // TODO(jaewan): Unhide public interface OnSessionTokensChangedListener { void onSessionTokensChanged(@NonNull List<SessionToken2> tokens); } /** * Listens the volume key long-presses. * @hide Loading Loading @@ -692,6 +793,35 @@ public final class MediaSessionManager { } } private static final class SessionTokensChangedWrapper { private Context mContext; private Executor mExecutor; private OnSessionTokensChangedListener mListener; public SessionTokensChangedWrapper(Context context, Executor executor, OnSessionTokensChangedListener listener) { mContext = context; mExecutor = executor; mListener = listener; } private final ISessionTokensListener.Stub mStub = new ISessionTokensListener.Stub() { @Override public void onSessionTokensChanged(final List<Bundle> bundles) { mExecutor.execute(() -> { List<SessionToken2> tokens = toTokenList(mContext, bundles); mListener.onSessionTokensChanged(tokens); }); } }; private void release() { mListener = null; mContext = null; mExecutor = null; } } private static final class OnVolumeKeyLongPressListenerImpl extends IOnVolumeKeyLongPressListener.Stub { private OnVolumeKeyLongPressListener mListener; Loading services/core/java/com/android/server/media/MediaSessionService.java +12 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.media.AudioSystem; import android.media.IAudioService; import android.media.IMediaSession2; import android.media.IRemoteVolumeController; import android.media.ISessionTokensListener; import android.media.MediaLibraryService2; import android.media.MediaSessionService2; import android.media.SessionToken2; Loading Loading @@ -1480,7 +1481,6 @@ public class MediaSessionService extends SystemService implements Monitor { } // TODO(jaewan): Protect this API with permission // TODO(jaewan): Add listeners for change in operations.. @Override public List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly) throws RemoteException { Loading @@ -1504,6 +1504,17 @@ public class MediaSessionService extends SystemService implements Monitor { return tokens; } @Override public void addSessionTokensListener(ISessionTokensListener listener, int userId, String packageName) { // TODO(jaewan): Implement. } @Override public void removeSessionTokensListener(ISessionTokensListener listener) { // TODO(jaewan): Implement } private int verifySessionsRequest(ComponentName componentName, int userId, final int pid, final int uid) { String packageName = null; Loading Loading
Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -419,9 +419,9 @@ java_library { "location/java/android/location/IGpsGeofenceHardware.aidl", "location/java/android/location/INetInitiatedListener.aidl", "location/java/com/android/internal/location/ILocationProvider.aidl", "media/java/android/media/IAudioService.aidl", "media/java/android/media/IAudioFocusDispatcher.aidl", "media/java/android/media/IAudioRoutesObserver.aidl", "media/java/android/media/IAudioService.aidl", "media/java/android/media/IMediaHTTPConnection.aidl", "media/java/android/media/IMediaHTTPService.aidl", "media/java/android/media/IMediaResourceMonitor.aidl", Loading @@ -432,6 +432,7 @@ java_library { "media/java/android/media/IMediaSession2.aidl", "media/java/android/media/IMediaSession2Callback.aidl", "media/java/android/media/IPlaybackConfigDispatcher.aidl", "media/java/android/media/ISessionTokensListener.aidl", ":libaudioclient_aidl", "media/java/android/media/IRecordingConfigDispatcher.aidl", "media/java/android/media/IRemoteDisplayCallback.aidl", Loading
media/java/android/media/ISessionTokensListener.aidl 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright 2018 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; import android.os.Bundle; /** * Listens for changes to the list of session tokens. * @hide */ oneway interface ISessionTokensListener { void onSessionTokensChanged(in List<Bundle> tokens); }
media/java/android/media/session/ISessionManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.media.session; import android.content.ComponentName; import android.media.IRemoteVolumeController; import android.media.IMediaSession2; import android.media.ISessionTokensListener; import android.media.session.IActiveSessionsListener; import android.media.session.ICallback; import android.media.session.IOnMediaKeyListener; Loading Loading @@ -55,4 +56,8 @@ interface ISessionManager { boolean onSessionCreated(in Bundle sessionToken); void onSessionDestroyed(in Bundle sessionToken); List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly); void addSessionTokensListener(in ISessionTokensListener listener, int userId, String packageName); void removeSessionTokensListener(in ISessionTokensListener listener); }
media/java/android/media/session/MediaSessionManager.java +139 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.media.session; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; Loading @@ -24,8 +25,8 @@ import android.annotation.SystemService; import android.content.ComponentName; import android.content.Context; import android.media.AudioManager; import android.media.IMediaSession2; import android.media.IRemoteVolumeController; import android.media.ISessionTokensListener; import android.media.MediaSession2; import android.media.MediaSessionService2; import android.media.SessionToken2; Loading @@ -44,6 +45,7 @@ import android.view.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; /** * Provides support for interacting with {@link MediaSession media sessions} Loading Loading @@ -71,6 +73,8 @@ public final class MediaSessionManager { private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners = new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>(); private final ArrayMap<OnSessionTokensChangedListener, SessionTokensChangedWrapper> mSessionTokensListener = new ArrayMap<>(); private final Object mLock = new Object(); private final ISessionManager mService; Loading Loading @@ -371,13 +375,15 @@ public final class MediaSessionManager { * Get {@link List} of {@link SessionToken2} whose sessions are active now. This list represents * active sessions regardless of whether they're {@link MediaSession2} or * {@link MediaSessionService2}. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewan): Protect this with permission. // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getActiveSessionTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -392,12 +398,15 @@ public final class MediaSessionManager { /** * Get {@link List} of {@link SessionToken2} for {@link MediaSessionService2} regardless of their * activeness. This list represents media apps that support background playback. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getSessionServiceTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -412,15 +421,17 @@ public final class MediaSessionManager { /** * Get all {@link SessionToken2}s. This is the combined list of {@link #getActiveSessionTokens()} * and {@link #getSessionServiceTokens}. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @return list of Tokens * @return list of tokens * @see #getActiveSessionTokens * @see #getSessionServiceTokens * @hide */ // TODO(jaewan): Unhide // TODO(jaewan): Protect this with permission. // TODO(jaewna): Add listener for change in lists. public List<SessionToken2> getAllSessionTokens() { try { List<Bundle> bundles = mService.getSessionTokens( Loading @@ -432,6 +443,86 @@ public final class MediaSessionManager { } } /** * Add a listener to be notified when the {@link #getAllSessionTokens()} changes. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @param executor executor to run this command * @param listener The listener to add. * @hide */ // TODO(jaewan): Unhide public void addOnSessionTokensChangedListener(@NonNull @CallbackExecutor Executor executor, @NonNull OnSessionTokensChangedListener listener) { addOnSessionTokensChangedListener(UserHandle.myUserId(), executor, listener); } /** * Add a listener to be notified when the {@link #getAllSessionTokens()} changes. * <p> * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the * calling app. You may also retrieve this list if your app is an enabled notification listener * using the {@link NotificationListenerService} APIs. * * @param userId The userId to listen for changes on. * @param executor executor to run this command * @param listener The listener to add. * @hide */ public void addOnSessionTokensChangedListener(int userId, @NonNull @CallbackExecutor Executor executor, @NonNull OnSessionTokensChangedListener listener) { if (executor == null) { throw new IllegalArgumentException("executor may not be null"); } if (listener == null) { throw new IllegalArgumentException("listener may not be null"); } synchronized (mLock) { if (mSessionTokensListener.get(listener) != null) { Log.w(TAG, "Attempted to add session listener twice, ignoring."); return; } SessionTokensChangedWrapper wrapper = new SessionTokensChangedWrapper( mContext, executor, listener); try { mService.addSessionTokensListener(wrapper.mStub, userId, mContext.getPackageName()); mSessionTokensListener.put(listener, wrapper); } catch (RemoteException e) { Log.e(TAG, "Error in addSessionTokensListener.", e); } } } /** * Stop receiving session token updates on the specified listener. * * @param listener The listener to remove. * @hide */ // TODO(jaewan): Unhide public void removeOnSessionTokensChangedListener( @NonNull OnSessionTokensChangedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener may not be null"); } synchronized (mLock) { SessionTokensChangedWrapper wrapper = mSessionTokensListener.remove(listener); if (wrapper != null) { try { mService.removeSessionTokensListener(wrapper.mStub); } catch (RemoteException e) { Log.e(TAG, "Error in removeSessionTokensListener.", e); } finally { wrapper.release(); } } } } private static List<SessionToken2> toTokenList(Context context, List<Bundle> bundles) { List<SessionToken2> tokens = new ArrayList<>(); if (bundles != null) { Loading Loading @@ -566,6 +657,16 @@ public final class MediaSessionManager { public void onActiveSessionsChanged(@Nullable List<MediaController> controllers); } /** * Listens for changes to the {@link #getAllSessionTokens()}. This can be added * using {@link #addOnActiveSessionsChangedListener}. * @hide */ // TODO(jaewan): Unhide public interface OnSessionTokensChangedListener { void onSessionTokensChanged(@NonNull List<SessionToken2> tokens); } /** * Listens the volume key long-presses. * @hide Loading Loading @@ -692,6 +793,35 @@ public final class MediaSessionManager { } } private static final class SessionTokensChangedWrapper { private Context mContext; private Executor mExecutor; private OnSessionTokensChangedListener mListener; public SessionTokensChangedWrapper(Context context, Executor executor, OnSessionTokensChangedListener listener) { mContext = context; mExecutor = executor; mListener = listener; } private final ISessionTokensListener.Stub mStub = new ISessionTokensListener.Stub() { @Override public void onSessionTokensChanged(final List<Bundle> bundles) { mExecutor.execute(() -> { List<SessionToken2> tokens = toTokenList(mContext, bundles); mListener.onSessionTokensChanged(tokens); }); } }; private void release() { mListener = null; mContext = null; mExecutor = null; } } private static final class OnVolumeKeyLongPressListenerImpl extends IOnVolumeKeyLongPressListener.Stub { private OnVolumeKeyLongPressListener mListener; Loading
services/core/java/com/android/server/media/MediaSessionService.java +12 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.media.AudioSystem; import android.media.IAudioService; import android.media.IMediaSession2; import android.media.IRemoteVolumeController; import android.media.ISessionTokensListener; import android.media.MediaLibraryService2; import android.media.MediaSessionService2; import android.media.SessionToken2; Loading Loading @@ -1480,7 +1481,6 @@ public class MediaSessionService extends SystemService implements Monitor { } // TODO(jaewan): Protect this API with permission // TODO(jaewan): Add listeners for change in operations.. @Override public List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly) throws RemoteException { Loading @@ -1504,6 +1504,17 @@ public class MediaSessionService extends SystemService implements Monitor { return tokens; } @Override public void addSessionTokensListener(ISessionTokensListener listener, int userId, String packageName) { // TODO(jaewan): Implement. } @Override public void removeSessionTokensListener(ISessionTokensListener listener) { // TODO(jaewan): Implement } private int verifySessionsRequest(ComponentName componentName, int userId, final int pid, final int uid) { String packageName = null; Loading