Discard on-going steps for domain selection on local hangup
If the user disconnects the call, then on-going steps can be
executed asynchronously for domain selection should be discarded
to avoid potential abnormal behavior.
Bug: 243344927
Test: atest TelephonyConnectionServiceTest
Change-Id: I1eece8955da8669c9f3458c35b24ec1558fd1abe
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 8253f71..519655e 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -2198,6 +2198,10 @@
phone, mEmergencyCallId, isTestEmergencyNumber);
future.thenAccept((result) -> {
Log.d(this, "startEmergencyCall-complete result=" + result);
+ if (mEmergencyCallId == null) {
+ Log.i(this, "startEmergencyCall-complete dialing canceled");
+ return;
+ }
if (result == android.telephony.DisconnectCause.NOT_DISCONNECTED) {
createEmergencyConnection(phone, (TelephonyConnection) resultConnection,
numberToDial, request, needToTurnOnRadio,
@@ -2272,6 +2276,10 @@
attr, mEmergencyDomainSelectionConnectionCallback);
future.thenAcceptAsync((result) -> {
Log.d(this, "createEmergencyConnection-complete result=" + result);
+ if (mEmergencyCallId == null) {
+ Log.i(this, "createEmergencyConnection-complete dialing canceled");
+ return;
+ }
Bundle extras = request.getExtras();
extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, result);
placeOutgoingConnection(request, resultConnection, phone);
@@ -2285,7 +2293,13 @@
Bundle extras = request.getExtras();
extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_CS);
mDomainSelectionMainExecutor.execute(
- () -> placeOutgoingConnection(request, resultConnection, phone));
+ () -> {
+ if (mEmergencyCallId == null) {
+ Log.i(this, "dialCsEmergencyCall dialing canceled");
+ return;
+ }
+ placeOutgoingConnection(request, resultConnection, phone);
+ });
}
private void releaseEmergencyCallDomainSelection(boolean cancel) {
@@ -2360,6 +2374,10 @@
if (future != null) {
future.thenAcceptAsync((result) -> {
Log.d(this, "reselectDomain-complete");
+ if (mEmergencyCallId == null) {
+ Log.i(this, "reselectDomain-complete dialing canceled");
+ return;
+ }
onEmergencyRedialOnDomain(c, phone, result);
}, mDomainSelectionMainExecutor);
return true;
@@ -2487,8 +2505,11 @@
phone, mEmergencyCallId, isTestEmergencyNumber);
future.thenAccept((result) -> {
Log.d(this, "onEmergencyRedial-complete result=" + result);
+ if (mEmergencyCallId == null) {
+ Log.i(this, "onEmergencyRedial-complete dialing canceled");
+ return;
+ }
if (result == android.telephony.DisconnectCause.NOT_DISCONNECTED) {
-
DomainSelectionConnection selectConnection =
mDomainSelectionResolver.getDomainSelectionConnection(
phone, SELECTOR_TYPE_CALLING, true);
@@ -2536,6 +2557,10 @@
private void recreateEmergencyConnection(final TelephonyConnection connection,
final Phone phone, final @NetworkRegistrationInfo.Domain int result) {
Log.d(this, "recreateEmergencyConnection result=" + result);
+ if (mEmergencyCallId == null) {
+ Log.i(this, "recreateEmergencyConnection dialing canceled");
+ return;
+ }
if (!getAllConnections().isEmpty()) {
if (!shouldHoldForEmergencyCall(phone)) {
// If we do not support holding ongoing calls for an outgoing
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index a76e4ab..61060d9 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -1952,6 +1952,179 @@
}
@Test
+ public void testDomainSelectionLocalHangupStartEmergencyCall() throws Exception {
+ setupForCallTest();
+
+ int selectedDomain = DOMAIN_CS;
+
+ setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ doReturn(future).when(mEmergencyStateTracker)
+ .startEmergencyCall(any(), anyString(), eq(false));
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ verify(mEmergencyStateTracker)
+ .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+
+ TelephonyConnection c = new TestTelephonyConnection();
+ c.setTelecomCallId(TELECOM_CALL_ID1);
+
+ // dialing is canceled
+ mTestConnectionService.onLocalHangup(c);
+
+ // startEmergencyCall has completed
+ future.complete(NOT_DISCONNECTED);
+
+ // verify that createEmergencyConnection is discarded
+ verify(mEmergencyCallDomainSelectionConnection, times(0))
+ .createEmergencyConnection(any(), any());
+ }
+
+ @Test
+ public void testDomainSelectionLocalHangupCreateEmergencyConnection() throws Exception {
+ setupForCallTest();
+
+ int selectedDomain = DOMAIN_CS;
+
+ setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+ .createEmergencyConnection(any(), any());
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+ TelephonyConnection c = new TestTelephonyConnection();
+ c.setTelecomCallId(TELECOM_CALL_ID1);
+
+ // dialing is canceled
+ mTestConnectionService.onLocalHangup(c);
+
+ // domain selection has completed
+ future.complete(selectedDomain);
+
+ // verify that dialing is discarded
+ verify(mPhone0, times(0)).dial(anyString(), any(), any());
+ }
+
+ @Test
+ public void testDomainSelectionRedialLocalHangupReselectDomain() throws Exception {
+ setupForCallTest();
+
+ int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+ int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+ int selectedDomain = DOMAIN_CS;
+
+ TestTelephonyConnection c = setupForReDialForDomainSelection(
+ mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+ c.setTelecomCallId(TELECOM_CALL_ID1);
+
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+ .reselectDomain(any());
+
+ assertTrue(mTestConnectionService.maybeReselectDomain(c, preciseDisconnectCause, null));
+ verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+
+ // dialing is canceled
+ mTestConnectionService.onLocalHangup(c);
+
+ // domain selection has completed
+ future.complete(selectedDomain);
+
+ // verify that dialing is discarded
+ verify(mPhone0, times(0)).dial(anyString(), any(), any());
+ }
+
+ @Test
+ public void testDomainSelectionNormalToEmergencyLocalHangupStartEmergencyCall()
+ throws Exception {
+ setupForCallTest();
+
+ int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+ int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+ int eccCategory = EMERGENCY_SERVICE_CATEGORY_POLICE;
+ int selectedDomain = DOMAIN_CS;
+
+ setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+ doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+
+ TestTelephonyConnection c = setupForReDialForDomainSelection(
+ mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+ c.setEmergencyServiceCategory(eccCategory);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
+ c.setTelecomCallId(TELECOM_CALL_ID1);
+
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ doReturn(future).when(mEmergencyStateTracker)
+ .startEmergencyCall(any(), anyString(), eq(false));
+
+ ImsReasonInfo reasonInfo = new ImsReasonInfo(CODE_SIP_ALTERNATE_EMERGENCY_CALL, 0, null);
+ assertTrue(mTestConnectionService.maybeReselectDomain(c,
+ preciseDisconnectCause, reasonInfo));
+
+ verify(mEmergencyStateTracker)
+ .startEmergencyCall(eq(mPhone0), eq(TELECOM_CALL_ID1), eq(false));
+
+ // dialing is canceled
+ mTestConnectionService.onLocalHangup(c);
+
+ // startEmergencyCall has completed
+ future.complete(NOT_DISCONNECTED);
+
+ // verify that createEmergencyConnection is discarded
+ verify(mEmergencyCallDomainSelectionConnection, times(0))
+ .createEmergencyConnection(any(), any());
+ }
+
+ @Test
+ public void testDomainSelectionNormalToEmergencyLocalHangupCreateEmergencyConnection()
+ throws Exception {
+ setupForCallTest();
+
+ int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+ int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+ int eccCategory = EMERGENCY_SERVICE_CATEGORY_POLICE;
+ int selectedDomain = DOMAIN_CS;
+
+ setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+ doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+
+ TestTelephonyConnection c = setupForReDialForDomainSelection(
+ mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
+ c.setEmergencyServiceCategory(eccCategory);
+ c.setAddress(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);
+ c.setTelecomCallId(TELECOM_CALL_ID1);
+
+ CompletableFuture<Integer> future = new CompletableFuture<>();
+ doReturn(future).when(mEmergencyCallDomainSelectionConnection)
+ .createEmergencyConnection(any(), any());
+
+ ImsReasonInfo reasonInfo = new ImsReasonInfo(CODE_SIP_ALTERNATE_EMERGENCY_CALL, 0, null);
+ assertTrue(mTestConnectionService.maybeReselectDomain(c,
+ preciseDisconnectCause, reasonInfo));
+
+ verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+ // dialing is canceled
+ mTestConnectionService.onLocalHangup(c);
+
+ // domain selection has completed
+ future.complete(selectedDomain);
+
+ // verify that dialing is discarded
+ verify(mPhone0, times(0)).dial(anyString(), any(), any());
+ }
+
+ @Test
public void testDomainSelectionWithMmiCode() {
//UT domain selection should not be handled by new domain selector.
doNothing().when(mContext).startActivity(any());