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

Commit 8b42e103 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Upstream - Handling Audio Disconnect Timeout"

parents 21a51725 d87abbe3
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -114,6 +114,10 @@ public class HeadsetStateMachine extends StateMachine {
    // NOTE: the value is not "final" - it is modified in the unit tests
    @VisibleForTesting static int sConnectTimeoutMs = 30000;

    // Number of times we should retry disconnecting audio before
    // disconnecting the device.
    private static final int MAX_RETRY_DISCONNECT_AUDIO = 3;

    private static final HeadsetAgIndicatorEnableState DEFAULT_AG_INDICATOR_ENABLE_STATE =
            new HeadsetAgIndicatorEnableState(true, true, true, true);

@@ -149,6 +153,8 @@ public class HeadsetStateMachine extends StateMachine {
    private final AtPhonebook mPhonebook;
    // HSP specific
    private boolean mNeedDialingOutReply;
    // Audio disconnect timeout retry count
    private int mAudioDisconnectRetry = 0;

    // Keys are AT commands, and values are the company IDs.
    private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;
@@ -1042,6 +1048,10 @@ public class HeadsetStateMachine extends StateMachine {
                // state. This is to prevent auto connect attempts from disconnecting
                // devices that previously successfully connected.
                removeDeferredMessages(CONNECT);
            } else if (mPrevState == mAudioDisconnecting) {
                // Reset audio disconnecting retry count. Either the disconnection was successful
                // or the retry count reached MAX_RETRY_DISCONNECT_AUDIO.
                mAudioDisconnectRetry = 0;
            }
            broadcastStateTransitions();
        }
@@ -1283,7 +1293,7 @@ public class HeadsetStateMachine extends StateMachine {
                        stateLogW("CONNECT_AUDIO device is not connected " + device);
                        break;
                    }
                    stateLogW("CONNECT_AUDIO device auido is already connected " + device);
                    stateLogW("CONNECT_AUDIO device audio is already connected " + device);
                    break;
                }
                case DISCONNECT_AUDIO: {
@@ -1385,8 +1395,18 @@ public class HeadsetStateMachine extends StateMachine {
                        stateLogW("CONNECT_TIMEOUT for unknown device " + device);
                        break;
                    }
                    stateLogW("CONNECT_TIMEOUT");
                    if (mAudioDisconnectRetry == MAX_RETRY_DISCONNECT_AUDIO) {
                        stateLogW("CONNECT_TIMEOUT: Disconnecting device");
                        // Restoring state to Connected with message DISCONNECT
                        deferMessage(obtainMessage(DISCONNECT, mDevice));
                        transitionTo(mConnected);
                    } else {
                        mAudioDisconnectRetry += 1;
                        stateLogW("CONNECT_TIMEOUT: retrying "
                                + (MAX_RETRY_DISCONNECT_AUDIO - mAudioDisconnectRetry)
                                + " more time(s)");
                        transitionTo(mAudioOn);
                    }
                    break;
                }
                default:
@@ -1407,6 +1427,8 @@ public class HeadsetStateMachine extends StateMachine {
                    break;
                case HeadsetHalConstants.AUDIO_STATE_CONNECTED:
                    stateLogW("processAudioEvent: audio disconnection failed");
                    // Audio connected, resetting disconnect retry.
                    mAudioDisconnectRetry = 0;
                    transitionTo(mAudioOn);
                    break;
                case HeadsetHalConstants.AUDIO_STATE_CONNECTING:
+41 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.bluetooth.hfp;

import static android.Manifest.permission.BLUETOOTH_CONNECT;

import static org.mockito.Mockito.*;

import android.bluetooth.BluetoothAdapter;
@@ -69,6 +70,7 @@ public class HeadsetStateMachineTest {
    private static final int CONNECT_TIMEOUT_TEST_WAIT_MILLIS = CONNECT_TIMEOUT_TEST_MILLIS * 3 / 2;
    private static final int ASYNC_CALL_TIMEOUT_MILLIS = 250;
    private static final String TEST_PHONE_NUMBER = "1234567890";
    private static final int MAX_RETRY_DISCONNECT_AUDIO = 3;
    private Context mTargetContext;
    private BluetoothAdapter mAdapter;
    private HandlerThread mHandlerThread;
@@ -742,23 +744,50 @@ public class HeadsetStateMachineTest {
    }

    /**
     * Test state transition from AudioDisconnecting to Connected state via
     * CONNECT_TIMEOUT message
     * Test state transition from AudioDisconnecting to AudioOn state via CONNECT_TIMEOUT message
     * until retry count is reached, then test transition to Disconnecting state.
     */
    @Test
    public void testStateTransition_AudioDisconnectingToConnected_Timeout() {
    public void testStateTransition_AudioDisconnectingToAudioOnAndDisconnecting_Timeout() {
        int numBroadcastsSent = setUpAudioDisconnectingState();
        // Wait for connection to timeout
        numBroadcastsSent++;
        for (int i = 0; i <= MAX_RETRY_DISCONNECT_AUDIO; i++) {
            if (i > 0) { // Skip first AUDIO_DISCONNECTING init as it was setup before the loop
                mHeadsetStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO, mTestDevice);
                // No new broadcast due to lack of AUDIO_DISCONNECTING intent variable
                verify(mHeadsetService, after(ASYNC_CALL_TIMEOUT_MILLIS)
                        .times(numBroadcastsSent)).sendBroadcastAsUser(
                        any(Intent.class), eq(UserHandle.ALL), eq(BLUETOOTH_CONNECT),
                        any(Bundle.class));
                Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
                        IsInstanceOf.instanceOf(HeadsetStateMachine.AudioDisconnecting.class));
                if (i == MAX_RETRY_DISCONNECT_AUDIO) {
                    // Increment twice numBroadcastsSent as DISCONNECT message is added on max retry
                    numBroadcastsSent += 2;
                } else {
                    numBroadcastsSent++;
                }
            }
            verify(mHeadsetService, timeout(CONNECT_TIMEOUT_TEST_WAIT_MILLIS).times(
                    numBroadcastsSent)).sendBroadcastAsUser(mIntentArgument.capture(),
                eq(UserHandle.ALL), eq(BLUETOOTH_CONNECT),
                any(Bundle.class));
                    eq(UserHandle.ALL), eq(BLUETOOTH_CONNECT), any(Bundle.class));
            if (i < MAX_RETRY_DISCONNECT_AUDIO) { // Test if state is AudioOn before max retry
                HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
                BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
                        BluetoothHeadset.STATE_AUDIO_CONNECTED,
                        BluetoothHeadset.STATE_AUDIO_CONNECTED,
                        mIntentArgument.getValue());
                Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
                IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
                        IsInstanceOf.instanceOf(HeadsetStateMachine.AudioOn.class));
            } else { // Max retry count reached, test Disconnecting state
                HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
                        BluetoothHeadset.STATE_DISCONNECTING,
                        BluetoothHeadset.STATE_CONNECTED,
                        mIntentArgument.getValue());
                Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
                        IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
            }
        }
    }

    /**