diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index a6028665b4e01..3debd9a179da6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -230,9 +230,10 @@ public class CachedBluetoothDeviceManager { private void clearNonBondedSubDevices() { for (int i = mCachedDevices.size() - 1; i >= 0; i--) { CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); - final Set memberDevices = cachedDevice.getMemberDevice(); + Set memberDevices = cachedDevice.getMemberDevice(); if (!memberDevices.isEmpty()) { - for (CachedBluetoothDevice memberDevice : memberDevices) { + for (Object it : memberDevices.toArray()) { + CachedBluetoothDevice memberDevice = (CachedBluetoothDevice) it; // Member device exists and it is not bonded if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) { cachedDevice.removeMemberDevice(memberDevice); 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 2c4f57fa77be3..d53a3e896868e 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 @@ -26,7 +26,9 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothUuid; import android.content.Context; +import android.os.ParcelUuid; import org.junit.Before; import org.junit.Test; @@ -37,6 +39,8 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; @RunWith(RobolectricTestRunner.class) public class CachedBluetoothDeviceManagerTest { @@ -51,6 +55,10 @@ public class CachedBluetoothDeviceManagerTest { private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33"; private final static long HISYNCID1 = 10; private final static long HISYNCID2 = 11; + private final static Map CAP_GROUP1 = + Map.of(1, BluetoothUuid.CAP); + private final static Map CAP_GROUP2 = + Map.of(2, BluetoothUuid.CAP); private final BluetoothClass DEVICE_CLASS_1 = new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); private final BluetoothClass DEVICE_CLASS_2 = @@ -70,6 +78,8 @@ public class CachedBluetoothDeviceManagerTest { @Mock private HearingAidProfile mHearingAidProfile; @Mock + private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile; + @Mock private BluetoothDevice mDevice1; @Mock private BluetoothDevice mDevice2; @@ -105,8 +115,12 @@ public class CachedBluetoothDeviceManagerTest { when(mA2dpProfile.isProfileReady()).thenReturn(true); when(mPanProfile.isProfileReady()).thenReturn(true); when(mHearingAidProfile.isProfileReady()).thenReturn(true); + when(mCsipSetCoordinatorProfile.isProfileReady()) + .thenReturn(true); doAnswer((invocation) -> mHearingAidProfile). when(mLocalProfileManager).getHearingAidProfile(); + doAnswer((invocation) -> mCsipSetCoordinatorProfile) + .when(mLocalProfileManager).getCsipSetCoordinatorProfile(); mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager); mCachedDevice1 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1)); mCachedDevice2 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2)); @@ -298,7 +312,7 @@ public class CachedBluetoothDeviceManagerTest { * Test to verify OnDeviceUnpaired() for main hearing Aid device unpair. */ @Test - public void onDeviceUnpaired_unpairMainDevice() { + public void onDeviceUnpaired_unpairHearingAidMainDevice() { when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); @@ -398,4 +412,153 @@ public class CachedBluetoothDeviceManagerTest { when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); assertThat(mCachedDeviceManager.onDeviceDisappeared(cachedDevice1)).isTrue(); } + + /** + * Test to verify getMemberDevice(), new device has the same group id. + */ + @Test + public void addDevice_sameGroupId_validMemberDevice() { + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice1); + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice2); + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice3); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); + + assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2); + assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3); + } + + /** + * Test to verify getMemberDevice(), new device has the different group id. + */ + @Test + public void addDevice_differentGroupId_validMemberDevice() { + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice1); + doAnswer((invocation) -> CAP_GROUP2).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice2); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + + assertThat(cachedDevice1.getMemberDevice()).isEmpty(); + } + + /** + * Test to verify addDevice(), new device has the same group id. + */ + @Test + public void addDevice_sameGroupId_validCachedDevices_mainDevicesAdded_memberDevicesNotAdded() { + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice1); + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice2); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + + Collection devices = mCachedDeviceManager.getCachedDevicesCopy(); + assertThat(devices).contains(cachedDevice1); + assertThat(devices).doesNotContain(cachedDevice2); + } + + /** + * Test to verify addDevice(), new device has the different group id. + */ + @Test + public void addDevice_differentGroupId_validCachedDevices_bothAdded() { + doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice1); + doAnswer((invocation) -> CAP_GROUP2).when(mCsipSetCoordinatorProfile) + .getGroupUuidMapByDevice(mDevice2); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + + Collection devices = mCachedDeviceManager.getCachedDevicesCopy(); + assertThat(devices).contains(cachedDevice1); + assertThat(devices).contains(cachedDevice2); + } + + /** + * Test to verify clearNonBondedDevices() for csip set member device. + */ + @Test + public void clearNonBondedDevices_nonBondedMemberDevice() { + when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE); + when(mDevice3.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3); + cachedDevice1.setMemberDevice(cachedDevice2); + cachedDevice1.setMemberDevice(cachedDevice3); + + assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2); + assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3); + mCachedDeviceManager.clearNonBondedDevices(); + + assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse(); + assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue(); + } + + /** + * Test to verify OnDeviceUnpaired() for csip device unpair. + */ + @Test + public void onDeviceUnpaired_unpairCsipMainDevice() { + when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + cachedDevice1.setGroupId(1); + cachedDevice2.setGroupId(1); + cachedDevice1.setMemberDevice(cachedDevice2); + + // Call onDeviceUnpaired for the one in mCachedDevices. + mCachedDeviceManager.onDeviceUnpaired(cachedDevice1); + verify(mDevice2).removeBond(); + } + + /** + * Test to verify OnDeviceUnpaired() for csip device unpair. + */ + @Test + public void onDeviceUnpaired_unpairCsipSubDevice() { + when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); + CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1); + CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2); + cachedDevice1.setGroupId(1); + cachedDevice2.setGroupId(1); + cachedDevice1.setMemberDevice(cachedDevice2); + + // Call onDeviceUnpaired for the one in mCachedDevices. + mCachedDeviceManager.onDeviceUnpaired(cachedDevice2); + verify(mDevice1).removeBond(); + } + + /** + * Test to verify isSubDevice_validSubDevice(). + */ + @Test + public void isSubDevice_validMemberDevice() { + doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1); + mCachedDeviceManager.addDevice(mDevice1); + + // Both device are not sub device in default value. + assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse(); + assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse(); + + // Add Device-2 as device with Device-1 with the same group id, and add Device-3 with + // the different group id. + doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2); + doReturn(CAP_GROUP2).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3); + mCachedDeviceManager.addDevice(mDevice2); + mCachedDeviceManager.addDevice(mDevice3); + + // Verify Device-2 is sub device, but Device-1, and Device-3 is not. + assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse(); + assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isTrue(); + assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse(); + } }