Merge "Refactor the CSIP and redesign the rule of transferring device" into udc-dev

This commit is contained in:
SongFerng Wang
2023-05-12 13:39:40 +00:00
committed by Android (Google) Code Review
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);
}
}