Merge "Update route when speakerphone changed externally" am: 44a7e4f147 am: 4db4bfcaaf
am: 1eedd53966
Change-Id: Ibe0913145db3dd5d3d6e89511fbd3333a6a3e5d1
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index 3a5d113..82d245d 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -123,6 +123,11 @@
// Wired headset, earpiece, or speakerphone, in that order of precedence.
public static final int SWITCH_BASELINE_ROUTE = 1005;
+ // Messages denoting that the speakerphone was turned on/off. Used to update state when we
+ // weren't the ones who turned it on/off
+ public static final int SPEAKER_ON = 1006;
+ public static final int SPEAKER_OFF = 1007;
+
public static final int USER_SWITCH_EARPIECE = 1101;
public static final int USER_SWITCH_BLUETOOTH = 1102;
public static final int USER_SWITCH_HEADSET = 1103;
@@ -181,6 +186,8 @@
put(SWITCH_HEADSET, "SWITCH_HEADSET");
put(SWITCH_SPEAKER, "SWITCH_SPEAKER");
put(SWITCH_BASELINE_ROUTE, "SWITCH_BASELINE_ROUTE");
+ put(SPEAKER_ON, "SPEAKER_ON");
+ put(SPEAKER_OFF, "SPEAKER_OFF");
put(USER_SWITCH_EARPIECE, "USER_SWITCH_EARPIECE");
put(USER_SWITCH_BLUETOOTH, "USER_SWITCH_BLUETOOTH");
@@ -374,6 +381,7 @@
switch (msg.what) {
case SWITCH_EARPIECE:
case USER_SWITCH_EARPIECE:
+ case SPEAKER_OFF:
// Nothing to do here
return HANDLED;
case BT_AUDIO_CONNECTED:
@@ -405,6 +413,7 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -449,6 +458,7 @@
switch (msg.what) {
case SWITCH_EARPIECE:
case USER_SWITCH_EARPIECE:
+ case SPEAKER_OFF:
// Nothing to do here
return HANDLED;
case BT_AUDIO_CONNECTED:
@@ -473,6 +483,7 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -594,10 +605,12 @@
return HANDLED;
case SWITCH_HEADSET:
case USER_SWITCH_HEADSET:
+ case SPEAKER_OFF:
// Nothing to do
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -662,10 +675,12 @@
return HANDLED;
case SWITCH_HEADSET:
case USER_SWITCH_HEADSET:
+ case SPEAKER_OFF:
// Nothing to do
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -835,9 +850,12 @@
mHasUserExplicitlyLeftBluetooth = true;
// fall through
case SWITCH_SPEAKER:
+ case SPEAKER_ON:
setBluetoothOff();
transitionTo(mActiveSpeakerRoute);
return HANDLED;
+ case SPEAKER_OFF:
+ return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
// Only disconnect SCO audio here instead of routing away from BT entirely.
@@ -926,8 +944,11 @@
mHasUserExplicitlyLeftBluetooth = true;
// fall through
case SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mActiveSpeakerRoute);
return HANDLED;
+ case SPEAKER_OFF:
+ return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
@@ -987,6 +1008,7 @@
return HANDLED;
case SWITCH_BLUETOOTH:
case USER_SWITCH_BLUETOOTH:
+ case SPEAKER_OFF:
// Nothing to do
return HANDLED;
case SWITCH_HEADSET:
@@ -999,6 +1021,7 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
transitionTo(mQuiescentSpeakerRoute);
return HANDLED;
case SWITCH_FOCUS:
@@ -1143,6 +1166,12 @@
case USER_SWITCH_SPEAKER:
// Nothing to do
return HANDLED;
+ case SPEAKER_ON:
+ // Expected, since we just transitioned here
+ return HANDLED;
+ case SPEAKER_OFF:
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
+ return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == NO_FOCUS) {
reinitialize();
@@ -1215,8 +1244,12 @@
return HANDLED;
case SWITCH_SPEAKER:
case USER_SWITCH_SPEAKER:
+ case SPEAKER_ON:
// Nothing to do
return HANDLED;
+ case SPEAKER_OFF:
+ sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
+ return HANDLED;
case SWITCH_FOCUS:
if (msg.arg1 == ACTIVE_FOCUS || msg.arg1 == RINGING_FOCUS) {
transitionTo(mActiveSpeakerRoute);
@@ -1294,6 +1327,28 @@
}
};
+ private final BroadcastReceiver mSpeakerPhoneChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.startSession("CARSM.mSPCR");
+ try {
+ if (AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED.equals(intent.getAction())) {
+ if (mAudioManager != null) {
+ if (mAudioManager.isSpeakerphoneOn()) {
+ sendInternalMessage(SPEAKER_ON);
+ } else {
+ sendInternalMessage(SPEAKER_OFF);
+ }
+ }
+ } else {
+ Log.w(this, "Received non-speakerphone-change intent");
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+ };
+
private final ActiveEarpieceRoute mActiveEarpieceRoute = new ActiveEarpieceRoute();
private final ActiveHeadsetRoute mActiveHeadsetRoute = new ActiveHeadsetRoute();
private final ActiveBluetoothRoute mActiveBluetoothRoute = new ActiveBluetoothRoute();
@@ -1446,6 +1501,8 @@
mWasOnSpeaker = false;
mContext.registerReceiver(mMuteChangeReceiver,
new IntentFilter(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED));
+ mContext.registerReceiver(mSpeakerPhoneChangeReceiver,
+ new IntentFilter(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED));
mStatusBarNotifier.notifyMute(initState.isMuted());
mStatusBarNotifier.notifySpeakerphone(initState.getRoute() == CallAudioState.ROUTE_SPEAKER);
@@ -1531,8 +1588,12 @@
}
private void setSpeakerphoneOn(boolean on) {
- Log.i(this, "turning speaker phone %s", on);
- mAudioManager.setSpeakerphoneOn(on);
+ if (mAudioManager.isSpeakerphoneOn() != on) {
+ Log.i(this, "turning speaker phone %s", on);
+ mAudioManager.setSpeakerphoneOn(on);
+ } else {
+ Log.i(this, "Ignoring speakerphone request -- already %s", on);
+ }
mStatusBarNotifier.notifySpeakerphone(on);
}
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 2a284d2..09d765a 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -615,7 +615,7 @@
waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
.getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
// setSpeakerPhoneOn(false) gets called once during the call initiation phase
- verify(audioManager, timeout(TEST_TIMEOUT).atLeast(2))
+ verify(audioManager, timeout(TEST_TIMEOUT).atLeast(1))
.setSpeakerphoneOn(false);
mConnectionServiceFixtureA.
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 57462c4..58f1ee7 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -219,8 +219,18 @@
return null;
}).when(mockBluetoothRouteManager).connectBluetoothAudio(nullable(String.class));
- when(mockAudioManager.isSpeakerphoneOn()).thenReturn(
- params.initialRoute == CallAudioState.ROUTE_SPEAKER);
+ // Set the speakerphone state depending on the message being sent. If it's one of the
+ // speakerphone override ones, set accordingly. Otherwise consult the initial route.
+ boolean speakerphoneOn;
+ if (params.action == CallAudioRouteStateMachine.SPEAKER_ON) {
+ speakerphoneOn = true;
+ } else if (params.action == CallAudioRouteStateMachine.SPEAKER_OFF) {
+ speakerphoneOn = false;
+ } else {
+ speakerphoneOn = params.initialRoute == CallAudioState.ROUTE_SPEAKER;
+ }
+ when(mockAudioManager.isSpeakerphoneOn()).thenReturn(speakerphoneOn);
+
when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes);
}
@@ -757,6 +767,58 @@
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
));
+ params.add(new RoutingTestParameters(
+ "Speakerphone turned on during earpiece", // name
+ CallAudioState.ROUTE_EARPIECE, // initialRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
+ NONE, // speakerInteraction
+ NONE, // bluetoothInteraction
+ CallAudioRouteStateMachine.SPEAKER_ON, // action
+ CallAudioState.ROUTE_SPEAKER, // expectedRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl
+ CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+ ));
+
+ params.add(new RoutingTestParameters(
+ "Speakerphone turned on during wired headset", // name
+ CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
+ CallAudioState.ROUTE_EARPIECE
+ | CallAudioState.ROUTE_BLUETOOTH
+ | CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
+ NONE, // speakerInteraction
+ NONE, // bluetoothInteraction
+ CallAudioRouteStateMachine.SPEAKER_ON, // action
+ CallAudioState.ROUTE_SPEAKER, // expectedRoute
+ CallAudioState.ROUTE_EARPIECE
+ | CallAudioState.ROUTE_BLUETOOTH
+ | CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
+ CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+ ));
+
+ params.add(new RoutingTestParameters(
+ "Speakerphone turned on during bluetooth", // name
+ CallAudioState.ROUTE_BLUETOOTH, // initialRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
+ NONE, // speakerInteraction
+ OFF, // bluetoothInteraction
+ CallAudioRouteStateMachine.SPEAKER_ON, // action
+ CallAudioState.ROUTE_SPEAKER, // expectedRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl
+ CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+ ));
+
+ params.add(new RoutingTestParameters(
+ "Speakerphone turned off externally during speaker", // name
+ CallAudioState.ROUTE_SPEAKER, // initialRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
+ NONE, // speakerInteraction
+ ON, // bluetoothInteraction
+ CallAudioRouteStateMachine.SPEAKER_OFF, // action
+ CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
+ CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl
+ CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+ ));
+
return params;
}