Loading services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +65 −93 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package com.android.server.media; import android.annotation.Nullable; import android.annotation.NonNull; import android.content.Context; import android.media.AudioPlaybackConfiguration; import android.media.IAudioService; Loading @@ -27,14 +27,15 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.HashSet; import java.util.HashMap; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; Loading @@ -49,47 +50,57 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor(); /** * Called when the state of audio player is changed. * Listener for handling the active state changes of audio players. */ interface OnAudioPlayerStateChangedListener { void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config); interface OnAudioPlayerActiveStateChangedListener { /** * Called when the active state of audio player is changed. * * @param config The audio playback configuration for the audio player of which active state * was changed. If {@param isRemoved} is {@code true}, this hold outdated * information. * @param isRemoved {@code true} if the audio player is removed. */ void onAudioPlayerActiveStateChanged( @NonNull AudioPlaybackConfiguration config, boolean isRemoved); } private final static class MessageHandler extends Handler { private static final int MSG_AUDIO_PLAYER_STATE_CHANGED = 1; private static final int MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED = 1; private final OnAudioPlayerStateChangedListener mListsner; private final OnAudioPlayerActiveStateChangedListener mListener; public MessageHandler(Looper looper, OnAudioPlayerStateChangedListener listener) { public MessageHandler(Looper looper, OnAudioPlayerActiveStateChangedListener listener) { super(looper); mListsner = listener; mListener = listener; } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_AUDIO_PLAYER_STATE_CHANGED: mListsner.onAudioPlayerStateChanged( msg.arg1, msg.arg2, (AudioPlaybackConfiguration) msg.obj); case MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED: mListener.onAudioPlayerActiveStateChanged((AudioPlaybackConfiguration) msg.obj, msg.arg1 != 0); break; } } public void sendAudioPlayerStateChangedMessage(int uid, int prevState, AudioPlaybackConfiguration config) { obtainMessage(MSG_AUDIO_PLAYER_STATE_CHANGED, uid, prevState, config).sendToTarget(); public void sendAudioPlayerActiveStateChangedMessage( final AudioPlaybackConfiguration config, final boolean isRemoved) { obtainMessage(MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED, isRemoved ? 1 : 0, 0 /* unused */, config).sendToTarget(); } } private final Object mLock = new Object(); @GuardedBy("mLock") private final Map<OnAudioPlayerStateChangedListener, MessageHandler> mListenerMap = new HashMap<>(); private final Map<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap = new ArrayMap<>(); @GuardedBy("mLock") private final Map<Integer, Integer> mAudioPlayerStates = new HashMap<>(); private final Set<Integer> mActiveAudioUids = new ArraySet(); @GuardedBy("mLock") private final Map<Integer, HashSet<Integer>> mAudioPlayersForUid = new HashMap<>(); private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs = new ArrayMap<>(); // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video) // The UID whose audio playback becomes active at the last comes first. // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID. Loading Loading @@ -122,32 +133,24 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } final long token = Binder.clearCallingIdentity(); try { final Map<Integer, Integer> prevAudioPlayerStates = new HashMap<>(mAudioPlayerStates); final Map<Integer, HashSet<Integer>> prevAudioPlayersForUid = new HashMap<>(mAudioPlayersForUid); synchronized (mLock) { mAudioPlayerStates.clear(); mAudioPlayersForUid.clear(); // Update mActiveAudioUids mActiveAudioUids.clear(); ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs = new ArrayMap<>(); for (AudioPlaybackConfiguration config : configs) { int pii = config.getPlayerInterfaceId(); int uid = config.getClientUid(); mAudioPlayerStates.put(pii, config.getPlayerState()); HashSet<Integer> players = mAudioPlayersForUid.get(uid); if (players == null) { players = new HashSet<Integer>(); players.add(pii); mAudioPlayersForUid.put(uid, players); } else { players.add(pii); } if (config.isActive()) { mActiveAudioUids.add(config.getClientUid()); activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config); } for (AudioPlaybackConfiguration config : configs) { if (!config.isActive()) { continue; } int uid = config.getClientUid(); if (!isActiveState(prevAudioPlayerStates.get(config.getPlayerInterfaceId()))) { // Update mSortedAuioPlaybackClientUids. for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) { AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i); final int uid = config.getClientUid(); if (!mPrevActiveAudioPlaybackConfigs.containsKey( config.getPlayerInterfaceId())) { if (DEBUG) { Log.d(TAG, "Found a new active media playback. " + AudioPlaybackConfiguration.toLogFriendlyString(config)); Loading @@ -163,40 +166,21 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { mSortedAudioPlaybackClientUids.add(0, uid); } } // Notify the change of audio player states. // Notify the active state change of audio players. for (AudioPlaybackConfiguration config : configs) { final Integer prevState = prevAudioPlayerStates.get(config.getPlayerInterfaceId()); final int prevStateInt = (prevState == null) ? AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN : prevState.intValue(); if (prevStateInt != config.getPlayerState()) { sendAudioPlayerStateChangedMessageLocked( config.getClientUid(), prevStateInt, config); } } for (Integer prevUid : prevAudioPlayersForUid.keySet()) { // If all players for prevUid is removed, notify the prev state was // PLAYER_STATE_STARTED only when there were a player whose state was // PLAYER_STATE_STARTED, otherwise any inactive state is okay to notify. if (!mAudioPlayersForUid.containsKey(prevUid)) { Set<Integer> prevPlayers = prevAudioPlayersForUid.get(prevUid); int prevState = AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN; for (int pii : prevPlayers) { Integer state = prevAudioPlayerStates.get(pii); if (state == null) { continue; } if (state == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { prevState = state; break; } else if (prevState == AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN) { prevState = state; } final int pii = config.getPlayerInterfaceId(); boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null; if (wasActive != config.isActive()) { sendAudioPlayerActiveStateChangedMessageLocked( config, /* isRemoved */ false); } sendAudioPlayerStateChangedMessageLocked(prevUid, prevState, null); } for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) { sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true); } // Update mPrevActiveAudioPlaybackConfigs mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs; } } finally { Binder.restoreCallingIdentity(token); Loading @@ -204,9 +188,10 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } /** * Registers OnAudioPlayerStateChangedListener. * Registers OnAudioPlayerActiveStateChangedListener. */ public void registerListener(OnAudioPlayerStateChangedListener listener, Handler handler) { public void registerListener( OnAudioPlayerActiveStateChangedListener listener, Handler handler) { synchronized (mLock) { mListenerMap.put(listener, new MessageHandler((handler == null) ? Looper.myLooper() : handler.getLooper(), listener)); Loading @@ -214,9 +199,9 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } /** * Unregisters OnAudioPlayerStateChangedListener. * Unregisters OnAudioPlayerActiveStateChangedListener. */ public void unregisterListener(OnAudioPlayerStateChangedListener listener) { public void unregisterListener(OnAudioPlayerActiveStateChangedListener listener) { synchronized (mLock) { mListenerMap.remove(listener); } Loading @@ -239,16 +224,7 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { */ public boolean isPlaybackActive(int uid) { synchronized (mLock) { Set<Integer> players = mAudioPlayersForUid.get(uid); if (players == null) { return false; } for (Integer pii : players) { if (isActiveState(mAudioPlayerStates.get(pii))) { return true; } } return false; return mActiveAudioUids.contains(uid); } } Loading Loading @@ -314,14 +290,10 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } } private void sendAudioPlayerStateChangedMessageLocked( final int uid, final int prevState, final AudioPlaybackConfiguration config) { private void sendAudioPlayerActiveStateChangedMessageLocked( final AudioPlaybackConfiguration config, final boolean isRemoved) { for (MessageHandler messageHandler : mListenerMap.values()) { messageHandler.sendAudioPlayerStateChangedMessage(uid, prevState, config); messageHandler.sendAudioPlayerActiveStateChangedMessage(config, isRemoved); } } private static boolean isActiveState(Integer state) { return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED); } } services/core/java/com/android/server/media/MediaRouterService.java +26 −22 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package com.android.server.media; import com.android.internal.util.DumpUtils; import com.android.server.Watchdog; import android.annotation.Nullable; import android.annotation.NonNull; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -101,6 +101,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; private final Handler mHandler = new Handler(); private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); private final IntArray mActivePlayerMinPriorityQueue = new IntArray(); private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray(); public MediaRouterService(Context context) { mContext = context; Loading @@ -111,7 +113,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() { new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() { static final long WAIT_MS = 500; final Runnable mRestoreBluetoothA2dpRunnable = new Runnable() { @Override Loading @@ -121,39 +123,41 @@ public final class MediaRouterService extends IMediaRouterService.Stub }; @Override public void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config) { public void onAudioPlayerActiveStateChanged( @NonNull AudioPlaybackConfiguration config, boolean isRemoved) { final boolean active = !isRemoved && config.isActive(); final int pii = config.getPlayerInterfaceId(); final int uid = config.getClientUid(); final int idx = mActivePlayerMinPriorityQueue.indexOf(pii); // Keep the latest active player and its uid at the end of the queue. if (idx >= 0) { mActivePlayerMinPriorityQueue.remove(idx); mActivePlayerUidMinPriorityQueue.remove(idx); } int restoreUid = -1; boolean active = config == null ? false : config.isActive(); if (active) { mActivePlayerMinPriorityQueue.add(config.getPlayerInterfaceId()); mActivePlayerUidMinPriorityQueue.add(uid); restoreUid = uid; } else if (prevState != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { // Noting to do if the prev state is not an active state. return; } else { IntArray sortedAudioPlaybackClientUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); for (int i = 0; i < sortedAudioPlaybackClientUids.size(); ++i) { if (mAudioPlayerStateMonitor.isPlaybackActive( sortedAudioPlaybackClientUids.get(i))) { restoreUid = sortedAudioPlaybackClientUids.get(i); break; } } } else if (mActivePlayerUidMinPriorityQueue.size() > 0) { restoreUid = mActivePlayerUidMinPriorityQueue.get( mActivePlayerUidMinPriorityQueue.size() - 1); } mHandler.removeCallbacks(mRestoreBluetoothA2dpRunnable); if (restoreUid >= 0) { restoreRoute(restoreUid); if (DEBUG) { Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid + " active " + active + " restoring " + restoreUid); Slog.d(TAG, "onAudioPlayerActiveStateChanged: " + "uid=" + uid + ", active=" + active + ", restoreUid=" + restoreUid); } } else { mHandler.postDelayed(mRestoreBluetoothA2dpRunnable, WAIT_MS); if (DEBUG) { Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid + " active " + active + " delaying"); Slog.d(TAG, "onAudioPlayerACTIVEStateChanged: " + "uid=" + uid + ", active=" + active + ", delaying"); } } } Loading services/core/java/com/android/server/media/MediaSessionService.java +12 −17 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.media; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.INotificationManager; import android.app.KeyguardManager; Loading Loading @@ -138,22 +137,18 @@ public class MediaSessionService extends SystemService implements Monitor { mAudioService = getAudioService(); mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() { @Override public void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config) { if (config == null || !config.isActive() || config.getPlayerType() (config, isRemoved) -> { if (isRemoved || !config.isActive() || config.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) { return; } synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(UserHandle.getUserId(uid)); FullUserRecord user = getFullUserRecordLocked( UserHandle.getUserId(config.getClientUid())); if (user != null) { user.mPriorityStack.updateMediaButtonSessionIfNeeded(); } } } }, null /* handler */); mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService); mContentResolver = getContext().getContentResolver(); Loading Loading
services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +65 −93 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ package com.android.server.media; import android.annotation.Nullable; import android.annotation.NonNull; import android.content.Context; import android.media.AudioPlaybackConfiguration; import android.media.IAudioService; Loading @@ -27,14 +27,15 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IntArray; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.HashSet; import java.util.HashMap; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; Loading @@ -49,47 +50,57 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor(); /** * Called when the state of audio player is changed. * Listener for handling the active state changes of audio players. */ interface OnAudioPlayerStateChangedListener { void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config); interface OnAudioPlayerActiveStateChangedListener { /** * Called when the active state of audio player is changed. * * @param config The audio playback configuration for the audio player of which active state * was changed. If {@param isRemoved} is {@code true}, this hold outdated * information. * @param isRemoved {@code true} if the audio player is removed. */ void onAudioPlayerActiveStateChanged( @NonNull AudioPlaybackConfiguration config, boolean isRemoved); } private final static class MessageHandler extends Handler { private static final int MSG_AUDIO_PLAYER_STATE_CHANGED = 1; private static final int MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED = 1; private final OnAudioPlayerStateChangedListener mListsner; private final OnAudioPlayerActiveStateChangedListener mListener; public MessageHandler(Looper looper, OnAudioPlayerStateChangedListener listener) { public MessageHandler(Looper looper, OnAudioPlayerActiveStateChangedListener listener) { super(looper); mListsner = listener; mListener = listener; } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_AUDIO_PLAYER_STATE_CHANGED: mListsner.onAudioPlayerStateChanged( msg.arg1, msg.arg2, (AudioPlaybackConfiguration) msg.obj); case MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED: mListener.onAudioPlayerActiveStateChanged((AudioPlaybackConfiguration) msg.obj, msg.arg1 != 0); break; } } public void sendAudioPlayerStateChangedMessage(int uid, int prevState, AudioPlaybackConfiguration config) { obtainMessage(MSG_AUDIO_PLAYER_STATE_CHANGED, uid, prevState, config).sendToTarget(); public void sendAudioPlayerActiveStateChangedMessage( final AudioPlaybackConfiguration config, final boolean isRemoved) { obtainMessage(MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED, isRemoved ? 1 : 0, 0 /* unused */, config).sendToTarget(); } } private final Object mLock = new Object(); @GuardedBy("mLock") private final Map<OnAudioPlayerStateChangedListener, MessageHandler> mListenerMap = new HashMap<>(); private final Map<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap = new ArrayMap<>(); @GuardedBy("mLock") private final Map<Integer, Integer> mAudioPlayerStates = new HashMap<>(); private final Set<Integer> mActiveAudioUids = new ArraySet(); @GuardedBy("mLock") private final Map<Integer, HashSet<Integer>> mAudioPlayersForUid = new HashMap<>(); private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs = new ArrayMap<>(); // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video) // The UID whose audio playback becomes active at the last comes first. // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID. Loading Loading @@ -122,32 +133,24 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } final long token = Binder.clearCallingIdentity(); try { final Map<Integer, Integer> prevAudioPlayerStates = new HashMap<>(mAudioPlayerStates); final Map<Integer, HashSet<Integer>> prevAudioPlayersForUid = new HashMap<>(mAudioPlayersForUid); synchronized (mLock) { mAudioPlayerStates.clear(); mAudioPlayersForUid.clear(); // Update mActiveAudioUids mActiveAudioUids.clear(); ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs = new ArrayMap<>(); for (AudioPlaybackConfiguration config : configs) { int pii = config.getPlayerInterfaceId(); int uid = config.getClientUid(); mAudioPlayerStates.put(pii, config.getPlayerState()); HashSet<Integer> players = mAudioPlayersForUid.get(uid); if (players == null) { players = new HashSet<Integer>(); players.add(pii); mAudioPlayersForUid.put(uid, players); } else { players.add(pii); } if (config.isActive()) { mActiveAudioUids.add(config.getClientUid()); activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config); } for (AudioPlaybackConfiguration config : configs) { if (!config.isActive()) { continue; } int uid = config.getClientUid(); if (!isActiveState(prevAudioPlayerStates.get(config.getPlayerInterfaceId()))) { // Update mSortedAuioPlaybackClientUids. for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) { AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i); final int uid = config.getClientUid(); if (!mPrevActiveAudioPlaybackConfigs.containsKey( config.getPlayerInterfaceId())) { if (DEBUG) { Log.d(TAG, "Found a new active media playback. " + AudioPlaybackConfiguration.toLogFriendlyString(config)); Loading @@ -163,40 +166,21 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { mSortedAudioPlaybackClientUids.add(0, uid); } } // Notify the change of audio player states. // Notify the active state change of audio players. for (AudioPlaybackConfiguration config : configs) { final Integer prevState = prevAudioPlayerStates.get(config.getPlayerInterfaceId()); final int prevStateInt = (prevState == null) ? AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN : prevState.intValue(); if (prevStateInt != config.getPlayerState()) { sendAudioPlayerStateChangedMessageLocked( config.getClientUid(), prevStateInt, config); } } for (Integer prevUid : prevAudioPlayersForUid.keySet()) { // If all players for prevUid is removed, notify the prev state was // PLAYER_STATE_STARTED only when there were a player whose state was // PLAYER_STATE_STARTED, otherwise any inactive state is okay to notify. if (!mAudioPlayersForUid.containsKey(prevUid)) { Set<Integer> prevPlayers = prevAudioPlayersForUid.get(prevUid); int prevState = AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN; for (int pii : prevPlayers) { Integer state = prevAudioPlayerStates.get(pii); if (state == null) { continue; } if (state == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { prevState = state; break; } else if (prevState == AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN) { prevState = state; } final int pii = config.getPlayerInterfaceId(); boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null; if (wasActive != config.isActive()) { sendAudioPlayerActiveStateChangedMessageLocked( config, /* isRemoved */ false); } sendAudioPlayerStateChangedMessageLocked(prevUid, prevState, null); } for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) { sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true); } // Update mPrevActiveAudioPlaybackConfigs mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs; } } finally { Binder.restoreCallingIdentity(token); Loading @@ -204,9 +188,10 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } /** * Registers OnAudioPlayerStateChangedListener. * Registers OnAudioPlayerActiveStateChangedListener. */ public void registerListener(OnAudioPlayerStateChangedListener listener, Handler handler) { public void registerListener( OnAudioPlayerActiveStateChangedListener listener, Handler handler) { synchronized (mLock) { mListenerMap.put(listener, new MessageHandler((handler == null) ? Looper.myLooper() : handler.getLooper(), listener)); Loading @@ -214,9 +199,9 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } /** * Unregisters OnAudioPlayerStateChangedListener. * Unregisters OnAudioPlayerActiveStateChangedListener. */ public void unregisterListener(OnAudioPlayerStateChangedListener listener) { public void unregisterListener(OnAudioPlayerActiveStateChangedListener listener) { synchronized (mLock) { mListenerMap.remove(listener); } Loading @@ -239,16 +224,7 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { */ public boolean isPlaybackActive(int uid) { synchronized (mLock) { Set<Integer> players = mAudioPlayersForUid.get(uid); if (players == null) { return false; } for (Integer pii : players) { if (isActiveState(mAudioPlayerStates.get(pii))) { return true; } } return false; return mActiveAudioUids.contains(uid); } } Loading Loading @@ -314,14 +290,10 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } } private void sendAudioPlayerStateChangedMessageLocked( final int uid, final int prevState, final AudioPlaybackConfiguration config) { private void sendAudioPlayerActiveStateChangedMessageLocked( final AudioPlaybackConfiguration config, final boolean isRemoved) { for (MessageHandler messageHandler : mListenerMap.values()) { messageHandler.sendAudioPlayerStateChangedMessage(uid, prevState, config); messageHandler.sendAudioPlayerActiveStateChangedMessage(config, isRemoved); } } private static boolean isActiveState(Integer state) { return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED); } }
services/core/java/com/android/server/media/MediaRouterService.java +26 −22 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ package com.android.server.media; import com.android.internal.util.DumpUtils; import com.android.server.Watchdog; import android.annotation.Nullable; import android.annotation.NonNull; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; Loading Loading @@ -101,6 +101,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; private final Handler mHandler = new Handler(); private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); private final IntArray mActivePlayerMinPriorityQueue = new IntArray(); private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray(); public MediaRouterService(Context context) { mContext = context; Loading @@ -111,7 +113,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() { new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() { static final long WAIT_MS = 500; final Runnable mRestoreBluetoothA2dpRunnable = new Runnable() { @Override Loading @@ -121,39 +123,41 @@ public final class MediaRouterService extends IMediaRouterService.Stub }; @Override public void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config) { public void onAudioPlayerActiveStateChanged( @NonNull AudioPlaybackConfiguration config, boolean isRemoved) { final boolean active = !isRemoved && config.isActive(); final int pii = config.getPlayerInterfaceId(); final int uid = config.getClientUid(); final int idx = mActivePlayerMinPriorityQueue.indexOf(pii); // Keep the latest active player and its uid at the end of the queue. if (idx >= 0) { mActivePlayerMinPriorityQueue.remove(idx); mActivePlayerUidMinPriorityQueue.remove(idx); } int restoreUid = -1; boolean active = config == null ? false : config.isActive(); if (active) { mActivePlayerMinPriorityQueue.add(config.getPlayerInterfaceId()); mActivePlayerUidMinPriorityQueue.add(uid); restoreUid = uid; } else if (prevState != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { // Noting to do if the prev state is not an active state. return; } else { IntArray sortedAudioPlaybackClientUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); for (int i = 0; i < sortedAudioPlaybackClientUids.size(); ++i) { if (mAudioPlayerStateMonitor.isPlaybackActive( sortedAudioPlaybackClientUids.get(i))) { restoreUid = sortedAudioPlaybackClientUids.get(i); break; } } } else if (mActivePlayerUidMinPriorityQueue.size() > 0) { restoreUid = mActivePlayerUidMinPriorityQueue.get( mActivePlayerUidMinPriorityQueue.size() - 1); } mHandler.removeCallbacks(mRestoreBluetoothA2dpRunnable); if (restoreUid >= 0) { restoreRoute(restoreUid); if (DEBUG) { Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid + " active " + active + " restoring " + restoreUid); Slog.d(TAG, "onAudioPlayerActiveStateChanged: " + "uid=" + uid + ", active=" + active + ", restoreUid=" + restoreUid); } } else { mHandler.postDelayed(mRestoreBluetoothA2dpRunnable, WAIT_MS); if (DEBUG) { Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid + " active " + active + " delaying"); Slog.d(TAG, "onAudioPlayerACTIVEStateChanged: " + "uid=" + uid + ", active=" + active + ", delaying"); } } } Loading
services/core/java/com/android/server/media/MediaSessionService.java +12 −17 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.media; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.INotificationManager; import android.app.KeyguardManager; Loading Loading @@ -138,22 +137,18 @@ public class MediaSessionService extends SystemService implements Monitor { mAudioService = getAudioService(); mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(); mAudioPlayerStateMonitor.registerListener( new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() { @Override public void onAudioPlayerStateChanged( int uid, int prevState, @Nullable AudioPlaybackConfiguration config) { if (config == null || !config.isActive() || config.getPlayerType() (config, isRemoved) -> { if (isRemoved || !config.isActive() || config.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) { return; } synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(UserHandle.getUserId(uid)); FullUserRecord user = getFullUserRecordLocked( UserHandle.getUserId(config.getClientUid())); if (user != null) { user.mPriorityStack.updateMediaButtonSessionIfNeeded(); } } } }, null /* handler */); mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService); mContentResolver = getContext().getContentResolver(); Loading