Merge "Switch stacks when the current stack has limited service" into main
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 10c0776..b8b3359 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -1759,6 +1759,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();