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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user