Merge "Refactor the CSIP and redesign the rule of transferring device" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6e8022dad5
@@ -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