Merge "Delay dialing normal routing emergency number in airplane mode" into udc-dev
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 91d345f..18b95e1 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -43,8 +43,10 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.CarrierConfigManager;
+import android.telephony.DataSpecificRegistrationInfo;
import android.telephony.DomainSelectionService;
import android.telephony.DomainSelectionService.SelectionAttributes;
import android.telephony.EmergencyRegResult;
@@ -123,6 +125,10 @@
// from the modem.
private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1000;
+ // Timeout to start dynamic routing of normal routing emergency numbers.
+ @VisibleForTesting
+ public static final int TIMEOUT_TO_DYNAMIC_ROUTING_MS = 10000;
+
// Timeout before we terminate the outgoing DSDA call if HOLD did not complete in time on the
// existing call.
private static final int DEFAULT_DSDA_OUTGOING_CALL_HOLD_TIMEOUT_MS = 2000;
@@ -1083,6 +1089,8 @@
if (isEmergencyNumber) {
mIsEmergencyCallPending = true;
}
+ int timeoutToOnTimeoutCallback = mDomainSelectionResolver.isDomainSelectionSupported()
+ ? TIMEOUT_TO_DYNAMIC_ROUTING_MS : 0;
mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() {
@Override
public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
@@ -1091,13 +1099,33 @@
}
@Override
- public boolean isOkToCall(Phone phone, int serviceState) {
+ public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
+ if (mDomainSelectionResolver.isDomainSelectionSupported()) {
+ return isEmergencyNumber;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
// HAL 1.4 introduced a new variant of dial for emergency calls, which includes
// an isTesting parameter. For HAL 1.4+, do not wait for IN_SERVICE, this will
// be handled at the RIL/vendor level by emergencyDial(...).
boolean waitForInServiceToDialEmergency = isTestEmergencyNumber
&& phone.getHalVersion(HAL_SERVICE_VOICE)
.less(RIL.RADIO_HAL_VERSION_1_4);
+ if (mDomainSelectionResolver.isDomainSelectionSupported()) {
+ if (isEmergencyNumber) {
+ // Since the domain selection service is enabled,
+ // dilaing normal routing emergency number only reaches here.
+ if (!isVoiceInService(phone, imsVoiceCapable)) {
+ // Wait for voice in service.
+ // That is, wait for IMS registration on PS only network.
+ serviceState = ServiceState.STATE_OUT_OF_SERVICE;
+ waitForInServiceToDialEmergency = true;
+ }
+ }
+ }
if (isEmergencyNumber && !waitForInServiceToDialEmergency) {
// We currently only look to make sure that the radio is on before dialing.
// We should be able to make emergency calls at any time after the radio has
@@ -1119,7 +1147,8 @@
|| serviceState == ServiceState.STATE_IN_SERVICE;
}
}
- }, isEmergencyNumber && !isTestEmergencyNumber, phone, isTestEmergencyNumber);
+ }, isEmergencyNumber && !isTestEmergencyNumber, phone, isTestEmergencyNumber,
+ timeoutToOnTimeoutCallback);
// Return the still unconnected GsmConnection and wait for the Radios to boot before
// connecting it to the underlying Phone.
return resultConnection;
@@ -2527,6 +2556,44 @@
return false;
}
+ private boolean isVoiceInService(Phone phone, boolean imsVoiceCapable) {
+ // Dialing normal call is available.
+ if (phone.isWifiCallingEnabled()) {
+ Log.i(this, "isVoiceInService VoWi-Fi available");
+ return true;
+ }
+
+ ServiceState ss = phone.getServiceStateTracker().getServiceState();
+ if (ss.getState() != ServiceState.STATE_IN_SERVICE) return false;
+
+ NetworkRegistrationInfo regState = ss.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (regState != null) {
+ int registrationState = regState.getRegistrationState();
+ if (registrationState != NetworkRegistrationInfo.REGISTRATION_STATE_HOME
+ && registrationState != NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) {
+ return true;
+ }
+
+ int networkType = regState.getAccessNetworkTechnology();
+ if (networkType == TelephonyManager.NETWORK_TYPE_LTE) {
+ DataSpecificRegistrationInfo regInfo = regState.getDataSpecificInfo();
+ if (regInfo.getLteAttachResultType()
+ == DataSpecificRegistrationInfo.LTE_ATTACH_TYPE_COMBINED) {
+ Log.i(this, "isVoiceInService combined attach");
+ return true;
+ }
+ }
+
+ if (networkType == TelephonyManager.NETWORK_TYPE_NR
+ || networkType == TelephonyManager.NETWORK_TYPE_LTE) {
+ Log.i(this, "isVoiceInService PS only network, IMS available " + imsVoiceCapable);
+ return imsVoiceCapable;
+ }
+ }
+ return true;
+ }
+
private boolean maybeReselectDomainForNormalCall(
final TelephonyConnection c, int callFailCause, ImsReasonInfo reasonInfo) {
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index d144d9d..fadfaaf 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -27,6 +27,7 @@
import static android.telephony.ims.ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL;
import static com.android.internal.telephony.RILConstants.GSM_PHONE;
+import static com.android.services.telephony.TelephonyConnectionService.TIMEOUT_TO_DYNAMIC_ROUTING_MS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -62,8 +63,11 @@
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
+import android.telephony.DataSpecificRegistrationInfo;
import android.telephony.DomainSelectionService;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -1240,11 +1244,13 @@
ArgumentCaptor<RadioOnStateListener.Callback> callback =
ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
- eq(testPhone), eq(false));
+ eq(testPhone), eq(false), eq(0));
- assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ assertFalse(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
when(mSST.isRadioOn()).thenReturn(true);
- assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ assertTrue(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
mConnection.setDisconnected(null);
callback.getValue().onComplete(null, true);
@@ -1266,11 +1272,13 @@
ArgumentCaptor<RadioOnStateListener.Callback> callback =
ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
- eq(testPhone), eq(false));
+ eq(testPhone), eq(false), eq(0));
- assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ assertFalse(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
when(mSST.isRadioOn()).thenReturn(true);
- assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ assertTrue(callback.getValue()
+ .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
callback.getValue().onComplete(null, true);
@@ -2010,6 +2018,255 @@
}
@Test
+ public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_InService()
+ throws Exception {
+ setupForCallTest();
+
+ doReturn(false).when(mPhone0).isRadioOn();
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_POWER_OFF);
+ when(mPhone0.getServiceState()).thenReturn(ss);
+ when(mSST.getServiceState()).thenReturn(ss);
+
+ setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
+
+ EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+ doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+ assertFalse(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+
+ when(mSST.isRadioOn()).thenReturn(true);
+
+ assertFalse(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+
+ ss.setState(ServiceState.STATE_IN_SERVICE);
+
+ assertTrue(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+ }
+
+ @Test
+ public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_Timeout()
+ throws Exception {
+ setupForCallTest();
+
+ doReturn(false).when(mPhone0).isRadioOn();
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_POWER_OFF);
+ when(mPhone0.getServiceState()).thenReturn(ss);
+ when(mSST.getServiceState()).thenReturn(ss);
+
+ setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
+
+ EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+ doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+ when(mSST.isRadioOn()).thenReturn(true);
+
+ assertFalse(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+ assertTrue(callback.getValue()
+ .onTimeout(mPhone0, ServiceState.STATE_OUT_OF_SERVICE, false));
+ }
+
+ @Test
+ public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_CombinedAttach()
+ throws Exception {
+ setupForCallTest();
+
+ doReturn(false).when(mPhone0).isRadioOn();
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_POWER_OFF);
+ when(mPhone0.getServiceState()).thenReturn(ss);
+ when(mSST.getServiceState()).thenReturn(ss);
+
+ setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
+
+ EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+ doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+ when(mSST.isRadioOn()).thenReturn(true);
+ ss.setState(ServiceState.STATE_IN_SERVICE);
+
+ DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
+ .setLteAttachResultType(DataSpecificRegistrationInfo.LTE_ATTACH_TYPE_COMBINED)
+ .build();
+
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ .setDataSpecificInfo(dsri)
+ .build();
+ ss.addNetworkRegistrationInfo(nri);
+
+ assertTrue(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+ }
+
+ @Test
+ public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_PsOnly()
+ throws Exception {
+ setupForCallTest();
+
+ doReturn(false).when(mPhone0).isRadioOn();
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_POWER_OFF);
+ when(mPhone0.getServiceState()).thenReturn(ss);
+ when(mSST.getServiceState()).thenReturn(ss);
+
+ setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
+
+ EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+ doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+ when(mSST.isRadioOn()).thenReturn(true);
+ ss.setState(ServiceState.STATE_IN_SERVICE);
+
+ DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
+ .build();
+
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ .setDataSpecificInfo(dsri)
+ .build();
+ ss.addNetworkRegistrationInfo(nri);
+
+ assertFalse(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+ assertTrue(callback.getValue()
+ .onTimeout(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+ }
+
+ @Test
+ public void testDomainSelectionNormalRoutingEmergencyNumber_exitingApm_PsOnly_ImsRegistered()
+ throws Exception {
+ setupForCallTest();
+
+ doReturn(false).when(mPhone0).isRadioOn();
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_POWER_OFF);
+ when(mPhone0.getServiceState()).thenReturn(ss);
+ when(mSST.getServiceState()).thenReturn(ss);
+
+ setupForDialForDomainSelection(mPhone0, DOMAIN_CS, false);
+
+ EmergencyNumber emergencyNumber = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED,
+ Collections.emptyList(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);
+
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
+ doReturn(emergencyNumber).when(mEmergencyNumberTracker).getEmergencyNumber(anyString());
+
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ any(), eq(false), eq(TIMEOUT_TO_DYNAMIC_ROUTING_MS));
+
+ when(mSST.isRadioOn()).thenReturn(true);
+ ss.setState(ServiceState.STATE_IN_SERVICE);
+
+ DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(3)
+ .build();
+
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ .setDataSpecificInfo(dsri)
+ .build();
+ ss.addNetworkRegistrationInfo(nri);
+
+ assertFalse(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, false));
+ assertTrue(callback.getValue()
+ .isOkToCall(mPhone0, ServiceState.STATE_IN_SERVICE, true));
+ }
+
+ @Test
public void testDomainSelectionNormalToEmergencyCs() throws Exception {
setupForCallTest();