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();
}