Merge "Clear auto select sub correctly" into 24D1-dev
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index aabceca..1e714c5 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -90,3 +90,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "hide_preinstalled_carrier_app_at_most_once"
+    namespace: "telephony"
+    description: "Fix bug when preloaded carrier app is uninstalled and lose provisioning data"
+    bug:"158028151"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/flags/satellite.aconfig b/flags/satellite.aconfig
index e640e6e..798ce40 100644
--- a/flags/satellite.aconfig
+++ b/flags/satellite.aconfig
@@ -12,4 +12,11 @@
     namespace: "telephony"
     description: "This flag controls satellite communication supported by carriers."
     bug:"296437388"
+}
+
+flag {
+    name: "satellite_internet"
+    namespace: "telephony"
+    description: "This flag enables satellite internet support."
+    bug:"326972202"
 }
\ No newline at end of file
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index e54c969..59b177b 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -281,6 +281,7 @@
     optional bool is_iwlan_cross_sim_at_end = 38;
     optional bool is_iwlan_cross_sim_at_connected = 39;
     optional bool vonr_enabled = 40;
+    optional bool is_ntn = 41;
 
     // Internal use only
     optional int64 setup_begin_millis = 10001;
@@ -373,6 +374,7 @@
     repeated int32 handover_failure_rat = 21;
     optional bool is_non_dds = 22;
     optional bool is_iwlan_cross_sim = 23;
+    optional bool is_ntn = 24;
 }
 
 message CellularServiceState {
@@ -391,6 +393,7 @@
     optional bool override_voice_service = 13;
     optional bool isDataEnabled = 14;
     optional bool is_iwlan_cross_sim = 15;
+    optional bool is_ntn = 16;
 
     // Internal use only
     optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index aaeba23..a5f433b 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
 import static android.telephony.TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE;
 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
@@ -632,7 +633,9 @@
             if (hasData()) mSubscriptionManagerService.setDefaultDataSubId(subId);
             if (hasCalling()) mSubscriptionManagerService.setDefaultVoiceSubId(subId);
             if (hasMessaging()) mSubscriptionManagerService.setDefaultSmsSubId(subId);
-            sendDefaultSubConfirmedNotification(subId);
+            if (!mSubscriptionManagerService.isEsimBootStrapProvisioningActivated()) {
+                sendDefaultSubConfirmedNotification(subId);
+            }
             return;
         }
 
@@ -685,7 +688,9 @@
         // Update mPrimarySubList. Opportunistic subscriptions can't be default
         // data / voice / sms subscription.
         List<Integer> prevPrimarySubList = mPrimarySubList;
-        mPrimarySubList = activeSubList.stream().filter(info -> !info.isOpportunistic())
+        mPrimarySubList = activeSubList.stream()
+                .filter(info -> !info.isOpportunistic())
+                .filter(info -> info.getProfileClass() != PROFILE_CLASS_PROVISIONING)
                 .map(info -> info.getSubscriptionId())
                 .collect(Collectors.toList());
 
@@ -751,6 +756,12 @@
 
     private void sendSubChangeNotificationIfNeeded(int change, boolean dataSelected,
             boolean voiceSelected, boolean smsSelected) {
+
+        if (mSubscriptionManagerService.isEsimBootStrapProvisioningActivated()) {
+            log("esim bootstrap activation in progress, skip notification");
+            return;
+        }
+
         @TelephonyManager.DefaultSubscriptionSelectType
         int simSelectDialogType = getSimSelectDialogType(
                 change, dataSelected, voiceSelected, smsSelected);
diff --git a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index 4b10cae..f9261ff 100644
--- a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
+++ b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -24,6 +24,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.telephony.uicc.IccFileHandler;
 import com.android.internal.telephony.uicc.IccUtils;
 import com.android.internal.util.State;
@@ -40,11 +41,14 @@
     private static final int CMD_START = 1;
     private static final int CMD_PARAMS_READY = 2;
 
+    private final Object mLock = new Object();
     // members
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    @GuardedBy("mLock")
     private CommandParamsFactory mCmdParamsFactory = null;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private RilMessage mCurrentRilMessage = null;
+    @GuardedBy("mLock")
     private Handler mCaller = null;
     private static int mSimCount = 0;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -113,9 +117,13 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private void sendCmdForExecution(RilMessage rilMsg) {
-        Message msg = mCaller.obtainMessage(CatService.MSG_ID_RIL_MSG_DECODED,
-                new RilMessage(rilMsg));
-        msg.sendToTarget();
+        synchronized (mLock) {
+            if (mCaller != null) {
+                Message msg = mCaller.obtainMessage(CatService.MSG_ID_RIL_MSG_DECODED,
+                        new RilMessage(rilMsg));
+                msg.sendToTarget();
+            }
+        }
     }
 
     private RilMessageDecoder(Handler caller, IccFileHandler fh, Context context) {
@@ -125,8 +133,10 @@
         addState(mStateCmdParamsReady);
         setInitialState(mStateStart);
 
-        mCaller = caller;
-        mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh, context);
+        synchronized (mLock) {
+            mCaller = caller;
+            mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh, context);
+        }
     }
 
     private RilMessageDecoder() {
@@ -166,7 +176,7 @@
     }
 
     private boolean decodeMessageParams(RilMessage rilMsg) {
-        boolean decodingStarted;
+        boolean decodingStarted = false;
 
         mCurrentRilMessage = rilMsg;
         switch(rilMsg.mId) {
@@ -188,16 +198,21 @@
                 decodingStarted = false;
                 break;
             }
-            try {
-                // Start asynch parsing of the command parameters.
-                mCmdParamsFactory.make(BerTlv.decode(rawData));
-                decodingStarted = true;
-            } catch (ResultException e) {
-                // send to Service for proper RIL communication.
-                CatLog.d(this, "decodeMessageParams: caught ResultException e=" + e);
-                mCurrentRilMessage.mResCode = e.result();
-                sendCmdForExecution(mCurrentRilMessage);
-                decodingStarted = false;
+
+            synchronized (mLock) {
+                if (mCmdParamsFactory != null) {
+                    try {
+                        // Start asynch parsing of the command parameters.
+                        mCmdParamsFactory.make(BerTlv.decode(rawData));
+                        decodingStarted = true;
+                    } catch (ResultException e) {
+                        // send to Service for proper RIL communication.
+                        CatLog.d(this, "decodeMessageParams: caught ResultException e=" + e);
+                        mCurrentRilMessage.mResCode = e.result();
+                        sendCmdForExecution(mCurrentRilMessage);
+                        decodingStarted = false;
+                    }
+                }
             }
             break;
         default:
@@ -211,10 +226,16 @@
         quitNow();
         mStateStart = null;
         mStateCmdParamsReady = null;
-        mCmdParamsFactory.dispose();
-        mCmdParamsFactory = null;
+
+        synchronized (mLock) {
+            if (mCmdParamsFactory != null) {
+                mCmdParamsFactory.dispose();
+                mCmdParamsFactory = null;
+            }
+            mCaller = null;
+        }
+
         mCurrentRilMessage = null;
-        mCaller = null;
         mInstance = null;
     }
 }
diff --git a/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
index 0db7844..85d5a35 100644
--- a/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
+++ b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
@@ -20,12 +20,14 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.os.FileUtils;
 import android.util.Log;
-import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.satellite.SatelliteConfig;
 import com.android.internal.telephony.satellite.SatelliteConfigParser;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.server.updates.ConfigUpdateInstallReceiver;
 
 import libcore.io.IoUtils;
@@ -33,6 +35,8 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 
@@ -43,7 +47,8 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected static final String UPDATE_DIR = "/data/misc/telephonyconfig";
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected static final String UPDATE_CONTENT_PATH = "telephony_config.pb";
+    protected static final String NEW_CONFIG_CONTENT_PATH = "new_telephony_config.pb";
+    protected static final String VALID_CONFIG_CONTENT_PATH = "valid_telephony_config.pb";
     protected static final String UPDATE_METADATA_PATH = "metadata/";
     public static final String VERSION = "version";
 
@@ -66,7 +71,7 @@
     }
 
     public TelephonyConfigUpdateInstallReceiver() {
-        super(UPDATE_DIR, UPDATE_CONTENT_PATH, UPDATE_METADATA_PATH, VERSION);
+        super(UPDATE_DIR, NEW_CONFIG_CONTENT_PATH, UPDATE_METADATA_PATH, VERSION);
     }
 
     /**
@@ -74,57 +79,94 @@
      */
     @Nullable
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    public byte[] getCurrentContent() {
+    public byte[] getContentFromContentPath(@NonNull File contentPath) {
         try {
-            return IoUtils.readFileAsByteArray(updateContent.getCanonicalPath());
+            return IoUtils.readFileAsByteArray(contentPath.getCanonicalPath());
         } catch (IOException e) {
-            Slog.i(TAG, "Failed to read current content, assuming first update!");
+            Log.e(TAG, "Failed to read current content : " + contentPath);
             return null;
         }
     }
 
+    /**
+     * @param parser target of validation.
+     * @return {@code true} if all the config data are valid {@code false} otherwise.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public boolean isValidSatelliteCarrierConfigData(@NonNull ConfigParser parser) {
+        SatelliteConfig satelliteConfig = (SatelliteConfig) parser.getConfig();
+        if (satelliteConfig == null) {
+            Log.e(TAG, "satelliteConfig is null");
+            return false;
+        }
+
+        // If no carrier config exist then it is considered as a valid config
+        Set<Integer> carrierIds = satelliteConfig.getAllSatelliteCarrierIds();
+        for (int carrierId : carrierIds) {
+            Map<String, Set<Integer>> plmnsServices =
+                    satelliteConfig.getSupportedSatelliteServices(carrierId);
+            Set<String> plmns = plmnsServices.keySet();
+            for (String plmn : plmns) {
+                if (!TelephonyUtils.isValidPlmn(plmn)) {
+                    Log.e(TAG, "found invalid plmn : " + plmn);
+                    return false;
+                }
+                Set<Integer> serviceSet = plmnsServices.get(plmn);
+                for (int service : serviceSet) {
+                    if (!TelephonyUtils.isValidService(service)) {
+                        Log.e(TAG, "found invalid service : " + service);
+                        return false;
+                    }
+                }
+            }
+        }
+        Log.d(TAG, "the config data is valid");
+        return true;
+    }
+
+
     @Override
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
     public void postInstall(Context context, Intent intent) {
         Log.d(TAG, "Telephony config is updated in file partition");
-        ConfigParser updatedConfigParser = getNewConfigParser(DOMAIN_SATELLITE,
-                getCurrentContent());
 
-        if (updatedConfigParser == null) {
-            Log.d(TAG, "updatedConfigParser is null");
+        ConfigParser newConfigParser = getNewConfigParser(DOMAIN_SATELLITE,
+                getContentFromContentPath(updateContent));
+
+        if (newConfigParser == null) {
+            Log.e(TAG, "newConfigParser is null");
             return;
         }
 
-        boolean isParserChanged = false;
+        if (!isValidSatelliteCarrierConfigData(newConfigParser)) {
+            Log.e(TAG, "received config data has invalid satellite carrier config data");
+            return;
+        }
 
         synchronized (getInstance().mConfigParserLock) {
-            if (getInstance().mConfigParser == null) {
-                getInstance().mConfigParser = updatedConfigParser;
-                isParserChanged = true;
-            } else {
-                int updatedVersion = updatedConfigParser.mVersion;
+            if (getInstance().mConfigParser != null) {
+                int updatedVersion = newConfigParser.mVersion;
                 int previousVersion = getInstance().mConfigParser.mVersion;
                 Log.d(TAG, "previous version is " + previousVersion + " | updated version is "
                         + updatedVersion);
-                if (updatedVersion > previousVersion) {
-                    getInstance().mConfigParser = updatedConfigParser;
-                    isParserChanged = true;
+                if (updatedVersion <= previousVersion) {
+                    Log.e(TAG, "updatedVersion is smaller than previousVersion");
+                    return;
                 }
             }
+            getInstance().mConfigParser = newConfigParser;
+        }
+
+        if (!getInstance().mCallbackHashMap.keySet().isEmpty()) {
+            Iterator<Executor> iterator = getInstance().mCallbackHashMap.keySet().iterator();
+            while (iterator.hasNext()) {
+                Executor executor = iterator.next();
+                getInstance().mCallbackHashMap.get(executor).onChanged(newConfigParser);
+            }
         }
 
-        if (isParserChanged) {
-            if (getInstance().mCallbackHashMap.keySet().isEmpty()) {
-                Log.d(TAG, "mCallbackHashMap.keySet().isEmpty");
-                return;
-            }
-            Iterator<Executor> iterator =
-                    getInstance().mCallbackHashMap.keySet().iterator();
-            while (iterator.hasNext()) {
-                Executor executor = iterator.next();
-                getInstance().mCallbackHashMap.get(executor).onChanged(
-                        updatedConfigParser);
-            }
+        if (!copySourceFileToTargetFile(NEW_CONFIG_CONTENT_PATH, VALID_CONFIG_CONTENT_PATH)) {
+            Log.e(TAG, "fail to copy to the valid satellite carrier config data");
         }
     }
 
@@ -135,7 +177,9 @@
         synchronized (getInstance().mConfigParserLock) {
             if (getInstance().mConfigParser == null) {
                 Log.d(TAG, "CreateNewConfigParser with domain " + domain);
-                getInstance().mConfigParser = getNewConfigParser(domain, getCurrentContent());
+                getInstance().mConfigParser = getNewConfigParser(
+                        domain, getContentFromContentPath(new File(updateDir,
+                                VALID_CONFIG_CONTENT_PATH)));
             }
             return getInstance().mConfigParser;
         }
@@ -197,4 +241,35 @@
                 return null;
         }
     }
+
+    /**
+     * @param sourceFileName source file name
+     * @param targetFileName target file name
+     * @return {@code true} if successful, {@code false} otherwise
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public boolean copySourceFileToTargetFile(
+            @NonNull String sourceFileName, @NonNull String targetFileName) {
+        try {
+            File sourceFile = new File(UPDATE_DIR, sourceFileName);
+            File targetFile = new File(UPDATE_DIR, targetFileName);
+            Log.d(TAG, "copy " + sourceFile.getName() + " >> " + targetFile.getName());
+
+            if (sourceFile.exists()) {
+                if (targetFile.exists()) {
+                    targetFile.delete();
+                }
+                FileUtils.copy(sourceFile, targetFile);
+                FileUtils.copyPermissions(sourceFile, targetFile);
+                Log.d(TAG, "success to copy the file " + sourceFile.getName() + " to "
+                        + targetFile.getName());
+                return true;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "copy error : " + e);
+            return false;
+        }
+        Log.d(TAG, "source file is not exist, no file to copy");
+        return false;
+    }
 }
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 0e06dad..6ad89ce 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -1436,6 +1436,18 @@
     }
 
     /**
+     * @return The capabilities that network will be forced to mark as cellular transport.
+     */
+    public @NetCapability Set<Integer> getForcedCellularTransportCapabilities() {
+        String[] forcedCellularTransportCapabilities = mResources.getStringArray(
+                com.android.internal.R.array.config_force_cellular_transport_capabilities);
+
+        return Arrays.stream(forcedCellularTransportCapabilities)
+                .map(DataUtils::getNetworkCapabilityFromString)
+                .collect(Collectors.toSet());
+    }
+
+    /**
      * Log debug messages.
      * @param s debug messages
      */
@@ -1543,6 +1555,9 @@
         pw.println("isTetheringProfileDisabledForRoaming="
                 + isTetheringProfileDisabledForRoaming());
         pw.println("allowClearInitialAttachDataProfile=" + allowClearInitialAttachDataProfile());
+        pw.println("forcedCellularTransportCapabilities=" + getForcedCellularTransportCapabilities()
+                .stream().map(DataUtils::networkCapabilityToString)
+                .collect(Collectors.joining(",")));
         pw.decreaseIndent();
     }
 }
diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java
index 3d10e9c..a54884f 100644
--- a/src/java/com/android/internal/telephony/data/DataEvaluation.java
+++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java
@@ -346,7 +346,9 @@
         /** Handover max retry stopped but network is not on the preferred transport. */
         HANDOVER_RETRY_STOPPED(true),
         /** BootStrap sim data limit reached. */
-        DATA_LIMIT_REACHED(true);
+        DATA_LIMIT_REACHED(true),
+        /** Data network connectivity transport not allowed. */
+        DATA_NETWORK_TRANSPORT_NOT_ALLOWED(true);
 
         private final boolean mIsHardReason;
 
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index 0dbbc5c..bd98403 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -314,6 +314,7 @@
                     TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK,
                     TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED,
                     TEAR_DOWN_REASON_DATA_LIMIT_REACHED,
+                    TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED,
             })
     public @interface TearDownReason {}
 
@@ -413,6 +414,9 @@
     /** Data network tear down due to bootstrap sim data limit reached. */
     public static final int TEAR_DOWN_REASON_DATA_LIMIT_REACHED = 31;
 
+    /** Data network tear down due to current data network transport mismatch. */
+    public static final int TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED = 32;
+
     //********************************************************************************************//
     // WHENEVER ADD A NEW TEAR DOWN REASON, PLEASE UPDATE DataDeactivateReasonEnum in enums.proto //
     //********************************************************************************************//
@@ -698,6 +702,11 @@
      */
     private boolean mLastKnownRoamingState;
 
+    /**
+     * The non-terrestrial status
+     */
+    private final boolean mIsSatellite;
+
     /** The reason that why setting up this data network is allowed. */
     private @NonNull DataAllowedReason mDataAllowedReason;
 
@@ -988,6 +997,8 @@
         mTransport = transport;
         mLastKnownDataNetworkType = getDataNetworkType();
         mLastKnownRoamingState = mPhone.getServiceState().getDataRoamingFromRegistration();
+        mIsSatellite = mPhone.getServiceState().isUsingNonTerrestrialNetwork()
+                && transport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
         mDataAllowedReason = dataAllowedReason;
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         mAttachedNetworkRequestList.addAll(networkRequestList);
@@ -2214,11 +2225,32 @@
     }
 
     /**
+     * @return {@code true} if this is a satellite data network.
+     */
+    public boolean isSatellite() {
+        return mIsSatellite;
+    }
+
+    /**
      * Update the network capabilities.
      */
     private void updateNetworkCapabilities() {
-        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
-                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+
+        if (mFlags.satelliteInternet() && mIsSatellite
+                && mDataConfigManager.getForcedCellularTransportCapabilities().stream()
+                .noneMatch(this::hasNetworkCapabilityInNetworkRequests)) {
+            // TODO: b/328622096 remove the try/catch
+            try {
+                builder.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+            } catch (IllegalArgumentException exception) {
+                loge("TRANSPORT_SATELLITE is not supported.");
+                builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+            }
+        } else {
+            builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        }
+
         boolean roaming = mPhone.getServiceState().getDataRoaming();
 
         builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
@@ -2385,6 +2417,11 @@
             builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         }
 
+        // mark the network as restricted when service state is non-terrestrial(satellite network)
+        if (mFlags.satelliteInternet() && mIsSatellite) {
+            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
         // Check if the feature force MMS on IWLAN is enabled. When the feature is enabled, MMS
         // will be attempted on IWLAN if possible, even if existing cellular networks already
         // supports IWLAN.
@@ -2401,7 +2438,7 @@
                 DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
                         .getDataProfileForNetworkRequest(new TelephonyNetworkRequest(
                                 new NetworkRequest.Builder().addCapability(
-                                NetworkCapabilities.NET_CAPABILITY_MMS).build(), mPhone),
+                                NetworkCapabilities.NET_CAPABILITY_MMS).build(), mPhone, mFlags),
                         TelephonyManager.NETWORK_TYPE_IWLAN, false, false, false);
                 // If we find another data data profile that can support MMS on IWLAN, then remove
                 // the MMS capability from this cellular network. This will allow IWLAN to be
@@ -3790,6 +3827,8 @@
                 return "TEAR_DOWN_REASON_PREFERRED_DATA_SWITCHED";
             case TEAR_DOWN_REASON_DATA_LIMIT_REACHED:
                 return "TEAR_DOWN_REASON_DATA_LIMIT_REACHED";
+            case TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED:
+                return "TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED";
             default:
                 return "UNKNOWN(" + reason + ")";
         }
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 70d3b23..2725295 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -1454,8 +1454,7 @@
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         // If we don't skip checking existing network, then we should check If one of the
         // existing networks can satisfy the internet request, then internet is allowed.
         if ((!mFeatureFlags.ignoreExistingNetworksForInternetAllowedChecking()
@@ -1514,8 +1513,7 @@
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataEvaluation evaluation = evaluateNetworkRequest(internetRequest,
                 DataEvaluationReason.EXTERNAL_QUERY);
         return evaluation.getDataDisallowedReasons();
@@ -1535,12 +1533,19 @@
         int transport = mAccessNetworksManager.getPreferredTransportByNetworkCapability(
                 networkRequest.getApnTypeNetworkCapability());
 
+        // Check if the request can be satisfied by cellular network or satellite network.
+        if (mFeatureFlags.satelliteInternet()
+                && !canConnectivityTransportSatisfyNetworkRequest(networkRequest, transport)) {
+            evaluation.addDataDisallowedReason(
+                    DataDisallowedReason.DATA_NETWORK_TRANSPORT_NOT_ALLOWED);
+        }
+
         // Bypass all checks for emergency network request.
         if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
             DataProfile emergencyProfile = mDataProfileManager.getDataProfileForNetworkRequest(
                     networkRequest, getDataNetworkType(transport),
                     mServiceState.isUsingNonTerrestrialNetwork(),
-                    isEsimBootStrapProvisioningActivated(), true);
+                    false /*isEsimBootStrapProvisioning*/, true);
 
             // Check if the profile is being throttled.
             if (mDataConfigManager.shouldHonorRetryTimerForEmergencyNetworkRequest()
@@ -1549,14 +1554,13 @@
                 evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_THROTTLED);
                 log("Emergency network request is throttled by the previous setup data "
                             + "call response.");
-                log(evaluation.toString());
-                networkRequest.setEvaluation(evaluation);
-                return evaluation;
             }
 
-            evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
-            if (emergencyProfile != null) {
-                evaluation.setCandidateDataProfile(emergencyProfile);
+            if (!evaluation.containsDisallowedReasons()) {
+                evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
+                if (emergencyProfile != null) {
+                    evaluation.setCandidateDataProfile(emergencyProfile);
+                }
             }
             networkRequest.setEvaluation(evaluation);
             log(evaluation.toString());
@@ -1645,11 +1649,6 @@
             evaluation.addDataDisallowedReason(DataDisallowedReason.CDMA_EMERGENCY_CALLBACK_MODE);
         }
 
-        // Check whether data is disallowed while using satellite
-        if (isDataDisallowedDueToSatellite(networkRequest.getCapabilities())) {
-            evaluation.addDataDisallowedReason(DataDisallowedReason.SERVICE_OPTION_NOT_SUPPORTED);
-        }
-
         // Check if only one data network is allowed.
         if (isOnlySingleDataNetworkAllowed(transport)
                 && !hasCapabilityExemptsFromSinglePdnRule(networkRequest.getCapabilities())) {
@@ -1802,6 +1801,9 @@
 
             if (!TextUtils.isEmpty(subscriberId)) {
                 builder.setSubscriberIds(Set.of(subscriberId));
+                // Consider data usage calculation of only metered network.
+                // Emergency data usage is excluded.
+                builder.setMeteredness(android.net.NetworkStats.METERED_YES);
                 NetworkTemplate template = builder.build();
                 final NetworkStats.Bucket ret = networkStatsManager
                         .querySummaryForDevice(template, 0L, System.currentTimeMillis());
@@ -1822,7 +1824,7 @@
                 networkRequestList.add(networkRequest);
             }
         }
-        return DataUtils.getGroupedNetworkRequestList(networkRequestList);
+        return DataUtils.getGroupedNetworkRequestList(networkRequestList, mFeatureFlags);
     }
 
     /**
@@ -1891,10 +1893,26 @@
             evaluation.addDataDisallowedReason(DataDisallowedReason.CDMA_EMERGENCY_CALLBACK_MODE);
         }
 
-        // Check whether data is disallowed while using satellite
-        if (isDataDisallowedDueToSatellite(dataNetwork.getNetworkCapabilities()
-                .getCapabilities())) {
-            evaluation.addDataDisallowedReason(DataDisallowedReason.SERVICE_OPTION_NOT_SUPPORTED);
+        // If the network is satellite, then the network must be restricted.
+        if (mFeatureFlags.satelliteInternet()) {
+            // The IWLAN data network should remain intact even when satellite is connected.
+            if (dataNetwork.getTransport() != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
+                // On satellite, every data network needs to be restricted.
+                if (mServiceState.isUsingNonTerrestrialNetwork()
+                        && dataNetwork.getNetworkCapabilities()
+                        .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
+                    evaluation.addDataDisallowedReason(
+                            DataDisallowedReason.DATA_NETWORK_TRANSPORT_NOT_ALLOWED);
+                }
+
+                // Check if the transport is compatible with the network
+                if (mServiceState.isUsingNonTerrestrialNetwork() != dataNetwork.isSatellite()) {
+                    // Since we don't support satellite/cellular network handover, we should always
+                    // tear down the network when transport changes.
+                    evaluation.addDataDisallowedReason(
+                            DataDisallowedReason.DATA_NETWORK_TRANSPORT_NOT_ALLOWED);
+                }
+            }
         }
 
         // Check whether data limit reached for bootstrap sim, else re-evaluate based on the timer
@@ -2082,15 +2100,91 @@
     }
 
     /**
-     * tethering and enterprise capabilities are not respected as restricted requests. For a request
-     * with these capabilities, any soft disallowed reasons are honored.
+     * Check if the transport from connectivity service can satisfy the network request. Note the
+     * transport here is connectivity service's transport (Wifi, cellular, satellite, etc..), not
+     * the widely used {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN WLAN},
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN WWAN} transport in telephony.
+     *
+     * @param networkRequest Network request
+     * @param transport The preferred transport type for the request. The transport here is
+     * WWAN/WLAN.
+     * @return {@code true} if the connectivity transport can satisfy the network request, otherwise
+     * {@code false}.
+     */
+    private boolean canConnectivityTransportSatisfyNetworkRequest(
+            @NonNull TelephonyNetworkRequest networkRequest, @TransportType int transport) {
+        // When the device is on satellite, only restricted network request can request network.
+        if (mServiceState.isUsingNonTerrestrialNetwork()
+                && networkRequest.getNativeNetworkRequest().hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) {
+            return false;
+        }
+
+        // If the network request does not specify cellular or satellite, then it can be
+        // satisfied when the device is either on cellular ot satellite.
+        if (!networkRequest.getNativeNetworkRequest().hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR)
+                && !networkRequest.getNativeNetworkRequest().hasTransport(
+                        NetworkCapabilities.TRANSPORT_SATELLITE)) {
+            return true;
+        }
+
+        // Check if this is a IWLAN network request.
+        if (networkRequest.getNativeNetworkRequest().hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR)
+                && transport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
+            // If the cellular request would result in bringing up network on IWLAN, then no
+            // need to check if the device is using satellite network.
+            return true;
+        }
+
+        // As a short term solution, allowing some networks to be always marked as cellular
+        // transport if certain capabilities are in the network request.
+        if (networkRequest.getNativeNetworkRequest().hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR) && Arrays.stream(
+                        networkRequest.getCapabilities())
+                .anyMatch(mDataConfigManager.getForcedCellularTransportCapabilities()::contains)) {
+            return true;
+        }
+
+        // If the network is cellular, then the request must specify cellular transport. Or if the
+        // the network is satellite, then the request must specify satellite transport and
+        // restricted.
+        return (mServiceState.isUsingNonTerrestrialNetwork()
+                && networkRequest.getNativeNetworkRequest().hasTransport(
+                        NetworkCapabilities.TRANSPORT_SATELLITE))
+                || (!mServiceState.isUsingNonTerrestrialNetwork()
+                        && networkRequest.getNativeNetworkRequest().hasTransport(
+                        NetworkCapabilities.TRANSPORT_CELLULAR));
+    }
+
+    /**
+     * Check if a network request should be treated as a valid restricted network request that
+     * can bypass soft disallowed reasons, for example, mobile data off.
+     *
      * @param networkRequest The network request to evaluate.
-     * @return {@code true} if the request doesn't contain any exceptional capabilities, its
-     * restricted capability, if any, is respected.
+     * @return {@code true} if the request can be considered as a valid restricted network request
+     * that can bypass any soft disallowed reasons, otherwise {@code false}.
      */
     private boolean isValidRestrictedRequest(@NonNull TelephonyNetworkRequest networkRequest) {
-        return !(networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
-                || networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+
+        if (!mFeatureFlags.satelliteInternet()) {
+            return !(networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+                    || networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE));
+        } else {
+            // tethering, enterprise and mms with restricted capabilities always honor soft
+            // disallowed reasons and not respected as restricted request
+            if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
+                    || networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
+                    || networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+                return false;
+            }
+            // When the device is on satellite, internet with restricted capabilities always honor
+            // soft disallowed reasons and not respected as restricted request
+            return !(mServiceState.isUsingNonTerrestrialNetwork()
+                    && networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+
+        }
     }
 
     /**
@@ -2300,6 +2394,8 @@
                     return DataNetwork.TEAR_DOWN_REASON_HANDOVER_FAILED;
                 case DATA_LIMIT_REACHED:
                     return DataNetwork.TEAR_DOWN_REASON_DATA_LIMIT_REACHED;
+                case DATA_NETWORK_TRANSPORT_NOT_ALLOWED:
+                    return DataNetwork.TEAR_DOWN_REASON_DATA_NETWORK_TRANSPORT_NOT_ALLOWED;
             }
         }
         return DataNetwork.TEAR_DOWN_REASON_NONE;
@@ -3590,7 +3686,7 @@
             return true;
         }
 
-        if (!oldNri.isNonTerrestrialNetwork() && newNri.isNonTerrestrialNetwork()) {
+        if (oldNri.isNonTerrestrialNetwork() != newNri.isNonTerrestrialNetwork()) {
             return true;
         }
 
@@ -3647,7 +3743,7 @@
             return true;
         }
 
-        if (oldSS.isUsingNonTerrestrialNetwork() && !newSS.isUsingNonTerrestrialNetwork()) {
+        if (oldSS.isUsingNonTerrestrialNetwork() != newSS.isUsingNonTerrestrialNetwork()) {
             return true;
         }
 
@@ -4023,41 +4119,6 @@
     }
 
     /**
-     * Check whether data is disallowed while using satellite
-     * @param capabilities An array of the NetworkCapabilities to be checked
-     * @return {@code true} if the capabilities contain any capability that are restricted
-     * while using satellite else {@code false}
-     */
-    private boolean isDataDisallowedDueToSatellite(@NetCapability int[] capabilities) {
-        if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
-            return false;
-        }
-
-        if (!mServiceState.isUsingNonTerrestrialNetwork()) {
-            // Device is not connected to satellite
-            return false;
-        }
-
-        Set<Integer> restrictedCapabilities = Set.of(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-        if (Arrays.stream(capabilities).noneMatch(restrictedCapabilities::contains)) {
-            // Only internet data disallowed while using satellite
-            return false;
-        }
-
-        for (NetworkRegistrationInfo nri : mServiceState.getNetworkRegistrationInfoList()) {
-            if (nri.isNonTerrestrialNetwork()
-                    && nri.getAvailableServices().contains(
-                            NetworkRegistrationInfo.SERVICE_TYPE_DATA)) {
-                // Data is supported while using satellite
-                return false;
-            }
-        }
-
-        // Data is disallowed while using satellite
-        return true;
-    }
-
-    /**
      * Request network validation.
      *
      * Nnetwork validation request is sent to the DataNetwork that matches the network capability
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index 51fc71b..0da220b 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -899,7 +899,7 @@
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         return getDataProfileForNetworkRequest(networkRequest, networkType,
                 mPhone.getServiceState().isUsingNonTerrestrialNetwork(),
                 mDataNetworkController.isEsimBootStrapProvisioningActivated(),
diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java
index 5933463..1fdc182 100644
--- a/src/java/com/android/internal/telephony/data/DataRetryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java
@@ -1192,7 +1192,7 @@
 
         boolean retryScheduled = false;
         List<NetworkRequestList> groupedNetworkRequestLists =
-                DataUtils.getGroupedNetworkRequestList(requestList);
+                DataUtils.getGroupedNetworkRequestList(requestList, mFlags);
         for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) {
             if (retryRule.isPermanentFailCauseRule() && retryRule.getFailCauses().contains(cause)) {
                 if (dataProfile.getApnSetting() != null) {
diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java
index 0dda7b5..cca6deb 100644
--- a/src/java/com/android/internal/telephony/data/DataUtils.java
+++ b/src/java/com/android/internal/telephony/data/DataUtils.java
@@ -41,6 +41,7 @@
 import android.util.ArrayMap;
 
 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.text.SimpleDateFormat;
@@ -406,35 +407,59 @@
      * Group the network requests into several list that contains the same network capabilities.
      *
      * @param networkRequestList The provided network requests.
+     * @param featureFlags The feature flag.
+     *
      * @return The network requests after grouping.
      */
     public static @NonNull List<NetworkRequestList> getGroupedNetworkRequestList(
-            @NonNull NetworkRequestList networkRequestList) {
-        // Key is the capabilities set.
-        Map<Set<Integer>, NetworkRequestList> requestsMap = new ArrayMap<>();
-        for (TelephonyNetworkRequest networkRequest : networkRequestList) {
-            requestsMap.computeIfAbsent(Arrays.stream(networkRequest.getCapabilities())
-                            .boxed().collect(Collectors.toSet()),
-                    v -> new NetworkRequestList()).add(networkRequest);
-        }
+            @NonNull NetworkRequestList networkRequestList, @NonNull FeatureFlags featureFlags) {
         List<NetworkRequestList> requests = new ArrayList<>();
-        // Create separate groups for enterprise requests with different enterprise IDs.
-        for (NetworkRequestList requestList : requestsMap.values()) {
-            List<TelephonyNetworkRequest> enterpriseRequests = requestList.stream()
-                    .filter(request ->
-                            request.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE))
-                    .collect(Collectors.toList());
-            if (enterpriseRequests.isEmpty()) {
-                requests.add(requestList);
-                continue;
+        if (featureFlags.satelliteInternet()) {
+            record NetworkCapabilitiesKey(Set<Integer> caps, Set<Integer> enterpriseIds,
+                                          Set<Integer> transportTypes) { }
+
+            // Key is the combination of capabilities, enterprise ids, and transport types.
+            Map<NetworkCapabilitiesKey, NetworkRequestList> requestsMap = new ArrayMap<>();
+            for (TelephonyNetworkRequest networkRequest : networkRequestList) {
+                requestsMap.computeIfAbsent(new NetworkCapabilitiesKey(
+                                Arrays.stream(networkRequest.getCapabilities())
+                                        .boxed().collect(Collectors.toSet()),
+                                Arrays.stream(networkRequest.getNativeNetworkRequest()
+                                                .getEnterpriseIds())
+                                        .boxed().collect(Collectors.toSet()),
+                                Arrays.stream(networkRequest.getNativeNetworkRequest()
+                                                .getTransportTypes())
+                                        .boxed().collect(Collectors.toSet())
+                                ),
+                        v -> new NetworkRequestList()).add(networkRequest);
             }
-            // Key is the enterprise ID
-            Map<Integer, NetworkRequestList> enterpriseRequestsMap = new ArrayMap<>();
-            for (TelephonyNetworkRequest request : enterpriseRequests) {
-                enterpriseRequestsMap.computeIfAbsent(request.getCapabilityDifferentiator(),
-                        v -> new NetworkRequestList()).add(request);
+            requests.addAll(requestsMap.values());
+        } else {
+            // Key is the capabilities set.
+            Map<Set<Integer>, NetworkRequestList> requestsMap = new ArrayMap<>();
+            for (TelephonyNetworkRequest networkRequest : networkRequestList) {
+                requestsMap.computeIfAbsent(Arrays.stream(networkRequest.getCapabilities())
+                                .boxed().collect(Collectors.toSet()),
+                        v -> new NetworkRequestList()).add(networkRequest);
             }
-            requests.addAll(enterpriseRequestsMap.values());
+            // Create separate groups for enterprise requests with different enterprise IDs.
+            for (NetworkRequestList requestList : requestsMap.values()) {
+                List<TelephonyNetworkRequest> enterpriseRequests = requestList.stream()
+                        .filter(request -> request.hasCapability(
+                                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE))
+                        .toList();
+                if (enterpriseRequests.isEmpty()) {
+                    requests.add(requestList);
+                    continue;
+                }
+                // Key is the enterprise ID
+                Map<Integer, NetworkRequestList> enterpriseRequestsMap = new ArrayMap<>();
+                for (TelephonyNetworkRequest request : enterpriseRequests) {
+                    enterpriseRequestsMap.computeIfAbsent(request.getCapabilityDifferentiator(),
+                            v -> new NetworkRequestList()).add(request);
+                }
+                requests.addAll(enterpriseRequestsMap.values());
+            }
         }
         // Sort the requests so the network request list with higher priority will be at the front.
         return requests.stream()
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index 92919aa..5c1d0e1 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.telephony.data;
 
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG;
 import static android.telephony.SubscriptionManager.DEFAULT_PHONE_INDEX;
 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
@@ -334,7 +333,7 @@
         @Override
         public void onCapabilitiesChanged(Network network,
                 NetworkCapabilities networkCapabilities) {
-            if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                 if (SubscriptionManager.isValidSubscriptionId(mExpectedSubId)
                         && mExpectedSubId == getSubIdFromNetworkSpecifier(
                         networkCapabilities.getNetworkSpecifier())) {
@@ -569,7 +568,7 @@
         mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
 
         final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder()
-                .addTransportType(TRANSPORT_CELLULAR)
+                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
@@ -594,6 +593,15 @@
                 .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_5)
                 .setNetworkSpecifier(new MatchAllNetworkSpecifier());
 
+        if (mFlags.satelliteInternet()) {
+            // TODO: b/328622096 remove the try/catch
+            try {
+                builder.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+            } catch (IllegalArgumentException exception) {
+                loge("TRANSPORT_SATELLITE is not supported.");
+            }
+        }
+
         NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
                 builder.build(), this);
         // we want to see all requests
@@ -987,7 +995,7 @@
 
     private void onRequestNetwork(NetworkRequest networkRequest) {
         TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest(
-                networkRequest, PhoneFactory.getDefaultPhone());
+                networkRequest, PhoneFactory.getDefaultPhone(), mFlags);
         if (!mNetworkRequestList.contains(telephonyNetworkRequest)) {
             mNetworkRequestList.add(telephonyNetworkRequest);
             onEvaluate(REQUESTS_CHANGED, "netRequest");
@@ -996,7 +1004,7 @@
 
     private void onReleaseNetwork(NetworkRequest networkRequest) {
         TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest(
-                networkRequest, PhoneFactory.getDefaultPhone());
+                networkRequest, PhoneFactory.getDefaultPhone(), mFlags);
         if (mNetworkRequestList.remove(telephonyNetworkRequest)) {
             onEvaluate(REQUESTS_CHANGED, "netReleased");
             collectReleaseNetworkMetrics(networkRequest);
diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
index 377c219..877d7b8 100644
--- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java
@@ -163,6 +163,16 @@
                 .addEnterpriseId(NetworkCapabilities.NET_ENTERPRISE_ID_5)
                 .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
                 .setSubscriptionId(subscriptionId).build());
+
+        if (mFlags.satelliteInternet()) {
+            // TODO: b/328622096 remove the try/catch
+            try {
+                builder.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+            } catch (IllegalArgumentException exception) {
+                log("TRANSPORT_SATELLITE is not supported.");
+            }
+        }
+
         return builder.build();
     }
 
@@ -263,7 +273,7 @@
 
     private void onNeedNetworkFor(Message msg) {
         TelephonyNetworkRequest networkRequest =
-                new TelephonyNetworkRequest((NetworkRequest) msg.obj, mPhone);
+                new TelephonyNetworkRequest((NetworkRequest) msg.obj, mPhone, mFlags);
         boolean shouldApply = mPhoneSwitcher.shouldApplyNetworkRequest(
                 networkRequest, mPhone.getPhoneId());
 
@@ -289,7 +299,7 @@
 
     private void onReleaseNetworkFor(Message msg) {
         TelephonyNetworkRequest networkRequest =
-                new TelephonyNetworkRequest((NetworkRequest) msg.obj, mPhone);
+                new TelephonyNetworkRequest((NetworkRequest) msg.obj, mPhone, mFlags);
         boolean applied = mNetworkRequests.get(networkRequest)
                 != AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
 
diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
index 2668302..b059100 100644
--- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
+++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
@@ -31,6 +31,7 @@
 import android.telephony.data.TrafficDescriptor.OsAppId;
 
 import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -182,15 +183,21 @@
     /** The data evaluation result. */
     private @Nullable DataEvaluation mEvaluation;
 
+    /** Feature flag. */
+    private final @NonNull FeatureFlags mFeatureFlags;
+
     /**
      * Constructor
      *
      * @param request The native network request from the clients.
      * @param phone The phone instance
+     * @param featureFlags The feature flag
      */
-    public TelephonyNetworkRequest(NetworkRequest request, Phone phone) {
+    public TelephonyNetworkRequest(@NonNull NetworkRequest request, @NonNull Phone phone,
+                                   @NonNull FeatureFlags featureFlags) {
         mPhone = phone;
         mNativeNetworkRequest = request;
+        mFeatureFlags = featureFlags;
 
         int capabilitiesAttributes = CAPABILITY_ATTRIBUTE_NONE;
         for (int networkCapability : mNativeNetworkRequest.getCapabilities()) {
@@ -274,6 +281,31 @@
         if ((hasAttribute(CAPABILITY_ATTRIBUTE_APN_SETTING)
                 || hasAttribute(CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN))
                 && dataProfile.getApnSetting() != null) {
+            if (mFeatureFlags.satelliteInternet()) {
+                if (mNativeNetworkRequest.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
+                        && !mNativeNetworkRequest.hasTransport(
+                                NetworkCapabilities.TRANSPORT_SATELLITE)) {
+                    if (Arrays.stream(getCapabilities()).noneMatch(mDataConfigManager
+                            .getForcedCellularTransportCapabilities()::contains)) {
+                        // If the request is explicitly for the cellular, then the data profile
+                        // needs to support cellular.
+                        if (!dataProfile.getApnSetting().isForInfrastructure(
+                                ApnSetting.INFRASTRUCTURE_CELLULAR)) {
+                            return false;
+                        }
+                    }
+                } else if (mNativeNetworkRequest.hasTransport(
+                        NetworkCapabilities.TRANSPORT_SATELLITE)
+                        && !mNativeNetworkRequest.hasTransport(
+                                NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                    // If the request is explicitly for the satellite, then the data profile needs
+                    // to support satellite.
+                    if (!dataProfile.getApnSetting().isForInfrastructure(
+                            ApnSetting.INFRASTRUCTURE_SATELLITE)) {
+                        return false;
+                    }
+                }
+            }
             // Fallback to the legacy APN type matching.
             List<Integer> apnTypes = Arrays.stream(getCapabilities()).boxed()
                     .map(DataUtils::networkCapabilityToApnType)
diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
index e3eed00..fddeb06 100644
--- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
@@ -35,7 +35,9 @@
 import android.telephony.DomainSelector;
 import android.telephony.EmergencyRegistrationResult;
 import android.telephony.NetworkRegistrationInfo;
+import android.telephony.PreciseDisconnectCause;
 import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsReasonInfo;
 import android.util.LocalLog;
 import android.util.Log;
 
@@ -351,6 +353,10 @@
 
     private boolean mIsTestMode = false;
 
+    private int mDisconnectCause = DisconnectCause.NOT_VALID;
+    private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
+    private String mReasonMessage = null;
+
     /**
      * Creates an instance.
      *
@@ -789,6 +795,51 @@
     }
 
     /**
+     * Save call disconnect info for error propagation.
+     * @param disconnectCause The code for the reason for the disconnect.
+     * @param preciseDisconnectCause The code for the precise reason for the disconnect.
+     * @param reasonMessage Description of the reason for the disconnect, not intended for the user
+     *                      to see.
+     */
+    public void setDisconnectCause(int disconnectCause, int preciseDisconnectCause,
+                                String reasonMessage) {
+        mDisconnectCause = disconnectCause;
+        mPreciseDisconnectCause = preciseDisconnectCause;
+        mReasonMessage = reasonMessage;
+    }
+
+    public int getDisconnectCause() {
+        return mDisconnectCause;
+    }
+
+    public int getPreciseDisconnectCause() {
+        return mPreciseDisconnectCause;
+    }
+
+    public String getReasonMessage() {
+        return mReasonMessage;
+    }
+
+    /**
+     * @return imsReasonInfo Reason for the IMS call failure.
+     */
+    public @Nullable ImsReasonInfo getImsReasonInfo() {
+        if (getSelectionAttributes() == null) {
+            // Neither selectDomain(...) nor reselectDomain(...) has been called yet.
+            return null;
+        }
+
+        return getSelectionAttributes().getPsDisconnectCause();
+    }
+
+    /**
+     * @return phoneId To support localized message based on phoneId
+     */
+    public int getPhoneId() {
+        return getPhone().getPhoneId();
+    }
+
+    /**
      * Dumps local log.
      */
     public void dump(@NonNull PrintWriter printWriter) {
diff --git a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java
index 0fd9201..095d61f 100644
--- a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java
@@ -24,11 +24,9 @@
 import android.telecom.PhoneAccount;
 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
 import android.telephony.Annotation.DisconnectCauses;
-import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService;
 import android.telephony.DomainSelectionService.EmergencyScanType;
 import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PreciseDisconnectCause;
 import android.telephony.ims.ImsReasonInfo;
 
 import com.android.internal.telephony.Phone;
@@ -41,9 +39,6 @@
 public class NormalCallDomainSelectionConnection extends DomainSelectionConnection {
 
     private static final boolean DBG = false;
-    private int mDisconnectCause = DisconnectCause.NOT_VALID;
-    private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
-    private String mReasonMessage = null;
 
     private @Nullable DomainSelectionConnectionCallback mCallback;
 
@@ -130,49 +125,4 @@
         }
         return builder.build();
     }
-
-    /**
-     * Save call disconnect info for error propagation.
-     * @param disconnectCause The code for the reason for the disconnect.
-     * @param preciseDisconnectCause The code for the precise reason for the disconnect.
-     * @param reasonMessage Description of the reason for the disconnect, not intended for the user
-     *                      to see.
-     */
-    public void setDisconnectCause(int disconnectCause, int preciseDisconnectCause,
-                                String reasonMessage) {
-        mDisconnectCause = disconnectCause;
-        mPreciseDisconnectCause = preciseDisconnectCause;
-        mReasonMessage = reasonMessage;
-    }
-
-    public int getDisconnectCause() {
-        return mDisconnectCause;
-    }
-
-    public int getPreciseDisconnectCause() {
-        return mPreciseDisconnectCause;
-    }
-
-    public String getReasonMessage() {
-        return mReasonMessage;
-    }
-
-    /**
-     * @return imsReasonInfo Reason for the IMS call failure.
-     */
-    public @Nullable ImsReasonInfo getImsReasonInfo() {
-        if (getSelectionAttributes() == null) {
-            // Neither selectDomain(...) nor reselectDomain(...) has been called yet.
-            return null;
-        }
-
-        return getSelectionAttributes().getPsDisconnectCause();
-    }
-
-    /**
-     * @return phoneId To support localized message based on phoneId
-     */
-    public int getPhoneId() {
-        return getPhone().getPhoneId();
-    }
 }
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index 1c8b696..b7c3255 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -354,11 +354,26 @@
                             mOnEcmExitCompleteRunnable.run();
                             mOnEcmExitCompleteRunnable = null;
                         }
+                        if (mPhone != null && mEmergencyMode == MODE_EMERGENCY_WWAN) {
+                            // In cross sim redialing.
+                            setEmergencyModeInProgress(true);
+                            mWasEmergencyModeSetOnModem = true;
+                            mPhone.setEmergencyMode(MODE_EMERGENCY_WWAN,
+                                    mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE,
+                                    Integer.valueOf(EMERGENCY_TYPE_CALL)));
+                        }
                     } else if (emergencyType == EMERGENCY_TYPE_SMS) {
                         if (mIsEmergencyCallStartedDuringEmergencySms) {
                             mIsEmergencyCallStartedDuringEmergencySms = false;
                             turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL,
                                     mIsTestEmergencyNumber);
+                        } else if (mPhone != null && mEmergencyMode == MODE_EMERGENCY_WWAN) {
+                            // Starting emergency call while exiting emergency mode
+                            setEmergencyModeInProgress(true);
+                            mWasEmergencyModeSetOnModem = true;
+                            mPhone.setEmergencyMode(MODE_EMERGENCY_WWAN,
+                                    mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE,
+                                    Integer.valueOf(EMERGENCY_TYPE_CALL)));
                         } else if (mIsEmergencySmsStartedDuringScbm) {
                             mIsEmergencySmsStartedDuringScbm = false;
                             setEmergencyMode(mSmsPhone, emergencyType,
@@ -713,6 +728,16 @@
             maybeNotifyTransportChangeCompleted(emergencyType, false);
             return;
         }
+
+        if (emergencyType == EMERGENCY_TYPE_CALL
+                && mode == MODE_EMERGENCY_WWAN
+                && isEmergencyModeInProgress() && !isInEmergencyMode()) {
+            // In cross sim redialing or ending emergency SMS, exitEmergencyMode is not completed.
+            mEmergencyMode = mode;
+            Rlog.i(TAG, "setEmergencyMode wait for the completion of exitEmergencyMode");
+            return;
+        }
+
         mEmergencyMode = mode;
         setEmergencyModeInProgress(true);
 
@@ -1210,6 +1235,15 @@
                 && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm();
     }
 
+    /**
+     * Returns {@code true} if currently in emergency callback mode with the given {@link Phone}.
+     *
+     * @param phone the {@link Phone} for the emergency call.
+     */
+    public boolean isInEcm(Phone phone) {
+        return isInEcm() && isSamePhone(mPhone, phone);
+    }
+
     private void sendEmergencyCallStateChange(Phone phone, boolean isAlive) {
         if ((isAlive && !mSentEmergencyCallState && getBroadcastEmergencyCallStateChanges(phone))
                 || (!isAlive && mSentEmergencyCallState)) {
@@ -1521,6 +1555,11 @@
 
                 @Override
                 public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
+                    if (!Objects.equals(mOngoingConnection, expectedConnection)) {
+                        Rlog.i(TAG, "isOkToCall "
+                                + expectedConnection.getTelecomCallId() + " canceled.");
+                        return true;
+                    }
                     // Wait for normal service state or timeout if required.
                     if (phone == phoneForEmergency
                             && waitForInServiceTimeout > 0
@@ -1533,6 +1572,11 @@
 
                 @Override
                 public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
+                    if (!Objects.equals(mOngoingConnection, expectedConnection)) {
+                        Rlog.i(TAG, "onTimeout "
+                                + expectedConnection.getTelecomCallId() + " canceled.");
+                        return true;
+                    }
                     // onTimeout shall be called only with the Phone for emergency
                     return phone.getServiceStateTracker().isRadioOn()
                             && !satelliteController.isSatelliteEnabled();
diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java
index 384112d..306f6bb 100644
--- a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java
+++ b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java
@@ -153,7 +153,7 @@
     private void powerOffSatellite(Phone phoneForEmergencyCall) {
         SatelliteController satelliteController = SatelliteController.getInstance();
         satelliteController.requestSatelliteEnabled(phoneForEmergencyCall.getSubId(),
-                false /* enableSatellite */, false /* enableDemoMode */,
+                false /* enableSatellite */, false /* enableDemoMode */, false /* isEmergency */,
                 new IIntegerConsumer.Stub() {
                     @Override
                     public void accept(int result) {
diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java
index 5949f66..fa0610a 100644
--- a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java
+++ b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java
@@ -395,6 +395,7 @@
                 if (mSatelliteController.isSatelliteEnabled()) {
                     mSatelliteController.requestSatelliteEnabled(mPhone.getSubId(),
                             false /* enableSatellite */, false /* enableDemoMode */,
+                            false /* isEmergency*/,
                             new IIntegerConsumer.Stub() {
                                 @Override
                                 public void accept(int result) {
diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
index e1f6309..2eadf17 100644
--- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java
@@ -41,6 +41,7 @@
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.data.DataNetwork;
 import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.subscription.SubscriptionInfoInternal;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 import com.android.telephony.Rlog;
@@ -64,10 +65,12 @@
     public static final int SIZE_LIMIT_HANDOVER_FAILURES = 15;
 
     private final DefaultNetworkMonitor mDefaultNetworkMonitor;
+    private final SatelliteController mSatelliteController;
 
     public DataCallSessionStats(Phone phone) {
         mPhone = phone;
         mDefaultNetworkMonitor = PhoneFactory.getMetricsCollector().getDefaultNetworkMonitor();
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     private boolean isSystemDefaultNetworkMobile() {
@@ -303,6 +306,7 @@
                 call.handoverFailureRat.length);
         copy.isNonDds = call.isNonDds;
         copy.isIwlanCrossSim = call.isIwlanCrossSim;
+        copy.isNtn = call.isNtn;
         return copy;
     }
 
@@ -329,6 +333,8 @@
         proto.handoverFailureRat = new int[0];
         proto.isNonDds = false;
         proto.isIwlanCrossSim = false;
+        proto.isNtn = mSatelliteController != null
+                ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
         return proto;
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 456b91b..fbdf909 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -972,7 +972,8 @@
                 state.foldState,
                 state.overrideVoiceService,
                 state.isDataEnabled,
-                state.isIwlanCrossSim);
+                state.isIwlanCrossSim,
+                state.isNtn);
     }
 
     private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
@@ -1030,7 +1031,8 @@
                 session.isIwlanCrossSimAtStart,
                 session.isIwlanCrossSimAtEnd,
                 session.isIwlanCrossSimAtConnected,
-                session.vonrEnabled);
+                session.vonrEnabled,
+                session.isNtn);
 
     }
 
@@ -1107,7 +1109,8 @@
                 dataCallSession.handoverFailureCauses,
                 dataCallSession.handoverFailureRat,
                 dataCallSession.isNonDds,
-                dataCallSession.isIwlanCrossSim);
+                dataCallSession.isIwlanCrossSim,
+                dataCallSession.isNtn);
     }
 
     private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index f3fe8fa..64b9bda 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -1715,7 +1715,8 @@
                     && state.foldState == key.foldState
                     && state.overrideVoiceService == key.overrideVoiceService
                     && state.isDataEnabled == key.isDataEnabled
-                    && state.isIwlanCrossSim == key.isIwlanCrossSim) {
+                    && state.isIwlanCrossSim == key.isIwlanCrossSim
+                    && state.isNtn == key.isNtn) {
                 return state;
             }
         }
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index d400c22..ff90978 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -44,6 +44,7 @@
 import com.android.internal.telephony.imsphone.ImsPhone;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.telephony.Rlog;
 
 import java.util.Set;
@@ -61,12 +62,14 @@
     private final PersistAtomsStorage mStorage;
     private final DeviceStateHelper mDeviceStateHelper;
     private boolean mExistAnyConnectedInternetPdn;
+    private final SatelliteController mSatelliteController;
 
     public ServiceStateStats(Phone phone) {
         super(Runnable::run);
         mPhone = phone;
         mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage();
         mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper();
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     /** Finalizes the durations of the current service state segment. */
@@ -135,6 +138,8 @@
             newState.overrideVoiceService = mOverrideVoiceService.get();
             newState.isDataEnabled = mPhone.getDataSettingsManager().isDataEnabled();
             newState.isIwlanCrossSim = isCrossSimCallingRegistered(mPhone);
+            newState.isNtn = mSatelliteController != null
+                    ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
             TimestampedServiceState prevState =
                     mLastState.getAndSet(new TimestampedServiceState(newState, now));
             addServiceStateAndSwitch(
@@ -306,6 +311,7 @@
         copy.overrideVoiceService = state.overrideVoiceService;
         copy.isDataEnabled = state.isDataEnabled;
         copy.isIwlanCrossSim = state.isIwlanCrossSim;
+        copy.isNtn = state.isNtn;
         return copy;
     }
 
diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
index 9cf53c9..8be9e83 100644
--- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
@@ -75,6 +75,7 @@
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.AudioCodec;
+import com.android.internal.telephony.satellite.SatelliteController;
 import com.android.internal.telephony.uicc.UiccController;
 import com.android.telephony.Rlog;
 
@@ -171,11 +172,14 @@
     private final VonrHelper mVonrHelper =
             PhoneFactory.getMetricsCollector().getVonrHelper();
 
+    private final SatelliteController mSatelliteController;
+
     public VoiceCallSessionStats(int phoneId, Phone phone, @NonNull FeatureFlags featureFlags) {
         mPhoneId = phoneId;
         mPhone = phone;
         mFlags = featureFlags;
         DataConnectionStateTracker.getInstance(phoneId).start(phone);
+        mSatelliteController = SatelliteController.getInstance();
     }
 
     /* CS calls */
@@ -570,6 +574,9 @@
             proto.vonrEnabled = mVonrHelper.getVonrEnabled(mPhone.getSubId());
         }
 
+        proto.isNtn = mSatelliteController != null
+                ? mSatelliteController.isInSatelliteModeForCarrierRoaming(mPhone) : false;
+
         mAtomsStorage.addVoiceCallSession(proto);
 
         // merge RAT usages to PersistPullers when the call session ends (i.e. no more active calls)
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index 6783e38..d4e97db 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -16,10 +16,14 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_IDLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -71,8 +75,10 @@
     @GuardedBy("mLock")
     private int mSendSubId;
     @GuardedBy("mLock")
+    private @SatelliteManager.DatagramType int mDatagramType = DATAGRAM_TYPE_UNKNOWN;
+    @GuardedBy("mLock")
     private @SatelliteManager.SatelliteDatagramTransferState int mSendDatagramTransferState =
-            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
+            SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
     @GuardedBy("mLock")
     private int mSendPendingCount = 0;
     @GuardedBy("mLock")
@@ -82,7 +88,7 @@
     private int mReceiveSubId;
     @GuardedBy("mLock")
     private @SatelliteManager.SatelliteDatagramTransferState int mReceiveDatagramTransferState =
-            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
+            SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
     @GuardedBy("mLock")
     private int mReceivePendingCount = 0;
     @GuardedBy("mLock")
@@ -132,7 +138,7 @@
      *                              about datagram transfer state changes.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected DatagramController(@NonNull Context context, @NonNull Looper  looper,
+    public DatagramController(@NonNull Context context, @NonNull Looper  looper,
             @NonNull PointingAppController pointingAppController) {
         mContext = context;
         mPointingAppController = pointingAppController;
@@ -188,6 +194,7 @@
      * @param callback The callback to get {@link SatelliteManager.SatelliteResult} of the request.
      */
     public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer<Integer> callback) {
+        logd("pollPendingSatelliteDatagrams");
         mDatagramReceiver.pollPendingSatelliteDatagrams(subId, callback);
     }
 
@@ -213,7 +220,6 @@
     public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull Consumer<Integer> callback) {
-        pushDemoModeDatagram(datagramType, datagram);
         mDatagramDispatcher.sendSatelliteDatagram(subId, datagramType, datagram,
                 needFullScreenPointingUI, callback);
     }
@@ -226,23 +232,25 @@
      * @param sendPendingCount number of datagrams that are currently being sent
      * @param errorCode If datagram transfer failed, the reason for failure.
      */
-    public void updateSendStatus(int subId,
+    public void updateSendStatus(int subId, @SatelliteManager.DatagramType int datagramType,
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int sendPendingCount, int errorCode) {
         synchronized (mLock) {
             logd("updateSendStatus"
                     + " subId: " + subId
+                    + " datagramType: " + datagramType
                     + " datagramTransferState: " + datagramTransferState
                     + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode);
 
             mSendSubId = subId;
+            mDatagramType = datagramType;
             mSendDatagramTransferState = datagramTransferState;
             mSendPendingCount = sendPendingCount;
             mSendErrorCode = errorCode;
-
             notifyDatagramTransferStateChangedToSessionController();
-            mPointingAppController.updateSendDatagramTransferState(mSendSubId,
+            mPointingAppController.updateSendDatagramTransferState(mSendSubId, mDatagramType,
                     mSendDatagramTransferState, mSendPendingCount, mSendErrorCode);
+            retryPollPendingDatagramsInDemoMode();
         }
     }
 
@@ -271,6 +279,7 @@
             notifyDatagramTransferStateChangedToSessionController();
             mPointingAppController.updateReceiveDatagramTransferState(mReceiveSubId,
                     mReceiveDatagramTransferState, mReceivePendingCount, mReceiveErrorCode);
+            retryPollPendingDatagramsInDemoMode();
         }
 
         if (isPollingInIdleState()) {
@@ -300,9 +309,16 @@
         mDatagramReceiver.onSatelliteModemStateChanged(state);
     }
 
-    void setDeviceAlignedWithSatellite(boolean isAligned) {
+    /**
+     * Set whether the device is aligned with the satellite.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public void setDeviceAlignedWithSatellite(boolean isAligned) {
         mDatagramDispatcher.setDeviceAlignedWithSatellite(isAligned);
         mDatagramReceiver.setDeviceAlignedWithSatellite(isAligned);
+        if (isAligned) {
+            retryPollPendingDatagramsInDemoMode();
+        }
     }
 
     @VisibleForTesting
@@ -332,14 +348,14 @@
     public boolean isSendingInIdleState() {
         synchronized (mLock) {
             return (mSendDatagramTransferState
-                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         }
     }
 
     public boolean isPollingInIdleState() {
         synchronized (mLock) {
             return (mReceiveDatagramTransferState
-                    == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+                    == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
         }
     }
 
@@ -380,8 +396,8 @@
      * @param datagramType datagram type, only DATAGRAM_TYPE_SOS_MESSAGE will be saved
      * @param datagram datagram The last datagram saved when sendSatelliteDatagramForDemo is called
      */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    protected void pushDemoModeDatagram(@SatelliteManager.DatagramType int datagramType,
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public void pushDemoModeDatagram(@SatelliteManager.DatagramType int datagramType,
             SatelliteDatagram datagram) {
         if (mIsDemoMode && datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) {
             synchronized (mLock) {
@@ -484,6 +500,23 @@
         mDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
     }
 
+    private void retryPollPendingDatagramsInDemoMode() {
+        synchronized (mLock) {
+            if (mIsDemoMode && isSendingInIdleState() && isPollingInIdleState()
+                    && !mDemoModeDatagramList.isEmpty()) {
+                Consumer<Integer> internalCallback = new Consumer<Integer>() {
+                    @Override
+                    public void accept(Integer result) {
+                        if (result != SATELLITE_RESULT_SUCCESS) {
+                            logd("retryPollPendingDatagramsInDemoMode result: " + result);
+                        }
+                    }
+                };
+                pollPendingSatelliteDatagrams(DEFAULT_SUBSCRIPTION_ID, internalCallback);
+            }
+        }
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index 83caf2e..2d052b6 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -16,8 +16,10 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
@@ -62,7 +64,7 @@
     private static final int EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT = 4;
     private static final int EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT = 5;
     private static final int EVENT_ABORT_SENDING_SATELLITE_DATAGRAMS_DONE = 6;
-    private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 7;
+    private static final int EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT = 7;
     private static final Long TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE = TimeUnit.SECONDS.toMillis(10);
     @NonNull private static DatagramDispatcher sInstance;
     @NonNull private final Context mContext;
@@ -100,6 +102,8 @@
             mPendingNonEmergencyDatagramsMap = new LinkedHashMap<>();
 
     private long mWaitTimeForDatagramSendingResponse;
+    @SatelliteManager.DatagramType
+    private int mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
 
     /**
      * Create the DatagramDispatcher singleton instance.
@@ -238,7 +242,8 @@
                             break;
                         }
                     }
-                    logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error);
+                    logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error
+                            + ", mIsDemoMode=" + mIsDemoMode);
 
                     /*
                      * The response should be ignored if either of the following hold
@@ -266,16 +271,12 @@
 
                     if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
                         // Update send status for current datagram
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
                                 getPendingDatagramCount(), error);
                         mControllerMetricsStats.reportOutgoingDatagramSuccessCount(
                                 argument.datagramType);
-                        if (mIsDemoMode) {
-                            sendMessageDelayed(
-                                    obtainMessage(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, request),
-                                    getDemoTimeoutDuration());
-                        }
+                        startWaitForSimulatedPollDatagramsDelayTimer(request);
                         if (getPendingDatagramCount() > 0) {
                             // Send response for current datagram
                             argument.callback.accept(error);
@@ -283,17 +284,18 @@
                             sendPendingDatagrams();
                         } else {
                             mDatagramController.updateSendStatus(argument.subId,
-                                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                                    0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                                    argument.datagramType,
+                                    SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
+                                    SatelliteManager.SATELLITE_RESULT_SUCCESS);
                             // Send response for current datagram
                             argument.callback.accept(error);
                         }
                     } else {
                         // Update send status
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                                 getPendingDatagramCount(), error);
-                        mDatagramController.updateSendStatus(argument.subId,
+                        mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                                 0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
                         // Send response for current datagram
@@ -320,16 +322,14 @@
             }
 
             case EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT:
-                handleEventDatagramWaitForConnectedStateTimedOut();
+                handleEventDatagramWaitForConnectedStateTimedOut(
+                        (SendSatelliteDatagramArgument) msg.obj);
                 break;
 
-            case CMD_POLL_PENDING_SATELLITE_DATAGRAMS:
-                if (mIsDemoMode) {
-                    request = (DatagramDispatcherHandlerRequest) msg.obj;
-                    SendSatelliteDatagramArgument argument =
-                            (SendSatelliteDatagramArgument) request.argument;
-                    pollPendingSatelliteDatagrams(argument.subId);
-                }
+            case EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT:
+                request = (DatagramDispatcherHandlerRequest) msg.obj;
+                handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
+                        (SendSatelliteDatagramArgument) request.argument);
                 break;
 
             default:
@@ -361,10 +361,10 @@
 
         long datagramId = mNextDatagramId.getAndUpdate(
                 n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID));
-
         SendSatelliteDatagramArgument datagramArgs =
                 new SendSatelliteDatagramArgument(subId, datagramId, datagramType, datagram,
                         needFullScreenPointingUI, callback);
+        mLastSendRequestDatagramType = datagramType;
 
         synchronized (mLock) {
             // Add datagram to pending datagram map
@@ -376,16 +376,16 @@
 
             if (mDatagramController.needsWaitingForSatelliteConnected()) {
                 logd("sendDatagram: wait for satellite connected");
-                mDatagramController.updateSendStatus(subId,
+                mDatagramController.updateSendStatus(subId, datagramType,
                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT,
                         getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
-                startDatagramWaitForConnectedStateTimer();
+                startDatagramWaitForConnectedStateTimer(datagramArgs);
             } else if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) {
                 // Modem can be busy receiving datagrams, so send datagram only when modem is
                 // not busy.
                 mSendingDatagramInProgress = true;
                 datagramArgs.setDatagramStartTime();
-                mDatagramController.updateSendStatus(subId,
+                mDatagramController.updateSendStatus(subId, datagramType,
                         SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
                         getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
                 sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone);
@@ -413,8 +413,11 @@
         logd("setDemoMode: mIsDemoMode=" + mIsDemoMode);
     }
 
+    /**
+     * Set whether the device is aligned with the satellite.
+     */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    protected void setDeviceAlignedWithSatellite(boolean isAligned) {
+    public void setDeviceAlignedWithSatellite(boolean isAligned) {
         synchronized (mLock) {
             mIsAligned = isAligned;
             logd("setDeviceAlignedWithSatellite: " + mIsAligned);
@@ -464,7 +467,7 @@
         mSendSatelliteDatagramRequest = null;
         SatelliteManager.SatelliteException exception =
                 new SatelliteManager.SatelliteException(
-                        SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+                        SATELLITE_RESULT_NOT_REACHABLE);
         Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
         AsyncResult.forMessage(message, null, exception);
         message.sendToTarget();
@@ -510,7 +513,7 @@
                     pendingDatagram.iterator().next().getValue();
             // Sets the trigger time for getting pending datagrams
             datagramArg.setDatagramStartTime();
-            mDatagramController.updateSendStatus(datagramArg.subId,
+            mDatagramController.updateSendStatus(datagramArg.subId, datagramArg.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING,
                     getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_SUCCESS);
             sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone);
@@ -632,12 +635,13 @@
         logd("cleanUpResources");
         mSendingDatagramInProgress = false;
         if (getPendingDatagramCount() > 0) {
-            mDatagramController.updateSendStatus(
-                    SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+            mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    mLastSendRequestDatagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(), SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED);
         }
         mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                mLastSendRequestDatagramType,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                 0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
         abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
@@ -646,18 +650,21 @@
         stopSatelliteAlignedTimer();
         stopDatagramWaitForConnectedStateTimer();
         stopWaitForDatagramSendingResponseTimer();
+        stopWaitForSimulatedPollDatagramsDelayTimer();
         mIsDemoMode = false;
         mSendSatelliteDatagramRequest = null;
         mIsAligned = false;
+        mLastSendRequestDatagramType = DATAGRAM_TYPE_UNKNOWN;
     }
 
-    private void startDatagramWaitForConnectedStateTimer() {
+    private void startDatagramWaitForConnectedStateTimer(
+            @NonNull SendSatelliteDatagramArgument datagramArgs) {
         if (isDatagramWaitForConnectedStateTimerStarted()) {
             logd("DatagramWaitForConnectedStateTimer is already started");
             return;
         }
         sendMessageDelayed(obtainMessage(
-                        EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT),
+                        EVENT_DATAGRAM_WAIT_FOR_CONNECTED_STATE_TIMED_OUT, datagramArgs),
                 mDatagramController.getDatagramWaitTimeForConnectedState());
     }
 
@@ -696,19 +703,22 @@
         removeMessages(EVENT_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMED_OUT);
     }
 
-    private void handleEventDatagramWaitForConnectedStateTimedOut() {
+    private void handleEventDatagramWaitForConnectedStateTimedOut(
+            @NonNull SendSatelliteDatagramArgument argument) {
         logw("Timed out to wait for satellite connected before sending datagrams");
         synchronized (mLock) {
             // Update send status
             mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(),
-                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+                    SATELLITE_RESULT_NOT_REACHABLE);
             mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                    argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
             abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                    SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
+                    SATELLITE_RESULT_NOT_REACHABLE);
         }
     }
 
@@ -758,10 +768,10 @@
             mSendingDatagramInProgress = false;
 
             // Update send status
-            mDatagramController.updateSendStatus(argument.subId,
+            mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
                     getPendingDatagramCount(), SATELLITE_RESULT_MODEM_TIMEOUT);
-            mDatagramController.updateSendStatus(argument.subId,
+            mDatagramController.updateSendStatus(argument.subId, argument.datagramType,
                     SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
                     0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
 
@@ -811,15 +821,38 @@
         }
     }
 
-    private void pollPendingSatelliteDatagrams(int subId) {
-        logd("pollPendingSatelliteDatagrams");
-        Consumer<Integer> internalCallback = new Consumer<Integer>() {
-            @Override
-            public void accept(Integer result) {
-                logd("pollPendingSatelliteDatagrams result: " + result);
-            }
-        };
-        mDatagramController.pollPendingSatelliteDatagrams(subId, internalCallback);
+    private void startWaitForSimulatedPollDatagramsDelayTimer(
+            @NonNull DatagramDispatcherHandlerRequest request) {
+        if (mIsDemoMode) {
+            logd("startWaitForSimulatedPollDatagramsDelayTimer");
+            sendMessageDelayed(
+                    obtainMessage(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT, request),
+                    getDemoTimeoutDuration());
+        } else {
+            logd("Should not start WaitForSimulatedPollDatagramsDelayTimer in non-demo mode");
+        }
+    }
+
+    private void stopWaitForSimulatedPollDatagramsDelayTimer() {
+        removeMessages(EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT);
+    }
+
+    private void handleEventWaitForSimulatedPollDatagramsDelayTimedOut(
+            @NonNull SendSatelliteDatagramArgument argument) {
+        if (mIsDemoMode) {
+            logd("handleEventWaitForSimulatedPollDatagramsDelayTimedOut");
+            mDatagramController.pushDemoModeDatagram(argument.datagramType, argument.datagram);
+            Consumer<Integer> internalCallback = new Consumer<Integer>() {
+                @Override
+                public void accept(Integer result) {
+                    logd("pollPendingSatelliteDatagrams result: " + result);
+                }
+            };
+            mDatagramController.pollPendingSatelliteDatagrams(argument.subId, internalCallback);
+        } else {
+            logd("Unexpected EVENT_WAIT_FOR_SIMULATED_POLL_DATAGRAMS_DELAY_TIMED_OUT in "
+                    + "non-demo mode");
+        }
     }
 
     long getDemoTimeoutDuration() {
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index 6c52a8c..a4b1193 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -743,7 +743,7 @@
     }
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    protected void setDeviceAlignedWithSatellite(boolean isAligned) {
+    public void setDeviceAlignedWithSatellite(boolean isAligned) {
         synchronized (mLock) {
             mIsAligned = isAligned;
             logd("setDeviceAlignedWithSatellite: " + mIsAligned);
diff --git a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
index add01c0..65a25ea 100644
--- a/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
+++ b/src/java/com/android/internal/telephony/satellite/NtnCapabilityResolver.java
@@ -39,9 +39,13 @@
      */
     public static void resolveNtnCapability(
             @NonNull NetworkRegistrationInfo networkRegistrationInfo, int subId) {
+        String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn();
+        if (TextUtils.isEmpty(registeredPlmn)) {
+            return;
+        }
+
         SatelliteController satelliteController = SatelliteController.getInstance();
         List<String> satellitePlmnList = satelliteController.getSatellitePlmnsForCarrier(subId);
-        String registeredPlmn = networkRegistrationInfo.getRegisteredPlmn();
         for (String satellitePlmn : satellitePlmnList) {
             if (TextUtils.equals(satellitePlmn, registeredPlmn)) {
                 logd("Registered to satellite PLMN " + satellitePlmn);
diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
index 878ee96..5e79a06 100644
--- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java
+++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
@@ -160,12 +160,14 @@
     }
 
     private static final class DatagramTransferStateHandlerRequest {
+        public int datagramType;
         public int datagramTransferState;
         public int pendingCount;
         public int errorCode;
 
-        DatagramTransferStateHandlerRequest(int datagramTransferState, int pendingCount,
-                int errorCode) {
+        DatagramTransferStateHandlerRequest(int datagramType, int datagramTransferState,
+                int pendingCount, int errorCode) {
+            this.datagramType = datagramType;
             this.datagramTransferState = datagramTransferState;
             this.pendingCount = pendingCount;
             this.errorCode = errorCode;
@@ -232,8 +234,9 @@
                     List<IBinder> toBeRemoved = new ArrayList<>();
                     mListeners.values().forEach(listener -> {
                         try {
-                            listener.onSendDatagramStateChanged(request.datagramTransferState,
-                                    request.pendingCount, request.errorCode);
+                            listener.onSendDatagramStateChanged(request.datagramType,
+                                    request.datagramTransferState, request.pendingCount,
+                                    request.errorCode);
                         } catch (RemoteException e) {
                             logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e);
                             toBeRemoved.add(listener.asBinder());
@@ -403,10 +406,11 @@
     }
 
     public void updateSendDatagramTransferState(int subId,
+            @SatelliteManager.DatagramType int datagramType,
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int sendPendingCount, int errorCode) {
         DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest(
-                datagramTransferState, sendPendingCount, errorCode);
+                datagramType, datagramTransferState, sendPendingCount, errorCode);
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
 
@@ -424,7 +428,8 @@
             @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState,
             int receivePendingCount, int errorCode) {
         DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest(
-                datagramTransferState, receivePendingCount, errorCode);
+                SatelliteManager.DATAGRAM_TYPE_UNKNOWN, datagramTransferState, receivePendingCount,
+                errorCode);
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
 
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java b/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java
index 60950f2..7aadf0d 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -139,6 +140,19 @@
     }
 
     /**
+     * Get carrier identifier set for the satellite
+     *
+     * @return carrier identifier set from the config data.
+     */
+    @NonNull
+    public Set<Integer> getAllSatelliteCarrierIds() {
+        if (mSupportedServicesPerCarrier != null) {
+            return new ArraySet<>(mSupportedServicesPerCarrier.keySet());
+        }
+        return new ArraySet<>();
+    }
+
+    /**
      * @return satellite region country codes
      */
     @NonNull
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 018fc3d..4b387c8 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -18,8 +18,11 @@
 
 import static android.provider.Settings.ACTION_SATELLITE_SETTING;
 import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
+import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY;
+import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
 import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
@@ -50,6 +53,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.Uri;
@@ -77,7 +81,9 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Telephony;
 import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
@@ -87,6 +93,7 @@
 import android.telephony.satellite.ISatelliteDatagramCallback;
 import android.telephony.satellite.ISatelliteModemStateCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
+import android.telephony.satellite.ISatelliteSupportedStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
@@ -114,6 +121,7 @@
 import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
 import com.android.internal.telephony.satellite.metrics.SessionMetricsStats;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.FunctionalUtils;
 
 import java.util.ArrayList;
@@ -123,13 +131,15 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Satellite controller is the backend service of
@@ -157,6 +167,9 @@
     private static final String OEM_ENABLED_SATELLITE_PROVISION_STATUS_KEY =
             "oem_enabled_satellite_provision_status_key";
 
+    public static final long DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS =
+            TimeUnit.SECONDS.toMillis(30);
+
     /** Message codes used in handleMessage() */
     //TODO: Move the Commands and events related to position updates to PointingAppController
     private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1;
@@ -175,8 +188,6 @@
     private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16;
     private static final int CMD_GET_SATELLITE_CAPABILITIES = 17;
     private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18;
-    private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 19;
-    private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 20;
     private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21;
     private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22;
     private static final int EVENT_RADIO_STATE_CHANGED = 23;
@@ -197,6 +208,7 @@
     private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38;
     private static final int EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT = 39;
     private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
+    private static final int EVENT_SATELLITE_SUPPORTED_STATE_CHANGED = 41;
 
     @NonNull private static SatelliteController sInstance;
     @NonNull private final Context mContext;
@@ -250,7 +262,10 @@
     private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false);
     private final AtomicBoolean mRegisteredForSatelliteCapabilitiesChanged =
             new AtomicBoolean(false);
-    private final AtomicBoolean mShouldReportNtnSignalStrength = new AtomicBoolean(false);
+    private final AtomicBoolean mIsModemEnabledReportingNtnSignalStrength =
+            new AtomicBoolean(false);
+    private final AtomicBoolean mRegisteredForSatelliteSupportedStateChanged =
+            new AtomicBoolean(false);
     /**
      * Map key: subId, value: callback to get error code of the provision request.
      */
@@ -274,6 +289,11 @@
      */
     private final ConcurrentHashMap<IBinder, ISatelliteCapabilitiesCallback>
             mSatelliteCapabilitiesChangedListeners = new ConcurrentHashMap<>();
+    /**
+     * Map key: binder of the callback, value: callback to receive supported state changed events.
+     */
+    private final ConcurrentHashMap<IBinder, ISatelliteSupportedStateCallback>
+            mSatelliteSupportedStateChangedListeners = new ConcurrentHashMap<>();
     private final Object mIsSatelliteSupportedLock = new Object();
     @GuardedBy("mIsSatelliteSupportedLock")
     private Boolean mIsSatelliteSupported = null;
@@ -335,6 +355,14 @@
     @NonNull private final SparseBooleanArray
             mWasSatelliteConnectedViaCarrier = new SparseBooleanArray();
 
+    /**
+     * Key: Subscription ID; Value: set of
+     * {@link android.telephony.NetworkRegistrationInfo.ServiceType}
+     */
+    @GuardedBy("mSatelliteConnectedLock")
+    @NonNull private final Map<Integer, List<Integer>>
+            mSatModeCapabilitiesForCarrierRoaming = new HashMap<>();
+
     @GuardedBy("mSatelliteConnectedLock")
     @NonNull private final SparseBooleanArray
             mIsSatelliteConnectedViaCarrierHysteresisTimeExpired = new SparseBooleanArray();
@@ -358,6 +386,9 @@
     /** Key Subscription ID, value : PLMN allowed list from entitlement. */
     @GuardedBy("mSupportedSatelliteServicesLock")
     private SparseArray<List<String>> mEntitlementPlmnListPerCarrier = new SparseArray<>();
+    /** Key Subscription ID, value : PLMN barred list from entitlement. */
+    @GuardedBy("mSupportedSatelliteServicesLock")
+    private SparseArray<List<String>> mEntitlementBarredPlmnListPerCarrier = new SparseArray<>();
     /**
      * Key : Subscription ID, Value : If there is an entitlementPlmnList, use it. Otherwise, use the
      * carrierPlmnList. */
@@ -377,6 +408,8 @@
     private static final String NOTIFICATION_CHANNEL_ID = "satellite";
 
     private final RegistrantList mSatelliteConfigUpdateChangedRegistrants = new RegistrantList();
+    private final BTWifiNFCStateReceiver mBTWifiNFCSateReceiver;
+    private final UwbAdapterStateCallback mUwbAdapterStateCallback;
 
     /**
      * @return The singleton instance of SatelliteController.
@@ -446,6 +479,8 @@
         mContentResolver = mContext.getContentResolver();
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
 
+        mBTWifiNFCSateReceiver = new BTWifiNFCStateReceiver();
+        mUwbAdapterStateCallback = new UwbAdapterStateCallback();
         initializeSatelliteModeRadios();
 
         ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) {
@@ -509,11 +544,12 @@
      * Get satelliteConfig from SatelliteConfigParser
      */
     public SatelliteConfig getSatelliteConfig() {
-        if (getSatelliteConfigParser() == null) {
-            Log.d(TAG, "getSatelliteConfigParser() is not ready");
+        SatelliteConfigParser satelliteConfigParser = getSatelliteConfigParser();
+        if (satelliteConfigParser == null) {
+            Log.d(TAG, "satelliteConfigParser is not ready");
             return null;
         }
-        return (SatelliteConfig) getSatelliteConfigParser().getConfig();
+        return satelliteConfigParser.getConfig();
     }
 
     /**
@@ -528,8 +564,6 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected void initializeSatelliteModeRadios() {
         if (mContentResolver != null) {
-            BTWifiNFCStateReceiver bTWifiNFCSateReceiver = new BTWifiNFCStateReceiver();
-            UwbAdapterStateCallback uwbAdapterStateCallback = new UwbAdapterStateCallback();
             IntentFilter radioStateIntentFilter = new IntentFilter();
 
             synchronized (mRadioStateLock) {
@@ -583,7 +617,14 @@
                         radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
                     }
                 }
-                mContext.registerReceiver(bTWifiNFCSateReceiver, radioStateIntentFilter);
+
+                try {
+                    // Unregister receiver before registering it.
+                    mContext.unregisterReceiver(mBTWifiNFCSateReceiver);
+                } catch (IllegalArgumentException e) {
+                    logd("initializeSatelliteModeRadios: unregisterReceiver, e=" + e);
+                }
+                mContext.registerReceiver(mBTWifiNFCSateReceiver, radioStateIntentFilter);
 
                 if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB)) {
                     UwbManager uwbManager = mContext.getSystemService(UwbManager.class);
@@ -592,8 +633,10 @@
                         mUwbStateEnabled = uwbManager.isUwbEnabled();
                         final long identity = Binder.clearCallingIdentity();
                         try {
+                            // Unregister callback before registering it.
+                            uwbManager.unregisterAdapterStateCallback(mUwbAdapterStateCallback);
                             uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(),
-                                    uwbAdapterStateCallback);
+                                    mUwbAdapterStateCallback);
                         } finally {
                             Binder.restoreCallingIdentity(identity);
                         }
@@ -729,13 +772,15 @@
     private static final class RequestSatelliteEnabledArgument {
         public boolean enableSatellite;
         public boolean enableDemoMode;
+        public boolean isEmergency;
         @NonNull public Consumer<Integer> callback;
         public long requestId;
 
         RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode,
-                Consumer<Integer> callback) {
+                boolean isEmergency, Consumer<Integer> callback) {
             this.enableSatellite = enableSatellite;
             this.enableDemoMode = enableDemoMode;
+            this.isEmergency = isEmergency;
             this.callback = callback;
             this.requestId = sNextSatelliteEnableRequestId.getAndUpdate(
                     n -> ((n + 1) % Long.MAX_VALUE));
@@ -940,6 +985,8 @@
                             mWaitingForDisableSatelliteModemResponse = false;
                         }
                     }
+                    // Request Ntn signal strength report when satellite enabled or disabled done.
+                    updateNtnSignalStrengthReporting(argument.enableSatellite);
                 } else {
                     synchronized (mSatelliteEnabledRequestLock) {
                         if (mSatelliteEnabledRequest != null &&
@@ -1073,39 +1120,6 @@
                 break;
             }
 
-            case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: {
-                request = (SatelliteControllerHandlerRequest) msg.obj;
-                onCompleted =
-                        obtainMessage(EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE, request);
-                mSatelliteModemInterface
-                        .requestIsSatelliteCommunicationAllowedForCurrentLocation(onCompleted);
-                break;
-            }
-
-            case EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE: {
-                ar = (AsyncResult) msg.obj;
-                request = (SatelliteControllerHandlerRequest) ar.userObj;
-                int error =  SatelliteServiceUtils.getSatelliteError(ar,
-                        "isSatelliteCommunicationAllowedForCurrentLocation");
-                Bundle bundle = new Bundle();
-                if (error == SATELLITE_RESULT_SUCCESS) {
-                    if (ar.result == null) {
-                        loge("isSatelliteCommunicationAllowedForCurrentLocation: result is null");
-                        error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
-                    } else {
-                        boolean communicationAllowed = (boolean) ar.result;
-                        if (DBG) {
-                            logd("isSatelliteCommunicationAllowedForCurrentLocation: "
-                                    + communicationAllowed);
-                        }
-                        bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED,
-                                communicationAllowed);
-                    }
-                }
-                ((ResultReceiver) request.argument).send(error, bundle);
-                break;
-            }
-
             case CMD_GET_TIME_SATELLITE_NEXT_VISIBLE: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE,
@@ -1300,24 +1314,7 @@
                 if (DBG) {
                     logd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: shouldReport=" + shouldReport);
                 }
-                request = new SatelliteControllerHandlerRequest(shouldReport,
-                        SatelliteServiceUtils.getPhone());
-                if (SATELLITE_RESULT_SUCCESS != evaluateOemSatelliteRequestAllowed(true)) {
-                    return;
-                }
-                if (!isSatelliteEnabled() || mShouldReportNtnSignalStrength.get() == shouldReport) {
-                    if (DBG) {
-                        logd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: ignore request.");
-                    }
-                    return;
-                }
-                onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE,
-                        request);
-                if (shouldReport) {
-                    mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
-                } else {
-                    mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted);
-                }
+                handleCmdUpdateNtnSignalStrengthReporting(shouldReport);
                 break;
             }
 
@@ -1326,9 +1323,10 @@
                 request = (SatelliteControllerHandlerRequest) ar.userObj;
                 boolean shouldReport = (boolean) request.argument;
                 int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
-                        "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE");
+                        "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: shouldReport="
+                                + shouldReport);
                 if (errorCode == SATELLITE_RESULT_SUCCESS) {
-                    mShouldReportNtnSignalStrength.set(shouldReport);
+                    mIsModemEnabledReportingNtnSignalStrength.set(shouldReport);
                 } else {
                     loge(((boolean) request.argument ? "startSendingNtnSignalStrength"
                             : "stopSendingNtnSignalStrength") + "returns " + errorCode);
@@ -1351,6 +1349,16 @@
                 break;
             }
 
+            case EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: {
+                ar = (AsyncResult) msg.obj;
+                if (ar.result == null) {
+                    loge("EVENT_SATELLITE_SUPPORTED_STATE_CHANGED: result is null");
+                } else {
+                    handleEventSatelliteSupportedStateChanged((boolean) ar.result);
+                }
+                break;
+            }
+
             case EVENT_SATELLITE_CONFIG_DATA_UPDATED: {
                 handleEventConfigDataUpdated();
                 mSatelliteConfigUpdateChangedRegistrants.notifyRegistrants();
@@ -1392,12 +1400,13 @@
      * @param enableSatellite {@code true} to enable the satellite modem and
      *                        {@code false} to disable.
      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
+     * @param isEmergency {@code true} to enable emergency mode, {@code false} otherwise.
      * @param callback The callback to get the error code of the request.
      */
     public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode,
-            @NonNull IIntegerConsumer callback) {
+            boolean isEmergency, @NonNull IIntegerConsumer callback) {
         logd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite
-                + " enableDemoMode: " + enableDemoMode);
+                + " enableDemoMode: " + enableDemoMode + " isEmergency: " + isEmergency);
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
         int error = evaluateOemSatelliteRequestAllowed(true);
         if (error != SATELLITE_RESULT_SUCCESS) {
@@ -1438,7 +1447,8 @@
         }
 
         RequestSatelliteEnabledArgument request =
-                new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result);
+                new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, isEmergency,
+                        result);
         /**
          * Multiple satellite enabled requests are handled as below:
          * 1. If there are no ongoing requests, store current request in mSatelliteEnabledRequest
@@ -1955,26 +1965,6 @@
     }
 
     /**
-     * Request to get whether satellite communication is allowed for the current location.
-     *
-     * @param subId The subId of the subscription to check whether satellite communication is
-     *              allowed for the current location for.
-     * @param result The result receiver that returns whether satellite communication is allowed
-     *               for the current location if the request is successful or an error code
-     *               if the request failed.
-     */
-    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
-            @NonNull ResultReceiver result) {
-        int error = evaluateOemSatelliteRequestAllowed(false);
-        if (error != SATELLITE_RESULT_SUCCESS) {
-            result.send(error, null);
-            return;
-        }
-
-        sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, null);
-    }
-
-    /**
      * Request to get the time after which the satellite will be visible.
      *
      * @param subId The subId to get the time after which the satellite will be visible for.
@@ -2221,6 +2211,43 @@
     }
 
     /**
+     * Registers for the satellite supported state changed.
+     *
+     * @param subId The subId of the subscription to register for supported state changed.
+     * @param callback The callback to handle the satellite supported state changed event.
+     *
+     * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
+     */
+    @SatelliteManager.SatelliteResult public int registerForSatelliteSupportedStateChanged(
+            int subId, @NonNull ISatelliteSupportedStateCallback callback) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForSatelliteSupportedStateChanged: oemEnabledSatelliteFlag is disabled");
+            return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
+        }
+
+        mSatelliteSupportedStateChangedListeners.put(callback.asBinder(), callback);
+        return SATELLITE_RESULT_SUCCESS;
+    }
+
+    /**
+     * Unregisters for the satellite supported state changed.
+     * If callback was not registered before, the request will be ignored.
+     *
+     * @param subId The subId of the subscription to unregister for supported state changed.
+     * @param callback The callback that was passed to
+     * {@link #registerForSatelliteSupportedStateChanged(int, ISatelliteSupportedStateCallback)}.
+     */
+    public void unregisterForSatelliteSupportedStateChanged(
+            int subId, @NonNull ISatelliteSupportedStateCallback callback) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("unregisterForSatelliteSupportedStateChanged: "
+                    + "oemEnabledSatelliteFlag is disabled");
+            return;
+        }
+        mSatelliteSupportedStateChangedListeners.remove(callback.asBinder());
+    }
+
+    /**
      * This API can be used by only CTS to update satellite vendor service package name.
      *
      * @param servicePackageName The package name of the satellite vendor service.
@@ -2486,7 +2513,7 @@
 
         mIsRadioOn = false;
         requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                false /* enableSatellite */, false /* enableDemoMode */,
+                false /* enableSatellite */, false /* enableDemoMode */, false /* isEmergency */,
                 new IIntegerConsumer.Stub() {
                     @Override
                     public void accept(int result) {
@@ -2518,6 +2545,12 @@
             logd("getSatellitePlmnsForCarrier: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
+
+        if (!isSatelliteSupportedViaCarrier(subId)) {
+            logd("Satellite for carrier is not supported.");
+            return new ArrayList<>();
+        }
+
         synchronized (mSupportedSatelliteServicesLock) {
             return mMergedPlmnListPerCarrier.get(subId, new ArrayList<>()).stream().toList();
         }
@@ -2549,7 +2582,22 @@
                 loge("getSupportedSatelliteServices: mSatelliteServicesSupportedByCarriers does "
                         + "not contain key subId=" + subId);
             }
-            return new ArrayList<>();
+
+            /* Returns default capabilities when carrier config does not contain service
+               capabilities for the given plmn */
+            PersistableBundle config = getPersistableBundle(subId);
+            int [] defaultCapabilities = config.getIntArray(
+                    KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY);
+            if (defaultCapabilities == null) {
+                logd("getSupportedSatelliteServices: defaultCapabilities is null");
+                return new ArrayList<>();
+            }
+            List<Integer> capabilitiesList = Arrays.stream(
+                    defaultCapabilities).boxed().collect(Collectors.toList());
+            logd("getSupportedSatelliteServices: subId=" + subId
+                    + ", supportedServices does not contain key plmn=" + plmn
+                    + ", return default values " + capabilitiesList);
+            return capabilitiesList;
         }
     }
 
@@ -2596,6 +2644,32 @@
     }
 
     /**
+     * @return {@code true} if satellite emergency messaging is supported via carrier by any
+     * subscription on the device, {@code false} otherwise.
+     */
+    public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
+        if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("isSatelliteEmergencyMessagingSupportedViaCarrier: carrierEnabledSatelliteFlag is"
+                    + " disabled");
+            return false;
+        }
+        for (Phone phone : PhoneFactory.getPhones()) {
+            if (isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isSatelliteEmergencyMessagingSupportedViaCarrier(int subId) {
+        if (!isSatelliteSupportedViaCarrier(subId)) {
+            return false;
+        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return config.getBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL);
+    }
+
+    /**
      * @return {@code Pair<true, subscription ID>} if any subscription on the device is connected to
      * satellite, {@code Pair<false, null>} otherwise.
      */
@@ -2628,33 +2702,124 @@
             return true;
         }
         for (Phone phone : PhoneFactory.getPhones()) {
-            if (isSatelliteSupportedViaCarrier(phone.getSubId())) {
-                synchronized (mSatelliteConnectedLock) {
-                    Boolean isHysteresisTimeExpired =
-                            mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.get(
-                                    phone.getSubId());
-                    if (isHysteresisTimeExpired != null && isHysteresisTimeExpired) {
-                        continue;
-                    }
-
-                    Long lastDisconnectedTime =
-                            mLastSatelliteDisconnectedTimesMillis.get(phone.getSubId());
-                    long satelliteConnectionHysteresisTime =
-                            getSatelliteConnectionHysteresisTimeMillis(phone.getSubId());
-                    if (lastDisconnectedTime != null
-                            && (getElapsedRealtime() - lastDisconnectedTime)
-                            <= satelliteConnectionHysteresisTime) {
-                        return true;
-                    } else {
-                        mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
-                                phone.getSubId(), true);
-                    }
-                }
+            if (isInSatelliteModeForCarrierRoaming(phone)) {
+                logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: "
+                        + "subId:" + phone.getSubId()
+                        + " is connected to satellite within hysteresis time");
+                return true;
             }
         }
         return false;
     }
 
+    /**
+     * Get whether device is connected to satellite via carrier.
+     *
+     * @param phone phone object
+     * @return {@code true} if the device is connected to satellite using the phone within the
+     * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
+     * duration, {@code false} otherwise.
+     */
+    public boolean isInSatelliteModeForCarrierRoaming(@Nullable Phone phone) {
+        if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("isInSatelliteModeForCarrierRoaming: carrierEnabledSatelliteFlag is disabled");
+            return false;
+        }
+
+        if (phone == null) {
+            return false;
+        }
+
+        if (!isSatelliteSupportedViaCarrier(phone.getSubId())) {
+            return false;
+        }
+
+        ServiceState serviceState = phone.getServiceState();
+        if (serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) {
+            return true;
+        }
+
+        synchronized (mSatelliteConnectedLock) {
+            Boolean isHysteresisTimeExpired =
+                    mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.get(
+                            phone.getSubId());
+            if (isHysteresisTimeExpired != null && isHysteresisTimeExpired) {
+                return false;
+            }
+
+            Long lastDisconnectedTime =
+                    mLastSatelliteDisconnectedTimesMillis.get(phone.getSubId());
+            long satelliteConnectionHysteresisTime =
+                    getSatelliteConnectionHysteresisTimeMillis(phone.getSubId());
+            if (lastDisconnectedTime != null
+                    && (getElapsedRealtime() - lastDisconnectedTime)
+                    <= satelliteConnectionHysteresisTime) {
+                return true;
+            } else {
+                mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
+                        phone.getSubId(), true);
+                mSatModeCapabilitiesForCarrierRoaming.remove(phone.getSubId());
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Return capabilities of carrier roaming satellite network.
+     *
+     * @param phone phone object
+     * @return The list of services supported by the carrier associated with the {@code subId}
+     */
+    @NonNull
+    public List<Integer> getCapabilitiesForCarrierRoamingSatelliteMode(Phone phone) {
+        if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("getCapabilitiesForCarrierRoamingSatelliteMode: carrierEnabledSatelliteFlag"
+                    + " is disabled");
+            return new ArrayList<>();
+        }
+
+        synchronized (mSatelliteConnectedLock) {
+            int subId = phone.getSubId();
+            if (mSatModeCapabilitiesForCarrierRoaming.containsKey(subId)) {
+                return mSatModeCapabilitiesForCarrierRoaming.get(subId);
+            }
+        }
+
+        return new ArrayList<>();
+    }
+
+    /**
+     * Get the carrier-enabled emergency call wait for connection timeout millis
+     */
+    public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+        long maxTimeoutMillis = 0;
+        for (Phone phone : PhoneFactory.getPhones()) {
+            if (!isSatelliteEmergencyMessagingSupportedViaCarrier(phone.getSubId())) {
+                continue;
+            }
+
+            int timeoutMillis =
+                    getCarrierEmergencyCallWaitForConnectionTimeoutMillis(phone.getSubId());
+            // Prioritize getting the timeout duration from the phone that is in satellite mode
+            // with carrier roaming
+            if (isInSatelliteModeForCarrierRoaming(phone)) {
+                return timeoutMillis;
+            }
+            if (maxTimeoutMillis < timeoutMillis) {
+                maxTimeoutMillis = timeoutMillis;
+            }
+        }
+        if (maxTimeoutMillis != 0) {
+            return maxTimeoutMillis;
+        }
+        return DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
+    }
+
+    private int getCarrierEmergencyCallWaitForConnectionTimeoutMillis(int subId) {
+        PersistableBundle config = getPersistableBundle(subId);
+        return config.getInt(KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected long getElapsedRealtime() {
         return SystemClock.elapsedRealtime();
@@ -2668,11 +2833,14 @@
      * @param subId              subId
      * @param entitlementEnabled {@code true} Satellite service enabled
      * @param allowedPlmnList    plmn allowed list to use the satellite service
+     * @param barredPlmnList    plmn barred list to pass the modem
      * @param callback           callback for accept
      */
     public void onSatelliteEntitlementStatusUpdated(int subId, boolean entitlementEnabled,
-            List<String> allowedPlmnList, @Nullable IIntegerConsumer callback) {
+            @Nullable List<String> allowedPlmnList, @Nullable List<String> barredPlmnList,
+            @Nullable IIntegerConsumer callback) {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("onSatelliteEntitlementStatusUpdated: carrierEnabledSatelliteFlag is not enabled");
             return;
         }
 
@@ -2684,9 +2852,16 @@
                 }
             };
         }
-        logd("onSatelliteEntitlementStatusUpdated subId=" + subId + " , entitlementEnabled="
-                + entitlementEnabled + ", allowedPlmnList=" + (Objects.equals(null, allowedPlmnList)
-                ? "" : allowedPlmnList + ""));
+        if (allowedPlmnList == null) {
+            allowedPlmnList = new ArrayList<>();
+        }
+        if (barredPlmnList == null) {
+            barredPlmnList = new ArrayList<>();
+        }
+        logd("onSatelliteEntitlementStatusUpdated subId=" + subId + ", entitlementEnabled="
+                + entitlementEnabled + ", allowedPlmnList=["
+                + String.join(",", allowedPlmnList) + "]" + ", barredPlmnList=["
+                + String.join(",", barredPlmnList) + "]");
 
         synchronized (mSupportedSatelliteServicesLock) {
             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false) != entitlementEnabled) {
@@ -2699,12 +2874,18 @@
                     loge("onSatelliteEntitlementStatusUpdated: setSubscriptionProperty, e=" + e);
                 }
             }
-            mMergedPlmnListPerCarrier.remove(subId);
 
-            mEntitlementPlmnListPerCarrier.put(subId, allowedPlmnList);
-            updatePlmnListPerCarrier(subId);
-            configureSatellitePlmnForCarrier(subId);
-            mSubscriptionManagerService.setSatelliteEntitlementPlmnList(subId, allowedPlmnList);
+            if (isValidPlmnList(allowedPlmnList) && isValidPlmnList(barredPlmnList)) {
+                mMergedPlmnListPerCarrier.remove(subId);
+                mEntitlementPlmnListPerCarrier.put(subId, allowedPlmnList);
+                mEntitlementBarredPlmnListPerCarrier.put(subId, barredPlmnList);
+                updatePlmnListPerCarrier(subId);
+                configureSatellitePlmnForCarrier(subId);
+                mSubscriptionManagerService.setSatelliteEntitlementPlmnList(subId, allowedPlmnList);
+            } else {
+                loge("onSatelliteEntitlementStatusUpdated: either invalid allowedPlmnList "
+                        + "or invalid barredPlmnList");
+            }
 
             if (mSatelliteEntitlementStatusPerCarrier.get(subId, false)) {
                 removeAttachRestrictionForCarrier(subId,
@@ -2717,6 +2898,20 @@
     }
 
     /**
+     * A list of PLMNs is considered valid if either the list is empty or all PLMNs in the list
+     * are valid.
+     */
+    private boolean isValidPlmnList(@NonNull List<String> plmnList) {
+        for (String plmn : plmnList) {
+            if (!TelephonyUtils.isValidPlmn(plmn)) {
+                loge("Invalid PLMN = " + plmn);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * If we have not successfully queried the satellite modem for its satellite service support,
      * we will retry the query one more time. Otherwise, we will return the cached result.
      */
@@ -2906,7 +3101,7 @@
 
         Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request);
         mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
-                argument.enableDemoMode, onCompleted);
+                argument.enableDemoMode, argument.isEmergency, onCompleted);
         startWaitForSatelliteEnablingResponseTimer(argument);
     }
 
@@ -2937,6 +3132,7 @@
             registerForSatelliteModemStateChanged();
             registerForNtnSignalStrengthChanged();
             registerForCapabilitiesChanged();
+            registerForSatelliteSupportedStateChanged();
 
             requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                     new ResultReceiver(this) {
@@ -2945,7 +3141,7 @@
                             logd("requestIsSatelliteProvisioned: resultCode=" + resultCode
                                     + ", resultData=" + resultData);
                             requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
-                                    false, false,
+                                    false, false, false,
                                     new IIntegerConsumer.Stub() {
                                         @Override
                                         public void accept(int result) {
@@ -2976,7 +3172,7 @@
             loge(caller + ": mSatelliteSessionController is not initialized yet");
         }
         if (!enabled) {
-            mShouldReportNtnSignalStrength.set(false);
+            mIsModemEnabledReportingNtnSignalStrength.set(false);
         }
     }
 
@@ -3040,6 +3236,16 @@
         }
     }
 
+    private void registerForSatelliteSupportedStateChanged() {
+        if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
+            if (!mRegisteredForSatelliteSupportedStateChanged.get()) {
+                mSatelliteModemInterface.registerForSatelliteSupportedStateChanged(
+                        this, EVENT_SATELLITE_SUPPORTED_STATE_CHANGED, null);
+                mRegisteredForSatelliteSupportedStateChanged.set(true);
+            }
+        }
+    }
+
     private void handleEventSatelliteProvisionStateChanged(boolean provisioned) {
         logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned);
 
@@ -3148,6 +3354,54 @@
         });
     }
 
+    private void handleEventSatelliteSupportedStateChanged(boolean supported) {
+        logd("handleSatelliteSupportedStateChangedEvent: supported=" + supported);
+
+        synchronized (mIsSatelliteSupportedLock) {
+            if (mIsSatelliteSupported != null && mIsSatelliteSupported == supported) {
+                if (DBG) {
+                    logd("current satellite support state and new supported state are matched,"
+                            + " ignore update.");
+                }
+                return;
+            }
+            /* In case satellite has been reported as not support from modem, but satellite is
+               enabled, request disable satellite. */
+            synchronized (mIsSatelliteEnabledLock) {
+                if (!supported && mIsSatelliteEnabled != null && mIsSatelliteEnabled) {
+                    logd("Invoke requestSatelliteEnabled(), supported=false, "
+                            + "mIsSatelliteEnabled=true");
+                    requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                            false /* enableSatellite */, false /* enableDemoMode */,
+                            false /* isEmergency */,
+                            new IIntegerConsumer.Stub() {
+                                @Override
+                                public void accept(int result) {
+                                    logd("handleSatelliteSupportedStateChangedEvent: request "
+                                            + "satellite disable, result="
+                                            + result);
+                                }
+                            });
+
+                }
+            }
+            mIsSatelliteSupported = supported;
+        }
+
+        List<ISatelliteSupportedStateCallback> deadCallersList = new ArrayList<>();
+        mSatelliteSupportedStateChangedListeners.values().forEach(listener -> {
+            try {
+                listener.onSatelliteSupportedStateChanged(supported);
+            } catch (RemoteException e) {
+                logd("handleSatelliteSupportedStateChangedEvent RemoteException: " + e);
+                deadCallersList.add(listener);
+            }
+        });
+        deadCallersList.forEach(listener -> {
+            mSatelliteSupportedStateChangedListeners.remove(listener.asBinder());
+        });
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected void setSettingsKeyForSatelliteMode(int val) {
         logd("setSettingsKeyForSatelliteMode val: " + val);
@@ -3231,10 +3485,12 @@
         synchronized (mSupportedSatelliteServicesLock) {
             List<String> carrierPlmnList = mMergedPlmnListPerCarrier.get(subId,
                     new ArrayList<>()).stream().toList();
+            List<String> barredPlmnList = mEntitlementBarredPlmnListPerCarrier.get(subId,
+                    new ArrayList<>()).stream().toList();
             int slotId = SubscriptionManager.getSlotIndex(subId);
             mSatelliteModemInterface.setSatellitePlmn(slotId, carrierPlmnList,
                     SatelliteServiceUtils.mergeStrLists(
-                            carrierPlmnList, mSatellitePlmnListFromOverlayConfig),
+                            carrierPlmnList, mSatellitePlmnListFromOverlayConfig, barredPlmnList),
                     obtainMessage(EVENT_SET_SATELLITE_PLMN_INFO_DONE));
         }
     }
@@ -3271,14 +3527,21 @@
      * Otherwise, If the carrierPlmnList exist then used it.
      */
     private void updatePlmnListPerCarrier(int subId) {
+        logd("updatePlmnListPerCarrier: subId=" + subId);
         synchronized (mSupportedSatelliteServicesLock) {
             List<String> carrierPlmnList, entitlementPlmnList;
-            entitlementPlmnList = mEntitlementPlmnListPerCarrier.get(subId,
-                    new ArrayList<>()).stream().toList();
-            if (!entitlementPlmnList.isEmpty()) {
-                mMergedPlmnListPerCarrier.put(subId, entitlementPlmnList);
-                logd("update it using entitlementPlmnList=" + entitlementPlmnList);
-                return;
+            if (getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
+                    false)) {
+                entitlementPlmnList = mEntitlementPlmnListPerCarrier.get(subId,
+                        new ArrayList<>()).stream().toList();
+                logd("updatePlmnListPerCarrier: entitlementPlmnList="
+                        + String.join(",", entitlementPlmnList)
+                        + " size=" + entitlementPlmnList.size());
+                if (!entitlementPlmnList.isEmpty()) {
+                    mMergedPlmnListPerCarrier.put(subId, entitlementPlmnList);
+                    logd("mMergedPlmnListPerCarrier is updated by Entitlement");
+                    return;
+                }
             }
 
             SatelliteConfig satelliteConfig = getSatelliteConfig();
@@ -3287,21 +3550,24 @@
                 int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
                 List<String> plmnList = satelliteConfig.getAllSatellitePlmnsForCarrier(carrierId);
                 if (!plmnList.isEmpty()) {
-                    logd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : " + plmnList);
+                    logd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : "
+                            + String.join(",", plmnList));
                     mMergedPlmnListPerCarrier.put(subId, plmnList);
                     return;
                 }
             }
 
-            if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) {
+            if (mSatelliteServicesSupportedByCarriers.containsKey(subId)
+                    && mSatelliteServicesSupportedByCarriers.get(subId) != null) {
                 carrierPlmnList =
                         mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList();
-                logd("mMergedPlmnListPerCarrier is updated by carrier config");
+                logd("mMergedPlmnListPerCarrier is updated by carrier config: "
+                        + String.join(",", carrierPlmnList));
             } else {
                 carrierPlmnList = new ArrayList<>();
+                logd("Empty mMergedPlmnListPerCarrier");
             }
             mMergedPlmnListPerCarrier.put(subId, carrierPlmnList);
-            logd("update it using carrierPlmnList=" + carrierPlmnList);
         }
     }
 
@@ -3319,7 +3585,7 @@
                 if (!supportedServicesPerPlmn.isEmpty()) {
                     mSatelliteServicesSupportedByCarriers.put(subId, supportedServicesPerPlmn);
                     logd("updateSupportedSatelliteServices using ConfigUpdater, "
-                            + "supportedServicesPerPlmn = " + supportedServicesPerPlmn);
+                            + "supportedServicesPerPlmn = " + supportedServicesPerPlmn.size());
                     updatePlmnListPerCarrier(subId);
                     return;
                 } else {
@@ -3348,16 +3614,10 @@
 
     @NonNull
     private Map<String, Set<Integer>> readSupportedSatelliteServicesFromCarrierConfig(int subId) {
-        synchronized (mCarrierConfigArrayLock) {
-            PersistableBundle config = mCarrierConfigArray.get(subId);
-            if (config == null) {
-                config = getConfigForSubId(subId);
-                mCarrierConfigArray.put(subId, config);
-            }
-            return SatelliteServiceUtils.parseSupportedSatelliteServices(
-                    config.getPersistableBundle(
-                            KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
-        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return SatelliteServiceUtils.parseSupportedSatelliteServices(
+                config.getPersistableBundle(
+                        KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
     }
 
     @NonNull private PersistableBundle getConfigForSubId(int subId) {
@@ -3365,7 +3625,10 @@
                 KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
                 KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT,
-                KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL);
+                KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL,
+                KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
+                KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL,
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT);
         if (config == null || config.isEmpty()) {
             config = CarrierConfigManager.getDefaultConfig();
         }
@@ -3405,8 +3668,10 @@
         }
     }
 
-    /** If there is no cached entitlement plmn list, read it from the db and use it if it is not an
-     * empty list. */
+    /**
+     * If there is no cached entitlement plmn list, read it from the db and use it if it is not an
+     * empty list.
+     */
     private void updateEntitlementPlmnListPerCarrier(int subId) {
         if (!getConfigForSubId(subId).getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false)) {
             logd("don't support entitlement");
@@ -3420,11 +3685,11 @@
                 List<String> entitlementPlmnList =
                         mSubscriptionManagerService.getSatelliteEntitlementPlmnList(subId);
                 if (entitlementPlmnList.isEmpty()) {
-                    loge("updateEntitlementPlmnListPerCarrier: no data for subId(" + subId + ")");
+                    logd("updateEntitlementPlmnListPerCarrier: read empty list");
                     return;
                 }
                 logd("updateEntitlementPlmnListPerCarrier: entitlementPlmnList="
-                        + entitlementPlmnList);
+                        + String.join(",", entitlementPlmnList));
                 mEntitlementPlmnListPerCarrier.put(subId, entitlementPlmnList);
             }
         }
@@ -3771,6 +4036,14 @@
                         mWasSatelliteConnectedViaCarrier.put(phone.getSubId(), true);
                         mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
                                 phone.getSubId(), false);
+
+                        for (NetworkRegistrationInfo nri
+                                : serviceState.getNetworkRegistrationInfoList()) {
+                            if (nri.isNonTerrestrialNetwork()) {
+                                mSatModeCapabilitiesForCarrierRoaming.put(phone.getSubId(),
+                                        nri.getAvailableServices());
+                            }
+                        }
                     } else {
                         Boolean connected = mWasSatelliteConnectedViaCarrier.get(phone.getSubId());
                         if (connected != null && connected) {
@@ -3788,15 +4061,9 @@
     }
 
     private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
-        synchronized (mCarrierConfigArrayLock) {
-            PersistableBundle config = mCarrierConfigArray.get(subId);
-            if (config == null) {
-                config = getConfigForSubId(subId);
-                mCarrierConfigArray.put(subId, config);
-            }
-            return (config.getInt(
-                    KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
-        }
+        PersistableBundle config = getPersistableBundle(subId);
+        return (config.getInt(
+                KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
     }
 
     private void persistOemEnabledSatelliteProvisionStatus(boolean isProvisioned) {
@@ -3946,7 +4213,7 @@
                     Consumer<Integer> result =
                             FunctionalUtils.ignoreRemoteException(callback::accept);
                     RequestSatelliteEnabledArgument request = new RequestSatelliteEnabledArgument(
-                            false, false, result);
+                            false, false, false, result);
                     synchronized (mSatelliteEnabledRequestLock) {
                         mSatelliteEnabledRequest = request;
                     }
@@ -3974,6 +4241,49 @@
         }
     }
 
+    private void handleCmdUpdateNtnSignalStrengthReporting(boolean shouldReport) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("handleCmdUpdateNtnSignalStrengthReporting: oemEnabledSatelliteFlag is "
+                    + "disabled");
+            return;
+        }
+
+        if (!isSatelliteEnabled()) {
+            logd("handleCmdUpdateNtnSignalStrengthReporting: ignore request, satellite is "
+                    + "disabled");
+            return;
+        }
+
+        if (mIsModemEnabledReportingNtnSignalStrength.get() == shouldReport) {
+            logd("handleCmdUpdateNtnSignalStrengthReporting: ignore request. "
+                    + "mIsModemEnabledReportingNtnSignalStrength="
+                    + mIsModemEnabledReportingNtnSignalStrength.get());
+            return;
+        }
+
+        updateNtnSignalStrengthReporting(shouldReport);
+    }
+
+    private void updateNtnSignalStrengthReporting(boolean shouldReport) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("updateNtnSignalStrengthReporting: oemEnabledSatelliteFlag is "
+                    + "disabled");
+            return;
+        }
+
+        SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest(
+                shouldReport, SatelliteServiceUtils.getPhone());
+        Message onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE,
+                request);
+        if (shouldReport) {
+            logd("updateNtnSignalStrengthReporting: startSendingNtnSignalStrength");
+            mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
+        } else {
+            logd("updateNtnSignalStrengthReporting: stopSendingNtnSignalStrength");
+            mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted);
+        }
+    }
+
     /**
      * This API can be used by only CTS to override the cached value for the device overlay config
      * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
@@ -4051,13 +4361,30 @@
                         com.android.internal.R.color.system_notification_accent_color))
                 .setVisibility(Notification.VISIBILITY_PUBLIC);
 
-        // Add action to invoke `What to expect` dialog of Messaging application.
-        Intent intentOpenMessage = new Intent(Intent.ACTION_VIEW);
-        intentOpenMessage.setData(Uri.parse("sms:"));
-        // TODO : b/322733285 add putExtra to invoke "What to expect" dialog.
-        PendingIntent pendingIntentOpenMessage = PendingIntent.getActivity(mContext, 0,
-                intentOpenMessage, PendingIntent.FLAG_IMMUTABLE);
+        // Add action to invoke message application.
+        // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
+        Optional<Intent> nullableIntent = Optional.ofNullable(
+                        Telephony.Sms.getDefaultSmsPackage(mContext))
+                .flatMap(packageName -> {
+                    PackageManager pm = mContext.getPackageManager();
+                    return Optional.ofNullable(pm.getLaunchIntentForPackage(packageName));
+                });
+        // If nullableIntent is null, create new Intent for most common way to invoke message app.
+        Intent finalIntent = nullableIntent.map(intent -> {
+            // Invoke the home screen of default message application.
+            intent.setAction(Intent.ACTION_MAIN);
+            intent.addCategory(Intent.CATEGORY_HOME);
+            return intent;
+        }).orElseGet(() -> {
+            loge("showSatelliteSystemNotification: no default sms package name, Invoke "
+                    + "default sms compose window instead");
+            Intent newIntent = new Intent(Intent.ACTION_VIEW);
+            newIntent.setData(Uri.parse("sms:"));
+            return newIntent;
+        });
 
+        PendingIntent pendingIntentOpenMessage = PendingIntent.getActivity(mContext, 0,
+                finalIntent, PendingIntent.FLAG_IMMUTABLE);
         Notification.Action actionOpenMessage = new Notification.Action.Builder(0,
                 mContext.getResources().getString(R.string.satellite_notification_open_message),
                 pendingIntentOpenMessage).build();
@@ -4078,6 +4405,18 @@
                 notificationBuilder.build(), UserHandle.ALL);
     }
 
+    @NonNull
+    private PersistableBundle getPersistableBundle(int subId) {
+        synchronized (mCarrierConfigArrayLock) {
+            PersistableBundle config = mCarrierConfigArray.get(subId);
+            if (config == null) {
+                config = getConfigForSubId(subId);
+                mCarrierConfigArray.put(subId, config);
+            }
+            return config;
+        }
+    }
+
     private static void logd(@NonNull String log) {
         Rlog.d(TAG, log);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index 2f86eea..2e99ae6 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -93,6 +93,8 @@
             new RegistrantList();
     @NonNull private final RegistrantList mSatelliteCapabilitiesChangedRegistrants =
             new RegistrantList();
+    @NonNull private final RegistrantList mSatelliteSupportedStateChangedRegistrants =
+            new RegistrantList();
 
     @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() {
         @Override
@@ -158,6 +160,11 @@
             mSatelliteCapabilitiesChangedRegistrants.notifyResult(
                     SatelliteServiceUtils.fromSatelliteCapabilities(satelliteCapabilities));
         }
+
+        @Override
+        public void onSatelliteSupportedStateChanged(boolean supported) {
+            mSatelliteSupportedStateChangedRegistrants.notifyResult(supported);
+        }
     };
 
     /**
@@ -505,6 +512,27 @@
     }
 
     /**
+     * Registers for the satellite supported state changed.
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForSatelliteSupportedStateChanged(
+            @NonNull Handler h, int what, @Nullable Object obj) {
+        mSatelliteSupportedStateChangedRegistrants.add(h, what, obj);
+    }
+
+    /**
+     * Unregisters for the satellite supported state changed.
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForSatelliteSupportedStateChanged(@NonNull Handler h) {
+        mSatelliteSupportedStateChangedRegistrants.remove(h);
+    }
+
+    /**
      * Request to enable or disable the satellite service listening mode.
      * Listening mode allows the satellite service to listen for incoming pages.
      *
@@ -591,19 +619,20 @@
      *
      * @param enableSatellite True to enable the satellite modem and false to disable.
      * @param enableDemoMode True to enable demo mode and false to disable.
+     * @param isEmergency {@code true} to enable emergency mode, {@code false} otherwise.
      * @param message The Message to send to result of the operation to.
      */
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
-            @NonNull Message message) {
+            boolean isEmergency, @NonNull Message message) {
         if (mSatelliteService != null) {
             try {
                 mSatelliteService.requestSatelliteEnabled(enableSatellite, enableDemoMode,
-                        new IIntegerConsumer.Stub() {
-                    @Override
-                    public void accept(int result) {
-                        int error = SatelliteServiceUtils.fromSatelliteError(result);
-                        logd("setSatelliteEnabled: " + error);
-                        Binder.withCleanCallingIdentity(() ->
+                        isEmergency, new IIntegerConsumer.Stub() {
+                            @Override
+                            public void accept(int result) {
+                                int error = SatelliteServiceUtils.fromSatelliteError(result);
+                                logd("setSatelliteEnabled: " + error);
+                                Binder.withCleanCallingIdentity(() ->
                                 sendMessageWithResult(message, null, error));
                     }
                 });
@@ -1009,48 +1038,6 @@
     }
 
     /**
-     * Request to get whether satellite communication is allowed for the current location.
-     *
-     * @param message The Message to send to result of the operation to.
-     */
-    public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull Message message) {
-        if (mSatelliteService != null) {
-            try {
-                mSatelliteService.requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                        new IIntegerConsumer.Stub() {
-                            @Override
-                            public void accept(int result) {
-                                int error = SatelliteServiceUtils.fromSatelliteError(result);
-                                logd("requestIsCommunicationAllowedForCurrentLocation: "
-                                        + error);
-                                Binder.withCleanCallingIdentity(() ->
-                                        sendMessageWithResult(message, null, error));
-                            }
-                        }, new IBooleanConsumer.Stub() {
-                            @Override
-                            public void accept(boolean result) {
-                                logd("requestIsCommunicationAllowedForCurrentLocation: "
-                                        + result);
-                                Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
-                                        message, result,
-                                        SatelliteManager.SATELLITE_RESULT_SUCCESS));
-                            }
-                        });
-            } catch (RemoteException e) {
-                loge("requestIsCommunicationAllowedForCurrentLocation: RemoteException "
-                        + e);
-                sendMessageWithResult(message, null,
-                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
-            }
-        } else {
-            loge("requestIsCommunicationAllowedForCurrentLocation: "
-                    + "Satellite service is unavailable.");
-            sendMessageWithResult(message, null,
-                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
-        }
-    }
-
-    /**
      * Request to get the time after which the satellite will be visible. This is an int
      * representing the duration in seconds after which the satellite will be visible.
      * This will return 0 if the satellite is currently visible.
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index c491476..062f431 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -99,7 +99,8 @@
     private boolean mIsSatelliteAllowedForCurrentLocation = false;
     @GuardedBy("mLock")
     private boolean mCheckingAccessRestrictionInProgress = false;
-    private final long mTimeoutMillis;
+    protected long mTimeoutMillis = 0;
+    private final long mOemEnabledTimeoutMillis;
     private final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime =
             new AtomicBoolean(false);
     @GuardedBy("mLock")
@@ -114,8 +115,7 @@
      * @param looper The looper used with the handler of this class.
      */
     public SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper) {
-        this(context, looper, SatelliteController.getInstance(), null,
-                getEmergencyCallWaitForConnectionTimeoutMillis(context));
+        this(context, looper, SatelliteController.getInstance(), null);
     }
 
     /**
@@ -127,17 +127,16 @@
      * @param satelliteController The SatelliteController singleton instance.
      * @param imsManager The ImsManager instance associated with the phone, which is used for making
      *                   the emergency call. This argument is not null only in unit tests.
-     * @param timeoutMillis The timeout duration of the timer.
      */
     @VisibleForTesting
     protected SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper,
-            @NonNull SatelliteController satelliteController, ImsManager imsManager,
-            long timeoutMillis) {
+            @NonNull SatelliteController satelliteController, ImsManager imsManager) {
         super(looper);
         mContext = context;
         mSatelliteController = satelliteController;
         mImsManager = imsManager;
-        mTimeoutMillis = timeoutMillis;
+        mOemEnabledTimeoutMillis =
+                getOemEnabledEmergencyCallWaitForConnectionTimeoutMillis(context);
         mISatelliteProvisionStateCallback = new ISatelliteProvisionStateCallback.Stub() {
             @Override
             public void onSatelliteProvisionStateChanged(boolean provisioned) {
@@ -185,7 +184,7 @@
      */
     public void onEmergencyCallStarted(@NonNull Connection connection) {
         if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
+                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
             logd("onEmergencyCallStarted: satellite is not supported");
             return;
         }
@@ -212,7 +211,7 @@
             String callId, @Connection.ConnectionState int state) {
         logd("callId=" + callId + ", state=" + state);
         if (!mSatelliteController.isSatelliteSupportedViaOem()
-                && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
+                && !mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
             logd("onEmergencyCallConnectionStateChanged: satellite is not supported");
             return;
         }
@@ -229,6 +228,8 @@
         if (sendEventDisplayEmergencyMessageForcefully(connection)) {
             return;
         }
+
+        selectEmergencyCallWaitForConnectionTimeoutDuration();
         if (mEmergencyConnection == null) {
             handleStateChangedEventForHysteresisTimer();
             registerForInterestedStateChangedEvents();
@@ -504,7 +505,18 @@
         }
     }
 
-    private static long getEmergencyCallWaitForConnectionTimeoutMillis(@NonNull Context context) {
+    private void selectEmergencyCallWaitForConnectionTimeoutDuration() {
+        if (mSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier()) {
+            mTimeoutMillis =
+                    mSatelliteController.getCarrierEmergencyCallWaitForConnectionTimeoutMillis();
+        } else {
+            mTimeoutMillis = mOemEnabledTimeoutMillis;
+        }
+        logd("mTimeoutMillis = " + mTimeoutMillis);
+    }
+
+    private static long getOemEnabledEmergencyCallWaitForConnectionTimeoutMillis(
+            @NonNull Context context) {
         return context.getResources().getInteger(
                 R.integer.config_emergency_call_wait_for_connection_timeout_millis);
     }
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index 0e6f706..33b35d7 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.telephony.satellite;
 
-import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE;
-import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE;
-
 import static java.util.stream.Collectors.joining;
 
 import android.annotation.NonNull;
@@ -43,6 +40,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.util.Arrays;
 import java.util.HashMap;
@@ -302,19 +300,23 @@
         }
 
         for (String plmn : supportedServicesBundle.keySet()) {
-            Set<Integer> supportedServicesSet = new HashSet<>();
-            for (int serviceType : supportedServicesBundle.getIntArray(plmn)) {
-                if (isServiceTypeValid(serviceType)) {
-                    supportedServicesSet.add(serviceType);
-                } else {
-                    loge("parseSupportedSatelliteServices: invalid service type=" + serviceType
-                            + " for plmn=" + plmn);
+            if (TelephonyUtils.isValidPlmn(plmn)) {
+                Set<Integer> supportedServicesSet = new HashSet<>();
+                for (int serviceType : supportedServicesBundle.getIntArray(plmn)) {
+                    if (TelephonyUtils.isValidService(serviceType)) {
+                        supportedServicesSet.add(serviceType);
+                    } else {
+                        loge("parseSupportedSatelliteServices: invalid service type=" + serviceType
+                                + " for plmn=" + plmn);
+                    }
                 }
+                logd("parseSupportedSatelliteServices: plmn=" + plmn + ", supportedServicesSet="
+                        + supportedServicesSet.stream().map(String::valueOf).collect(
+                        joining(",")));
+                supportedServicesMap.put(plmn, supportedServicesSet);
+            } else {
+                loge("parseSupportedSatelliteServices: invalid plmn=" + plmn);
             }
-            logd("parseSupportedSatelliteServices: plmn=" + plmn + ", supportedServicesSet="
-                    + supportedServicesSet.stream().map(String::valueOf).collect(
-                            joining(",")));
-            supportedServicesMap.put(plmn, supportedServicesSet);
         }
         return supportedServicesMap;
     }
@@ -330,8 +332,18 @@
         return mergedStrSet.stream().toList();
     }
 
-    private static boolean isServiceTypeValid(int serviceType) {
-        return (serviceType >= FIRST_SERVICE_TYPE && serviceType <= LAST_SERVICE_TYPE);
+    /**
+     * Merge three string lists into one such that the result list does not have any duplicate
+     * items.
+     */
+    @NonNull
+    public static List<String> mergeStrLists(List<String> strList1, List<String> strList2,
+            List<String> strList3) {
+        Set<String> mergedStrSet = new HashSet<>();
+        mergedStrSet.addAll(strList1);
+        mergedStrSet.addAll(strList2);
+        mergedStrSet.addAll(strList3);
+        return mergedStrSet.stream().toList();
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
index 82af4e8..bb77d5c 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java
@@ -1217,7 +1217,22 @@
      * @return {@code true} if the subscription is visible to the user.
      */
     public boolean isVisible() {
-        return !isOpportunistic() || TextUtils.isEmpty(mGroupUuid);
+        // Provisioning profile
+        if (getProfileClass() == SubscriptionManager.PROFILE_CLASS_PROVISIONING) {
+            return false;
+        }
+
+        // Satellite profile
+        if (getOnlyNonTerrestrialNetwork() == 1) {
+            return false;
+        }
+
+        // Opportunistic profile
+        if (isOpportunistic() && !TextUtils.isEmpty(mGroupUuid)) {
+            return false;
+        }
+
+        return true;
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 8757c97..bae43b6 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -124,6 +124,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
@@ -4412,13 +4413,49 @@
     public List<String> getSatelliteEntitlementPlmnList(int subId) {
         SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(
                 subId);
-        if (subInfo == null) {
-            loge("getSatelliteEntitlementPlmnList: invalid subId=" + subId);
-            return new ArrayList<>();
+
+        return Optional.ofNullable(subInfo)
+                .map(SubscriptionInfoInternal::getSatelliteEntitlementPlmns)
+                .filter(s -> !s.isEmpty())
+                .map(s -> Arrays.stream(s.split(",")).collect(Collectors.toList()))
+                .orElse(new ArrayList<>());
+    }
+
+    /**
+     * checks whether esim bootstrap is activated for any of the available active subscription info
+     * list.
+     *
+     * @return {@code true} if esim bootstrap is activated for any of the active subscription,
+     * else {@code false}
+     *
+     */
+    public boolean isEsimBootStrapProvisioningActivated() {
+        if (!mFeatureFlags.esimBootstrapProvisioningFlag()) {
+            return false;
         }
 
-        return Arrays.stream(subInfo.getSatelliteEntitlementPlmns().split(",")).collect(
-                Collectors.toList());
+        List<SubscriptionInfo> activeSubInfos =
+                getActiveSubscriptionInfoList(mContext.getOpPackageName(),
+                        mContext.getAttributionTag(), true/*isForAllProfile*/);
+
+        return activeSubInfos.stream().anyMatch(subInfo -> subInfo != null
+                && subInfo.getProfileClass() == SubscriptionManager.PROFILE_CLASS_PROVISIONING);
+    }
+
+    /**
+     * checks whether esim bootstrap is activated for the subscription.
+     *
+     * @return {@code true} if esim bootstrap is activated for sub id else {@code false}
+     *
+     */
+    public boolean isEsimBootStrapProvisioningActiveForSubId(int subId) {
+        if (!mFeatureFlags.esimBootstrapProvisioningFlag()) {
+            return false;
+        }
+
+        SubscriptionInfoInternal subInfo = getSubscriptionInfoInternal(subId);
+        return subInfo != null
+                && subInfo.getProfileClass() == SubscriptionManager.PROFILE_CLASS_PROVISIONING;
     }
 
     /**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
index 2a66a5f..e06e4fe 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.os.CarrierAssociatedAppEntry;
 import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.test.mock.MockContentProvider;
@@ -34,9 +35,12 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.telephony.flags.Flags;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
@@ -59,6 +63,9 @@
     private static final int USER_ID = 12345;
     private static final String CALLING_PACKAGE = "phone";
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     // Mocked classes
     private Context mContext;
     private PackageManager mPackageManager;
@@ -79,6 +86,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_PREINSTALLED_CARRIER_APP_AT_MOST_ONCE);
         System.setProperty("dexmaker.dexcache",
                 InstrumentationRegistry.getTargetContext().getCacheDir().getPath());
         Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
@@ -113,6 +121,7 @@
     public void testDisableCarrierAppsUntilPrivileged_EmptyList() {
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, new ArraySet<>(), ASSOCIATED_APPS, mContext);
+
         Mockito.verifyNoMoreInteractions(mPackageManager, mTelephonyManager);
     }
 
@@ -125,9 +134,11 @@
                         | PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(null);
         ArraySet<String> systemCarrierAppsDisabledUntilUsed = new ArraySet<>();
         systemCarrierAppsDisabledUntilUsed.add("com.example.missing.app");
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, systemCarrierAppsDisabledUntilUsed, ASSOCIATED_APPS,
                 mContext);
+
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN));
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -147,8 +158,10 @@
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN));
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -173,15 +186,16 @@
         Mockito.when(mPackageManager
                 .getApplicationEnabledSetting(Mockito.anyString()))
                 .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
-
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -199,15 +213,16 @@
         Mockito.when(mPackageManager
                 .getApplicationEnabledSetting(Mockito.anyString()))
                 .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
-
         Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
                 PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -231,8 +246,10 @@
                         | PackageManager.MATCH_SYSTEM_ONLY)).thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -255,11 +272,12 @@
         Mockito.when(mPackageManager
                 .getApplicationEnabledSetting(Mockito.anyString()))
                 .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
-
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -287,8 +305,10 @@
                 .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
@@ -329,8 +349,10 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -371,8 +393,10 @@
                 .thenReturn(null);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
@@ -412,8 +436,10 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -440,8 +466,10 @@
                 .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -465,9 +493,11 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -476,7 +506,7 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Configured app has no privileges, and was uninstalled - should do nothing. */
+    /** Configured app has no privileges, and was explicitly disabled - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Disabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -492,8 +522,10 @@
                 .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -502,7 +534,7 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Telephony is not initialized, and app was uninstalled - should do nothing. */
+    /** Telephony is not initialized, and app was explicitly disabled - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NullPrivileges_Disabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -516,9 +548,11 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -527,7 +561,7 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Configured app has no privileges, and is explicitly installed - should do nothing. */
+    /** Configured app has no privileges, and was explicitly enabled - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Enabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -543,8 +577,10 @@
                 .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -553,7 +589,7 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Telephony is not initialized, and app is explicitly installed - should do nothing. */
+    /** Telephony is not initialized, and app was explicitly enabled - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NullPrivileges_Enabled() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -567,9 +603,11 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -578,7 +616,8 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Configured /data app has no privileges - should do nothing. */
+    /** Configured app has been installed as an update in /data and has no privileges
+     *  - should do nothing. */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_UpdatedApp() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -595,8 +634,10 @@
                 .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -620,9 +661,11 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -632,7 +675,8 @@
     }
 
     /**
-     * Configured app has no privileges, and is in the default state - should uninstalled.
+     * Configured app has no privileges, is in the default state and it was never uninstalled before
+     *  - should uninstalled.
      * Associated app is installed and should not be touched.
      */
     @Test @SmallTest
@@ -660,8 +704,10 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -675,8 +721,8 @@
     }
 
     /**
-     * Configured app has no privileges, and is in the default state along with associated app -
-     * should uninstall both.
+     * Configured app has no privileges, is in the default state along with associated app and never
+     * unstalled before - should uninstall both.
      */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Associated_Default()
@@ -703,8 +749,10 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -717,7 +765,7 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has already occurred - should only uninstall configured app.
+     * disabling has already occurred - should uninstall nothing.
      */
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NoPrivileges_Associated_Default_HandledSdk()
@@ -747,15 +795,17 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Different associated app SDK than usual.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS,
                 makeAssociatedApp(CARRIER_APP, ASSOCIATED_APP, Build.VERSION.SDK_INT), mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
-        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_INSTALLED);
@@ -765,7 +815,7 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has already occurred - should only uninstall configured app.
+     * disabling has already occurred - should uninstall nothing.
      */
     @Test @SmallTest
     public void testDCAUP_NoPrivileges_Associated_Default_HandledSdk_AssociatedSdkUnspecified()
@@ -795,14 +845,16 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Using SDK_UNSPECIFIED for the associated app's addedInSdk.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
-        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_INSTALLED);
@@ -812,15 +864,14 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has not yet occurred on this SDK level - should uninstall both since the associated
-     * app's SDK matches.
+     * disabling has not yet occurred on any SDK level - should uninstall both since disabling never
+     * occurred before and the associated app's SDK matches.
      */
     @Test @SmallTest
     public void testDCAUP_NoPrivileges_Associated_Default_NewSdk_AssociatedSdkCurrent()
             throws Exception {
         Settings.Secure.putIntForUser(
-                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED,
-                Build.VERSION.SDK_INT - 1, USER_ID);
+                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, USER_ID);
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.packageName = CARRIER_APP;
         appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
@@ -843,10 +894,12 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Different associated app SDK than usual.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS,
                 makeAssociatedApp(CARRIER_APP, ASSOCIATED_APP, Build.VERSION.SDK_INT), mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -861,7 +914,7 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has not yet occurred on the current SDK - should only uninstall configured app
+     * disabling has not yet occurred on the current SDK - should uninstall nothing
      * since the associated app's SDK isn't specified but we've already run at least once.
      */
     @Test @SmallTest
@@ -892,14 +945,16 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Using SDK_UNSPECIFIED for the associated app's addedInSdk.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
-        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_INSTALLED);
@@ -909,7 +964,7 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has not yet occurred on the current SDK - should only uninstall configured app
+     * disabling has not yet occurred on the current SDK - should uninstall nothing
      * since the associated app's SDK doesn't match.
      */
     @Test @SmallTest
@@ -940,16 +995,18 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Different associated app SDK than usual.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS,
                 makeAssociatedApp(CARRIER_APP, ASSOCIATED_APP, Build.VERSION.SDK_INT - 1),
                 mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
-        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_INSTALLED);
@@ -959,8 +1016,8 @@
 
     /**
      * Configured app has no privileges, and is in the default state along with associated app, and
-     * disabling has not yet occurred on this SDK level - should uninstall both since the associated
-     * app's SDK is newer than the last evaluation.
+     * disabling has not yet occurred on this SDK level - should uninstall only associated
+     * app since the associated app's SDK is newer than the last evaluation.
      *
      * While this case is expected to feel somewhat strange, it effectively simulates skipping a
      * whole SDK level in a single OTA. For example, the device is on P. A new associated app is
@@ -996,16 +1053,18 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Different associated app SDK than usual.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS,
                 makeAssociatedApp(CARRIER_APP, ASSOCIATED_APP, Build.VERSION.SDK_INT - 1),
                 mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
-        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(ASSOCIATED_APP,
                 PackageManager.SYSTEM_APP_STATE_INSTALLED);
@@ -1043,10 +1102,12 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Different associated app SDK than usual.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS,
                 makeAssociatedApp(CARRIER_APP, ASSOCIATED_APP, Build.VERSION.SDK_INT), mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -1089,9 +1150,11 @@
                 .thenReturn(associatedAppInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         // Using SDK_UNSPECIFIED for the associated app's addedInSdk.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(ASSOCIATED_APP,
@@ -1104,7 +1167,10 @@
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
     }
 
-    /** Telephony is not initialized, and app is in the default state - should uninstall it. */
+    /**
+     * Telephony is not initialized, and app is in the default state and never uninstall before
+     * - should uninstall it.
+     **/
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NullPrivileges_Default() throws Exception {
         ApplicationInfo appInfo = new ApplicationInfo();
@@ -1118,16 +1184,51 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
     }
 
-    /** Configured app has no privileges, and is disabled until used or not installed - should do
+    /**
+     * Telephony is not initialized, and app is in the default state but uninstall before
+     * - should not uninstall again.
+     **/
+    @Test @SmallTest
+    public void testDisableCarrierAppsUntilPrivileged_NullPrivileges_Default_alreadyUninstalled()
+            throws Exception {
+        Settings.Secure.putIntForUser(
+                mContentResolver, Settings.Secure.CARRIER_APPS_HANDLED,
+                Build.VERSION.SDK_INT, USER_ID);
+        ApplicationInfo appInfo = new ApplicationInfo();
+        appInfo.packageName = CARRIER_APP;
+        appInfo.flags |= ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_INSTALLED;
+        Mockito.when(mPackageManager
+                .getApplicationEnabledSetting(Mockito.anyString()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+        Mockito.when(mPackageManager.getApplicationInfo(CARRIER_APP,
+                PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+                        | PackageManager.MATCH_SYSTEM_ONLY))
+                .thenReturn(appInfo);
+
+        CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
+                null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
+                ASSOCIATED_APPS, mContext);
+
+        Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
+                PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
+        Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(CARRIER_APP,
+                PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
+    }
+
+    /**
+     * Configured app has no privileges, and is disabled until used or not installed - should do
      *  nothing.
      **/
     @Test @SmallTest
@@ -1146,8 +1247,10 @@
                 .thenReturn(appInfo);
         Mockito.when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(CARRIER_APP))
                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mTelephonyManager,
                 mContentResolver, USER_ID, CARRIER_APPS, ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
@@ -1156,8 +1259,9 @@
                 Mockito.eq(PackageManager.SYSTEM_APP_STATE_UNINSTALLED));
     }
 
-    /** Telephony is not initialized, and app is disabled until used or not installed - should do
-     *  nothing.
+    /**
+     * Telephony is not initialized, and app is disabled until used or not installed - should do
+     * nothing.
      **/
     @Test @SmallTest
     public void testDisableCarrierAppsUntilPrivileged_NullPrivileges_DisabledUntilUsed()
@@ -1173,9 +1277,11 @@
                         | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
                         | PackageManager.MATCH_SYSTEM_ONLY))
                 .thenReturn(appInfo);
+
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE,
                 null /* telephonyManager */, mContentResolver, USER_ID, CARRIER_APPS,
                 ASSOCIATED_APPS, mContext);
+
         Mockito.verify(mPackageManager).setSystemAppState(CARRIER_APP,
                 PackageManager.SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN);
         Mockito.verify(mPackageManager, Mockito.never()).setSystemAppState(Mockito.anyString(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index a7e9604..d1ab64d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -1007,4 +1007,57 @@
         // Default data is set to sub1
         verify(mSubscriptionManagerService).syncGroupedSetting(1);
     }
+
+    @Test
+    public void testDailogsAndWarnings_WithBootstrapSim() {
+        doReturn(true).when(mFeatureFlags).esimBootstrapProvisioningFlag();
+
+        // Mark sub 2 as inactive.
+        markSubscriptionInactive(2);
+        mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
+        sendCarrierConfigChanged(0, 1);
+        processAllMessages();
+
+        // Sub 1 should be default sub silently.
+        verify(mSubscriptionManagerService).setDefaultDataSubId(1);
+        verify(mSubscriptionManagerService).setDefaultVoiceSubId(1);
+        verify(mSubscriptionManagerService).setDefaultSmsSubId(1);
+        verifyDismissIntentSent();
+
+        // Mark sub 2 bootstrap sim as active in phone[1].
+        doReturn(true).when(mSubscriptionManagerService).isEsimBootStrapProvisioningActivated();
+        setSimSlotIndex(2, 1);
+        clearInvocations(mSubscriptionManagerService);
+        clearInvocations(mContext);
+        mSubInfo[2] = new SubscriptionInfoInternal.Builder().setId(2).setSimSlotIndex(1)
+                .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build();
+        mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
+        sendCarrierConfigChanged(1, 2);
+        processAllMessages();
+
+        // Taking out SIM 1.
+        clearInvocations(mSubscriptionManagerService);
+        markSubscriptionInactive(1/*subid*/);
+        mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
+        sendCarrierConfigChanged(0/*phoneid*/, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        processAllMessages();
+
+        // No user selection needed, no intent should be sent for notification
+        verify(mContext, never()).sendBroadcast(any());
+
+        //Insert back sim1 and switch from sub 1 to sub 3 in phone[0].
+        clearInvocations(mSubscriptionManagerService);
+        markSubscriptionInactive(1);
+        setSimSlotIndex(3, 0);
+        mMultiSimSettingControllerUT.notifySubscriptionInfoChanged();
+        sendCarrierConfigChanged(0/*phoneid*/, 3/*subid*/);
+        processAllMessages();
+
+        // Sub 3 should be default sub.
+        verify(mSubscriptionManagerService).setDefaultDataSubId(3);
+        verify(mSubscriptionManagerService).setDefaultVoiceSubId(3);
+        verify(mSubscriptionManagerService).setDefaultSmsSubId(3);
+        verify(mContext, never()).sendBroadcast(any());
+    }
+
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java
index 629327d..0563481 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java
@@ -16,34 +16,47 @@
 
 package com.android.internal.telephony.configupdate;
 
-import static com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver.UPDATE_CONTENT_PATH;
+import static android.telephony.NetworkRegistrationInfo.FIRST_SERVICE_TYPE;
+import static android.telephony.NetworkRegistrationInfo.LAST_SERVICE_TYPE;
+
+import static com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver.NEW_CONFIG_CONTENT_PATH;
 import static com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver.UPDATE_DIR;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeast;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Intent;
+import android.util.ArraySet;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.satellite.SatelliteConfig;
 import com.android.internal.telephony.satellite.SatelliteConfigParser;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.io.File;
 import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -74,7 +87,7 @@
         TelephonyConfigUpdateInstallReceiver testReceiver =
                 new TelephonyConfigUpdateInstallReceiver();
         assertEquals(UPDATE_DIR, testReceiver.getUpdateDir().toString());
-        assertEquals(new File(new File(UPDATE_DIR), UPDATE_CONTENT_PATH).toString(),
+        assertEquals(new File(new File(UPDATE_DIR), NEW_CONFIG_CONTENT_PATH).toString(),
                 testReceiver.getUpdateContent().toString());
     }
 
@@ -92,38 +105,133 @@
         // create spyTelephonyConfigUpdateInstallReceiver
         TelephonyConfigUpdateInstallReceiver spyTelephonyConfigUpdateInstallReceiver =
                 spy(new TelephonyConfigUpdateInstallReceiver());
-
-        // mock BeforeParser
-        String mBase64StrForPBByteArray =
-                "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
-        byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
-        doReturn(mBytesProtoBuffer).when(
-                spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
-        SatelliteConfigParser mMockSatelliteConfigParserBefore =
-                spy(new SatelliteConfigParser(mBytesProtoBuffer));
-        doReturn(mMockSatelliteConfigParserBefore).when(
-                spyTelephonyConfigUpdateInstallReceiver).getConfigParser(DOMAIN_SATELLITE);
-
-        // mock UpdatedParser
-        SatelliteConfigParser spySatelliteConfigParserAfter =
-                spy(new SatelliteConfigParser(mBytesProtoBuffer));
-        doReturn(5).when(spySatelliteConfigParserAfter).getVersion();
-        doReturn(spySatelliteConfigParserAfter).when(spyTelephonyConfigUpdateInstallReceiver)
-                .getNewConfigParser(any(), any());
-
+        doReturn(true).when(spyTelephonyConfigUpdateInstallReceiver)
+                .copySourceFileToTargetFile(any(), any());
         replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
                 null, spyTelephonyConfigUpdateInstallReceiver);
 
         assertSame(spyTelephonyConfigUpdateInstallReceiver,
                 TelephonyConfigUpdateInstallReceiver.getInstance());
 
+        // valid config data case
+        // mVersion:4 | mSupportedServicesPerCarrier:{1={310160=[1, 2, 3], 310220=[3]}} |
+        // mSatelliteRegionCountryCodes:[US] | mIsSatelliteRegionAllowed:true | s2CellFile size:10
+        String mBase64StrForPBByteArray =
+                "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+        byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+        doReturn(mBytesProtoBuffer).when(
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
+
+        // mock UpdatedParser
+        SatelliteConfigParser spyValidParser =
+                spy(new SatelliteConfigParser(mBytesProtoBuffer));
+
         ConcurrentHashMap<Executor, ConfigProviderAdaptor.Callback> spyCallbackHashMap = spy(
                 new ConcurrentHashMap<>());
         spyCallbackHashMap.put(mExecutor, mCallback);
         spyTelephonyConfigUpdateInstallReceiver.setCallbackMap(spyCallbackHashMap);
+
         spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
 
-        verify(spyCallbackHashMap, atLeast(1)).keySet();
+        verify(spyCallbackHashMap, times(2)).keySet();
+        verify(spyTelephonyConfigUpdateInstallReceiver, times(1))
+                .copySourceFileToTargetFile(any(), any());
+        Mockito.clearInvocations(spyCallbackHashMap);
+        Mockito.clearInvocations(spyTelephonyConfigUpdateInstallReceiver);
+
+        replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "mConfigParser",
+                spyTelephonyConfigUpdateInstallReceiver, spyValidParser);
+
+        // valid config data but smaller version case
+        // mVersion:3 | mSupportedServicesPerCarrier:{1={12345=[1, 2]}} |
+        // mSatelliteRegionCountryCodes:[US] | mIsSatelliteRegionAllowed:true | s2CellFile size:10
+        mBase64StrForPBByteArray =
+                "CicIAxIPCAESCwoFMTIzNDUQARACGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+        mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+
+        // mock UpdatedParser
+        SatelliteConfigParser spyInvalidParser =
+                spy(new SatelliteConfigParser(mBytesProtoBuffer));
+        doReturn(spyInvalidParser).when(spyTelephonyConfigUpdateInstallReceiver)
+                .getNewConfigParser(any(), any());
+
+        spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
+
+        verify(spyCallbackHashMap, times(0)).keySet();
+        verify(spyTelephonyConfigUpdateInstallReceiver, times(0))
+                .copySourceFileToTargetFile(any(), any());
+        Mockito.clearInvocations(spyCallbackHashMap);
+        Mockito.clearInvocations(spyTelephonyConfigUpdateInstallReceiver);
+
+        // Empty config data case which is valid
+        // mSupportedServicesPerCarrier:{} | mSatelliteRegionCountryCodes:[US] |
+        // mIsSatelliteRegionAllowed:true | s2CellFile size:30
+        mBase64StrForPBByteArray =
+                "CioIDBomCh4wMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkSAlVTGAE=";
+        mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+        doReturn(mBytesProtoBuffer).when(
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
+
+        // mock UpdatedParser
+        SatelliteConfigParser spyValidEmptyParser =
+                spy(new SatelliteConfigParser(mBytesProtoBuffer));
+        doReturn(spyValidEmptyParser).when(spyTelephonyConfigUpdateInstallReceiver)
+                .getNewConfigParser(any(), any());
+
+        spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
+        verify(spyCallbackHashMap, times(2)).keySet();
+        verify(spyTelephonyConfigUpdateInstallReceiver, times(1))
+                .copySourceFileToTargetFile(any(), any());
+        Mockito.clearInvocations(spyCallbackHashMap);
+        Mockito.clearInvocations(spyTelephonyConfigUpdateInstallReceiver);
+
+        // Wrong plmn("1234") config data case
+        // mSupportedServicesPerCarrier:{1={"1234"=[1, 2, 3]}} |
+        // mSatelliteRegionCountryCodes:[US]
+        // | mIsSatelliteRegionAllowed:true | s2CellFile size:10
+        mBase64StrForPBByteArray =
+                "CigIDBIQCAESDAoEMTIzNBABEAIQAxoSCgowMTIzNDU2Nzg5EgJVUxgB";
+        mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+        doReturn(mBytesProtoBuffer).when(
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
+
+        // mock UpdatedParser
+        spyInvalidParser =
+                spy(new SatelliteConfigParser(mBytesProtoBuffer));
+        doReturn(spyInvalidParser).when(spyTelephonyConfigUpdateInstallReceiver)
+                .getNewConfigParser(any(), any());
+
+        spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
+
+        verify(spyCallbackHashMap, times(0)).keySet();
+        verify(spyTelephonyConfigUpdateInstallReceiver, times(0))
+                .copySourceFileToTargetFile(any(), any());
+        Mockito.clearInvocations(spyCallbackHashMap);
+        Mockito.clearInvocations(spyTelephonyConfigUpdateInstallReceiver);
+
+        // Wrong service("8") config data case
+        // mSupportedServicesPerCarrier:{1={12345=[6, "8"]}} |
+        // mSatelliteRegionCountryCodes:[US] |
+        // mIsSatelliteRegionAllowed:true | s2CellFile size:10
+        mBase64StrForPBByteArray =
+                "CicIDBIPCAESCwoFMTIzNDUQBhAIGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+        mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+        doReturn(mBytesProtoBuffer).when(
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
+
+        // mock UpdatedParser
+        spyInvalidParser =
+                spy(new SatelliteConfigParser(mBytesProtoBuffer));
+        doReturn(spyInvalidParser).when(spyTelephonyConfigUpdateInstallReceiver)
+                .getNewConfigParser(any(), any());
+
+        spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
+
+        verify(spyCallbackHashMap, times(0)).keySet();
+        verify(spyTelephonyConfigUpdateInstallReceiver, times(0))
+                .copySourceFileToTargetFile(any(), any());
+        Mockito.clearInvocations(spyCallbackHashMap);
+        Mockito.clearInvocations(spyTelephonyConfigUpdateInstallReceiver);
     }
 
 
@@ -133,7 +241,7 @@
                 spy(new TelephonyConfigUpdateInstallReceiver());
 
         doReturn(null).when(
-                spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
 
         replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
                 null, spyTelephonyConfigUpdateInstallReceiver);
@@ -144,7 +252,7 @@
                 "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
         byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
         doReturn(mBytesProtoBuffer).when(
-                spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
+                spyTelephonyConfigUpdateInstallReceiver).getContentFromContentPath(any());
 
         replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
                 null, spyTelephonyConfigUpdateInstallReceiver);
@@ -172,4 +280,59 @@
         testReceiver.unregisterCallback(testCallback);
         assertEquals(0, testReceiver.getCallbackMap().size());
     }
+
+    @Test
+    public void testIsValidSatelliteCarrierConfigData() {
+        TelephonyConfigUpdateInstallReceiver spyTelephonyConfigUpdateInstallReceiver =
+                spy(new TelephonyConfigUpdateInstallReceiver());
+        SatelliteConfigParser mockParser = mock(SatelliteConfigParser.class);
+        SatelliteConfig mockConfig = mock(SatelliteConfig.class);
+        doReturn(new ArraySet<>()).when(mockConfig).getAllSatelliteCarrierIds();
+        doReturn(mockConfig).when(mockParser).getConfig();
+
+        assertTrue(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+
+        doReturn(Set.of(1)).when(mockConfig).getAllSatelliteCarrierIds();
+        Map<String, Set<Integer>> validPlmnsServices = new HashMap<>();
+        validPlmnsServices.put("123456", Set.of(FIRST_SERVICE_TYPE, 3, LAST_SERVICE_TYPE));
+        validPlmnsServices.put("12345", Set.of(FIRST_SERVICE_TYPE, 4, LAST_SERVICE_TYPE));
+        doReturn(validPlmnsServices).when(mockConfig).getSupportedSatelliteServices(anyInt());
+        doReturn(mockConfig).when(mockParser).getConfig();
+
+        assertTrue(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+
+        doReturn(Set.of(1)).when(mockConfig).getAllSatelliteCarrierIds();
+        Map<String, Set<Integer>> invalidPlmnsServices1 = new HashMap<>();
+        invalidPlmnsServices1.put("123456", Set.of(FIRST_SERVICE_TYPE - 1, 3, LAST_SERVICE_TYPE));
+        doReturn(invalidPlmnsServices1).when(mockConfig).getSupportedSatelliteServices(anyInt());
+        doReturn(mockConfig).when(mockParser).getConfig();
+        assertFalse(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+
+        doReturn(Set.of(1)).when(mockConfig).getAllSatelliteCarrierIds();
+        Map<String, Set<Integer>> invalidPlmnsServices2 = new HashMap<>();
+        invalidPlmnsServices2.put("123456", Set.of(FIRST_SERVICE_TYPE, 3, LAST_SERVICE_TYPE + 1));
+        doReturn(invalidPlmnsServices2).when(mockConfig).getSupportedSatelliteServices(anyInt());
+        doReturn(mockConfig).when(mockParser).getConfig();
+        assertFalse(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+
+        doReturn(Set.of(1)).when(mockConfig).getAllSatelliteCarrierIds();
+        Map<String, Set<Integer>> invalidPlmnsServices3 = new HashMap<>();
+        invalidPlmnsServices3.put("1234", Set.of(FIRST_SERVICE_TYPE, 3, LAST_SERVICE_TYPE));
+        doReturn(invalidPlmnsServices3).when(mockConfig).getSupportedSatelliteServices(anyInt());
+        doReturn(mockConfig).when(mockParser).getConfig();
+        assertFalse(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+
+        doReturn(Set.of(1)).when(mockConfig).getAllSatelliteCarrierIds();
+        Map<String, Set<Integer>> invalidPlmnsServices4 = new HashMap<>();
+        invalidPlmnsServices4.put("1234567", Set.of(FIRST_SERVICE_TYPE, 3, LAST_SERVICE_TYPE));
+        doReturn(invalidPlmnsServices4).when(mockConfig).getSupportedSatelliteServices(anyInt());
+        doReturn(mockConfig).when(mockParser).getConfig();
+        assertFalse(spyTelephonyConfigUpdateInstallReceiver
+                .isValidSatelliteCarrierConfigData(mockParser));
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
index 9423551..d11b730 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -182,7 +182,6 @@
     private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback;
 
     private boolean mIsNonTerrestrialNetwork = false;
-    private ArrayList<Integer> mCarrierSupportedSatelliteServices = new ArrayList<>();
     private FeatureFlags mFeatureFlags;
 
     private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder()
@@ -700,7 +699,6 @@
                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                 .setDataSpecificInfo(dsri)
                 .setIsNonTerrestrialNetwork(mIsNonTerrestrialNetwork)
-                .setAvailableServices(mCarrierSupportedSatelliteServices)
                 .setEmergencyOnly(isEmergencyOnly)
                 .build());
 
@@ -710,7 +708,6 @@
                 .setRegistrationState(iwlanRegState)
                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                 .setIsNonTerrestrialNetwork(mIsNonTerrestrialNetwork)
-                .setAvailableServices(mCarrierSupportedSatelliteServices)
                 .setEmergencyOnly(isEmergencyOnly)
                 .build());
 
@@ -854,6 +851,9 @@
                 .config_enable_iwlan_handover_policy, true);
         mContextFixture.putBooleanResource(com.android.internal.R.bool
                 .config_enhanced_iwlan_handover_check, true);
+        mContextFixture.putStringArrayResource(com.android.internal.R.array
+                .config_force_cellular_transport_capabilities,
+                new String[] {"ims", "eims", "xcap"});
     }
 
     @Before
@@ -896,6 +896,8 @@
         doReturn(PhoneConstants.State.IDLE).when(mCT).getState();
         doReturn(new SubscriptionInfoInternal.Builder().setId(1).build())
                 .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt());
+        doReturn(true).when(mFeatureFlags).carrierEnabledSatelliteFlag();
+        doReturn(true).when(mFeatureFlags).satelliteInternet();
 
         List<SubscriptionInfo> infoList = new ArrayList<>();
         infoList.add(mMockSubInfo);
@@ -1136,15 +1138,24 @@
     }
 
     private @NonNull TelephonyNetworkRequest createNetworkRequest(Integer... capabilities) {
+        return createNetworkRequest(false, capabilities);
+    }
+
+    private @NonNull TelephonyNetworkRequest createNetworkRequest(boolean restricted,
+                                                                  Integer... capabilities) {
         NetworkCapabilities netCaps = new NetworkCapabilities();
         for (int networkCapability : capabilities) {
             netCaps.addCapability(networkCapability);
         }
 
+        if (restricted) {
+            netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        }
+
         NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps,
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
-        return new TelephonyNetworkRequest(nativeNetworkRequest, mPhone);
+        return new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags);
     }
 
     // The purpose of this test is to make sure the network request insertion/removal works as
@@ -1405,7 +1416,7 @@
         netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
                 new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
-                        NetworkRequest.Type.REQUEST), mPhone));
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
         processAllMessages();
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
         List<DataNetwork> dataNetworkList = getDataNetworks();
@@ -1708,72 +1719,224 @@
     }
 
     @Test
-    public void testNonTerrestrialNetworkChangedWithoutDataSupport() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+    public void testIsNetworkRequestSatisfiedByTransportCellularTransportRequest() {
         mIsNonTerrestrialNetwork = true;
-        // Data is not supported while using satellite
-        mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE);
+
+        // Data is not supported for cellular transport network request while using satellite
+        // network
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mDataNetworkControllerUT.addNetworkRequest(
-                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        // Set network request transport as Cellular in satellite network
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
         processAllMessages();
 
-        // Data with internet capability should not be allowed
-        // when the device is using non-terrestrial network
-        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        // Verify data is not connected since Network request cannot satisfy by transport
+        verify(mMockedDataNetworkControllerCallback, never())
+                .onConnectedInternetDataNetworksChanged(any());
 
         mIsNonTerrestrialNetwork = false;
-        mCarrierSupportedSatelliteServices.clear();
-        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
-
-        // Verify data is restored.
-        verifyInternetConnected();
     }
 
     @Test
-    public void testNonTerrestrialNetworkWithDataSupport() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+    public void testMobileDataDisabledIsValidRestrictedRequestWithSatelliteInternetRequest() {
         mIsNonTerrestrialNetwork = true;
-        // Data is supported while using satellite
-        mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_DATA);
+
+        //Mobile Data Disabled
+        mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName());
+        processAllMessages();
+
+        // Data is not supported for cellular transport network request while using satellite
+        // network
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mDataNetworkControllerUT.addNetworkRequest(
-                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        // Set network request transport as Satellite with restricted capability + internet
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
         processAllMessages();
 
-        // Verify data is connected.
-        verifyInternetConnected();
+        // Verify data is not connected since Network request cannot satisfy by transport
+        verify(mMockedDataNetworkControllerCallback, never())
+                .onConnectedInternetDataNetworksChanged(any());
 
         mIsNonTerrestrialNetwork = false;
-        mCarrierSupportedSatelliteServices.clear();
     }
 
     @Test
-    public void testNonTerrestrialNetworkWithFlagDisabled() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
-
+    public void testMobileDataDisabledIsValidRestrictedRequestWithTransportSatelliteMMSRequest()
+            throws Exception {
         mIsNonTerrestrialNetwork = true;
-        // Data is not supported while using satellite
-        mCarrierSupportedSatelliteServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE);
+
+        // Data disabled
+        mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName());
+        // Always allow MMS off
+        mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager
+                .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false);
+        processAllMessages();
+
+        // Data is not supported for cellular transport network request while using satellite
+        // network
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
 
-        mDataNetworkControllerUT.addNetworkRequest(
-                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+        // Set network request transport as Cellular+Satellite with restricted capability + mms
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
         processAllMessages();
 
-        // As feature is disabled, data is connected.
-        verifyInternetConnected();
+        // Verify mms is not connected
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
 
         mIsNonTerrestrialNetwork = false;
-        mCarrierSupportedSatelliteServices.clear();
     }
 
+    @Test
+    public void testOnMmsAlwaysALlowedIsValidRestrictedRequestWithTransportSatelliteMMSRequest()
+            throws Exception {
+        mIsNonTerrestrialNetwork = true;
+
+        // Data disabled
+        mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled(
+                TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName());
+        // Always allow MMS On
+        mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager
+                .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true);
+        processAllMessages();
+
+        // Data is not supported for cellular transport network request while using satellite
+        // network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // Set network request transport as Cellular+Satellite with restricted capability + mms
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
+        processAllMessages();
+
+        // Verify mms is connected if mms always allowed is on
+        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS);
+
+        mIsNonTerrestrialNetwork = false;
+    }
+
+    @Test
+    public void testIsNetworkRequestSatisfiedByTransportSatelliteTransportRequest_Terrestrial() {
+        // Set network request transport as satellite in satellite network
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
+        processAllMessages();
+
+        // Verify data is not supported for satellite transport network request while using cellular
+        verify(mMockedDataNetworkControllerCallback, never())
+                .onConnectedInternetDataNetworksChanged(any());
+
+    }
+
+    @Test
+    public void testIsNetworkRequestSatisfiedByTransportSatelliteTransportRequest() {
+        mIsNonTerrestrialNetwork = true;
+
+        // Data is supported for satellite transport network request while using satellite network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // Set network request transport as satellite while using satellite network
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
+        processAllMessages();
+
+        // Verify data is connected since Network request satisfy by transport
+        verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any());
+
+        mIsNonTerrestrialNetwork = false;
+    }
+
+    @Test
+    public void testIsNetworkRequestSatisfiedByTransportNoTransportRequest() {
+        mIsNonTerrestrialNetwork = true;
+
+        // Data is supported for no transport network request while using satellite network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // Set network request transport as no transport with Internet capability
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
+        processAllMessages();
+
+        // Verify data is connected since Network request satisfy by transport
+        verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any());
+
+        mIsNonTerrestrialNetwork = false;
+    }
+
+    @Test
+    public void testIsNetworkCapabilitySatelliteAndCellularCapableImsCellularTransportRequest()
+            throws Exception {
+        mIsNonTerrestrialNetwork = true;
+
+        // IMS PDN is supported for cellular network request while using satellite network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+
+        // Set network request transport as Cellular + IMS
+        NetworkCapabilities netCaps = new NetworkCapabilities();
+        netCaps.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+        netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+        netCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
+                new NetworkRequest(netCaps, ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags));
+        processAllMessages();
+
+        // Verify ims is connected since, cellular network request for ims is allowed while using
+        // satellite network
+        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
+                NetworkCapabilities.NET_CAPABILITY_MMTEL);
+
+        mIsNonTerrestrialNetwork = false;
+    }
 
     @Test
     public void testRoamingDataChanged() throws Exception {
@@ -3437,7 +3600,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
 
         mDataNetworkControllerUT.addNetworkRequest(tnr);
         processAllMessages();
@@ -3461,7 +3624,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
 
         mDataNetworkControllerUT.addNetworkRequest(tnr);
         processAllMessages();
@@ -3533,7 +3696,7 @@
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(
-                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone));
+                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN);
@@ -3649,7 +3812,7 @@
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(
-                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone));
+                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         // Everything should be disconnected.
@@ -3687,7 +3850,7 @@
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(
-                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone));
+                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         // Everything should be disconnected.
@@ -3910,7 +4073,7 @@
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(
-                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone));
+                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile);
@@ -3934,7 +4097,7 @@
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(
-                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone));
+                new TelephonyNetworkRequest(nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile);
@@ -3999,7 +4162,7 @@
         NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps,
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
-                nativeNetworkRequest, mPhone);
+                nativeNetworkRequest, mPhone, mFeatureFlags);
 
         mDataNetworkControllerUT.addNetworkRequest(networkRequest);
 
@@ -4051,7 +4214,7 @@
         NetworkRequest nativeNetworkRequest = new NetworkRequest(netCaps,
                 ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST);
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
-                nativeNetworkRequest, mPhone);
+                nativeNetworkRequest, mPhone, mFeatureFlags);
 
         mDataNetworkControllerUT.addNetworkRequest(networkRequest);
         processAllMessages();
@@ -4693,11 +4856,12 @@
                 ConnectivityManager.TYPE_MOBILE, 0, NetworkRequest.Type.REQUEST);
 
         mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
-                nativeNetworkRequest, mPhone));
+                nativeNetworkRequest, mPhone, mFeatureFlags));
         processAllMessages();
 
         // Intentionally create a new telephony request with the original native network request.
-        TelephonyNetworkRequest request = new TelephonyNetworkRequest(nativeNetworkRequest, mPhone);
+        TelephonyNetworkRequest request = new TelephonyNetworkRequest(
+                nativeNetworkRequest, mPhone, mFeatureFlags);
 
         mDataNetworkControllerUT.removeNetworkRequest(request);
         processAllFutureMessages();
@@ -4788,7 +4952,7 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                        .build(), mPhone));
+                        .build(), mPhone, mFeatureFlags));
         processAllMessages();
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE,
                 NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY);
@@ -4797,7 +4961,7 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
                         .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                        .build(), mPhone));
+                        .build(), mPhone, mFeatureFlags));
         processAllMessages();
         List<DataNetwork> dataNetworkList = getDataNetworks();
         assertThat(dataNetworkList).hasSize(1);
@@ -4867,12 +5031,16 @@
 
     @Test
     public void testNonTerrestrialNetwork() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
         mIsNonTerrestrialNetwork = true;
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         mDataNetworkControllerUT.addNetworkRequest(
-                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS));
+                createNetworkRequest(false, NetworkCapabilities.NET_CAPABILITY_RCS));
+        processAllMessages();
+        verifyAllDataDisconnected();
+
+        mDataNetworkControllerUT.addNetworkRequest(
+                createNetworkRequest(true, NetworkCapabilities.NET_CAPABILITY_RCS));
         processAllMessages();
         verifyConnectedNetworkHasDataProfile(mNtnDataProfile);
     }
@@ -5031,8 +5199,7 @@
     }
 
     @Test
-    public void testNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+    public void testNtnNetworkOnProvisioningProfileClassWithFlagEnabled() throws Exception {
         when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
         // Allowed data limit Unlimited
         mContextFixture.putIntResource(com.android.internal.R.integer
@@ -5044,7 +5211,7 @@
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         mDataNetworkControllerUT.addNetworkRequest(
-                createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_RCS));
+                createNetworkRequest(true, NetworkCapabilities.NET_CAPABILITY_RCS));
         processAllMessages();
 
         assertThat(mDataNetworkControllerUT.isEsimBootStrapProvisioningActivated()).isTrue();
@@ -5053,8 +5220,7 @@
     }
 
     @Test
-    public void testNonNtnNetworkOnProvisioningProfileClass_WithFlagEnabled() throws Exception {
-        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+    public void testNonNtnNetworkOnProvisioningProfileClassWithFlagEnabled() throws Exception {
         when(mFeatureFlags.esimBootstrapProvisioningFlag()).thenReturn(true);
         doReturn(new SubscriptionInfoInternal.Builder().setId(1)
                 .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING).build())
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index ebfc41a..19502f5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -320,13 +320,13 @@
     }
 
     private void serviceStateChanged(@Annotation.NetworkType int networkType,
-            @NetworkRegistrationInfo.RegistrationState int regState) {
-        serviceStateChanged(networkType, regState, null);
+            @NetworkRegistrationInfo.RegistrationState int regState, boolean isNtn) {
+        serviceStateChanged(networkType, regState, null, isNtn);
     }
 
     private void serviceStateChanged(@Annotation.NetworkType int networkType,
             @NetworkRegistrationInfo.RegistrationState int regState,
-            DataSpecificRegistrationInfo dsri) {
+            DataSpecificRegistrationInfo dsri, boolean isNtn) {
         ServiceState ss = new ServiceState();
         ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
@@ -334,6 +334,7 @@
                 .setRegistrationState(regState)
                 .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
                 .setDataSpecificInfo(dsri)
+                .setIsNonTerrestrialNetwork(isNtn)
                 .build());
 
         ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
@@ -410,9 +411,14 @@
         doReturn(FAKE_IMSI).when(mPhone).getSubscriberId();
         doReturn(true).when(mDataNetworkController)
                 .isNetworkRequestExisting(any(TelephonyNetworkRequest.class));
+        doReturn(Set.of(NetworkCapabilities.NET_CAPABILITY_IMS,
+                NetworkCapabilities.NET_CAPABILITY_EIMS, NetworkCapabilities.NET_CAPABILITY_XCAP))
+                .when(mDataConfigManager).getForcedCellularTransportCapabilities();
+        doReturn(true).when(mFeatureFlags).carrierEnabledSatelliteFlag();
+        doReturn(true).when(mFeatureFlags).satelliteInternet();
 
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, false/*isNtn*/);
     }
 
     @After
@@ -446,7 +452,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         setSuccessfulSetupDataResponse(
                 mMockedWwanDataServiceManager, 123, Collections.emptyList(), mDefaultQos);
@@ -551,12 +557,13 @@
                 .build();
         // Out of service
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri,
+                false/*isNtn*/);
 
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
@@ -597,7 +604,8 @@
                 .build();
         // Out of service
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri,
+                false/*isNtn*/);
 
         DataCallResponse response = new DataCallResponse.Builder()
                 .setCause(0)
@@ -653,7 +661,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
@@ -742,7 +750,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         List<TrafficDescriptor> tds = List.of(
                 new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -777,7 +785,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         List<TrafficDescriptor> tds = List.of(
                 new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -810,7 +818,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         List<TrafficDescriptor> tds = List.of(
                 new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -843,7 +851,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_CBS)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         List<TrafficDescriptor> tds = List.of(
                 new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -877,7 +885,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_CBS)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         List<TrafficDescriptor> tds = List.of(
                 new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -962,7 +970,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123);
 
@@ -1183,7 +1191,7 @@
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         networkRequestList.add(networkRequest);
 
         SimulatedCommands simulatedCommands2 = mock(SimulatedCommands.class);
@@ -1238,7 +1246,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
@@ -1335,7 +1343,7 @@
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         // Data disabled
         doReturn(false).when(mDataSettingsManager).isDataEnabled();
@@ -1371,14 +1379,14 @@
     @Test
     public void testRestrictedNetworkDataRoamingEnabled() throws Exception {
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
+                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, false/*isNtn*/);
 
         NetworkRequestList networkRequestList = new NetworkRequestList();
         // Restricted network request
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         // Data roaming disabled
         doReturn(false).when(mDataSettingsManager).isDataRoamingEnabled();
@@ -1516,7 +1524,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
                 mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
@@ -1620,7 +1628,7 @@
                         LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
                 .build();
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri, false/*isNtn*/);
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
@@ -1634,7 +1642,7 @@
                 .build();
         logd("Trigger non VoPS");
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri, false/*isNtn*/);
         // MMTEL should not be removed.
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
@@ -1651,7 +1659,7 @@
                         LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
                 .build();
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri, false/*isNtn*/);
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
@@ -1665,7 +1673,7 @@
                 .build();
         logd("Trigger non VoPS");
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
-                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri, false/*isNtn*/);
         // MMTEL should be removed to reflect the actual Vops status.
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse();
@@ -1724,7 +1732,7 @@
 
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder().addCapability(
-                        NetworkCapabilities.NET_CAPABILITY_SUPL).build(), mPhone);
+                        NetworkCapabilities.NET_CAPABILITY_SUPL).build(), mPhone, mFeatureFlags);
         mDataNetworkUT.attachNetworkRequests(new NetworkRequestList(networkRequest));
         processAllMessages();
 
@@ -1747,7 +1755,7 @@
 
         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder().addCapability(
-                        NetworkCapabilities.NET_CAPABILITY_SUPL).build(), mPhone);
+                        NetworkCapabilities.NET_CAPABILITY_SUPL).build(), mPhone, mFeatureFlags);
         mDataNetworkUT.attachNetworkRequests(new NetworkRequestList(networkRequest));
         processAllMessages();
 
@@ -1900,7 +1908,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
 
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
                 mDataServiceManagers, mInternetDataProfile, networkRequestList,
@@ -2044,7 +2052,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
                 mDataServiceManagers, m5gDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
@@ -2141,7 +2149,7 @@
         NetworkRequest.Builder builder = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
         builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-        networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone));
+        networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone, mFeatureFlags));
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
                 mDataServiceManagers, mImsDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
@@ -2248,7 +2256,7 @@
         NetworkRequestList networkRequestList = new NetworkRequestList();
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                .build(), mPhone));
+                .build(), mPhone, mFeatureFlags));
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123);
         mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
                 mDataServiceManagers, mImsDataProfile, networkRequestList,
@@ -2264,7 +2272,7 @@
         NetworkRequest.Builder builder = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
         if (isMmtel) builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-        networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone));
+        networkRequestList.add(new TelephonyNetworkRequest(builder.build(), mPhone, mFeatureFlags));
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
@@ -2277,6 +2285,37 @@
         processAllMessages();
     }
 
+    private void setupNonTerrestrialDataNetwork() {
+        NetworkRequestList networkRequestList = new NetworkRequestList();
+
+        networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .build(), mPhone, mFeatureFlags));
+        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        processAllMessages();
+    }
+
+    private void setupTerrestrialDataNetwork() {
+        NetworkRequestList networkRequestList = new NetworkRequestList();
+        networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                .build(), mPhone, mFeatureFlags));
+        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        processAllMessages();
+    }
+
     @Test
     public void testMmsCapabilityRemovedWhenMmsPreferredOnIwlan() throws Exception {
         doReturn(true).when(mFeatureFlags).forceIwlanMms();
@@ -2355,4 +2394,104 @@
 
         verify(mDataNetworkCallback).onQosSessionsChanged(newQosSessions);
     }
+
+    @Test
+    public void testIsTransportSatelliteSupportNonImsNonTerrestrialNetwork() throws Exception {
+        // Service state at Non-terrestrial network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, true/*isNtn*/);
+
+        // set up data network with transport type satellite + Internet
+        setupNonTerrestrialDataNetwork();
+
+        //Check now transport type for the data network is satellite
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)).isTrue();
+    }
+
+    @Test
+    public void testIsTransportSatelliteSupportWithImsNonTerrestrialNetwork() throws Exception {
+        // Service state at Non-terrestrial network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, true/*isNtn*/);
+
+        // set up data network with transport type satellite + IMS
+        createImsDataNetwork(false/*isMmtel*/);
+
+        //Check transport type for the data network is Cellular for Ims at non-terrestrial network
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue();
+    }
+
+    @Test
+    public void testSatelliteTransportSupportedNonImsTerrestrialToNonTerrestrial()
+            throws Exception {
+        // Service state at terrestrial network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, false/*isNtn*/);
+
+        // set up data network with transport type cellular + Internet
+        setupTerrestrialDataNetwork();
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue();
+
+        // Service State change terrestrial to non-terrestrial
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, true/*isNtn*/);
+
+        // Make sure transport type for the data network is still Cellular
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue();
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)).isFalse();
+
+        // Disconnect the Data call
+        mDataNetworkUT.sendMessage(19/*EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE*/, 0/*Success*/);
+        processAllMessages();
+
+        // set up data network with transport type satellite + Internet
+        setupNonTerrestrialDataNetwork();
+
+        //Check now transport type for the data network is satellite
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)).isTrue();
+    }
+
+    @Test
+    public void testSatelliteTransportSupportedNonImsNonTerrestrialToTerrestrial()
+            throws Exception {
+        // Service state at non-terrestrial network
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, true/*isNtn*/);
+
+        // set up data network with transport type satellite + Internet
+        setupNonTerrestrialDataNetwork();
+
+        //Check now transport type for the data network is satellite
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)).isTrue();
+
+        // Service State change non-terrestrial to terrestrial
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, false/*isNtn*/);
+
+        // Make sure transport type for the data network is still satellite
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE)).isTrue();
+
+        // Make sure transport type for the data network is not cellular
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isFalse();
+
+        // Disconnect the Data call
+        mDataNetworkUT.sendMessage(19/*EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE*/, 0/*Success*/);
+        processAllMessages();
+
+        // set up data network with transport type cellular + Internet
+        setupTerrestrialDataNetwork();
+
+        //Check now transport type for the data network is cellular
+        assertThat(mDataNetworkUT.getNetworkCapabilities()
+                .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue();
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
index 44d207d..3d6b4f4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -888,7 +888,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
@@ -899,7 +899,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)
                 .build();
-        tnr = new TelephonyNetworkRequest(request, mPhone);
+        tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
@@ -909,7 +909,7 @@
         request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 .build();
-        tnr = new TelephonyNetworkRequest(request, mPhone);
+        tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
@@ -918,7 +918,7 @@
         request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                 .build();
-        tnr = new TelephonyNetworkRequest(request, mPhone);
+        tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dp).isNull();
@@ -931,7 +931,7 @@
         request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                 .build();
-        tnr = new TelephonyNetworkRequest(request, mPhone);
+        tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_NR, false, false , false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
@@ -943,7 +943,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_GSM, false, false, false);
         // Should not find data profile due to RAT incompatible.
@@ -955,7 +955,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -973,7 +973,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
@@ -986,7 +986,7 @@
         tnr = new TelephonyNetworkRequest(new NetworkRequest(new NetworkCapabilities()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                 .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
-                0, NetworkRequest.Type.REQUEST), mPhone);
+                0, NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
@@ -1002,7 +1002,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
@@ -1018,7 +1018,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
@@ -1036,7 +1036,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, true, false, false);
 
@@ -1050,7 +1050,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -1090,7 +1090,7 @@
         TelephonyNetworkRequest dunTnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dunDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         DataNetwork dunInternetNetwork = Mockito.mock(DataNetwork.class);
@@ -1189,7 +1189,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isNull();
@@ -1198,7 +1198,7 @@
         tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
@@ -1207,7 +1207,7 @@
         tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isEqualTo(null);
@@ -1237,7 +1237,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isNull();
@@ -1246,7 +1246,7 @@
         tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
@@ -1255,7 +1255,7 @@
         tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile).isEqualTo(null);
@@ -1291,7 +1291,7 @@
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 new TelephonyNetworkRequest(new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                        .build(), mPhone),
+                        .build(), mPhone, mFeatureFlags),
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN);
     }
@@ -1301,7 +1301,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         // This should get the merged data profile after deduping.
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
@@ -1439,7 +1439,7 @@
     public void testDefaultEmergencyDataProfileValid() {
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
@@ -1456,7 +1456,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -1522,7 +1522,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         changeSimStateTo(TelephonyManager.SIM_STATE_LOADED);
         mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
         processAllMessages();
@@ -1828,7 +1828,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
@@ -1852,7 +1852,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false);
 
@@ -1883,7 +1883,7 @@
 
         // Verify the we can get the previously permanent failed data profile again.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                new TelephonyNetworkRequest(request, mPhone),
+                new TelephonyNetworkRequest(request, mPhone, mFeatureFlags),
                 TelephonyManager.NETWORK_TYPE_LTE, false, false, false))
                 .isNotNull();
     }
@@ -1902,7 +1902,7 @@
         // flag is enabled at data profile, during esim bootstrap provisioning
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(
@@ -1912,7 +1912,7 @@
         // is enabled at data profile, during esim bootstrap provisioning
         tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                  .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                 .build(), mPhone);
+                 .build(), mPhone, mFeatureFlags);
         dataProfile  = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("IMS_APN");
@@ -1921,7 +1921,7 @@
         // is disabled at data profile, during esim bootstrap provisioning
         tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         dataProfile  = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
         assertThat(dataProfile).isEqualTo(null);
@@ -1930,7 +1930,7 @@
         // is disabled at data profile, during esim bootstrap provisioning
         tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
         assertThat(dataProfile).isEqualTo(null);
@@ -1950,7 +1950,7 @@
         // type
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, false, true, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(
@@ -1972,7 +1972,7 @@
         // type
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 tnr, TelephonyManager.NETWORK_TYPE_LTE, true, true, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(RCS_APN1);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
index 2541bd1..c413f83 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
@@ -292,7 +292,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
         mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile1,
@@ -316,7 +316,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
         mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3,
@@ -345,7 +345,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
         mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3,
@@ -432,7 +432,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
 
@@ -535,7 +535,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
         mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile1,
@@ -568,7 +568,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
 
@@ -647,7 +647,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
 
@@ -709,7 +709,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
 
@@ -798,7 +798,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
         mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile1,
@@ -839,7 +839,7 @@
         NetworkRequest request = new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
-        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone, mFeatureFlags);
         DataNetworkController.NetworkRequestList
                 networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
 
@@ -853,7 +853,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                .build(), mPhone);
+                .build(), mPhone, mFeatureFlags);
         assertThat(mDataRetryManagerUT.isSimilarNetworkRequestRetryScheduled(tnr,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isTrue();
         assertThat(mDataRetryManagerUT.isSimilarNetworkRequestRetryScheduled(tnr,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java
index ea8a7d7..38de618 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataUtilsTest.java
@@ -18,24 +18,32 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import java.util.List;
 
 public class DataUtilsTest extends TelephonyTest {
 
+    private FeatureFlags mFeatureFlags;
+
     @Before
     public void setUp() throws Exception {
         logd("DataUtilsTest +Setup!");
         super.setUp(getClass().getSimpleName());
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
+        doReturn(true).when(mFeatureFlags).satelliteInternet();
         logd("DataUtilsTest -Setup!");
     }
 
@@ -57,10 +65,13 @@
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE,
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE,
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE,
+                NetworkCapabilities.NET_CAPABILITY_IMS,
+                NetworkCapabilities.NET_CAPABILITY_IMS,
         };
 
         int requestId = 0;
         int enterpriseId = 1;
+        int transportType = NetworkCapabilities.TRANSPORT_CELLULAR;
         TelephonyNetworkRequest networkRequest;
         for (int netCap : netCaps) {
             if (netCap == NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) {
@@ -69,24 +80,31 @@
                                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                                 .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                                 .addEnterpriseId(enterpriseId).build(), -1, requestId++,
-                        NetworkRequest.Type.REQUEST), mPhone);
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
                 if (enterpriseId == 1) enterpriseId++;
+            } else if (netCap == NetworkCapabilities.NET_CAPABILITY_IMS) {
+                networkRequest = new TelephonyNetworkRequest(new NetworkRequest(
+                        new NetworkCapabilities.Builder()
+                                .addTransportType(transportType)
+                                .addCapability(netCap).build(), -1, requestId++,
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
+                transportType = NetworkCapabilities.TRANSPORT_SATELLITE;
             } else {
                 networkRequest = new TelephonyNetworkRequest(new NetworkRequest(
                         new NetworkCapabilities.Builder()
                                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                                 .addCapability(netCap).build(), -1, requestId++,
-                        NetworkRequest.Type.REQUEST), mPhone);
+                        NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
             }
             requestList.add(networkRequest);
         }
 
-        assertThat(requestList).hasSize(8);
+        assertThat(requestList).hasSize(10);
 
         List<NetworkRequestList> requestListList =
-                DataUtils.getGroupedNetworkRequestList(requestList);
+                DataUtils.getGroupedNetworkRequestList(requestList, mFeatureFlags);
 
-        assertThat(requestListList).hasSize(5);
+        assertThat(requestListList).hasSize(7);
         requestList = requestListList.get(0);
         assertThat(requestList).hasSize(1);
         assertThat(requestList.get(0).hasCapability(
@@ -100,26 +118,40 @@
                 NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue();
 
         requestList = requestListList.get(2);
-        assertThat(requestList).hasSize(2);
+        assertThat(requestList).hasSize(1);
         assertThat(requestList.get(0).hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
-        assertThat(requestList.get(1).hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
+                NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue();
+        assertThat(requestList.get(0).getNativeNetworkRequest().hasTransport(
+                NetworkCapabilities.TRANSPORT_CELLULAR)).isTrue();
 
         requestList = requestListList.get(3);
         assertThat(requestList).hasSize(1);
         assertThat(requestList.get(0).hasCapability(
-                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
-        assertThat(requestList.get(0).getCapabilityDifferentiator() == 1).isTrue();
+                NetworkCapabilities.NET_CAPABILITY_IMS)).isTrue();
+        assertThat(requestList.get(0).getNativeNetworkRequest().hasTransport(
+                NetworkCapabilities.TRANSPORT_SATELLITE)).isTrue();
 
         requestList = requestListList.get(4);
         assertThat(requestList).hasSize(2);
         assertThat(requestList.get(0).hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
+        assertThat(requestList.get(1).hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
+
+        requestList = requestListList.get(5);
+        assertThat(requestList).hasSize(1);
+        assertThat(requestList.get(0).hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
-        assertThat(requestList.get(0).getCapabilityDifferentiator() == 2).isTrue();
+        assertThat(requestList.get(0).getCapabilityDifferentiator()).isEqualTo(1);
+
+        requestList = requestListList.get(6);
+        assertThat(requestList).hasSize(2);
+        assertThat(requestList.get(0).hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
+        assertThat(requestList.get(0).getCapabilityDifferentiator()).isEqualTo(2);
         assertThat(requestList.get(1).hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
-        assertThat(requestList.get(1).getCapabilityDifferentiator() == 2).isTrue();
+        assertThat(requestList.get(1).getCapabilityDifferentiator()).isEqualTo(2);
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
index 00da66d..8420acf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -221,8 +221,8 @@
         NetworkRequest internetNetworkRequest = addInternetNetworkRequest(null, 50);
 
         assertFalse("phone active after request", mPhoneSwitcherUT
-                .shouldApplyNetworkRequest(
-                        new TelephonyNetworkRequest(internetNetworkRequest, mPhone), 0));
+                .shouldApplyNetworkRequest(new TelephonyNetworkRequest(
+                        internetNetworkRequest, mPhone, mFeatureFlags), 0));
 
         // not registered yet - shouldn't inc
         verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong());
@@ -628,9 +628,9 @@
         // Phone 0 (sub 1) should be activated as it has default data sub.
         assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
 
         // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated.
         mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, null);
@@ -645,9 +645,9 @@
 
         // switch shouldn't occur due to the higher priority event
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId());
         assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId());
 
@@ -657,9 +657,9 @@
         assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId());
         assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
     }
 
     @Test
@@ -751,13 +751,13 @@
         verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any());
         verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 0));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 1));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 1));
 
         // Set sub 2 as preferred sub should make phone 1 preferredDataModem
         doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService
@@ -773,13 +773,13 @@
         processAllMessages();
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 0));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 0));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 1));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 1));
 
         clearInvocations(mMockRadioConfig);
         clearInvocations(mActivePhoneSwitchHandler);
@@ -796,13 +796,13 @@
         processAllMessages();
         verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 0));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(mmsRequest, mPhone), 1));
+                new TelephonyNetworkRequest(mmsRequest, mPhone, mFeatureFlags), 1));
 
         // SetDataAllowed should never be triggered.
         verify(mCommandsInterface0, never()).setDataAllowed(anyBoolean(), any());
@@ -1038,9 +1038,9 @@
         setDefaultDataSubId(1);
         NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         clearInvocations(mMockRadioConfig);
         setAllPhonesInactive();
         // Initialization done.
@@ -1050,18 +1050,18 @@
         notifyPhoneAsInCall(mPhone2);
         verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
 
         // Phone2 has active call, and data is on. So data switch to it.
         doReturn(true).when(mPhone).isUserDataEnabled();
         notifyDataEnabled(true);
         verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         clearInvocations(mMockRadioConfig);
 
         // Phone2(nDDS) call ended. But Phone1 having cross-SIM call. Don't switch.
@@ -1070,9 +1070,9 @@
         notifyPhoneAsInactive(mPhone2);
         verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
 
         // Phone(DDS) call ended.
         // Honor auto data switch's suggestion: if DDS is OOS, auto switch to Phone2(nDDS).
@@ -1083,9 +1083,9 @@
         // verify immediately switch back to DDS upon call ends
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
 
         // verify the attempt to do auto data switch to Phone2(nDDS)
         processAllFutureMessages();
@@ -1098,9 +1098,9 @@
         notifyPhoneAsInHoldingCall(mPhone2);
         verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
     }
 
     @Test
@@ -1115,9 +1115,9 @@
         setDefaultDataSubId(1);
         NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         clearInvocations(mMockRadioConfig);
         setAllPhonesInactive();
         // Initialization done.
@@ -1127,17 +1127,17 @@
         notifyPhoneAsInCall(mPhone2);
         verify(mMockRadioConfig).setPreferredDataModem(eq(1), any());
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
 
         // During the active call, user turns off data, should immediately switch back to DDS
         notifyDataEnabled(false);
         verify(mMockRadioConfig).setPreferredDataModem(eq(0), any());
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
     }
 
     @Test
@@ -1165,16 +1165,16 @@
         setDefaultDataSubId(1);
         NetworkRequest internetRequest = addInternetNetworkRequest(2, 50);
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
 
         // Restricted network request will should be applied.
         internetRequest = addInternetNetworkRequest(2, 50, true);
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
     }
 
     @Test
@@ -1605,9 +1605,9 @@
         setDefaultDataSubId(1);
         NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         clearInvocations(mMockRadioConfig);
         setAllPhonesInactive();
         // Initialization done.
@@ -1646,9 +1646,9 @@
         setDefaultDataSubId(1);
         NetworkRequest internetRequest = addInternetNetworkRequest(null, 50);
         assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 0));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 0));
         assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                new TelephonyNetworkRequest(internetRequest, mPhone), 1));
+                new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), 1));
         clearInvocations(mMockRadioConfig);
         setAllPhonesInactive();
         // Initialization done.
@@ -1909,10 +1909,10 @@
             if (defaultDataSub == (i + 1)) {
                 // sub id is always phoneId+1 for testing
                 assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                        new TelephonyNetworkRequest(internetRequest, mPhone), i));
+                        new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), i));
             } else {
                 assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest(
-                        new TelephonyNetworkRequest(internetRequest, mPhone), i));
+                        new TelephonyNetworkRequest(internetRequest, mPhone, mFeatureFlags), i));
             }
         }
     }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java
index ad99eaf..e1a0eac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java
@@ -135,7 +135,8 @@
     }
 
     private void activatePhoneInPhoneSwitcher(int phoneId, NetworkRequest nr, boolean active) {
-        TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(nr, mPhone);
+        TelephonyNetworkRequest networkRequest =
+                new TelephonyNetworkRequest(nr, mPhone, mFeatureFlags);
         doReturn(active).when(mPhoneSwitcher).shouldApplyNetworkRequest(
                 eq(networkRequest), eq(phoneId));
         mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java
index 26a9fde..1517006 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java
@@ -18,6 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
@@ -123,7 +126,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build();
         TelephonyNetworkRequest internetRequest =
-                new TelephonyNetworkRequest(nativeRequest, mPhone);
+                new TelephonyNetworkRequest(nativeRequest, mPhone, mFeatureFlags);
         assertThat(internetRequest.getNativeNetworkRequest()).isEqualTo(nativeRequest);
     }
 
@@ -132,11 +135,11 @@
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         TelephonyNetworkRequest imsRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         assertThat(internetRequest.getPriority()).isEqualTo(20);
         assertThat(imsRequest.getPriority()).isEqualTo(40);
@@ -152,7 +155,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                         .setNetworkSpecifier(telephonyNetworkSpecifier)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         assertThat(internetRequest.getNetworkSpecifier()).isEqualTo(telephonyNetworkSpecifier);
     }
 
@@ -164,7 +167,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         assertThat(internetRequest.getCapabilities()).isEqualTo(
                 new int[]{NetworkCapabilities.NET_CAPABILITY_INTERNET,
                         NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED,
@@ -191,7 +194,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         assertThat(request.getApnTypeNetworkCapability())
                 .isEqualTo(NetworkCapabilities.NET_CAPABILITY_SUPL);
 
@@ -200,7 +203,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         assertThat(request.getApnTypeNetworkCapability())
                 .isEqualTo(NetworkCapabilities.NET_CAPABILITY_FOTA);
 
@@ -209,7 +212,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         assertThat(request.getApnTypeNetworkCapability())
                 .isEqualTo(NetworkCapabilities.NET_CAPABILITY_EIMS);
     }
@@ -219,7 +222,7 @@
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         NetworkCapabilities caps = new NetworkCapabilities.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
@@ -233,7 +236,7 @@
         TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         caps = new NetworkCapabilities.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
@@ -250,15 +253,15 @@
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         TelephonyNetworkRequest mmsRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         DataProfile internetDataProfile = new DataProfile.Builder()
                 .setApnSetting(INTERNET_APN_SETTING)
                 .build();
@@ -281,12 +284,12 @@
         TelephonyNetworkRequest enterpriseRequest1 = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         TelephonyNetworkRequest enterpriseRequest2 = new TelephonyNetworkRequest(
                 new NetworkRequest(new NetworkCapabilities()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
-                        0, NetworkRequest.Type.REQUEST), mPhone);
+                        0, NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
 
         DataProfile enterpriseDataProfile1 = new DataProfile.Builder()
                 .setTrafficDescriptor(new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -309,18 +312,18 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
         TelephonyNetworkRequest enterpriseRequest2 = new TelephonyNetworkRequest(
                 new NetworkRequest(new NetworkCapabilities()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
-                        0, NetworkRequest.Type.REQUEST), mPhone);
+                        0, NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
         TelephonyNetworkRequest internetRequest = new TelephonyNetworkRequest(
                 new NetworkRequest(new NetworkCapabilities()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET),
                         ConnectivityManager.TYPE_NONE,
-                        0, NetworkRequest.Type.REQUEST), mPhone);
+                        0, NetworkRequest.Type.REQUEST), mPhone, mFeatureFlags);
 
         DataProfile enterpriseDataProfile = new DataProfile.Builder()
                 .setApnSetting(ENTERPRISE_APN_SETTING)
@@ -342,12 +345,12 @@
         TelephonyNetworkRequest urllcRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         TelephonyNetworkRequest embbRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         DataProfile urllcDataProfile = new DataProfile.Builder()
                 .setTrafficDescriptor(new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -364,12 +367,12 @@
         TelephonyNetworkRequest urllcRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         TelephonyNetworkRequest embbRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         DataProfile embbDataProfile = new DataProfile.Builder()
                 .setTrafficDescriptor(new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -386,12 +389,12 @@
         TelephonyNetworkRequest cbsRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_CBS)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         TelephonyNetworkRequest embbRequest = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
-                        .build(), mPhone);
+                        .build(), mPhone, mFeatureFlags);
 
         DataProfile cbsDataProfile = new DataProfile.Builder()
                 .setTrafficDescriptor(new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(
@@ -402,4 +405,92 @@
         assertThat(cbsRequest.canBeSatisfiedBy(cbsDataProfile)).isTrue();
         assertThat(embbRequest.canBeSatisfiedBy(cbsDataProfile)).isFalse();
     }
+
+    @Test
+    public void testSatelliteNetworkRequest() {
+        when(mFeatureFlags.satelliteInternet()).thenReturn(true);
+        TelephonyNetworkRequest satelliteRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                        .addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE)
+                        .build(), mPhone, mFeatureFlags);
+
+        TelephonyNetworkRequest generalRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                        .build(), mPhone, mFeatureFlags);
+
+        ApnSetting satelliteInternetApn = new ApnSetting.Builder()
+                .setEntryName("apn")
+                .setApnName("apn")
+                .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+                .setCarrierEnabled(true)
+                .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE)
+                .build();
+
+        ApnSetting cellularInternetApn = new ApnSetting.Builder()
+                .setEntryName("apn")
+                .setApnName("apn")
+                .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+                .setCarrierEnabled(true)
+                .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_CELLULAR)
+                .build();
+
+        DataProfile satelliteInternetDataProfile = new DataProfile.Builder()
+                .setApnSetting(satelliteInternetApn)
+                .build();
+
+        DataProfile cellularInternetDataProfile = new DataProfile.Builder()
+                .setApnSetting(cellularInternetApn)
+                .build();
+
+        assertThat(satelliteRequest.canBeSatisfiedBy(satelliteInternetDataProfile)).isTrue();
+        assertThat(generalRequest.canBeSatisfiedBy(satelliteInternetDataProfile)).isTrue();
+        assertThat(satelliteRequest.canBeSatisfiedBy(cellularInternetDataProfile)).isFalse();
+        assertThat(generalRequest.canBeSatisfiedBy(cellularInternetDataProfile)).isTrue();
+    }
+
+    @Test
+    public void testCellularNetworkRequest() {
+        doReturn(true).when(mFeatureFlags).satelliteInternet();
+        TelephonyNetworkRequest cellularRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+                        .build(), mPhone, mFeatureFlags);
+
+        TelephonyNetworkRequest generalRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                        .build(), mPhone, mFeatureFlags);
+
+        ApnSetting satelliteInternetApn = new ApnSetting.Builder()
+                .setEntryName("apn")
+                .setApnName("apn")
+                .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+                .setCarrierEnabled(true)
+                .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE)
+                .build();
+
+        ApnSetting cellularInternetApn = new ApnSetting.Builder()
+                .setEntryName("apn")
+                .setApnName("apn")
+                .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT)
+                .setCarrierEnabled(true)
+                .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_CELLULAR)
+                .build();
+
+        DataProfile satelliteInternetDataProfile = new DataProfile.Builder()
+                .setApnSetting(satelliteInternetApn)
+                .build();
+
+        DataProfile cellularInternetDataProfile = new DataProfile.Builder()
+                .setApnSetting(cellularInternetApn)
+                .build();
+
+        assertThat(cellularRequest.canBeSatisfiedBy(satelliteInternetDataProfile)).isFalse();
+        assertThat(generalRequest.canBeSatisfiedBy(satelliteInternetDataProfile)).isTrue();
+        assertThat(cellularRequest.canBeSatisfiedBy(cellularInternetDataProfile)).isTrue();
+        assertThat(generalRequest.canBeSatisfiedBy(cellularInternetDataProfile)).isTrue();
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
index 47f8ce2..5fd7a77 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
@@ -22,6 +22,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -42,8 +43,10 @@
 import android.telecom.PhoneAccount;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.DisconnectCause;
 import android.telephony.DomainSelectionService;
 import android.telephony.EmergencyRegistrationResult;
+import android.telephony.PreciseDisconnectCause;
 import android.telephony.data.ApnSetting;
 import android.telephony.ims.ImsReasonInfo;
 import android.testing.AndroidTestingRunner;
@@ -773,6 +776,26 @@
         verify(mDomainSelectionController, times(1)).selectDomain(any(), eq(transportCallback));
     }
 
+    @Test
+    @SmallTest
+    public void testSetDisconnectCause() throws Exception {
+        mDsc = createConnection(mPhone, SELECTOR_TYPE_CALLING, true,
+                mDomainSelectionController);
+
+        assertEquals(DisconnectCause.NOT_VALID, mDsc.getDisconnectCause());
+        assertEquals(PreciseDisconnectCause.NOT_VALID, mDsc.getPreciseDisconnectCause());
+        assertEquals(mPhone.getPhoneId(), mDsc.getPhoneId());
+
+        String reason = "No SIM or SIM error";
+        mDsc.setDisconnectCause(DisconnectCause.ICC_ERROR,
+                PreciseDisconnectCause.NO_VALID_SIM, reason);
+
+        assertEquals(DisconnectCause.ICC_ERROR, mDsc.getDisconnectCause());
+        assertEquals(PreciseDisconnectCause.NO_VALID_SIM, mDsc.getPreciseDisconnectCause());
+        assertEquals(reason, mDsc.getReasonMessage());
+        assertEquals(mPhone.getPhoneId(), mDsc.getPhoneId());
+    }
+
     private DomainSelectionConnection createConnection(Phone phone, int selectorType,
             boolean isEmergency, DomainSelectionController controller) throws Exception {
         DomainSelectionConnection dsc = new DomainSelectionConnection(phone,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
index 699ee7b..6260761 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -260,6 +260,46 @@
         verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any());
     }
 
+    @Test
+    @SmallTest
+    public void startEmergencyCall_radioOff_turnOnRadioHangupCallTurnOffRadio() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                true /* isSuplDdsSwitchRequiredForEmergencyCall */);
+        // Create test Phones and set radio off
+        Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */,
+                false /* isRadioOn */);
+        setConfigForDdsSwitch(testPhone, null,
+                CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "150");
+        ServiceState ss = mock(ServiceState.class);
+        doReturn(ss).when(mSST).getServiceState();
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .build();
+        doReturn(nri).when(ss).getNetworkRegistrationInfo(anyInt(), anyInt());
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(testPhone,
+                mTestConnection1, false);
+
+        // startEmergencyCall should trigger radio on
+        ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
+                .forClass(RadioOnStateListener.Callback.class);
+        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
+                eq(false), eq(DEFAULT_WAIT_FOR_IN_SERVICE_TIMEOUT_MS));
+
+        // Hangup the call
+        emergencyStateTracker.endCall(mTestConnection1);
+
+        // onTimeout and isOkToCall should return true even in case radion is off
+        assertTrue(callback.getValue()
+                .isOkToCall(testPhone, ServiceState.STATE_POWER_OFF, false));
+        assertTrue(callback.getValue()
+                .onTimeout(testPhone, ServiceState.STATE_POWER_OFF, false));
+
+        callback.getValue().onComplete(null, true);
+
+        assertFalse(future.isDone());
+    }
+
     /**
      * Test that if startEmergencyCall fails to turn on radio, then it's future completes with
      * DisconnectCause.POWER_OFF.
@@ -577,6 +617,9 @@
         assertTrue(emergencyStateTracker.isInEcm());
         assertFalse(emergencyStateTracker.isInCdmaEcm());
         assertTrue(emergencyStateTracker.isInImsEcm());
+
+        assertTrue(emergencyStateTracker.isInEcm(testPhone));
+        assertFalse(emergencyStateTracker.isInEcm(getPhone(1)));
     }
 
     /**
@@ -2837,6 +2880,94 @@
         verify(mContext, never()).sendStickyBroadcastAsUser(any(), any());
     }
 
+    @Test
+    @SmallTest
+    public void testEnsureExecutionOrderOfExitEmergencyModeThenSetEmergencyMode() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true,
+                /* isRadioOn= */ true);
+        setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT);
+
+        // First trial
+        CompletableFuture<Integer> unused = emergencyStateTracker.startEmergencyCall(phone0,
+                mTestConnection1, false);
+        processAllMessages();
+
+        assertTrue(emergencyStateTracker.isInEmergencyMode());
+        assertTrue(emergencyStateTracker.isInEmergencyCall());
+        verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+
+        ArgumentCaptor<Message> msgCaptor = ArgumentCaptor.forClass(Message.class);
+        emergencyStateTracker.endCall(mTestConnection1);
+        processAllMessages();
+
+        verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+        verify(phone0).exitEmergencyMode(msgCaptor.capture());
+
+        Message msg = msgCaptor.getValue();
+
+        assertNotNull(msg);
+
+        // Second trial
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencyCall(phone0,
+                mTestConnection2, false);
+        processAllMessages();
+
+        assertFalse(future.isDone());
+        verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+
+        AsyncResult.forMessage(msg, null, null);
+        msg.sendToTarget();
+        processAllMessages();
+
+        verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+    }
+
+    @Test
+    @SmallTest
+    public void testEnsureExecutionOrderOfExitEmergencyModeThenSetEmergencyModeWithSms() {
+        EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker(
+                /* isSuplDdsSwitchRequiredForEmergencyCall= */ true);
+        Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false,
+                /* isRadioOn= */ true);
+        setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT);
+        CompletableFuture<Integer> future = emergencyStateTracker.startEmergencySms(phone0,
+                TEST_SMS_ID, false);
+        processAllMessages();
+
+        assertTrue(emergencyStateTracker.isInEmergencyMode());
+        verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+
+        assertTrue(emergencyStateTracker.getEmergencyRegistrationResult().equals(E_REG_RESULT));
+        // Expect: DisconnectCause#NOT_DISCONNECTED.
+        assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED),
+                Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
+
+        ArgumentCaptor<Message> msgCaptor = ArgumentCaptor.forClass(Message.class);
+        emergencyStateTracker.endSms(TEST_SMS_ID, true, DOMAIN_CS);
+
+        verify(phone0).exitEmergencyMode(msgCaptor.capture());
+
+        Message msg = msgCaptor.getValue();
+
+        assertNotNull(msg);
+
+        // Dial emergency call
+        future = emergencyStateTracker.startEmergencyCall(phone0,
+                mTestConnection2, false);
+        processAllMessages();
+
+        assertFalse(future.isDone());
+        verify(phone0, times(1)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+
+        AsyncResult.forMessage(msg, null, null);
+        msg.sendToTarget();
+        processAllMessages();
+
+        verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class));
+    }
+
     private EmergencyStateTracker setupEmergencyStateTracker(
             boolean isSuplDdsSwitchRequiredForEmergencyCall) {
         doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java
index 5a6fdc2..037f82c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java
@@ -205,7 +205,7 @@
         verify(mCallback).onComplete(eq(mListener), eq(false));
         verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(false), eq(false), eq(false));
         verify(mSatelliteController, never()).requestSatelliteEnabled(
-                anyInt(), eq(false), eq(false), any());
+                anyInt(), eq(false), eq(false), eq(false), any());
     }
 
     @Test
@@ -225,7 +225,7 @@
         verify(mCallback).onComplete(eq(mListener), eq(false));
         verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false));
         verify(mSatelliteController, never()).requestSatelliteEnabled(
-                anyInt(), eq(false), eq(false), any());
+                anyInt(), eq(false), eq(false), eq(false), any());
     }
 
     @Test
@@ -246,7 +246,7 @@
         verify(mCallback).onComplete(eq(mListener), eq(false));
         verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false));
         verify(mSatelliteController, times(2)).requestSatelliteEnabled(
-                anyInt(), eq(false), eq(false), any());
+                anyInt(), eq(false), eq(false), eq(false), any());
     }
 
     @Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
index d63dc3c..2e64c46 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/DataCallSessionStatsTest.java
@@ -19,7 +19,9 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -308,4 +310,49 @@
         assertTrue(stats.oosAtEnd);
         assertFalse(stats.ongoing);
     }
+
+    @Test
+    public void testIsNtn() {
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+
+        mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+        mDataCallSessionStats.onSetupDataCallResponse(
+                mDefaultImsResponse,
+                TelephonyManager.NETWORK_TYPE_LTE,
+                ApnSetting.TYPE_IMS,
+                ApnSetting.PROTOCOL_IP,
+                DataFailCause.NONE);
+
+        mDataCallSessionStats.setTimeMillis(60000L);
+        mDataCallSessionStats.conclude();
+
+        ArgumentCaptor<DataCallSession> callCaptor =
+                ArgumentCaptor.forClass(DataCallSession.class);
+        verify(mPersistAtomsStorage).addDataCallSession(callCaptor.capture());
+        DataCallSession stats = callCaptor.getValue();
+
+        assertTrue(stats.isNtn);
+
+        reset(mPersistAtomsStorage);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any()))
+                .thenReturn(false);
+
+        mDataCallSessionStats.onSetupDataCall(ApnSetting.TYPE_IMS);
+        mDataCallSessionStats.onSetupDataCallResponse(
+                mDefaultImsResponse,
+                TelephonyManager.NETWORK_TYPE_LTE,
+                ApnSetting.TYPE_IMS,
+                ApnSetting.PROTOCOL_IP,
+                DataFailCause.NONE);
+
+        mDataCallSessionStats.setTimeMillis(60000L);
+        mDataCallSessionStats.conclude();
+
+
+        verify(mPersistAtomsStorage).addDataCallSession(callCaptor.capture());
+        stats = callCaptor.getValue();
+
+        assertFalse(stats.isNtn);
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
index 16dab44..27878d1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
@@ -30,15 +30,20 @@
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.NetworkRegistrationInfo;
@@ -58,6 +63,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
@@ -76,6 +82,9 @@
 
     private TestableServiceStateStats mServiceStateStats;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static class TestableServiceStateStats extends ServiceStateStats {
         private long mTimeMillis = START_TIME_MILLIS;
 
@@ -1324,6 +1333,34 @@
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
+    @Test
+    public void testIsNtn() {
+        // Using default service state for LTE
+        mServiceStateStats.onServiceStateChanged(mServiceState);
+        mServiceStateStats.incTimeMillis(100L);
+        mServiceStateStats.conclude();
+
+        ArgumentCaptor<CellularServiceState> captor =
+                ArgumentCaptor.forClass(CellularServiceState.class);
+        verify(mPersistAtomsStorage)
+                .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+        CellularServiceState state = captor.getValue();
+        assertFalse(state.isNtn);
+
+        reset(mPersistAtomsStorage);
+        reset(mServiceState);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+        mServiceStateStats.onServiceStateChanged(mServiceState);
+        mServiceStateStats.incTimeMillis(100L);
+        mServiceStateStats.conclude();
+
+        verify(mPersistAtomsStorage)
+                .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+        state = captor.getValue();
+        assertTrue(state.isNtn);
+    }
+
     private void mockWwanPsRat(@NetworkType int rat) {
         mockWwanRat(
                 NetworkRegistrationInfo.DOMAIN_PS,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
index 58cc516..edc481a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java
@@ -34,15 +34,19 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.os.Looper;
@@ -2753,6 +2757,36 @@
         assertProtoEquals(expectedRatUsage, ratUsage.get()[0]);
     }
 
+    @Test
+    public void testIsNtn() {
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any())).thenReturn(true);
+
+        mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+        mVoiceCallSessionStats0.setTimeMillis(2200L);
+        mVoiceCallSessionStats0.onImsCallTerminated(mImsConnection0,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, 0));
+
+        ArgumentCaptor<VoiceCallSession> callCaptor =
+                ArgumentCaptor.forClass(VoiceCallSession.class);
+        verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+        VoiceCallSession session = callCaptor.getValue();
+        assertTrue(session.isNtn);
+
+        reset(mPersistAtomsStorage);
+        reset(mServiceState);
+
+        when(mSatelliteController.isInSatelliteModeForCarrierRoaming(any()))
+                .thenReturn(false);
+        mVoiceCallSessionStats0.onImsDial(mImsConnection0);
+        mVoiceCallSessionStats0.setTimeMillis(2200L);
+        mVoiceCallSessionStats0.onImsCallTerminated(mImsConnection0,
+                new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, 0));
+
+        verify(mPersistAtomsStorage, times(1)).addVoiceCallSession(callCaptor.capture());
+        session = callCaptor.getValue();
+        assertFalse(session.isNtn);
+    }
+
     private AtomicReference<VoiceCallRatUsage[]> setupRatUsageCapture() {
         final AtomicReference<VoiceCallRatUsage[]> ratUsage = new AtomicReference<>(null);
         doAnswer(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
new file mode 100644
index 0000000..78322ff
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramControllerTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.satellite;
+
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE;
+import static android.telephony.satellite.SatelliteManager.DATAGRAM_TYPE_UNKNOWN;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Looper;
+import android.telephony.satellite.SatelliteDatagram;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class DatagramControllerTest extends TelephonyTest {
+    private static final String TAG = "DatagramControllerTest";
+
+    private DatagramController mDatagramControllerUT;
+
+    @Mock private DatagramReceiver mMockDatagramReceiver;
+    @Mock private DatagramDispatcher mMockDatagramDispatcher;
+    @Mock private PointingAppController mMockPointingAppController;
+    @Mock private SatelliteSessionController mMockSatelliteSessionController;
+
+    private static final int SUB_ID = 0;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp(getClass().getSimpleName());
+        MockitoAnnotations.initMocks(this);
+        logd(TAG + " Setup!");
+
+        replaceInstance(DatagramDispatcher.class, "sInstance", null,
+                mMockDatagramDispatcher);
+        replaceInstance(DatagramReceiver.class, "sInstance", null,
+                mMockDatagramReceiver);
+        replaceInstance(SatelliteSessionController.class, "sInstance", null,
+                mMockSatelliteSessionController);
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        mDatagramControllerUT = new DatagramController(
+                mContext, Looper.myLooper(), mMockPointingAppController);
+
+        // Move both send and receive to IDLE state
+        mDatagramControllerUT.updateSendStatus(SUB_ID, DATAGRAM_TYPE_UNKNOWN,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, SATELLITE_RESULT_SUCCESS);
+        mDatagramControllerUT.updateReceiveStatus(SUB_ID, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0,
+                SATELLITE_RESULT_SUCCESS);
+        pushDemoModeSosDatagram();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        logd(TAG + " tearDown");
+        super.tearDown();
+    }
+
+    @Test
+    public void testUpdateSendStatus() throws Exception {
+        testUpdateSendStatus(true, DATAGRAM_TYPE_SOS_MESSAGE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
+        testUpdateSendStatus(true, DATAGRAM_TYPE_LOCATION_SHARING,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        testUpdateSendStatus(false, DATAGRAM_TYPE_KEEP_ALIVE,
+                SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING);
+    }
+
+    @Test
+    public void testUpdateReceiveStatus() throws Exception {
+        testUpdateReceiveStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING);
+        testUpdateReceiveStatus(true, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE);
+        testUpdateReceiveStatus(false, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING);
+    }
+
+    @Test
+    public void testSetDeviceAlignedWithSatellite() throws Exception {
+        testSetDeviceAlignedWithSatellite(true);
+        testSetDeviceAlignedWithSatellite(false);
+    }
+
+    private void testUpdateSendStatus(boolean isDemoMode, int datagramType, int sendState) {
+        mDatagramControllerUT.setDemoMode(isDemoMode);
+        clearAllInvocations();
+
+        int sendPendingCount = 1;
+        int errorCode = SATELLITE_RESULT_SUCCESS;
+        mDatagramControllerUT.updateSendStatus(SUB_ID, datagramType, sendState, sendPendingCount,
+                errorCode);
+
+        verify(mMockSatelliteSessionController)
+                .onDatagramTransferStateChanged(eq(sendState), anyInt());
+        verify(mMockPointingAppController).updateSendDatagramTransferState(
+                eq(SUB_ID), eq(datagramType), eq(sendState), eq(sendPendingCount), eq(errorCode));
+
+        if (isDemoMode) {
+            if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
+                verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
+                        anyInt(), any(Consumer.class));
+            }
+        } else {
+            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
+                    anyInt(), any(Consumer.class));
+        }
+    }
+
+    private void testUpdateReceiveStatus(boolean isDemoMode, int receiveState) {
+        mDatagramControllerUT.setDemoMode(isDemoMode);
+        clearAllInvocations();
+
+        int receivePendingCount = 1;
+        int errorCode = SATELLITE_RESULT_SUCCESS;
+        mDatagramControllerUT.updateReceiveStatus(
+                SUB_ID, receiveState, receivePendingCount, errorCode);
+
+        verify(mMockSatelliteSessionController)
+                .onDatagramTransferStateChanged(anyInt(), eq(receiveState));
+        verify(mMockPointingAppController).updateReceiveDatagramTransferState(
+                eq(SUB_ID), eq(receiveState), eq(receivePendingCount), eq(errorCode));
+
+        if (isDemoMode && receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE) {
+            verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
+                    anyInt(), any(Consumer.class));
+        } else {
+            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
+                    anyInt(), any(Consumer.class));
+        }
+    }
+
+    private void testSetDeviceAlignedWithSatellite(boolean isAligned) {
+        mDatagramControllerUT.setDemoMode(true);
+        clearAllInvocations();
+
+        mDatagramControllerUT.setDeviceAlignedWithSatellite(isAligned);
+        verify(mMockDatagramDispatcher).setDeviceAlignedWithSatellite(eq(isAligned));
+        verify(mMockDatagramReceiver).setDeviceAlignedWithSatellite(eq(isAligned));
+        if (isAligned) {
+            verify(mMockDatagramReceiver).pollPendingSatelliteDatagrams(
+                    anyInt(), any(Consumer.class));
+        } else {
+            verify(mMockDatagramReceiver, never()).pollPendingSatelliteDatagrams(
+                    anyInt(), any(Consumer.class));
+        }
+    }
+
+    private void clearAllInvocations() {
+        clearInvocations(mMockSatelliteSessionController);
+        clearInvocations(mMockPointingAppController);
+        clearInvocations(mMockDatagramReceiver);
+        clearInvocations(mMockDatagramDispatcher);
+    }
+
+    private void pushDemoModeSosDatagram() {
+        String testMessage = "This is a test datagram message";
+        SatelliteDatagram datagram = new SatelliteDatagram(testMessage.getBytes());
+        mDatagramControllerUT.setDemoMode(true);
+        mDatagramControllerUT.pushDemoModeDatagram(DATAGRAM_TYPE_SOS_MESSAGE, datagram);
+    }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
index 79f1928..3d6f617 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.satellite;
 
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.internal.telephony.satellite.DatagramController.SATELLITE_ALIGN_TIMEOUT;
 
@@ -83,6 +84,7 @@
     private static final int SUB_ID = 0;
     private static final int DATAGRAM_TYPE1 = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE;
     private static final int DATAGRAM_TYPE2 = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING;
+    private static final int DATAGRAM_TYPE3 = SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE;
     private static final String TEST_MESSAGE = "This is a test datagram message";
     private static final long TEST_EXPIRE_TIMER_SATELLITE_ALIGN = TimeUnit.SECONDS.toMillis(1);
     private static final int TEST_WAIT_FOR_DATAGRAM_SENDING_RESPONSE_TIMEOUT_MILLIS =
@@ -91,8 +93,7 @@
             TimeUnit.SECONDS.toMillis(60);
     private static final Long TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE = TimeUnit.SECONDS.toMillis(10);
 
-    private DatagramDispatcher mDatagramDispatcherUT;
-    private TestDatagramDispatcher mTestDemoModeDatagramDispatcher;
+    private TestDatagramDispatcher mDatagramDispatcherUT;
 
     @Mock private DatagramController mMockDatagramController;
     @Mock private DatagramReceiver mMockDatagramReceiver;
@@ -139,9 +140,7 @@
                 mMockSatelliteSessionController);
 
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
-        mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(),
-                mMockDatagramController);
-        mTestDemoModeDatagramDispatcher = new TestDatagramDispatcher(mContext, Looper.myLooper(),
+        mDatagramDispatcherUT = new TestDatagramDispatcher(mContext, Looper.myLooper(),
                 mMockDatagramController);
 
         mResultListener = new LinkedBlockingQueue<>(1);
@@ -155,7 +154,6 @@
         logd(TAG + " tearDown");
         mDatagramDispatcherUT.destroy();
         mDatagramDispatcherUT = null;
-        mTestDemoModeDatagramDispatcher = null;
         mResultListener = null;
         mDatagram = null;
         mInOrder = null;
@@ -183,9 +181,9 @@
                 true, mResultListener::offer);
         processAllMessages();
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
-        mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID),
+        mInOrder.verify(mMockDatagramController).updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                 eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT), eq(1),
-                eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController).getDatagramWaitTimeForConnectedState();
         verifyZeroInteractions(mMockSatelliteModemInterface);
         assertTrue(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
@@ -196,23 +194,23 @@
 
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
         assertFalse(mDatagramDispatcherUT.isDatagramWaitForConnectedStateTimerStarted());
 
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+        assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
 
         clearInvocations(mMockSatelliteModemInterface);
         clearInvocations(mMockDatagramController);
@@ -234,12 +232,14 @@
         verifyZeroInteractions(mMockSatelliteModemInterface);
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1),
                         eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
         mInOrder.verify(mMockDatagramController)
                 .updateSendStatus(eq(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+                        eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         assertEquals(1, mResultListener.size());
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
@@ -306,21 +306,21 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+        assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
 
         clearInvocations(mMockSatelliteModemInterface);
         clearInvocations(mMockDatagramController);
@@ -336,17 +336,17 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(1),
                         eq(SATELLITE_RESULT_MODEM_TIMEOUT));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
@@ -376,17 +376,17 @@
         mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
         mInOrder.verify(mMockDatagramController).isPollingInIdleState();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0),
                         eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         verifyNoMoreInteractions(mMockDatagramController);
 
         assertThat(mResultListener.peek()).isEqualTo(
@@ -397,16 +397,16 @@
     public void testSendSatelliteDatagram_DemoMode_Align_Success() throws Exception {
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
-            mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
+            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
+        mDatagramDispatcherUT.setDemoMode(true);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(true);
 
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
 
         processAllMessages();
@@ -414,59 +414,62 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        mTestDemoModeDatagramDispatcher.setDemoMode(false);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
+                        eq(SATELLITE_RESULT_SUCCESS));
+        assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
+        mDatagramDispatcherUT.setDemoMode(false);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
     }
 
     @Test
     public void testSendSatelliteDatagram_DemoMode_Align_failed() throws Exception {
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
-            mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
+            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
 
-        long previousTimer = mTestDemoModeDatagramDispatcher.getSatelliteAlignedTimeoutDuration();
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        mTestDemoModeDatagramDispatcher.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
+        long previousTimer = mDatagramDispatcherUT.getSatelliteAlignedTimeoutDuration();
+        mDatagramDispatcherUT.setDemoMode(true);
+        mDatagramDispatcherUT.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
 
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         processAllFutureMessages();
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED),
                         anyInt(), eq(SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
         assertThat(mResultListener.peek()).isEqualTo(
                 SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE);
-        mTestDemoModeDatagramDispatcher.setDemoMode(false);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
-        mTestDemoModeDatagramDispatcher.setDuration(previousTimer);
+        verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any());
+        verify(mMockDatagramController, never()).pushDemoModeDatagram(
+                anyInt(), any(SatelliteDatagram.class));
+        mDatagramDispatcherUT.setDemoMode(false);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
+        mDatagramDispatcherUT.setDuration(previousTimer);
     }
 
     @Test
@@ -474,16 +477,16 @@
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
             mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
-                    new AsyncResult(message.obj, SatelliteManager.SATELLITE_RESULT_SUCCESS,
+                    new AsyncResult(message.obj, SATELLITE_RESULT_SUCCESS,
                             null)).sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
+        mDatagramDispatcherUT.setDemoMode(true);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(true);
         replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
 
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram,
                 true, mResultListener::offer);
 
         processAllMessages();
@@ -491,24 +494,24 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
 
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+        assertThat(mResultListener.peek()).isEqualTo(SATELLITE_RESULT_SUCCESS);
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
+                .updateSendStatus(eq(SUB_ID), eq(DATAGRAM_TYPE2),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(SATELLITE_RESULT_SUCCESS));
 
-        mTestDemoModeDatagramDispatcher.setDemoMode(false);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
+        mDatagramDispatcherUT.setDemoMode(false);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
     }
 
     @Test
@@ -543,13 +546,13 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED),
                         eq(1), eq(SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED));
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), eq(DATAGRAM_TYPE1),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
-                        eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(0), eq(SATELLITE_RESULT_SUCCESS));
     }
 
     @Test
@@ -560,9 +563,9 @@
         processAllMessages();
 
         mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(anyInt(),
+                .updateSendStatus(anyInt(), anyInt(),
                         eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
-                        eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                        eq(0), eq(SATELLITE_RESULT_SUCCESS));
     }
 
     @Test
@@ -572,68 +575,84 @@
 
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
-            mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
+            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
                 anyBoolean(), anyBoolean(), any(Message.class));
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
+        mDatagramDispatcherUT.setDemoMode(true);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(true);
         mIntegerConsumerSemaphore.drainPermits();
 
         // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is true
-        mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+        mDatagramDispatcherUT.setShouldSendDatagramToModemInDemoMode(null);
         mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, true);
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mIntegerConsumer);
         processAllMessages();
+        moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
+        processAllMessages();
         waitForIntegerConsumerResult(1);
-        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+        assertEquals(SATELLITE_RESULT_SUCCESS,
                 (int) mIntegerConsumerResult.get(0));
         mIntegerConsumerResult.clear();
         verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
 
+        moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
+        processAllMessages();
+        verify(mMockDatagramController).pushDemoModeDatagram(
+                anyInt(), any(SatelliteDatagram.class));
+        verify(mMockDatagramController).pollPendingSatelliteDatagrams(anyInt(), any());
+
         // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is false
         reset(mMockSatelliteModemInterface);
-        mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+        mDatagramDispatcherUT.setShouldSendDatagramToModemInDemoMode(null);
         mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, false);
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mIntegerConsumer);
         processAllMessages();
         moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
         processAllMessages();
 
-        verify(mMockDatagramController).pollPendingSatelliteDatagrams(anyInt(), any());
-
         waitForIntegerConsumerResult(1);
-        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+        assertEquals(SATELLITE_RESULT_SUCCESS,
                 (int) mIntegerConsumerResult.get(0));
         mIntegerConsumerResult.clear();
         verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
 
+        moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
+        processAllMessages();
+        verify(mMockDatagramController, times(2)).pushDemoModeDatagram(
+                anyInt(), any(SatelliteDatagram.class));
+        verify(mMockDatagramController, times(2)).pollPendingSatelliteDatagrams(anyInt(), any());
+
         // Send datagram one more time
         reset(mMockSatelliteModemInterface);
-        mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mIntegerConsumer);
         processAllMessages();
         moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
         processAllMessages();
 
-        verify(mMockDatagramController, times(2)).pollPendingSatelliteDatagrams(anyInt(), any());
-
         waitForIntegerConsumerResult(1);
-        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+        assertEquals(SATELLITE_RESULT_SUCCESS,
                 (int) mIntegerConsumerResult.get(0));
         mIntegerConsumerResult.clear();
         verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram(
                 any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
 
-        mTestDemoModeDatagramDispatcher.setDemoMode(false);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
-        mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+        moveTimeForward(TIMEOUT_DATAGRAM_DELAY_IN_DEMO_MODE);
+        processAllMessages();
+        verify(mMockDatagramController, times(3)).pushDemoModeDatagram(
+                anyInt(), any(SatelliteDatagram.class));
+        verify(mMockDatagramController, times(3)).pollPendingSatelliteDatagrams(anyInt(), any());
+
+        mDatagramDispatcherUT.setDemoMode(false);
+        mDatagramDispatcherUT.setDeviceAlignedWithSatellite(false);
+        mDatagramDispatcherUT.setShouldSendDatagramToModemInDemoMode(null);
     }
 
     private boolean waitForIntegerConsumerResult(int expectedNumberOfEvents) {
@@ -665,7 +684,7 @@
         }
 
         @Override
-        protected  void setDeviceAlignedWithSatellite(boolean isAligned) {
+        public void setDeviceAlignedWithSatellite(boolean isAligned) {
             super.setDeviceAlignedWithSatellite(isAligned);
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
index 5a1a8f7..0a07f03 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -324,6 +324,7 @@
         mTestDemoModeDatagramReceiver.setDemoMode(true);
         mTestDemoModeDatagramReceiver.setDeviceAlignedWithSatellite(true);
         when(mMockDatagramController.popDemoModeDatagram()).thenReturn(mDatagram);
+
         mTestDemoModeDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
         processAllMessages();
         verify(mMockDatagramController, times(1)).popDemoModeDatagram();
@@ -478,7 +479,7 @@
         }
 
         @Override
-        protected void setDeviceAlignedWithSatellite(boolean isAligned) {
+        public void setDeviceAlignedWithSatellite(boolean isAligned) {
             super.setDeviceAlignedWithSatellite(isAligned);
         }
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
index f8827be..873078e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/NtnCapabilityResolverTest.java
@@ -30,6 +30,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.annotation.NonNull;
 import android.telephony.CellIdentity;
@@ -100,6 +102,7 @@
                 .mapToInt(Integer::intValue)
                 .toArray()));
         NtnCapabilityResolver.resolveNtnCapability(satelliteNri, SUB_ID);
+        verify(mMockSatelliteController).getSatellitePlmnsForCarrier(anyInt());
         assertNotEquals(satelliteNri, originalNri);
         assertTrue(satelliteNri.isNonTerrestrialNetwork());
         assertTrue(Arrays.equals(mSatelliteSupportedServices,
@@ -118,12 +121,32 @@
                         .mapToInt(Integer::intValue)
                         .toArray()));
         NtnCapabilityResolver.resolveNtnCapability(cellularNri, SUB_ID);
+        verify(mMockSatelliteController, times(2)).getSatellitePlmnsForCarrier(anyInt());
         assertEquals(cellularNri, originalNri);
         assertFalse(cellularNri.isNonTerrestrialNetwork());
         assertFalse(Arrays.equals(mSatelliteSupportedServices,
                 cellularNri.getAvailableServices().stream()
                         .mapToInt(Integer::intValue)
                         .toArray()));
+
+        // Test resolving an empty-PLMN NetworkRegistrationInfo.
+        NetworkRegistrationInfo emptyPlmnNri = createNetworkRegistrationInfo("");
+        originalNri = new NetworkRegistrationInfo(emptyPlmnNri);
+
+        assertEquals(emptyPlmnNri, originalNri);
+        assertFalse(emptyPlmnNri.isNonTerrestrialNetwork());
+        assertFalse(Arrays.equals(mSatelliteSupportedServices,
+                emptyPlmnNri.getAvailableServices().stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        NtnCapabilityResolver.resolveNtnCapability(emptyPlmnNri, SUB_ID);
+        verify(mMockSatelliteController, times(2)).getSatellitePlmnsForCarrier(anyInt());
+        assertEquals(emptyPlmnNri, originalNri);
+        assertFalse(emptyPlmnNri.isNonTerrestrialNetwork());
+        assertFalse(Arrays.equals(mSatelliteSupportedServices,
+                emptyPlmnNri.getAvailableServices().stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
     }
 
     private NetworkRegistrationInfo createNetworkRegistrationInfo(@NonNull String registeredPlmn) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
index 3917a32..0fe48c8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
@@ -150,6 +150,7 @@
     }
     private class TestSatelliteTransmissionUpdateCallback
                                 extends ISatelliteTransmissionUpdateCallback.Stub {
+        int mDatagramType;
         int mState;
         int mSendPendingCount;
         int mReceivePendingCount;
@@ -163,8 +164,9 @@
         }
 
         @Override
-        public void onSendDatagramStateChanged(int state, int sendPendingCount,
+        public void onSendDatagramStateChanged(int datagramType, int state, int sendPendingCount,
                                     int errorCode) {
+            mDatagramType = datagramType;
             mState = state;
             mSendPendingCount = sendPendingCount;
             mErrorCode = errorCode;
@@ -191,6 +193,10 @@
             }
         }
 
+        public int getDatagramType() {
+            return mDatagramType;
+        }
+
         public int getState() {
             return mState;
         }
@@ -208,7 +214,7 @@
         }
     }
 
-    private boolean waitForReceiveDatagramStateChangedRessult(
+    private boolean waitForReceiveDatagramStateChangedResult(
             int expectedNumberOfEvents) {
         for (int i = 0; i < expectedNumberOfEvents; i++) {
             try {
@@ -218,7 +224,7 @@
                     return false;
                 }
             } catch (Exception ex) {
-                loge("waitForReceiveDatagramStateChangedRessult: Got exception=" + ex);
+                loge("waitForReceiveDatagramStateChangedResult: Got exception=" + ex);
                 return false;
             }
         }
@@ -347,9 +353,12 @@
         mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID,
                 mSatelliteTransmissionUpdateCallback);
         mPointingAppController.updateSendDatagramTransferState(SUB_ID,
+                SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, 1,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
         assertTrue(waitForSendDatagramStateChangedRessult(1));
+        assertEquals(SatelliteManager.DATAGRAM_TYPE_KEEP_ALIVE,
+                mSatelliteTransmissionUpdateCallback.getDatagramType());
         assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS,
                 mSatelliteTransmissionUpdateCallback.getState());
         assertEquals(1, mSatelliteTransmissionUpdateCallback.getSendPendingCount());
@@ -368,7 +377,7 @@
         mPointingAppController.updateReceiveDatagramTransferState(SUB_ID,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, 2,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        assertTrue(waitForReceiveDatagramStateChangedRessult(1));
+        assertTrue(waitForReceiveDatagramStateChangedResult(1));
         assertEquals(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS,
                 mSatelliteTransmissionUpdateCallback.getState());
         assertEquals(2, mSatelliteTransmissionUpdateCallback.getReceivePendingCount());
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 f91c974..43ca1c6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
 import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
 import static android.telephony.SubscriptionManager.SATELLITE_ENTITLEMENT_STATUS;
@@ -57,6 +58,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
+import static com.android.internal.telephony.satellite.SatelliteController.DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS;
 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_FALSE;
 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_TRUE;
 
@@ -106,6 +108,7 @@
 import android.telephony.satellite.ISatelliteDatagramCallback;
 import android.telephony.satellite.ISatelliteModemStateCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
+import android.telephony.satellite.ISatelliteSupportedStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
 import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
@@ -557,58 +560,6 @@
     }
 
     @Test
-    public void testRequestIsSatelliteCommunicationAllowedForCurrentLocation() {
-        mSatelliteAllowedSemaphore.drainPermits();
-        setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
-        verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID,
-                mSatelliteAllowedReceiver);
-        processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1));
-        assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, mQueriedSatelliteAllowedResultCode);
-
-        resetSatelliteControllerUT();
-        mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID,
-                mSatelliteAllowedReceiver);
-        processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1));
-        assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode);
-
-        resetSatelliteControllerUT();
-        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        setUpResponseForRequestIsSatelliteAllowedForCurrentLocation(true,
-                SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID,
-                mSatelliteAllowedReceiver);
-        processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1));
-        assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteAllowedResultCode);
-        assertTrue(mQueriedSatelliteAllowed);
-
-        resetSatelliteControllerUT();
-        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID,
-                mSatelliteAllowedReceiver);
-        processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1));
-        assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode);
-
-        resetSatelliteControllerUT();
-        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(
-                SATELLITE_RESULT_INVALID_MODEM_STATE);
-        mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID,
-                mSatelliteAllowedReceiver);
-        processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1));
-        assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, mQueriedSatelliteAllowedResultCode);
-    }
-
-    @Test
     public void testRequestTimeForNextSatelliteVisibility() {
         mSatelliteVisibilityTimeSemaphore.drainPermits();
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
@@ -742,7 +693,8 @@
 
         // Fail to enable satellite when SatelliteController is not fully loaded yet.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
@@ -752,7 +704,8 @@
         mIIntegerConsumerResults.clear();
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
         verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0));
@@ -767,7 +720,8 @@
         verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS);
         verifySatelliteProvisioned(false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SERVICE_NOT_PROVISIONED,
@@ -780,8 +734,9 @@
         // Successfully enable satellite
         mIIntegerConsumerResults.clear();
         mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -797,7 +752,7 @@
 
         // Successfully disable satellite when radio is turned off.
         mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
         setRadioPower(false);
         mSatelliteControllerUT.onCellularRadioPowerOffRequested();
         processAllMessages();
@@ -814,8 +769,9 @@
 
         // Fail to enable satellite when radio is off.
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         // Radio is not on, can not enable satellite
@@ -829,8 +785,10 @@
         mIIntegerConsumerResults.clear();
         clearInvocations(mMockPointingAppController);
         mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_INVALID_MODEM_STATE);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false,
+                SATELLITE_RESULT_INVALID_MODEM_STATE);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0));
@@ -842,8 +800,9 @@
         // Successfully enable satellite when radio is on.
         mIIntegerConsumerResults.clear();
         mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -861,7 +820,8 @@
 
         // Successfully enable satellite when it is already enabled.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -869,7 +829,8 @@
 
         // Fail to enable satellite with a different demo mode when it is already enabled.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, true, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, true, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_INVALID_ARGUMENTS, (long) mIIntegerConsumerResults.get(0));
@@ -877,8 +838,9 @@
 
         // Successfully disable satellite.
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -886,7 +848,8 @@
 
         // Disable satellite when satellite is already disabled.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -894,7 +857,8 @@
 
         // Disable satellite with a different demo mode when satellite is already disabled.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, true, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, true, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -902,11 +866,13 @@
 
         // Send a second request while the first request in progress
         mIIntegerConsumerResults.clear();
-        setUpNoResponseForRequestSatelliteEnabled(true, false);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpNoResponseForRequestSatelliteEnabled(true, false, false);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_REQUEST_IN_PROGRESS, (long) mIIntegerConsumerResults.get(0));
@@ -918,14 +884,16 @@
         assertEquals(SATELLITE_RESULT_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0));
 
         // Move to satellite-disabling in progress.
-        setUpNoResponseForRequestSatelliteEnabled(false, false);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpNoResponseForRequestSatelliteEnabled(false, false, false);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
 
         // Disable is in progress. Thus, a new request to enable satellite will be rejected.
         mIIntegerConsumerResults.clear();
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_ERROR, (long) mIIntegerConsumerResults.get(0));
@@ -941,15 +909,17 @@
          * will lead to no response for requestSatelliteEnabled.
          */
         mSatelliteControllerUT.allRadiosDisabled = false;
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
 
         resetSatelliteControllerUTEnabledState();
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         // We should receive 2 callbacks for the above 2 requests.
         assertTrue(waitForIIntegerConsumerResult(2));
@@ -960,15 +930,17 @@
 
         // Repeat the same test as above but with error response from modem for the second request
         mSatelliteControllerUT.allRadiosDisabled = false;
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
 
         resetSatelliteControllerUTEnabledState();
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_NO_RESOURCES);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_NO_RESOURCES);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         // We should receive 2 callbacks for the above 2 requests.
         assertTrue(waitForIIntegerConsumerResult(2));
@@ -1252,7 +1224,7 @@
 
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
 
         setUpResponseForRequestIsSatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
         mSatelliteControllerUT.onSatelliteServiceConnected();
@@ -1686,7 +1658,7 @@
     }
 
     @Test
-    public void testSupportedSatelliteServices() {
+    public void testSupportedSatelliteServices() throws Exception {
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
         List<String> satellitePlmnList = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
                 SUB_ID);
@@ -1700,6 +1672,7 @@
                 R.array.config_satellite_providers, satelliteProviderStrArray);
         int[] expectedSupportedServices2 = {2};
         int[] expectedSupportedServices3 = {1, 3};
+        int[] defaultSupportedServices = {5, 6};
         PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle();
         carrierSupportedSatelliteServicesPerProvider.putIntArray(
                 "00102", expectedSupportedServices2);
@@ -1709,6 +1682,9 @@
         mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
                         .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 carrierSupportedSatelliteServicesPerProvider);
+        mCarrierConfigBundle.putIntArray(
+                CarrierConfigManager.KEY_CARRIER_ROAMING_SATELLITE_DEFAULT_SERVICES_INT_ARRAY,
+                defaultSupportedServices);
         TestSatelliteController testSatelliteController =
                 new TestSatelliteController(mContext, Looper.myLooper(), mFeatureFlags);
 
@@ -1718,6 +1694,9 @@
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00101");
         assertTrue(supportedSatelliteServices.isEmpty());
 
+        // Add entitlement provided PLMNs.
+        setEntitlementPlmnList(testSatelliteController, SUB_ID,
+                Arrays.asList("00102", "00104", "00105"));
         // Carrier config changed with carrierEnabledSatelliteFlag disabled
         for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
                 : mCarrierConfigChangedListenerList) {
@@ -1733,9 +1712,17 @@
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103");
         assertTrue(supportedSatelliteServices.isEmpty());
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(supportedSatelliteServices.isEmpty());
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(supportedSatelliteServices.isEmpty());
 
         // Trigger carrier config changed with carrierEnabledSatelliteFlag enabled
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        mCarrierConfigBundle.putBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+                true);
         for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
                 : mCarrierConfigChangedListenerList) {
             pair.first.execute(() -> pair.second.onCarrierConfigChanged(
@@ -1749,6 +1736,7 @@
                 expectedSupportedSatellitePlmns, satellitePlmnList.stream().toArray()));
         supportedSatelliteServices =
                 mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00102");
+        // "00101" should return carrier config assigned value, though it is in allowed list.
         assertTrue(Arrays.equals(expectedSupportedServices2,
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
@@ -1759,6 +1747,19 @@
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
                         .toArray()));
+        // "00104", and "00105" should return default supported service.
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
 
         // Subscriptions changed
         int[] newActiveSubIds = {SUB_ID1};
@@ -1773,13 +1774,32 @@
 
         satellitePlmnList = testSatelliteController.getSatellitePlmnsForCarrier(SUB_ID);
         assertTrue(satellitePlmnList.isEmpty());
+        // "00102" and "00103" should return default supported service for SUB_ID.
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00102");
-        assertTrue(supportedSatelliteServices.isEmpty());
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00103");
-        assertTrue(supportedSatelliteServices.isEmpty());
-
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        // "00104", and "00105" should return default supported service for SUB_ID.
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
 
         supportedSatelliteServices =
                 testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00102");
@@ -1795,6 +1815,19 @@
                 supportedSatelliteServices.stream()
                         .mapToInt(Integer::intValue)
                         .toArray()));
+        /* "00104", and "00105" should return default supported service. */
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00104");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
+        supportedSatelliteServices =
+                testSatelliteController.getSupportedSatelliteServices(SUB_ID1, "00105");
+        assertTrue(Arrays.equals(defaultSupportedServices,
+                supportedSatelliteServices.stream()
+                        .mapToInt(Integer::intValue)
+                        .toArray()));
     }
 
     @Test
@@ -2527,12 +2560,16 @@
         processAllMessages();
         mSatelliteControllerUT.elapsedRealtime = 0;
         assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
 
         when(mServiceState.isUsingNonTerrestrialNetwork()).thenReturn(false);
         when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false);
         sendServiceStateChangedEvent();
         processAllMessages();
         assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
 
         // Last satellite connected time of Phone2 should be 0
         when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(true);
@@ -2542,6 +2579,8 @@
         mSatelliteControllerUT.elapsedRealtime = 2 * 60 * 1000;
         // But Phone2 is connected to NTN right now
         assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
+        assertTrue(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
 
         // Last satellite disconnected time of Phone2 should be 2 * 60 * 1000
         when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false);
@@ -2549,10 +2588,14 @@
         processAllMessages();
         // Current time (2) - last disconnected time (2) < hysteresis timeout (1)
         assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
+        assertTrue(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
 
         // Current time (4) - last disconnected time (2) > hysteresis timeout (1)
         mSatelliteControllerUT.elapsedRealtime = 4 * 60 * 1000;
         assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone));
+        assertFalse(mSatelliteControllerUT.isInSatelliteModeForCarrierRoaming(mPhone2));
     }
 
     @Test
@@ -2685,7 +2728,7 @@
         // Verify call the requestSetSatelliteEnabledForCarrier to enable the satellite when
         // satellite service is enabled by entitlement server.
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, true, new ArrayList<>(),
-                mIIntegerConsumer);
+                new ArrayList<>(), mIIntegerConsumer);
         processAllMessages();
 
         assertTrue(waitForIIntegerConsumerResult(1));
@@ -2705,7 +2748,7 @@
                 .when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
         setUpResponseForRequestSetSatelliteEnabledForCarrier(false, SATELLITE_RESULT_SUCCESS);
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false, new ArrayList<>(),
-                mIIntegerConsumer);
+                new ArrayList<>(), mIIntegerConsumer);
         processAllMessages();
 
         assertTrue(waitForIIntegerConsumerResult(1));
@@ -2719,51 +2762,42 @@
             throws Exception {
         logd("testPassSatellitePlmnToModemAfterUpdateSatelliteEntitlementStatus");
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+
         replaceInstance(SatelliteController.class, "mMergedPlmnListPerCarrier",
                 mSatelliteControllerUT, new SparseArray<>());
-        List<String> overlayConfigPlmnList =  new ArrayList<>();
+        List<String> overlayConfigPlmnList = new ArrayList<>();
         replaceInstance(SatelliteController.class, "mSatellitePlmnListFromOverlayConfig",
                 mSatelliteControllerUT, overlayConfigPlmnList);
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
+        mCarrierConfigBundle.putBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+                true);
 
-        // If the PlmnListPerCarrier and the overlay config plmn list are empty verify passing to
-        // the modem.
+        // If the entitlement plmn list, the carrier plmn list, the overlay config plmn list and
+        // the barred plmn list are empty, verify not passing to the modem.
+        reset(mMockSatelliteModemInterface);
         List<String> entitlementPlmnList = new ArrayList<>();
+        List<String> barredPlmnList = new ArrayList<>();
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
-                entitlementPlmnList, mIIntegerConsumer);
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+        verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
+                anyBoolean(), anyBoolean(), any(Message.class));
 
-        List<String> plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
-                SUB_ID);
-        List<String> allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
-                plmnListPerCarrier, overlayConfigPlmnList);
-
-        assertEquals(new ArrayList<>(), plmnListPerCarrier);
-        assertEquals(new ArrayList<>(), allSatellitePlmnList);
-        verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(),
-                eq(plmnListPerCarrier), eq(allSatellitePlmnList), any(Message.class));
-
-        // If the PlmnListPerCarrier and the overlay config plmn list are exist verify passing
-        // the modem.
+        // If the entitlement plmn list and the overlay config plmn list are available and the
+        // carrier plmn list and the barred plmn list are empty, verify passing to the modem.
+        reset(mMockSatelliteModemInterface);
         entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", "00103"}).toList();
+        List<String> mergedPlmnList = entitlementPlmnList;
         overlayConfigPlmnList =
                 Arrays.stream(new String[]{"00101", "00102", "00104"}).toList();
         replaceInstance(SatelliteController.class, "mSatellitePlmnListFromOverlayConfig",
                 mSatelliteControllerUT, overlayConfigPlmnList);
+        verifyPassingToModemAfterQueryCompleted(entitlementPlmnList, mergedPlmnList,
+                overlayConfigPlmnList, barredPlmnList);
 
-        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, true,
-                entitlementPlmnList, mIIntegerConsumer);
-
-        plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
-        allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
-                plmnListPerCarrier, overlayConfigPlmnList);
-
-        assertEquals(entitlementPlmnList, plmnListPerCarrier);
-        verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(),
-                eq(plmnListPerCarrier), eq(allSatellitePlmnList), any(Message.class));
-
-        // If the PlmnListPerCarrier and the overlay config plmn list are exist verify passing
-        // the modem.
+        // If the entitlement plmn list, the overlay config plmn list and the carrier plmn list
+        // are available and the barred plmn list is empty, verify passing to the modem.
         reset(mMockSatelliteModemInterface);
-        entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", "00103"}).toList();
         Map<Integer, Map<String, Set<Integer>>>
                 satelliteServicesSupportedByCarriers = new HashMap<>();
         List<String> carrierConfigPlmnList = Arrays.stream(new String[]{"00105", "00106"}).toList();
@@ -2773,19 +2807,80 @@
         satelliteServicesSupportedByCarriers.put(SUB_ID, plmnAndService);
         replaceInstance(SatelliteController.class, "mSatelliteServicesSupportedByCarriers",
                 mSatelliteControllerUT, satelliteServicesSupportedByCarriers);
-        overlayConfigPlmnList = Arrays.stream(new String[]{"00101", "00102", "00104"}).toList();
-        replaceInstance(SatelliteController.class, "mSatellitePlmnListFromOverlayConfig",
-                mSatelliteControllerUT, overlayConfigPlmnList);
-        List<String> mergedPlmnList = entitlementPlmnList;
+        verifyPassingToModemAfterQueryCompleted(entitlementPlmnList, mergedPlmnList,
+                overlayConfigPlmnList, barredPlmnList);
 
-        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, true,
-                entitlementPlmnList, mIIntegerConsumer);
+        // If the entitlement plmn list is empty and the overlay config plmn list and the carrier
+        // plmn list are available, verify passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = new ArrayList<>();
+        mergedPlmnList = carrierConfigPlmnList;
+        verifyPassingToModemAfterQueryCompleted(entitlementPlmnList, mergedPlmnList,
+                overlayConfigPlmnList, barredPlmnList);
 
-        plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
-        allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
-                plmnListPerCarrier, overlayConfigPlmnList);
+        // If the entitlement plmn list is empty and the overlay config plmn list, the carrier
+        // plmn list and the barred plmn list are available, verify passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        barredPlmnList = Arrays.stream(new String[]{"00105", "00107"}).toList();
+        verifyPassingToModemAfterQueryCompleted(entitlementPlmnList, mergedPlmnList,
+                overlayConfigPlmnList, barredPlmnList);
+
+        // If the entitlement plmn list is null and the overlay config plmn list and the carrier
+        // plmn list are available, verify passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = null;
+        mergedPlmnList = carrierConfigPlmnList;
+        verifyPassingToModemAfterQueryCompleted(entitlementPlmnList, mergedPlmnList,
+                overlayConfigPlmnList, barredPlmnList);
+
+        // If the entitlement plmn list is invalid, verify not passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", ""}).toList();
+        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+        verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
+                anyBoolean(), anyBoolean(), any(Message.class));
+
+        // If the entitlement plmn list is invalid, verify not passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", "123456789"}).toList();
+        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+        verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
+                anyBoolean(), anyBoolean(), any(Message.class));
+
+        // If the entitlement plmn list is invalid, verify not passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", "12"}).toList();
+        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+        verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
+                anyBoolean(), anyBoolean(), any(Message.class));
+
+        // If the entitlement plmn list is invalid, verify not passing to the modem.
+        reset(mMockSatelliteModemInterface);
+        entitlementPlmnList = Arrays.stream(new String[]{"00101", "00102", "1234"}).toList();
+        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+        verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
+                anyBoolean(), anyBoolean(), any(Message.class));
+    }
+
+    private void verifyPassingToModemAfterQueryCompleted(List<String> entitlementPlmnList,
+            List<String> mergedPlmnList, List<String> overlayConfigPlmnList,
+            List<String> barredPlmnList) {
+        mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false,
+                entitlementPlmnList, barredPlmnList, mIIntegerConsumer);
+
+        List<String> plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
+                SUB_ID);
+        List<String> allSatellitePlmnList = SatelliteServiceUtils.mergeStrLists(
+                plmnListPerCarrier, overlayConfigPlmnList, barredPlmnList);
 
         assertEquals(mergedPlmnList, plmnListPerCarrier);
+        if (overlayConfigPlmnList.isEmpty()) {
+            assertEquals(plmnListPerCarrier, allSatellitePlmnList);
+        }
         verify(mMockSatelliteModemInterface, times(1)).setSatellitePlmn(anyInt(),
                 eq(plmnListPerCarrier), eq(allSatellitePlmnList), any(Message.class));
     }
@@ -2870,6 +2965,17 @@
                 mSatelliteControllerUT, entitlementPlmnListPerCarrier);
     }
 
+    private void setEntitlementPlmnList(SatelliteController targetClass, int subId,
+            List<String> plmnList) throws Exception {
+        SparseArray<List<String>> entitlementPlmnListPerCarrier = new SparseArray<>();
+        if (!plmnList.isEmpty()) {
+            entitlementPlmnListPerCarrier.clear();
+            entitlementPlmnListPerCarrier.put(subId, plmnList);
+        }
+        replaceInstance(SatelliteController.class, "mEntitlementPlmnListPerCarrier",
+                targetClass, entitlementPlmnListPerCarrier);
+    }
+
     private void setConfigDataPlmnList(List<String> plmnList) {
         doReturn(plmnList).when(mMockConfig).getAllSatellitePlmnsForCarrier(anyInt());
         doReturn(mMockConfig).when(mMockConfigParser).getConfig();
@@ -2913,8 +3019,11 @@
     public void testUpdatePlmnListPerCarrier() throws Exception {
         logd("testUpdatePlmnListPerCarrier");
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+
         replaceInstance(SatelliteController.class, "mMergedPlmnListPerCarrier",
                 mSatelliteControllerUT, new SparseArray<>());
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
         List<String> plmnListPerCarrier;
 
         // verify whether an empty list is returned with conditions below
@@ -2975,21 +3084,21 @@
 
         // Change SUB_ID's EntitlementStatus to true
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, true, new ArrayList<>(),
-                mIIntegerConsumer);
+                new ArrayList<>(), mIIntegerConsumer);
 
         assertEquals(true, satelliteEnabledPerCarrier.get(SUB_ID));
         assertEquals(false, satelliteEnabledPerCarrier.get(SUB_ID1));
 
         // Change SUB_ID1's EntitlementStatus to true
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID1, true, new ArrayList<>(),
-                mIIntegerConsumer);
+                new ArrayList<>(), mIIntegerConsumer);
 
         assertEquals(true, satelliteEnabledPerCarrier.get(SUB_ID));
         assertEquals(true, satelliteEnabledPerCarrier.get(SUB_ID1));
 
         // Change SUB_ID's EntitlementStatus to false
         mSatelliteControllerUT.onSatelliteEntitlementStatusUpdated(SUB_ID, false, new ArrayList<>(),
-                mIIntegerConsumer);
+                new ArrayList<>(), mIIntegerConsumer);
 
         assertEquals(false, satelliteEnabledPerCarrier.get(SUB_ID));
         assertEquals(true, satelliteEnabledPerCarrier.get(SUB_ID1));
@@ -3030,8 +3139,8 @@
         logd("testUpdateEntitlementPlmnListPerCarrier");
         when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
 
-        // If the Satellite entitlement plmn list read from the DB is empty and carrier config
-        // plmn list also is empty , check whether an empty list is returned when calling
+        // If the Satellite entitlement plmn list read from the DB is empty list and carrier
+        // config plmn list also is empty , check whether an empty list is returned when calling
         // getSatellitePlmnsForCarrier before the entitlement query.
         doReturn(new ArrayList<>()).when(
                 mMockSubscriptionManagerService).getSatelliteEntitlementPlmnList(anyInt());
@@ -3158,8 +3267,9 @@
 
         // Successfully disable satellite
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -3168,11 +3278,12 @@
         // Time out to enable satellite
         ArgumentCaptor<Message> enableSatelliteResponse = ArgumentCaptor.forClass(Message.class);
         mIIntegerConsumerResults.clear();
-        setUpNoResponseForRequestSatelliteEnabled(true, false);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpNoResponseForRequestSatelliteEnabled(true, false, false);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
-        verify(mMockSatelliteModemInterface).requestSatelliteEnabled(eq(true), eq(false),
+        verify(mMockSatelliteModemInterface).requestSatelliteEnabled(eq(true), eq(false), eq(false),
                 enableSatelliteResponse.capture());
 
         clearInvocations(mMockSatelliteModemInterface);
@@ -3180,8 +3291,8 @@
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_MODEM_TIMEOUT, (long) mIIntegerConsumerResults.get(0));
-        verify(mMockSatelliteModemInterface).requestSatelliteEnabled(eq(false), eq(false), any(
-                Message.class));
+        verify(mMockSatelliteModemInterface).requestSatelliteEnabled(eq(false), eq(false),
+                eq(false), any(Message.class));
         verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
 
         // Send the response for the above request to enable satellite. SatelliteController should
@@ -3194,8 +3305,9 @@
 
         // Successfully enable satellite
         mIIntegerConsumerResults.clear();
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -3205,11 +3317,13 @@
         ArgumentCaptor<Message> disableSatelliteResponse = ArgumentCaptor.forClass(Message.class);
         mIIntegerConsumerResults.clear();
         clearInvocations(mMockSatelliteModemInterface);
-        setUpNoResponseForRequestSatelliteEnabled(false, false);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer);
+        setUpNoResponseForRequestSatelliteEnabled(false, false, false);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertFalse(waitForIIntegerConsumerResult(1));
         verify(mMockSatelliteModemInterface).requestSatelliteEnabled(eq(false), eq(false),
+                eq(false),
                 disableSatelliteResponse.capture());
 
         clearInvocations(mMockSatelliteModemInterface);
@@ -3218,7 +3332,7 @@
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_MODEM_TIMEOUT, (long) mIIntegerConsumerResults.get(0));
         verify(mMockSatelliteModemInterface, never()).requestSatelliteEnabled(anyBoolean(),
-                anyBoolean(), any(Message.class));
+                anyBoolean(), anyBoolean(), any(Message.class));
         verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
 
         // Send the response for the above request to disable satellite. SatelliteController should
@@ -3230,6 +3344,317 @@
         verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
     }
 
+    @Test
+    public void testUpdateNtnSignalStrentghReportWithFeatureFlagEnabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        mIsSatelliteEnabledSemaphore.drainPermits();
+        mIIntegerConsumerResults.clear();
+        resetSatelliteControllerUT();
+
+        // Successfully provisioned
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        sendProvisionedStateChangedEvent(true, null);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        sendProvisionedStateChangedEvent(true, null);
+        processAllMessages();
+        verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+
+        // startSendingNtnSignalStrength should be invoked when satellite is enabled
+        mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
+        assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled);
+        assertEquals(
+                SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue);
+        verify(mMockSatelliteModemInterface, times(1)).startSendingNtnSignalStrength(
+                any(Message.class));
+
+        // Ignore request ntn signal strength for redundant enable request
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
+        verify(mMockSatelliteModemInterface, never()).startSendingNtnSignalStrength(
+                any(Message.class));
+
+        // stopSendingNtnSignalStrength should be invoked when satellite is successfully off.
+        mIIntegerConsumerResults.clear();
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
+        verify(mMockSatelliteModemInterface, times(1)).stopSendingNtnSignalStrength(
+                any(Message.class));
+
+        // Ignore redundant request for stop reporting ntn signal strength.
+        mIIntegerConsumerResults.clear();
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        mIIntegerConsumerResults.clear();
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
+        verify(mMockSatelliteModemInterface, never()).stopSendingNtnSignalStrength(
+                any(Message.class));
+
+        // startSendingNtnSignalStrength is invoked when satellite is enabled again.
+        mIIntegerConsumerResults.clear();
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false;
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
+        assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled);
+        assertEquals(
+                SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue);
+        verify(mMockSatelliteModemInterface, times(1)).startSendingNtnSignalStrength(
+                any(Message.class));
+    }
+
+    @Test
+    public void testRegisterForSatelliteSupportedStateChanged_WithFeatureFlagEnabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        Semaphore semaphore = new Semaphore(0);
+        final boolean[] isSupported  = new boolean[1];
+        ISatelliteSupportedStateCallback callback =
+                new ISatelliteSupportedStateCallback.Stub() {
+                    @Override
+                    public void onSatelliteSupportedStateChanged(boolean supported) {
+                        logd("onSatelliteSupportedStateChanged: supported=" + supported);
+                        isSupported[0] = supported;
+                        try {
+                            semaphore.release();
+                        } catch (Exception ex) {
+                            loge("onSatelliteSupportedStateChanged: Got exception in releasing "
+                                    + "semaphore, ex=" + ex);
+                        }
+                    }
+                };
+
+        resetSatelliteControllerUT();
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        int errorCode = mSatelliteControllerUT.registerForSatelliteSupportedStateChanged(
+                SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_SUCCESS, errorCode);
+
+        sendSatelliteSupportedStateChangedEvent(true, null);
+        processAllMessages();
+        // Verify redundant report is ignored
+        assertFalse(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+
+        // Verify updated state is reported
+        sendSatelliteSupportedStateChangedEvent(false, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        assertEquals(false, isSupported[0]);
+        verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+
+        // Verify redundant report is ignored
+        sendSatelliteSupportedStateChangedEvent(false, null);
+        processAllMessages();
+        assertFalse(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+
+        // Verify updated state is reported
+        sendSatelliteSupportedStateChangedEvent(true, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        assertEquals(true, isSupported[0]);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+
+        // Successfully enable satellite
+        sendProvisionedStateChangedEvent(true, null);
+        processAllMessages();
+        verifySatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        mIIntegerConsumerResults.clear();
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
+        processAllMessages();
+        assertTrue(waitForIIntegerConsumerResult(1));
+        assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
+        verifySatelliteEnabled(true, SATELLITE_RESULT_SUCCESS);
+
+        // Send satellite is not supported state from modem to disable satellite
+        setUpResponseForRequestSatelliteEnabled(false, false, false, SATELLITE_RESULT_SUCCESS);
+        sendSatelliteSupportedStateChangedEvent(false, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        assertEquals(false, isSupported[0]);
+
+        // It is needed to set satellite as support to check whether satellite is enabled or not
+        sendSatelliteSupportedStateChangedEvent(true, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+        assertEquals(true, isSupported[0]);
+        // Verify satellite was disabled
+        verifySatelliteEnabled(false, SATELLITE_RESULT_SUCCESS);
+
+        mSatelliteControllerUT.unregisterForSatelliteSupportedStateChanged(SUB_ID, callback);
+        sendSatelliteSupportedStateChangedEvent(true, null);
+        processAllMessages();
+        assertFalse(waitForForEvents(
+                semaphore, 1, "testRegisterForSatelliteSupportedStateChanged"));
+    }
+
+    @Test
+    public void testRegisterForSatelliteSupportedStateChanged_WithFeatureFlagDisabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+
+        Semaphore semaphore = new Semaphore(0);
+        ISatelliteSupportedStateCallback callback =
+                new ISatelliteSupportedStateCallback.Stub() {
+                    @Override
+                    public void onSatelliteSupportedStateChanged(boolean supported) {
+                        logd("onSatelliteSupportedStateChanged: supported=" + supported);
+                        try {
+                            semaphore.release();
+                        } catch (Exception ex) {
+                            loge("onSatelliteSupportedStateChanged: Got exception in releasing "
+                                    + "semaphore, ex=" + ex);
+                        }
+                    }
+                };
+        int errorCode = mSatelliteControllerUT.registerForSatelliteSupportedStateChanged(
+                SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+    }
+
+    @Test
+    public void testIsSatelliteEmergencyMessagingSupportedViaCarrier() {
+        // Carrier-enabled flag is off
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Carrier-enabled flag is on and satellite attach is not supported
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Trigger carrier config changed to enable satellite attach
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+        assertFalse(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+
+        // Trigger carrier config changed to enable satellite attach & emergency messaging
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        mCarrierConfigBundle.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+        assertTrue(mSatelliteControllerUT.isSatelliteEmergencyMessagingSupportedViaCarrier());
+    }
+
+    @Test
+    public void testGetCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+        // Carrier-enabled flag is off
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+        assertEquals(DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Carrier-enabled flag is on
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+        assertEquals(DEFAULT_CARRIER_EMERGENCY_CALL_WAIT_FOR_CONNECTION_TIMEOUT_MILLIS,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Trigger carrier config changed to enable satellite attach
+        int timeoutMillisForCarrier1 = 1000;
+        PersistableBundle carrierConfigBundle1 = new PersistableBundle();
+        carrierConfigBundle1.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        carrierConfigBundle1.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        carrierConfigBundle1.putInt(
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
+                timeoutMillisForCarrier1);
+        doReturn(carrierConfigBundle1)
+                .when(mCarrierConfigManager).getConfigForSubId(eq(SUB_ID), anyVararg());
+
+        int timeoutMillisForCarrier2 = 2000;
+        PersistableBundle carrierConfigBundle2 = new PersistableBundle();
+        carrierConfigBundle2.putBoolean(
+                CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+        carrierConfigBundle2.putBoolean(
+                CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
+        carrierConfigBundle2.putInt(
+                KEY_EMERGENCY_CALL_TO_SATELLITE_T911_HANDOVER_TIMEOUT_MILLIS_INT,
+                timeoutMillisForCarrier2);
+        doReturn(carrierConfigBundle2)
+                .when(mCarrierConfigManager).getConfigForSubId(eq(SUB_ID1), anyVararg());
+
+        for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+                : mCarrierConfigChangedListenerList) {
+            pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+                    /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+            );
+        }
+        processAllMessages();
+
+        // Both phones are not in satellite mode for carrier roaming, and thus the max timeout
+        // duration - timeoutMillisForCarrier2 - is used
+        assertEquals(timeoutMillisForCarrier2,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Phone 1 is in satellite mode for carrier roaming
+        when(mServiceState.isUsingNonTerrestrialNetwork()).thenReturn(true);
+        assertEquals(timeoutMillisForCarrier1,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+
+        // Both phones are in satellite mode for carrier roaming. The timeout duration of the first
+        // phone will be selected
+        when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(true);
+        assertEquals(timeoutMillisForCarrier1,
+                mSatelliteControllerUT.getCarrierEmergencyCallWaitForConnectionTimeoutMillis());
+    }
+
     private void resetSatelliteControllerUTEnabledState() {
         logd("resetSatelliteControllerUTEnabledState");
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
@@ -3281,8 +3706,9 @@
         setRadioPower(true);
         processAllMessages();
 
-        setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_RESULT_SUCCESS);
-        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer);
+        setUpResponseForRequestSatelliteEnabled(true, false, false, SATELLITE_RESULT_SUCCESS);
+        mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, false,
+                mIIntegerConsumer);
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
@@ -3314,32 +3740,6 @@
         }).when(mMockSatelliteModemInterface).requestIsSatelliteSupported(any(Message.class));
     }
 
-    private void setUpResponseForRequestIsSatelliteAllowedForCurrentLocation(
-            boolean isSatelliteAllowed, @SatelliteManager.SatelliteResult int error) {
-        SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS)
-                ? null : new SatelliteException(error);
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-            AsyncResult.forMessage(message, isSatelliteAllowed, exception);
-            message.sendToTarget();
-            return null;
-        }).when(mMockSatelliteModemInterface)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(any(Message.class));
-    }
-
-    private void setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(
-            @SatelliteManager.SatelliteResult int error) {
-        SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS)
-                ? null : new SatelliteException(error);
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-            AsyncResult.forMessage(message, null, exception);
-            message.sendToTarget();
-            return null;
-        }).when(mMockSatelliteModemInterface)
-                .requestIsSatelliteCommunicationAllowedForCurrentLocation(any(Message.class));
-    }
-
     private void setUpResponseForRequestTimeForNextSatelliteVisibility(
             int satelliteVisibilityTime, @SatelliteManager.SatelliteResult int error) {
         SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS)
@@ -3381,19 +3781,21 @@
     }
 
     private void setUpResponseForRequestSatelliteEnabled(
-            boolean enabled, boolean demoMode, @SatelliteManager.SatelliteResult int error) {
+            boolean enabled, boolean demoMode, boolean emergency,
+            @SatelliteManager.SatelliteResult int error) {
         SatelliteException exception = (error == SATELLITE_RESULT_SUCCESS)
                 ? null : new SatelliteException(error);
         doAnswer(invocation -> {
             if (exception == null && !enabled) {
                 sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_OFF, null);
             }
-            Message message = (Message) invocation.getArguments()[2];
+            Message message = (Message) invocation.getArguments()[3];
             AsyncResult.forMessage(message, null, exception);
             message.sendToTarget();
             return null;
         }).when(mMockSatelliteModemInterface)
-                .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class));
+                .requestSatelliteEnabled(eq(enabled), eq(demoMode), eq(emergency),
+                        any(Message.class));
     }
 
     private void setUpResponseForRequestSetSatelliteEnabledForCarrier(
@@ -3409,9 +3811,11 @@
                 .requestSetSatelliteEnabledForCarrier(anyInt(), eq(enabled), any(Message.class));
     }
 
-    private void setUpNoResponseForRequestSatelliteEnabled(boolean enabled, boolean demoMode) {
+    private void setUpNoResponseForRequestSatelliteEnabled(boolean enabled, boolean demoMode,
+            boolean emergency) {
         doNothing().when(mMockSatelliteModemInterface)
-                .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class));
+                .requestSatelliteEnabled(eq(enabled), eq(demoMode), eq(emergency),
+                        any(Message.class));
     }
 
     private void setUpResponseForProvisionSatelliteService(
@@ -3563,24 +3967,6 @@
         return true;
     }
 
-    private boolean waitForRequestIsSatelliteAllowedForCurrentLocationResult(
-            int expectedNumberOfEvents) {
-        for (int i = 0; i < expectedNumberOfEvents; i++) {
-            try {
-                if (!mSatelliteAllowedSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
-                    loge("Timeout to receive "
-                            + "requestIsCommunicationAllowedForCurrentLocation()"
-                            + " callback");
-                    return false;
-                }
-            } catch (Exception ex) {
-                loge("waitForRequestIsSatelliteSupportedResult: Got exception=" + ex);
-                return false;
-            }
-        }
-        return true;
-    }
-
     private boolean waitForRequestTimeForNextSatelliteVisibilityResult(
             int expectedNumberOfEvents) {
         for (int i = 0; i < expectedNumberOfEvents; i++) {
@@ -3791,6 +4177,13 @@
         msg.sendToTarget();
     }
 
+    private void sendSatelliteSupportedStateChangedEvent(boolean supported, Throwable exception) {
+        Message msg = mSatelliteControllerUT.obtainMessage(
+                41 /* EVENT_SATELLITE_SUPPORTED_STATE_CHANGED */);
+        msg.obj = new AsyncResult(null, supported, exception);
+        msg.sendToTarget();
+    }
+
     private void setRadioPower(boolean on) {
         mSimulatedCommands.setRadioPower(on, false, false, null);
     }
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 d12828a..67e0174 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -86,7 +86,7 @@
 @TestableLooper.RunWithLooper
 public class SatelliteSOSMessageRecommenderTest extends TelephonyTest {
     private static final String TAG = "SatelliteSOSMessageRecommenderTest";
-    private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
+    private static final int TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
     private static final int PHONE_ID = 0;
     private static final int PHONE_ID2 = 1;
     private static final String CALL_ID = "CALL_ID";
@@ -118,6 +118,9 @@
                 .thenReturn("");
         when(mResources.getString(R.string.config_satellite_emergency_handover_intent_action))
                 .thenReturn(DEFAULT_HANDOVER_INTENT_ACTION);
+        when(mResources.getInteger(
+                R.integer.config_emergency_call_wait_for_connection_timeout_millis))
+                .thenReturn(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
         when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
         mTestSatelliteController = new TestSatelliteController(mContext,
                 Looper.myLooper(), mFeatureFlags);
@@ -132,8 +135,7 @@
         when(mPhone2.getServiceState()).thenReturn(mServiceState2);
         when(mPhone2.getPhoneId()).thenReturn(PHONE_ID2);
         mTestSOSMessageRecommender = new TestSOSMessageRecommender(mContext, Looper.myLooper(),
-                mTestSatelliteController, mTestImsManager,
-                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+                mTestSatelliteController, mTestImsManager);
         when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
         when(mPhone.isImsRegistered()).thenReturn(false);
@@ -505,8 +507,7 @@
         TestSOSMessageRecommender testSOSMessageRecommender = new TestSOSMessageRecommender(
                 mContext,
                 Looper.myLooper(),
-                satelliteController, mTestImsManager,
-                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+                satelliteController, mTestImsManager);
         testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
         processAllMessages();
 
@@ -532,6 +533,32 @@
                 originalIsSatelliteViaOemProvisioned;
     }
 
+    @Test
+    public void testSelectEmergencyCallWaitForConnectionTimeoutDuration() {
+        // Both OEM and carrier don't support satellite
+        mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = false;
+        mTestSatelliteController.isOemEnabledSatelliteSupported = false;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(0, mTestSOSMessageRecommender.getTimeOutMillis());
+
+        // Only OEM support satellite
+        mTestSatelliteController.isOemEnabledSatelliteSupported = true;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
+                mTestSOSMessageRecommender.getTimeOutMillis());
+
+        // Both OEM and carrier support satellite. Thus, carrier's timeout duration will be used
+        long carrierTimeoutMillis = 1000;
+        mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = true;
+        mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                carrierTimeoutMillis;
+        mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+        processAllMessages();
+        assertEquals(carrierTimeoutMillis, mTestSOSMessageRecommender.getTimeOutMillis());
+    }
+
     private void testStopTrackingCallBeforeTimeout(
             @Connection.ConnectionState int connectionState) {
         mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
@@ -636,6 +663,9 @@
         private boolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = true;
         public boolean isOemEnabledSatelliteSupported = true;
         public boolean isCarrierEnabledSatelliteSupported = true;
+        public boolean isSatelliteEmergencyMessagingSupportedViaCarrier = true;
+        public long carrierEmergencyCallWaitForConnectionTimeoutMillis =
+                TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS;
 
         /**
          * Create a SatelliteController to act as a backend service of
@@ -696,6 +726,16 @@
             return INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
         }
 
+        @Override
+        public boolean isSatelliteEmergencyMessagingSupportedViaCarrier() {
+            return isSatelliteEmergencyMessagingSupportedViaCarrier;
+        }
+
+        @Override
+        public long getCarrierEmergencyCallWaitForConnectionTimeoutMillis() {
+            return carrierEmergencyCallWaitForConnectionTimeoutMillis;
+        }
+
         public void setSatelliteConnectedViaCarrierWithinHysteresisTime(
                 boolean connectedViaCarrier) {
             mIsSatelliteConnectedViaCarrierWithinHysteresisTime = connectedViaCarrier;
@@ -811,12 +851,10 @@
          * @param imsManager          The ImsManager instance associated with the phone, which is
          *                            used for making the emergency call. This argument is not
          *                            null only in unit tests.
-         * @param timeoutMillis       The timeout duration of the timer.
          */
         TestSOSMessageRecommender(Context context, Looper looper,
-                SatelliteController satelliteController, ImsManager imsManager,
-                long timeoutMillis) {
-            super(context, looper, satelliteController, imsManager, timeoutMillis);
+                SatelliteController satelliteController, ImsManager imsManager) {
+            super(context, looper, satelliteController, imsManager);
         }
 
         @Override
@@ -843,6 +881,10 @@
         public void sendServiceStateChangedEvent() {
             sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED));
         }
+
+        public long getTimeOutMillis() {
+            return mTimeoutMillis;
+        }
     }
 
     private static class TestConnection extends Connection {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java
index 28874df..0e4adcd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteServiceUtilsTest.java
@@ -17,6 +17,7 @@
 package com.android.internal.telephony.satellite;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.os.PersistableBundle;
@@ -60,6 +61,8 @@
         String plmn1 = "10101";
         String plmn2 = "10102";
         String plmn3 = "10103";
+        String plmn4 = "";
+        String plmn5 = "123456789";
         int[] supportedServicesForPlmn1 = {1, 2, 3};
         int[] supportedServicesForPlmn2 = {3, 4, 100};
         int[] expectedServicesForPlmn1 = {1, 2, 3};
@@ -74,6 +77,8 @@
         supportedServicesBundle.putIntArray(plmn1, supportedServicesForPlmn1);
         supportedServicesBundle.putIntArray(plmn2, supportedServicesForPlmn2);
         supportedServicesBundle.putIntArray(plmn3, new int[0]);
+        supportedServicesBundle.putIntArray(plmn4, supportedServicesForPlmn1);
+        supportedServicesBundle.putIntArray(plmn5, supportedServicesForPlmn2);
 
         supportedServiceMap =
                 SatelliteServiceUtils.parseSupportedSatelliteServices(supportedServicesBundle);
@@ -96,6 +101,9 @@
         assertTrue(supportedServiceMap.containsKey(plmn3));
         supportedServices = supportedServiceMap.get(plmn3);
         assertTrue(supportedServices.isEmpty());
+
+        assertFalse(supportedServiceMap.containsKey(plmn4));
+        assertFalse(supportedServiceMap.containsKey(plmn5));
     }
 
     @Test
@@ -105,5 +113,10 @@
         List<String> expectedMergedList = Arrays.asList("1", "2", "3");
         List<String> mergedList = SatelliteServiceUtils.mergeStrLists(l1, l2);
         assertEquals(expectedMergedList, mergedList);
+
+        List<String> l3 = Arrays.asList("2", "3", "4");
+        expectedMergedList = Arrays.asList("1", "2", "3", "4");
+        mergedList = SatelliteServiceUtils.mergeStrLists(l1, l2, l3);
+        assertEquals(expectedMergedList, mergedList);
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
index 6e2c5bf..de43b85 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java
@@ -341,4 +341,69 @@
         assertThat(subInfoNull.getCountryIso()).isEqualTo("");
         assertThat(subInfoNull.getGroupOwner()).isEqualTo("");
     }
+
+    @Test
+    public void testIsVisible() {
+        // Regular profile
+        SubscriptionInfoInternal regularSub =
+                new SubscriptionInfoInternal.Builder()
+                    .setId(2)
+                    .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1)
+                    .setSimSlotIndex(0)
+                    .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+                    .setOnlyNonTerrestrialNetwork(0)
+                    .setOpportunistic(0)
+                    .setGroupUuid(SubscriptionDatabaseManagerTest.FAKE_UUID1)
+                    .build();
+        assertThat(regularSub.isVisible()).isTrue();
+
+        // Provisioning profile
+        SubscriptionInfoInternal provSub =
+                new SubscriptionInfoInternal.Builder()
+                    .setId(2)
+                    .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1)
+                    .setSimSlotIndex(0)
+                    .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING)
+                    .setOnlyNonTerrestrialNetwork(0)
+                    .setOpportunistic(0)
+                    .build();
+        assertThat(provSub.isVisible()).isFalse();
+
+        // NTN profile
+        SubscriptionInfoInternal ntnSub =
+                new SubscriptionInfoInternal.Builder()
+                    .setId(2)
+                    .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1)
+                    .setSimSlotIndex(0)
+                    .setOnlyNonTerrestrialNetwork(1)
+                    .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+                    .setOpportunistic(0)
+                    .build();
+        assertThat(ntnSub.isVisible()).isFalse();
+
+        // Opportunistic profile without group UUID
+        SubscriptionInfoInternal opportunisticSub =
+                new SubscriptionInfoInternal.Builder()
+                    .setId(2)
+                    .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1)
+                    .setSimSlotIndex(0)
+                    .setOnlyNonTerrestrialNetwork(0)
+                    .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+                    .setOpportunistic(1)
+                    .build();
+        assertThat(opportunisticSub.isVisible()).isTrue();
+
+        // Opportunistic profile with group UUID
+        SubscriptionInfoInternal opportunisticSubUuid =
+                new SubscriptionInfoInternal.Builder()
+                    .setId(2)
+                    .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1)
+                    .setSimSlotIndex(0)
+                    .setOnlyNonTerrestrialNetwork(0)
+                    .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL)
+                    .setOpportunistic(1)
+                    .setGroupUuid(SubscriptionDatabaseManagerTest.FAKE_UUID1)
+                    .build();
+        assertThat(opportunisticSubUuid.isVisible()).isFalse();
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
index defa730..9fee311 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java
@@ -43,13 +43,16 @@
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER2;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG1;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG2;
+import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SATELLITE_ENTITLEMENT_PLMNS1;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO1;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO2;
 import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_UUID1;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -131,11 +134,13 @@
 import java.io.StringWriter;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -3202,4 +3207,60 @@
         System.setProperty("persist.radio.allow_mock_modem", "false");
         doReturn(false).when(mFlags).oemEnabledSatelliteFlag();
     }
+
+    @Test
+    public void testGetSatelliteEntitlementPlmnList() throws Exception {
+        mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE);
+
+        // When the empty list is stored, verify whether SubscriptionInfoInternal returns an
+        // empty string and SubscriptionManagerService returns an empty List.
+        insertSubscription(FAKE_SUBSCRIPTION_INFO1);
+        List<String> expectedPlmnList = new ArrayList<>();
+        int subId = 1;
+
+        SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT
+                .getSubscriptionInfoInternal(subId);
+        assertTrue(subInfo.getSatelliteEntitlementPlmns().isEmpty());
+        assertEquals(expectedPlmnList,
+                mSubscriptionManagerServiceUT.getSatelliteEntitlementPlmnList(subId));
+
+        // When the list is stored as [123123,12310], verify whether SubscriptionInfoInternal
+        // returns the string as "123123,12310" and SubscriptionManagerService returns the List as
+        // [123123,12310].
+        insertSubscription(FAKE_SUBSCRIPTION_INFO2);
+        String expectedPlmn = FAKE_SATELLITE_ENTITLEMENT_PLMNS1;
+        expectedPlmnList = Arrays.stream(expectedPlmn.split(",")).collect(Collectors.toList());
+        subId = 2;
+
+        subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(subId);
+        assertEquals(expectedPlmn, subInfo.getSatelliteEntitlementPlmns());
+        assertEquals(expectedPlmnList,
+                mSubscriptionManagerServiceUT.getSatelliteEntitlementPlmnList(subId));
+
+        // When calling SubscriptionDatabaseManager#getSubscriptionInfoInternalreturns returns a
+        // null, then verify the SubscriptionManagerService returns an empty List.
+        SubscriptionDatabaseManager mockSubscriptionDatabaseManager = Mockito.mock(
+                SubscriptionDatabaseManager.class);
+        Field field = SubscriptionManagerService.class.getDeclaredField(
+                "mSubscriptionDatabaseManager");
+        field.setAccessible(true);
+        field.set(mSubscriptionManagerServiceUT, mockSubscriptionDatabaseManager);
+
+        doReturn(null).when(mockSubscriptionDatabaseManager).getSubscriptionInfoInternal(anyInt());
+        expectedPlmnList = new ArrayList<>();
+        assertEquals(expectedPlmnList,
+                mSubscriptionManagerServiceUT.getSatelliteEntitlementPlmnList(subId));
+
+        // When calling SubscriptionDatabaseManager#getSubscriptionInfoInternalreturns returns a
+        // non null. And when calling SubscriptionInfoInternal#getSatelliteEntitlementPlmns
+        // returns a null, then verify the SubscriptionManagerService returns an empty List.
+        SubscriptionInfoInternal mockSubscriptionInfoInternal = Mockito.mock(
+                SubscriptionInfoInternal.class);
+        doReturn(mockSubscriptionInfoInternal).when(
+                mockSubscriptionDatabaseManager).getSubscriptionInfoInternal(anyInt());
+        doReturn(null).when(mockSubscriptionInfoInternal).getSatelliteEntitlementPlmns();
+
+        assertEquals(expectedPlmnList,
+                mSubscriptionManagerServiceUT.getSatelliteEntitlementPlmnList(subId));
+    }
 }