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

Commit 887777aa 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 21476a96 6e8022da
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -318,7 +318,10 @@ public class CachedBluetoothDeviceManager {
            return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
            return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                state);
                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,
            return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                state);
                state);
        }
        }
+144 −142
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import androidx.annotation.ChecksSdkIntAtLeast;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
@@ -83,14 +84,14 @@ public class CsipDeviceManager {
    boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
    boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
        final int groupId = newDevice.getGroupId();
        final int groupId = newDevice.getGroupId();
        if (isValidGroupId(groupId)) {
        if (isValidGroupId(groupId)) {
            final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
            final CachedBluetoothDevice mainDevice = getCachedDevice(groupId);
            log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
            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.
            // 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
            // Once there is other devices with the same groupId, to add new device as member
            // devices.
            // devices.
            if (CsipDevice != null) {
            if (mainDevice != null) {
                CsipDevice.addMemberDevice(newDevice);
                mainDevice.addMemberDevice(newDevice);
                newDevice.setName(CsipDevice.getName());
                newDevice.setName(mainDevice.getName());
                return true;
                return true;
            }
            }
        }
        }
@@ -152,14 +153,7 @@ public class CsipDeviceManager {
            log("onGroupIdChanged: groupId is invalid");
            log("onGroupIdChanged: groupId is invalid");
            return;
            return;
        }
        }
        log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString());
        updateRelationshipOfGroupDevices(groupId);
        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);
    }
    }


    // @return {@code true}, the event is processed inside the method. It is for updating
    // @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,
    boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
            int state) {
            int state) {
        log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + 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 (state != BluetoothProfile.STATE_CONNECTED
                    if (device.isConnected()) {
                && state != BluetoothProfile.STATE_DISCONNECTED) {
                        log("set device: " + device + " as the main device");
            return false;
                        // 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;
        return updateRelationshipOfGroupDevices(cachedDevice.getGroupId());
            default:
                // Do not handle this state.
    }
    }

    @VisibleForTesting
    boolean updateRelationshipOfGroupDevices(int groupId) {
        if (!isValidGroupId(groupId)) {
            log("The device is not group.");
            return false;
            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) {
    CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
        if (device == null || mCachedDevices == null) {
        if (device == null || mCachedDevices == null) {
@@ -262,115 +225,154 @@ public class CsipDeviceManager {
        return false;
        return false;
    }
    }


    private List<CachedBluetoothDevice> getMemberDevicesList(int groupId) {
    @VisibleForTesting
        return mCachedDevices.stream()
    List<CachedBluetoothDevice> getGroupDevicesFromAllOfDevicesList(int groupId) {
                .filter(cacheDevice -> cacheDevice.getGroupId() == groupId)
        List<CachedBluetoothDevice> groupDevicesList = new ArrayList<>();
                .collect(Collectors.toList());
        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,
    @VisibleForTesting
            List<CachedBluetoothDevice> memberDevicesList) {
    CachedBluetoothDevice getPreferredMainDevice(int groupId,
        // First, priority connected lead device from LE profile
            List<CachedBluetoothDevice> groupDevicesList) {
        // Second, the DUAL mode device which has A2DP/HFP and LE audio
        // How to select the preferred main device?
        // Last, any one of LE device in the list.
        // 1. The DUAL mode connected device which has A2DP/HFP and LE audio.
        if (memberDevicesList == null || memberDevicesList.isEmpty()) {
        // 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;
            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 LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
        final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
        final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
        final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
        final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
        final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT())
        final BluetoothDevice leAudioLeadDevice = (leAudioProfile != null && isAtLeastT())
                ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null;
                ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null;


        if (mainBluetoothDevice != null) {
        if (leAudioLeadDevice != null) {
            log("getPreferredMainDevice: The LeadDevice from LE profile is "
            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");
            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;
        }
        }

        CachedBluetoothDevice oneOfConnectedDevices = groupDevicesList.stream()
        // 2nd
                .filter(cachedDevice -> cachedDevice.isConnected())
        newMainDevice = memberDevicesList.stream()
                .filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream()
                        .anyMatch(profile -> profile instanceof A2dpProfile
                                || profile instanceof HeadsetProfile))
                .findFirst().orElse(null);
                .findFirst().orElse(null);
        if (newMainDevice != null) {
        if (oneOfConnectedDevices != null) {
            log("getPreferredMainDevice: The DUAL mode device");
            log("getPreferredMainDevice: One of the connected devices.");
            return newMainDevice;
            return oneOfConnectedDevices;
        }
        }


        if (dualModeDevice != null) {
            log("getPreferredMainDevice: The DUAL mode device.");
            return dualModeDevice;
        }
        // last
        // last
        if (!memberDevicesList.isEmpty()) {
        if (!groupDevicesList.isEmpty()) {
            newMainDevice = memberDevicesList.get(0);
            log("getPreferredMainDevice: One of the group devices.");
            return groupDevicesList.get(0);
        }
        }
        return newMainDevice;
        return null;
    }
    }


    private void addMemberDevicesIntoMainDevice(List<CachedBluetoothDevice> memberDevicesList,
    @VisibleForTesting
            CachedBluetoothDevice newMainDevice) {
    boolean addMemberDevicesIntoMainDevice(int groupId, CachedBluetoothDevice preferredMainDevice) {
        if (newMainDevice == null) {
        boolean hasChanged = false;
        if (preferredMainDevice == null) {
            log("addMemberDevicesIntoMainDevice: No main device. Do nothing.");
            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 the current main device is not preferred main device, then set it as new main device.
        if (!memberDevicesList.contains(newMainDevice) && isMemberInOtherMainDevice) {
        // Otherwise, do nothing.
            log("addMemberDevicesIntoMainDevice: The 'new main device' is not in list, and it is "
        BluetoothDevice bluetoothDeviceOfPreferredMainDevice = preferredMainDevice.getDevice();
                    + "the member at other device. Do switch main and member.");
        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
            // To switch content and dispatch to notify UI change
            mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfNewMainDevice);
            mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfPreferredMainDevice);
            mainDeviceOfNewMainDevice.switchMemberDeviceContent(newMainDevice);
            mainDeviceOfPreferredMainDevice.switchMemberDeviceContent(preferredMainDevice);
            mainDeviceOfNewMainDevice.refresh();
            mainDeviceOfPreferredMainDevice.refresh();
            // It is necessary to do remove and add for updating the mapping on
            // It is necessary to do remove and add for updating the mapping on
            // preference and device
            // preference and device
            mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfNewMainDevice);
            mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfPreferredMainDevice);
        } else {
            hasChanged = true;
            log("addMemberDevicesIntoMainDevice: Set new main device");
        }
            for (CachedBluetoothDevice memberDeviceItem : memberDevicesList) {

                if (memberDeviceItem.equals(newMainDevice)) {
        // 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;
                    continue;
                }
                }
                Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice();

                if (!memberSet.isEmpty()) {
                Set<CachedBluetoothDevice> memberSet = deviceItem.getMemberDevice();
                for (CachedBluetoothDevice memberSetItem : memberSet) {
                for (CachedBluetoothDevice memberSetItem : memberSet) {
                        if (!memberSetItem.equals(newMainDevice)) {
                    if (!memberSetItem.equals(preferredMainDevice)) {
                            newMainDevice.addMemberDevice(memberSetItem);
                        preferredMainDevice.addMemberDevice(memberSetItem);
                    }
                    }
                }
                }
                memberSet.clear();
                memberSet.clear();
                }
                preferredMainDevice.addMemberDevice(deviceItem);

                mCachedDevices.remove(deviceItem);
                newMainDevice.addMemberDevice(memberDeviceItem);
                mBtManager.getEventManager().dispatchDeviceRemoved(deviceItem);
                mCachedDevices.remove(memberDeviceItem);
                hasChanged = true;
                mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem);
            }

            if (!mCachedDevices.contains(newMainDevice)) {
                mCachedDevices.add(newMainDevice);
                mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice);
            }
            }
        }
        }
        if (hasChanged) {
            log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
            log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
                    + mCachedDevices);
                    + mCachedDevices);
        }
        }
        return hasChanged;
    }


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

File added.

Preview size limit exceeded, changes collapsed.