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

Commit e258302c authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Maybe default speaker on wired headset disconnect

When the wired headset disconnects and the previous routing is speaker,
ensure that we route back into speaker. This has been implemented as
part of the legacy routing. Ignore this special cased routing when we're not in call.

Bug: 376364368
Flag: com.android.server.telecom.flags.default_speaker_on_wired_headset_disconnect
Test: Manual verification
Test: atest CallAudioRouteControllerTest

Change-Id: I9920d767725f018ad456356c723adbc2a503f61d
parent 1ac2e832
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -162,3 +162,14 @@ flag {
    purpose: PURPOSE_BUGFIX
  }
}

# OWNER=pmadapurmath TARGET=25Q2
flag {
  name: "default_speaker_on_wired_headset_disconnect"
  namespace: "telecom"
  description: "Maybe route back into speaker (if it was the previous route) when a wired headset disconnects"
  bug: "376364368"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+10 −1
Original line number Diff line number Diff line
@@ -655,7 +655,16 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {

        // Route to expected state
        if (mCurrentRoute.equals(wiredHeadsetRoute)) {
            routeTo(mIsActive, getBaseRoute(true, null));
            // Preserve speaker routing if it was the last audio routing path when the wired headset
            // disconnects. Ignore this special cased routing when the route isn't active
            // (in other words, when we're not in a call).
            AudioRoute route = mFeatureFlags.defaultSpeakerOnWiredHeadsetDisconnect()
                    && mIsActive && mPendingAudioRoute.getOrigRoute() != null
                    && mPendingAudioRoute.getOrigRoute().getType() == TYPE_SPEAKER
                    && mSpeakerDockRoute != null
                    && mSpeakerDockRoute.getType() == AudioRoute.TYPE_SPEAKER
                    ? mSpeakerDockRoute : getBaseRoute(true, null);
            routeTo(mIsActive, route);
        }
    }

+49 −0
Original line number Diff line number Diff line
@@ -461,6 +461,28 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
                any(CallAudioState.class), eq(expectedState));
    }

    @SmallTest
    @Test
    public void testDefaultSpeakerOnWiredHeadsetDisconnect() {
        when(mFeatureFlags.defaultSpeakerOnWiredHeadsetDisconnect()).thenReturn(true);
        mController.initialize();
        mController.setActive(true);
        verifyMaybeDefaultSpeakerOnDisconnectWiredHeadset(
                CallAudioState.ROUTE_SPEAKER /* expectedAudioType */);
    }

    @SmallTest
    @Test
    public void testIgnoreDefaultSpeakerOnWiredHeadsetDisconnect() {
        when(mFeatureFlags.defaultSpeakerOnWiredHeadsetDisconnect()).thenReturn(true);
        // Note here that the routing isn't active to represent that we're not in a call. If a wired
        // headset is disconnected and the last route was speaker, we shouldn't switch back to
        // speaker when we're not in a call.
        mController.initialize();
        verifyMaybeDefaultSpeakerOnDisconnectWiredHeadset(
                CallAudioState.ROUTE_EARPIECE /* expectedAudioType */);
    }

    @SmallTest
    @Test
    public void testConnectAndDisconnectDock() {
@@ -1332,4 +1354,31 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));
    }

    private void verifyMaybeDefaultSpeakerOnDisconnectWiredHeadset(int expectedAudioType) {
        // Ensure audio is routed to speaker initially
        mController.sendMessageWithSessionInfo(SPEAKER_ON);
        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));

        // Then simulate wired headset being connected after speaker was initially the audio route
        mController.sendMessageWithSessionInfo(CONNECT_WIRED_HEADSET);
        mController.sendMessageWithSessionInfo(SPEAKER_OFF);
        expectedState = new CallAudioState(false, CallAudioState.ROUTE_WIRED_HEADSET,
                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));

        // Verify that we route back into speaker once the wired headset disconnects
        mController.sendMessageWithSessionInfo(DISCONNECT_WIRED_HEADSET);
        expectedState = new CallAudioState(false, expectedAudioType,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));
    }
}