DSDA: Disconnect nonholdable calls with MT call
Ensures that we disconnect the non-holdable calls on one sim when we
receive an incoming call another sim. Previously, we would just
disconnect the active call but in a scenario where we have a HOLDING +
ACTIVE call plus a RINGING call (on another sim), we should also opt to
disconnect the held call as well. A good example of this is with
Verizon.
Bug: 392698669
Test: atest
CtsTelecomCujTestCases: CallSequencingManagedHoldRestrictionTest
Test: Manual verification with non-holdable sim to ensure that calls are
disconnected when receiving an incoming call on the other sim
Flag: com.android.server.telecom.flags.enable_call_sequencing
Change-Id: I6369cc2ca7a241cd5762bb3a1a3eb1bbabd52728
diff --git a/src/com/android/server/telecom/callsequencing/CallSequencingController.java b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
index 713d155..dcc5ac4 100644
--- a/src/com/android/server/telecom/callsequencing/CallSequencingController.java
+++ b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
@@ -62,6 +62,7 @@
import com.android.server.telecom.metrics.TelecomMetricsController;
import com.android.server.telecom.stats.CallFailureCause;
+import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -343,8 +344,12 @@
return CompletableFuture.completedFuture(false);
} else {
if (isSequencingRequiredActiveAndCall) {
- return activeCall.disconnect("Active call disconnected in favor of"
- + " new call.");
+ // Disconnect all calls with the same phone account as the active call
+ // as they do would not support holding.
+ Log.i(this, "Disconnecting non-holdable calls from account (%s).",
+ activeCall.getTargetPhoneAccount());
+ return disconnectAllCallsWithPhoneAccount(
+ activeCall.getTargetPhoneAccount());
} else {
Log.i(this, "holdActiveCallForNewCallWithSequencing: "
+ "allowing ConnectionService to determine how to handle "
@@ -895,6 +900,25 @@
&& callToUnhold.getState() == CallState.ON_HOLD;
}
+ private CompletableFuture<Boolean> disconnectAllCallsWithPhoneAccount(
+ PhoneAccountHandle handle) {
+ CompletableFuture<Boolean> disconnectFuture = CompletableFuture.completedFuture(true);
+ List<Call> calls = mCallsManager.getCalls().stream()
+ .filter(c -> c.getTargetPhoneAccount().equals(handle)).toList();
+ for (Call call: calls) {
+ // Wait for all disconnects before we accept the new call.
+ disconnectFuture = disconnectFuture.thenComposeAsync((result) -> {
+ if (!result) {
+ Log.i(this, "disconnectAllCallsWithPhoneAccount: "
+ + "Failed to disconnect %s.", call);
+ }
+ return call.disconnect("Un-holdable call " + call + " disconnected "
+ + "in favor of new call.");
+ }, new LoggedHandlerExecutor(mHandler, "CSC.dACWPA", mCallsManager.getLock()));
+ }
+ return disconnectFuture;
+ }
+
/**
* Generic helper to log the result of the {@link CompletableFuture} containing the transactions
* that are being processed in the context of call sequencing.
diff --git a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
index 64d2d7d..9cfc95c 100644
--- a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
@@ -18,7 +18,6 @@
import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL;
import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES;
-import static com.android.server.telecom.UserUtil.showErrorDialogForRestrictedOutgoingCall;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.TestCase.fail;
@@ -78,8 +77,8 @@
import org.junit.runners.JUnit4;
import org.mockito.Mock;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
@@ -342,6 +341,7 @@
public void testHoldCallForNewCall_DoesNotSupportHold_Disconnect() {
setPhoneAccounts(mNewCall, mActiveCall, false);
setActiveCallFocus(mActiveCall);
+ when(mCallsManager.getCalls()).thenReturn(Collections.singletonList(mActiveCall));
when(mCallsManager.canHold(mActiveCall)).thenReturn(false);
when(mCallsManager.supportsHold(mActiveCall)).thenReturn(false);
when(mActiveCall.disconnect(anyString())).thenReturn(