Use setCommunicationDevice to connect hearing aid BT devices.

Currently we can't switch audio routes when connect to a hearing aid BT
device and can't continue playing music via hearing aid BT device
automatically after a call. Use setCommunicationDevice API same as LE
audio device to solve this.
Also fix minor bug for LE audio BT device to make sure these device
won't be disabled unintentionally.

Bug: 229358080
Bug: 232360337
Test: TelecomUnitTestCases, manually test the audio route can switch
properly in a call initially routed via hearing aid BT device and can
play music properly after the call.

Change-Id: I7ff35d5eada34335fafa6f0aeaff019803541b51
Merged-In: I7ff35d5eada34335fafa6f0aeaff019803541b51
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 7c87cfa..81982c9 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -186,6 +186,7 @@
     private boolean mLeAudioCallbackRegistered = false;
     private BluetoothLeAudio mBluetoothLeAudioService;
     private boolean mLeAudioSetAsCommunicationDevice = false;
+    private boolean mHearingAidSetAsCommunicationDevice = false;
     private BluetoothDevice mBluetoothHearingAidActiveDeviceCache;
     private BluetoothAdapter mBluetoothAdapter;
     private AudioManager mAudioManager;
@@ -396,6 +397,7 @@
     public void disconnectAudio() {
         disconnectSco();
         clearLeAudioCommunicationDevice();
+        clearHearingAidCommunicationDevice();
     }
 
     public void disconnectSco() {
@@ -410,17 +412,43 @@
         return mLeAudioSetAsCommunicationDevice;
     }
 
+    public boolean isHearingAidSetAsCommunicationDevice() {
+        return mHearingAidSetAsCommunicationDevice;
+    }
+
     public void clearLeAudioCommunicationDevice() {
         if (!mLeAudioSetAsCommunicationDevice) {
             return;
         }
-        mLeAudioSetAsCommunicationDevice = false;
 
         if (mAudioManager == null) {
-            Log.i(this, " mAudioManager is null");
+            Log.i(this, "clearLeAudioCommunicationDevice: mAudioManager is null");
+            mLeAudioSetAsCommunicationDevice = false;
             return;
         }
-        mAudioManager.clearCommunicationDevice();
+        if (mAudioManager.getCommunicationDevice() != null
+                && mAudioManager.getCommunicationDevice().getType()
+                == AudioDeviceInfo.TYPE_BLE_HEADSET) {
+            mAudioManager.clearCommunicationDevice();
+            mLeAudioSetAsCommunicationDevice = false;
+        }
+    }
+
+    public void clearHearingAidCommunicationDevice() {
+        if (!mHearingAidSetAsCommunicationDevice) {
+            return;
+        }
+
+        if (mAudioManager == null) {
+            Log.i(this, "clearHearingAidCommunicationDevice: mAudioManager is null");
+            mHearingAidSetAsCommunicationDevice = false;
+        }
+        if (mAudioManager.getCommunicationDevice() != null
+                && mAudioManager.getCommunicationDevice().getType()
+                == AudioDeviceInfo.TYPE_HEARING_AID) {
+            mAudioManager.clearCommunicationDevice();
+            mHearingAidSetAsCommunicationDevice = false;
+        }
     }
 
     public boolean setLeAudioCommunicationDevice() {
@@ -456,6 +484,9 @@
             return false;
         }
 
+        // clear hearing aid communication device if set
+        clearHearingAidCommunicationDevice();
+
         // Turn BLE_OUT_HEADSET ON.
         boolean result = mAudioManager.setCommunicationDevice(bleHeadset);
         if (!result) {
@@ -467,6 +498,53 @@
         return result;
     }
 
+    public boolean setHearingAidCommunicationDevice() {
+        Log.i(this, "setHearingAidCommunicationDevice");
+
+        if (mHearingAidSetAsCommunicationDevice) {
+            Log.i(this, "mHearingAidSetAsCommunicationDevice already set");
+            return true;
+        }
+
+        if (mAudioManager == null) {
+            Log.w(this, " mAudioManager is null");
+            return false;
+        }
+
+        AudioDeviceInfo hearingAid = null;
+        List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices();
+        if (devices.size() == 0) {
+            Log.w(this, " No communication devices available.");
+            return false;
+        }
+
+        for (AudioDeviceInfo device : devices) {
+            Log.i(this, " Available device type:  " + device.getType());
+            if (device.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
+                hearingAid = device;
+                break;
+            }
+        }
+
+        if (hearingAid == null) {
+            Log.w(this, " No hearingAid device available");
+            return false;
+        }
+
+        // clear LE audio communication device if set
+        clearLeAudioCommunicationDevice();
+
+        // Turn hearing aid ON.
+        boolean result = mAudioManager.setCommunicationDevice(hearingAid);
+        if (!result) {
+            Log.w(this, " Could not set hearingAid device");
+        } else {
+            Log.i(this, " hearingAid device set");
+            mHearingAidSetAsCommunicationDevice = true;
+        }
+        return result;
+    }
+
     // Connect audio to the bluetooth device at address, checking to see whether it's
     // le audio, hearing aid or a HFP device, and using the proper BT API.
     public boolean connectAudio(String address) {
@@ -486,9 +564,12 @@
                 Log.w(this, "Attempting to turn on audio when the hearing aid service is null");
                 return false;
             }
-            return mBluetoothAdapter.setActiveDevice(
+            if (mBluetoothAdapter.setActiveDevice(
                     mHearingAidDevicesByAddress.get(address),
-                    BluetoothAdapter.ACTIVE_DEVICE_ALL);
+                    BluetoothAdapter.ACTIVE_DEVICE_ALL)) {
+                return setHearingAidCommunicationDevice();
+            }
+            return false;
         } else if (mHfpDevicesByAddress.containsKey(address)) {
             BluetoothDevice device = mHfpDevicesByAddress.get(address);
             if (mBluetoothHeadset == null) {
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 64659eb..337d383 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -381,7 +381,10 @@
                         break;
                     case CONNECT_BT:
                         if (!switchingBtDevices) {
-                            // Ignore connection to already connected device.
+                            // Ignore connection to already connected device but still notify
+                            // CallAudioRouteStateMachine since this might be a switch from other
+                            // to this already connected BT audio
+                            mListener.onBluetoothAudioConnected();
                             break;
                         }
 
@@ -621,6 +624,9 @@
             }
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) {
             mHearingAidActiveDeviceCache = device;
+            if (device == null) {
+                mDeviceManager.clearHearingAidCommunicationDevice();
+            }
         } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) {
             mHfpActiveDeviceCache = device;
         } else {
@@ -783,12 +789,14 @@
         }
 
         if (bluetoothHearingAid != null) {
-            for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+            if (mDeviceManager.isHearingAidSetAsCommunicationDevice()) {
+                for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
                         BluetoothProfile.HEARING_AID)) {
-                if (device != null) {
-                    hearingAidActiveDevice = device;
-                    activeDevices++;
-                    break;
+                    if (device != null) {
+                        hearingAidActiveDevice = device;
+                        activeDevices++;
+                        break;
+                    }
                 }
             }
         }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index 5c5ded0..1ffcc8a 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -185,9 +185,18 @@
                      * is set as communication device before we can say that BT_AUDIO_IS_ON
                      */
                     if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice()) {
-                        Log.w(LOG_TAG, "Device %s cannot be use as communication device.", device);
+                        Log.w(LOG_TAG,
+                                "Device %s cannot be use as LE audio communication device.",
+                                device);
                         return;
                     }
+                } else {
+                    /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID */
+                    if (!mBluetoothDeviceManager.setHearingAidCommunicationDevice()) {
+                        Log.w(LOG_TAG,
+                                "Device %s cannot be use as hearing aid communication device.",
+                                device);
+                    }
                 }
                 mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args);
            }
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index 764885b..2680702 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -391,44 +391,23 @@
     @SmallTest
     @Test
     public void testConnectDisconnectAudioHearingAid() {
-        receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
-                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
-        when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
-                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
-        mBluetoothDeviceManager.connectAudio(device2.getAddress());
-        verify(mAdapter).setActiveDevice(device2, BluetoothAdapter.ACTIVE_DEVICE_ALL);
-        verify(mBluetoothHeadset, never()).connectAudio();
-        verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
-                eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
-
-        when(mAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
-                .thenReturn(Arrays.asList(device2, null));
-
-        mBluetoothDeviceManager.disconnectAudio();
-        verify(mBluetoothHeadset).disconnectAudio();
-    }
-
-    @SmallTest
-    @Test
-    public void testConnectDisconnectAudioLeAudio() {
         receiverUnderTest.setIsInCall(true);
         receiverUnderTest.onReceive(mContext,
                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
-                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
 
         AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
-        when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);
+        when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_HEARING_AID);
         List<AudioDeviceInfo> devices = new ArrayList<>();
         devices.add(mockAudioDeviceInfo);
 
         when(mockAudioManager.getAvailableCommunicationDevices())
-                        .thenReturn(devices);
-        when(mockAudioManager.setCommunicationDevice(mockAudioDeviceInfo))
-                       .thenReturn(true);
+                .thenReturn(devices);
+        when(mockAudioManager.setCommunicationDevice(eq(mockAudioDeviceInfo)))
+                .thenReturn(true);
 
         mBluetoothDeviceManager.connectAudio(device5.getAddress());
         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
@@ -436,6 +415,7 @@
         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
 
+        when(mockAudioManager.getCommunicationDevice()).thenReturn(mockAudioDeviceInfo);
         mBluetoothDeviceManager.disconnectAudio();
         verify(mockAudioManager).clearCommunicationDevice();
     }
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index d1d48ce..e01cbbe 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -123,7 +123,7 @@
         verifyConnectionAttempt(DEVICE1, 0);
         verifyConnectionAttempt(DEVICE2, 0);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + HEARING_AID_DEVICE.getAddress(),
+                        + ":" + DEVICE1.getAddress(),
                 sm.getCurrentState().getName());
         sm.quitNow();
     }