Merge "Switch to active BT route when changing focus" into pi-dev
diff --git a/src/com/android/server/telecom/BluetoothHeadsetProxy.java b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
index f32f454..0f492df 100644
--- a/src/com/android/server/telecom/BluetoothHeadsetProxy.java
+++ b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
@@ -56,8 +56,8 @@
         return mBluetoothHeadset.getConnectionState(device);
     }
 
-    public boolean isAudioConnected(BluetoothDevice device) {
-        return mBluetoothHeadset.isAudioConnected(device);
+    public int getAudioState(BluetoothDevice device) {
+        return mBluetoothHeadset.getAudioState(device);
     }
 
     public boolean connectAudio() {
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 0d96ccb..4274017 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -1452,7 +1452,10 @@
             BluetoothDevice connectedDevice =
                     mBluetoothRouteManager.getBluetoothAudioConnectedDevice();
             if (address == null && connectedDevice != null) {
-                // null means connect to any device, so don't bother reconnecting
+                // null means connect to any device, so don't bother reconnecting. Also, send a
+                // message to ourselves telling us that BT audio is already connected.
+                Log.i(this, "HFP audio already on. Skipping connecting.");
+                sendInternalMessage(BT_AUDIO_CONNECTED);
                 return;
             }
             if (connectedDevice == null || !Objects.equals(address, connectedDevice.getAddress())) {
@@ -1630,7 +1633,7 @@
         return UserHandle.USER_OWNER;
     }
 
-    private boolean isInActiveState() {
+    public boolean isInActiveState() {
         AudioState currentState = (AudioState) getCurrentState();
         if (currentState == null) {
             Log.w(this, "Current state is null, assuming inactive state");
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 298129a..ba56145 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
 import android.content.Context;
 import android.os.Message;
 import android.telecom.Log;
@@ -653,7 +654,8 @@
 
         for (int i = 0; i < deviceList.size(); i++) {
             BluetoothDevice device = deviceList.get(i);
-            boolean isAudioOn = bluetoothHeadset.isAudioConnected(device);
+            boolean isAudioOn = bluetoothHeadset.getAudioState(device)
+                    != BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
             Log.v(this, "isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn
                     + "for headset: " + device);
             if (isAudioOn) {
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index 30848f8..5b45828 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
 import android.content.ContentResolver;
 import android.os.Parcel;
 import android.telecom.Log;
@@ -130,7 +131,8 @@
         when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
         if (activeDevice != null) {
-            when(mHeadsetProxy.isAudioConnected(eq(activeDevice))).thenReturn(true);
+            when(mHeadsetProxy.getAudioState(eq(activeDevice)))
+                    .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
         }
         doAnswer(invocation -> {
             BluetoothDevice first = getFirstExcluding(devices,
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
index b9c1427..e7cd6ee 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
 import android.content.ContentResolver;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -306,7 +307,8 @@
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
         when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice);
         if (audioOnDevice != null) {
-            when(mHeadsetProxy.isAudioConnected(eq(audioOnDevice))).thenReturn(true);
+            when(mHeadsetProxy.getAudioState(eq(audioOnDevice)))
+                    .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
         }
         doAnswer(invocation -> {
             BluetoothDevice first = getFirstExcluding(devices,
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 6330996..9c90d3e 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -433,6 +433,46 @@
 
     @SmallTest
     @Test
+    public void testFocusChangeWithAlreadyActiveBtDevice() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+        List<BluetoothDevice> availableDevices =
+                Arrays.asList(bluetoothDevice1, bluetoothDevice2);
+
+        // Set up a state where there's an HFP connected bluetooth device already.
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
+        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
+        when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices);
+        when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice())
+                .thenReturn(bluetoothDevice1);
+
+        // We want to be in the QuiescentBluetoothRoute because there's no call yet
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH,
+                bluetoothDevice1, availableDevices);
+        stateMachine.initialize(initState);
+
+        // Switch to active, pretending that a call came in.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
+                CallAudioRouteStateMachine.ACTIVE_FOCUS);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+
+        // Make sure that we've successfully switched to the active BT route without actually
+        // calling connectAudio.
+        verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(nullable(String.class));
+        assertTrue(stateMachine.isInActiveState());
+    }
+
+    @SmallTest
+    @Test
     public void testInitializationWithEarpieceNoHeadsetNoBluetooth() {
         CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
                 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);