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

Commit ca8aac2c authored by Grzegorz Kołodziejczyk's avatar Grzegorz Kołodziejczyk
Browse files

le_audio: ignore connect events in connecting state

After bonding the enabled profiles are connected automatically:

BluetoothAdapterService: connectEnabledProfiles: Connecting LeAudio
and this may happen multiple times. Additionally during testing
LeAudioService::connect() may be invoked causing 2 redundant connect
calls that happen in Connecting state of the LeAudio state machine.
The events are then deferred, and on any failure and the state change to
Disconnected they are being invoked again in Disconnected state.

Bug: 381200144
Bug: 384460395
Flag: com.android.bluetooth.flags.leaudio_sm_ignore_connect_events_in_connecting_state
Test: atest LeAudioStateMachine
Change-Id: I97231165e097d701c4f1b26f307d41713967b96c
parent aae2d3c1
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.os.Message;
import android.util.Log;

import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -276,7 +277,12 @@ final class LeAudioStateMachine extends StateMachine {

            switch (message.what) {
                case CONNECT:
                    if (Flags.leaudioSmIgnoreConnectEventsInConnectingState()
                            && !hasDeferredMessages(DISCONNECT)) {
                        Log.w(TAG, "Connecting: CONNECT ignored: " + mDevice);
                    } else {
                        deferMessage(message);
                    }
                    break;
                case CONNECT_TIMEOUT:
                    Log.w(TAG, "Connecting connection timeout: " + mDevice);
+44 −0
Original line number Diff line number Diff line
@@ -17,6 +17,9 @@

package com.android.bluetooth.le_audio;

import static com.android.bluetooth.le_audio.LeAudioStateMachine.CONNECT;
import static com.android.bluetooth.le_audio.LeAudioStateMachine.DISCONNECT;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.after;
@@ -34,12 +37,15 @@ import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Bundle;
import android.os.HandlerThread;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;

import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.flags.Flags;

import org.junit.After;
import org.junit.Before;
@@ -60,6 +66,7 @@ public class LeAudioStateMachineTest {
    private static final int TIMEOUT_MS = 1000;

    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Mock private AdapterService mAdapterService;
    @Mock private LeAudioService mLeAudioService;
@@ -232,4 +239,41 @@ public class LeAudioStateMachineTest {
        assertThat(mLeAudioStateMachine.getCurrentState())
                .isInstanceOf(LeAudioStateMachine.Disconnected.class);
    }

    private void sendAndDispatchMessage(int what, Object obj) {
        mLeAudioStateMachine.sendMessage(what, obj);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
    }

    @Test
    @EnableFlags(Flags.FLAG_LEAUDIO_SM_IGNORE_CONNECT_EVENTS_IN_CONNECTING_STATE)
    public void connectEventNeglectedWhileInConnectingState() {
        allowConnection(true);
        doReturn(true).when(mLeAudioNativeInterface).connectLeAudio(any(BluetoothDevice.class));
        doReturn(true).when(mLeAudioNativeInterface).disconnectLeAudio(any(BluetoothDevice.class));

        sendAndDispatchMessage(CONNECT, mTestDevice);
        // Verify that one connection state change is notified
        verify(mLeAudioService, timeout(TIMEOUT_MS))
                .notifyConnectionStateChanged(
                        any(),
                        eq(BluetoothProfile.STATE_CONNECTING),
                        eq(BluetoothProfile.STATE_DISCONNECTED));
        assertThat(mLeAudioStateMachine.getCurrentState())
                .isInstanceOf(LeAudioStateMachine.Connecting.class);

        // Dispatch CONNECT event twice more
        sendAndDispatchMessage(CONNECT, mTestDevice);
        sendAndDispatchMessage(CONNECT, mTestDevice);
        sendAndDispatchMessage(DISCONNECT, mTestDevice);
        // Verify that one connection state change is notified
        verify(mLeAudioService, timeout(TIMEOUT_MS))
                .notifyConnectionStateChanged(
                        any(),
                        eq(BluetoothProfile.STATE_DISCONNECTED),
                        eq(BluetoothProfile.STATE_CONNECTING));
        assertThat(mLeAudioStateMachine.getCurrentState())
                .isInstanceOf(LeAudioStateMachine.Disconnected.class);
        TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
    }
}