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

Commit 3941192a authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Fix speakerphone logic when connecting/disconnecting dock.

The previous Telecom logic enabled speakerphone in the base speaker state,
which meant that both Quiescent and Active speaker state would result in
the global speaker state changing.

Moved logic to enable speakerphone to the ActiveSpeakerState.
When dock connects/disconnects while in QuiescentEarpieceState, switch to
QuiescentSpeakerState to ensure when a call starts we CAN use the speaker.

Also, added some better logging in CallAudioRouteStateMachine so we can
see the current state in the telecom dumpsys.

Test: Added CallAudioRouteStateMachineTest#testDockWhenInQuiescentState which verifies connect/disconnect dock behavior while idle does not activate speaker phone.
Test: Added CallAudioRouteTransitionTests to verify correct audio mode transitions when docking/undocking.
Test: Manual test; ran adb shell dumpsys DockObserver set state 3 while idle and verified that telecom dumpsys reports QuiesecentSpeakerState.
Test: Manual test; ran adb shell dumpsys DockObserver set state 0 while idle and verified telecom dumpsys reports QuiescentEarpiece state.
Test: Manual test; start call, ran adb shell dumpsys DockObserver set state 3 to enter dock; verified call enters speaker.
Test: Manual test; from previous manual test ran adb shell dumpsys DockObserver set state 0 to exist dock.  Verified call leaves speaker state.
Fixes: 227560170
Change-Id: I409a49a2b75ea72f558ba5ed8906f1bcd2e82de3
parent e3dfe2d9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -542,9 +542,9 @@ public class CallAudioManager extends CallsManagerListenerBase {
        mCallAudioModeStateMachine.dump(pw);
        pw.decreaseIndent();

        pw.println("CallAudioRouteStateMachine pending messages:");
        pw.println("CallAudioRouteStateMachine:");
        pw.increaseIndent();
        mCallAudioRouteStateMachine.dumpPendingMessages(pw);
        mCallAudioRouteStateMachine.dump(pw);
        pw.decreaseIndent();

        pw.println("BluetoothDeviceManager:");
+15 −4
Original line number Diff line number Diff line
@@ -411,6 +411,8 @@ public class CallAudioRouteStateMachine extends StateMachine {
                        Log.w(this, "Ignoring switch to headset command. Not available.");
                    }
                    return HANDLED;
                case CONNECT_DOCK:
                    // fall through; we want to switch to speaker mode when docked and in a call.
                case SWITCH_SPEAKER:
                case USER_SWITCH_SPEAKER:
                    setSpeakerphoneOn(true);
@@ -486,6 +488,8 @@ public class CallAudioRouteStateMachine extends StateMachine {
                        Log.w(this, "Ignoring switch to headset command. Not available.");
                    }
                    return HANDLED;
                case CONNECT_DOCK:
                    // fall through; we want to go to the quiescent speaker route when out of a call
                case SWITCH_SPEAKER:
                case USER_SWITCH_SPEAKER:
                    transitionTo(mQuiescentSpeakerRoute);
@@ -537,10 +541,6 @@ public class CallAudioRouteStateMachine extends StateMachine {
                case BT_AUDIO_DISCONNECTED:
                    // This may be sent as a confirmation by the BT stack after switch off BT.
                    return HANDLED;
                case CONNECT_DOCK:
                    setSpeakerphoneOn(true);
                    sendInternalMessage(SWITCH_SPEAKER);
                    return HANDLED;
                case DISCONNECT_DOCK:
                    // Nothing to do here
                    return HANDLED;
@@ -1273,6 +1273,8 @@ public class CallAudioRouteStateMachine extends StateMachine {
                case SPEAKER_ON:
                    // Nothing to do
                    return HANDLED;
                case DISCONNECT_DOCK:
                    // Fall-through; same as if speaker goes off, we want to switch baseline.
                case SPEAKER_OFF:
                    sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
                    return HANDLED;
@@ -1619,6 +1621,15 @@ public class CallAudioRouteStateMachine extends StateMachine {
        quitNow();
    }

    public void dump(IndentingPrintWriter pw) {
        pw.print("Current state: ");
        pw.println(getCurrentState().getName());
        pw.println("Pending messages:");
        pw.increaseIndent();
        dumpPendingMessages(pw);
        pw.decreaseIndent();
    }

    public void dumpPendingMessages(IndentingPrintWriter pw) {
        getHandler().getLooper().dump(pw::println, "");
    }
+6 −1
Original line number Diff line number Diff line
@@ -29,7 +29,12 @@ import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/** Listens for and caches car dock state. */
/**
 * Listens for and caches car dock state.
 * Testing; you can enable/disable dock with adb commands:
 *   adb shell dumpsys DockObserver set state 3
 *   adb shell dumpsys DockObserver set state 0
 */
@VisibleForTesting
public class DockManager {
    @VisibleForTesting
+31 −0
Original line number Diff line number Diff line
@@ -503,6 +503,37 @@ public class CallAudioRouteStateMachineTest extends TelecomTestCase {
        verifyNewSystemCallAudioState(initState, expectedEndState);
    }

    @SmallTest
    @Test
    public void testDockWhenInQuiescentState() {
        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
                mContext,
                mockCallsManager,
                mockBluetoothRouteManager,
                mockWiredHeadsetManager,
                mockStatusBarNotifier,
                mAudioServiceFactory,
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
                mThreadHandler.getLooper());
        stateMachine.setCallAudioManager(mockCallAudioManager);
        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
        stateMachine.initialize(initState);

        // Raise a dock connect event.
        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_DOCK);
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        assertTrue(!stateMachine.isInActiveState());
        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(true));

        // Raise a dock disconnect event.
        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.DISCONNECT_DOCK);
        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
        assertTrue(!stateMachine.isInActiveState());
        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(false));
    }

    @SmallTest
    @Test
    public void testFocusChangeFromQuiescentSpeaker() {
+24 −0
Original line number Diff line number Diff line
@@ -823,6 +823,30 @@ public class CallAudioRouteTransitionTests extends TelecomTestCase {
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
        ));

        params.add(new RoutingTestParameters(
                "Connect dock from earpiece", // name
                CallAudioState.ROUTE_EARPIECE, // initialRoute
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
                ON, // speakerInteraction
                NONE, // bluetoothInteraction
                CallAudioRouteStateMachine.CONNECT_DOCK, // action
                CallAudioState.ROUTE_SPEAKER, // expectedRoute
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
        ));

        params.add(new RoutingTestParameters(
                "Disconnect dock from speaker", // name
                CallAudioState.ROUTE_SPEAKER, // initialRoute
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
                OFF, // speakerInteraction
                NONE, // bluetoothInteraction
                CallAudioRouteStateMachine.DISCONNECT_DOCK, // action
                CallAudioState.ROUTE_EARPIECE, // expectedRoute
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
        ));

        return params;
    }