summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2018-05-21 20:20:31 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-05-21 20:20:31 +0000
commitaef6efeef5545834331e7aa557f0f4d339c8162e (patch)
treee4dbe509d6a791cbc8e1dbac10767aa855ef6a23
parent4b0351d53f5739394c0bc3a4c3629e5d539279c4 (diff)
parent6159842dec1f35a6f4e8b6cb1e5730bea43631e3 (diff)
Merge "Fix the Hearing Aids connected state in Settings App" into pi-dev
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java103
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java3
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java194
4 files changed, 289 insertions, 12 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4e9e566b0d87..0b58c9dd0355 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -505,5 +505,6 @@ public class BluetoothEventManager {
callback.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}
+ mDeviceManager.onProfileConnectionStateChanged(device, state, bluetoothProfile);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 15f6983a684c..e9d96ae0310f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -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() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
index 466980c38e8e..108069022567 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothEventManagerTest.java
@@ -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);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index bab3cab3795c..16ed85cf5afa 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -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();
@@ -303,6 +340,153 @@ public class CachedBluetoothDeviceManagerTest {
}
/**
+ * 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.
*/
@Test