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

Commit 3f0f10cb authored by Hall Liu's avatar Hall Liu Committed by android-build-merger
Browse files

Merge "Reconnect to Bluetooth if user switches back to it"

am: c3a3cad7

Change-Id: I9c7fb8954f1ed997107482a1cbc1f64ef068a33f
parents b6ebc401 c3a3cad7
Loading
Loading
Loading
Loading
+8 −14
Original line number Diff line number Diff line
@@ -265,7 +265,6 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    } else {
                        removedRoutes |= ROUTE_BLUETOOTH;
                    }
                    // TODO: update in-call app on the list of BT devices.
                    isHandled = HANDLED;
                    break;
                case SWITCH_BASELINE_ROUTE:
@@ -276,6 +275,10 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    sendInternalMessage(calculateBaselineRouteMessage(true,
                            msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE));
                    return HANDLED;
                case USER_SWITCH_BLUETOOTH:
                    // If the user tries to switch to BT, reset the explicitly-switched-away flag.
                    mHasUserExplicitlyLeftBluetooth = false;
                    return NOT_HANDLED;
                case SWITCH_FOCUS:
                    mAudioFocusType = msg.arg1;
                    return NOT_HANDLED;
@@ -283,10 +286,12 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    return NOT_HANDLED;
            }

            if (addedRoutes != 0 || removedRoutes != 0) {
            if (addedRoutes != 0 || removedRoutes != 0
                    || msg.what == BLUETOOTH_DEVICE_LIST_CHANGED) {
                mAvailableRoutes = modifyRoutes(mAvailableRoutes, removedRoutes, addedRoutes, true);
                mDeviceSupportedRoutes = modifyRoutes(mDeviceSupportedRoutes, removedRoutes,
                        addedRoutes, false);
                updateSystemAudioState();
            }

            return isHandled;
@@ -467,18 +472,15 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    } else {
                        Log.i(this, "Not switching to BT route from earpiece because user has " +
                                "explicitly disconnected.");
                        updateSystemAudioState();
                    }
                    return HANDLED;
                case DISCONNECT_BLUETOOTH:
                    updateSystemAudioState();
                    // No change in audio route required
                    return HANDLED;
                case DISCONNECT_WIRED_HEADSET:
                    Log.e(this, new IllegalStateException(),
                            "Wired headset should not go from connected to not when on " +
                            "earpiece");
                    updateSystemAudioState();
                    return HANDLED;
                case BT_AUDIO_DISCONNECTED:
                    // This may be sent as a confirmation by the BT stack after switch off BT.
@@ -657,8 +659,6 @@ public class CallAudioRouteStateMachine extends StateMachine {
                case CONNECT_WIRED_HEADSET:
                    Log.e(this, new IllegalStateException(),
                            "Wired headset should already be connected.");
                    mAvailableRoutes |= ROUTE_WIRED_HEADSET;
                    updateSystemAudioState();
                    return HANDLED;
                case CONNECT_BLUETOOTH:
                    if (!mHasUserExplicitlyLeftBluetooth) {
@@ -666,11 +666,9 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    } else {
                        Log.i(this, "Not switching to BT route from headset because user has " +
                                "explicitly disconnected.");
                        updateSystemAudioState();
                    }
                    return HANDLED;
                case DISCONNECT_BLUETOOTH:
                    updateSystemAudioState();
                    // No change in audio route required
                    return HANDLED;
                case DISCONNECT_WIRED_HEADSET:
@@ -975,7 +973,6 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    mWasOnSpeaker = false;
                    return HANDLED;
                case DISCONNECT_WIRED_HEADSET:
                    updateSystemAudioState();
                    // No change in audio route required
                    return HANDLED;
                case CONNECT_DOCK:
@@ -1009,7 +1006,7 @@ public class CallAudioRouteStateMachine extends StateMachine {
            setBluetoothOff();
            CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_SPEAKER,
                    mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices());
            setSystemAudioState(newState);
            setSystemAudioState(newState, true);
            updateInternalCallAudioState();
        }

@@ -1175,15 +1172,12 @@ public class CallAudioRouteStateMachine extends StateMachine {
                    } else {
                        Log.i(this, "Not switching to BT route from speaker because user has " +
                                "explicitly disconnected.");
                        updateSystemAudioState();
                    }
                    return HANDLED;
                case DISCONNECT_BLUETOOTH:
                    updateSystemAudioState();
                    // No change in audio route required
                    return HANDLED;
                case DISCONNECT_WIRED_HEADSET:
                    updateSystemAudioState();
                    // No change in audio route required
                    return HANDLED;
                case BT_AUDIO_DISCONNECTED:
+97 −9
Original line number Diff line number Diff line
@@ -45,9 +45,11 @@ import org.mockito.stubbing.Answer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.same;
@@ -229,10 +231,11 @@ public class CallAudioRouteStateMachineTest
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        verifyNewSystemCallAudioState(initState, expectedMiddleState);
        resetMocks(true);
        resetMocks();

        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET);
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        verifyNewSystemCallAudioState(expectedMiddleState, initState);
    }

@@ -267,7 +270,7 @@ public class CallAudioRouteStateMachineTest

        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        verifyNewSystemCallAudioState(initState, expectedEndState);
        resetMocks(false);
        resetMocks();
        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH);
        stateMachine.sendMessageWithSessionInfo(
@@ -277,6 +280,77 @@ public class CallAudioRouteStateMachineTest
        assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState());
    }

    @MediumTest
    public void testUserBluetoothSwitchOffAndOnAgain() {
        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
                mContext,
                mockCallsManager,
                mockBluetoothRouteManager,
                mockWiredHeadsetManager,
                mockStatusBarNotifier,
                mAudioServiceFactory,
                true);
        Collection<BluetoothDevice> availableDevices = Collections.singleton(bluetoothDevice1);

        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
        when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices);

        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
        stateMachine.initialize(initState);

        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
                CallAudioRouteStateMachine.ACTIVE_FOCUS);
        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);

        // Switch off the BT route explicitly.
        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE,
                CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE);
        CallAudioState expectedMidState = new CallAudioState(false,
                CallAudioState.ROUTE_EARPIECE,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH,
                null, availableDevices);

        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        verifyNewSystemCallAudioState(initState, expectedMidState);
        resetMocks();

        // Now, switch back to BT explicitly
        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
        when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices);
        doAnswer(invocation -> {
            when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice())
                    .thenReturn(bluetoothDevice1);
            stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);
            return null;
        }).when(mockBluetoothRouteManager).connectBluetoothAudio(nullable(String.class));
        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.USER_SWITCH_BLUETOOTH);
        CallAudioState expectedEndState = new CallAudioState(false,
                CallAudioState.ROUTE_BLUETOOTH,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH,
                bluetoothDevice1, availableDevices);
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        // second wait needed for the BT_AUDIO_CONNECTED message
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        verifyNewSystemCallAudioState(expectedMidState, expectedEndState);

        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH);
        when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice())
                .thenReturn(null);
        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.CONNECT_BLUETOOTH);

        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        // second wait needed for the BT_AUDIO_CONNECTED message
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
        // Verify that we're still on bluetooth.
        assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState());
    }

    @MediumTest
    public void testBluetoothRinging() {
        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
@@ -320,7 +394,7 @@ public class CallAudioRouteStateMachineTest
                mockStatusBarNotifier,
                mAudioServiceFactory,
                true);

        setInBandRing(false);
        when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(false);
        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
@@ -330,15 +404,23 @@ public class CallAudioRouteStateMachineTest

        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
                CallAudioRouteStateMachine.RINGING_FOCUS);
        // Wait for the state machine to finish transiting to ActiveEarpiece before hooking up
        // bluetooth mocks
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);

        when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
        when(mockBluetoothRouteManager.getConnectedDevices())
                .thenReturn(Collections.singletonList(bluetoothDevice1));
        stateMachine.sendMessageWithSessionInfo(
                CallAudioRouteStateMachine.BLUETOOTH_DEVICE_LIST_CHANGED);
        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);

        verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(null);
        CallAudioState expectedEndState = new CallAudioState(false,
                CallAudioState.ROUTE_BLUETOOTH,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH,
                null, Collections.singletonList(bluetoothDevice1));
        verifyNewSystemCallAudioState(initState, expectedEndState);

        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
@@ -879,7 +961,7 @@ public class CallAudioRouteStateMachineTest

    private void runParametrizedTestCaseWithFocus(final RoutingTestParameters params)
            throws Throwable {
        resetMocks(true);
        resetMocks();

        // Construct a fresh state machine on every case
        final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
@@ -908,7 +990,7 @@ public class CallAudioRouteStateMachineTest
        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);

        // Reset mocks one more time to discard stuff from initialization
        resetMocks(false);
        resetMocks();
        setupMocksForParams(stateMachine, params);
        stateMachine.sendMessageWithSessionInfo(params.action);

@@ -984,7 +1066,7 @@ public class CallAudioRouteStateMachineTest

    private void runParametrizedTestCaseWithoutFocus(final RoutingTestParameters params)
            throws Throwable {
        resetMocks(true);
        resetMocks();

        // Construct a fresh state machine on every case
        final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
@@ -1050,12 +1132,18 @@ public class CallAudioRouteStateMachineTest
        verify(mockConnectionServiceWrapper, timeout(TEST_TIMEOUT).atLeastOnce())
                .onCallAudioStateChanged(same(fakeCall), newStateCaptor2.capture());

        assertTrue(oldStateCaptor.getValue().equals(expectedOldState));
        assertTrue(oldStateCaptor.getAllValues().get(0).equals(expectedOldState));
        assertTrue(newStateCaptor1.getValue().equals(expectedNewState));
        assertTrue(newStateCaptor2.getValue().equals(expectedNewState));
    }

    private void resetMocks(boolean resetNotificationFilter) {
    private void setInBandRing(boolean enabled) {
        mComponentContextFixture.putBooleanResource(
                com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support,
                enabled);
    }

    private void resetMocks() {
        reset(mockAudioManager, mockBluetoothRouteManager, mockCallsManager,
                mockConnectionServiceWrapper, fakeCall);
        when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);