DSDA: Reject outgoing call when ringing call present
Make sure we reject the outgoing call when there's a unanswered incoming
call. The user should see a message indicating that they cannot place a
call while the incoming call is unanswered.
Bug: 393957944
Test: atest CallSequencingTests
Test: Manual verification
Flag: com.android.server.telecom.flags.enable_call_sequencing
Change-Id: I0580c68a975f55678294174acc2faa65d6a54c10
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c950337..9d9f5e1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -423,6 +423,9 @@
<!-- In-call screen: error message shown when the user attempts to place a call, but the live
call cannot be held. -->
<string name="callFailed_unholdable_call">Cannot place a call as there is an unholdable call. Disconnect the call prior to placing a new call.</string>
+ <!-- In-call screen: error message shown when the user has attempted to place a new outgoing
+ call while there is already a call in ringing state. -->
+ <string name="callFailed_already_ringing">Cannot place a call as there is an unanswered incoming call. Answer or reject the incoming call prior to placing a new call.</string>
<!-- In-call screen: error message shown when the user attempts to dial an MMI code, but there
is an ongoing call on a different phone account. -->
<string name="callFailed_reject_mmi">This MMI code is not available for calls across multiple accounts.</string>
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 39cd379..abcdd18 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -4461,6 +4461,11 @@
CallState.SIMULATED_RINGING, CallState.RINGING, CallState.ANSWERED) != null;
}
+ public boolean hasManagedRingingOrSimulatedRingingCall() {
+ return getFirstCallWithState(null /* callToSkip */, true /* skipSelfManaged */,
+ CallState.SIMULATED_RINGING, CallState.RINGING, CallState.ANSWERED) != null;
+ }
+
@VisibleForTesting
public boolean onMediaButton(int type) {
if (hasAnyCalls()) {
@@ -4604,11 +4609,11 @@
@VisibleForTesting
public Call getFirstCallWithState(int... states) {
- return getFirstCallWithState(null, states);
+ return getFirstCallWithState(null, false /* skipSelfManaged */, states);
}
public Call getFirstCallWithLiveState() {
- return getFirstCallWithState(null, LIVE_CALL_STATES);
+ return getFirstCallWithState(null, false /* skipSelfManaged */, LIVE_CALL_STATES);
}
@VisibleForTesting
@@ -4633,7 +4638,7 @@
*
* @param callToSkip Call that this method should skip while searching
*/
- Call getFirstCallWithState(Call callToSkip, int... states) {
+ Call getFirstCallWithState(Call callToSkip, boolean skipSelfManaged, int... states) {
for (int currentState : states) {
// check the foreground first
Call foregroundCall = getForegroundCall();
@@ -4655,6 +4660,10 @@
continue;
}
+ if (skipSelfManaged && call.isSelfManaged()) {
+ continue;
+ }
+
if (currentState == call.getState()) {
return call;
}
diff --git a/src/com/android/server/telecom/callsequencing/CallSequencingController.java b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
index 5166c03..713d155 100644
--- a/src/com/android/server/telecom/callsequencing/CallSequencingController.java
+++ b/src/com/android/server/telecom/callsequencing/CallSequencingController.java
@@ -697,6 +697,12 @@
* made for the outgoing call.
*/
private CompletableFuture<Boolean> makeRoomForOutgoingCall(Call call) {
+ // For the purely managed CS cases, check if there's a ringing call, in which case we will
+ // disallow the outgoing call.
+ if (!call.isSelfManaged() && mCallsManager.hasManagedRingingOrSimulatedRingingCall()) {
+ showErrorDialogForOutgoingDuringRingingCall(call);
+ return CompletableFuture.completedFuture(false);
+ }
// Already room!
if (!mCallsManager.hasMaximumLiveCalls(call)) {
return CompletableFuture.completedFuture(true);
@@ -921,20 +927,34 @@
}
private void showErrorDialogForMaxOutgoingCall(Call call) {
- call.setStartFailCause(CallFailureCause.MAX_OUTGOING_CALLS);
- int stringId = R.string.callFailed_too_many_calls;
+ int resourceId = R.string.callFailed_too_many_calls;
String reason = " there are two calls already in progress. Disconnect one of the calls "
+ "or merge the calls.";
- showErrorDialogForRestrictedOutgoingCall(mContext, stringId, TAG, reason);
+ showErrorDialogForFailedCall(call, CallFailureCause.MAX_OUTGOING_CALLS, resourceId, reason);
+ }
+
+ private void showErrorDialogForOutgoingDuringRingingCall(Call call) {
+ int resourceId = R.string.callFailed_already_ringing;
+ String reason = " can't place outgoing call with an unanswered incoming call.";
+ showErrorDialogForFailedCall(call, null, resourceId, reason);
}
private void showErrorDialogForCannotHoldCall(Call call, boolean setCallFailure) {
+ CallFailureCause cause = null;
if (setCallFailure) {
- call.setStartFailCause(CallFailureCause.CANNOT_HOLD_CALL);
+ cause = CallFailureCause.CANNOT_HOLD_CALL;
}
- int stringId = R.string.callFailed_unholdable_call;
+ int resourceId = R.string.callFailed_unholdable_call;
String reason = " unable to hold live call. Disconnect the unholdable call.";
- showErrorDialogForRestrictedOutgoingCall(mContext, stringId, TAG, reason);
+ showErrorDialogForFailedCall(call, cause, resourceId, reason);
+ }
+
+ private void showErrorDialogForFailedCall(Call call, CallFailureCause cause, int resourceId,
+ String reason) {
+ if (cause != null) {
+ call.setStartFailCause(cause);
+ }
+ showErrorDialogForRestrictedOutgoingCall(mContext, resourceId, TAG, reason);
}
public Handler getHandler() {
diff --git a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
index f1861cb..64d2d7d 100644
--- a/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallSequencingTests.java
@@ -560,6 +560,16 @@
@Test
@SmallTest
+ public void testMakeRoomForOutgoingCallFail_RingingCall() {
+ when(mNewCall.isSelfManaged()).thenReturn(false);
+ when(mCallsManager.hasManagedRingingOrSimulatedRingingCall()).thenReturn(true);
+
+ CompletableFuture<Boolean> future = mController.makeRoomForOutgoingCall(false, mNewCall);
+ assertFalse(waitForFutureResult(future, true));
+ }
+
+ @Test
+ @SmallTest
public void testDisconnectCallSuccess() {
when(mActiveCall.disconnect()).thenReturn(CompletableFuture.completedFuture(true));
int previousState = CallState.ACTIVE;