Refactor the CSIP and redesign the rule of transferring device

The CSIP design is changed, it need to consider multi profiles
case, therefore it must use the unified rule to set main device up.

Bug: 280728631
Test: make RunSettingsLibRoboTests -j40 ROBOTEST_FILTER=CsipDeviceManagerTest
Test: Build pass
Change-Id: I8b73700e9da547e8ef63b36ad8eab2d52e2c1647
This commit is contained in:
SongFerngWang
2023-05-12 17:31:24 +08:00
parent 05da757a7f
commit bcb1dda324
3 changed files with 494 additions and 144 deletions

View File

@@ -318,7 +318,10 @@ public class CachedBluetoothDeviceManager {
return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
state);
}
if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
if (profileId == BluetoothProfile.HEADSET
|| profileId == BluetoothProfile.A2DP
|| profileId == BluetoothProfile.LE_AUDIO
|| profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
state);
}

View File

@@ -28,6 +28,7 @@ import androidx.annotation.ChecksSdkIntAtLeast;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -83,14 +84,14 @@ public class CsipDeviceManager {
boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
final int groupId = newDevice.getGroupId();
if (isValidGroupId(groupId)) {
final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
final CachedBluetoothDevice mainDevice = getCachedDevice(groupId);
log("setMemberDeviceIfNeeded, main: " + mainDevice + ", member: " + newDevice);
// Just add one of the coordinated set from a pair in the list that is shown in the UI.
// Once there is other devices with the same groupId, to add new device as member
// devices.
if (CsipDevice != null) {
CsipDevice.addMemberDevice(newDevice);
newDevice.setName(CsipDevice.getName());
if (mainDevice != null) {
mainDevice.addMemberDevice(newDevice);
newDevice.setName(mainDevice.getName());
return true;
}
}
@@ -152,14 +153,7 @@ public class CsipDeviceManager {
log("onGroupIdChanged: groupId is invalid");
return;
}
log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString());
List<CachedBluetoothDevice> memberDevicesList = getMemberDevicesList(groupId);
CachedBluetoothDevice newMainDevice =
getPreferredMainDeviceWithoutConectionState(groupId, memberDevicesList);
log("onGroupIdChanged: The mainDevice= " + newMainDevice
+ " and the memberDevicesList of groupId= " + groupId + " =" + memberDevicesList);
addMemberDevicesIntoMainDevice(memberDevicesList, newMainDevice);
updateRelationshipOfGroupDevices(groupId);
}
// @return {@code true}, the event is processed inside the method. It is for updating
@@ -168,61 +162,30 @@ public class CsipDeviceManager {
boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
int state) {
log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + state);
switch (state) {
case BluetoothProfile.STATE_CONNECTED:
onGroupIdChanged(cachedDevice.getGroupId());
CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
if (mainDevice.isConnected()) {
// When main device exists and in connected state, receiving member device
// connection. To refresh main device UI
mainDevice.refresh();
return true;
} else {
// When both LE Audio devices are disconnected, receiving member device
// connection. To switch content and dispatch to notify UI change
mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
mainDevice.switchMemberDeviceContent(cachedDevice);
mainDevice.refresh();
// It is necessary to do remove and add for updating the mapping on
// preference and device
mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
return true;
}
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
// When main device exists, receiving sub device disconnection
// To update main device UI
mainDevice.refresh();
return true;
}
final Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
if (memberSet.isEmpty()) {
break;
}
for (CachedBluetoothDevice device : memberSet) {
if (device.isConnected()) {
log("set device: " + device + " as the main device");
// Main device is disconnected and sub device is connected
// To copy data from sub device to main device
mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
cachedDevice.switchMemberDeviceContent(device);
cachedDevice.refresh();
// It is necessary to do remove and add for updating the mapping on
// preference and device
mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
return true;
}
}
break;
default:
// Do not handle this state.
if (state != BluetoothProfile.STATE_CONNECTED
&& state != BluetoothProfile.STATE_DISCONNECTED) {
return false;
}
return false;
return updateRelationshipOfGroupDevices(cachedDevice.getGroupId());
}
@VisibleForTesting
boolean updateRelationshipOfGroupDevices(int groupId) {
if (!isValidGroupId(groupId)) {
log("The device is not group.");
return false;
}
log("updateRelationshipOfGroupDevices: mCachedDevices list =" + mCachedDevices.toString());
// Get the preferred main device by getPreferredMainDeviceWithoutConectionState
List<CachedBluetoothDevice> groupDevicesList = getGroupDevicesFromAllOfDevicesList(groupId);
CachedBluetoothDevice preferredMainDevice =
getPreferredMainDevice(groupId, groupDevicesList);
log("The preferredMainDevice= " + preferredMainDevice
+ " and the groupDevicesList of groupId= " + groupId
+ " =" + groupDevicesList);
return addMemberDevicesIntoMainDevice(groupId, preferredMainDevice);
}
CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
@@ -262,114 +225,153 @@ public class CsipDeviceManager {
return false;
}
private List<CachedBluetoothDevice> getMemberDevicesList(int groupId) {
return mCachedDevices.stream()
.filter(cacheDevice -> cacheDevice.getGroupId() == groupId)
.collect(Collectors.toList());
@VisibleForTesting
List<CachedBluetoothDevice> getGroupDevicesFromAllOfDevicesList(int groupId) {
List<CachedBluetoothDevice> groupDevicesList = new ArrayList<>();
if (!isValidGroupId(groupId)) {
return groupDevicesList;
}
for (CachedBluetoothDevice item : mCachedDevices) {
if (groupId != item.getGroupId()) {
continue;
}
groupDevicesList.add(item);
groupDevicesList.addAll(item.getMemberDevice());
}
return groupDevicesList;
}
private CachedBluetoothDevice getPreferredMainDeviceWithoutConectionState(int groupId,
List<CachedBluetoothDevice> memberDevicesList) {
// First, priority connected lead device from LE profile
// Second, the DUAL mode device which has A2DP/HFP and LE audio
// Last, any one of LE device in the list.
if (memberDevicesList == null || memberDevicesList.isEmpty()) {
@VisibleForTesting
CachedBluetoothDevice getPreferredMainDevice(int groupId,
List<CachedBluetoothDevice> groupDevicesList) {
// How to select the preferred main device?
// 1. The DUAL mode connected device which has A2DP/HFP and LE audio.
// 2. One of connected LE device in the list. Default is the lead device from LE profile.
// 3. If there is no connected device, then reset the relationship. Set the DUAL mode
// deviced as the main device. Otherwise, set any one of the device.
if (groupDevicesList == null || groupDevicesList.isEmpty()) {
return null;
}
CachedBluetoothDevice dualModeDevice = groupDevicesList.stream()
.filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream()
.anyMatch(profile -> profile instanceof LeAudioProfile))
.filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream()
.anyMatch(profile -> profile instanceof A2dpProfile
|| profile instanceof HeadsetProfile))
.findFirst().orElse(null);
if (dualModeDevice != null && dualModeDevice.isConnected()) {
log("getPreferredMainDevice: The connected DUAL mode device");
return dualModeDevice;
}
final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT())
final BluetoothDevice leAudioLeadDevice = (leAudioProfile != null && isAtLeastT())
? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null;
if (mainBluetoothDevice != null) {
if (leAudioLeadDevice != null) {
log("getPreferredMainDevice: The LeadDevice from LE profile is "
+ mainBluetoothDevice.getAnonymizedAddress());
+ leAudioLeadDevice.getAnonymizedAddress());
}
// 1st
CachedBluetoothDevice newMainDevice =
mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null;
if (newMainDevice != null) {
if (newMainDevice.isConnected()) {
log("getPreferredMainDevice: The connected LeadDevice from LE profile");
return newMainDevice;
} else {
log("getPreferredMainDevice: The LeadDevice is not connect.");
}
} else {
CachedBluetoothDevice leAudioLeadCachedDevice =
leAudioLeadDevice != null ? deviceManager.findDevice(leAudioLeadDevice) : null;
if (leAudioLeadCachedDevice == null) {
log("getPreferredMainDevice: The LeadDevice is not in the all of devices list");
} else if (leAudioLeadCachedDevice.isConnected()) {
log("getPreferredMainDevice: The connected LeadDevice from LE profile");
return leAudioLeadCachedDevice;
}
// 2nd
newMainDevice = memberDevicesList.stream()
.filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream()
.anyMatch(profile -> profile instanceof A2dpProfile
|| profile instanceof HeadsetProfile))
CachedBluetoothDevice oneOfConnectedDevices = groupDevicesList.stream()
.filter(cachedDevice -> cachedDevice.isConnected())
.findFirst().orElse(null);
if (newMainDevice != null) {
log("getPreferredMainDevice: The DUAL mode device");
return newMainDevice;
if (oneOfConnectedDevices != null) {
log("getPreferredMainDevice: One of the connected devices.");
return oneOfConnectedDevices;
}
// last
if (!memberDevicesList.isEmpty()) {
newMainDevice = memberDevicesList.get(0);
if (dualModeDevice != null) {
log("getPreferredMainDevice: The DUAL mode device.");
return dualModeDevice;
}
return newMainDevice;
// last
if (!groupDevicesList.isEmpty()) {
log("getPreferredMainDevice: One of the group devices.");
return groupDevicesList.get(0);
}
return null;
}
private void addMemberDevicesIntoMainDevice(List<CachedBluetoothDevice> memberDevicesList,
CachedBluetoothDevice newMainDevice) {
if (newMainDevice == null) {
@VisibleForTesting
boolean addMemberDevicesIntoMainDevice(int groupId, CachedBluetoothDevice preferredMainDevice) {
boolean hasChanged = false;
if (preferredMainDevice == null) {
log("addMemberDevicesIntoMainDevice: No main device. Do nothing.");
return;
return hasChanged;
}
if (memberDevicesList.isEmpty()) {
log("addMemberDevicesIntoMainDevice: No member device in list. Do nothing.");
return;
}
CachedBluetoothDevice mainDeviceOfNewMainDevice = findMainDevice(newMainDevice);
boolean isMemberInOtherMainDevice = mainDeviceOfNewMainDevice != null;
if (!memberDevicesList.contains(newMainDevice) && isMemberInOtherMainDevice) {
log("addMemberDevicesIntoMainDevice: The 'new main device' is not in list, and it is "
+ "the member at other device. Do switch main and member.");
// If the current main device is not preferred main device, then set it as new main device.
// Otherwise, do nothing.
BluetoothDevice bluetoothDeviceOfPreferredMainDevice = preferredMainDevice.getDevice();
CachedBluetoothDevice mainDeviceOfPreferredMainDevice = findMainDevice(preferredMainDevice);
boolean hasPreferredMainDeviceAlreadyBeenMainDevice =
mainDeviceOfPreferredMainDevice == null;
if (!hasPreferredMainDeviceAlreadyBeenMainDevice) {
// preferredMainDevice has not been the main device.
// switch relationship between the mainDeviceOfPreferredMainDevice and
// PreferredMainDevice
log("addMemberDevicesIntoMainDevice: The PreferredMainDevice have the mainDevice. "
+ "Do switch relationship between the mainDeviceOfPreferredMainDevice and "
+ "PreferredMainDevice");
// To switch content and dispatch to notify UI change
mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfNewMainDevice);
mainDeviceOfNewMainDevice.switchMemberDeviceContent(newMainDevice);
mainDeviceOfNewMainDevice.refresh();
mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfPreferredMainDevice);
mainDeviceOfPreferredMainDevice.switchMemberDeviceContent(preferredMainDevice);
mainDeviceOfPreferredMainDevice.refresh();
// It is necessary to do remove and add for updating the mapping on
// preference and device
mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfNewMainDevice);
} else {
log("addMemberDevicesIntoMainDevice: Set new main device");
for (CachedBluetoothDevice memberDeviceItem : memberDevicesList) {
if (memberDeviceItem.equals(newMainDevice)) {
mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfPreferredMainDevice);
hasChanged = true;
}
// If the mCachedDevices List at CachedBluetoothDeviceManager has multiple items which are
// the same groupId, then combine them and also keep the preferred main device as main
// device.
List<CachedBluetoothDevice> topLevelOfGroupDevicesList = mCachedDevices.stream()
.filter(device -> device.getGroupId() == groupId)
.collect(Collectors.toList());
boolean haveMultiMainDevicesInAllOfDevicesList = topLevelOfGroupDevicesList.size() > 1;
// Update the new main of CachedBluetoothDevice, since it may be changed in above step.
final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
preferredMainDevice = deviceManager.findDevice(bluetoothDeviceOfPreferredMainDevice);
if (haveMultiMainDevicesInAllOfDevicesList) {
// put another devices into main device.
for (CachedBluetoothDevice deviceItem : topLevelOfGroupDevicesList) {
if (deviceItem.getDevice() == null || deviceItem.getDevice().equals(
bluetoothDeviceOfPreferredMainDevice)) {
continue;
}
Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice();
if (!memberSet.isEmpty()) {
for (CachedBluetoothDevice memberSetItem : memberSet) {
if (!memberSetItem.equals(newMainDevice)) {
newMainDevice.addMemberDevice(memberSetItem);
}
Set<CachedBluetoothDevice> memberSet = deviceItem.getMemberDevice();
for (CachedBluetoothDevice memberSetItem : memberSet) {
if (!memberSetItem.equals(preferredMainDevice)) {
preferredMainDevice.addMemberDevice(memberSetItem);
}
memberSet.clear();
}
newMainDevice.addMemberDevice(memberDeviceItem);
mCachedDevices.remove(memberDeviceItem);
mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem);
}
if (!mCachedDevices.contains(newMainDevice)) {
mCachedDevices.add(newMainDevice);
mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice);
memberSet.clear();
preferredMainDevice.addMemberDevice(deviceItem);
mCachedDevices.remove(deviceItem);
mBtManager.getEventManager().dispatchDeviceRemoved(deviceItem);
hasChanged = true;
}
}
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
+ mCachedDevices);
if (hasChanged) {
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
+ mCachedDevices);
}
return hasChanged;
}
private void log(String msg) {

View File

@@ -0,0 +1,345 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settingslib.bluetooth;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Parcel;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class CsipDeviceManagerTest {
private final static String DEVICE_NAME_1 = "TestName_1";
private final static String DEVICE_NAME_2 = "TestName_2";
private final static String DEVICE_NAME_3 = "TestName_3";
private final static String DEVICE_ALIAS_1 = "TestAlias_1";
private final static String DEVICE_ALIAS_2 = "TestAlias_2";
private final static String DEVICE_ALIAS_3 = "TestAlias_3";
private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
private final static int GROUP1 = 1;
private final BluetoothClass DEVICE_CLASS_1 =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
private final BluetoothClass DEVICE_CLASS_2 =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@Mock
private LocalBluetoothProfileManager mLocalProfileManager;
@Mock
private BluetoothEventManager mBluetoothEventManager;
@Mock
private BluetoothDevice mDevice1;
@Mock
private BluetoothDevice mDevice2;
@Mock
private BluetoothDevice mDevice3;
@Mock
private HeadsetProfile mHfpProfile;
@Mock
private A2dpProfile mA2dpProfile;
@Mock
private LeAudioProfile mLeAudioProfile;
private CachedBluetoothDevice mCachedDevice1;
private CachedBluetoothDevice mCachedDevice2;
private CachedBluetoothDevice mCachedDevice3;
private CachedBluetoothDeviceManager mCachedDeviceManager;
private CsipDeviceManager mCsipDeviceManager;
private Context mContext;
private List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
private BluetoothClass createBtClass(int deviceClass) {
Parcel p = Parcel.obtain();
p.writeInt(deviceClass);
p.setDataPosition(0); // reset position of parcel before passing to constructor
BluetoothClass bluetoothClass = BluetoothClass.CREATOR.createFromParcel(p);
p.recycle();
return bluetoothClass;
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
when(mDevice1.getAddress()).thenReturn(DEVICE_ADDRESS_1);
when(mDevice2.getAddress()).thenReturn(DEVICE_ADDRESS_2);
when(mDevice3.getAddress()).thenReturn(DEVICE_ADDRESS_3);
when(mDevice1.getName()).thenReturn(DEVICE_NAME_1);
when(mDevice2.getName()).thenReturn(DEVICE_NAME_2);
when(mDevice3.getName()).thenReturn(DEVICE_NAME_3);
when(mDevice1.getAlias()).thenReturn(DEVICE_ALIAS_1);
when(mDevice2.getAlias()).thenReturn(DEVICE_ALIAS_2);
when(mDevice3.getAlias()).thenReturn(DEVICE_ALIAS_3);
when(mDevice1.getBluetoothClass()).thenReturn(DEVICE_CLASS_1);
when(mDevice2.getBluetoothClass()).thenReturn(DEVICE_CLASS_2);
when(mDevice3.getBluetoothClass()).thenReturn(DEVICE_CLASS_2);
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalProfileManager);
when(mLocalProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mLocalProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile);
when(mLeAudioProfile.getConnectedGroupLeadDevice(anyInt())).thenReturn(null);
mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
mCachedDevices = mCachedDeviceManager.mCachedDevices;
mCsipDeviceManager = mCachedDeviceManager.mCsipDeviceManager;
// Setup the default for testing
mCachedDevice1 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1));
mCachedDevice2 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2));
mCachedDevice3 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice3));
mCachedDevice1.setGroupId(GROUP1);
mCachedDevice2.setGroupId(GROUP1);
mCachedDevice1.addMemberDevice(mCachedDevice2);
mCachedDevices.add(mCachedDevice1);
mCachedDevices.add(mCachedDevice3);
List<LocalBluetoothProfile> profiles = new ArrayList<LocalBluetoothProfile>();
profiles.add(mHfpProfile);
profiles.add(mA2dpProfile);
profiles.add(mLeAudioProfile);
when(mCachedDevice1.getConnectableProfiles()).thenReturn(profiles);
when(mCachedDevice1.isConnected()).thenReturn(true);
profiles.clear();
profiles.add(mLeAudioProfile);
when(mCachedDevice2.getConnectableProfiles()).thenReturn(profiles);
when(mCachedDevice2.isConnected()).thenReturn(true);
profiles.clear();
profiles.add(mHfpProfile);
profiles.add(mA2dpProfile);
when(mCachedDevice3.getConnectableProfiles()).thenReturn(profiles);
when(mCachedDevice3.isConnected()).thenReturn(true);
}
@Test
public void onProfileConnectionStateChangedIfProcessed_profileIsConnecting_returnOff() {
assertThat(mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(mCachedDevice1,
BluetoothProfile.STATE_CONNECTING)).isFalse();
}
@Test
public void onProfileConnectionStateChangedIfProcessed_profileIsDisconnecting_returnOff() {
assertThat(mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(mCachedDevice1,
BluetoothProfile.STATE_DISCONNECTING)).isFalse();
}
@Test
public void updateRelationshipOfGroupDevices_invalidGroupId_returnOff() {
assertThat(mCsipDeviceManager.updateRelationshipOfGroupDevices(
BluetoothCsipSetCoordinator.GROUP_ID_INVALID)).isFalse();
}
@Test
public void getGroupDevicesFromAllOfDevicesList_invalidGroupId_returnEmpty() {
assertThat(mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(
BluetoothCsipSetCoordinator.GROUP_ID_INVALID).isEmpty()).isTrue();
}
@Test
public void getGroupDevicesFromAllOfDevicesList_validGroupId_returnGroupDevices() {
List<CachedBluetoothDevice> expectedList = new ArrayList<>();
expectedList.add(mCachedDevice1);
expectedList.add(mCachedDevice2);
assertThat(mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1))
.isEqualTo(expectedList);
}
@Test
public void getPreferredMainDevice_dualModeDevice_returnDualModeDevice() {
CachedBluetoothDevice expectedDevice = mCachedDevice1;
assertThat(
mCsipDeviceManager.getPreferredMainDevice(GROUP1,
mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1)))
.isEqualTo(expectedDevice);
}
@Test
public void getPreferredMainDevice_noConnectedDualModeDevice_returnLeadDevice() {
when(mCachedDevice1.isConnected()).thenReturn(false);
when(mLeAudioProfile.getConnectedGroupLeadDevice(anyInt())).thenReturn(mDevice2);
CachedBluetoothDevice expectedDevice = mCachedDevice2;
assertThat(
mCsipDeviceManager.getPreferredMainDevice(GROUP1,
mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1)))
.isEqualTo(expectedDevice);
}
@Test
public void getPreferredMainDevice_noConnectedDualModeDeviceNoLeadDevice_returnConnectedOne() {
when(mCachedDevice1.isConnected()).thenReturn(false);
when(mCachedDevice2.isConnected()).thenReturn(true);
CachedBluetoothDevice expectedDevice = mCachedDevice2;
assertThat(
mCsipDeviceManager.getPreferredMainDevice(GROUP1,
mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1)))
.isEqualTo(expectedDevice);
}
@Test
public void getPreferredMainDevice_noConnectedDevice_returnDualModeDevice() {
when(mCachedDevice1.isConnected()).thenReturn(false);
when(mCachedDevice2.isConnected()).thenReturn(false);
CachedBluetoothDevice expectedDevice = mCachedDevice1;
assertThat(
mCsipDeviceManager.getPreferredMainDevice(GROUP1,
mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1)))
.isEqualTo(expectedDevice);
}
@Test
public void getPreferredMainDevice_noConnectedDeviceNoDualMode_returnFirstOneDevice() {
when(mCachedDevice1.isConnected()).thenReturn(false);
when(mCachedDevice2.isConnected()).thenReturn(false);
List<LocalBluetoothProfile> profiles = new ArrayList<LocalBluetoothProfile>();
profiles.add(mLeAudioProfile);
when(mCachedDevice1.getConnectableProfiles()).thenReturn(profiles);
CachedBluetoothDevice expectedDevice = mCachedDevice1;
assertThat(
mCsipDeviceManager.getPreferredMainDevice(GROUP1,
mCsipDeviceManager.getGroupDevicesFromAllOfDevicesList(GROUP1)))
.isEqualTo(expectedDevice);
}
@Test
public void addMemberDevicesIntoMainDevice_noPreferredDevice_returnFalseAndNoChangeList() {
CachedBluetoothDevice preferredDevice = null;
List<CachedBluetoothDevice> expectedList = new ArrayList<>();
for (CachedBluetoothDevice item : mCachedDevices) {
expectedList.add(item);
}
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isFalse();
for (CachedBluetoothDevice expectedItem : expectedList) {
assertThat(mCachedDevices.contains(expectedItem)).isTrue();
}
}
@Test
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndNoOtherInList_noChangeList()
{
// Condition: The preferredDevice is main and no other main device in top list
// Expected Result: return false and the list is no changed
CachedBluetoothDevice preferredDevice = mCachedDevice1;
List<CachedBluetoothDevice> expectedList = new ArrayList<>();
for (CachedBluetoothDevice item : mCachedDevices) {
expectedList.add(item);
}
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isFalse();
for (CachedBluetoothDevice expectedItem : expectedList) {
assertThat(mCachedDevices.contains(expectedItem)).isTrue();
}
}
@Test
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_returnTrue() {
// Condition: The preferredDevice is main and there is another main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice1;
mCachedDevice1.getMemberDevice().clear();
mCachedDevices.clear();
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
assertThat(mCachedDevices.contains(preferredDevice)).isTrue();
assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
}
@Test
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMember_returnTrue() {
// Condition: The preferredDevice is member
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
// expected main is mCachedDevice1 which is the main of preferredDevice, since system
// switch the relationship between preferredDevice and the main of preferredDevice
assertThat(mCachedDevices.contains(mCachedDevice1)).isTrue();
assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
}
@Test
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_returnTrue() {
// Condition: The preferredDevice is member and there are two main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
// expected main is mCachedDevice1 which is the main of preferredDevice, since system
// switch the relationship between preferredDevice and the main of preferredDevice
assertThat(mCachedDevices.contains(mCachedDevice1)).isTrue();
assertThat(mCachedDevices.contains(mCachedDevice2)).isFalse();
assertThat(mCachedDevices.contains(mCachedDevice3)).isFalse();
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice2);
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
assertThat(mCachedDevice1.getMemberDevice()).contains(mCachedDevice3);
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
}
}