Cross-SIM reg: check data is on other slot

- For determining CST availability, IWLAN would check if the
current sub was the nDDS, and assume that the data PDN was always on the DDS.
- This cross-SIM condition is relaxed so that either sub can establish
CST, as long as the active data PDN is on the other sub.
- This will allow the DDS to establish cross-SIM over nDDS in some
  cases: for eg.  when DDS is OOS and nDDS temporarily holds the data PDN.
- Clean up of IwlanNetworkServiceTests.

Bug: 249609998
Test: Live test on P10. UTs updated:
IwlanDataServiceTests#testIwlanSetupDataCallFailsWithCellularAndCstDisabled
IwlanDataServiceTests#testIwlanSetupDataCallFailsWithCellularOnSameSubAndCstEnabled
IwlanDataServiceTests#testIwlanSetupDataCallSucceedsWithCellularOnDifferentSubAndCstEnabled
IwlanNetworkServiceTests#testNetworkRegistrationInfoSearchingForCellularAndCstDisabled
IwlanNetworkServiceTests#testNetworkRegistrationInfoSearchingForCellularOnSameSubAndCstEnabled
IwlanNetworkServiceTests#testNetworkRegistrationInfoHomeForCellularOnDifferentSubAndCstEnabled

Change-Id: I471914c79ff07d5c25499b8953c6ec7cde67fd7d
diff --git a/src/com/google/android/iwlan/IwlanDataService.java b/src/com/google/android/iwlan/IwlanDataService.java
index a251bd6..9ae95f2 100644
--- a/src/com/google/android/iwlan/IwlanDataService.java
+++ b/src/com/google/android/iwlan/IwlanDataService.java
@@ -839,7 +839,7 @@
                         getTunnelManager().closeTunnel(entry.getKey(), true);
                     } else {
                         if (mIwlanDataService.isNetworkConnected(
-                                IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()),
+                                IwlanHelper.isActiveDataOnOtherSlot(mContext, getSlotIndex()),
                                 IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex()))) {
                             getTunnelManager().updateNetwork(network, entry.getKey());
                         }
@@ -909,11 +909,19 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             pw.println("---- IwlanDataServiceProvider[" + getSlotIndex() + "] ----");
             boolean isDDS = IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex());
+            boolean isActiveDataOnOtherSlot =
+                    IwlanHelper.isActiveDataOnOtherSlot(mContext, getSlotIndex());
             boolean isCSTEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex());
-            pw.println("isDefaultDataSub: " + isDDS + " isCrossSimEnabled: " + isCSTEnabled);
+            pw.println(
+                    "isDefaultDataSlot: "
+                            + isDDS
+                            + " isActiveDataOnOtherSlot: "
+                            + isActiveDataOnOtherSlot
+                            + " isCrossSimEnabled: "
+                            + isCSTEnabled);
             pw.println(
                     "isNetworkConnected: "
-                            + isNetworkConnected(isDDS, isCSTEnabled)
+                            + isNetworkConnected(isActiveDataOnOtherSlot, isCSTEnabled)
                             + " Wfc enabled: "
                             + mWfcEnabled);
             for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) {
@@ -939,6 +947,7 @@
             IwlanDataServiceProvider.TunnelState tunnelState;
             DataServiceCallback callback;
             int reason;
+            int slotId;
 
             switch (msg.what) {
                 case EVENT_TUNNEL_OPENED:
@@ -1127,17 +1136,19 @@
                         return;
                     }
 
-                    boolean isDDS =
-                            IwlanHelper.isDefaultDataSlot(
-                                    mContext, iwlanDataServiceProvider.getSlotIndex());
-                    boolean isCSTEnabled =
-                            IwlanHelper.isCrossSimCallingEnabled(
-                                    mContext, iwlanDataServiceProvider.getSlotIndex());
-                    boolean networkConnected = isNetworkConnected(isDDS, isCSTEnabled);
+                    slotId = iwlanDataServiceProvider.getSlotIndex();
+                    boolean isActiveDataOnOtherSlot =
+                            IwlanHelper.isActiveDataOnOtherSlot(mContext, slotId);
+                    boolean isCSTEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, slotId);
+                    boolean networkConnected =
+                            isNetworkConnected(isActiveDataOnOtherSlot, isCSTEnabled);
                     Log.d(
-                            TAG,
+                            TAG + "[" + slotId + "]",
                             "isDds: "
-                                    + isDDS
+                                    + IwlanHelper.isDefaultDataSlot(
+                                            mContext, slotId)
+                                    + ", isActiveDataOnOtherSlot: "
+                                    + isActiveDataOnOtherSlot
                                     + ", isCstEnabled: "
                                     + isCSTEnabled
                                     + ", transport: "
@@ -1164,7 +1175,7 @@
                                 && tunnelState.getState()
                                         == IwlanDataServiceProvider.TunnelState.TUNNEL_UP) {
                             Log.w(
-                                    TAG,
+                                    TAG + "[" + slotId + "]",
                                     "The tunnel for " + dataProfile.getApn() + " already exists.");
                             iwlanDataServiceProvider.deliverCallback(
                                     IwlanDataServiceProvider.CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
@@ -1175,7 +1186,7 @@
                             return;
                         } else {
                             Log.e(
-                                    TAG,
+                                    TAG + "[" + slotId + "]",
                                     "Force close the existing PDN. pduSessionId = "
                                             + tunnelState.getPduSessionId()
                                             + " Tunnel State = "
@@ -1240,7 +1251,7 @@
                                     .bringUpTunnel(
                                             tunnelReqBuilder.build(),
                                             iwlanDataServiceProvider.getIwlanTunnelCallback());
-                    Log.d(TAG, "bringup Tunnel with result:" + result);
+                    Log.d(TAG + "[" + slotId + "]", "bringup Tunnel with result:" + result);
                     if (!result) {
                         iwlanDataServiceProvider.deliverCallback(
                                 IwlanDataServiceProvider.CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
@@ -1259,11 +1270,11 @@
                     reason = deactivateDataCallData.mReason;
 
                     int cid = deactivateDataCallData.mCid;
-                    int slotIndex = iwlanDataServiceProvider.getSlotIndex();
+                    slotId = iwlanDataServiceProvider.getSlotIndex();
                     boolean isNetworkLost =
                             !isNetworkConnected(
-                                    IwlanHelper.isDefaultDataSlot(mContext, slotIndex),
-                                    IwlanHelper.isCrossSimCallingEnabled(mContext, slotIndex));
+                                    IwlanHelper.isActiveDataOnOtherSlot(mContext, slotId),
+                                    IwlanHelper.isCrossSimCallingEnabled(mContext, slotId));
                     boolean isHandOutSuccessful = (reason == REQUEST_REASON_HANDOVER);
 
                     for (String apn : iwlanDataServiceProvider.mTunnelStateForApn.keySet()) {
@@ -1327,14 +1338,10 @@
                 case EVENT_REMOVE_DATA_SERVICE_PROVIDER:
                     iwlanDataServiceProvider = (IwlanDataServiceProvider) msg.obj;
 
-                    IwlanDataServiceProvider dsp =
-                            sIwlanDataServiceProviders.remove(
-                                    iwlanDataServiceProvider.getSlotIndex());
+                    slotId = iwlanDataServiceProvider.getSlotIndex();
+                    IwlanDataServiceProvider dsp = sIwlanDataServiceProviders.remove(slotId);
                     if (dsp == null) {
-                        Log.w(
-                                TAG,
-                                "No DataServiceProvider exists for slot "
-                                        + iwlanDataServiceProvider.getSlotIndex());
+                        Log.w(TAG + "[" + slotId + "]", "No DataServiceProvider exists for slot!");
                     }
 
                     if (sIwlanDataServiceProviders.isEmpty()) {
@@ -1451,12 +1458,16 @@
     }
 
     @VisibleForTesting
-    static boolean isNetworkConnected(boolean isDds, boolean isCstEnabled) {
-        if (!isDds && isCstEnabled) {
-            // Only Non-DDS sub with CST enabled, can use any transport.
+    static boolean isNetworkConnected(boolean isActiveDataOnOtherSlot, boolean isCstEnabled) {
+        if (isActiveDataOnOtherSlot && isCstEnabled) {
+            // For cross-SIM IWLAN (Transport.MOBILE), an active data PDN must be maintained on the
+            // other slot.
+            if (sNetworkConnected && (sDefaultDataTransport != Transport.MOBILE)) {
+                Log.e(TAG, "Internet is on other slot, but default transport is not MOBILE!");
+            }
             return sNetworkConnected;
         } else {
-            // For all other cases, only wifi transport can be used.
+            // For all other cases, only Transport.WIFI can be used.
             return ((sDefaultDataTransport == Transport.WIFI) && sNetworkConnected);
         }
     }
diff --git a/src/com/google/android/iwlan/IwlanHelper.java b/src/com/google/android/iwlan/IwlanHelper.java
index fab936c..34adddd 100644
--- a/src/com/google/android/iwlan/IwlanHelper.java
+++ b/src/com/google/android/iwlan/IwlanHelper.java
@@ -237,6 +237,37 @@
         return false;
     }
 
+    /**
+     * Gets the slot index associated with the current active data subscription.
+     *
+     * <p>The currently active data slot may be different from the default data slot. For instance,
+     * when the DDS is OOS or the nDDS is in a voice call, the data PDN may move to the nDDS.
+     *
+     * @param context application context
+     * @return slot index associated with the active data subscription, or
+     *     SubscriptionManager#INVALID_SIM_SLOT_INDEX if no active data PDN.
+     */
+    private static int getActiveDataSlot(Context context) {
+        SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
+        return sm.getSlotIndex(sm.getActiveDataSubscriptionId());
+    }
+
+    /**
+     * For dual-SIM UEs, determines if the active data PDN is on the other slot to the one provided.
+     *
+     * @param context application context
+     * @param slotIndex slot index associated with current subscription
+     * @return whether the other subscription has active data PDN.
+     */
+    public static boolean isActiveDataOnOtherSlot(Context context, int slotIndex) {
+        int activeDataSlot = getActiveDataSlot(context);
+        Log.d("apsankar:", slotIndex + " " + activeDataSlot);
+        if (activeDataSlot != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+            return activeDataSlot != slotIndex;
+        }
+        return false;
+    }
+
     public static boolean isCrossSimCallingEnabled(Context context, int slotId) {
         boolean isCstEnabled = false;
         int subid = getSubId(context, slotId);
@@ -316,7 +347,7 @@
     }
 
     static long elapsedRealtime() {
-      /*Returns milliseconds since boot, including time spent in sleep.*/
-      return SystemClock.elapsedRealtime();
+        /*Returns milliseconds since boot, including time spent in sleep.*/
+        return SystemClock.elapsedRealtime();
     }
 }
diff --git a/src/com/google/android/iwlan/IwlanNetworkService.java b/src/com/google/android/iwlan/IwlanNetworkService.java
index 361eaa1..5e87710 100644
--- a/src/com/google/android/iwlan/IwlanNetworkService.java
+++ b/src/com/google/android/iwlan/IwlanNetworkService.java
@@ -196,7 +196,7 @@
         @VisibleForTesting
         void subscriptionChanged() {
             boolean subActive = false;
-            SubscriptionManager sm = SubscriptionManager.from(mContext);
+            SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
             if (sm.getActiveSubscriptionInfoForSimSlotIndex(getSlotIndex()) != null) {
                 subActive = true;
             }
@@ -222,6 +222,7 @@
             Log.d(TAG, "msg.what = " + eventToString(msg.what));
 
             IwlanNetworkServiceProvider iwlanNetworkServiceProvider;
+            int slotId;
 
             switch (msg.what) {
                 case IwlanEventListener.CROSS_SIM_CALLING_ENABLE_EVENT:
@@ -261,23 +262,24 @@
                             .setEmergencyOnly(!iwlanNetworkServiceProvider.mIsSubActive)
                             .setDomain(NetworkRegistrationInfo.DOMAIN_PS);
 
+                    slotId = iwlanNetworkServiceProvider.getSlotIndex();
                     if (!IwlanNetworkService.isNetworkConnected(
-                            IwlanHelper.isDefaultDataSlot(
-                                    mContext, iwlanNetworkServiceProvider.getSlotIndex()),
-                            IwlanHelper.isCrossSimCallingEnabled(
-                                    mContext, iwlanNetworkServiceProvider.getSlotIndex()))) {
+                            IwlanHelper.isActiveDataOnOtherSlot(mContext, slotId),
+                            IwlanHelper.isCrossSimCallingEnabled(mContext, slotId))) {
                         nriBuilder
                                 .setRegistrationState(
                                         NetworkRegistrationInfo
                                                 .REGISTRATION_STATE_NOT_REGISTERED_SEARCHING)
                                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN);
-                        Log.d(TAG, "reg state REGISTRATION_STATE_NOT_REGISTERED_SEARCHING");
+                        Log.d(
+                                TAG + "[" + slotId + "]",
+                                ": reg state" + " REGISTRATION_STATE_NOT_REGISTERED_SEARCHING");
                     } else {
                         nriBuilder
                                 .setRegistrationState(
                                         NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                                 .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN);
-                        Log.d(TAG, "reg state REGISTRATION_STATE_HOME");
+                        Log.d(TAG + "[" + slotId + "]", ": reg state REGISTRATION_STATE_HOME");
                     }
 
                     callback.onRequestNetworkRegistrationInfoComplete(
@@ -296,14 +298,12 @@
 
                 case EVENT_REMOVE_NETWORK_SERVICE_PROVIDER:
                     iwlanNetworkServiceProvider = (IwlanNetworkServiceProvider) msg.obj;
-                    IwlanNetworkServiceProvider nsp =
-                            sIwlanNetworkServiceProviders.remove(
-                                    iwlanNetworkServiceProvider.getSlotIndex());
+                    slotId = iwlanNetworkServiceProvider.getSlotIndex();
+                    IwlanNetworkServiceProvider nsp = sIwlanNetworkServiceProviders.remove(slotId);
                     if (nsp == null) {
                         Log.w(
-                                TAG,
-                                "No NetworkServiceProvider exists for slot "
-                                        + iwlanNetworkServiceProvider.getSlotIndex());
+                                TAG + "[" + slotId + "]",
+                                "No NetworkServiceProvider exists for slot!");
                         return;
                     }
                     if (sIwlanNetworkServiceProviders.isEmpty()) {
@@ -360,9 +360,14 @@
         return np;
     }
 
-    public static boolean isNetworkConnected(boolean isDds, boolean isCstEnabled) {
-        if (!isDds && isCstEnabled) {
-            // Only Non-DDS sub with CST enabled, can use any transport.
+    public static boolean isNetworkConnected(
+            boolean isActiveDataOnOtherSlot, boolean isCstEnabled) {
+        if (isActiveDataOnOtherSlot && isCstEnabled) {
+            // For cross-SIM IWLAN (Transport.MOBILE), an active data PDN must be maintained on the
+            // other slot.
+            if (sNetworkConnected && (sDefaultDataTransport != Transport.MOBILE)) {
+                Log.e(TAG, "Internet is on other slot, but default transport is not MOBILE!");
+            }
             return sNetworkConnected;
         } else {
             // For all other cases, only wifi transport can be used.
diff --git a/test/com/google/android/iwlan/IwlanDataServiceTest.java b/test/com/google/android/iwlan/IwlanDataServiceTest.java
index 0729fc7..f058b2c 100644
--- a/test/com/google/android/iwlan/IwlanDataServiceTest.java
+++ b/test/com/google/android/iwlan/IwlanDataServiceTest.java
@@ -173,7 +173,7 @@
                         .mockStatic(EpdgSelector.class)
                         .mockStatic(ErrorPolicyManager.class)
                         .mockStatic(IwlanBroadcastReceiver.class)
-                        .mockStatic(IwlanHelper.class)
+                        .mockStatic(SubscriptionManager.class)
                         .strictness(Strictness.LENIENT)
                         .startMocking();
 
@@ -185,6 +185,11 @@
 
         when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt()))
                 .thenReturn(mMockSubscriptionInfo);
+        when(mMockSubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
+        when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX))
+                .thenReturn(DEFAULT_SLOT_INDEX);
+        when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX + 1))
+                .thenReturn(DEFAULT_SLOT_INDEX + 1);
 
         when(mMockSubscriptionInfo.getSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
 
@@ -231,7 +236,7 @@
         }
     }
 
-    private void verifiyNetworkConnected(int transportType) {
+    private void verifyNetworkConnected(int transportType) {
         NetworkCapabilities mockNetworkCapabilities = mock(NetworkCapabilities.class);
 
         when(mockNetworkCapabilities.hasTransport(anyInt())).thenReturn(false);
@@ -242,7 +247,7 @@
         networkMonitorCallback.onCapabilitiesChanged(mMockNetwork, mockNetworkCapabilities);
     }
 
-    private void verifiyNetworkLost(int transportType) {
+    private void verifyNetworkLost() {
         IwlanNetworkMonitorCallback networkMonitorCallback =
                 mIwlanDataService.getNetworkMonitorCallback();
         networkMonitorCallback.onLost(mMockNetwork);
@@ -250,8 +255,10 @@
 
     @Test
     public void testWifionConnected() {
-        verifiyNetworkConnected(TRANSPORT_WIFI);
-        assertTrue(mIwlanDataService.isNetworkConnected(false, false));
+        verifyNetworkConnected(TRANSPORT_WIFI);
+        assertTrue(
+                mIwlanDataService.isNetworkConnected(
+                        false /* isActiveDataOnOtherSlot */, false /* isCstEnabled */));
     }
 
     @Test
@@ -259,8 +266,10 @@
         when(mMockIwlanDataServiceProvider.getSlotIndex()).thenReturn(DEFAULT_SLOT_INDEX + 1);
         mIwlanDataService.addIwlanDataServiceProvider(mMockIwlanDataServiceProvider);
 
-        verifiyNetworkLost(TRANSPORT_WIFI);
-        assertFalse(mIwlanDataService.isNetworkConnected(false, false));
+        verifyNetworkLost();
+        assertFalse(
+                mIwlanDataService.isNetworkConnected(
+                        false /* isActiveDataOnOtherSlot */, false /* isCstEnabled */));
         verify(mMockIwlanDataServiceProvider).forceCloseTunnelsInDeactivatingState();
         mIwlanDataService.removeDataServiceProvider(mMockIwlanDataServiceProvider);
         mTestLooper.dispatchAll();
@@ -505,7 +514,7 @@
 
         doReturn(mMockEpdgTunnelManager).when(mSpyIwlanDataServiceProvider).getTunnelManager();
 
-        verifiyNetworkConnected(TRANSPORT_WIFI);
+        verifyNetworkConnected(TRANSPORT_WIFI);
 
         mSpyIwlanDataServiceProvider.setTunnelState(
                 dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, false, 1);
@@ -533,7 +542,7 @@
 
         doReturn(mMockEpdgTunnelManager).when(mSpyIwlanDataServiceProvider).getTunnelManager();
 
-        verifiyNetworkConnected(TRANSPORT_WIFI);
+        verifyNetworkConnected(TRANSPORT_WIFI);
 
         mSpyIwlanDataServiceProvider.setTunnelState(
                 dp, mMockDataServiceCallback, TunnelState.TUNNEL_IN_BRINGUP, null, false, 1);
@@ -719,21 +728,16 @@
     }
 
     @Test
-    public void testIwlanSetupDataCallWithCellularAndCstDisabled() {
+    public void testIwlanSetupDataCallFailsWithCellularAndCstDisabled() throws Exception {
         DataProfile dp = buildDataProfile();
 
-        /* Mobile is connected */
+        /* Internet is connected through Mobile */
         mIwlanDataService.setNetworkConnected(
                 true, mMockNetwork, IwlanDataService.Transport.MOBILE);
 
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(false);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
+        /* CST is disabled, and data is on the same sub as the data service provider */
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(false);
+        when(mMockSubscriptionManager.getActiveDataSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
 
         mIwlanDataServiceProvider.setupDataCall(
                 AccessNetworkType.IWLAN, /* AccessNetworkType */
@@ -756,27 +760,52 @@
     }
 
     @Test
-    public void testIwlanSetupDataCallWithCellularAndCstEnabled() {
+    public void testIwlanSetupDataCallFailsWithCellularOnSameSubAndCstEnabled() throws Exception {
         DataProfile dp = buildDataProfile();
 
-        /* Clear state */
-        mIwlanDataService.setNetworkConnected(
-                false, mMockNetwork, IwlanDataService.Transport.UNSPECIFIED_NETWORK);
-
-        /* Mobile is connected */
+        /* Internet is connected through Mobile */
         mIwlanDataService.setNetworkConnected(
                 true, mMockNetwork, IwlanDataService.Transport.MOBILE);
 
-        doReturn(mMockEpdgTunnelManager).when(mSpyIwlanDataServiceProvider).getTunnelManager();
+        /* CST is enabled, but data is on the same sub as the DataServiceProvider */
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true);
+        when(mMockSubscriptionManager.getActiveDataSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
 
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(false);
+        mSpyIwlanDataServiceProvider.setupDataCall(
+                AccessNetworkType.IWLAN, /* AccessNetworkType */
+                dp, /* dataProfile */
+                false, /* isRoaming */
+                true, /* allowRoaming */
+                DataService.REQUEST_REASON_NORMAL, /* DataService.REQUEST_REASON_NORMAL */
+                null, /* LinkProperties */
+                1, /* pduSessionId */
+                null, /* sliceInfo */
+                null, /* trafficDescriptor */
+                true, /* matchAllRuleAllowed */
+                mMockDataServiceCallback);
+        mTestLooper.dispatchAll();
+
+        verify(mMockDataServiceCallback, timeout(1000).times(1))
+                .onSetupDataCallComplete(
+                        eq(5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */),
+                        isNull());
+    }
+
+    @Test
+    public void testIwlanSetupDataCallSucceedsWithCellularOnDifferentSubAndCstEnabled()
+            throws Exception {
+        DataProfile dp = buildDataProfile();
+
+        /* Internet is connected through Mobile */
+        mIwlanDataService.setNetworkConnected(
+                true, mMockNetwork, IwlanDataService.Transport.MOBILE);
+
+        /* CST is enabled, and data is on a different sub than the DataServiceProvider */
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true);
+        when(mMockSubscriptionManager.getActiveDataSubscriptionId())
+                .thenReturn(DEFAULT_SUB_INDEX + 1);
+
+        doReturn(mMockEpdgTunnelManager).when(mSpyIwlanDataServiceProvider).getTunnelManager();
 
         mSpyIwlanDataServiceProvider.setupDataCall(
                 AccessNetworkType.IWLAN, /* AccessNetworkType */
diff --git a/test/com/google/android/iwlan/IwlanNetworkServiceTest.java b/test/com/google/android/iwlan/IwlanNetworkServiceTest.java
index 000190a..3164bf2 100644
--- a/test/com/google/android/iwlan/IwlanNetworkServiceTest.java
+++ b/test/com/google/android/iwlan/IwlanNetworkServiceTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.telephony.AccessNetworkConstants;
@@ -31,6 +32,8 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsManager;
+import android.telephony.ims.ImsMmTelManager;
 
 import com.google.android.iwlan.IwlanNetworkService.IwlanNetworkServiceProvider;
 
@@ -40,17 +43,21 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.util.Arrays;
 
 public class IwlanNetworkServiceTest {
     private static final String TAG = IwlanNetworkServiceTest.class.getSimpleName();
     private static final int DEFAULT_SLOT_INDEX = 0;
+    private static final int DEFAULT_SUB_INDEX = 0;
 
     @Mock private Context mMockContext;
     @Mock private ConnectivityManager mMockConnectivityManager;
     @Mock private SubscriptionManager mMockSubscriptionManager;
     @Mock private SubscriptionInfo mMockSubscriptionInfo;
+    @Mock private ImsManager mMockImsManager;
+    @Mock private ImsMmTelManager mMockImsMmTelManager;
     @Mock private INetworkServiceCallback mCallback;
     MockitoSession mStaticMockSession;
 
@@ -64,8 +71,8 @@
 
         mStaticMockSession =
                 mockitoSession()
-                        .mockStatic(IwlanHelper.class)
                         .mockStatic(SubscriptionManager.class)
+                        .strictness(Strictness.LENIENT)
                         .startMocking();
 
         when(mMockContext.getSystemService(eq(ConnectivityManager.class)))
@@ -77,10 +84,17 @@
         when(mMockSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
                         eq(DEFAULT_SLOT_INDEX)))
                 .thenReturn(mMockSubscriptionInfo);
+        when(mMockSubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
+        when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX))
+                .thenReturn(DEFAULT_SLOT_INDEX);
+        when(mMockSubscriptionManager.getSlotIndex(DEFAULT_SUB_INDEX + 1))
+                .thenReturn(DEFAULT_SLOT_INDEX + 1);
 
-        lenient()
-                .when(SubscriptionManager.from(eq(mMockContext)))
-                .thenReturn(mMockSubscriptionManager);
+        when(mMockSubscriptionInfo.getSubscriptionId()).thenReturn(DEFAULT_SUB_INDEX);
+
+        when(mMockContext.getSystemService(eq(ImsManager.class))).thenReturn(mMockImsManager);
+
+        when(mMockImsManager.getImsMmTelManager(anyInt())).thenReturn(mMockImsMmTelManager);
 
         mIwlanNetworkService = new IwlanNetworkService();
         mIwlanNetworkService.setAppContext(mMockContext);
@@ -97,22 +111,23 @@
         mStaticMockSession.finishMocking();
     }
 
-    @Test
-    public void testRequestNetworkRegistrationInfo() throws Exception {
-        int domain = NetworkRegistrationInfo.DOMAIN_PS;
-        boolean mIsSubActive = true;
-        long startTime;
-
+    @Nullable
+    IwlanNetworkServiceProvider initNSP() {
         // Wait for IwlanNetworkServiceProvider created and timeout is 1 second.
-        startTime = System.currentTimeMillis();
+        long startTime = System.currentTimeMillis();
+        IwlanNetworkServiceProvider nsp = null;
         while (System.currentTimeMillis() - startTime < 1000) {
-            mIwlanNetworkServiceProvider =
-                    mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
-            if (mIwlanNetworkServiceProvider != null) {
+            nsp = mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
+            if (nsp != null) {
                 break;
             }
         }
+        return nsp;
+    }
 
+    @Test
+    public void testRequestNetworkRegistrationInfo() throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
         assertTrue(mIwlanNetworkServiceProvider != null);
 
         // Set Wifi on and verify mCallback should receive onNetworkStateChanged.
@@ -126,223 +141,145 @@
         // Create expected NetworkRegistrationInfo
         NetworkRegistrationInfo.Builder expectedStateBuilder =
                 generateStateBuilder(
-                        domain, mIsSubActive, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* isSubActive */,
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mBinder.requestNetworkRegistrationInfo(0, domain, mCallback);
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
 
         verify(mCallback, timeout(1000).times(1))
                 .onRequestNetworkRegistrationInfoComplete(
                         eq(NetworkServiceCallback.RESULT_SUCCESS),
                         eq(expectedStateBuilder.build()));
-
-        IwlanNetworkService.setNetworkConnected(
-                false, IwlanNetworkService.Transport.UNSPECIFIED_NETWORK);
     }
 
     @Test
-    public void testNetworkRegistrationInfoForCellularAndCstDisabled() throws Exception {
-        int domain = NetworkRegistrationInfo.DOMAIN_PS;
-        boolean mIsSubActive = true;
-        long startTime;
-
-        // Wait for IwlanNetworkServiceProvider created and timeout is 1 second.
-        startTime = System.currentTimeMillis();
-        while (System.currentTimeMillis() - startTime < 1000) {
-            mIwlanNetworkServiceProvider =
-                    mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
-            if (mIwlanNetworkServiceProvider != null) {
-                break;
-            }
-        }
-
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(false);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-
+    public void testNetworkRegistrationInfoSearchingForCellularAndCstDisabled() throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
         assertTrue(mIwlanNetworkServiceProvider != null);
 
-        // Set Network on and verify mCallback should receive onNetworkStateChanged.
-        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.MOBILE);
-        verify(mCallback, timeout(1000).times(1)).onNetworkStateChanged();
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(false);
 
-        // Set Sub active and verify mCallback should receive onNetworkStateChanged.
+        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.MOBILE);
         mIwlanNetworkServiceProvider.subscriptionChanged();
-        verify(mCallback, timeout(1000).times(2)).onNetworkStateChanged();
 
         // Create expected NetworkRegistrationInfo
         NetworkRegistrationInfo.Builder expectedStateBuilder =
                 generateStateBuilder(
-                        domain,
-                        mIsSubActive,
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* isSubActive */,
                         NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING);
 
-        mBinder.requestNetworkRegistrationInfo(0, domain, mCallback);
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
 
         verify(mCallback, timeout(1000).times(1))
                 .onRequestNetworkRegistrationInfoComplete(
                         eq(NetworkServiceCallback.RESULT_SUCCESS),
                         eq(expectedStateBuilder.build()));
-
-        IwlanNetworkService.setNetworkConnected(
-                false, IwlanNetworkService.Transport.UNSPECIFIED_NETWORK);
     }
 
     @Test
-    public void testNetworkRegistrationInfoForCellularAndCstEnabled() throws Exception {
-        int domain = NetworkRegistrationInfo.DOMAIN_PS;
-        boolean mIsSubActive = true;
-        long startTime;
-
-        // Wait for IwlanNetworkServiceProvider created and timeout is 1 second.
-        startTime = System.currentTimeMillis();
-        while (System.currentTimeMillis() - startTime < 1000) {
-            mIwlanNetworkServiceProvider =
-                    mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
-            if (mIwlanNetworkServiceProvider != null) {
-                break;
-            }
-        }
-
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(false);
-
+    public void testNetworkRegistrationInfoSearchingForCellularOnSameSubAndCstEnabled()
+            throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
         assertTrue(mIwlanNetworkServiceProvider != null);
 
-        // Set Network on and verify mCallback should receive onNetworkStateChanged.
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true);
+
         mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.MOBILE);
-        verify(mCallback, timeout(1000).times(1)).onNetworkStateChanged();
-
-        // Set Sub active and verify mCallback should receive onNetworkStateChanged.
         mIwlanNetworkServiceProvider.subscriptionChanged();
-        verify(mCallback, timeout(1000).times(2)).onNetworkStateChanged();
 
         // Create expected NetworkRegistrationInfo
         NetworkRegistrationInfo.Builder expectedStateBuilder =
                 generateStateBuilder(
-                        domain, mIsSubActive, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* mIsSubActive */,
+                        NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING);
 
-        mBinder.requestNetworkRegistrationInfo(0, domain, mCallback);
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
 
         verify(mCallback, timeout(1000).times(1))
                 .onRequestNetworkRegistrationInfoComplete(
                         eq(NetworkServiceCallback.RESULT_SUCCESS),
                         eq(expectedStateBuilder.build()));
-
-        IwlanNetworkService.setNetworkConnected(
-                false, IwlanNetworkService.Transport.UNSPECIFIED_NETWORK);
     }
 
     @Test
-    public void testNetworkRegistrationInfoForWiFiAndCstEnabled() throws Exception {
-        int domain = NetworkRegistrationInfo.DOMAIN_PS;
-        boolean mIsSubActive = true;
-        long startTime;
-
-        // Wait for IwlanNetworkServiceProvider created and timeout is 1 second.
-        startTime = System.currentTimeMillis();
-        while (System.currentTimeMillis() - startTime < 1000) {
-            mIwlanNetworkServiceProvider =
-                    mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
-            if (mIwlanNetworkServiceProvider != null) {
-                break;
-            }
-        }
-
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-
+    public void testNetworkRegistrationInfoHomeForCellularOnDifferentSubAndCstEnabled()
+            throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
         assertTrue(mIwlanNetworkServiceProvider != null);
 
-        // Set Network on and verify mCallback should receive onNetworkStateChanged.
-        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.WIFI);
-        verify(mCallback, timeout(1000).times(1)).onNetworkStateChanged();
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true);
+        when(mMockSubscriptionManager.getActiveDataSubscriptionId())
+                .thenReturn(DEFAULT_SUB_INDEX + 1);
 
-        // Set Sub active and verify mCallback should receive onNetworkStateChanged.
+        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.MOBILE);
         mIwlanNetworkServiceProvider.subscriptionChanged();
-        verify(mCallback, timeout(1000).times(2)).onNetworkStateChanged();
 
         // Create expected NetworkRegistrationInfo
         NetworkRegistrationInfo.Builder expectedStateBuilder =
                 generateStateBuilder(
-                        domain, mIsSubActive, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* isSubActive */,
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mBinder.requestNetworkRegistrationInfo(0, domain, mCallback);
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
 
         verify(mCallback, timeout(1000).times(1))
                 .onRequestNetworkRegistrationInfoComplete(
                         eq(NetworkServiceCallback.RESULT_SUCCESS),
                         eq(expectedStateBuilder.build()));
-
-        IwlanNetworkService.setNetworkConnected(
-                false, IwlanNetworkService.Transport.UNSPECIFIED_NETWORK);
     }
 
     @Test
-    public void testNetworkRegistrationInfoForWiFiAndCstDisabled() throws Exception {
-        int domain = NetworkRegistrationInfo.DOMAIN_PS;
-        boolean mIsSubActive = true;
-        long startTime;
-
-        // Wait for IwlanNetworkServiceProvider created and timeout is 1 second.
-        startTime = System.currentTimeMillis();
-        while (System.currentTimeMillis() - startTime < 1000) {
-            mIwlanNetworkServiceProvider =
-                    mIwlanNetworkService.getNetworkServiceProvider(DEFAULT_SLOT_INDEX);
-            if (mIwlanNetworkServiceProvider != null) {
-                break;
-            }
-        }
-
-        lenient()
-                .when(
-                        IwlanHelper.isCrossSimCallingEnabled(
-                                eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(false);
-        lenient()
-                .when(IwlanHelper.isDefaultDataSlot(eq(mMockContext), eq(DEFAULT_SLOT_INDEX)))
-                .thenReturn(true);
-
+    public void testNetworkRegistrationInfoHomeForWiFiAndCstEnabled() throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
         assertTrue(mIwlanNetworkServiceProvider != null);
 
-        // Set Network on and verify mCallback should receive onNetworkStateChanged.
-        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.WIFI);
-        verify(mCallback, timeout(1000).times(1)).onNetworkStateChanged();
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(true);
 
-        // Set Sub active and verify mCallback should receive onNetworkStateChanged.
+        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.WIFI);
         mIwlanNetworkServiceProvider.subscriptionChanged();
-        verify(mCallback, timeout(1000).times(2)).onNetworkStateChanged();
 
         // Create expected NetworkRegistrationInfo
         NetworkRegistrationInfo.Builder expectedStateBuilder =
                 generateStateBuilder(
-                        domain, mIsSubActive, NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* isSubActive */,
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mBinder.requestNetworkRegistrationInfo(0, domain, mCallback);
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
 
         verify(mCallback, timeout(1000).times(1))
                 .onRequestNetworkRegistrationInfoComplete(
                         eq(NetworkServiceCallback.RESULT_SUCCESS),
                         eq(expectedStateBuilder.build()));
+    }
 
-        IwlanNetworkService.setNetworkConnected(
-                false, IwlanNetworkService.Transport.UNSPECIFIED_NETWORK);
+    @Test
+    public void testNetworkRegistrationInfoHomeForWiFiAndCstDisabled() throws Exception {
+        mIwlanNetworkServiceProvider = initNSP();
+        assertTrue(mIwlanNetworkServiceProvider != null);
+
+        when(mMockImsMmTelManager.isCrossSimCallingEnabled()).thenReturn(false);
+
+        mIwlanNetworkService.setNetworkConnected(true, IwlanNetworkService.Transport.WIFI);
+        mIwlanNetworkServiceProvider.subscriptionChanged();
+
+        // Create expected NetworkRegistrationInfo
+        NetworkRegistrationInfo.Builder expectedStateBuilder =
+                generateStateBuilder(
+                        NetworkRegistrationInfo.DOMAIN_PS,
+                        true /* isSubActive */,
+                        NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        mBinder.requestNetworkRegistrationInfo(0, NetworkRegistrationInfo.DOMAIN_PS, mCallback);
+
+        verify(mCallback, timeout(1000).times(1))
+                .onRequestNetworkRegistrationInfoComplete(
+                        eq(NetworkServiceCallback.RESULT_SUCCESS),
+                        eq(expectedStateBuilder.build()));
     }
 
     private NetworkRegistrationInfo.Builder generateStateBuilder(