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

Commit 2a1b62e2 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "bt-a2dp-fix-state-machine-timeout"

* changes:
  A2DP: Make sure CONNECT_TIMEOUT is scheduled in intermediate states
  A2DP: Simplify debug log mechanism
parents 7c54c03a d278a87c
Loading
Loading
Loading
Loading
+53 −78
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ final class A2dpStateMachine extends StateMachine {
    A2dpStateMachine(BluetoothDevice device, A2dpService a2dpService,
                     A2dpNativeInterface a2dpNativeInterface, Looper looper) {
        super(TAG, looper);
        setDbg(DBG);
        mDevice = device;
        mA2dpService = a2dpService;
        mA2dpNativeInterface = a2dpNativeInterface;
@@ -115,9 +116,7 @@ final class A2dpStateMachine extends StateMachine {

    static A2dpStateMachine make(BluetoothDevice device, A2dpService a2dpService,
                                 A2dpNativeInterface a2dpNativeInterface, Looper looper) {
        if (DBG) {
            Log.d(TAG, "make for device " + device);
        }
        Log.i(TAG, "make for device " + device);
        A2dpStateMachine a2dpSm = new A2dpStateMachine(device, a2dpService, a2dpNativeInterface,
                                                       looper);
        a2dpSm.start();
@@ -125,29 +124,24 @@ final class A2dpStateMachine extends StateMachine {
    }

    public void doQuit() {
        if (DBG) {
            Log.d(TAG, "doQuit for device " + mDevice);
        }
        log("doQuit for device " + mDevice);
        quitNow();
    }

    public void cleanup() {
        if (DBG) {
            Log.d(TAG, "cleanup for device " + mDevice);
        }
        log("cleanup for device " + mDevice);
    }

    @VisibleForTesting
    class Disconnected extends State {
        @Override
        public void enter() {
            Log.i(TAG, "Enter Disconnected(" + mDevice + "): "
                    + messageWhatToString(getCurrentMessage().what));
            Message currentMessage = getCurrentMessage();
            Log.i(TAG, "Enter Disconnected(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            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
@@ -164,19 +158,16 @@ final class A2dpStateMachine extends StateMachine {

        @Override
        public void exit() {
            if (DBG) {
                Log.d(TAG, "Exit Disconnected(" + mDevice + "): "
                        + messageWhatToString(getCurrentMessage().what));
            }
            Message currentMessage = getCurrentMessage();
            log("Exit Disconnected(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_DISCONNECTED;
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) {
                Log.d(TAG, "Disconnected process message(" + mDevice + "): "
            log("Disconnected process message(" + mDevice + "): "
                    + messageWhatToString(message.what));
            }

            switch (message.what) {
                case CONNECT:
@@ -187,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);
@@ -198,9 +188,7 @@ final class A2dpStateMachine extends StateMachine {
                    break;
                case STACK_EVENT:
                    A2dpStackEvent event = (A2dpStackEvent) message.obj;
                    if (DBG) {
                        Log.d(TAG, "Disconnected: stack event: " + event);
                    }
                    log("Disconnected: stack event: " + event);
                    if (!mDevice.equals(event.device)) {
                        Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event);
                    }
@@ -263,27 +251,27 @@ final class A2dpStateMachine extends StateMachine {
    class Connecting extends State {
        @Override
        public void enter() {
            Log.i(TAG, "Enter Connecting(" + mDevice + "): "
                    + messageWhatToString(getCurrentMessage().what));
            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);
        }

        @Override
        public void exit() {
            if (DBG) {
                Log.d(TAG, "Exit Connecting(" + mDevice + "): "
                        + messageWhatToString(getCurrentMessage().what));
            }
            Message currentMessage = getCurrentMessage();
            log("Exit Connecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_CONNECTING;
            removeMessages(CONNECT_TIMEOUT);
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) {
                Log.d(TAG, "Connecting process message(" + mDevice + "): "
            log("Connecting process message(" + mDevice + "): "
                    + messageWhatToString(message.what));
            }

            switch (message.what) {
                case CONNECT:
@@ -307,9 +295,7 @@ final class A2dpStateMachine extends StateMachine {
                    break;
                case STACK_EVENT:
                    A2dpStackEvent event = (A2dpStackEvent) message.obj;
                    if (DBG) {
                        Log.d(TAG, "Connecting: stack event: " + event);
                    }
                    log("Connecting: stack event: " + event);
                    if (!mDevice.equals(event.device)) {
                        Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event);
                    }
@@ -360,27 +346,27 @@ final class A2dpStateMachine extends StateMachine {
    class Disconnecting extends State {
        @Override
        public void enter() {
            Log.i(TAG, "Enter Disconnecting(" + mDevice + "): "
                    + messageWhatToString(getCurrentMessage().what));
            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);
        }

        @Override
        public void exit() {
            if (DBG) {
                Log.d(TAG, "Exit Disconnecting(" + mDevice + "): "
                        + messageWhatToString(getCurrentMessage().what));
            }
            Message currentMessage = getCurrentMessage();
            log("Exit Disconnecting(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_DISCONNECTING;
            removeMessages(CONNECT_TIMEOUT);
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) {
                Log.d(TAG, "Disconnecting process message(" + mDevice + "): "
            log("Disconnecting process message(" + mDevice + "): "
                    + messageWhatToString(message.what));
            }

            switch (message.what) {
                case CONNECT:
@@ -401,9 +387,7 @@ final class A2dpStateMachine extends StateMachine {
                    break;
                case STACK_EVENT:
                    A2dpStackEvent event = (A2dpStackEvent) message.obj;
                    if (DBG) {
                        Log.d(TAG, "Disconnecting: stack event: " + event);
                    }
                    log("Disconnecting: stack event: " + event);
                    if (!mDevice.equals(event.device)) {
                        Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event);
                    }
@@ -467,13 +451,12 @@ final class A2dpStateMachine extends StateMachine {
    class Connected extends State {
        @Override
        public void enter() {
            Log.i(TAG, "Enter Connected(" + mDevice + "): "
                    + messageWhatToString(getCurrentMessage().what));
            Message currentMessage = getCurrentMessage();
            Log.i(TAG, "Enter Connected(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            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
@@ -483,19 +466,15 @@ final class A2dpStateMachine extends StateMachine {

        @Override
        public void exit() {
            if (DBG) {
                Log.d(TAG, "Exit Connected(" + mDevice + "): "
                        + messageWhatToString(getCurrentMessage().what));
            }
            Message currentMessage = getCurrentMessage();
            log("Exit Connected(" + mDevice + "): " + (currentMessage == null ? "null"
                    : messageWhatToString(currentMessage.what)));
            mLastConnectionState = BluetoothProfile.STATE_CONNECTED;
        }

        @Override
        public boolean processMessage(Message message) {
            if (DBG) {
                Log.d(TAG, "Connected process message(" + mDevice + "): "
                        + messageWhatToString(message.what));
            }
            log("Connected process message(" + mDevice + "): " + messageWhatToString(message.what));

            switch (message.what) {
                case CONNECT:
@@ -512,15 +491,9 @@ 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;
                    if (DBG) {
                        Log.d(TAG, "Connected: stack event: " + event);
                    }
                    log("Connected: stack event: " + event);
                    if (!mDevice.equals(event.device)) {
                        Log.wtfStack(TAG, "Device(" + mDevice + "): event mismatch: " + event);
                    }
@@ -657,10 +630,8 @@ final class A2dpStateMachine extends StateMachine {

    // This method does not check for error conditon (newState == prevState)
    private void broadcastConnectionState(int newState, int prevState) {
        if (DBG) {
            Log.d(TAG, "Connection state " + mDevice + ": " + profileStateToString(prevState)
        log("Connection state " + mDevice + ": " + profileStateToString(prevState)
                    + "->" + profileStateToString(newState));
        }

        Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
@@ -672,11 +643,8 @@ final class A2dpStateMachine extends StateMachine {
    }

    private void broadcastAudioState(int newState, int prevState) {
        if (DBG) {
            Log.d(TAG, "A2DP Playing state : device: " + mDevice + " State:"
                    + audioStateToString(prevState) + "->"
                    + audioStateToString(newState));
        }
        log("A2DP Playing state : device: " + mDevice + " State:" + audioStateToString(prevState)
                + "->" + audioStateToString(newState));

        Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
@@ -768,4 +736,11 @@ final class A2dpStateMachine extends StateMachine {
        }
        scanner.close();
    }

    @Override
    protected void log(String msg) {
        if (DBG) {
            super.log(msg);
        }
    }
}
+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));
    }
}