Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b52ff78 authored by SongFerng Wang's avatar SongFerng Wang Committed by Automerger Merge Worker
Browse files

Merge "Refactor the CSIP and redesign the rule of transferring device" into udc-dev am: 6e8022da

parents ad4e23a3 6e8022da
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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);
        }
+144 −142
Original line number Diff line number Diff line
@@ -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,62 +162,31 @@ 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;
                    }
        if (state != BluetoothProfile.STATE_CONNECTED
                && state != BluetoothProfile.STATE_DISCONNECTED) {
            return false;
        }
                break;
            default:
                // Do not handle this state.
        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) {
        if (device == null || mCachedDevices == null) {
@@ -262,115 +225,154 @@ 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());
        }

        // 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.");
                    + leAudioLeadDevice.getAnonymizedAddress());
        }
        } 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;
        }

        if (dualModeDevice != null) {
            log("getPreferredMainDevice: The DUAL mode device.");
            return dualModeDevice;
        }
        // last
        if (!memberDevicesList.isEmpty()) {
            newMainDevice = memberDevicesList.get(0);
        if (!groupDevicesList.isEmpty()) {
            log("getPreferredMainDevice: One of the group devices.");
            return groupDevicesList.get(0);
        }
        return newMainDevice;
        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;
        }
        if (memberDevicesList.isEmpty()) {
            log("addMemberDevicesIntoMainDevice: No member device in list. Do nothing.");
            return;
            return hasChanged;
        }
        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()) {

                Set<CachedBluetoothDevice> memberSet = deviceItem.getMemberDevice();
                for (CachedBluetoothDevice memberSetItem : memberSet) {
                        if (!memberSetItem.equals(newMainDevice)) {
                            newMainDevice.addMemberDevice(memberSetItem);
                    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);
                preferredMainDevice.addMemberDevice(deviceItem);
                mCachedDevices.remove(deviceItem);
                mBtManager.getEventManager().dispatchDeviceRemoved(deviceItem);
                hasChanged = true;
            }
        }
        if (hasChanged) {
            log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
                    + mCachedDevices);
        }
        return hasChanged;
    }

    private void log(String msg) {
        if (DEBUG) {
+345 −0

File added.

Preview size limit exceeded, changes collapsed.