OSDN Git Service

Correct A2DP status when audio routes changed
authorSungsoo Lim <sungsoo@google.com>
Tue, 21 Nov 2017 04:12:24 +0000 (13:12 +0900)
committerSungsoo Lim <sungsoo@google.com>
Thu, 23 Nov 2017 02:28:46 +0000 (11:28 +0900)
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

services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
services/core/java/com/android/server/media/MediaRouterService.java

index d71c3b0..7881a95 100644 (file)
@@ -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<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap =
             new ArrayMap<>();
     @GuardedBy("mLock")
-    private final Set<Integer> mActiveAudioUids = new ArraySet();
+    private final Set<Integer> mActiveAudioUids = new ArraySet<>();
     @GuardedBy("mLock")
     private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs =
             new ArrayMap<>();
index 3e51252..0b089fb 100644 (file)
@@ -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.");
         }