Merge "Respect user switch BT from ringing call state." into main
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index de3975f..5fb4a3a 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -97,6 +97,7 @@
     private Map<AudioRoute, BluetoothDevice> mBluetoothRoutes;
     private Pair<Integer, String> mActiveBluetoothDevice;
     private Map<Integer, String> mActiveDeviceCache;
+    private String mBluetoothAddressForRinging;
     private Map<Integer, AudioRoute> mTypeRoutes;
     private PendingAudioRoute mPendingAudioRoute;
     private AudioRoute.Factory mAudioRouteFactory;
@@ -794,6 +795,7 @@
                     routeTo(false, mCurrentRoute);
                     // Clear pending messages
                     mPendingAudioRoute.clearPendingMessages();
+                    clearRingingBluetoothAddress();
                 }
             }
             case ACTIVE_FOCUS -> {
@@ -802,7 +804,17 @@
                 // the end tone. Otherwise, it's possible that we'll override the route a client has
                 // previously requested.
                 if (handleEndTone == 0) {
-                    routeTo(true, getBaseRoute(true, null));
+                    // Cache BT device switch in the case that inband ringing is disabled and audio
+                    // was routed to a watch. When active focus is received, this selection will be
+                    // honored provided that the current route is associated.
+                    Log.i(this, "handleSwitchFocus (ACTIVE_FOCUS): mBluetoothAddressForRinging = "
+                        + "%s, mCurrentRoute = %s", mBluetoothAddressForRinging, mCurrentRoute);
+                    AudioRoute audioRoute = mBluetoothAddressForRinging != null
+                        && mBluetoothAddressForRinging.equals(mCurrentRoute.getBluetoothAddress())
+                        ? mCurrentRoute
+                        : getBaseRoute(true, null);
+                    routeTo(true, audioRoute);
+                    clearRingingBluetoothAddress();
                 }
             }
             case RINGING_FOCUS -> {
@@ -857,6 +869,7 @@
             if (mFocusType == RINGING_FOCUS) {
                 routeTo(mBluetoothRouteManager.isInbandRingEnabled(bluetoothDevice) && mIsActive,
                         bluetoothRoute);
+                mBluetoothAddressForRinging = bluetoothDevice.getAddress();
             } else {
                 routeTo(mIsActive, bluetoothRoute);
             }
@@ -1297,6 +1310,10 @@
         mIsScoAudioConnected = value;
     }
 
+    private void clearRingingBluetoothAddress() {
+        mBluetoothAddressForRinging = null;
+    }
+
     /**
      * Update the active bluetooth device being tracked (as well as for individual profiles).
      * We need to keep track of active devices for individual profiles because of potential
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteControllerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteControllerTest.java
index b56a37b..f8cc857 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteControllerTest.java
@@ -80,6 +80,7 @@
 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
 
+import dalvik.annotation.TestTarget;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -762,6 +763,42 @@
                 any(CallAudioState.class), eq(expectedState));
     }
 
+    @SmallTest
+    @Test
+    public void testRouteFromBtSwitchInRingingSelected() {
+        when(mFeatureFlags.ignoreAutoRouteToWatchDevice()).thenReturn(true);
+        when(mBluetoothRouteManager.isWatch(any(BluetoothDevice.class))).thenReturn(true);
+        when(mBluetoothRouteManager.isInbandRingEnabled(eq(BLUETOOTH_DEVICE_1))).thenReturn(false);
+
+        mController.initialize();
+        mController.sendMessageWithSessionInfo(BT_DEVICE_ADDED, AudioRoute.TYPE_BLUETOOTH_SCO,
+            BLUETOOTH_DEVICE_1);
+        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
+            CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH
+                | CallAudioState.ROUTE_SPEAKER, null, BLUETOOTH_DEVICES);
+        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
+            any(CallAudioState.class), eq(expectedState));
+
+        mController.sendMessageWithSessionInfo(SWITCH_FOCUS, RINGING_FOCUS, 0);
+        assertFalse(mController.isActive());
+
+        // BT device should be cached. Verify routing into BT device once focus becomes active.
+        mController.sendMessageWithSessionInfo(USER_SWITCH_BLUETOOTH, 0,
+            BLUETOOTH_DEVICE_1.getAddress());
+        expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
+            CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH
+                | CallAudioState.ROUTE_SPEAKER, BLUETOOTH_DEVICE_1, BLUETOOTH_DEVICES);
+        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
+            any(CallAudioState.class), eq(expectedState));
+        mController.sendMessageWithSessionInfo(SWITCH_FOCUS, ACTIVE_FOCUS, 0);
+        mController.sendMessageWithSessionInfo(BT_AUDIO_CONNECTED, 0, BLUETOOTH_DEVICE_1);
+        expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
+            CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH
+                | CallAudioState.ROUTE_SPEAKER, BLUETOOTH_DEVICE_1, BLUETOOTH_DEVICES);
+        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
+            any(CallAudioState.class), eq(expectedState));
+    }
+
     private void verifyConnectBluetoothDevice(int audioType) {
         mController.initialize();
         mController.setActive(true);