Add flag for call audio mode change.
Adding a flag for the new behavior which takes place when swapping between
a PSTN and VOIP call; this was a bug fix made to correct missing audio
mode transitions.
Bug: 289861657
Test: atest CallAudioManagerTest
Change-Id: I0feba38a3a529d139f251b995c0ddda40d89465b
diff --git a/flags/telecom_callaudioroutestatemachine_flags.aconfig b/flags/telecom_callaudioroutestatemachine_flags.aconfig
index c231551..e64fa68 100644
--- a/flags/telecom_callaudioroutestatemachine_flags.aconfig
+++ b/flags/telecom_callaudioroutestatemachine_flags.aconfig
@@ -5,4 +5,11 @@
namespace: "telecom"
description: "Fix supported routes wrongly include bluetooth issue."
bug: "292599751"
+}
+
+flag {
+ name: "ensure_audio_mode_updates_on_foreground_call_change"
+ namespace: "telecom"
+ description: "Ensure that the audio mode is updated anytime the foreground call changes."
+ bug: "289861657"
}
\ No newline at end of file
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 6557dc6..427b0ce 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -31,6 +31,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.CallAudioModeStateMachine.MessageArgs.Builder;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
+import com.android.server.telecom.flags.FeatureFlags;
import java.util.Collection;
import java.util.HashSet;
@@ -62,6 +63,7 @@
private final Ringer mRinger;
private final RingbackPlayer mRingbackPlayer;
private final DtmfLocalTonePlayer mDtmfLocalTonePlayer;
+ private final FeatureFlags mFeatureFlags;
private Call mStreamingCall;
private Call mForegroundCall;
@@ -76,7 +78,8 @@
Ringer ringer,
RingbackPlayer ringbackPlayer,
BluetoothStateReceiver bluetoothStateReceiver,
- DtmfLocalTonePlayer dtmfLocalTonePlayer) {
+ DtmfLocalTonePlayer dtmfLocalTonePlayer,
+ FeatureFlags featureFlags) {
mActiveDialingOrConnectingCalls = new LinkedHashSet<>(1);
mRingingCalls = new LinkedHashSet<>(1);
mHoldingCalls = new LinkedHashSet<>(1);
@@ -102,6 +105,7 @@
mRingbackPlayer = ringbackPlayer;
mBluetoothStateReceiver = bluetoothStateReceiver;
mDtmfLocalTonePlayer = dtmfLocalTonePlayer;
+ mFeatureFlags = featureFlags;
mPlayerFactory.setCallAudioManager(this);
mCallAudioModeStateMachine.setCallAudioManager(this);
@@ -772,20 +776,26 @@
possibleConnectingCall = call;
}
}
- // Prefer a connecting call
- if (possibleConnectingCall != null) {
- mForegroundCall = possibleConnectingCall;
+ if (mFeatureFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
+ // Prefer a connecting call
+ if (possibleConnectingCall != null) {
+ mForegroundCall = possibleConnectingCall;
+ } else {
+ // Next, prefer an active or dialing call which is not in the process of being
+ // disconnected.
+ mForegroundCall = mActiveDialingOrConnectingCalls
+ .stream()
+ .filter(c -> (c.getState() == CallState.ACTIVE
+ || c.getState() == CallState.DIALING)
+ && !c.isLocallyDisconnecting())
+ .findFirst()
+ // If we can't find one, then just fall back to the first one.
+ .orElse(mActiveDialingOrConnectingCalls.iterator().next());
+ }
} else {
- // Next, prefer an active or dialing call which is not in the process of being
- // disconnected.
- mForegroundCall = mActiveDialingOrConnectingCalls
- .stream()
- .filter(c -> (c.getState() == CallState.ACTIVE
- || c.getState() == CallState.DIALING)
- && !c.isLocallyDisconnecting())
- .findFirst()
- // If we can't find one, then just fall back to the first one.
- .orElse(mActiveDialingOrConnectingCalls.iterator().next());
+ // Legacy (buggy) behavior.
+ mForegroundCall = possibleConnectingCall == null ?
+ mActiveDialingOrConnectingCalls.iterator().next() : possibleConnectingCall;
}
} else if (mRingingCalls.size() > 0) {
mForegroundCall = mRingingCalls.iterator().next();
@@ -806,7 +816,8 @@
mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
- if (mForegroundCall != null) {
+ if (mForegroundCall != null
+ && mFeatureFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
// Ensure the voip audio mode for the new foreground call is taken into account.
mCallAudioModeStateMachine.sendMessageWithArgs(
CallAudioModeStateMachine.FOREGROUND_VOIP_MODE_CHANGE,
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 0e78ca1..ba02009 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -657,7 +657,7 @@
this, callAudioModeStateMachineFactory.create(systemStateHelper,
(AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE), featureFlags),
playerFactory, mRinger, new RingbackPlayer(playerFactory),
- bluetoothStateReceiver, mDtmfLocalTonePlayer);
+ bluetoothStateReceiver, mDtmfLocalTonePlayer, featureFlags);
mConnectionSvrFocusMgr = connectionServiceFocusManagerFactory.create(mRequester);
mHeadsetMediaButton = headsetMediaButtonFactory.create(context, this, mLock);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index c8ceea9..df281ca 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -36,6 +36,7 @@
import com.android.server.telecom.Ringer;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
+import com.android.server.telecom.flags.FeatureFlags;
import org.junit.After;
import org.junit.Before;
@@ -79,6 +80,8 @@
@Mock private BluetoothStateReceiver mBluetoothStateReceiver;
@Mock private TelecomSystem.SyncRoot mLock;
+ @Mock private FeatureFlags mFlags;
+
private CallAudioManager mCallAudioManager;
@Override
@@ -94,6 +97,7 @@
return mockInCallTonePlayer;
}).when(mPlayerFactory).createPlayer(anyInt());
when(mCallsManager.getLock()).thenReturn(mLock);
+ when(mFlags.ensureAudioModeUpdatesOnForegroundCallChange()).thenReturn(true);
mCallAudioManager = new CallAudioManager(
mCallAudioRouteStateMachine,
mCallsManager,
@@ -102,7 +106,8 @@
mRinger,
mRingbackPlayer,
mBluetoothStateReceiver,
- mDtmfLocalTonePlayer);
+ mDtmfLocalTonePlayer,
+ mFlags);
}
@Override
@@ -278,19 +283,27 @@
verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
assertMessageArgEquality(expectedArgs, captor.getValue());
- // Expet another invocation due to audio mode change signal.
- verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
- anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
-
+ if (mFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
+ // Expect another invocation due to audio mode change signal.
+ verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ } else {
+ verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ }
when(call.getState()).thenReturn(CallState.ACTIVE);
mCallAudioManager.onCallStateChanged(call, CallState.DIALING, CallState.ACTIVE);
verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
assertMessageArgEquality(expectedArgs, captor.getValue());
- verify(mCallAudioModeStateMachine, times(4)).sendMessageWithArgs(
- anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
-
+ if (mFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
+ verify(mCallAudioModeStateMachine, times(4)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ } else {
+ verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ }
disconnectCall(call);
stopTone();
@@ -298,6 +311,12 @@
verifyProperCleanup();
}
+ @Test
+ public void testSingleOutgoingCallWithoutAudioModeUpdateOnForegroundCallChange() {
+ when(mFlags.ensureAudioModeUpdatesOnForegroundCallChange()).thenReturn(false);
+ testSingleOutgoingCall();
+ }
+
@MediumTest
@Test
public void testRingbackStartStop() {
@@ -329,9 +348,14 @@
verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
assertMessageArgEquality(expectedArgs, captor.getValue());
- // Expect an extra time due to audio mode change signal
- verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
- anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ if (mFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
+ // Expect an extra time due to audio mode change signal
+ verify(mCallAudioModeStateMachine, times(3)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ } else {
+ verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
+ anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+ }
// Ensure we started ringback.
verify(mRingbackPlayer).startRingbackForCall(any(Call.class));
@@ -353,6 +377,12 @@
verify(mRingbackPlayer, times(1)).startRingbackForCall(any(Call.class));
}
+ @Test
+ public void testRingbackStartStopWithoutAudioModeUpdateOnForegroundCallChange() {
+ when(mFlags.ensureAudioModeUpdatesOnForegroundCallChange()).thenReturn(false);
+ testRingbackStartStop();
+ }
+
@SmallTest
@Test
public void testNewCallGoesToAudioProcessing() {
@@ -708,6 +738,10 @@
@SmallTest
@Test
public void testTriggerAudioManagerModeChange() {
+ if (!mFlags.ensureAudioModeUpdatesOnForegroundCallChange()) {
+ // Skip if the new behavior isn't in use.
+ return;
+ }
// Start with an incoming PSTN call
Call pstnCall = mock(Call.class);
when(pstnCall.getState()).thenReturn(CallState.RINGING);