From 90f4c8959e6bff9825c033966d461ed0d0e3b6cb Mon Sep 17 00:00:00 2001 From: Sungsoo Lim Date: Tue, 21 Nov 2017 13:12:24 +0900 Subject: [PATCH] Correct A2DP status when audio routes changed When a Bluetooth device is connected and then a media is started, sometimes MediaRouterService gets media playback status change first and get the Bluetooth device status change later. This causes the media plays through the phone speaker instead of BT devices. This CL prevent that situation by not changing A2DP status when BT device is not connected, and by calling restoreBluetoothA2dp at the end of dispatchAudioRoutesChanged. Bug: 69499034 Test: manually tested the bug, passed Media CTS Change-Id: I7547a39e5ce58f58c249a25efa55446a3b023416 --- .../server/media/AudioPlayerStateMonitor.java | 13 +++++------ .../android/server/media/MediaRouterService.java | 27 +++++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java index d71c3b04d22e..7881a952eab9 100644 --- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java +++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java @@ -35,7 +35,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -56,9 +55,9 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { /** * 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 config The audio playback configuration for the audio player for which active + * state was changed. If {@param isRemoved} is {@code true}, this holds + * outdated information. * @param isRemoved {@code true} if the audio player is removed. */ void onAudioPlayerActiveStateChanged( @@ -70,7 +69,7 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { private final OnAudioPlayerActiveStateChangedListener mListener; - public MessageHandler(Looper looper, OnAudioPlayerActiveStateChangedListener listener) { + MessageHandler(Looper looper, OnAudioPlayerActiveStateChangedListener listener) { super(looper); mListener = listener; } @@ -85,7 +84,7 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { } } - public void sendAudioPlayerActiveStateChangedMessage( + void sendAudioPlayerActiveStateChangedMessage( final AudioPlaybackConfiguration config, final boolean isRemoved) { obtainMessage(MSG_AUDIO_PLAYER_ACTIVE_STATE_CHANGED, isRemoved ? 1 : 0, 0 /* unused */, config).sendToTarget(); @@ -97,7 +96,7 @@ class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub { private final Map mListenerMap = new ArrayMap<>(); @GuardedBy("mLock") - private final Set mActiveAudioUids = new ArraySet(); + private final Set mActiveAudioUids = new ArraySet<>(); @GuardedBy("mLock") private ArrayMap mPrevActiveAudioPlaybackConfigs = new ArrayMap<>(); diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 3e512528e410..0b089fbc6129 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -100,7 +100,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final IAudioService mAudioService; private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; private final Handler mHandler = new Handler(); - private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); + private final AudioRoutesInfo mAudioRoutesInfo = new AudioRoutesInfo(); private final IntArray mActivePlayerMinPriorityQueue = new IntArray(); private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray(); @@ -156,7 +156,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub } else { mHandler.postDelayed(mRestoreBluetoothA2dpRunnable, WAIT_MS); if (DEBUG) { - Slog.d(TAG, "onAudioPlayerACTIVEStateChanged: " + "uid=" + uid + Slog.d(TAG, "onAudioPlayerActiveStateChanged: " + "uid=" + uid + ", active=" + active + ", delaying"); } } @@ -170,7 +170,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub @Override public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { synchronized (mLock) { - if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) { + if (newRoutes.mainType != mAudioRoutesInfo.mainType) { if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET | AudioRoutesInfo.MAIN_HEADPHONES | AudioRoutesInfo.MAIN_USB)) == 0) { @@ -180,10 +180,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub // headset was plugged in. mGlobalBluetoothA2dpOn = false; } - mCurAudioRoutesInfo.mainType = newRoutes.mainType; + mAudioRoutesInfo.mainType = newRoutes.mainType; } if (!TextUtils.equals( - newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) { + newRoutes.bluetoothName, mAudioRoutesInfo.bluetoothName)) { if (newRoutes.bluetoothName == null) { // BT was disconnected. mGlobalBluetoothA2dpOn = false; @@ -191,8 +191,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub // BT was connected or changed. mGlobalBluetoothA2dpOn = true; } - mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; + mAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName; } + // Although a Bluetooth device is connected before a new audio playback is + // started, dispatchAudioRoutChanged() can be called after + // onAudioPlayerActiveStateChanged(). That causes restoreBluetoothA2dp() + // is called before mGlobalBluetoothA2dpOn is updated. + // Calling restoreBluetoothA2dp() here could prevent that. + restoreBluetoothA2dp(); } } }); @@ -409,12 +415,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub void restoreBluetoothA2dp() { try { + boolean btConnected = false; boolean a2dpOn = false; synchronized (mLock) { + btConnected = mAudioRoutesInfo.bluetoothName != null; a2dpOn = mGlobalBluetoothA2dpOn; } - Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")"); - mAudioService.setBluetoothA2dpOn(a2dpOn); + // We don't need to change a2dp status when bluetooth is not connected. + if (btConnected) { + Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")"); + mAudioService.setBluetoothA2dpOn(a2dpOn); + } } catch (RemoteException e) { Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn."); } -- 2.11.0