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

Commit d278a87c authored by Jack He's avatar Jack He
Browse files

A2DP: Make sure CONNECT_TIMEOUT is scheduled in intermediate states

* Always schedule CONNECT_TIMEOUT message when entering Connecting and
  Disconnecting state
* Always remove CONNECT_TIMEOUT message when exting Connecting and
  Disconnecting state
* Add testIncomingTimeout in A2dpStateMachineTest to verify that an
  incoming connecting request could timeout as well

Bug: 73899051
Test: connect and disconnect to A2dp devices
      runtest -j32 bluetooth -c com.android.bluetooth.a2dp.A2dpStateMachineTest

Change-Id: I4412c77c8395a1ede12d7c1bd071822e55f5dd9c
parent b10d00f9
Loading
Loading
Loading
Loading
+4 −9
Original line number Diff line number Diff line
@@ -142,8 +142,6 @@ final class A2dpStateMachine extends StateMachine {
            mConnectionState = BluetoothProfile.STATE_DISCONNECTED;

            removeDeferredMessages(DISCONNECT);
            // Remove Timeout messages when moved to stable state
            removeMessages(CONNECT_TIMEOUT);

            if (mLastConnectionState != -1) {
                // Don't broadcast during startup
@@ -180,7 +178,6 @@ final class A2dpStateMachine extends StateMachine {
                    }
                    if (mA2dpService.okToConnect(mDevice)) {
                        transitionTo(mConnecting);
                        sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs);
                    } else {
                        // Reject the request and stay in Disconnected state
                        Log.w(TAG, "Outgoing A2DP Connecting request rejected: " + mDevice);
@@ -257,6 +254,7 @@ final class A2dpStateMachine extends StateMachine {
            Message currentMessage = getCurrentMessage();
            Log.i(TAG, "Enter Connecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs);
            mConnectionState = BluetoothProfile.STATE_CONNECTING;
            broadcastConnectionState(mConnectionState, mLastConnectionState);
        }
@@ -267,6 +265,7 @@ final class A2dpStateMachine extends StateMachine {
            log("Exit Connecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_CONNECTING;
            removeMessages(CONNECT_TIMEOUT);
        }

        @Override
@@ -350,6 +349,7 @@ final class A2dpStateMachine extends StateMachine {
            Message currentMessage = getCurrentMessage();
            Log.i(TAG, "Enter Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            sendMessageDelayed(CONNECT_TIMEOUT, sConnectTimeoutMs);
            mConnectionState = BluetoothProfile.STATE_DISCONNECTING;
            broadcastConnectionState(mConnectionState, mLastConnectionState);
        }
@@ -360,6 +360,7 @@ final class A2dpStateMachine extends StateMachine {
            log("Exit Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING;
            removeMessages(CONNECT_TIMEOUT);
        }

        @Override
@@ -456,8 +457,6 @@ final class A2dpStateMachine extends StateMachine {
            mConnectionState = BluetoothProfile.STATE_CONNECTED;

            removeDeferredMessages(CONNECT);
            // Remove Timeout messages when moved to stable state
            removeMessages(CONNECT_TIMEOUT);

            broadcastConnectionState(mConnectionState, mLastConnectionState);
            // Upon connected, the audio starts out as stopped
@@ -492,10 +491,6 @@ final class A2dpStateMachine extends StateMachine {
                    transitionTo(mDisconnecting);
                }
                break;
                case CONNECT_TIMEOUT:
                    // Ignore - nothing to timeout. We are already connected.
                    Log.w(TAG, "Connected: CONNECT_TIMEOUT ignored: " + mDevice);
                    break;
                case STACK_EVENT:
                    A2dpStackEvent event = (A2dpStackEvent) message.obj;
                    log("Connected: stack event: " + event);
+39 −0
Original line number Diff line number Diff line
@@ -215,4 +215,43 @@ public class A2dpStateMachineTest {
        Assert.assertThat(mA2dpStateMachine.getCurrentState(),
                          IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class));
    }

    /**
     * Test that an incoming connection times out
     */
    @Test
    public void testIncomingTimeout() {
        allowConnection(true);
        doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
        doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));

        // Inject an event for when incoming connection is requested
        A2dpStackEvent connStCh =
                new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
        connStCh.device = mTestDevice;
        connStCh.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTING;
        mA2dpStateMachine.sendMessage(A2dpStateMachine.STACK_EVENT, connStCh);

        // Verify that one connection state broadcast is executed
        ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
        verify(mA2dpService, timeout(TIMEOUT_MS).times(1)).sendBroadcast(intentArgument1.capture(),
                anyString());
        Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
                intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));

        // Check that we are in Connecting state
        Assert.assertThat(mA2dpStateMachine.getCurrentState(),
                IsInstanceOf.instanceOf(A2dpStateMachine.Connecting.class));

        // Verify that one connection state broadcast is executed
        ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class);
        verify(mA2dpService, timeout(A2dpStateMachine.sConnectTimeoutMs * 2).times(
                2)).sendBroadcast(intentArgument2.capture(), anyString());
        Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
                intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));

        // Check that we are in Disconnected state
        Assert.assertThat(mA2dpStateMachine.getCurrentState(),
                IsInstanceOf.instanceOf(A2dpStateMachine.Disconnected.class));
    }
}