Merge "Fix the Hearing Aids connected state in Settings App" into pi-dev

This commit is contained in:
TreeHugger Robot
2018-05-21 20:20:31 +00:00
committed by Android (Google) Code Review
4 changed files with 289 additions and 12 deletions

View File

@@ -505,5 +505,6 @@ public class BluetoothEventManager {
callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}
mDeviceManager.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}

View File

@@ -19,6 +19,7 @@ package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
@@ -323,16 +324,31 @@ public class CachedBluetoothDeviceManager {
if (cachedDevice.getHiSyncId() == hiSyncId) {
if (firstMatchedIndex != -1) {
/* Found the second one */
mCachedDevices.remove(i);
mHearingAidDevicesNotAddedInCache.add(cachedDevice);
int indexToRemoveFromUi;
CachedBluetoothDevice deviceToRemoveFromUi;
// Since the hiSyncIds have been updated for a connected pair of hearing aids,
// we remove the entry of one the hearing aids from the UI. Unless the
// hiSyncId get updated, the system does not know its a hearing aid, so we add
// hiSyncId get updated, the system does not know it is a hearing aid, so we add
// both the hearing aids as separate entries in the UI first, then remove one
// of them after the hiSyncId is populated.
log("onHiSyncIdChanged: removed device=" + cachedDevice + ", with hiSyncId="
+ hiSyncId);
mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
// of them after the hiSyncId is populated. We will choose the device that
// is not connected to be removed.
if (cachedDevice.isConnected()) {
indexToRemoveFromUi = firstMatchedIndex;
deviceToRemoveFromUi = mCachedDevices.get(firstMatchedIndex);
mCachedDevicesMapForHearingAids.put(hiSyncId, cachedDevice);
} else {
indexToRemoveFromUi = i;
deviceToRemoveFromUi = cachedDevice;
mCachedDevicesMapForHearingAids.put(hiSyncId,
mCachedDevices.get(firstMatchedIndex));
}
mCachedDevices.remove(indexToRemoveFromUi);
mHearingAidDevicesNotAddedInCache.add(deviceToRemoveFromUi);
log("onHiSyncIdChanged: removed from UI device=" + deviceToRemoveFromUi
+ ", with hiSyncId=" + hiSyncId);
mBtManager.getEventManager().dispatchDeviceRemoved(deviceToRemoveFromUi);
break;
} else {
mCachedDevicesMapForHearingAids.put(hiSyncId, cachedDevice);
@@ -342,6 +358,72 @@ public class CachedBluetoothDeviceManager {
}
}
private CachedBluetoothDevice getHearingAidOtherDevice(CachedBluetoothDevice thisDevice,
long hiSyncId) {
if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
return null;
}
// Searched the lists for the other side device with the matching hiSyncId.
for (CachedBluetoothDevice notCachedDevice : mHearingAidDevicesNotAddedInCache) {
if ((hiSyncId == notCachedDevice.getHiSyncId()) &&
(!Objects.equals(notCachedDevice, thisDevice))) {
return notCachedDevice;
}
}
CachedBluetoothDevice cachedDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
if (!Objects.equals(cachedDevice, thisDevice)) {
return cachedDevice;
}
return null;
}
private void hearingAidSwitchDisplayDevice(CachedBluetoothDevice toDisplayDevice,
CachedBluetoothDevice toHideDevice, long hiSyncId)
{
log("hearingAidSwitchDisplayDevice: toDisplayDevice=" + toDisplayDevice
+ ", toHideDevice=" + toHideDevice);
// Remove the "toHideDevice" device from the UI.
mHearingAidDevicesNotAddedInCache.add(toHideDevice);
mCachedDevices.remove(toHideDevice);
mBtManager.getEventManager().dispatchDeviceRemoved(toHideDevice);
// Add the "toDisplayDevice" device to the UI.
mHearingAidDevicesNotAddedInCache.remove(toDisplayDevice);
mCachedDevices.add(toDisplayDevice);
mCachedDevicesMapForHearingAids.put(hiSyncId, toDisplayDevice);
mBtManager.getEventManager().dispatchDeviceAdded(toDisplayDevice);
}
public synchronized void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
int state, int bluetoothProfile) {
if (bluetoothProfile == BluetoothProfile.HEARING_AID
&& cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
&& cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
long hiSyncId = cachedDevice.getHiSyncId();
CachedBluetoothDevice otherDevice = getHearingAidOtherDevice(cachedDevice, hiSyncId);
if (otherDevice == null) {
// no other side device. Nothing to do.
return;
}
if (state == BluetoothProfile.STATE_CONNECTED &&
mHearingAidDevicesNotAddedInCache.contains(cachedDevice)) {
hearingAidSwitchDisplayDevice(cachedDevice, otherDevice, hiSyncId);
} else if (state == BluetoothProfile.STATE_DISCONNECTED
&& otherDevice.isConnected()) {
CachedBluetoothDevice mapDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
if ((mapDevice != null) && (Objects.equals(cachedDevice, mapDevice))) {
hearingAidSwitchDisplayDevice(otherDevice, cachedDevice, hiSyncId);
}
}
}
}
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
final long hiSyncId = device.getHiSyncId();
@@ -353,9 +435,16 @@ public class CachedBluetoothDeviceManager {
// TODO: Look for more cleanups on unpairing the device.
mHearingAidDevicesNotAddedInCache.remove(i);
if (device == cachedDevice) continue;
log("onDeviceUnpaired: Unpair device=" + cachedDevice);
cachedDevice.unpair();
}
}
CachedBluetoothDevice mappedDevice = mCachedDevicesMapForHearingAids.get(hiSyncId);
if ((mappedDevice != null) && (!Objects.equals(device, mappedDevice))) {
log("onDeviceUnpaired: Unpair mapped device=" + mappedDevice);
mappedDevice.unpair();
}
}
public synchronized void dispatchAudioModeChanged() {

View File

@@ -98,5 +98,8 @@ public class BluetoothEventManagerTest {
verify(mBluetoothCallback).onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
verify(mCachedDeviceManager).onProfileConnectionStateChanged(mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP);
}
}

View File

@@ -235,7 +235,7 @@ public class CachedBluetoothDeviceManagerTest {
* Test to verify onHiSyncIdChanged() for hearing aid devices with same HiSyncId.
*/
@Test
public void testOnDeviceAdded_sameHiSyncId_populateInDifferentLists() {
public void testOnHiSyncIdChanged_sameHiSyncId_populateInDifferentLists() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
@@ -261,16 +261,53 @@ public class CachedBluetoothDeviceManagerTest {
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
assertThat(devices).contains(cachedDevice2);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids.values())
.contains(cachedDevice2);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids)
.containsKey(HISYNCID1);
}
/**
* Test to verify onHiSyncIdChanged() for 2 hearing aid devices with same HiSyncId but one
* device is connected and other is disconnected. The connected device should be chosen.
*/
@Test
public void testOnHiSyncIdChanged_sameHiSyncIdAndOneConnected_chooseConnectedDevice() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice2);
assertThat(cachedDevice2).isNotNull();
cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
/* Device 1 is connected and Device 2 is disconnected */
when(mHearingAidProfile.getConnectionStatus(mDevice1)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
when(mHearingAidProfile.getConnectionStatus(mDevice2)).
thenReturn(BluetoothProfile.STATE_DISCONNECTED);
// Since both devices do not have hiSyncId, they should be added in mCachedDevices.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
cachedDevice1.setHiSyncId(HISYNCID1);
cachedDevice2.setHiSyncId(HISYNCID1);
mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
// Only the connected device, device 1, should be visible to UI.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
containsExactly(HISYNCID1, cachedDevice1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).
containsExactly(cachedDevice2);
}
/**
* Test to verify onHiSyncIdChanged() for hearing aid devices with different HiSyncId.
*/
@Test
public void testOnDeviceAdded_differentHiSyncId_populateInSameList() {
public void testOnHiSyncIdChanged_differentHiSyncId_populateInSameList() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
@@ -302,6 +339,153 @@ public class CachedBluetoothDeviceManagerTest {
.contains(cachedDevice2);
}
/**
* Test to verify onProfileConnectionStateChanged() for single hearing aid device connection.
*/
@Test
public void testOnProfileConnectionStateChanged_singleDeviceConnected_visible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
// Since both devices do not have hiSyncId, they should be added in mCachedDevices.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
cachedDevice1.setHiSyncId(HISYNCID1);
mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
// Connect the Device 1
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
containsExactly(HISYNCID1, cachedDevice1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
// Disconnect the Device 1
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
containsExactly(HISYNCID1, cachedDevice1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
}
/**
* Test to verify onProfileConnectionStateChanged() for two hearing aid devices where both
* devices are disconnected and they get connected.
*/
@Test
public void testOnProfileConnectionStateChanged_twoDevicesConnected_oneDeviceVisible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice2);
assertThat(cachedDevice2).isNotNull();
cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
// Since both devices do not have hiSyncId, they should be added in mCachedDevices.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
cachedDevice1.setHiSyncId(HISYNCID1);
cachedDevice2.setHiSyncId(HISYNCID1);
mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
// There should be one cached device but can be either one.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
// Connect the Device 1
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).
containsExactly(HISYNCID1, cachedDevice1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice2);
assertThat(mCachedDeviceManager.mCachedDevices).contains(cachedDevice1);
when(mHearingAidProfile.getConnectionStatus(mDevice1)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
when(mHearingAidProfile.getConnectionStatus(mDevice2)).
thenReturn(BluetoothProfile.STATE_DISCONNECTED);
// Connect the Device 2
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice2,
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).hasSize(1);
assertThat(mCachedDeviceManager.mCachedDevices).hasSize(1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
}
/**
* Test to verify onProfileConnectionStateChanged() for two hearing aid devices where both
* devices are connected and they get disconnected.
*/
@Test
public void testOnProfileConnectionStateChanged_twoDevicesDisconnected_oneDeviceVisible() {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice1);
assertThat(cachedDevice1).isNotNull();
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mLocalAdapter,
mLocalProfileManager, mDevice2);
assertThat(cachedDevice2).isNotNull();
cachedDevice1.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
cachedDevice2.onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mHearingAidProfile.getConnectionStatus(mDevice1)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
when(mHearingAidProfile.getConnectionStatus(mDevice2)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
// Since both devices do not have hiSyncId, they should be added in mCachedDevices.
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(2);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).isEmpty();
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).isEmpty();
cachedDevice1.setHiSyncId(HISYNCID1);
cachedDevice2.setHiSyncId(HISYNCID1);
mCachedDeviceManager.onHiSyncIdChanged(HISYNCID1);
/* Disconnect the Device 1 */
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice1,
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).containsExactly(cachedDevice2);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).contains(cachedDevice1);
assertThat(mCachedDeviceManager.mCachedDevices).contains(cachedDevice2);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids)
.containsExactly(HISYNCID1, cachedDevice2);
when(mHearingAidProfile.getConnectionStatus(mDevice1)).
thenReturn(BluetoothProfile.STATE_DISCONNECTED);
when(mHearingAidProfile.getConnectionStatus(mDevice2)).
thenReturn(BluetoothProfile.STATE_CONNECTED);
/* Disconnect the Device 2 */
mCachedDeviceManager.onProfileConnectionStateChanged(cachedDevice2,
BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.HEARING_AID);
assertThat(mCachedDeviceManager.getCachedDevicesCopy()).hasSize(1);
assertThat(mCachedDeviceManager.mHearingAidDevicesNotAddedInCache).hasSize(1);
assertThat(mCachedDeviceManager.mCachedDevices).hasSize(1);
assertThat(mCachedDeviceManager.mCachedDevicesMapForHearingAids).hasSize(1);
}
/**
* Test to verify OnDeviceUnpaired() for a paired hearing Aid device pair.
*/