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

Commit 50916164 authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

LeAudio: Fix late LeAudio connect of ASHA/LeAudio HS

Fix for following scenario:
1. Connect/Pair 1 set member of LeAudio/ASHA hearing aid
2. Toggle LeAudio switch to use LeAudio
3. Connect second set member.

Issue would be that second member will use ASHA.

Since this issue will is visible when flag:
leaudio_quick_leaudio_toggle_switch_fix is enabled,
lets use it in description

Bug: 330515834
Bug: 328595942
Test: atest PhonePolicyTest

Change-Id: I9efecb0e29422a9a05a31fd8ecbc84993565bd2d
parent 1f97e950
Loading
Loading
Loading
Loading
+42 −28
Original line number Diff line number Diff line
@@ -698,14 +698,20 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
                + BluetoothProfile.getProfileName(profileId) + " isDualModeAudioEnabled="
                + isDualModeAudioEnabled());

        if (device != null) {
        if (device == null) {
            return;
        }

        mDatabaseManager.setConnection(device, profileId);

            if (isDualModeAudioEnabled()) return;
        boolean isDualMode = isDualModeAudioEnabled();

        if (profileId == BluetoothProfile.LE_AUDIO) {
            A2dpService a2dpService = mFactory.getA2dpService();
            HeadsetService hsService = mFactory.getHeadsetService();
            LeAudioService leAudioService = mFactory.getLeAudioService();
            HearingAidService hearingAidService = mFactory.getHearingAidService();

            if (leAudioService == null) {
                debugLog("processActiveDeviceChanged: LeAudioService is null");
                return;
@@ -713,20 +719,28 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
            List<BluetoothDevice> leAudioActiveGroupDevices =
                    leAudioService.getGroupDevices(leAudioService.getGroupId(device));

                // Disable classic audio profiles for all group devices as lead can change
            // Disable classic audio profiles and ASHA for all group devices as lead can change
            for (BluetoothDevice activeGroupDevice : leAudioActiveGroupDevices) {
                    if (hsService != null) {
                        debugLog("Disable HFP for the LE audio dual mode group device "
                if (hsService != null && !isDualMode) {
                    debugLog(
                            "Disable HFP for the LE audio dual mode group device "
                                    + activeGroupDevice);
                        hsService.setConnectionPolicy(activeGroupDevice,
                                BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
                    hsService.setConnectionPolicy(
                            activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
                }
                    if (a2dpService != null) {
                        debugLog("Disable A2DP for the LE audio dual mode group device "
                if (a2dpService != null && !isDualMode) {
                    debugLog(
                            "Disable A2DP for the LE audio dual mode group device "
                                    + activeGroupDevice);
                        a2dpService.setConnectionPolicy(activeGroupDevice,
                                BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
                    a2dpService.setConnectionPolicy(
                            activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
                }
                if (hearingAidService != null) {
                    debugLog(
                            "Disable ASHA for the LE audio dual mode group device "
                                    + activeGroupDevice);
                    hearingAidService.setConnectionPolicy(
                            activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
                }
            }
        }
+125 −3
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.btservice.storage.MetadataDatabase;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.hap.HapClientService;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.le_audio.LeAudioService;

@@ -84,6 +86,8 @@ public class PhonePolicyTest {
    @Mock private LeAudioService mLeAudioService;
    @Mock private DatabaseManager mDatabaseManager;
    @Mock private CsipSetCoordinatorService mCsipSetCoordinatorService;
    @Mock private HearingAidService mHearingAidService;
    @Mock private HapClientService mHapClientService;

    private List<BluetoothDevice> mLeAudioAllowedConnectionPolicyList = new ArrayList<>();

@@ -104,6 +108,8 @@ public class PhonePolicyTest {
        doReturn(mA2dpService).when(mServiceFactory).getA2dpService();
        doReturn(mLeAudioService).when(mServiceFactory).getLeAudioService();
        doReturn(mCsipSetCoordinatorService).when(mServiceFactory).getCsipSetCoordinatorService();
        doReturn(mHearingAidService).when(mServiceFactory).getHearingAidService();
        doReturn(mHapClientService).when(mServiceFactory).getHapClientService();

        // Start handler thread for this test
        mHandlerThread = new HandlerThread("PhonePolicyTestHandlerThread");
@@ -169,11 +175,13 @@ public class PhonePolicyTest {

        // Check that the priorities of the devices for preferred profiles are set to ON
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
                .setProfileConnectionPolicy(device, BluetoothProfile.HEADSET,
                .setProfileConnectionPolicy(
                        device,
                        BluetoothProfile.HEADSET,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        verify(mDatabaseManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS))
                .setProfileConnectionPolicy(device, BluetoothProfile.A2DP,
                        BluetoothProfile.CONNECTION_POLICY_ALLOWED);
                .setProfileConnectionPolicy(
                        device, BluetoothProfile.A2DP, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
    }

    private void processInitProfilePriorities_LeAudioOnlyHelper(
@@ -593,6 +601,120 @@ public class PhonePolicyTest {
                        eq(secondDevice), eq(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));
    }

    @Test
    public void testLateConnectOfLeAudioEnabled_AshaAndLeAudioBud() {
        mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_QUICK_LEAUDIO_TOGGLE_SWITCH_FIX);
        Utils.setDualModeAudioStateForTesting(false);
        mPhonePolicy.mLeAudioEnabledByDefault = true;
        mPhonePolicy.mAutoConnectProfilesSupported = true;

        /* Just for the moment, set to true to setup first device */
        SystemProperties.set(
                PhonePolicy.BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, Boolean.toString(true));

        int csipGroupId = 1;
        int groupSize = 2;

        List<BluetoothDevice> connectedDevices = new ArrayList<>();
        when(mCsipSetCoordinatorService.getDesiredGroupSize(csipGroupId)).thenReturn(groupSize);
        when(mCsipSetCoordinatorService.getGroupId(any(), any())).thenReturn(csipGroupId);
        when(mLeAudioService.getGroupId(any())).thenReturn(csipGroupId);
        when(mCsipSetCoordinatorService.getGroupDevicesOrdered(csipGroupId))
                .thenReturn(connectedDevices);

        // Connect first set member
        BluetoothDevice firstDevice = getTestDevice(mAdapter, 0);
        connectedDevices.add(firstDevice);

        /* Build list of test UUIDs */
        ParcelUuid[] uuids = new ParcelUuid[4];
        uuids[0] = BluetoothUuid.LE_AUDIO;
        uuids[1] = BluetoothUuid.COORDINATED_SET;
        uuids[2] = BluetoothUuid.HEARING_AID;
        uuids[3] = BluetoothUuid.HAS;

        // Prepare common handlers
        when(mHearingAidService.getConnectionPolicy(any(BluetoothDevice.class)))
                .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        when(mLeAudioService.setConnectionPolicy(
                        any(BluetoothDevice.class), eq(BluetoothProfile.CONNECTION_POLICY_ALLOWED)))
                .thenAnswer(
                        invocation -> {
                            return setLeAudioAllowedConnectionPolicy(invocation.getArgument(0));
                        });
        when(mLeAudioService.getConnectionPolicy(any(BluetoothDevice.class)))
                .thenAnswer(
                        invocation -> {
                            return getLeAudioConnectionPolicy(invocation.getArgument(0));
                        });
        when(mLeAudioService.getGroupDevices(csipGroupId)).thenReturn(connectedDevices);

        when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager);
        when(mAdapterService.getRemoteUuids(any(BluetoothDevice.class))).thenReturn(uuids);
        when(mAdapterService.isProfileSupported(
                        any(BluetoothDevice.class), eq(BluetoothProfile.HEARING_AID)))
                .thenReturn(false);
        when(mAdapterService.isProfileSupported(
                        any(BluetoothDevice.class), eq(BluetoothProfile.LE_AUDIO)))
                .thenReturn(true);

        /* Always DualMode for test purpose */
        when(mAdapterService.getRemoteType(any(BluetoothDevice.class)))
                .thenReturn(BluetoothDevice.DEVICE_TYPE_LE);

        // Inject first devices
        mPhonePolicy.onUuidsDiscovered(firstDevice, uuids);
        mPhonePolicy.profileConnectionStateChanged(
                BluetoothProfile.CSIP_SET_COORDINATOR,
                firstDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTED);
        waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

        // Verify connection policy is set properly
        verify(mLeAudioService, times(1))
                .setConnectionPolicy(
                        eq(firstDevice), eq(BluetoothProfile.CONNECTION_POLICY_ALLOWED));

        mPhonePolicy.profileActiveDeviceChanged(BluetoothProfile.LE_AUDIO, firstDevice);
        waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

        verify(mHearingAidService, times(1))
                .setConnectionPolicy(
                        eq(firstDevice), eq(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));

        /* Remove bypass and check that second set member will be added*/
        SystemProperties.set(
                PhonePolicy.BYPASS_LE_AUDIO_ALLOWLIST_PROPERTY, Boolean.toString(false));

        // Now connect second device and make sure
        // Connect first set member
        BluetoothDevice secondDevice = getTestDevice(mAdapter, 1);
        connectedDevices.add(secondDevice);

        // Inject second set member connection
        mPhonePolicy.onUuidsDiscovered(secondDevice, uuids);
        mPhonePolicy.profileConnectionStateChanged(
                BluetoothProfile.CSIP_SET_COORDINATOR,
                secondDevice,
                BluetoothProfile.STATE_DISCONNECTED,
                BluetoothProfile.STATE_CONNECTED);
        waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

        // Verify connection policy is set properly
        verify(mLeAudioService, times(1))
                .setConnectionPolicy(
                        eq(secondDevice), eq(BluetoothProfile.CONNECTION_POLICY_ALLOWED));

        mPhonePolicy.profileActiveDeviceChanged(BluetoothProfile.LE_AUDIO, secondDevice);
        waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());

        verify(mHearingAidService, times(1))
                .setConnectionPolicy(
                        eq(secondDevice), eq(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN));
    }

    /**
     * Test that when the adapter is turned ON then we call autoconnect on devices that have HFP and
     * A2DP enabled. NOTE that the assumption is that we have already done the pairing previously