Merge "Change the way to determine the availability of emergency over VoWi-Fi"
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index ae4659d..53a60af 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -41,14 +41,22 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 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_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;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
 import android.os.CancellationSignal;
 import android.os.Looper;
 import android.os.Message;
@@ -69,6 +77,7 @@
 import android.telephony.TransportSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.text.TextUtils;
 import android.util.LocalLog;
 
@@ -97,6 +106,30 @@
 
     private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
 
+    /**
+     * Network callback used to determine whether Wi-Fi is connected or not.
+     */
+    private ConnectivityManager.NetworkCallback mNetworkCallback =
+            new ConnectivityManager.NetworkCallback() {
+                @Override
+                public void onAvailable(Network network) {
+                    logi("onAvailable: " + network);
+                    mWiFiAvailable = true;
+                }
+
+                @Override
+                public void onLost(Network network) {
+                    logi("onLost: " + network);
+                    mWiFiAvailable = false;
+                }
+
+                @Override
+                public void onUnavailable() {
+                    logi("onUnavailable");
+                    mWiFiAvailable = false;
+                }
+            };
+
     private boolean mIsEmergencyBarred;
     private boolean mImsRegistered;
     private boolean mIsVoiceCapable;
@@ -122,8 +155,12 @@
     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
     private List<String> mCdmaPreferredNumbers;
     private boolean mPreferImsWhenCallsOnCs;
+    private int mVoWifiRequiresCondition;
+    private boolean mIsMonitoringConnectivity;
+    private boolean mWiFiAvailable;
     private int mScanTimeout;
     private int mMaxNumOfVoWifiTries;
+    private boolean mVoWifiOverEmergencyPdn;
     private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
     private int mCallSetupTimerOnCurrentRat;
     private boolean mRequiresImsRegistration;
@@ -353,8 +390,10 @@
         mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
         mPreferImsWhenCallsOnCs = b.getBoolean(
                 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;
         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);
         mCallSetupTimerOnCurrentRat = b.getInt(
                 KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
@@ -386,8 +425,10 @@
                 + ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
                         EmergencyCallDomainSelector::domainPreferenceToString)
                 + ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
+                + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
                 + ", scanTimeout=" + mScanTimeout
                 + ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+                + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
                 + ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
                         mPreferredNetworkScanType)
                 + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
@@ -560,6 +601,7 @@
                 // remove any pending timers.
                 removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
                 sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
+                registerForConnectivityChanges();
             }
         }
     }
@@ -639,8 +681,33 @@
     }
 
     private void handleNetworkScanTimeout() {
-        if (isImsRegisteredWithVoiceCapability()
-                && isImsRegisteredOverWifi()) {
+        logi("handleNetworkScanTimeout overEmergencyPdn=" + mVoWifiOverEmergencyPdn
+                + ", wifiAvailable=" + mWiFiAvailable);
+        boolean available = mWiFiAvailable;
+        if (mVoWifiOverEmergencyPdn) {
+            // SOS APN
+            if (!available && isImsRegisteredOverCrossSim()) {
+                available = true;
+            }
+            if (available) {
+                switch (mVoWifiRequiresCondition) {
+                    case VOWIFI_REQUIRES_SETTING_ENABLED:
+                        available = isWifiCallingSettingEnabled();
+                        break;
+                    case VOWIFI_REQUIRES_VALID_EID:
+                        available = isWifiCallingActivated();
+                        break;
+                    default:
+                        break;
+                }
+            }
+        } else {
+            // IMS APN. When IMS is already registered over Wi-Fi.
+            available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
+        }
+
+        logi("handleNetworkScanTimeout VoWi-Fi available=" + available);
+        if (available) {
             if (mCancelSignal != null) {
                 mCancelSignal.cancel();
                 mCancelSignal = null;
@@ -811,6 +878,41 @@
         return true;
     }
 
+    private boolean isWifiCallingActivated() {
+        try {
+            ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+            ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
+            String eid = pm.getProvisioningStringValue(
+                    ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
+            boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
+            logi("isWifiCallingActivated " + activated);
+            return activated;
+        } catch (Exception e) {
+            logi("isWifiCallingActivated e=" + e);
+        }
+        return false;
+    }
+
+    private boolean isWifiCallingSettingEnabled() {
+        boolean result = false;
+        try {
+            if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+                ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
+                ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
+                if (isInRoaming()) {
+                    result = mmTelManager.isVoWiFiRoamingSettingEnabled();
+                } else {
+                    result = mmTelManager.isVoWiFiSettingEnabled();
+                }
+                logi("isWifiCallingSettingEnabled " + result);
+                return result;
+            }
+        } catch (Exception e) {
+            logi("isWifiCallingSettingEnabled e=" + e);
+        }
+        return result;
+    }
+
     private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
         int[] rats = mImsRatsConfig;
         if (isInRoaming()) rats = mImsRoamRatsConfig;
@@ -897,6 +999,21 @@
     }
 
     /**
+     * Determines whether IMS is registered over the mobile data of another subscription.
+     *
+     * @return {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    private boolean isImsRegisteredOverCrossSim() {
+        boolean ret = false;
+        if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
+            ret = mImsStateTracker.isImsRegisteredOverCrossSim();
+        }
+
+        logi("isImsRegisteredOverCrossSim " + ret);
+        return ret;
+    }
+
+    /**
      * Determines whether IMS is registered with voice capability.
      *
      * @return {@code true} if IMS is registered with voice capability.
@@ -952,6 +1069,40 @@
         mWwanSelectorCallback.onDomainSelected(domain);
     }
 
+    /**
+     * Registers for changes to network connectivity.
+     */
+    private void registerForConnectivityChanges() {
+        if (mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("registerForConnectivityChanges");
+            NetworkRequest.Builder builder = new NetworkRequest.Builder();
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+            cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+            mIsMonitoringConnectivity = true;
+        }
+    }
+
+    /**
+     * Unregisters for connectivity changes.
+     */
+    private void unregisterForConnectivityChanges() {
+        if (!mIsMonitoringConnectivity) {
+            return;
+        }
+
+        ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm != null) {
+            logi("unregisterForConnectivityChanges");
+            cm.unregisterNetworkCallback(mNetworkCallback);
+            mIsMonitoringConnectivity = false;
+        }
+    }
+
     private static String arrayToString(int[] intArray, IntFunction<String> func) {
         int length = intArray.length;
         StringBuilder sb = new StringBuilder("{");
@@ -1027,6 +1178,7 @@
         mDestroyed = true;
         mImsStateTracker.removeBarringInfoListener(this);
         mImsStateTracker.removeImsStateListener(this);
+        unregisterForConnectivityChanges();
 
         super.destroy();
     }
diff --git a/src/com/android/services/telephony/domainselection/ImsStateTracker.java b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
index ee19d68..fc3f811 100644
--- a/src/com/android/services/telephony/domainselection/ImsStateTracker.java
+++ b/src/com/android/services/telephony/domainselection/ImsStateTracker.java
@@ -130,6 +130,7 @@
     /** The IMS registration state and the network type that performed IMS registration. */
     private Boolean mImsRegistered;
     private @RadioAccessNetworkType int mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+    private Boolean mImsRegisteredOverCrossSim;
     /** The MMTEL capabilities - Voice, Video, SMS, and Ut. */
     private MmTelCapabilities mMmTelCapabilities;
     private final Runnable mMmTelFeatureUnavailableRunnable = new Runnable() {
@@ -361,6 +362,13 @@
     }
 
     /**
+     * Returns {@code true} if IMS is registered over the mobile data of another subscription.
+     */
+    public boolean isImsRegisteredOverCrossSim() {
+        return mImsRegisteredOverCrossSim != null && mImsRegisteredOverCrossSim;
+    }
+
+    /**
      * Returns {@code true} if IMS voice call is capable, {@code false} otherwise.
      */
     public boolean isImsVoiceCapable() {
@@ -406,6 +414,7 @@
         mMmTelFeatureAvailable = null;
         mImsRegistered = null;
         mImsAccessNetworkType = AccessNetworkType.UNKNOWN;
+        mImsRegisteredOverCrossSim = null;
         mMmTelCapabilities = null;
     }
 
@@ -418,6 +427,7 @@
         setMmTelFeatureAvailable(false);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
     }
 
@@ -450,6 +460,13 @@
         }
     }
 
+    private void setImsRegisteredOverCrossSim(boolean crossSim) {
+        if (!Objects.equals(mImsRegisteredOverCrossSim, Boolean.valueOf(crossSim))) {
+            logi("setImsRegisteredOverCrossSim: " + mImsRegisteredOverCrossSim + " >> " + crossSim);
+            mImsRegisteredOverCrossSim = Boolean.valueOf(crossSim);
+        }
+    }
+
     /**
      * Notifies the specified listener of the current IMS state if it's valid.
      *
@@ -565,6 +582,8 @@
         setImsRegistered(true);
         setImsAccessNetworkType(
                 imsRegTechToAccessNetworkType(attributes.getRegistrationTechnology()));
+        setImsRegisteredOverCrossSim(attributes.getRegistrationTechnology()
+                == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
         notifyImsRegistrationStateChanged();
     }
 
@@ -575,6 +594,7 @@
         logd("onImsUnregistered: " + info);
         setImsRegistered(false);
         setImsAccessNetworkType(AccessNetworkType.UNKNOWN);
+        setImsRegisteredOverCrossSim(false);
         setMmTelCapabilities(new MmTelCapabilities());
         notifyImsRegistrationStateChanged();
     }
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 3f6ce98..7a01004 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -35,9 +35,14 @@
 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
 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_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_NO_PREFERENCE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_NONE;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
+import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
+import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
 import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS;
 import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
@@ -62,6 +67,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IPowerManager;
@@ -82,6 +89,7 @@
 import android.telephony.WwanSelectorCallback;
 import android.telephony.ims.ImsManager;
 import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ProvisioningManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableLooper;
 import android.util.Log;
@@ -111,12 +119,14 @@
     private static final int SLOT_0_SUB_ID = 1;
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
+    @Mock private ConnectivityManager mConnectivityManager;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private WwanSelectorCallback mWwanSelectorCallback;
     @Mock private TransportSelectorCallback mTransportSelectorCallback;
     @Mock private ImsMmTelManager mMmTelManager;
     @Mock private ImsStateTracker mImsStateTracker;
     @Mock private DomainSelectorBase.DestroyListener mDestroyListener;
+    @Mock private ProvisioningManager mProvisioningManager;
 
     private Context mContext;
 
@@ -126,6 +136,7 @@
     private SelectionAttributes mSelectionAttributes;
     private @AccessNetworkConstants.RadioAccessNetworkType List<Integer> mAccessNetwork;
     private PowerManager mPowerManager;
+    private ConnectivityManager.NetworkCallback mNetworkCallback;
 
     @Before
     public void setUp() throws Exception {
@@ -141,6 +152,8 @@
                     return Context.CARRIER_CONFIG_SERVICE;
                 } else if (serviceClass == PowerManager.class) {
                     return Context.POWER_SERVICE;
+                } else if (serviceClass == ConnectivityManager.class) {
+                    return Context.CONNECTIVITY_SERVICE;
                 }
                 return super.getSystemServiceName(serviceClass);
             }
@@ -151,6 +164,9 @@
                     case (Context.POWER_SERVICE) : {
                         return mPowerManager;
                     }
+                    case (Context.CONNECTIVITY_SERVICE) : {
+                        return mConnectivityManager;
+                    }
                 }
                 return super.getSystemService(name);
             }
@@ -183,6 +199,17 @@
         when(mCarrierConfigManager.getConfigForSubId(anyInt()))
             .thenReturn(getDefaultPersistableBundle());
 
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                mNetworkCallback = (ConnectivityManager.NetworkCallback)
+                        invocation.getArguments()[1];
+                return null;
+            }
+        }).when(mConnectivityManager).registerNetworkCallback(
+                any(NetworkRequest.class), any(ConnectivityManager.NetworkCallback.class));
+
         IPowerManager powerManager = mock(IPowerManager.class);
         mPowerManager = new PowerManager(mContext, powerManager, mock(IThermalService.class),
                 new Handler(mHandlerThread.getLooper()));
@@ -190,6 +217,8 @@
         ImsManager imsManager = mContext.getSystemService(ImsManager.class);
         when(imsManager.getImsMmTelManager(anyInt())).thenReturn(mMmTelManager);
         when(mMmTelManager.isAdvancedCallingSettingEnabled()).thenReturn(true);
+        doReturn(mProvisioningManager).when(imsManager).getProvisioningManager(anyInt());
+        doReturn(null).when(mProvisioningManager).getProvisioningStringValue(anyInt());
 
         when(mTransportSelectorCallback.onWwanSelected()).thenReturn(mWwanSelectorCallback);
         doAnswer(new Answer<Void>() {
@@ -882,6 +911,10 @@
 
     @Test
     public void testDefaultEpsImsRegisteredBarredScanTimeoutWifi() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
         createSelector(SLOT_0_SUB_ID);
         unsolBarringInfoChanged(true);
 
@@ -898,6 +931,121 @@
 
         assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
 
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiSosPdnRequiresSettingEnabled() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_SETTING_ENABLED);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling setting is disabled.
+        mNetworkCallback.onAvailable(null);
+        when(mMmTelManager.isVoWiFiRoamingSettingEnabled()).thenReturn(false);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling setting is enabled.
+        when(mMmTelManager.isVoWiFiSettingEnabled()).thenReturn(true);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiSosPdnRequiresValidEid() throws Exception {
+        PersistableBundle bundle = getDefaultPersistableBundle();
+        bundle.putBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL, true);
+        bundle.putInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT, VOWIFI_REQUIRES_VALID_EID);
+        when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
+
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected. But Wi-Fi calling s not activated.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected and Wi-Fi calling is activated.
+        doReturn("1").when(mProvisioningManager).getProvisioningStringValue(anyInt());
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+    }
+
+    @Test
+    public void testVoWifiImsPdnRequiresNone() throws Exception {
+        createSelector(SLOT_0_SUB_ID);
+        unsolBarringInfoChanged(true);
+
+        EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.DOMAIN_PS,
+                true, true, 0, 0, "", "");
+        SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+        mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+        bindImsServiceUnregistered();
+        processAllMessages();
+
+        assertTrue(mDomainSelector.hasMessages(MSG_NETWORK_SCAN_TIMEOUT));
+
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        // Wi-Fi is not connected.
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // Wi-Fi is connected but IMS is not registered over Wi-Fi.
+        mNetworkCallback.onAvailable(null);
+        mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+        verify(mTransportSelectorCallback, times(0)).onWlanSelected();
+
+        // IMS is registered over Wi-Fi.
+        bindImsService(true);
         mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
 
         verify(mTransportSelectorCallback, times(1)).onWlanSelected();
@@ -1025,8 +1173,10 @@
                 CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP
                 };
         boolean imsWhenVoiceOnCs = false;
+        int voWifiRequiresCondition = VOWIFI_REQUIRES_NONE;
         int maxRetriesOverWiFi = 1;
         int cellularScanTimerSec = 10;
+        boolean voWifiOverEmergencyPdn = false;
         int scanType = SCAN_TYPE_NO_PREFERENCE;
         boolean requiresImsRegistration = false;
         boolean requiresVoLteEnabled = false;
@@ -1034,17 +1184,19 @@
         String[] cdmaPreferredNumbers = new String[] {};
 
         return getPersistableBundle(imsRats, csRats, imsRoamRats, csRoamRats,
-                domainPreference, roamDomainPreference, imsWhenVoiceOnCs, maxRetriesOverWiFi,
-                cellularScanTimerSec, scanType, requiresImsRegistration, requiresVoLteEnabled,
-                ltePreferredAfterNrFailed, cdmaPreferredNumbers);
+                domainPreference, roamDomainPreference, imsWhenVoiceOnCs,
+                voWifiRequiresCondition, maxRetriesOverWiFi, cellularScanTimerSec,
+                scanType, voWifiOverEmergencyPdn, requiresImsRegistration,
+                requiresVoLteEnabled, ltePreferredAfterNrFailed, cdmaPreferredNumbers);
     }
 
     private static PersistableBundle getPersistableBundle(
             @Nullable int[] imsRats, @Nullable int[] csRats,
             @Nullable int[] imsRoamRats, @Nullable int[] csRoamRats,
             @Nullable int[] domainPreference, @Nullable int[] roamDomainPreference,
-            boolean imsWhenVoiceOnCs, int maxRetriesOverWiFi,
-            int cellularScanTimerSec, int scanType, boolean requiresImsRegistration,
+            boolean imsWhenVoiceOnCs, int voWifiRequiresCondition,
+            int maxRetriesOverWiFi, int cellularScanTimerSec, int scanType,
+            boolean voWifiOverEmergencyPdn, boolean requiresImsRegistration,
             boolean requiresVoLteEnabled, boolean ltePreferredAfterNrFailed,
             @Nullable String[] cdmaPreferredNumbers) {
 
@@ -1075,8 +1227,10 @@
                     roamDomainPreference);
         }
         bundle.putBoolean(KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL, imsWhenVoiceOnCs);
+        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.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);
         bundle.putBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL, requiresVoLteEnabled);
diff --git a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
index 3e04bc0..430adea 100644
--- a/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/ImsStateTrackerTest.java
@@ -526,6 +526,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.EUTRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -534,6 +535,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.NGRAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -542,6 +544,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -550,6 +553,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertTrue(mImsStateTracker.isImsRegisteredOverWlan());
+        assertTrue(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.IWLAN, mImsStateTracker.getImsAccessNetworkType());
 
         callback.onRegistered(new ImsRegistrationAttributes.Builder(
@@ -558,6 +562,7 @@
         assertFalse(mImsStateTracker.isImsStateReady());
         assertTrue(mImsStateTracker.isImsRegistered());
         assertFalse(mImsStateTracker.isImsRegisteredOverWlan());
+        assertFalse(mImsStateTracker.isImsRegisteredOverCrossSim());
         assertEquals(AccessNetworkType.UNKNOWN, mImsStateTracker.getImsAccessNetworkType());
 
         verify(mImsStateListener, times(5)).onImsRegistrationStateChanged();