Loading src/com/android/server/telecom/CallAudioManager.java +5 −5 Original line number Diff line number Diff line Loading @@ -321,23 +321,23 @@ public class CallAudioManager extends CallsManagerListenerBase { switch (route) { case CallAudioState.ROUTE_BLUETOOTH: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_BLUETOOTH); CallAudioRouteStateMachine.USER_SWITCH_BLUETOOTH); return; case CallAudioState.ROUTE_SPEAKER: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_SPEAKER); CallAudioRouteStateMachine.USER_SWITCH_SPEAKER); return; case CallAudioState.ROUTE_WIRED_HEADSET: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_HEADSET); CallAudioRouteStateMachine.USER_SWITCH_HEADSET); return; case CallAudioState.ROUTE_EARPIECE: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_EARPIECE); CallAudioRouteStateMachine.USER_SWITCH_EARPIECE); return; case CallAudioState.ROUTE_WIRED_OR_EARPIECE: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE); CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE); return; default: Log.wtf(this, "Invalid route specified: %d", route); Loading src/com/android/server/telecom/CallAudioRouteStateMachine.java +74 −15 Original line number Diff line number Diff line Loading @@ -85,6 +85,12 @@ public class CallAudioRouteStateMachine extends StateMachine { // Wired headset, earpiece, or speakerphone, in that order of precedence. public static final int SWITCH_BASELINE_ROUTE = 1005; public static final int USER_SWITCH_EARPIECE = 1101; public static final int USER_SWITCH_BLUETOOTH = 1102; public static final int USER_SWITCH_HEADSET = 1103; public static final int USER_SWITCH_SPEAKER = 1104; public static final int USER_SWITCH_BASELINE_ROUTE = 1105; public static final int REINITIALIZE = 2001; public static final int MUTE_ON = 3001; Loading Loading @@ -114,6 +120,12 @@ public class CallAudioRouteStateMachine extends StateMachine { put(SWITCH_SPEAKER, "SWITCH_SPEAKER"); put(SWITCH_BASELINE_ROUTE, "SWITCH_BASELINE_ROUTE"); put(USER_SWITCH_EARPIECE, "USER_SWITCH_EARPIECE"); put(USER_SWITCH_BLUETOOTH, "USER_SWITCH_BLUETOOTH"); put(USER_SWITCH_HEADSET, "USER_SWITCH_HEADSET"); put(USER_SWITCH_SPEAKER, "USER_SWITCH_SPEAKER"); put(USER_SWITCH_BASELINE_ROUTE, "USER_SWITCH_BASELINE_ROUTE"); put(REINITIALIZE, "REINITIALIZE"); put(MUTE_ON, "MUTE_ON"); Loading Loading @@ -204,24 +216,17 @@ public class CallAudioRouteStateMachine extends StateMachine { return NOT_HANDLED; } case SWITCH_BASELINE_ROUTE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { sendInternalMessage(SWITCH_EARPIECE); } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { sendInternalMessage(SWITCH_HEADSET); } else if (!mDoesDeviceSupportEarpieceRoute) { sendInternalMessage(SWITCH_SPEAKER); } else { Log.e(this, new IllegalStateException(), "Neither headset nor earpiece are available, but there is an " + "earpiece on the device. Defaulting to earpiece."); sendInternalMessage(SWITCH_EARPIECE); } sendInternalMessage(calculateBaselineRouteMessage(false)); return HANDLED; case USER_SWITCH_BASELINE_ROUTE: sendInternalMessage(calculateBaselineRouteMessage(true)); return HANDLED; case REINITIALIZE: CallAudioState initState = getInitialAudioState(); mAvailableRoutes = initState.getSupportedRouteMask(); mIsMuted = initState.isMuted(); mWasOnSpeaker = initState.getRoute() == ROUTE_SPEAKER; mHasUserExplicitlyLeftBluetooth = false; transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute())); return HANDLED; default: Loading Loading @@ -269,9 +274,11 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: // Nothing to do here return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -279,6 +286,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); } else { Loading @@ -286,6 +294,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -313,6 +322,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -369,7 +379,11 @@ public class CallAudioRouteStateMachine extends StateMachine { sendInternalMessage(SWITCH_HEADSET); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -428,6 +442,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); } else { Loading @@ -435,6 +450,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -442,9 +458,11 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: // Nothing to do return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -472,6 +490,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -531,7 +550,11 @@ public class CallAudioRouteStateMachine extends StateMachine { updateSystemAudioState(); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -590,6 +613,9 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; } switch (msg.what) { case USER_SWITCH_EARPIECE: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); Loading @@ -598,8 +624,12 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: // Nothing to do return HANDLED; case USER_SWITCH_HEADSET: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); Loading @@ -607,6 +637,9 @@ public class CallAudioRouteStateMachine extends StateMachine { Log.w(this, "Ignoring switch to headset command. Not available."); } return HANDLED; case USER_SWITCH_SPEAKER: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; Loading Loading @@ -635,6 +668,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -751,6 +785,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch(msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); } else { Loading @@ -758,6 +793,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -765,6 +801,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); } else { Loading @@ -772,6 +809,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: // Nothing to do return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -799,6 +837,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; // Omit setting mWasOnSpeaker to true here, since this does not reflect a call // actually being on speakerphone. updateInternalCallAudioState(); Loading Loading @@ -861,7 +900,11 @@ public class CallAudioRouteStateMachine extends StateMachine { sendInternalMessage(SWITCH_HEADSET); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -908,6 +951,7 @@ public class CallAudioRouteStateMachine extends StateMachine { private final StatusBarNotifier mStatusBarNotifier; private final CallAudioManager.AudioServiceFactory mAudioServiceFactory; private final boolean mDoesDeviceSupportEarpieceRoute; private boolean mHasUserExplicitlyLeftBluetooth = false; private HashMap<String, Integer> mStateNameToRouteCode; private HashMap<Integer, AudioState> mRouteCodeToQuiescentState; Loading Loading @@ -1214,4 +1258,19 @@ public class CallAudioRouteStateMachine extends StateMachine { } return true; } private int calculateBaselineRouteMessage(boolean isExplicitUserRequest) { if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET; } else if (!mDoesDeviceSupportEarpieceRoute) { return isExplicitUserRequest ? USER_SWITCH_SPEAKER : SWITCH_SPEAKER; } else { Log.e(this, new IllegalStateException(), "Neither headset nor earpiece are available, but there is an " + "earpiece on the device. Defaulting to earpiece."); return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; } } } No newline at end of file tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java +49 −5 Original line number Diff line number Diff line Loading @@ -190,6 +190,46 @@ public class CallAudioRouteStateMachineTest verifyNewSystemCallAudioState(expectedMiddleState, initState); } @MediumTest public void testUserBluetoothSwitchOff() { CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( mContext, mockCallsManager, mockBluetoothManager, mockWiredHeadsetManager, mockStatusBarNotifier, mAudioServiceFactory, true); when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true); when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true); CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); stateMachine.initialize(initState); stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, CallAudioRouteStateMachine.HAS_FOCUS); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE); CallAudioState expectedEndState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE); verifyNewSystemCallAudioState(initState, expectedEndState); resetMocks(); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.CONNECT_BLUETOOTH); waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE); assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState()); } @SmallTest public void testInitializationWithEarpieceNoHeadsetNoBluetooth() { CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, Loading Loading @@ -709,6 +749,15 @@ public class CallAudioRouteStateMachineTest // Verify that no substantive interactions have taken place with the // rest of the system verifyNoSystemAudioChanges(); // Verify the end state CallAudioState expectedState = new CallAudioState(false, params.expectedRoute, params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER); assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); } private void verifyNoSystemAudioChanges() { verify(mockBluetoothManager, never()).disconnectBluetoothAudio(); verify(mockBluetoothManager, never()).connectBluetoothAudio(); verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class)); Loading @@ -716,11 +765,6 @@ public class CallAudioRouteStateMachineTest any(CallAudioState.class)); verify(mockConnectionServiceWrapper, never()).onCallAudioStateChanged( any(Call.class), any(CallAudioState.class)); // Verify the end state CallAudioState expectedState = new CallAudioState(false, params.expectedRoute, params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER); assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); } private void verifyNewSystemCallAudioState(CallAudioState expectedOldState, Loading Loading
src/com/android/server/telecom/CallAudioManager.java +5 −5 Original line number Diff line number Diff line Loading @@ -321,23 +321,23 @@ public class CallAudioManager extends CallsManagerListenerBase { switch (route) { case CallAudioState.ROUTE_BLUETOOTH: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_BLUETOOTH); CallAudioRouteStateMachine.USER_SWITCH_BLUETOOTH); return; case CallAudioState.ROUTE_SPEAKER: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_SPEAKER); CallAudioRouteStateMachine.USER_SWITCH_SPEAKER); return; case CallAudioState.ROUTE_WIRED_HEADSET: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_HEADSET); CallAudioRouteStateMachine.USER_SWITCH_HEADSET); return; case CallAudioState.ROUTE_EARPIECE: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_EARPIECE); CallAudioRouteStateMachine.USER_SWITCH_EARPIECE); return; case CallAudioState.ROUTE_WIRED_OR_EARPIECE: mCallAudioRouteStateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE); CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE); return; default: Log.wtf(this, "Invalid route specified: %d", route); Loading
src/com/android/server/telecom/CallAudioRouteStateMachine.java +74 −15 Original line number Diff line number Diff line Loading @@ -85,6 +85,12 @@ public class CallAudioRouteStateMachine extends StateMachine { // Wired headset, earpiece, or speakerphone, in that order of precedence. public static final int SWITCH_BASELINE_ROUTE = 1005; public static final int USER_SWITCH_EARPIECE = 1101; public static final int USER_SWITCH_BLUETOOTH = 1102; public static final int USER_SWITCH_HEADSET = 1103; public static final int USER_SWITCH_SPEAKER = 1104; public static final int USER_SWITCH_BASELINE_ROUTE = 1105; public static final int REINITIALIZE = 2001; public static final int MUTE_ON = 3001; Loading Loading @@ -114,6 +120,12 @@ public class CallAudioRouteStateMachine extends StateMachine { put(SWITCH_SPEAKER, "SWITCH_SPEAKER"); put(SWITCH_BASELINE_ROUTE, "SWITCH_BASELINE_ROUTE"); put(USER_SWITCH_EARPIECE, "USER_SWITCH_EARPIECE"); put(USER_SWITCH_BLUETOOTH, "USER_SWITCH_BLUETOOTH"); put(USER_SWITCH_HEADSET, "USER_SWITCH_HEADSET"); put(USER_SWITCH_SPEAKER, "USER_SWITCH_SPEAKER"); put(USER_SWITCH_BASELINE_ROUTE, "USER_SWITCH_BASELINE_ROUTE"); put(REINITIALIZE, "REINITIALIZE"); put(MUTE_ON, "MUTE_ON"); Loading Loading @@ -204,24 +216,17 @@ public class CallAudioRouteStateMachine extends StateMachine { return NOT_HANDLED; } case SWITCH_BASELINE_ROUTE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { sendInternalMessage(SWITCH_EARPIECE); } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { sendInternalMessage(SWITCH_HEADSET); } else if (!mDoesDeviceSupportEarpieceRoute) { sendInternalMessage(SWITCH_SPEAKER); } else { Log.e(this, new IllegalStateException(), "Neither headset nor earpiece are available, but there is an " + "earpiece on the device. Defaulting to earpiece."); sendInternalMessage(SWITCH_EARPIECE); } sendInternalMessage(calculateBaselineRouteMessage(false)); return HANDLED; case USER_SWITCH_BASELINE_ROUTE: sendInternalMessage(calculateBaselineRouteMessage(true)); return HANDLED; case REINITIALIZE: CallAudioState initState = getInitialAudioState(); mAvailableRoutes = initState.getSupportedRouteMask(); mIsMuted = initState.isMuted(); mWasOnSpeaker = initState.getRoute() == ROUTE_SPEAKER; mHasUserExplicitlyLeftBluetooth = false; transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute())); return HANDLED; default: Loading Loading @@ -269,9 +274,11 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: // Nothing to do here return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -279,6 +286,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); } else { Loading @@ -286,6 +294,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -313,6 +322,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -369,7 +379,11 @@ public class CallAudioRouteStateMachine extends StateMachine { sendInternalMessage(SWITCH_HEADSET); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -428,6 +442,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); } else { Loading @@ -435,6 +450,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -442,9 +458,11 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: // Nothing to do return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -472,6 +490,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -531,7 +550,11 @@ public class CallAudioRouteStateMachine extends StateMachine { updateSystemAudioState(); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -590,6 +613,9 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; } switch (msg.what) { case USER_SWITCH_EARPIECE: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); Loading @@ -598,8 +624,12 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: // Nothing to do return HANDLED; case USER_SWITCH_HEADSET: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); Loading @@ -607,6 +637,9 @@ public class CallAudioRouteStateMachine extends StateMachine { Log.w(this, "Ignoring switch to headset command. Not available."); } return HANDLED; case USER_SWITCH_SPEAKER: mHasUserExplicitlyLeftBluetooth = true; // fall through case SWITCH_SPEAKER: transitionTo(mActiveSpeakerRoute); return HANDLED; Loading Loading @@ -635,6 +668,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; updateInternalCallAudioState(); } Loading Loading @@ -751,6 +785,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } switch(msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { transitionTo(mActiveEarpieceRoute); } else { Loading @@ -758,6 +793,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { transitionTo(mActiveBluetoothRoute); } else { Loading @@ -765,6 +801,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { transitionTo(mActiveHeadsetRoute); } else { Loading @@ -772,6 +809,7 @@ public class CallAudioRouteStateMachine extends StateMachine { } return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: // Nothing to do return HANDLED; case SWITCH_FOCUS: Loading Loading @@ -799,6 +837,7 @@ public class CallAudioRouteStateMachine extends StateMachine { @Override public void enter() { super.enter(); mHasUserExplicitlyLeftBluetooth = false; // Omit setting mWasOnSpeaker to true here, since this does not reflect a call // actually being on speakerphone. updateInternalCallAudioState(); Loading Loading @@ -861,7 +900,11 @@ public class CallAudioRouteStateMachine extends StateMachine { sendInternalMessage(SWITCH_HEADSET); return HANDLED; case CONNECT_BLUETOOTH: if (!mHasUserExplicitlyLeftBluetooth) { sendInternalMessage(SWITCH_BLUETOOTH); } else { updateSystemAudioState(); } return HANDLED; case DISCONNECT_BLUETOOTH: updateSystemAudioState(); Loading Loading @@ -908,6 +951,7 @@ public class CallAudioRouteStateMachine extends StateMachine { private final StatusBarNotifier mStatusBarNotifier; private final CallAudioManager.AudioServiceFactory mAudioServiceFactory; private final boolean mDoesDeviceSupportEarpieceRoute; private boolean mHasUserExplicitlyLeftBluetooth = false; private HashMap<String, Integer> mStateNameToRouteCode; private HashMap<Integer, AudioState> mRouteCodeToQuiescentState; Loading Loading @@ -1214,4 +1258,19 @@ public class CallAudioRouteStateMachine extends StateMachine { } return true; } private int calculateBaselineRouteMessage(boolean isExplicitUserRequest) { if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; } else if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { return isExplicitUserRequest ? USER_SWITCH_HEADSET : SWITCH_HEADSET; } else if (!mDoesDeviceSupportEarpieceRoute) { return isExplicitUserRequest ? USER_SWITCH_SPEAKER : SWITCH_SPEAKER; } else { Log.e(this, new IllegalStateException(), "Neither headset nor earpiece are available, but there is an " + "earpiece on the device. Defaulting to earpiece."); return isExplicitUserRequest ? USER_SWITCH_EARPIECE : SWITCH_EARPIECE; } } } No newline at end of file
tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java +49 −5 Original line number Diff line number Diff line Loading @@ -190,6 +190,46 @@ public class CallAudioRouteStateMachineTest verifyNewSystemCallAudioState(expectedMiddleState, initState); } @MediumTest public void testUserBluetoothSwitchOff() { CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( mContext, mockCallsManager, mockBluetoothManager, mockWiredHeadsetManager, mockStatusBarNotifier, mAudioServiceFactory, true); when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true); when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true); CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); stateMachine.initialize(initState); stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, CallAudioRouteStateMachine.HAS_FOCUS); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE); CallAudioState expectedEndState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE); verifyNewSystemCallAudioState(initState, expectedEndState); resetMocks(); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH); stateMachine.sendMessageWithSessionInfo( CallAudioRouteStateMachine.CONNECT_BLUETOOTH); waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE); assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState()); } @SmallTest public void testInitializationWithEarpieceNoHeadsetNoBluetooth() { CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, Loading Loading @@ -709,6 +749,15 @@ public class CallAudioRouteStateMachineTest // Verify that no substantive interactions have taken place with the // rest of the system verifyNoSystemAudioChanges(); // Verify the end state CallAudioState expectedState = new CallAudioState(false, params.expectedRoute, params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER); assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); } private void verifyNoSystemAudioChanges() { verify(mockBluetoothManager, never()).disconnectBluetoothAudio(); verify(mockBluetoothManager, never()).connectBluetoothAudio(); verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class)); Loading @@ -716,11 +765,6 @@ public class CallAudioRouteStateMachineTest any(CallAudioState.class)); verify(mockConnectionServiceWrapper, never()).onCallAudioStateChanged( any(Call.class), any(CallAudioState.class)); // Verify the end state CallAudioState expectedState = new CallAudioState(false, params.expectedRoute, params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER); assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); } private void verifyNewSystemCallAudioState(CallAudioState expectedOldState, Loading