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

Commit f3d300b0 authored by SongFerngWang's avatar SongFerngWang
Browse files

[LE Unicast] Using the active device as main device after grouping

After onGroupIdChanged, the CsipDeviceManager assigns the first
device with the same groupId as main device. It is not correct
since the main device shouble be the active device. This issue
causes the summary can't shows 'Active' at the Settings.

Bug: 232892046
Test: Build pass
Change-Id: I00e5471b9315c896b8c16723ad37d66a922c27e4
Merged-In: I00e5471b9315c896b8c16723ad37d66a922c27e4
parent 2be0e5e3
Loading
Loading
Loading
Loading
+73 −17
Original line number Original line Diff line number Diff line
@@ -20,15 +20,19 @@ import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.BluetoothUuid;
import android.os.Build;
import android.os.ParcelUuid;
import android.os.ParcelUuid;
import android.util.Log;
import android.util.Log;


import androidx.annotation.ChecksSdkIntAtLeast;

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


import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.Set;
import java.util.stream.Collectors;


/**
/**
 * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
 * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
@@ -126,11 +130,62 @@ public class CsipDeviceManager {
        }
        }
    }
    }


    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
    private static boolean isAtLeastT() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
    }

    // Group devices by groupId
    // Group devices by groupId
    @VisibleForTesting
    @VisibleForTesting
    void onGroupIdChanged(int groupId) {
    void onGroupIdChanged(int groupId) {
        if (!isValidGroupId(groupId)) {
            log("onGroupIdChanged: groupId is invalid");
            return;
        }
        log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString());
        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
        final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager();
        final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
        final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ?
                leAudioProfile.getConnectedGroupLeadDevice(groupId) : null;
        CachedBluetoothDevice newMainDevice =
                mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null;
        if (newMainDevice != null) {
            final CachedBluetoothDevice finalNewMainDevice = newMainDevice;
            final List<CachedBluetoothDevice> memberDevices = mCachedDevices.stream()
                    .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice)
                            && cachedDevice.getGroupId() == groupId)
                    .collect(Collectors.toList());
            if (memberDevices == null || memberDevices.isEmpty()) {
                log("onGroupIdChanged: There is no member device in list.");
                return;
            }
            log("onGroupIdChanged: removed from UI device =" + memberDevices
                    + ", with groupId=" + groupId + " mainDevice= " + newMainDevice);
            for (CachedBluetoothDevice memberDeviceItem : memberDevices) {
                Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice();
                if (!memberSet.isEmpty()) {
                    log("onGroupIdChanged: Transfer the member list into new main device.");
                    for (CachedBluetoothDevice memberListItem : memberSet) {
                        if (!memberListItem.equals(newMainDevice)) {
                            newMainDevice.addMemberDevice(memberListItem);
                        }
                    }
                    memberSet.clear();
                }

                newMainDevice.addMemberDevice(memberDeviceItem);
                mCachedDevices.remove(memberDeviceItem);
                mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem);
            }

            if (!mCachedDevices.contains(newMainDevice)) {
                mCachedDevices.add(newMainDevice);
                mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice);
            }
        } else {
            log("onGroupIdChanged: There is no main device from the LE profile.");
            int firstMatchedIndex = -1;
            int firstMatchedIndex = -1;
        CachedBluetoothDevice mainDevice = null;


            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
                final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
                final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
@@ -141,19 +196,20 @@ public class CsipDeviceManager {
                if (firstMatchedIndex == -1) {
                if (firstMatchedIndex == -1) {
                    // Found the first one
                    // Found the first one
                    firstMatchedIndex = i;
                    firstMatchedIndex = i;
                mainDevice = cachedDevice;
                    newMainDevice = cachedDevice;
                    continue;
                    continue;
                }
                }


                log("onGroupIdChanged: removed from UI device =" + cachedDevice
                log("onGroupIdChanged: removed from UI device =" + cachedDevice
                        + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
                        + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);


            mainDevice.addMemberDevice(cachedDevice);
                newMainDevice.addMemberDevice(cachedDevice);
                mCachedDevices.remove(i);
                mCachedDevices.remove(i);
                mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
                mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
                break;
                break;
            }
            }
        }
        }
    }


    // @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
    // le audio device on group relationship when receiving connected or disconnected.
    // le audio device on group relationship when receiving connected or disconnected.
+32 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;


import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothCodecConfig;
@@ -183,6 +184,37 @@ public class LeAudioProfile implements LocalBluetoothProfile {
        return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
        return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
    }
    }


    /**
     * Get Lead device for the group.
     *
     * Lead device is the device that can be used as an active device in the system.
     * Active devices points to the Audio Device for the Le Audio group.
     * This method returns the Lead devices for the connected LE Audio
     * group and this device should be used in the setActiveDevice() method by other parts
     * of the system, which wants to set to active a particular Le Audio group.
     *
     * Note: getActiveDevice() returns the Lead device for the currently active LE Audio group.
     * Note: When Lead device gets disconnected while Le Audio group is active and has more devices
     * in the group, then Lead device will not change. If Lead device gets disconnected, for the
     * Le Audio group which is not active, a new Lead device will be chosen
     *
     * @param groupId The group id.
     * @return group lead device.
     *
     * @hide
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    public @Nullable BluetoothDevice getConnectedGroupLeadDevice(int groupId) {
        if (DEBUG) {
            Log.d(TAG,"getConnectedGroupLeadDevice");
        }
        if (mService == null) {
            Log.e(TAG,"No service.");
            return null;
        }
        return mService.getConnectedGroupLeadDevice(groupId);
    }

    @Override
    @Override
    public boolean isEnabled(BluetoothDevice device) {
    public boolean isEnabled(BluetoothDevice device) {
        if (mService == null || device == null) {
        if (mService == null || device == null) {