Merge "Resolve multiple BT device switching and active device updates" into main
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 839b89f..7422286 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -766,6 +766,7 @@
         if (bluetoothRoute != null) {
             Log.i(this, "request to route to bluetooth route: %s (active=%b)", bluetoothRoute,
                     mIsActive);
+            updateActiveBluetoothDevice(new Pair<>(type, deviceAddress));
             routeTo(mIsActive, bluetoothRoute);
         } else {
             Log.i(this, "request to route to unavailable bluetooth route - type (%s), address (%s)",
@@ -784,10 +785,34 @@
      * Message being handled: BT_ACTIVE_DEVICE_GONE
      */
     private void handleBtActiveDeviceGone(@AudioRoute.AudioRouteType int type) {
-        if ((mIsPending && mPendingAudioRoute.getDestRoute().getType() == type)
-                || (!mIsPending && mCurrentRoute.getType() == type)) {
-            // Fallback to an available route
-            routeTo(mIsActive, getBaseRoute(true, null));
+        // Determine what the active device for the BT audio type was so that we can exclude this
+        // device from being used when calculating the base route.
+        String previouslyActiveDeviceAddress = mFeatureFlags
+                .resolveActiveBtRoutingAndBtTimingIssue()
+                ? mActiveDeviceCache.get(type)
+                : null;
+        // It's possible that the dest route hasn't been set yet when the controller is first
+        // initialized.
+        boolean pendingRouteNeedsUpdate = mPendingAudioRoute.getDestRoute() != null
+                && mPendingAudioRoute.getDestRoute().getType() == type;
+        boolean currentRouteNeedsUpdate = mCurrentRoute.getType() == type;
+        if (mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+            if (pendingRouteNeedsUpdate) {
+                pendingRouteNeedsUpdate &= mPendingAudioRoute.getDestRoute().getBluetoothAddress()
+                        .equals(previouslyActiveDeviceAddress);
+            }
+            if (currentRouteNeedsUpdate) {
+                currentRouteNeedsUpdate &= mCurrentRoute.getBluetoothAddress()
+                        .equals(previouslyActiveDeviceAddress);
+            }
+        }
+        if ((mIsPending && pendingRouteNeedsUpdate) || (!mIsPending && currentRouteNeedsUpdate)) {
+            // Fallback to an available route excluding the previously active device.
+            routeTo(mIsActive, getBaseRoute(true, previouslyActiveDeviceAddress));
+        }
+        // Clear out the active device for the BT audio type.
+        if (mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+            updateActiveBluetoothDevice(new Pair(type, null));
         }
     }
 
@@ -1490,9 +1515,16 @@
             // If a device was removed, check to ensure that no other device is still considered
             // active.
             boolean hasActiveDevice = false;
-            for (String address : mActiveDeviceCache.values()) {
+            List<Map.Entry<Integer, String>> activeBtDevices = new ArrayList<>(
+                    mActiveDeviceCache.entrySet());
+            for (Map.Entry<Integer,String> activeDevice : activeBtDevices) {
+                Integer btAudioType = activeDevice.getKey();
+                String address = activeDevice.getValue();
                 if (address != null) {
                     hasActiveDevice = true;
+                    if (mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+                        mActiveBluetoothDevice = new Pair<>(btAudioType, address);
+                    }
                     break;
                 }
             }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index cd52889..bb1a745 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -252,12 +252,17 @@
             CallAudioRouteController audioRouteController = (CallAudioRouteController)
                     mCallAudioRouteAdapter;
             if (device == null) {
-                audioRouteController.updateActiveBluetoothDevice(new Pair(audioRouteType, null));
+                if (!mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+                    audioRouteController.updateActiveBluetoothDevice(
+                            new Pair(audioRouteType, null));
+                }
                 mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_ACTIVE_DEVICE_GONE,
                         audioRouteType);
             } else {
-                audioRouteController.updateActiveBluetoothDevice(
-                        new Pair(audioRouteType, device.getAddress()));
+                if (!mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+                    audioRouteController.updateActiveBluetoothDevice(
+                            new Pair(audioRouteType, device.getAddress()));
+                }
                 mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_ACTIVE_DEVICE_PRESENT,
                         audioRouteType, device.getAddress());
                 if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID
@@ -267,9 +272,11 @@
                         Log.i(this, "handleActiveDeviceChanged: Failed to set "
                                 + "communication device for %s. Sending PENDING_ROUTE_FAILED to "
                                 + "pending audio route.", device);
-                        mCallAudioRouteAdapter.getPendingAudioRoute()
-                                .onMessageReceived(new Pair<>(PENDING_ROUTE_FAILED,
-                                        device.getAddress()), device.getAddress());
+                        if (!mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
+                            mCallAudioRouteAdapter.getPendingAudioRoute()
+                                    .onMessageReceived(new Pair<>(PENDING_ROUTE_FAILED,
+                                            device.getAddress()), device.getAddress());
+                        }
                     } else {
                         // Track the currently set communication device.
                         int routeType = deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO