Select proper handover type and monitoring timeout duration

Bug: 366014519
Flag: EXEMPT bugfix
Test: SatelliteSOSMessageRecommenderTest SatelliteControllerTest
Manual system test with Skylo, Vzw, Starlink
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8dcd39dfd023e7497fabf2d9de73b636a4652a89)
Merged-In: I2962b57c7ea8e364119be92b1b467fcebb6d9354
Change-Id: I2962b57c7ea8e364119be92b1b467fcebb6d9354
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index a1354ac..dc6a0de 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -3961,28 +3961,30 @@
     }
 
     /**
-     * @return {@code true} if the device is connected to satellite via any carrier within the
+     * @return {@code true} and the corresponding subId if the device is connected to
+     * satellite via any carrier within the
      * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
-     * duration, {@code false} otherwise.
+     * duration, {@code false} and null otherwise.
      */
-    public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() {
+    public Pair<Boolean, Integer> isSatelliteConnectedViaCarrierWithinHysteresisTime() {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
             logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: carrierEnabledSatelliteFlag"
                     + " is disabled");
-            return false;
+            return new Pair<>(false, null);
         }
-        if (isUsingNonTerrestrialNetworkViaCarrier().first) {
-            return true;
+        Pair<Boolean, Integer> ntnConnectedState = isUsingNonTerrestrialNetworkViaCarrier();
+        if (ntnConnectedState.first) {
+            return ntnConnectedState;
         }
         for (Phone phone : PhoneFactory.getPhones()) {
             if (isInSatelliteModeForCarrierRoaming(phone)) {
                 logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: "
                         + "subId:" + phone.getSubId()
                         + " is connected to satellite within hysteresis time");
-                return true;
+                return new Pair<>(true, phone.getSubId());
             }
         }
-        return false;
+        return new Pair<>(false, null);
     }
 
     /**
@@ -4185,7 +4187,7 @@
         return DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
     }
 
-    private int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
+    public int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
         PersistableBundle config = getPersistableBundle(subId);
         return config.getInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
     }
@@ -4546,12 +4548,22 @@
             return null;
         }
         String iccid = subInfo.getIccId();
-        String apn = getConfigForSubId(subId).getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
+        String apn = getNiddApnName(subId);
         return new SatelliteModemEnableRequestAttributes(
                 arg.enableSatellite, arg.enableDemoMode, arg.isEmergency,
                 new SatelliteSubscriptionInfo(iccid, apn));
     }
 
+    @NonNull private String getNiddApnName(int subId) {
+        if (SatelliteServiceUtils.isNtnOnlySubscriptionId(subId)) {
+            String apn = mContext.getResources().getString(R.string.config_satellite_nidd_apn_name);
+            if (!TextUtils.isEmpty(apn)) {
+                return apn;
+            }
+        }
+        return getConfigForSubId(subId).getString(KEY_SATELLITE_NIDD_APN_NAME_STRING, "");
+    }
+
     private void handleRequestSatelliteAttachRestrictionForCarrierCmd(
             SatelliteControllerHandlerRequest request) {
         RequestHandleSatelliteAttachRestrictionForCarrierArgument argument =
@@ -6532,7 +6544,7 @@
                         /*visible*/ true);
             }
         } else if (mIsNotificationShowing
-                && !isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
+                && !isSatelliteConnectedViaCarrierWithinHysteresisTime().first) {
             // Dismiss the notification if it is still displaying.
             dismissSatelliteNotification();
         }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index e924878..ea6dedd 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -52,6 +52,7 @@
 import android.telephony.PersistentLogger;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.ImsReasonInfo;
 import android.telephony.ims.ImsRegistrationAttributes;
@@ -79,6 +80,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
@@ -119,8 +121,10 @@
     private boolean mCheckingAccessRestrictionInProgress = false;
     protected long mTimeoutMillis = 0;
     private final long mOemEnabledTimeoutMillis;
-    private final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime =
+    protected final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime =
             new AtomicBoolean(false);
+    protected final AtomicInteger mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime =
+            new AtomicInteger(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     @GuardedBy("mLock")
     private boolean mIsTimerTimedOut = false;
     protected int mCountOfTimerStarted = 0;
@@ -238,8 +242,7 @@
          * should do this check now so that we have higher chance of sending the event
          * EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
          */
-        mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(
-                mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        updateSatelliteConnectedViaCarrierWithinHysteresisTimeState();
         sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, connection));
     }
 
@@ -377,8 +380,7 @@
 
     private void updateSatelliteViaCarrierAvailability() {
         if (!mIsSatelliteConnectedViaCarrierWithinHysteresisTime.get()) {
-            mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(
-                    mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+            updateSatelliteConnectedViaCarrierWithinHysteresisTimeState();
         }
     }
 
@@ -571,10 +573,19 @@
 
     private void selectEmergencyCallWaitForConnectionTimeoutDuration() {
         if (isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
+            int satelliteSubId = mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime.get();
             mTimeoutMillis =
-                    mSatelliteController.getCarrierEmergencyCallWaitForConnectionTimeoutMillis();
+                    mSatelliteController.getCarrierEmergencyCallWaitForConnectionTimeoutMillis(
+                            satelliteSubId);
         } else {
-            mTimeoutMillis = mOemEnabledTimeoutMillis;
+            int satelliteSubId = mSatelliteController.getSelectedSatelliteSubId();
+            if (!SatelliteServiceUtils.isNtnOnlySubscriptionId(satelliteSubId)) {
+                mTimeoutMillis =
+                    mSatelliteController.getCarrierEmergencyCallWaitForConnectionTimeoutMillis(
+                        satelliteSubId);
+            } else {
+                mTimeoutMillis = mOemEnabledTimeoutMillis;
+            }
         }
         plogd("mTimeoutMillis = " + mTimeoutMillis);
     }
@@ -763,17 +774,18 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public int getEmergencyCallToSatelliteHandoverType() {
-        if (Flags.carrierRoamingNbIotNtn()
-                && isDeviceProvisioned()
-                && isSatelliteAllowedByReasons()
-                && isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
-            int satelliteSubId = mSatelliteController.getSelectedSatelliteSubId();
+        if (isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
+            int satelliteSubId = mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime.get();
             return mSatelliteController.getCarrierRoamingNtnEmergencyCallToSatelliteHandoverType(
                     satelliteSubId);
-        } else if (isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
-            return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
         } else {
-            return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+            int satelliteSubId = mSatelliteController.getSelectedSatelliteSubId();
+            if (!SatelliteServiceUtils.isNtnOnlySubscriptionId(satelliteSubId)) {
+                return mSatelliteController
+                    .getCarrierRoamingNtnEmergencyCallToSatelliteHandoverType(satelliteSubId);
+            } else {
+                return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+            }
         }
     }
 
@@ -831,6 +843,19 @@
         return (provisioned != null) && provisioned;
     }
 
+    private void updateSatelliteConnectedViaCarrierWithinHysteresisTimeState() {
+        Pair<Boolean, Integer> satelliteConnectedState =
+                mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime();
+        mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(satelliteConnectedState.first);
+        if (satelliteConnectedState.first) {
+            mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime.set(
+                    satelliteConnectedState.second);
+        } else {
+            mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime.set(
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        }
+    }
+
     private static void logv(@NonNull String log) {
         Rlog.v(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index b55c622..2ee9759 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -366,6 +366,29 @@
     }
 
     /**
+     * Check if the subscription ID is a NTN only subscription ID.
+     *
+     * @return {@code true} if the subscription ID is a NTN only subscription ID,
+     * {@code false} otherwise.
+    */
+    public static boolean isNtnOnlySubscriptionId(int subId) {
+        SubscriptionManagerService subscriptionManagerService =
+            SubscriptionManagerService.getInstance();
+        if (subscriptionManagerService == null) {
+            logd("isNtnOnlySubscriptionId: subscriptionManagerService is null");
+            return false;
+        }
+
+        SubscriptionInfo subInfo = subscriptionManagerService.getSubscriptionInfo(subId);
+        if (subInfo == null) {
+            logd("isNtnOnlySubscriptionId: subInfo is null for subId=" + subId);
+            return false;
+        }
+
+        return subInfo.isOnlyNonTerrestrialNetwork();
+    }
+
+    /**
      * Expected format of the input dictionary bundle is:
      * <ul>
      *     <li>Key: PLMN string.</li>
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 6f716b5..28ac17b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -2974,7 +2974,8 @@
     @Test
     public void testCarrierEnabledSatelliteConnectionHysteresisTime() throws Exception {
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
-        assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT
+                        .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
 
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
@@ -2994,7 +2995,8 @@
         doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths();
         processAllMessages();
         mSatelliteControllerUT.elapsedRealtime = 0;
-        assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT
+                        .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
 
@@ -3002,7 +3004,8 @@
         when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false);
         sendServiceStateChangedEvent();
         processAllMessages();
-        assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT
+                        .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
         verify(mPhone, times(1)).notifyCarrierRoamingNtnModeChanged(eq(false));
@@ -3017,7 +3020,8 @@
         // 2 minutes later and hysteresis timeout is 1 minute
         mSatelliteControllerUT.elapsedRealtime = 2 * 60 * 1000;
         // But Phone2 is connected to NTN right now
-        assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertTrue(mSatelliteControllerUT
+                       .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
         assertTrue(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
         verify(mPhone, times(0)).notifyCarrierRoamingNtnModeChanged(eq(false));
@@ -3030,7 +3034,8 @@
         sendServiceStateChangedEvent();
         processAllMessages();
         // Current time (2) - last disconnected time (2) < hysteresis timeout (1)
-        assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertTrue(mSatelliteControllerUT
+                       .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
         assertTrue(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
         verify(mPhone, times(0)).notifyCarrierRoamingNtnModeChanged(eq(false));
@@ -3042,7 +3047,8 @@
         mSatelliteControllerUT.elapsedRealtime = 4 * 60 * 1000;
         moveTimeForward(2 * 60 * 1000);
         processAllMessages();
-        assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT
+                        .isSatelliteConnectedViaCarrierWithinHysteresisTime().first);
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
         assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
         verify(mPhone, times(0)).notifyCarrierRoamingNtnModeChanged(eq(false));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index 529088b..efd9ccd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -29,6 +29,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -48,11 +49,13 @@
 import android.os.Looper;
 import android.os.OutcomeReceiver;
 import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.telecom.Connection;
 import android.telecom.TelecomManager;
 import android.telephony.BinderCacheManager;
 import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.telephony.ims.RegistrationManager;
@@ -62,6 +65,7 @@
 import android.testing.TestableLooper;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.ims.ImsException;
 import com.android.ims.ImsManager;
@@ -72,6 +76,7 @@
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.flags.Flags;
 import com.android.internal.telephony.metrics.SatelliteStats;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import org.junit.After;
 import org.junit.Before;
@@ -98,9 +103,11 @@
 public class SatelliteSOSMessageRecommenderTest extends TelephonyTest {
     private static final String TAG = "SatelliteSOSMessageRecommenderTest";
     private static final int TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
+    private static final int TEST_EMERGENCY_CALL_TO_T911_MSG_HYSTERESIS_TIMEOUT_MILLIS = 1000;
     private static final int PHONE_ID = 0;
     private static final int PHONE_ID2 = 1;
     private static final int SUB_ID = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+    private static final int SUB_ID1 = 1;
     private static final String CALL_ID = "CALL_ID";
     private static final String WRONG_CALL_ID = "WRONG_CALL_ID";
     private static final String DEFAULT_SATELLITE_MESSAGING_PACKAGE = "android.com.google.default";
@@ -108,6 +115,12 @@
             "android.com.google.default.SmsMmsApp";
     private static final String DEFAULT_HANDOVER_INTENT_ACTION =
             "android.com.vendor.action.EMERGENCY_MESSAGING";
+    private static final String DEFAULT_SOS_HANDOVER_APP =
+            "android.com.vendor.message;android.com.vendor.message.SosHandoverApp";
+    private static final String DEFAULT_SATELLITE_SOS_HANDOVER_PACKAGE =
+        "android.com.vendor.message";
+    private static final String DEFAULT_SATELLITE_SOS_HANDOVER_CLASS =
+            "android.com.vendor.message.SosHandoverApp";
     private static final String DEFAULT_T911_HANDOVER_INTENT_ACTION = Intent.ACTION_SENDTO;
     private TestSatelliteController mTestSatelliteController;
     private TestImsManager mTestImsManager;
@@ -125,6 +138,7 @@
     private ServiceState mServiceState2;
     @Mock
     private SatelliteStats mMockSatelliteStats;
+    @Mock private SubscriptionManagerService mMockSubscriptionManagerService;
 
     @Before
     public void setUp() throws Exception {
@@ -139,6 +153,8 @@
         when(mResources.getInteger(
                 R.integer.config_emergency_call_wait_for_connection_timeout_millis))
                 .thenReturn(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+        when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
+                .thenReturn(DEFAULT_SOS_HANDOVER_APP);
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         when(mFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
         mTestSatelliteController = new TestSatelliteController(mContext,
@@ -164,8 +180,19 @@
         when(mPhone2.isImsRegistered()).thenReturn(false);
         replaceInstance(SatelliteStats.class, "sInstance", null,
                 mMockSatelliteStats);
+        replaceInstance(SubscriptionManagerService.class, "sInstance", null,
+                mMockSubscriptionManagerService);
         doNothing().when(mMockSatelliteStats).onSatelliteSosMessageRecommender(
                 any(SatelliteStats.SatelliteSosMessageRecommenderParams.class));
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            false, -1);
+        mTestSOSMessageRecommender.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            false, -1);
+        mTestSatelliteController.selectedSatelliteSubId = SUB_ID1;
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo.Builder()
+                .setId(SUB_ID1).setOnlyNonTerrestrialNetwork(true).build();
+        when(mMockSubscriptionManagerService.getSubscriptionInfo(eq(SUB_ID1)))
+            .thenReturn(subscriptionInfo);
     }
 
     @After
@@ -175,9 +202,14 @@
 
     @Test
     public void testTimeoutBeforeEmergencyCallEnd_T911() {
-        testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
-                DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
-                DEFAULT_T911_HANDOVER_INTENT_ACTION);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
+        testTimeoutBeforeEmergencyCallEnd(
+            TEST_EMERGENCY_CALL_TO_T911_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+            EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
+            DEFAULT_SATELLITE_MESSAGING_PACKAGE,
+            DEFAULT_SATELLITE_MESSAGING_CLASS,
+            DEFAULT_T911_HANDOVER_INTENT_ACTION);
         verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
         assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
@@ -188,10 +220,12 @@
                 "android.com.vendor.message;android.com.vendor.message.SmsApp";
         when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
                 .thenReturn(satelliteHandoverApp);
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
-        testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
-                "android.com.vendor.message", "android.com.vendor.message.SmsApp",
-                DEFAULT_HANDOVER_INTENT_ACTION);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
+        testTimeoutBeforeEmergencyCallEnd(
+            TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+            EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+            "android.com.vendor.message", "android.com.vendor.message.SmsApp",
+            DEFAULT_HANDOVER_INTENT_ACTION);
         verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
         assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
@@ -202,9 +236,11 @@
                 "android.com.vendor.message;android.com.vendor.message.SmsApp;abc";
         when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
                 .thenReturn(satelliteHandoverApp);
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
-        testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
-                DEFAULT_HANDOVER_INTENT_ACTION);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
+        testTimeoutBeforeEmergencyCallEnd(
+            TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+            EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
+            DEFAULT_HANDOVER_INTENT_ACTION);
         verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
         assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
@@ -213,9 +249,11 @@
     public void testTimeoutBeforeEmergencyCallEnd_SOS_WithoutHandoverAppConfigured() {
         when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
                 .thenReturn("");
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
-        testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
-                DEFAULT_HANDOVER_INTENT_ACTION);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
+        testTimeoutBeforeEmergencyCallEnd(
+            TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+            EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
+            DEFAULT_HANDOVER_INTENT_ACTION);
         verify(mMockSatelliteStats, times(1)).onSatelliteSosMessageRecommender(any());
         assertTrue(mTestSOSMessageRecommender.isDialerNotified());
     }
@@ -232,7 +270,7 @@
         verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
     }
 
-    private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType,
+    private void testTimeoutBeforeEmergencyCallEnd(int timeoutMillis, int expectedHandoverType,
             String expectedPackageName, String expectedClassName, String expectedAction) {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
@@ -250,7 +288,7 @@
 
         // Wait for the timeout to expires
         mTestSOSMessageRecommender.isSatelliteAllowedCallback.onResult(true);
-        moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+        moveTimeForward(timeoutMillis);
         processAllMessages();
         if (TextUtils.isEmpty(expectedPackageName) || TextUtils.isEmpty(expectedClassName)) {
             assertTrue(mTestConnection.isEventWithoutLaunchIntentSent(
@@ -267,7 +305,7 @@
 
     @Test
     public void testTimeoutBeforeEmergencyCallEnd_EventDisplayEmergencyMessageNotSent() {
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSatelliteController.setDeviceProvisioned(false);
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
@@ -297,7 +335,7 @@
     @Test
     public void testTimeoutBeforeEmergencyCallEnd_T911_FromNotConnectedToConnected() {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSatelliteController.isOemEnabledSatelliteSupported = false;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
@@ -312,7 +350,8 @@
         processAllMessages();
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
         // Wait for the timeout to expires
         moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
         processAllMessages();
@@ -362,8 +401,9 @@
         processAllMessages();
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
-                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
+                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+                DEFAULT_SATELLITE_SOS_HANDOVER_PACKAGE,
+                DEFAULT_SATELLITE_SOS_HANDOVER_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -373,7 +413,7 @@
 
     @Test
     public void testSatelliteProvisionStateChangedBeforeTimeout() {
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
@@ -394,7 +434,6 @@
         assertFalse(mTestSOSMessageRecommender.isDialerNotified());
         reset(mMockSatelliteStats);
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -418,8 +457,9 @@
         processAllMessages();
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
-                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
+                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+                DEFAULT_SATELLITE_SOS_HANDOVER_PACKAGE,
+                DEFAULT_SATELLITE_SOS_HANDOVER_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
         assertFalse(mTestSOSMessageRecommender.isTimerStarted());
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
         assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2);
@@ -459,8 +499,9 @@
         processAllMessages();
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
-                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
+                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+                DEFAULT_SATELLITE_SOS_HANDOVER_PACKAGE,
+                DEFAULT_SATELLITE_SOS_HANDOVER_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -527,7 +568,6 @@
     @Test
     public void testSatelliteNotAllowedInCurrentLocation() {
         mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
@@ -562,7 +602,8 @@
                 mContext,
                 Looper.myLooper(),
                 satelliteController, mTestImsManager);
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
         testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
 
@@ -608,11 +649,8 @@
 
         // Both OEM and carrier support satellite, but device is not connected to carrier satellite
         // within hysteresis time. Thus, OEM timer will be used.
-        long carrierTimeoutMillis = 1000;
         mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = true;
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
-        mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
-                carrierTimeoutMillis;
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         processAllMessages();
         assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
@@ -621,8 +659,26 @@
 
         // Both OEM and carrier support satellite, and device is connected to carrier satellite
         // within hysteresis time. Thus, carrier timer will be used.
+        int carrierTimeoutMillis = 1000;
         mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = true;
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
+        mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                carrierTimeoutMillis;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
+        processAllMessages();
+        assertEquals(carrierTimeoutMillis, mTestSOSMessageRecommender.getTimeOutMillis());
+        verify(mMockSatelliteStats, never()).onSatelliteSosMessageRecommender(any());
+
+        // Both OEM and carrier support satellite, device is not connected to carrier satellite
+        // within hysteresis time, but selected satellite subId is not NTN only. Thus, carrier
+        // timer will be used.
+        carrierTimeoutMillis = 2000;
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo.Builder()
+                .setId(SUB_ID1).setOnlyNonTerrestrialNetwork(false).build();
+        when(mMockSubscriptionManagerService.getSubscriptionInfo(eq(SUB_ID1)))
+            .thenReturn(subscriptionInfo);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
                 carrierTimeoutMillis;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
@@ -635,7 +691,8 @@
     public void testGetEmergencyCallToSatelliteHandoverType_SatelliteViaCarrierAndOemAvailable() {
         mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
         mTestSatelliteController.mIsDeviceProvisionedForTest = true;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
@@ -649,7 +706,8 @@
     public void testGetEmergencyCallToSatelliteHandoverType_OnlySatelliteViaCarrierAvailable() {
         mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(
+            true, SUB_ID1);
         mTestSatelliteController.mIsDeviceProvisionedForTest = false;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
@@ -663,13 +721,13 @@
     public void testGetEmergencyCallToSatelliteHandoverType_OemAndCarrierNotAvailable() {
         mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN);
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSatelliteController.mIsDeviceProvisionedForTest = true;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
                 mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
 
-        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+        mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false, -1);
         mTestSatelliteController.mIsDeviceProvisionedForTest = false;
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
         assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
@@ -745,8 +803,9 @@
         processAllMessages();
 
         assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
-                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
-                DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_T911_HANDOVER_INTENT_ACTION));
+                EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+                DEFAULT_SATELLITE_SOS_HANDOVER_PACKAGE,
+                DEFAULT_SATELLITE_SOS_HANDOVER_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
         assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
         assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
         assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -777,11 +836,18 @@
         private int mUnregisterForSatelliteProvisionStateChangedCalls = 0;
         private Boolean mIsDeviceProvisionedForTest = true;
         private boolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = true;
+        private int mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime = -1;
         public boolean isOemEnabledSatelliteSupported = true;
         public boolean isCarrierEnabledSatelliteSupported = true;
         public boolean isSatelliteEmergencyMessagingSupportedViaCarrier = true;
-        public long carrierEmergencyCallWaitForConnectionTimeoutMillis =
-                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS;
+        public int carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                TEST_EMERGENCY_CALL_TO_T911_MSG_HYSTERESIS_TIMEOUT_MILLIS;
+        public int overrideEmergencyCallToSatelliteHandoverType =
+            SatelliteController.INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+        public boolean isSatelliteEsosSupported = false;
+        public int carrierRoamingNtnEmergencyCallToSatelliteHandoverType =
+            EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
+        public int selectedSatelliteSubId = -1;
 
         /**
          * Create a SatelliteController to act as a backend service of
@@ -833,13 +899,14 @@
         }
 
         @Override
-        public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() {
-            return mIsSatelliteConnectedViaCarrierWithinHysteresisTime;
+        public Pair<Boolean,Integer> isSatelliteConnectedViaCarrierWithinHysteresisTime() {
+            return new Pair(mIsSatelliteConnectedViaCarrierWithinHysteresisTime,
+                mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime);
         }
 
         @Override
         protected int getEnforcedEmergencyCallToSatelliteHandoverType() {
-            return INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+            return overrideEmergencyCallToSatelliteHandoverType;
         }
 
         @Override
@@ -853,14 +920,35 @@
         }
 
         @Override
+        public int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
+            return carrierEmergencyCallWaitForConnectionTimeoutMillis;
+        }
+
+        @Override
         protected List<DeviceState> getSupportedDeviceStates() {
             return List.of(new DeviceState(new DeviceState.Configuration.Builder(0 /* identifier */,
                     "DEFAULT" /* name */).build()));
         }
 
+        @Override
+        public boolean isSatelliteEsosSupported(int subId) {
+            return isSatelliteEsosSupported;
+        }
+
+        @Override
+        public int getCarrierRoamingNtnEmergencyCallToSatelliteHandoverType(int subId) {
+            return carrierRoamingNtnEmergencyCallToSatelliteHandoverType;
+        }
+
+        @Override
+        public int getSelectedSatelliteSubId() {
+            return selectedSatelliteSubId;
+        }
+
         public void setSatelliteConnectedViaCarrierWithinHysteresisTime(
-                boolean connectedViaCarrier) {
+                boolean connectedViaCarrier, int subId) {
             mIsSatelliteConnectedViaCarrierWithinHysteresisTime = connectedViaCarrier;
+            mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime = subId;
         }
 
         public int getRegisterForSatelliteProvisionStateChangedCalls() {
@@ -986,7 +1074,7 @@
                 DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS);
         private boolean mIsDialerNotified;
         private boolean mProvisionState = true;
-        private boolean mSatelliteAllowedByReasons = true;
+        public boolean isSatelliteAllowedByReasons = true;
 
         /**
          * Create an instance of SatelliteSOSMessageRecommender.
@@ -1028,7 +1116,7 @@
 
         @Override
         protected boolean isSatelliteAllowedByReasons() {
-            return mSatelliteAllowedByReasons;
+            return isSatelliteAllowedByReasons;
         }
 
         public boolean isTimerStarted() {
@@ -1050,6 +1138,12 @@
         public boolean isDialerNotified() {
             return mIsDialerNotified;
         }
+
+        public void setSatelliteConnectedViaCarrierWithinHysteresisTime(
+                boolean connectedViaCarrier, int subId) {
+            mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(connectedViaCarrier);
+            mSubIdOfSatelliteConnectedViaCarrierWithinHysteresisTime.set(subId);
+        }
     }
 
     private static class TestConnection extends Connection {