Implement maximum cellular timeout to trigger VoWi-Fi emergency
To support Wifi redial logic change to improve UX.
Bug: 265819822
Test: atest EmergencyCallDomainSelectorTest
Change-Id: Ie29ff9ce265268a92dedbcbcdbd6e0716bd67e2c
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 6848c9f..3388c97 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -42,6 +42,7 @@
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
@@ -109,6 +110,8 @@
@VisibleForTesting
public static final int MSG_NETWORK_SCAN_TIMEOUT = 12;
private static final int MSG_NETWORK_SCAN_RESULT = 13;
+ @VisibleForTesting
+ public static final int MSG_MAX_CELLULAR_TIMEOUT = 14;
private static final int NOT_SUPPORTED = -1;
@@ -180,6 +183,7 @@
private boolean mIsMonitoringConnectivity;
private boolean mWiFiAvailable;
private int mScanTimeout;
+ private int mMaxCellularTimeout;
private int mMaxNumOfVoWifiTries;
private boolean mVoWifiOverEmergencyPdn;
private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
@@ -199,6 +203,8 @@
private boolean mDomainSelected = false;
/** Indicates whether the cross sim redialing timer has expired. */
private boolean mCrossStackTimerExpired = false;
+ /** Indicates whether max cellular timer expired. */
+ private boolean mMaxCellularTimerExpired = false;
/**
* Indicates whether {@link #selectDomain(SelectionAttributes, TransportSelectionCallback)}
@@ -243,6 +249,10 @@
handleScanResult((EmergencyRegResult) msg.obj);
break;
+ case MSG_MAX_CELLULAR_TIMEOUT:
+ handleMaxCellularTimeout();
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -362,6 +372,18 @@
}
}
+ if (mMaxCellularTimerExpired) {
+ if (mLastTransportType == TRANSPORT_TYPE_WWAN
+ && maybeDialOverWlan()) {
+ // Cellular call failed and max cellular search timer expired, so redial on Wi-Fi.
+ // If this VoWi-Fi fails, the timer shall be restarted on next reselectDomain().
+ return;
+ } else if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
+ // Since VoWi-Fi failed, allow for requestScan to restart max cellular timer.
+ mMaxCellularTimerExpired = false;
+ }
+ }
+
if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
// Dialing over Wi-Fi failed. Try scanning cellular networks.
onWwanSelected(this::reselectDomainInternal);
@@ -477,6 +499,7 @@
KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
+ mMaxCellularTimeout = b.getInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT) * 1000;
mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
@@ -512,6 +535,7 @@
+ ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
+ ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
+ ", scanTimeout=" + mScanTimeout
+ + ", maxCellularTimeout=" + mMaxCellularTimeout
+ ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+ ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
+ ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
@@ -699,6 +723,9 @@
registerForConnectivityChanges();
}
}
+ if (!mMaxCellularTimerExpired && !hasMessages(MSG_MAX_CELLULAR_TIMEOUT)) {
+ startMaxCellularTimer();
+ }
}
/**
@@ -811,8 +838,33 @@
return preferredNetworks;
}
+ private void handleMaxCellularTimeout() {
+ logi("handleMaxCellularTimeout");
+ if (mVoWifiTrialCount >= mMaxNumOfVoWifiTries) {
+ logi("handleMaxCellularTimeout already tried maximum");
+ return;
+ }
+
+ mMaxCellularTimerExpired = true;
+
+ if (mDomainSelected) {
+ // Dialing is already requested.
+ logi("handleMaxCellularTimeout wait for reselectDomain");
+ return;
+ }
+
+ if (!maybeDialOverWlan()) {
+ logd("handleMaxCellularTimeout VoWi-Fi is not available");
+ }
+ }
+
private void handleNetworkScanTimeout() {
- logi("handleNetworkScanTimeout overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+ logi("handleNetworkScanTimeout");
+ maybeDialOverWlan();
+ }
+
+ private boolean maybeDialOverWlan() {
+ logi("maybeDialOverWlan overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+ ", wifiAvailable=" + mWiFiAvailable);
boolean available = mWiFiAvailable;
if (mVoWifiOverEmergencyPdn) {
@@ -837,7 +889,7 @@
available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
}
- logi("handleNetworkScanTimeout VoWi-Fi available=" + available);
+ logi("maybeDialOverWlan VoWi-Fi available=" + available);
if (available) {
if (mCancelSignal != null) {
mCancelSignal.cancel();
@@ -845,6 +897,8 @@
}
onWlanSelected();
}
+
+ return available;
}
/**
@@ -983,7 +1037,11 @@
private boolean isEmcOverWifiSupported() {
if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
List<Integer> domains = getDomainPreference();
- return domains.contains(DOMAIN_PS_NON_3GPP);
+ boolean ret = domains.contains(DOMAIN_PS_NON_3GPP);
+ logi("isEmcOverWifiSupported " + ret);
+ return ret;
+ } else {
+ logi("isEmcOverWifiSupported invalid subId");
}
return false;
}
@@ -1184,6 +1242,8 @@
mVoWifiTrialCount++;
mTransportSelectorCallback.onWlanSelected(mVoWifiOverEmergencyPdn);
mWwanSelectorCallback = null;
+ removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
+ removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
}
private void onWwanSelected(Runnable runnable) {
@@ -1251,6 +1311,19 @@
}
}
+ /** Starts the max cellular timer. */
+ private void startMaxCellularTimer() {
+ logd("startMaxCellularTimer tried=" + mVoWifiTrialCount
+ + ", max=" + mMaxNumOfVoWifiTries);
+ if (isEmcOverWifiSupported()
+ && (mMaxCellularTimeout > 0)
+ && (mVoWifiTrialCount < mMaxNumOfVoWifiTries)) {
+ logi("startMaxCellularTimer start timer");
+ sendEmptyMessageDelayed(MSG_MAX_CELLULAR_TIMEOUT, mMaxCellularTimeout);
+ registerForConnectivityChanges();
+ }
+ }
+
private boolean allowEmergencyCalls(EmergencyRegResult regResult) {
if (mModemCount < 2) return true;
if (regResult == null) {
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 72162b8..9be85ed 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -37,6 +37,7 @@
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE;
@@ -52,6 +53,7 @@
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN;
+import static com.android.services.telephony.domainselection.EmergencyCallDomainSelector.MSG_MAX_CELLULAR_TIMEOUT;
import static com.android.services.telephony.domainselection.EmergencyCallDomainSelector.MSG_NETWORK_SCAN_TIMEOUT;
import static junit.framework.Assert.assertEquals;
@@ -1679,6 +1681,172 @@
assertFalse(mAccessNetwork.contains(EUTRAN));
}
+ @Test
+ public void testMaxCellularTimeout() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 20);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ setupForHandleScanResult();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
+
+ // Max cellular timer expired
+ mDomainSelector.removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
+
+ assertFalse(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+ }
+
+
+ @Test
+ public void testMaxCellularTimeoutScanTimeout() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 20);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ setupForHandleScanResult();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
+
+ // Scan timer expired
+ mDomainSelector.removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+ }
+
+ @Test
+ public void testMaxCellularTimeoutWhileDialingOnCellular() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 5);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_CS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+
+ verifyCsDialed();
+
+ assertFalse(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ mDomainSelector.reselectDomain(attr);
+ processAllMessages();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
+ processAllMessages();
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+ // Max cellular timer expired
+ mDomainSelector.removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
+ processAllMessages();
+
+ mDomainSelector.reselectDomain(attr);
+ processAllMessages();
+
+ assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+ }
+
+ @Test
+ public void testMaxCellularTimeoutWileDialingOnWlan() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 20);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ setupForHandleScanResult();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
+
+ // Network scan timer expired
+ mDomainSelector.removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+ assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+ }
+
+ @Test
+ public void testMaxCellularTimeoutWileDialingOnWlanAllowMultipleTries() throws Exception {
+ PersistableBundle bundle = getDefaultPersistableBundle();
+ bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, 20);
+ bundle.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, 2);
+ when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+ setupForHandleScanResult();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(0)).onWlanSelected(anyBoolean());
+
+ // Wi-Fi is connected.
+ mNetworkCallback.onAvailable(null);
+
+ // Network scan timer expired
+ mDomainSelector.removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected(anyBoolean());
+ assertFalse(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ EmergencyRegResult regResult = getEmergencyRegResult(UTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_CS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.reselectDomain(attr);
+ processAllMessages();
+
+ assertTrue(mDomainSelector.hasMessages(MSG_MAX_CELLULAR_TIMEOUT));
+
+ // Max cellular timer expired
+ mDomainSelector.removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_MAX_CELLULAR_TIMEOUT));
+ processAllMessages();
+
+ verify(mTransportSelectorCallback, times(2)).onWlanSelected(anyBoolean());
+ }
+
private void setupForScanListTest(PersistableBundle bundle) throws Exception {
setupForScanListTest(bundle, false);
}
@@ -1851,6 +2019,7 @@
int voWifiRequiresCondition = VOWIFI_REQUIRES_NONE;
int maxRetriesOverWiFi = 1;
int cellularScanTimerSec = 10;
+ int maxCellularTimerSec = 0;
boolean voWifiOverEmergencyPdn = false;
int scanType = SCAN_TYPE_NO_PREFERENCE;
boolean requiresImsRegistration = false;
@@ -1861,7 +2030,7 @@
return getPersistableBundle(imsRats, csRats, imsRoamRats, csRoamRats,
domainPreference, roamDomainPreference, imsWhenVoiceOnCs,
voWifiRequiresCondition, maxRetriesOverWiFi, cellularScanTimerSec,
- scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
+ maxCellularTimerSec, scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
requiresVoLteEnabled, ltePreferredAfterNrFailed, cdmaPreferredNumbers);
}
@@ -1870,7 +2039,8 @@
@Nullable int[] imsRoamRats, @Nullable int[] csRoamRats,
@Nullable int[] domainPreference, @Nullable int[] roamDomainPreference,
boolean imsWhenVoiceOnCs, int voWifiRequiresCondition,
- int maxRetriesOverWiFi, int cellularScanTimerSec, int scanType,
+ int maxRetriesOverWiFi, int cellularScanTimerSec,
+ int maxCellularTimerSec, int scanType,
boolean voWifiOverEmergencyPdn, boolean requiresImsRegistration,
boolean requiresVoLteEnabled, boolean ltePreferredAfterNrFailed,
@Nullable String[] cdmaPreferredNumbers) {
@@ -1905,6 +2075,7 @@
bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, voWifiRequiresCondition);
bundle.putInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT, maxRetriesOverWiFi);
bundle.putInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT, cellularScanTimerSec);
+ bundle.putInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT, maxCellularTimerSec);
bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, voWifiOverEmergencyPdn);
bundle.putInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT, scanType);
bundle.putBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL, requiresImsRegistration);