diff options
| author | 2018-05-21 20:20:31 +0000 | |
|---|---|---|
| committer | 2018-05-21 20:20:31 +0000 | |
| commit | aef6efeef5545834331e7aa557f0f4d339c8162e (patch) | |
| tree | e4dbe509d6a791cbc8e1dbac10767aa855ef6a23 | |
| parent | 4b0351d53f5739394c0bc3a4c3629e5d539279c4 (diff) | |
| parent | 6159842dec1f35a6f4e8b6cb1e5730bea43631e3 (diff) | |
Merge "Fix the Hearing Aids connected state in Settings App" into pi-dev
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 |