Switch stacks when the current stack has limited service
Per resource configuration, switch stacks
when current stack has limited service and there is
another stack with which normal service is available
in some countries.
Bug: 325193155
Test: atest EmergencyCallDomainSelectorTest
Change-Id: I85b1d1d950c12084b60eaad98812802db753a8a6
diff --git a/res/values/config.xml b/res/values/config.xml
index 7cd4e18..cfb472e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -337,6 +337,14 @@
<item>de</item>
</string-array>
+ <!-- Array of countries that a normal service capable subscription is preferred
+ for emergency calls. Values should be ISO3166 country codes in lowercase. -->
+ <string-array name="config_countries_prefer_normal_service_capable_subscription"
+ translatable="false">
+ <!-- b/317945295 -->
+ <item>in</item>
+ </string-array>
+
<!-- The component name(a flattened ComponentName string) for the telephony domain selection
service. The device should fallback to the modem based domain selection architecture
if this is not configured. -->
diff --git a/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
index 44904f4..d368d46 100644
--- a/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
+++ b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
@@ -29,9 +29,12 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.os.SystemProperties;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
@@ -144,7 +147,7 @@
* @param selector The instance of {@link EmergencyCallDomainSelector}.
* @param callId The call identifier.
* @param number The dialing number.
- * @param inService Indiates that normal service is available.
+ * @param inService Indicates that normal service is available.
* @param roaming Indicates that it's in roaming or non-domestic network.
* @param modemCount The number of active modem count
*/
@@ -228,12 +231,26 @@
}
/**
+ * Returns whether there is another slot with which normal service is available.
+ *
+ * @return {@code true} if there is another slot with which normal service is available.
+ * {@code false} otherwise.
+ */
+ public boolean isThereOtherSlotInService() {
+ return isThereOtherSlot(true);
+ }
+
+ /**
* Returns whether there is another slot emergency capable.
*
* @return {@code true} if there is another slot emergency capable,
* {@code false} otherwise.
*/
public boolean isThereOtherSlot() {
+ return isThereOtherSlot(false);
+ }
+
+ private boolean isThereOtherSlot(boolean networkRegisteredOnly) {
logi("isThereOtherSlot modemCount=" + mModemCount);
if (mModemCount < 2) return false;
@@ -254,7 +271,13 @@
int subId = SubscriptionManager.getSubscriptionId(i);
if (mEmergencyNumberHelper.isEmergencyNumber(subId, mNumber)) {
logi("isThereOtherSlot index=" + i + "(" + subId + "), found");
- return true;
+ if (networkRegisteredOnly) {
+ if (isNetworkRegistered(subId)) {
+ return true;
+ }
+ } else {
+ return true;
+ }
} else {
logi("isThereOtherSlot index=" + i + "(" + subId + "), not emergency number");
}
@@ -263,6 +286,31 @@
return false;
}
+ private boolean isNetworkRegistered(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+
+ TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId);
+ ServiceState ss = tm.getServiceState();
+ if (ss != null) {
+ NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null && nri.isNetworkRegistered()) {
+ // PS is IN_SERVICE state.
+ return true;
+ }
+ nri = ss.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null && nri.isNetworkRegistered()) {
+ // CS is IN_SERVICE state.
+ return true;
+ }
+ }
+ logi("isNetworkRegistered subId=" + subId + " not network registered");
+ return false;
+ }
+
/**
* Caches the configuration.
*/
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index f48ea46..05ae1f0 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -118,6 +118,7 @@
private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
private static List<String> sSimReadyAllowList;
+ private static List<String> sPreferSlotWithNormalServiceList;
/**
* Network callback used to determine whether Wi-Fi is connected or not.
@@ -576,26 +577,43 @@
* Caches the resource configuration.
*/
private void readResourceConfiguration() {
- if (sSimReadyAllowList != null) return;
+ if (sSimReadyAllowList == null) {
+ sSimReadyAllowList = readResourceConfiguration(
+ R.array.config_countries_require_sim_for_emergency);
+ }
+ logi("readResourceConfiguration simReadyCountries=" + sSimReadyAllowList);
+
+ if (sPreferSlotWithNormalServiceList == null) {
+ sPreferSlotWithNormalServiceList = readResourceConfiguration(
+ R.array.config_countries_prefer_normal_service_capable_subscription);
+ }
+ logi("readResourceConfiguration preferNormalServiceCountries="
+ + sPreferSlotWithNormalServiceList);
+ }
+
+ private List<String> readResourceConfiguration(int id) {
+ logi("readResourceConfiguration id=" + id);
+
+ List<String> resource = null;
try {
- sSimReadyAllowList = Arrays.asList(mContext.getResources().getStringArray(
- R.array.config_countries_require_sim_for_emergency));
+ resource = Arrays.asList(mContext.getResources().getStringArray(id));
} catch (Resources.NotFoundException nfe) {
loge("readResourceConfiguration exception=" + nfe);
} catch (NullPointerException npe) {
loge("readResourceConfiguration exception=" + npe);
} finally {
- if (sSimReadyAllowList == null) {
- sSimReadyAllowList = new ArrayList<String>();
+ if (resource == null) {
+ resource = new ArrayList<String>();
}
}
- logi("readResourceConfiguration simReadyCountries=" + sSimReadyAllowList);
+ return resource;
}
/** For test purpose only */
@VisibleForTesting
public void clearResourceConfiguration() {
sSimReadyAllowList = null;
+ sPreferSlotWithNormalServiceList = null;
}
private void selectDomain() {
@@ -643,6 +661,9 @@
boolean psInService = isPsInService();
if (!csInService && !psInService) {
+ if (maybeRedialOnTheOtherSlotInNormalService()) {
+ return;
+ }
mCsNetworkType = getSelectableCsNetworkType();
mPsNetworkType = getSelectablePsNetworkType(false);
logi("selectDomain limited service ps=" + accessNetworkTypeToString(mPsNetworkType)
@@ -1400,6 +1421,20 @@
return true;
}
+ private boolean maybeRedialOnTheOtherSlotInNormalService() {
+ EmergencyRegistrationResult regResult =
+ mSelectionAttributes.getEmergencyRegistrationResult();
+ if (regResult == null) return false;
+
+ String iso = regResult.getCountryIso();
+ if (sPreferSlotWithNormalServiceList.contains(iso)
+ && mCrossSimRedialingController.isThereOtherSlotInService()) {
+ terminateSelectionForCrossSimRedialing(false);
+ return true;
+ }
+ return false;
+ }
+
private void terminateSelectionPermanentlyForSlot() {
logi("terminateSelectionPermanentlyForSlot");
terminateSelection(true);
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index b9c1845..89c03e7 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -1758,6 +1758,28 @@
}
@Test
+ public void testDualSimNormalServiceOnTheOtherSubscription() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+ doReturn(2).when(mTelephonyManager).getActiveModemCount();
+ doReturn(true).when(mCsrdCtrl).isThereOtherSlotInService();
+ doReturn(new String[] {"in"}).when(mResources).getStringArray(anyInt());
+
+ EmergencyRegistrationResult regResult = getEmergencyRegResult(EUTRAN,
+ REGISTRATION_STATE_UNKNOWN,
+ 0, false, false, 0, 0, "", "", "in");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ verify(mTransportSelectorCallback, times(1))
+ .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+ }
+
+ @Test
public void testEutranWithCsDomainOnly() throws Exception {
setupForHandleScanResult();