Merge "add feature flag to fix stuck imcoming call" into main
diff --git a/Android.bp b/Android.bp
index 66cca32..301343c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -90,7 +90,6 @@
         "android.hardware.radio.modem-V3-java",
         "android.hardware.radio.network-V3-java",
         "android.hardware.radio.sim-V3-java",
-        "android.hardware.radio.satellite-V1-java",
         "android.hardware.radio.voice-V3-java",
         "voip-common",
         "ims-common",
diff --git a/flags/data.aconfig b/flags/data.aconfig
index c769bcc..0bcd4bd 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -1,8 +1,22 @@
 package: "com.android.internal.telephony.flags"
 
 flag {
+  name: "unthrottle_check_transport"
+  namespace: "telephony"
+  description: "Check transport when unthrottle."
+  bug: "303922311"
+}
+
+flag {
   name: "relax_ho_teardown"
   namespace: "telephony"
   description: "Relax handover tear down if the device is currently in voice call."
   bug: "270895912"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "allow_mmtel_in_non_vops"
+  namespace: "telephony"
+  description: "Allow bring up MMTEL in nonVops area specified by carrier config."
+  bug: "241198464"
+}
diff --git a/flags/messaging.aconfig b/flags/messaging.aconfig
index 777edb7..3c20d69 100644
--- a/flags/messaging.aconfig
+++ b/flags/messaging.aconfig
@@ -5,4 +5,11 @@
   namespace: "telephony"
   description: "Previously, the DB allows insertion of a random sub Id, but doesn't allow query it. This change rejects such interaction."
   bug: "294125411"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "sms_domain_selection_enabled"
+  namespace: "telephony"
+  description: "This flag controls AP domain selection support for normal/emergency SMS."
+  bug: "262804071"
+}
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 2b5ab2b..87acccc 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -13,4 +13,11 @@
   namespace: "telephony"
   description: "Whether to log MMS/SMS database access info and report anomaly when getting exception."
   bug: "275225402"
+}
+
+flag {
+  name: "enable_wps_check_api_flag"
+  namespace: "telephony"
+  description: "Enable system api isWpsCallNumber. Its an utility api to check if the dialed number is for Wireless Priority Service call."
+  bug: "304272356"
 }
\ No newline at end of file
diff --git a/flags/network.aconfig b/flags/network.aconfig
index 0c7873e..299a2a0 100644
--- a/flags/network.aconfig
+++ b/flags/network.aconfig
@@ -6,3 +6,10 @@
     description: "enabling this flag allows KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY to control N1 mode enablement"
     bug:"302033535"
 }
+
+flag {
+  name: "hide_roaming_icon"
+  namespace: "telephony"
+  description: "Allow carriers to hide the roaming (R) icon when roaming."
+  bug: "301467052"
+}
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 722cb7c..993aa4d 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -427,6 +427,8 @@
     optional int64 video_available_millis = 10;
     optional int64 ut_capable_millis = 11;
     optional int64 ut_available_millis = 12;
+    optional int64 registering_millis = 13;
+    optional int64 unregistered_millis = 14;
 
     // Internal use only
     optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index f461e68..4ec1f71 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -18,7 +18,6 @@
 package com.android.internal.telephony;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.AsyncResult;
@@ -119,13 +118,6 @@
     protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList();
     protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList();
     protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList();
-    protected RegistrantList mPendingSatelliteMessageCountRegistrants = new RegistrantList();
-    protected RegistrantList mNewSatelliteMessagesRegistrants = new RegistrantList();
-    protected RegistrantList mSatelliteMessagesTransferCompleteRegistrants = new RegistrantList();
-    protected RegistrantList mSatellitePointingInfoChangedRegistrants = new RegistrantList();
-    protected RegistrantList mSatelliteModeChangedRegistrants = new RegistrantList();
-    protected RegistrantList mSatelliteRadioTechnologyChangedRegistrants = new RegistrantList();
-    protected RegistrantList mSatelliteProvisionStateChangedRegistrants = new RegistrantList();
 
     @UnsupportedAppUsage
     protected Registrant mGsmSmsRegistrant;
@@ -1182,81 +1174,4 @@
     public void unregisterForTriggerImsDeregistration(Handler h) {
         mTriggerImsDeregistrationRegistrants.remove(h);
     }
-
-    @Override
-    public void registerForPendingSatelliteMessageCount(
-            @NonNull Handler h, int what, @Nullable Object obj) {
-        mPendingSatelliteMessageCountRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) {
-        mPendingSatelliteMessageCountRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForNewSatelliteMessages(
-            @NonNull Handler h, int what, @Nullable Object obj) {
-        mNewSatelliteMessagesRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForNewSatelliteMessages(@NonNull Handler h) {
-        mNewSatelliteMessagesRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForSatelliteMessagesTransferComplete(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        mSatelliteMessagesTransferCompleteRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) {
-        mSatelliteMessagesTransferCompleteRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForSatellitePointingInfoChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        mSatellitePointingInfoChangedRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) {
-        mSatellitePointingInfoChangedRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForSatelliteModeChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        mSatelliteModeChangedRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForSatelliteModeChanged(@NonNull Handler h) {
-        mSatelliteModeChangedRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        mSatelliteRadioTechnologyChangedRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) {
-        mSatelliteRadioTechnologyChangedRegistrants.remove(h);
-    }
-
-    @Override
-    public void registerForSatelliteProvisionStateChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        mSatelliteProvisionStateChangedRegistrants.add(h, what, obj);
-    }
-
-    @Override
-    public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {
-        mSatelliteProvisionStateChangedRegistrants.remove(h);
-    }
 }
diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
index beb6b26..195ef16 100644
--- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
+++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PersistableBundle;
+import android.os.UserManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ImsiEncryptionInfo;
 import android.telephony.SubscriptionManager;
@@ -108,6 +109,7 @@
     private boolean mAllowedOverMeteredNetwork = false;
     private boolean mDeleteOldKeyAfterDownload = false;
     private TelephonyManager mTelephonyManager;
+    private UserManager mUserManager;
 
     @VisibleForTesting
     public String mMccMncForDownload;
@@ -125,18 +127,35 @@
         mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
                 .createForSubscriptionId(mPhone.getSubId());
+        mUserManager = mContext.getSystemService(UserManager.class);
         CarrierConfigManager carrierConfigManager = mContext.getSystemService(
                 CarrierConfigManager.class);
         // Callback which directly handle config change should be executed on handler thread
         carrierConfigManager.registerCarrierConfigChangeListener(this::post,
                 (slotIndex, subId, carrierId, specificCarrierId) -> {
-                    if (slotIndex == mPhone.getPhoneId()) {
+                    boolean isUserUnlocked = mUserManager.isUserUnlocked();
+
+                    if (isUserUnlocked && slotIndex == mPhone.getPhoneId()) {
                         Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex);
                         handleAlarmOrConfigChange();
+                    } else {
+                        Log.d(LOG_TAG, "User is locked");
+                        mContext.registerReceiver(mUserUnlockedReceiver, new IntentFilter(
+                                Intent.ACTION_USER_UNLOCKED));
                     }
                 });
     }
 
+    private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+                Log.d(LOG_TAG, "Received UserUnlockedReceiver");
+                handleAlarmOrConfigChange();
+            }
+        }
+    };
+
     private final BroadcastReceiver mDownloadReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java
index 6b6d84f..6b80e9f 100644
--- a/src/java/com/android/internal/telephony/CommandException.java
+++ b/src/java/com/android/internal/telephony/CommandException.java
@@ -352,28 +352,6 @@
                 return new CommandException(Error.RF_HARDWARE_ISSUE);
             case RILConstants.NO_RF_CALIBRATION_INFO:
                 return new CommandException(Error.NO_RF_CALIBRATION_INFO);
-            case RILConstants.ENCODING_NOT_SUPPORTED:
-                return new CommandException(Error.ENCODING_NOT_SUPPORTED);
-            case RILConstants.FEATURE_NOT_SUPPORTED:
-                return new CommandException(Error.FEATURE_NOT_SUPPORTED);
-            case RILConstants.INVALID_CONTACT:
-                return new CommandException(Error.INVALID_CONTACT);
-            case RILConstants.MODEM_INCOMPATIBLE:
-                return new CommandException(Error.MODEM_INCOMPATIBLE);
-            case RILConstants.NETWORK_TIMEOUT:
-                return new CommandException(Error.NETWORK_TIMEOUT);
-            case RILConstants.NO_SATELLITE_SIGNAL:
-                return new CommandException(Error.NO_SATELLITE_SIGNAL);
-            case RILConstants.NOT_SUFFICIENT_ACCOUNT_BALANCE:
-                return new CommandException(Error.NOT_SUFFICIENT_ACCOUNT_BALANCE);
-            case RILConstants.RADIO_TECHNOLOGY_NOT_SUPPORTED:
-                return new CommandException(Error.RADIO_TECHNOLOGY_NOT_SUPPORTED);
-            case RILConstants.SUBSCRIBER_NOT_AUTHORIZED:
-                return new CommandException(Error.SUBSCRIBER_NOT_AUTHORIZED);
-            case RILConstants.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL:
-                return new CommandException(Error.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL);
-            case RILConstants.UNIDENTIFIED_SUBSCRIBER:
-                return new CommandException(Error.UNIDENTIFIED_SUBSCRIBER);
             default:
                 Rlog.e("GSM", "Unrecognized RIL errno " + ril_errno);
                 return new CommandException(Error.INVALID_RESPONSE);
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 006a421..71c2001 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -74,7 +74,6 @@
     // Used as parameters for call forward methods below
     static final int CF_ACTION_DISABLE          = 0;
     static final int CF_ACTION_ENABLE           = 1;
-//  static final int CF_ACTION_UNUSED           = 2;
     static final int CF_ACTION_REGISTRATION     = 3;
     static final int CF_ACTION_ERASURE          = 4;
 
@@ -628,85 +627,85 @@
     @UnsupportedAppUsage
     void setEmergencyCallbackMode(Handler h, int what, Object obj);
 
-     /**
-      * Fires on any CDMA OTA provision status change
-      */
-     @UnsupportedAppUsage
-     void registerForCdmaOtaProvision(Handler h,int what, Object obj);
-     @UnsupportedAppUsage
-     void unregisterForCdmaOtaProvision(Handler h);
+    /**
+     * Fires on any CDMA OTA provision status change
+     */
+    @UnsupportedAppUsage
+    void registerForCdmaOtaProvision(Handler h, int what, Object obj);
+    @UnsupportedAppUsage
+    void unregisterForCdmaOtaProvision(Handler h);
 
-     /**
-      * Registers the handler when out-band ringback tone is needed.<p>
-      *
-      *  Messages received from this:
-      *  Message.obj will be an AsyncResult
-      *  AsyncResult.userObj = obj
-      *  AsyncResult.result = boolean. <p>
-      */
-     void registerForRingbackTone(Handler h, int what, Object obj);
-     void unregisterForRingbackTone(Handler h);
+    /**
+     * Registers the handler when out-band ringback tone is needed.<p>
+     *
+     *  Messages received from this:
+     *  Message.obj will be an AsyncResult
+     *  AsyncResult.userObj = obj
+     *  AsyncResult.result = boolean. <p>
+     */
+    void registerForRingbackTone(Handler h, int what, Object obj);
+    void unregisterForRingbackTone(Handler h);
 
-     /**
-      * Registers the handler when mute/unmute need to be resent to get
-      * uplink audio during a call.<p>
-      *
-      * @param h Handler for notification message.
-      * @param what User-defined message code.
-      * @param obj User object.
-      *
-      */
-     void registerForResendIncallMute(Handler h, int what, Object obj);
-     void unregisterForResendIncallMute(Handler h);
+    /**
+     * Registers the handler when mute/unmute need to be resent to get
+     * uplink audio during a call.<p>
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     *
+     */
+    void registerForResendIncallMute(Handler h, int what, Object obj);
+    void unregisterForResendIncallMute(Handler h);
 
-     /**
-      * Registers the handler for when Cdma subscription changed events
-      *
-      * @param h Handler for notification message.
-      * @param what User-defined message code.
-      * @param obj User object.
-      *
-      */
-     void registerForCdmaSubscriptionChanged(Handler h, int what, Object obj);
-     void unregisterForCdmaSubscriptionChanged(Handler h);
+    /**
+     * Registers the handler for when Cdma subscription changed events
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     *
+     */
+    void registerForCdmaSubscriptionChanged(Handler h, int what, Object obj);
+    void unregisterForCdmaSubscriptionChanged(Handler h);
 
-     /**
-      * Registers the handler for when Cdma prl changed events
-      *
-      * @param h Handler for notification message.
-      * @param what User-defined message code.
-      * @param obj User object.
-      *
-      */
-     void registerForCdmaPrlChanged(Handler h, int what, Object obj);
-     void unregisterForCdmaPrlChanged(Handler h);
+    /**
+     * Registers the handler for when Cdma prl changed events
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     *
+     */
+    void registerForCdmaPrlChanged(Handler h, int what, Object obj);
+    void unregisterForCdmaPrlChanged(Handler h);
 
-     /**
-      * Registers the handler for when Cdma prl changed events
-      *
-      * @param h Handler for notification message.
-      * @param what User-defined message code.
-      * @param obj User object.
-      *
-      */
-     void registerForExitEmergencyCallbackMode(Handler h, int what, Object obj);
-     void unregisterForExitEmergencyCallbackMode(Handler h);
+    /**
+     * Registers the handler for when Cdma prl changed events
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     *
+     */
+    void registerForExitEmergencyCallbackMode(Handler h, int what, Object obj);
+    void unregisterForExitEmergencyCallbackMode(Handler h);
 
-     /**
-      * Registers the handler for RIL_UNSOL_RIL_CONNECT events.
-      *
-      * When ril connects or disconnects a message is sent to the registrant
-      * which contains an AsyncResult, ar, in msg.obj. The ar.result is an
-      * Integer which is the version of the ril or -1 if the ril disconnected.
-      *
-      * @param h Handler for notification message.
-      * @param what User-defined message code.
-      * @param obj User object.
-      */
-     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-     void registerForRilConnected(Handler h, int what, Object obj);
-     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-     void unregisterForRilConnected(Handler h);
+    /**
+     * Registers the handler for RIL_UNSOL_RIL_CONNECT events.
+     *
+     * When ril connects or disconnects a message is sent to the registrant
+     * which contains an AsyncResult, ar, in msg.obj. The ar.result is an
+     * Integer which is the version of the ril or -1 if the ril disconnected.
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    void registerForRilConnected(Handler h, int what, Object obj);
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    void unregisterForRilConnected(Handler h);
 
     /**
      * Registers the handler for RIL_UNSOL_SIM_DETACH_FROM_NETWORK_CONFIG_CHANGED events.
@@ -921,7 +920,7 @@
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
     void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,
-              boolean hasKnownUserIntentEmergency, int clirMode, Message result);
+            boolean hasKnownUserIntentEmergency, int clirMode, Message result);
 
     /**
      *  returned message
@@ -935,7 +934,7 @@
      * CLIR_INVOCATION  == on "CLIR invocation" (restrict CLI presentation)
      */
     void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,
-              boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result);
+            boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result);
 
     /**
      *  returned message
@@ -1372,7 +1371,7 @@
      */
     @UnsupportedAppUsage
     void setCallForward(int action, int cfReason, int serviceClass,
-                String number, int timeSeconds, Message response);
+            String number, int timeSeconds, Message response);
 
     /**
      * cfReason is one of CF_REASON_*
@@ -1450,7 +1449,7 @@
 
     @UnsupportedAppUsage
     void queryFacilityLock (String facility, String password, int serviceClass,
-        Message response);
+            Message response);
 
     /**
      * (AsyncResult)response.obj).result will be an Integer representing
@@ -1465,7 +1464,7 @@
      */
 
     void queryFacilityLockForApp(String facility, String password, int serviceClass, String appId,
-        Message response);
+            Message response);
 
     /**
      * @param facility one of CB_FACILTY_*
@@ -1476,7 +1475,7 @@
      */
     @UnsupportedAppUsage
     void setFacilityLock (String facility, boolean lockState, String password,
-        int serviceClass, Message response);
+            int serviceClass, Message response);
 
     /**
      * Set the facility lock for the app with this AID on the ICC card.
@@ -1489,7 +1488,7 @@
      * @param response is callback message
      */
     void setFacilityLockForApp(String facility, boolean lockState, String password,
-        int serviceClass, String appId, Message response);
+            int serviceClass, String appId, Message response);
 
     void sendUSSD (String ussdString, Message response);
 
@@ -1526,7 +1525,7 @@
     @UnsupportedAppUsage
     void setPreferredNetworkType(int networkType , Message response);
 
-     /**
+    /**
      *  Query the preferred network type setting
      *
      * @param response is callback message to report one of  NT_*_TYPE
@@ -1543,7 +1542,7 @@
     void setAllowedNetworkTypesBitmap(
             @TelephonyManager.NetworkTypeBitMask int networkTypeBitmask, Message response);
 
-     /**
+    /**
      *  Query the allowed network types setting.
      *
      * @param response is callback message to report allowed network types bitmask
@@ -2148,7 +2147,7 @@
         return HalVersion.UNKNOWN;
     }
 
-   /**
+    /**
      * Sets user selected subscription at Modem.
      *
      * @param slotId
@@ -2613,7 +2612,7 @@
         return true;
     };
 
-   /**
+    /**
      * Return the class name of the currently bound modem service.
      *
      * @return the class name of the modem service.
@@ -2622,18 +2621,18 @@
         return "default";
     };
 
-   /**
+    /**
      * Request the SIM phonebook records of all activated UICC applications
      *
      * @param result Callback message containing the count of ADN valid record.
      */
-    public void getSimPhonebookRecords(Message result);
+    void getSimPhonebookRecords(Message result);
 
-   /**
+    /**
      * Request the SIM phonebook Capacity of all activated UICC applications
      *
      */
-    public void getSimPhonebookCapacity(Message result);
+    void getSimPhonebookCapacity(Message result);
 
     /**
      * Request to insert/delete/update the SIM phonebook record
@@ -2641,7 +2640,7 @@
      * @param phonebookRecordInfo adn record information to be updated
      * @param result Callback message containing the SIM phonebook record index.
      */
-    public void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecordInfo, Message result);
+    void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecordInfo, Message result);
 
     /**
      * Registers the handler when the SIM phonebook is changed.
@@ -2650,14 +2649,14 @@
      * @param what User-defined message code.
      * @param obj User object .
      */
-    public void registerForSimPhonebookChanged(Handler h, int what, Object obj);
+    void registerForSimPhonebookChanged(Handler h, int what, Object obj);
 
     /**
      * Unregister for notifications when SIM phonebook has already init done.
      *
      * @param h Handler to be removed from the registrant list.
      */
-    public void unregisterForSimPhonebookChanged(Handler h);
+    void unregisterForSimPhonebookChanged(Handler h);
 
     /**
      * Registers the handler when a group of SIM phonebook records received.
@@ -2666,14 +2665,14 @@
      * @param what User-defined message code.
      * @param obj User object.
      */
-    public void registerForSimPhonebookRecordsReceived(Handler h, int what, Object obj);
+    void registerForSimPhonebookRecordsReceived(Handler h, int what, Object obj);
 
     /**
      * Unregister for notifications when a group of SIM phonebook records received.
      *
      * @param h Handler to be removed from the registrant list.
      */
-     public void unregisterForSimPhonebookRecordsReceived(Handler h);
+    void unregisterForSimPhonebookRecordsReceived(Handler h);
 
     /**
      * Registers for notifications of connection setup failure.
@@ -2892,263 +2891,4 @@
      * @param result Callback message to receive the result.
      */
     default void isN1ModeEnabled(Message result) {}
-
-    /**
-     * Get feature capabilities supported by satellite.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    default void getSatelliteCapabilities(Message result) {}
-
-    /**
-     * Turn satellite modem on/off.
-     *
-     * @param result Message that will be sent back to the requester
-     * @param on {@code true} for turning on.
-     *           {@code false} for turning off.
-     */
-    default void setSatellitePower(Message result, boolean on) {}
-
-    /**
-     * Get satellite modem state.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    default void getSatellitePowerState(Message result) {}
-
-    /**
-     * Get satellite provision state.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    default void getSatelliteProvisionState(Message result) {}
-
-    /**
-     * Check whether satellite modem is supported by the device.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    default void isSatelliteSupported(Message result) {}
-
-    /**
-     * Provision the subscription with a satellite provider. This is needed to register the
-     * subscription if the provider allows dynamic registration.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param imei IMEI of the SIM associated with the satellite modem.
-     * @param msisdn MSISDN of the SIM associated with the satellite modem.
-     * @param imsi IMSI of the SIM associated with the satellite modem.
-     * @param features List of features to be provisioned.
-     */
-    default void provisionSatelliteService(
-            Message result, String imei, String msisdn, String imsi, int[] features) {}
-
-    /**
-     * Add contacts that are allowed to be used for satellite communication. This is applicable for
-     * incoming messages as well.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param contacts List of allowed contacts to be added.
-     */
-    default void addAllowedSatelliteContacts(Message result, String[] contacts) {}
-
-    /**
-     * Remove contacts that are allowed to be used for satellite communication. This is applicable
-     * for incoming messages as well.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param contacts List of allowed contacts to be removed.
-     */
-    default void removeAllowedSatelliteContacts(Message result, String[] contacts) {}
-
-    /**
-     * Send text messages.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param messages List of messages in text format to be sent.
-     * @param destination The recipient of the message.
-     * @param latitude The current latitude of the device.
-     * @param longitude The current longitude of the device. The location (i.e., latitude and
-     *        longitude) of the device will be filled for emergency messages.
-     */
-    default void sendSatelliteMessages(Message result, String[] messages, String destination,
-            double latitude, double longitude) {}
-
-    /**
-     * Get pending messages.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void getPendingSatelliteMessages(Message result) {}
-
-    /**
-     * Get current satellite registration mode.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void getSatelliteMode(Message result) {}
-
-    /**
-     * Set the filter for what type of indication framework want to receive from modem.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param filterBitmask The filter bitmask identifying what type of indication Telephony
-     *                      framework wants to receive from modem.
-     */
-    default void setSatelliteIndicationFilter(Message result, int filterBitmask) {}
-
-    /**
-     * User started pointing to the satellite. Modem should continue to update the ponting input
-     * as user moves device.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void startSendingSatellitePointingInfo(Message result) {}
-
-    /**
-     * Stop sending satellite pointing info to the framework.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void stopSendingSatellitePointingInfo(Message result) {}
-
-    /**
-     * Get max number of characters per text message.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void getMaxCharactersPerSatelliteTextMessage(Message result) {}
-
-    /**
-     * Get whether satellite communication is allowed for the current location.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {}
-
-    /**
-     * Get the time after which the satellite will be visible.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    default void getTimeForNextSatelliteVisibility(Message result) {}
-
-    /**
-     * Registers for pending message count from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForPendingSatelliteMessageCount(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for pending message count from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) {}
-
-    /**
-     * Registers for new messages from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForNewSatelliteMessages(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for new messages from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForNewSatelliteMessages(@NonNull Handler h) {}
-
-    /**
-     * Registers for messages transfer complete from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForSatelliteMessagesTransferComplete(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for messages transfer complete from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) {}
-
-    /**
-     * Registers for pointing info changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForSatellitePointingInfoChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for pointing info changed from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) {}
-
-    /**
-     * Registers for mode changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForSatelliteModeChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for mode changed from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForSatelliteModeChanged(@NonNull Handler h) {}
-
-    /**
-     * Registers for radio technology changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for radio technology changed from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) {}
-
-    /**
-     * Registers for provision state changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    default void registerForSatelliteProvisionStateChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {}
-
-    /**
-     * Unregisters for provision state changed from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    default void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {}
-}
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index ecc6208..7bdf2ff 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -22,6 +22,7 @@
 import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
 import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK;
 
+import android.annotation.NonNull;
 import android.app.UiModeManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -47,6 +48,7 @@
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.telephony.Rlog;
 
@@ -92,10 +94,14 @@
     private static final int NR_NSA_TRACKING_INDICATIONS_ALWAYS_ON = 2;
 
     private final Phone mPhone;
+    @NonNull
+    private final FeatureFlags mFeatureFlags;
 
     private final LocalLog mLocalLog = new LocalLog(64);
 
     private final RegistrantList mPhysicalChannelConfigRegistrants = new RegistrantList();
+    private final RegistrantList mSignalStrengthReportDecisionCallbackRegistrants =
+            new RegistrantList();
 
     private final NetworkRequest mWifiNetworkRequest =
             new NetworkRequest.Builder()
@@ -269,8 +275,9 @@
      *
      * @param phone Phone object
      */
-    public DeviceStateMonitor(Phone phone) {
+    public DeviceStateMonitor(Phone phone, @NonNull FeatureFlags featureFlags) {
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
                 Context.DISPLAY_SERVICE);
         dm.registerDisplayListener(mDisplayListener, null);
@@ -602,6 +609,15 @@
             // use a null message since we don't care of receiving response
             mPhone.mCi.getBarringInfo(null);
         }
+
+        // Determine whether to notify registrants about the non-terrestrial signal strength change.
+        if (mFeatureFlags.oemEnabledSatelliteFlag()) {
+            if (shouldEnableSignalStrengthReports()) {
+                mSignalStrengthReportDecisionCallbackRegistrants.notifyResult(true);
+            } else {
+                mSignalStrengthReportDecisionCallbackRegistrants.notifyResult(false);
+            }
+        }
     }
 
     /**
@@ -778,6 +794,33 @@
     }
 
     /**
+     * Register a callback to decide whether signal strength should be notified or not.
+     * @param h Handler to notify
+     * @param what msg.what when the message is delivered
+     * @param obj AsyncResult.userObj when the message is delivered
+     */
+    public void registerForSignalStrengthReportDecision(Handler h, int what, Object obj) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            Rlog.d(TAG, "oemEnabledSatelliteFlag is disabled");
+            return;
+        }
+        Registrant r = new Registrant(h, what, obj);
+        mSignalStrengthReportDecisionCallbackRegistrants.add(r);
+    }
+
+    /**
+     * Register a callback to decide whether signal strength should be notified or not.
+     * @param h Handler to notify
+     */
+    public void unregisterForSignalStrengthReportDecision(Handler h) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            Rlog.d(TAG, "oemEnabledSatelliteFlag is disabled");
+            return;
+        }
+        mSignalStrengthReportDecisionCallbackRegistrants.remove(h);
+    }
+
+    /**
      * @param msg Debug message
      * @param logIntoLocalLog True if log into the local log
      */
diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java
index 567331d..945b640 100644
--- a/src/java/com/android/internal/telephony/DisplayInfoController.java
+++ b/src/java/com/android/internal/telephony/DisplayInfoController.java
@@ -19,9 +19,11 @@
 import android.annotation.NonNull;
 import android.os.Handler;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Registrant;
 import android.os.RegistrantList;
 import android.telephony.AnomalyReporter;
+import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyDisplayInfo;
 import android.telephony.TelephonyManager;
@@ -29,6 +31,7 @@
 import android.util.LocalLog;
 import android.util.Pair;
 
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -66,34 +69,55 @@
 
     /** Event for service state changed (roaming). */
     private static final int EVENT_SERVICE_STATE_CHANGED = 1;
+    /** Event for carrier config changed. */
+    private static final int EVENT_CARRIER_CONFIG_CHANGED = 2;
 
-    private final Phone mPhone;
-    private final NetworkTypeController mNetworkTypeController;
-    private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = new RegistrantList();
-    private @NonNull TelephonyDisplayInfo mTelephonyDisplayInfo;
-    private @NonNull ServiceState mServiceState;
+    @NonNull private final Phone mPhone;
+    @NonNull private final NetworkTypeController mNetworkTypeController;
+    @NonNull private final RegistrantList mTelephonyDisplayInfoChangedRegistrants =
+            new RegistrantList();
+    @NonNull private final FeatureFlags mFeatureFlags;
+    @NonNull private TelephonyDisplayInfo mTelephonyDisplayInfo;
+    @NonNull private ServiceState mServiceState;
+    @NonNull private PersistableBundle mConfigs;
 
-    public DisplayInfoController(Phone phone) {
+    public DisplayInfoController(@NonNull Phone phone, @NonNull FeatureFlags featureFlags) {
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         mLogTag = "DIC-" + mPhone.getPhoneId();
+        mServiceState = mPhone.getServiceStateTracker().getServiceState();
+        mConfigs = new PersistableBundle();
+        try {
+            mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                    .getConfigForSubId(mPhone.getSubId(),
+                            CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
+        } catch (Exception ignored) {
+            // CarrierConfigLoader might not be available yet.
+            // Once it's available, configs will be updated through the listener.
+        }
+        mPhone.getServiceStateTracker()
+                .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
+        mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                .registerCarrierConfigChangeListener(Runnable::run,
+                        (slotIndex, subId, carrierId, specificCarrierId) -> {
+                            if (slotIndex == mPhone.getPhoneId()) {
+                                obtainMessage(EVENT_CARRIER_CONFIG_CHANGED).sendToTarget();
+                            }
+                        });
         mTelephonyDisplayInfo = new TelephonyDisplayInfo(
                 TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
+                TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+                false);
         mNetworkTypeController = new NetworkTypeController(phone, this);
+        // EVENT_UPDATE will transition from DefaultState to the current state
+        // and update the TelephonyDisplayInfo based on the current state.
         mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
-
-        mServiceState = mPhone.getServiceStateTracker().getServiceState();
-        post(() -> {
-            mPhone.getServiceStateTracker()
-                    .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
-            updateTelephonyDisplayInfo();
-        });
     }
 
     /**
      * @return the current TelephonyDisplayInfo
      */
-    public @NonNull TelephonyDisplayInfo getTelephonyDisplayInfo() {
+    @NonNull public TelephonyDisplayInfo getTelephonyDisplayInfo() {
         return mTelephonyDisplayInfo;
     }
 
@@ -105,7 +129,7 @@
         TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo(
                 mNetworkTypeController.getDataNetworkType(),
                 mNetworkTypeController.getOverrideNetworkType(),
-                mServiceState.getRoaming());
+                isRoaming());
         if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) {
             logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to "
                     + newDisplayInfo);
@@ -117,6 +141,24 @@
     }
 
     /**
+     * Determine the roaming status for icon display only.
+     * If this is {@code true}, the roaming indicator will be shown, and if this is {@code false},
+     * the roaming indicator will not be shown.
+     * To get the actual roaming status, use {@link ServiceState#getRoaming()} instead.
+     *
+     * @return Whether the device is considered roaming for display purposes.
+     */
+    private boolean isRoaming() {
+        boolean roaming = mServiceState.getRoaming();
+        if (roaming && mFeatureFlags.hideRoamingIcon()
+                && !mConfigs.getBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL)) {
+            logl("Override roaming for display due to carrier configs.");
+            roaming = false;
+        }
+        return roaming;
+    }
+
+    /**
      * Validate the display info and trigger anomaly report if needed.
      *
      * @param displayInfo The display info to validate.
@@ -175,6 +217,13 @@
                 log("ServiceState updated, isRoaming=" + mServiceState.getRoaming());
                 updateTelephonyDisplayInfo();
                 break;
+            case EVENT_CARRIER_CONFIG_CHANGED:
+                mConfigs = mPhone.getContext().getSystemService(CarrierConfigManager.class)
+                        .getConfigForSubId(mPhone.getSubId(),
+                                CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL);
+                log("Carrier configs updated: " + mConfigs);
+                updateTelephonyDisplayInfo();
+                break;
         }
     }
 
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index ecf8e5f..6f30fb5 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -359,12 +359,13 @@
                 .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
                         this, this.mCi);
         mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName())
-                .makeDeviceStateMonitor(this);
+                .makeDeviceStateMonitor(this, mFeatureFlags);
 
         // DisplayInfoController creates an OverrideNetworkTypeController, which uses
         // DeviceStateMonitor so needs to be crated after it is instantiated.
         mDisplayInfoController = mTelephonyComponentFactory.inject(
-                DisplayInfoController.class.getName()).makeDisplayInfoController(this);
+                DisplayInfoController.class.getName())
+                .makeDisplayInfoController(this, featureFlags);
 
         mDataNetworkController = mTelephonyComponentFactory.inject(
                 DataNetworkController.class.getName())
@@ -463,7 +464,7 @@
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
         mIccSmsInterfaceManager = mTelephonyComponentFactory
                 .inject(IccSmsInterfaceManager.class.getName())
-                .makeIccSmsInterfaceManager(this);
+                .makeIccSmsInterfaceManager(this, mFeatureFlags);
 
         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 2d77631..7c1670c 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -21,6 +21,7 @@
 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -47,6 +48,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
 import com.android.internal.telephony.uicc.IccConstants;
 import com.android.internal.telephony.uicc.IccFileHandler;
@@ -155,11 +157,11 @@
         }
     };
 
-    protected IccSmsInterfaceManager(Phone phone) {
+    protected IccSmsInterfaceManager(Phone phone, @NonNull FeatureFlags featureFlags) {
         this(phone, phone.getContext(),
                 (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE),
                 new SmsDispatchersController(
-                        phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor),
+                        phone, phone.mSmsStorageMonitor, phone.mSmsUsageMonitor, featureFlags),
                 new SmsPermissions(phone, phone.getContext(),
                         (AppOpsManager) phone.getContext().getSystemService(
                                 Context.APP_OPS_SERVICE)));
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index 67dbdb5..4e4d55d 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -202,10 +202,13 @@
                         tracker.onSent(mContext);
                         mTrackers.remove(token);
                         mPhone.notifySmsSent(tracker.mDestAddress);
+                        mSmsDispatchersController.notifySmsSentToEmergencyStateTracker(
+                                tracker.mDestAddress, tracker.mMessageId);
                         break;
                     case ImsSmsImplBase.SEND_STATUS_ERROR:
                         tracker.onFailed(mContext, reason, networkReasonCode);
                         mTrackers.remove(token);
+                        notifySmsSentFailedToEmergencyStateTracker(tracker);
                         break;
                     case ImsSmsImplBase.SEND_STATUS_ERROR_RETRY:
                         int maxRetryCountOverIms = getMaxRetryCountOverIms();
@@ -224,6 +227,7 @@
                         } else {
                             tracker.onFailed(mContext, reason, networkReasonCode);
                             mTrackers.remove(token);
+                            notifySmsSentFailedToEmergencyStateTracker(tracker);
                         }
                         break;
                     case ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK:
diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java
index 83417c5..a20e748 100644
--- a/src/java/com/android/internal/telephony/MockModem.java
+++ b/src/java/com/android/internal/telephony/MockModem.java
@@ -21,7 +21,6 @@
 import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING;
 import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM;
 import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK;
-import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE;
 import static android.telephony.TelephonyManager.HAL_SERVICE_SIM;
 import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE;
 
@@ -45,8 +44,6 @@
     private static final String BIND_IRADIOVOICE = "android.telephony.mockmodem.iradiovoice";
     private static final String BIND_IRADIOIMS = "android.telephony.mockmodem.iradioims";
     private static final String BIND_IRADIOCONFIG = "android.telephony.mockmodem.iradioconfig";
-    private static final String BIND_IRADIOSATELLITE =
-            "android.telephony.mockmodem.iradiosatellite";
     private static final String PHONE_ID = "phone_id";
 
     private static final byte DEFAULT_PHONE_ID = 0x00;
@@ -68,7 +65,6 @@
     private IBinder mVoiceBinder;
     private IBinder mImsBinder;
     private IBinder mConfigBinder;
-    private IBinder mSatelliteBinder;
     private ServiceConnection mModemServiceConnection;
     private ServiceConnection mSimServiceConnection;
     private ServiceConnection mMessagingServiceConnection;
@@ -77,7 +73,6 @@
     private ServiceConnection mVoiceServiceConnection;
     private ServiceConnection mImsServiceConnection;
     private ServiceConnection mConfigServiceConnection;
-    private ServiceConnection mSatelliteServiceConnection;
 
     private byte mPhoneId;
     private String mTag;
@@ -120,8 +115,6 @@
                 mVoiceBinder = binder;
             } else if (mService == HAL_SERVICE_IMS) {
                 mImsBinder = binder;
-            } else if (mService == HAL_SERVICE_SATELLITE) {
-                mSatelliteBinder = binder;
             } else if (mService == RADIOCONFIG_SERVICE) {
                 mConfigBinder = binder;
             }
@@ -145,8 +138,6 @@
                 mVoiceBinder = null;
             } else if (mService == HAL_SERVICE_IMS) {
                 mImsBinder = null;
-            } else if (mService == HAL_SERVICE_SATELLITE) {
-                mSatelliteBinder = null;
             } else if (mService == RADIOCONFIG_SERVICE) {
                 mConfigBinder = null;
             }
@@ -188,8 +179,6 @@
                 return mVoiceBinder;
             case HAL_SERVICE_IMS:
                 return mImsBinder;
-            case HAL_SERVICE_SATELLITE:
-                return mSatelliteBinder;
             case RADIOCONFIG_SERVICE:
                 return mConfigBinder;
             default:
@@ -317,20 +306,6 @@
             } else {
                 Rlog.d(TAG, "IRadio Ims is bound");
             }
-        } else if (service == HAL_SERVICE_SATELLITE) {
-            if (mSatelliteBinder == null) {
-                mSatelliteServiceConnection = new MockModemConnection(HAL_SERVICE_SATELLITE);
-
-                boolean status =
-                        bindModuleToMockModemService(
-                                mPhoneId, BIND_IRADIOSATELLITE, mSatelliteServiceConnection);
-                if (!status) {
-                    Rlog.d(TAG, "IRadio Satellite bind fail");
-                    mSatelliteServiceConnection = null;
-                }
-            } else {
-                Rlog.d(TAG, "IRadio Satellite is bound");
-            }
         }
     }
 
@@ -393,13 +368,6 @@
                 mImsBinder = null;
                 Rlog.d(TAG, "unbind IRadio Ims");
             }
-        } else if (service == HAL_SERVICE_SATELLITE) {
-            if (mSatelliteServiceConnection != null) {
-                mContext.unbindService(mSatelliteServiceConnection);
-                mSatelliteServiceConnection = null;
-                mSatelliteBinder = null;
-                Rlog.d(TAG, "unbind IRadio Satellite");
-            }
         }
     }
 
@@ -423,8 +391,6 @@
                 return "voice";
             case HAL_SERVICE_IMS:
                 return "ims";
-            case HAL_SERVICE_SATELLITE:
-                return "satellite";
             case RADIOCONFIG_SERVICE:
                 return "config";
             default:
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index f4f756f..50cf844 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -72,7 +72,6 @@
 import android.telephony.ims.RegistrationManager;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
-import android.telephony.satellite.SatelliteDatagram;
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
@@ -728,6 +727,28 @@
     }
 
     /**
+     * Determines if the carrier prefers to use an in service sim for a normal routed emergency
+     * call.
+     * @return true when carrier config
+     * {@link CarrierConfigManager#KEY_PREFER_IN_SERVICE_SIM_FOR_NORMAL_ROUTED_EMERGENCY_CALLS_BOOL}
+     * is true.
+     */
+    public boolean shouldPreferInServiceSimForNormalRoutedEmergencyCall() {
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle b = configManager.getConfigForSubId(getSubId(), CarrierConfigManager
+                .KEY_PREFER_IN_SERVICE_SIM_FOR_NORMAL_ROUTED_EMERGENCY_CALLS_BOOL);
+        if (b != null) {
+            return b.getBoolean(CarrierConfigManager
+                            .KEY_PREFER_IN_SERVICE_SIM_FOR_NORMAL_ROUTED_EMERGENCY_CALLS_BOOL,
+                    false);
+        } else {
+            // Default value set in CarrierConfigManager
+            return false;
+        }
+    }
+
+    /**
      * When overridden the derived class needs to call
      * super.handleMessage(msg) so this method has a
      * a chance to process the message.
@@ -5175,279 +5196,6 @@
     }
 
     /**
-     * Start receiving satellite position updates.
-     * This can be called by the pointing UI when the user starts pointing to the satellite.
-     * Modem should continue to report the pointing input as the device or satellite moves.
-     *
-     * @param result The Message to send to result of the operation to.
-     **/
-    public void startSatellitePositionUpdates(Message result) {
-        mCi.startSendingSatellitePointingInfo(result);
-    }
-
-    /**
-     * Stop receiving satellite position updates.
-     * This can be called by the pointing UI when the user stops pointing to the satellite.
-     *
-     * @param result The Message to send to result of the operation to.
-     **/
-    public void stopSatellitePositionUpdates(Message result) {
-        mCi.stopSendingSatellitePointingInfo(result);
-    }
-
-    /**
-     * Get maximum number of characters per text message on satellite.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void getMaxCharactersPerSatelliteTextMessage(Message result) {
-        mCi.getMaxCharactersPerSatelliteTextMessage(result);
-    }
-
-    /**
-     * Power on or off the satellite modem.
-     * @param result The Message to send the result of the operation to.
-     * @param powerOn {@code true} to power on the satellite modem and {@code false} to power off.
-     */
-    public void setSatellitePower(Message result, boolean powerOn) {
-        mCi.setSatellitePower(result, powerOn);
-    }
-
-    /**
-     * Check whether the satellite modem is powered on.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void isSatellitePowerOn(Message result) {
-        mCi.getSatellitePowerState(result);
-    }
-
-    /**
-     * Check whether the satellite service is supported on the device.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void isSatelliteSupported(Message result) {
-        mCi.isSatelliteSupported(result);
-    }
-
-    /**
-     * Check whether the satellite modem is provisioned.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void isSatelliteProvisioned(Message result) {
-        mCi.getSatelliteProvisionState(result);
-    }
-
-    /**
-     * Get the satellite capabilities.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void getSatelliteCapabilities(Message result) {
-        mCi.getSatelliteCapabilities(result);
-    }
-
-    /**
-     * Registers for pointing info changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForSatellitePositionInfoChanged(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        //TODO: Rename CommandsInterface and other modules when updating HAL APIs.
-        mCi.registerForSatellitePointingInfoChanged(h, what, obj);
-    }
-
-    /**
-     * Unregisters for pointing info changed from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) {
-        //TODO: Rename CommandsInterface and other modules when updating HAL APIs.
-        mCi.unregisterForSatellitePointingInfoChanged(h);
-    }
-
-    /**
-     * Registers for datagrams delivered events from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForSatelliteDatagramsDelivered(@NonNull Handler h,
-            int what, @Nullable Object obj) {
-        //TODO: Remove.
-        mCi.registerForSatelliteMessagesTransferComplete(h, what, obj);
-    }
-
-    /**
-     * Unregisters for datagrams delivered events from satellite modem.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    public void unregisterForSatelliteDatagramsDelivered(@NonNull Handler h) {
-        //TODO: Remove.
-        mCi.unregisterForSatelliteMessagesTransferComplete(h);
-    }
-
-    /**
-     * Provision the subscription with a satellite provider.
-     * This is needed to register the device/subscription if the provider allows dynamic
-     * registration.
-     *
-     * @param result Callback message to receive the result.
-     * @param token The token of the device/subscription to be provisioned.
-     */
-    public void provisionSatelliteService(Message result, String token) {
-        // TODO: update parameters in HAL
-        // mCi.provisionSatelliteService(result, token);
-    }
-
-    /**
-     * Deprovision the device/subscription with a satellite provider.
-     * This is needed to unregister the device/subscription if the provider allows dynamic
-     * registration.
-     * If provisioning is in progress for the given SIM, cancel the request.
-     * If there is no request in progress, deprovision the given SIM.
-     *
-     * @param result Callback message to receive the result.
-     * @param token The token of the device/subscription to be deprovisioned.
-     */
-    public void deprovisionSatelliteService(Message result, String token) {
-        //TODO (b/266126070): add implementation.
-    }
-
-    /**
-     * Register for a satellite provision state changed event.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForSatelliteProvisionStateChanged(Handler h, int what, Object obj) {
-        mCi.registerForSatelliteProvisionStateChanged(h, what, obj);
-    }
-
-    /**
-     * Unregister for a satellite provision state changed event.
-     *
-     * @param h Handler to be removed from the registrant list.
-     */
-    public void unregisterForSatelliteProvisionStateChanged(Handler h) {
-        mCi.unregisterForSatelliteProvisionStateChanged(h);
-    }
-
-    /**
-     * Get the list of provisioned satellite features.
-     *
-     * @param result Callback message to receive the result.
-     */
-    public void getProvisionedSatelliteFeatures(Message result) {
-        //TODO (b/266126070): add implementation.
-    }
-
-    /**
-     * Registers for satellite state changed from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForSatelliteModemStateChanged(@NonNull Handler h, int what,
-            @Nullable Object obj) {
-        mCi.registerForSatelliteModeChanged(h, what, obj);
-    }
-
-    /**
-     * Unregisters for satellite state changed from satellite modem.
-     *
-     * @param h Handler to be removed from registrant list.
-     */
-    public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) {
-        mCi.unregisterForSatelliteModeChanged(h);
-    }
-
-    /**
-     * Registers for pending datagram count info from satellite modem.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForPendingDatagramCount(@NonNull Handler h, int what,
-            @Nullable Object obj) {
-        mCi.registerForPendingSatelliteMessageCount(h, what, obj);
-    }
-
-    /**
-     * Unregisters for pending datagram count info from satellite modem.
-     *
-     * @param h Handler to be removed from registrant list.
-     */
-    public void unregisterForPendingDatagramCount(@NonNull Handler h) {
-        mCi.unregisterForPendingSatelliteMessageCount(h);
-    }
-
-    /**
-     * Register to receive incoming datagrams over satellite.
-     *
-     * @param h Handler for notification message.
-     * @param what User-defined message code.
-     * @param obj User object.
-     */
-    public void registerForSatelliteDatagramsReceived(@NonNull Handler h, int what,
-            @Nullable Object obj) {
-        // TODO: rename
-        mCi.registerForNewSatelliteMessages(h, what, obj);
-    }
-
-    /**
-     * Unregister to stop receiving incoming datagrams over satellite.
-     *
-     * @param h Handler to be removed from registrant list.
-     */
-    public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) {
-        // TODO: rename
-        mCi.unregisterForNewSatelliteMessages(h);
-    }
-
-    /**
-     * Poll pending datagrams over satellite.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void pollPendingSatelliteDatagrams(Message result) {
-        //mCi.pollPendingSatelliteDatagrams(result);
-    }
-
-    /**
-     * Send datagram over satellite.
-     * @param result The Message to send the result of the operation to.
-     * @param datagram Datagram to send over satellite.
-     * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in
-     *                                 full screen mode.
-     */
-    public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram,
-            boolean needFullScreenPointingUI) {
-        //mCi.sendSatelliteDatagram(result, datagram);
-    }
-
-    /**
-     * Check whether satellite communication is allowed for the current location.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {
-        mCi.isSatelliteCommunicationAllowedForCurrentLocation(result);
-    }
-
-    /**
-     * Get the time after which the satellite will be visible.
-     * @param result The Message to send the result of the operation to.
-     */
-    public void requestTimeForNextSatelliteVisibility(Message result) {
-        mCi.getTimeForNextSatelliteVisibility(result);
-    }
-
-    /**
      * Start callback mode
      * @param type for callback mode entry.
      */
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 3c8c5f3..7e8bfe8 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -22,7 +22,6 @@
 import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM;
 import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK;
 import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO;
-import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE;
 import static android.telephony.TelephonyManager.HAL_SERVICE_SIM;
 import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE;
 
@@ -207,7 +206,7 @@
 
     public static final int MIN_SERVICE_IDX = HAL_SERVICE_RADIO;
 
-    public static final int MAX_SERVICE_IDX = HAL_SERVICE_SATELLITE;
+    public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS;
 
     /**
      * An array of sets that records if services are disabled in the HAL for a specific phone ID
@@ -242,8 +241,6 @@
     private ModemIndication mModemIndication;
     private NetworkResponse mNetworkResponse;
     private NetworkIndication mNetworkIndication;
-    private SatelliteResponse mSatelliteResponse;
-    private SatelliteIndication mSatelliteIndication;
     private SimResponse mSimResponse;
     private SimIndication mSimIndication;
     private VoiceResponse mVoiceResponse;
@@ -682,7 +679,7 @@
     /**
      * Returns a {@link RadioDataProxy}, {@link RadioMessagingProxy}, {@link RadioModemProxy},
      * {@link RadioNetworkProxy}, {@link RadioSimProxy}, {@link RadioVoiceProxy},
-     * {@link RadioImsProxy}, {@link RadioSatelliteProxy}, or null if the service is not available.
+     * {@link RadioImsProxy}, or null if the service is not available.
      */
     @NonNull
     public <T extends RadioServiceProxy> T getRadioServiceProxy(Class<T> serviceClass) {
@@ -707,9 +704,6 @@
         if (serviceClass == RadioImsProxy.class) {
             return (T) getRadioServiceProxy(HAL_SERVICE_IMS);
         }
-        if (serviceClass == RadioSatelliteProxy.class) {
-            return (T) getRadioServiceProxy(HAL_SERVICE_SATELLITE);
-        }
         riljLoge("getRadioServiceProxy: unrecognized " + serviceClass);
         return null;
     }
@@ -847,21 +841,6 @@
                                             .asInterface(binder)));
                         }
                         break;
-                    case HAL_SERVICE_SATELLITE:
-                        if (mMockModem == null) {
-                            binder = ServiceManager.waitForDeclaredService(
-                                    android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR
-                                            + "/" + HIDL_SERVICE_NAME[mPhoneId]);
-                        } else {
-                            binder = mMockModem.getServiceBinder(HAL_SERVICE_SATELLITE);
-                        }
-                        if (binder != null) {
-                            mHalVersion.put(service, ((RadioSatelliteProxy) serviceProxy).setAidl(
-                                    mHalVersion.get(service),
-                                    android.hardware.radio.satellite.IRadioSatellite.Stub
-                                            .asInterface(binder)));
-                        }
-                        break;
                 }
 
                 if (serviceProxy.isEmpty()
@@ -947,12 +926,6 @@
                                 ((RadioImsProxy) serviceProxy).getAidl().setResponseFunctions(
                                         mImsResponse, mImsIndication);
                                 break;
-                            case HAL_SERVICE_SATELLITE:
-                                mDeathRecipients.get(service).linkToDeath(
-                                        ((RadioSatelliteProxy) serviceProxy).getAidl().asBinder());
-                                ((RadioSatelliteProxy) serviceProxy).getAidl().setResponseFunctions(
-                                        mSatelliteResponse, mSatelliteIndication);
-                                break;
                         }
                     } else {
                         if (mHalVersion.get(service).greaterOrEqual(RADIO_HAL_VERSION_2_0)) {
@@ -1061,8 +1034,6 @@
         mModemIndication = new ModemIndication(this);
         mNetworkResponse = new NetworkResponse(this);
         mNetworkIndication = new NetworkIndication(this);
-        mSatelliteResponse = new SatelliteResponse(this);
-        mSatelliteIndication = new SatelliteIndication(this);
         mSimResponse = new SimResponse(this);
         mSimIndication = new SimIndication(this);
         mVoiceResponse = new VoiceResponse(this);
@@ -1079,9 +1050,9 @@
                     }
                 } catch (SecurityException ex) {
                     /* TODO(b/211920208): instead of the following workaround (guessing if
-                    * we're in a test based on proxies being populated), mock ServiceManager
-                    * to not throw SecurityException and return correct value based on what
-                    * HAL we're testing. */
+                     * we're in a test based on proxies being populated), mock ServiceManager
+                     * to not throw SecurityException and return correct value based on what
+                     * HAL we're testing. */
                     if (proxies == null) throw ex;
                 }
                 mDeathRecipients.put(service, new BinderServiceDeathRecipient(service));
@@ -1097,7 +1068,6 @@
             mServiceProxies.put(HAL_SERVICE_SIM, new RadioSimProxy());
             mServiceProxies.put(HAL_SERVICE_VOICE, new RadioVoiceProxy());
             mServiceProxies.put(HAL_SERVICE_IMS, new RadioImsProxy());
-            mServiceProxies.put(HAL_SERVICE_SATELLITE, new RadioSatelliteProxy());
         } else {
             mServiceProxies = proxies;
         }
@@ -1180,9 +1150,6 @@
             case HAL_SERVICE_IMS:
                 serviceName = android.hardware.radio.ims.IRadioIms.DESCRIPTOR;
                 break;
-            case HAL_SERVICE_SATELLITE:
-                serviceName = android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR;
-                break;
         }
 
         if (!serviceName.equals("")
@@ -1270,8 +1237,6 @@
             service = HAL_SERVICE_VOICE;
         } else if (proxy instanceof RadioImsProxy) {
             service = HAL_SERVICE_IMS;
-        } else if (proxy instanceof RadioSatelliteProxy) {
-            service = HAL_SERVICE_SATELLITE;
         }
 
         if (mHalVersion.get(service).less(version)) {
@@ -5113,442 +5078,6 @@
         });
     }
 
-    /**
-     * Get feature capabilities supported by satellite.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    @Override
-    public void getSatelliteCapabilities(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getSatelliteCapabilities", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_CAPABILITIES, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "getSatelliteCapabilities", () -> {
-            satelliteProxy.getCapabilities(rr.mSerial);
-        });
-    }
-
-    /**
-     * Turn satellite modem on/off.
-     *
-     * @param result Message that will be sent back to the requester
-     * @param on True for turning on.
-     *           False for turning off.
-     */
-    @Override
-    public void setSatellitePower(Message result, boolean on) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("setSatellitePower", satelliteProxy, result, RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_POWER, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "setSatellitePower", () -> {
-            satelliteProxy.setPower(rr.mSerial, on);
-        });
-    }
-
-    /**
-     * Get satellite modem state.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    @Override
-    public void getSatellitePowerState(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getSatellitePowerState", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_POWER, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "getSatellitePowerState", () -> {
-            satelliteProxy.getPowerState(rr.mSerial);
-        });
-    }
-
-    /**
-     * Get satellite provision state.
-     *
-     * @param result Message that will be sent back to the requester
-     */
-    @Override
-    public void getSatelliteProvisionState(Message result) {
-        // Satellite HAL APIs are not supported before Android V.
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getSatelliteProvisionState", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-    }
-
-    /**
-     * Provision the subscription with a satellite provider. This is needed to register the
-     * subscription if the provider allows dynamic registration.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param imei IMEI of the SIM associated with the satellite modem.
-     * @param msisdn MSISDN of the SIM associated with the satellite modem.
-     * @param imsi IMSI of the SIM associated with the satellite modem.
-     * @param features List of features to be provisioned.
-     */
-    @Override
-    public void provisionSatelliteService(
-            Message result, String imei, String msisdn, String imsi, int[] features) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("provisionSatelliteService", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_PROVISION_SATELLITE_SERVICE, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "provisionSatelliteService", () -> {
-            satelliteProxy.provisionService(rr.mSerial, imei, msisdn, imsi, features);
-        });
-    }
-
-    /**
-     * Add contacts that are allowed to be used for satellite communication. This is applicable for
-     * incoming messages as well.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param contacts List of allowed contacts to be added.
-     */
-    @Override
-    public void addAllowedSatelliteContacts(Message result, String[] contacts) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("addAllowedSatelliteContacts", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "addAllowedSatelliteContacts", () -> {
-            satelliteProxy.addAllowedSatelliteContacts(rr.mSerial, contacts);
-        });
-    }
-
-    /**
-     * Remove contacts that are allowed to be used for satellite communication. This is applicable
-     * for incoming messages as well.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param contacts List of allowed contacts to be removed.
-     */
-    @Override
-    public void removeAllowedSatelliteContacts(Message result, String[] contacts) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("removeAllowedSatelliteContacts", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "removeAllowedSatelliteContacts",
-                () -> {
-                    satelliteProxy.removeAllowedSatelliteContacts(rr.mSerial, contacts);
-                });
-    }
-
-    /**
-     * Send text messages.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param messages List of messages in text format to be sent.
-     * @param destination The recipient of the message.
-     * @param latitude The current latitude of the device.
-     * @param longitude The current longitude of the device.
-     */
-    @Override
-    public void sendSatelliteMessages(Message result, String[] messages, String destination,
-            double latitude, double longitude) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("sendSatelliteMessages", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_SEND_SATELLITE_MESSAGES, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "sendSatelliteMessages", () -> {
-            satelliteProxy.sendMessages(rr.mSerial, messages, destination, latitude, longitude);
-        });
-    }
-
-    /**
-     * Get pending messages.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void getPendingSatelliteMessages(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getPendingSatelliteMessages", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "getPendingSatelliteMessages", () -> {
-            satelliteProxy.getPendingMessages(rr.mSerial);
-        });
-    }
-
-    /**
-     * Get current satellite registration mode.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void getSatelliteMode(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getSatelliteMode", satelliteProxy, result, RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_MODE, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "getSatelliteMode", () -> {
-            satelliteProxy.getSatelliteMode(rr.mSerial);
-        });
-    }
-
-    /**
-     * Set the filter for what type of indication framework want to receive from modem.
-     *
-     * @param result Message that will be sent back to the requester.
-     * @param filterBitmask The filter bitmask identifying what type of indication framework want to
-     *                         receive from modem.
-     */
-    @Override
-    public void setSatelliteIndicationFilter(Message result, int filterBitmask) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("setSatelliteIndicationFilter", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "setSatelliteIndicationFilter", () -> {
-            satelliteProxy.setIndicationFilter(rr.mSerial, filterBitmask);
-        });
-    }
-
-    /**
-     * Check whether satellite modem is supported by the device.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void isSatelliteSupported(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("isSatelliteSupported", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-        /**
-         * TODO: when adding implementation of this method, we need to return successful result
-         * with satellite support set to false if radioSatelliteProxy.isEmpty() is true or
-         * mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0) is false.
-         */
-    }
-
-    /**
-     * User started pointing to the satellite. Modem should continue to update the ponting input
-     * as user moves device.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void startSendingSatellitePointingInfo(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("startSendingSatellitePointingInfo", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "startSendingSatellitePointingInfo",
-                () -> {
-                    satelliteProxy.startSendingSatellitePointingInfo(rr.mSerial);
-                });
-    }
-
-    /**
-     * Stop pointing to satellite indications.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void stopSendingSatellitePointingInfo(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("stopSendingSatellitePointingInfo", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "stopSendingSatellitePointingInfo",
-                () -> {
-                    satelliteProxy.stopSendingSatellitePointingInfo(rr.mSerial);
-                });
-    }
-
-    /**
-     * Get max text limit for messaging per message.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void getMaxCharactersPerSatelliteTextMessage(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getMaxCharactersPerSatelliteTextMessage", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE,
-                result, mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr,
-                "getMaxCharactersPerSatelliteTextMessage", () -> {
-                    satelliteProxy.getMaxCharactersPerTextMessage(rr.mSerial);
-                });
-    }
-
-    /**
-     * Get whether satellite communication is allowed for the current location
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {
-        // TODO: link to HAL implementation
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("isSatelliteCommunicationAllowedForCurrentLocation", satelliteProxy,
-                result, RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-    }
-
-    /**
-     * Get time for next visibility of satellite.
-     *
-     * @param result Message that will be sent back to the requester.
-     */
-    @Override
-    public void getTimeForNextSatelliteVisibility(Message result) {
-        RadioSatelliteProxy satelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class);
-        if (!canMakeRequest("getTimeForNextSatelliteVisibility", satelliteProxy, result,
-                RADIO_HAL_VERSION_2_0)) {
-            return;
-        }
-
-        RILRequest rr = obtainRequest(RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY, result,
-                mRILDefaultWorkSource);
-
-        if (RILJ_LOGD) {
-            // Do not log function arg for privacy
-            riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
-        }
-
-        radioServiceInvokeHelper(HAL_SERVICE_SATELLITE, rr, "getTimeForNextSatelliteVisibility",
-                () -> {
-                    satelliteProxy.getTimeForNextSatelliteVisibility(rr.mSerial);
-                });
-    }
-
     //***** Private Methods
     /**
      * This is a helper function to be called when an indication callback is called for any radio
@@ -5707,12 +5236,12 @@
         } else {
             switch (rr.mRequest) {
                 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
-                if (mTestingEmergencyCall.getAndSet(false)) {
-                    if (mEmergencyCallbackModeRegistrant != null) {
-                        riljLog("testing emergency call, notify ECM Registrants");
-                        mEmergencyCallbackModeRegistrant.notifyRegistrant();
+                    if (mTestingEmergencyCall.getAndSet(false)) {
+                        if (mEmergencyCallbackModeRegistrant != null) {
+                            riljLog("testing emergency call, notify ECM Registrants");
+                            mEmergencyCallbackModeRegistrant.notifyRegistrant();
+                        }
                     }
-                }
             }
         }
         return rr;
@@ -6341,7 +5870,6 @@
         pw.println(" " + mServiceProxies.get(HAL_SERVICE_SIM));
         pw.println(" " + mServiceProxies.get(HAL_SERVICE_VOICE));
         pw.println(" " + mServiceProxies.get(HAL_SERVICE_IMS));
-        pw.println(" " + mServiceProxies.get(HAL_SERVICE_SATELLITE));
         pw.println(" mWakeLock=" + mWakeLock);
         pw.println(" mWakeLockTimeout=" + mWakeLockTimeout);
         synchronized (mRequestList) {
@@ -6420,10 +5948,8 @@
                 return "VOICE";
             case HAL_SERVICE_IMS:
                 return "IMS";
-            case HAL_SERVICE_SATELLITE:
-                return "SATELLITE";
             default:
                 return "UNKNOWN:" + service;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java
index d41b725..c2c29f8 100644
--- a/src/java/com/android/internal/telephony/RILUtils.java
+++ b/src/java/com/android/internal/telephony/RILUtils.java
@@ -25,7 +25,6 @@
 import static android.telephony.TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK;
 
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOCATE_PDU_SESSION_ID;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOW_DATA;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER;
@@ -93,17 +92,12 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEISV;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_LOCATION_PRIVACY_SETTING;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MODEM_STATUS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MUTE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_CAPABILITIES;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_MODE;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_POWER;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS;
@@ -111,7 +105,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_USAGE_SETTING;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GSM_BROADCAST_ACTIVATION;
@@ -136,7 +129,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_RAW;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_STRINGS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PROVISION_SATELLITE_SERVICE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_NETWORKS;
@@ -148,14 +140,12 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_TTY_MODE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RELEASE_PDU_SESSION_ID;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_SMS_MEMORY_STATUS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RESET_RADIO;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SCREEN_STATE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_ANBR_QUERY;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_DEVICE_STATE;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SATELLITE_MESSAGES;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_USSD;
@@ -186,8 +176,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_POWER;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIM_CARD_POWER;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SMSC_ADDRESS;
@@ -213,7 +201,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_KEEPALIVE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_LCE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_NETWORK_SCAN;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_GET_PROFILE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND;
@@ -224,7 +211,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_KEEPALIVE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE;
 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN;
@@ -259,7 +245,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW;
@@ -267,7 +252,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD_REQUEST;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PCO_DATA;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_REGISTRATION_FAILED;
@@ -287,11 +271,6 @@
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RINGBACK_TONE;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_REFRESH;
 import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_SMS_STORAGE_FULL;
@@ -380,9 +359,6 @@
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
 import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason;
-import android.telephony.satellite.PointingInfo;
-import android.telephony.satellite.SatelliteCapabilities;
-import android.telephony.satellite.SatelliteManager;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.SparseArray;
@@ -980,8 +956,8 @@
      * @param dp Data profile
      * @return The converted DataProfileInfo
      */
-    public static android.hardware.radio.data.DataProfileInfo convertToHalDataProfile(@Nullable
-            DataProfile dp) {
+    public static android.hardware.radio.data.DataProfileInfo convertToHalDataProfile(
+            @Nullable DataProfile dp) {
         if (dp == null) return null;
         android.hardware.radio.data.DataProfileInfo dpi =
                 new android.hardware.radio.data.DataProfileInfo();
@@ -1007,8 +983,11 @@
         dpi.persistent = dp.isPersistent();
         dpi.preferred = dp.isPreferred();
         dpi.alwaysOn = false;
+        dpi.infrastructureBitmap = android.hardware.radio.data.DataProfileInfo
+                .INFRASTRUCTURE_CELLULAR;
         if (dp.getApnSetting() != null) {
             dpi.alwaysOn = dp.getApnSetting().isAlwaysOn();
+            dpi.infrastructureBitmap = dp.getApnSetting().getInfrastructureBitmask();
         }
         dpi.trafficDescriptor = convertToHalTrafficDescriptorAidl(dp.getTrafficDescriptor());
 
@@ -1046,6 +1025,7 @@
                 .setRoamingProtocol(dpi.roamingProtocol)
                 .setUser(dpi.user)
                 .setAlwaysOn(dpi.alwaysOn)
+                .setInfrastructureBitmask(dpi.infrastructureBitmap)
                 .build();
 
         TrafficDescriptor td;
@@ -3286,7 +3266,7 @@
             protocolType = result.type;
             ifname = result.ifname;
             laList = result.addresses.stream().map(la -> convertToLinkAddress(
-                    la.address, la.properties, la.deprecationTime, la.expirationTime))
+                            la.address, la.properties, la.deprecationTime, la.expirationTime))
                     .collect(Collectors.toList());
             dnses = result.dnses.toArray(new String[0]);
             gateways = result.gateways.toArray(new String[0]);
@@ -3304,7 +3284,7 @@
             protocolType = result.type;
             ifname = result.ifname;
             laList = result.addresses.stream().map(la -> convertToLinkAddress(
-                    la.address, la.properties, la.deprecationTime, la.expirationTime))
+                            la.address, la.properties, la.deprecationTime, la.expirationTime))
                     .collect(Collectors.toList());
             dnses = result.dnses.toArray(new String[0]);
             gateways = result.gateways.toArray(new String[0]);
@@ -3572,23 +3552,24 @@
     public static NetworkSlicingConfig convertHalSlicingConfig(
             android.hardware.radio.V1_6.SlicingConfig sc) {
         List<UrspRule> urspRules = sc.urspRules.stream().map(ur -> new UrspRule(ur.precedence,
-                ur.trafficDescriptors.stream()
-                        .map(td -> {
-                            try {
-                                return convertHalTrafficDescriptor(td);
-                            } catch (IllegalArgumentException e) {
-                                loge("convertHalSlicingConfig: Failed to convert traffic descriptor"
-                                        + ". e=" + e);
-                                return null;
-                            }
-                        })
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList()),
-                ur.routeSelectionDescriptor.stream().map(rsd -> new RouteSelectionDescriptor(
-                        rsd.precedence, rsd.sessionType.value(), rsd.sscMode.value(),
-                        rsd.sliceInfo.stream().map(RILUtils::convertHalSliceInfo)
+                        ur.trafficDescriptors.stream()
+                                .map(td -> {
+                                    try {
+                                        return convertHalTrafficDescriptor(td);
+                                    } catch (IllegalArgumentException e) {
+                                        loge("convertHalSlicingConfig: Failed to convert traffic "
+                                                + "descriptor. e=" + e);
+                                        return null;
+                                    }
+                                })
+                                .filter(Objects::nonNull)
                                 .collect(Collectors.toList()),
-                        rsd.dnn)).collect(Collectors.toList())))
+                        ur.routeSelectionDescriptor.stream().map(
+                                rsd -> new RouteSelectionDescriptor(rsd.precedence,
+                                        rsd.sessionType.value(), rsd.sscMode.value(),
+                                        rsd.sliceInfo.stream().map(RILUtils::convertHalSliceInfo)
+                                                .collect(Collectors.toList()),
+                                        rsd.dnn)).collect(Collectors.toList())))
                 .collect(Collectors.toList());
         return new NetworkSlicingConfig(urspRules, sc.sliceInfo.stream()
                 .map(RILUtils::convertHalSliceInfo).collect(Collectors.toList()));
@@ -5145,34 +5126,6 @@
                 return "SET_LOCATION_PRIVACY_SETTING";
             case RIL_REQUEST_GET_LOCATION_PRIVACY_SETTING:
                 return "GET_LOCATION_PRIVACY_SETTING";
-            case RIL_REQUEST_GET_SATELLITE_CAPABILITIES:
-                return "GET_SATELLITE_CAPABILITIES";
-            case RIL_REQUEST_SET_SATELLITE_POWER:
-                return "SET_SATELLITE_POWER";
-            case RIL_REQUEST_GET_SATELLITE_POWER:
-                return "GET_SATELLITE_POWER";
-            case RIL_REQUEST_PROVISION_SATELLITE_SERVICE:
-                return "PROVISION_SATELLITE_SERVICE";
-            case RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS:
-                return "ADD_ALLOWED_SATELLITE_CONTACTS";
-            case RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS:
-                return "REMOVE_ALLOWED_SATELLITE_CONTACTS";
-            case RIL_REQUEST_SEND_SATELLITE_MESSAGES:
-                return "SEND_SATELLITE_MESSAGES";
-            case RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES:
-                return "GET_PENDING_SATELLITE_MESSAGES";
-            case RIL_REQUEST_GET_SATELLITE_MODE:
-                return "GET_SATELLITE_MODE";
-            case RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER:
-                return "SET_SATELLITE_INDICATION_FILTER";
-            case RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO:
-                return "START_SENDING_SATELLITE_POINTING_INFO";
-            case RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO:
-                return "STOP_SENDING_SATELLITE_POINTING_INFO";
-            case RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE:
-                return "GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE";
-            case RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY:
-                return "GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY";
             default:
                 return "<unknown request " + request + ">";
         }
@@ -5295,20 +5248,6 @@
                 return "UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED";
             case RIL_UNSOL_SLICING_CONFIG_CHANGED:
                 return "UNSOL_SLICING_CONFIG_CHANGED";
-            case RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT:
-                return "UNSOL_PENDING_SATELLITE_MESSAGE_COUNT";
-            case RIL_UNSOL_NEW_SATELLITE_MESSAGES:
-                return "UNSOL_NEW_SATELLITE_MESSAGES";
-            case RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE:
-                return "UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE";
-            case RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED:
-                return "UNSOL_SATELLITE_POINTING_INFO_CHANGED";
-            case RIL_UNSOL_SATELLITE_MODE_CHANGED:
-                return "UNSOL_SATELLITE_MODE_CHANGED";
-            case RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED:
-                return "UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED";
-            case RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED:
-                return "UNSOL_SATELLITE_PROVISION_STATE_CHANGED";
             /* The follow unsols are not defined in RIL.h */
             case RIL_UNSOL_ICC_SLOT_STATUS:
                 return "UNSOL_ICC_SLOT_STATUS";
@@ -5324,12 +5263,12 @@
                 return "UNSOL_BARRING_INFO_CHANGED";
             case RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT:
                 return "UNSOL_EMERGENCY_NETWORK_SCAN_RESULT";
-            case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION:
-                return "UNSOL_TRIGGER_IMS_DEREGISTRATION";
             case RIL_UNSOL_CONNECTION_SETUP_FAILURE:
                 return "UNSOL_CONNECTION_SETUP_FAILURE";
             case RIL_UNSOL_NOTIFY_ANBR:
                 return "UNSOL_NOTIFY_ANBR";
+            case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION:
+                return "UNSOL_TRIGGER_IMS_DEREGISTRATION";
             default:
                 return "<unknown response " + response + ">";
         }
@@ -5446,7 +5385,7 @@
                 try {
                     val = o.getClass().getDeclaredMethod(getTagMethod).invoke(o);
                 } catch (NoSuchMethodException | IllegalAccessException
-                        | InvocationTargetException e) {
+                         | InvocationTargetException e) {
                     loge(e.toString());
                 }
                 if (val != null) {
@@ -5715,93 +5654,6 @@
     }
 
     /**
-     * Convert android.hardware.radio.satellite.SatelliteCapabilities to
-     * android.telephony.satellite.SatelliteCapabilities
-     */
-    public static SatelliteCapabilities convertHalSatelliteCapabilities(
-            android.hardware.radio.satellite.SatelliteCapabilities capabilities) {
-        Set<Integer> supportedRadioTechnologies = new HashSet<>();
-        if (capabilities.supportedRadioTechnologies != null
-                && capabilities.supportedRadioTechnologies.length > 0) {
-            for (int technology : capabilities.supportedRadioTechnologies) {
-                supportedRadioTechnologies.add(technology);
-            }
-        }
-        return new SatelliteCapabilities(supportedRadioTechnologies,
-                capabilities.needsPointingToSatellite, 0, null);
-    }
-
-    /**
-     * Convert from android.hardware.radio.satellite.PointingInfo to
-     * android.telephony.satellite.stub.PointingInfo
-     */
-    public static PointingInfo convertHalSatellitePointingInfo(
-            android.hardware.radio.satellite.PointingInfo pointingInfo) {
-        return new PointingInfo(pointingInfo.satelliteAzimuthDegrees,
-                pointingInfo.satelliteElevationDegrees);
-    }
-
-    /**
-     * Convert from android.telephony.satellite.stub.PointingInfo to
-     * android.hardware.radio.satellite.PointingInfo
-     */
-    public static android.hardware.radio.satellite.PointingInfo convertToHalSatellitePointingInfo(
-            PointingInfo pointingInfo) {
-        android.hardware.radio.satellite.PointingInfo halPointingInfo =
-                new android.hardware.radio.satellite.PointingInfo();
-        halPointingInfo.satelliteAzimuthDegrees = pointingInfo.getSatelliteAzimuthDegrees();
-        halPointingInfo.satelliteElevationDegrees = pointingInfo.getSatelliteElevationDegrees();
-        return halPointingInfo;
-    }
-
-    /**
-     * Convert satellite-related errors from CommandException.Error to
-     * SatelliteManager.SatelliteServiceResult.
-     * @param error The satellite error.
-     * @return The converted SatelliteServiceResult.
-     */
-    @SatelliteManager.SatelliteResult
-    public static int convertToSatelliteError(
-            CommandException.Error error) {
-        switch (error) {
-            case INTERNAL_ERR:
-                //fallthrough to SYSTEM_ERR
-            case MODEM_ERR:
-                //fallthrough to SYSTEM_ERR
-            case SYSTEM_ERR:
-                return SatelliteManager.SATELLITE_RESULT_MODEM_ERROR;
-            case INVALID_ARGUMENTS:
-                return SatelliteManager.SATELLITE_RESULT_INVALID_ARGUMENTS;
-            case INVALID_MODEM_STATE:
-                return SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE;
-            case RADIO_NOT_AVAILABLE:
-                return SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE;
-            case REQUEST_NOT_SUPPORTED:
-                return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
-            case NO_MEMORY:
-                //fallthrough to NO_RESOURCES
-            case NO_RESOURCES:
-                return SatelliteManager.SATELLITE_RESULT_NO_RESOURCES;
-            case NETWORK_ERR:
-                return SatelliteManager.SATELLITE_RESULT_NETWORK_ERROR;
-            case NETWORK_TIMEOUT:
-                return SatelliteManager.SATELLITE_RESULT_NETWORK_TIMEOUT;
-            case NO_NETWORK_FOUND:
-                //fallthrough to NO_SATELLITE_SIGNAL
-            case NO_SATELLITE_SIGNAL:
-                return SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE;
-            case ABORTED:
-                return SatelliteManager.SATELLITE_RESULT_REQUEST_ABORTED;
-            case ACCESS_BARRED:
-                return SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED;
-            case SUBSCRIBER_NOT_AUTHORIZED:
-                return SatelliteManager.SATELLITE_RESULT_NOT_AUTHORIZED;
-            default:
-                return SatelliteManager.SATELLITE_RESULT_ERROR;
-        }
-    }
-
-    /**
      * Converts the call state to HAL IMS call state.
      *
      * @param state The {@link Call.State}.
diff --git a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java
deleted file mode 100644
index ec334b6..0000000
--- a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2022 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;
-
-import android.os.RemoteException;
-import android.telephony.Rlog;
-
-/**
- * A holder for IRadioSatellite.
- * Use getAidl to get IRadioSatellite and call the AIDL implementations of the HAL APIs.
- */
-public class RadioSatelliteProxy extends RadioServiceProxy {
-    private static final String TAG = "RadioSatelliteProxy";
-    private volatile android.hardware.radio.satellite.IRadioSatellite mSatelliteProxy = null;
-
-    /**
-     * Sets IRadioSatellite as the AIDL implementation for RadioServiceProxy.
-     * @param halVersion Radio HAL version.
-     * @param satellite IRadioSatellite implementation.
-     *
-     * @return updated HAL version.
-     */
-    public HalVersion setAidl(HalVersion halVersion,
-            android.hardware.radio.satellite.IRadioSatellite satellite) {
-        HalVersion version = halVersion;
-        try {
-            version = RIL.getServiceHalVersion(satellite.getInterfaceVersion());
-        } catch (RemoteException e) {
-            Rlog.e(TAG, "setAidl: " + e);
-        }
-        mHalVersion = version;
-        mSatelliteProxy = satellite;
-        mIsAidl = true;
-
-        Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion);
-        return mHalVersion;
-    }
-
-    /**
-     * Gets the AIDL implementation of RadioSatelliteProxy.
-     * @return IRadioSatellite implementation.
-     */
-    public android.hardware.radio.satellite.IRadioSatellite getAidl() {
-        return mSatelliteProxy;
-    }
-
-    /**
-     * Resets RadioSatelliteProxy.
-     */
-    @Override
-    public void clear() {
-        super.clear();
-        mSatelliteProxy = null;
-    }
-
-    /**
-     * Checks whether a IRadioSatellite implementation exists.
-     * @return true if there is neither a HIDL nor AIDL implementation.
-     */
-    @Override
-    public boolean isEmpty() {
-        return mRadioProxy == null && mSatelliteProxy == null;
-    }
-
-    /**
-     * Call IRadioSatellite#responseAcknowledgement
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    @Override
-    public void responseAcknowledgement() throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.responseAcknowledgement();
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getCapabilities
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getCapabilities(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getCapabilities(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#setPower
-     * @param serial Serial number of request.
-     * @param on True for turning on.
-     *           False for turning off.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void setPower(int serial, boolean on) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.setPower(serial, on);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getPowerState
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getPowerState(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getPowerState(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#provisionService
-     * @param serial Serial number of request.
-     * @param imei IMEI of the SIM associated with the satellite modem.
-     * @param msisdn MSISDN of the SIM associated with the satellite modem.
-     * @param imsi IMSI of the SIM associated with the satellite modem.
-     * @param features List of features to be provisioned.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void provisionService(int serial, String imei, String msisdn, String imsi,
-            int[] features) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.provisionService(serial, imei, msisdn, imsi, features);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#addAllowedSatelliteContacts
-     * @param serial Serial number of request.
-     * @param contacts List of allowed contacts to be added.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void addAllowedSatelliteContacts(int serial, String[] contacts) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.addAllowedSatelliteContacts(serial, contacts);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#removeAllowedSatelliteContacts
-     * @param serial Serial number of request.
-     * @param contacts List of allowed contacts to be removed.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void removeAllowedSatelliteContacts(int serial, String[] contacts)
-            throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.removeAllowedSatelliteContacts(serial, contacts);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#sendMessages
-     * @param serial Serial number of request.
-     * @param messages List of messages in text format to be sent.
-     * @param destination The recipient of the message.
-     * @param latitude The current latitude of the device.
-     * @param longitude The current longitude of the device
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void sendMessages(int serial, String[] messages, String destination, double latitude,
-            double longitude) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.sendMessages(serial, messages, destination, latitude, longitude);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getPendingMessages
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getPendingMessages(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getPendingMessages(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getSatelliteMode
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getSatelliteMode(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getSatelliteMode(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#setIndicationFilter
-     * @param serial Serial number of request.
-     * @param filterBitmask The filter identifying what type of indication framework want to
-     *                         receive from modem.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void setIndicationFilter(int serial, int filterBitmask) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.setIndicationFilter(serial, filterBitmask);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#startSendingSatellitePointingInfo
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void startSendingSatellitePointingInfo(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.startSendingSatellitePointingInfo(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#stopSendingSatellitePointingInfo
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void stopSendingSatellitePointingInfo(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.stopSendingSatellitePointingInfo(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getMaxCharactersPerTextMessage
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getMaxCharactersPerTextMessage(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getMaxCharactersPerTextMessage(serial);
-        }
-    }
-
-    /**
-     * Call IRadioSatellite#getTimeForNextSatelliteVisibility
-     * @param serial Serial number of request.
-     * @throws RemoteException Throws RemoteException when RadioSatellite service is not available.
-     */
-    public void getTimeForNextSatelliteVisibility(int serial) throws RemoteException {
-        if (isEmpty()) return;
-        if (isAidl()) {
-            mSatelliteProxy.getTimeForNextSatelliteVisibility(serial);
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index 739ca8c..54c27c5 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -1010,6 +1010,16 @@
     protected abstract boolean shouldBlockSmsForEcbm();
 
     /**
+     * Notifies the {@link SmsDispatchersController} that sending MO SMS is failed.
+     *
+     * @param tracker holds the SMS message to be sent
+     */
+    protected void notifySmsSentFailedToEmergencyStateTracker(SmsTracker tracker) {
+        mSmsDispatchersController.notifySmsSentFailedToEmergencyStateTracker(
+                tracker.mDestAddress, tracker.mMessageId);
+    }
+
+    /**
      * Called when SMS send completes. Broadcasts a sentIntent on success.
      * On failure, either sets up retries or broadcasts a sentIntent with
      * the failure in the result code.
@@ -1041,6 +1051,8 @@
             }
             tracker.onSent(mContext);
             mPhone.notifySmsSent(tracker.mDestAddress);
+            mSmsDispatchersController.notifySmsSentToEmergencyStateTracker(
+                    tracker.mDestAddress, tracker.mMessageId);
 
             mPhone.getSmsStats().onOutgoingSms(
                     tracker.mImsRetry > 0 /* isOverIms */,
@@ -1091,6 +1103,7 @@
             // if sms over IMS is not supported on data and voice is not available...
             if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
                 tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
+                notifySmsSentFailedToEmergencyStateTracker(tracker);
                 mPhone.getSmsStats().onOutgoingSms(
                         tracker.mImsRetry > 0 /* isOverIms */,
                         SmsConstants.FORMAT_3GPP2.equals(getFormat()),
@@ -1151,6 +1164,7 @@
             } else {
                 int errorCode = (smsResponse != null) ? smsResponse.mErrorCode : NO_ERROR_CODE;
                 tracker.onFailed(mContext, error, errorCode);
+                notifySmsSentFailedToEmergencyStateTracker(tracker);
                 mPhone.getSmsStats().onOutgoingSms(
                         tracker.mImsRetry > 0 /* isOverIms */,
                         SmsConstants.FORMAT_3GPP2.equals(getFormat()),
@@ -2375,6 +2389,7 @@
             int errorCode) {
         for (SmsTracker tracker : trackers) {
             tracker.onFailed(mContext, error, errorCode);
+            notifySmsSentFailedToEmergencyStateTracker(tracker);
         }
         if (trackers.length > 0) {
             // This error occurs before the SMS is sent. Make an assumption if it would have
diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java
deleted file mode 100644
index 2e561c3..0000000
--- a/src/java/com/android/internal/telephony/SatelliteIndication.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2022 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;
-
-import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE;
-
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED;
-import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED;
-
-import android.hardware.radio.satellite.IRadioSatelliteIndication;
-import android.os.AsyncResult;
-import android.telephony.satellite.SatelliteDatagram;
-import android.util.Pair;
-
-/**
- * Interface declaring unsolicited radio indications for Satellite APIs.
- */
-public class SatelliteIndication extends IRadioSatelliteIndication.Stub {
-    private final RIL mRil;
-
-    public SatelliteIndication(RIL ril) {
-        mRil = ril;
-    }
-
-    @Override
-    public String getInterfaceHash() {
-        return IRadioSatelliteIndication.HASH;
-    }
-
-    @Override
-    public int getInterfaceVersion() {
-        return IRadioSatelliteIndication.VERSION;
-    }
-
-    /**
-     * Indicates that satellite has pending messages for the device to be pulled.
-     *
-     * @param indicationType Type of radio indication
-     * @param count Number of pending messages.
-     */
-    public void onPendingMessageCount(int indicationType, int count) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT);
-
-        if (mRil.mPendingSatelliteMessageCountRegistrants != null) {
-            mRil.mPendingSatelliteMessageCountRegistrants.notifyRegistrants(
-                    new AsyncResult(null, count, null));
-        }
-    }
-
-    /**
-     * Indicates new message received on device.
-     *
-     * @param indicationType Type of radio indication
-     * @param messages List of new messages received.
-     */
-    public void onNewMessages(int indicationType, String[] messages) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_NEW_SATELLITE_MESSAGES);
-
-        if (mRil.mNewSatelliteMessagesRegistrants != null) {
-            for (int i = 0; i < messages.length; i++) {
-                SatelliteDatagram datagram = new SatelliteDatagram(messages[i].getBytes());
-                mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants(
-                        new AsyncResult(null, new Pair<>(datagram, messages.length - i - 1), null));
-            }
-        }
-    }
-
-    /**
-     * Confirms that ongoing message transfer is complete.
-     *
-     * @param indicationType Type of radio indication
-     * @param complete True mean the transfer is complete.
-     *                 False means the transfer is not complete.
-     */
-    public void onMessagesTransferComplete(int indicationType, boolean complete) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE);
-
-        if (mRil.mSatelliteMessagesTransferCompleteRegistrants != null) {
-            mRil.mSatelliteMessagesTransferCompleteRegistrants.notifyRegistrants(
-                    new AsyncResult(null, complete, null));
-        }
-    }
-
-    /**
-     * Indicate that satellite Pointing input has changed.
-     *
-     * @param indicationType Type of radio indication
-     * @param pointingInfo The current pointing info.
-     */
-    public void onSatellitePointingInfoChanged(int indicationType,
-            android.hardware.radio.satellite.PointingInfo pointingInfo) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED);
-
-        if (mRil.mSatellitePointingInfoChangedRegistrants != null) {
-            mRil.mSatellitePointingInfoChangedRegistrants.notifyRegistrants(
-                    new AsyncResult(
-                            null,
-                            RILUtils.convertHalSatellitePointingInfo(pointingInfo),
-                            null));
-        }
-    }
-
-    /**
-     * Indicate that satellite mode has changed.
-     *
-     * @param indicationType Type of radio indication
-     * @param mode The current mode of the satellite modem.
-     */
-    public void onSatelliteModeChanged(int indicationType, int mode) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MODE_CHANGED);
-
-        if (mRil.mSatelliteModeChangedRegistrants != null) {
-            mRil.mSatelliteModeChangedRegistrants.notifyRegistrants(
-                    new AsyncResult(null, mode, null));
-        }
-    }
-
-    /**
-     * Indicate that satellite radio technology has changed.
-     *
-     * @param indicationType Type of radio indication
-     * @param technology The current technology of the satellite modem.
-     */
-    public void onSatelliteRadioTechnologyChanged(int indicationType, int technology) {
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED);
-
-        if (mRil.mSatelliteRadioTechnologyChangedRegistrants != null) {
-            mRil.mSatelliteRadioTechnologyChangedRegistrants.notifyRegistrants(
-                    new AsyncResult(null, technology, null));
-        }
-    }
-
-    /**
-     * Indicate that satellite provision state has changed.
-     *
-     * @param indicationType Type of radio indication
-     * @param provisioned True means the service is provisioned.
-     *                    False means the service is not provisioned.
-     * @param features List of Feature whose provision state has changed.
-     */
-    public void onProvisionStateChanged(int indicationType, boolean provisioned, int[] features) {
-        // TODO: remove features and update AsyncResult
-        mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType);
-
-        if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED);
-
-        if (mRil.mSatelliteProvisionStateChangedRegistrants != null) {
-            mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants(
-                    new AsyncResult(provisioned, null, null));
-        }
-    }
-}
diff --git a/src/java/com/android/internal/telephony/SatelliteResponse.java b/src/java/com/android/internal/telephony/SatelliteResponse.java
deleted file mode 100644
index 559691b..0000000
--- a/src/java/com/android/internal/telephony/SatelliteResponse.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2021 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;
-
-import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE;
-
-import android.hardware.radio.RadioError;
-import android.hardware.radio.RadioResponseInfo;
-import android.hardware.radio.satellite.IRadioSatelliteResponse;
-import android.telephony.satellite.SatelliteCapabilities;
-
-/**
- * Interface declaring response functions to solicited radio requests for Satellite APIs.
- */
-public class SatelliteResponse extends IRadioSatelliteResponse.Stub {
-    private final RIL mRil;
-
-    public SatelliteResponse(RIL ril) {
-        mRil = ril;
-    }
-
-    /**
-     * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for
-     * radio request which take long time to respond.
-     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
-     * @param serial Serial no. of the request whose acknowledgement is sent.
-     */
-    public void acknowledgeRequest(int serial) {
-        mRil.processRequestAck(serial);
-    }
-    /**
-     * Response of the request getCapabilities.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param capabilities List of capabilities that the satellite modem supports.
-     */
-    public void getCapabilitiesResponse(RadioResponseInfo responseInfo,
-            android.hardware.radio.satellite.SatelliteCapabilities capabilities) {
-        RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo);
-
-        if (rr != null) {
-            SatelliteCapabilities convertedSatelliteCapabilities =
-                    RILUtils.convertHalSatelliteCapabilities(capabilities);
-            if (responseInfo.error == RadioError.NONE) {
-                RadioResponse.sendMessageResponse(rr.mResult, convertedSatelliteCapabilities);
-            }
-            mRil.processResponseDone(rr, responseInfo, convertedSatelliteCapabilities);
-        }
-    }
-
-    /**
-     * Response of the request setPower.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void setPowerResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request getPowerState.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param on True means the modem is ON.
-     *           False means the modem is OFF.
-     */
-    public void getPowerStateResponse(RadioResponseInfo responseInfo, boolean on) {
-        RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, on ? 1 : 0);
-    }
-
-    /**
-     * Response of the request provisionService.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param provisioned True means the service is provisioned.
-     *                    False means the service is not provisioned.
-     */
-    public void provisionServiceResponse(RadioResponseInfo responseInfo, boolean provisioned) {
-        RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, provisioned ? 1 : 0);
-    }
-
-    /**
-     * Response of the request addAllowedSatelliteContacts.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void addAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request removeAllowedSatelliteContacts.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void removeAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request sendMessages.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void sendMessagesResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request getPendingMessages.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param messages List of pending messages received.
-     */
-    public void getPendingMessagesResponse(RadioResponseInfo responseInfo, String[] messages) {
-        RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo);
-
-        if (rr != null) {
-            if (responseInfo.error == RadioError.NONE) {
-                RadioResponse.sendMessageResponse(rr.mResult, messages);
-            }
-            mRil.processResponseDone(rr, responseInfo, messages);
-        }
-    }
-
-    /**
-     * Response of the request getSatelliteMode.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param mode Current Mode of the satellite modem.
-     * @param technology The current technology of the satellite modem.
-     */
-    public void getSatelliteModeResponse(RadioResponseInfo responseInfo, int mode, int technology) {
-        RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo);
-
-        if (rr != null) {
-            int[] ret = new int[]{mode, technology};
-            if (responseInfo.error == RadioError.NONE) {
-                RadioResponse.sendMessageResponse(rr.mResult, ret);
-            }
-            mRil.processResponseDone(rr, responseInfo, ret);
-        }
-    }
-
-    /**
-     * Response of the request setIndicationFilter.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void setIndicationFilterResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request startSendingSatellitePointingInfo.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void startSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request stopSendingSatellitePointingInfo.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     */
-    public void stopSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) {
-        RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo);
-    }
-
-    /**
-     * Response of the request getMaxCharactersPerTextMessage.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param charLimit Maximum number of characters in a text message that can be sent.
-     */
-    public void getMaxCharactersPerTextMessageResponse(
-            RadioResponseInfo responseInfo, int charLimit) {
-        RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, charLimit);
-    }
-
-    /**
-     * Response of the request getTimeForNextSatelliteVisibility.
-     *
-     * @param responseInfo Response info struct containing serial no. and error
-     * @param timeInSeconds The duration in seconds after which the satellite will be visible.
-     */
-    public void getTimeForNextSatelliteVisibilityResponse(
-            RadioResponseInfo responseInfo, int timeInSeconds) {
-        RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, timeInSeconds);
-    }
-
-    @Override
-    public String getInterfaceHash() {
-        return IRadioSatelliteResponse.HASH;
-    }
-
-    @Override
-    public int getInterfaceVersion() {
-        return IRadioSatelliteResponse.VERSION;
-    }
-}
diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java
index d2dfcac..8795840 100644
--- a/src/java/com/android/internal/telephony/SmsDispatchersController.java
+++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java
@@ -45,16 +45,20 @@
 import android.telephony.SmsManager;
 import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
 import android.text.TextUtils;
 
 import com.android.ims.ImsManager;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
 import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
 import com.android.internal.telephony.domainselection.DomainSelectionConnection;
 import com.android.internal.telephony.domainselection.DomainSelectionResolver;
 import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection;
 import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection;
+import com.android.internal.telephony.emergency.EmergencyStateTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
 import com.android.internal.telephony.gsm.GsmSMSDispatcher;
 import com.android.telephony.Rlog;
@@ -62,8 +66,10 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -94,6 +100,15 @@
     /** InboundSmsHandler exited WaitingState */
     protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17;
 
+    /** Called when SMS should be sent using AP domain selection. */
+    private static final int EVENT_SEND_SMS_USING_DOMAIN_SELECTION = 18;
+
+    /** Called when SMS is completely sent using AP domain selection regardless of the result. */
+    private static final int EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION = 19;
+
+    /** Called when AP domain selection is abnormally terminated. */
+    private static final int EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY = 20;
+
     /** Delete any partial message segments after being IN_SERVICE for 1 day. */
     private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24;
     /** Constant for invalid time */
@@ -117,6 +132,7 @@
     private final SmsUsageMonitor mUsageMonitor;
     private final CommandsInterface mCi;
     private final Context mContext;
+    private final @NonNull FeatureFlags mFeatureFlags;
 
     /** true if IMS is registered and sms is supported, false otherwise.*/
     private boolean mIms = false;
@@ -183,7 +199,7 @@
             };
 
     /** Stores the sending SMS information for a pending request. */
-    private class PendingRequest {
+    private static class PendingRequest {
         public static final int TYPE_DATA = 1;
         public static final int TYPE_TEXT = 2;
         public static final int TYPE_MULTIPART_TEXT = 3;
@@ -310,13 +326,18 @@
 
         @Override
         public void onSelectionTerminated(@DisconnectCauses int cause) {
-            notifyDomainSelectionTerminated(this);
+            logd("onSelectionTerminated: emergency=" + mEmergency + ", cause=" + cause);
+            // This callback is invoked by another thread, so this operation is posted and handled
+            // through the execution flow of SmsDispatchersController.
+            SmsDispatchersController.this.sendMessage(
+                    obtainMessage(EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY, this));
         }
     }
 
     /** Manages the domain selection connections: MO SMS or emergency SMS. */
     private DomainSelectionConnectionHolder mDscHolder;
     private DomainSelectionConnectionHolder mEmergencyDscHolder;
+    private EmergencyStateTracker mEmergencyStateTracker;
 
     /**
      * Puts a delivery pending tracker to the map based on the format.
@@ -332,13 +353,13 @@
     }
 
     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
-            SmsUsageMonitor usageMonitor) {
-        this(phone, storageMonitor, usageMonitor, phone.getLooper());
+            SmsUsageMonitor usageMonitor, @NonNull FeatureFlags featureFlags) {
+        this(phone, storageMonitor, usageMonitor, phone.getLooper(), featureFlags);
     }
 
     @VisibleForTesting
     public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
-            SmsUsageMonitor usageMonitor, Looper looper) {
+            SmsUsageMonitor usageMonitor, Looper looper, @NonNull FeatureFlags featureFlags) {
         super(looper);
 
         Rlog.d(TAG, "SmsDispatchersController created");
@@ -346,6 +367,7 @@
         mContext = phone.getContext();
         mUsageMonitor = usageMonitor;
         mCi = phone.mCi;
+        mFeatureFlags = featureFlags;
         mPhone = phone;
 
         // Create dispatchers, inbound SMS handlers and
@@ -447,7 +469,36 @@
                 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
                 resetPartialSegmentWaitTimer();
                 break;
-
+            case EVENT_SEND_SMS_USING_DOMAIN_SELECTION: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                DomainSelectionConnectionHolder holder =
+                        (DomainSelectionConnectionHolder) args.arg1;
+                PendingRequest request = (PendingRequest) args.arg2;
+                String logTag = (String) args.arg3;
+                try {
+                    handleSendSmsUsingDomainSelection(holder, request, logTag);
+                } finally {
+                    args.recycle();
+                }
+                break;
+            }
+            case EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                String destAddr = (String) args.arg1;
+                Long messageId = (Long) args.arg2;
+                Boolean success = (Boolean) args.arg3;
+                try {
+                    handleSmsSentCompletedUsingDomainSelection(destAddr, messageId, success);
+                } finally {
+                    args.recycle();
+                }
+                break;
+            }
+            case EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY: {
+                handleDomainSelectionTerminatedAbnormally(
+                        (DomainSelectionConnectionHolder) msg.obj);
+                break;
+            }
             default:
                 if (isCdmaMo()) {
                     mCdmaDispatcher.handleMessage(msg);
@@ -701,7 +752,7 @@
         boolean retryUsingImsService = false;
 
         if (!tracker.mUsesImsServiceForIms) {
-            if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+            if (isSmsDomainSelectionEnabled()) {
                 DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
 
                 // If the DomainSelectionConnection is not available,
@@ -756,6 +807,8 @@
                 // should never come here...
                 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+                notifySmsSentFailedToEmergencyStateTracker(
+                        tracker.mDestAddress, tracker.mMessageId);
                 return;
             }
             String scAddr = (String) map.get("scAddr");
@@ -763,6 +816,8 @@
             if (destAddr == null) {
                 Rlog.e(TAG, "sendRetrySms failed due to null destAddr");
                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+                notifySmsSentFailedToEmergencyStateTracker(
+                        tracker.mDestAddress, tracker.mMessageId);
                 return;
             }
 
@@ -803,6 +858,8 @@
                         + "scAddr: %s, "
                         + "destPort: %s", scAddr, map.get("destPort")));
                 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+                notifySmsSentFailedToEmergencyStateTracker(
+                        tracker.mDestAddress, tracker.mMessageId);
                 return;
             }
             // replace old smsc and pdu with newly encoded ones
@@ -889,6 +946,16 @@
     }
 
     /**
+     * Checks whether the SMS domain selection is enabled or not.
+     *
+     * @return {@code true} if the SMS domain selection is enabled, {@code false} otherwise.
+     */
+    private boolean isSmsDomainSelectionEnabled() {
+        return mFeatureFlags.smsDomainSelectionEnabled()
+                && mDomainSelectionResolverProxy.isDomainSelectionSupported();
+    }
+
+    /**
      * Determines whether or not to use CDMA format for MO SMS when the domain selection uses.
      * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on
      * IMS SMS format, otherwise format is based on current phone type.
@@ -929,7 +996,6 @@
     private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) {
         DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency);
         DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null;
-        boolean created = false;
 
         if (connection == null) {
             connection = mDomainSelectionResolverProxy.getDomainSelectionConnection(
@@ -940,8 +1006,6 @@
                 // Use the legacy architecture.
                 return null;
             }
-
-            created = true;
         }
 
         if (holder == null) {
@@ -965,6 +1029,7 @@
      * @param holder The {@link DomainSelectionConnectionHolder} that contains the
      *               {@link DomainSelectionConnection} and its related information.
      */
+    @SuppressWarnings("FutureReturnValueIgnored")
     private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) {
         DomainSelectionService.SelectionAttributes attr =
                 new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(),
@@ -1001,16 +1066,14 @@
     }
 
     /**
-     * Sends a SMS after selecting the domain via the domain selection service.
+     * Requests the domain selection for MO SMS.
      *
      * @param holder The {@link DomainSelectionConnectionHolder} that contains the
      *               {@link DomainSelectionConnection} and its related information.
-     * @param request The {@link PendingRequest} that stores the SMS request
-     *                (data, text, multipart text) to be sent.
-     * @param logTag The log tag to display which method called this method.
+     * @param logTag The log string.
      */
-    private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
-            @NonNull PendingRequest request, @NonNull String logTag) {
+    private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+            @NonNull PendingRequest request, String logTag) {
         boolean isDomainSelectionRequested = holder.isDomainSelectionRequested();
         // The domain selection is in progress so waits for the result of
         // the domain selection by adding this request to the pending list.
@@ -1025,6 +1088,120 @@
     }
 
     /**
+     * Handles an event for sending a SMS after selecting the domain via the domain selection
+     * service.
+     *
+     * @param holder The {@link DomainSelectionConnectionHolder} that contains the
+     *               {@link DomainSelectionConnection} and its related information.
+     * @param request The {@link PendingRequest} that stores the SMS request
+     *                (data, text, multipart text) to be sent.
+     * @param logTag The log tag to display which method called this method.
+     */
+    @SuppressWarnings("FutureReturnValueIgnored")
+    private void handleSendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+            @NonNull PendingRequest request, @NonNull String logTag) {
+        if (holder.isEmergency()) {
+            if (mEmergencyStateTracker == null) {
+                mEmergencyStateTracker = EmergencyStateTracker.getInstance();
+            }
+
+            CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencySms(mPhone,
+                    String.valueOf(request.messageId),
+                    isTestEmergencyNumber(request.destAddr));
+            future.thenAccept((result) -> {
+                logi("startEmergencySms(" + logTag + "): messageId=" + request.messageId
+                        + ", result=" + result);
+                // An emergency SMS should be proceeded regardless of the result of the
+                // EmergencyStateTracker.
+                // So the domain selection request should be invoked without checking the result.
+                requestDomainSelection(holder, request, logTag);
+            });
+        } else {
+            requestDomainSelection(holder, request, logTag);
+        }
+    }
+
+    /**
+     * Sends a SMS after selecting the domain via the domain selection service.
+     *
+     * @param holder The {@link DomainSelectionConnectionHolder} that contains the
+     *               {@link DomainSelectionConnection} and its related information.
+     * @param request The {@link PendingRequest} that stores the SMS request
+     *                (data, text, multipart text) to be sent.
+     * @param logTag The log tag to display which method called this method.
+     */
+    private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+            @NonNull PendingRequest request, @NonNull String logTag) {
+        // Run on main thread for interworking with EmergencyStateTracker
+        // and adding the pending request.
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = holder;
+        args.arg2 = request;
+        args.arg3 = logTag;
+        sendMessage(obtainMessage(EVENT_SEND_SMS_USING_DOMAIN_SELECTION, args));
+    }
+
+    /**
+     * Called when sending MO SMS is complete regardless of the sent result.
+     *
+     * @param destAddr The destination address for SMS.
+     * @param messageId The message id for SMS.
+     * @param success A flag specifying whether MO SMS is successfully sent or not.
+     */
+    private void handleSmsSentCompletedUsingDomainSelection(@NonNull String destAddr,
+            long messageId, boolean success) {
+        if (mEmergencyStateTracker != null) {
+            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+            if (tm.isEmergencyNumber(destAddr)) {
+                mEmergencyStateTracker.endSms(String.valueOf(messageId), success);
+            }
+        }
+    }
+
+    /**
+     * Called when MO SMS is successfully sent.
+     */
+    protected void notifySmsSentToEmergencyStateTracker(@NonNull String destAddr, long messageId) {
+        if (isSmsDomainSelectionEnabled()) {
+            // Run on main thread for interworking with EmergencyStateTracker.
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = destAddr;
+            args.arg2 = Long.valueOf(messageId);
+            args.arg3 = Boolean.TRUE;
+            sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
+        }
+    }
+
+    /**
+     * Called when sending MO SMS is failed.
+     */
+    protected void notifySmsSentFailedToEmergencyStateTracker(@NonNull String destAddr,
+            long messageId) {
+        if (isSmsDomainSelectionEnabled()) {
+            // Run on main thread for interworking with EmergencyStateTracker.
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = destAddr;
+            args.arg2 = Long.valueOf(messageId);
+            args.arg3 = Boolean.FALSE;
+            sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
+        }
+    }
+
+    private boolean isTestEmergencyNumber(String number) {
+        try {
+            TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+            Map<Integer, List<EmergencyNumber>> eMap = tm.getEmergencyNumberList();
+            return eMap.values().stream().flatMap(Collection::stream).anyMatch(eNumber ->
+                    eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)
+                    && number.equals(eNumber.getNumber()));
+        } catch (IllegalStateException ise) {
+            return false;
+        } catch (RuntimeException r) {
+            return false;
+        }
+    }
+
+    /**
      * Finishes the domain selection for MO SMS.
      *
      * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished.
@@ -1054,21 +1231,16 @@
     }
 
     /**
-     * Notifies the application that MO SMS is not sent by the error of domain selection.
+     * Called when MO SMS is not sent by the error of domain selection.
      *
      * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated.
      */
-    private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) {
-        final List<PendingRequest> pendingRequests = holder.getPendingRequests();
-
-        logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size());
-
-        for (PendingRequest r : pendingRequests) {
-            triggerSentIntentForFailure(r.sentIntents);
-        }
-
+    private void handleDomainSelectionTerminatedAbnormally(
+            @NonNull DomainSelectionConnectionHolder holder) {
+        logd("handleDomainSelectionTerminatedAbnormally: pendingRequests="
+                + holder.getPendingRequests().size());
+        sendAllPendingRequests(holder, NetworkRegistrationInfo.DOMAIN_UNKNOWN);
         holder.setConnection(null);
-        holder.clearAllRequests();
     }
 
     /**
@@ -1089,12 +1261,36 @@
                     + ", size=" + pendingRequests.size());
         }
 
+        // When the domain selection request is failed, SMS should be fallback
+        // to the legacy implementation.
+        boolean wasDomainUnknown = false;
+
+        if (domain == NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+            logd("sendAllPendingRequests: fallback - imsAvailable="
+                    + mImsSmsDispatcher.isAvailable());
+
+            wasDomainUnknown = true;
+
+            if (mImsSmsDispatcher.isAvailable()) {
+                domain = NetworkRegistrationInfo.DOMAIN_PS;
+            } else {
+                domain = NetworkRegistrationInfo.DOMAIN_CS;
+            }
+        }
+
         for (PendingRequest r : pendingRequests) {
             switch (r.type) {
                 case PendingRequest.TYPE_DATA:
                     sendData(domain, r);
                     break;
                 case PendingRequest.TYPE_TEXT:
+                    // When the domain selection request is failed, emergency SMS should be fallback
+                    // to the legacy implementation.
+                    if (wasDomainUnknown
+                            && domain != NetworkRegistrationInfo.DOMAIN_PS
+                            && mImsSmsDispatcher.isEmergencySmsSupport(r.destAddr)) {
+                        domain = NetworkRegistrationInfo.DOMAIN_PS;
+                    }
                     sendText(domain, r);
                     break;
                 case PendingRequest.TYPE_MULTIPART_TEXT:
@@ -1308,7 +1504,7 @@
             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage);
         }
 
-        if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+        if (isSmsDomainSelectionEnabled()) {
             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
 
             // If the DomainSelectionConnection is not available,
@@ -1547,7 +1743,7 @@
             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
         }
 
-        if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+        if (isSmsDomainSelectionEnabled()) {
             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
             boolean isEmergency = tm.isEmergencyNumber(destAddr);
             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency);
@@ -1696,7 +1892,7 @@
             scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
         }
 
-        if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+        if (isSmsDomainSelectionEnabled()) {
             DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
 
             // If the DomainSelectionConnection is not available,
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 17a4a54..8b832dd 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -327,8 +327,12 @@
         return new IccPhoneBookInterfaceManager(phone);
     }
 
-    public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone) {
-        return new IccSmsInterfaceManager(phone);
+    /**
+     * Returns a new {@link IccSmsInterfaceManager} instance.
+     */
+    public IccSmsInterfaceManager makeIccSmsInterfaceManager(Phone phone,
+            @NonNull FeatureFlags featureFlags) {
+        return new IccSmsInterfaceManager(phone, featureFlags);
     }
 
     /**
@@ -402,8 +406,12 @@
         return new AppSmsManager(context);
     }
 
-    public DeviceStateMonitor makeDeviceStateMonitor(Phone phone) {
-        return new DeviceStateMonitor(phone);
+    /**
+     * Create a DeviceStateMonitor.
+     */
+    public DeviceStateMonitor makeDeviceStateMonitor(Phone phone,
+            @NonNull FeatureFlags featureFlags) {
+        return new DeviceStateMonitor(phone, featureFlags);
     }
 
     /**
@@ -444,8 +452,8 @@
     /**
      * Create a new DisplayInfoController.
      */
-    public DisplayInfoController makeDisplayInfoController(Phone phone) {
-        return new DisplayInfoController(phone);
+    public DisplayInfoController makeDisplayInfoController(Phone phone, FeatureFlags featureFlags) {
+        return new DisplayInfoController(phone, featureFlags);
     }
 
     /**
@@ -494,15 +502,17 @@
      * @param dataServiceManager Data service manager instance.
      * @param looper The looper to be used by the handler. Currently the handler thread is the phone
      * process's main thread.
+     * @param featureFlags Feature flags controlling which feature is enabled.     *
      * @param callback Callback for passing events back to data network controller.
      * @return The data profile manager instance.
      */
     public @NonNull DataProfileManager makeDataProfileManager(@NonNull Phone phone,
             @NonNull DataNetworkController dataNetworkController,
             @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper,
+            @NonNull FeatureFlags featureFlags,
             @NonNull DataProfileManager.DataProfileManagerCallback callback) {
         return new DataProfileManager(phone, dataNetworkController, dataServiceManager, looper,
-                callback);
+                featureFlags, callback);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index ebc6342..2119003 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -129,6 +129,7 @@
         // if sms over IMS is not supported on data and voice is not available...
         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
             tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
+            notifySmsSentFailedToEmergencyStateTracker(tracker);
             return;
         }
 
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 22ad593..950ac10 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -31,6 +31,7 @@
 import android.telephony.Annotation.NetCapability;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.SubscriptionManager;
@@ -46,6 +47,7 @@
 import com.android.internal.telephony.data.DataNetworkController.HandoverRule;
 import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryRule;
 import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryRule;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -259,6 +261,7 @@
     private @NonNull final Phone mPhone;
     private @NonNull final String mLogTag;
 
+    @NonNull private final FeatureFlags mFeatureFlags;
     private @NonNull final CarrierConfigManager mCarrierConfigManager;
     private @NonNull PersistableBundle mCarrierConfig = null;
     private @NonNull Resources mResources = null;
@@ -295,6 +298,9 @@
     private @NonNull final List<HandoverRule> mHandoverRuleList = new ArrayList<>();
     /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/
     private boolean mShouldKeepNetworkUpInNonVops = false;
+    /** The set of network types that enable VOPS even in non VOPS area. */
+    @NonNull private final @CarrierConfigManager.Ims.NetworkType List<Integer>
+            mEnabledVopsNetworkTypesInNonVops = new ArrayList<>();
     /**
      * A map of network types to the estimated downlink values by signal strength 0 - 4 for that
      * network type
@@ -309,9 +315,11 @@
      * @param looper The looper to be used by the handler. Currently the handler thread is the
      * phone process's main thread.
      */
-    public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper) {
+    public DataConfigManager(@NonNull Phone phone, @NonNull Looper looper,
+            @NonNull FeatureFlags featureFlags) {
         super(looper);
         mPhone = phone;
+        mFeatureFlags = featureFlags;
         mLogTag = "DCM-" + mPhone.getPhoneId();
         log("DataConfigManager created.");
 
@@ -666,6 +674,11 @@
         synchronized (this) {
             mShouldKeepNetworkUpInNonVops = mCarrierConfig.getBoolean(CarrierConfigManager
                     .Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL);
+            int[] allowedNetworkTypes = mCarrierConfig.getIntArray(
+                    CarrierConfigManager.Ims.KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY);
+            if (allowedNetworkTypes != null) {
+                Arrays.stream(allowedNetworkTypes).forEach(mEnabledVopsNetworkTypesInNonVops::add);
+            }
         }
     }
 
@@ -684,9 +697,29 @@
         return Collections.unmodifiableSet(mCapabilitiesExemptFromSingleDataList);
     }
 
-    /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/
-    public boolean shouldKeepNetworkUpInNonVops() {
-        return mShouldKeepNetworkUpInNonVops;
+    /**
+     * @param regState The modem reported data registration state.
+     * @return {@code true} if should keep IMS network in case of moving to non VOPS area.
+     */
+    public boolean shouldKeepNetworkUpInNonVops(@NetworkRegistrationInfo.RegistrationState
+            int regState) {
+        return mShouldKeepNetworkUpInNonVops || allowBringUpNetworkInNonVops(regState);
+    }
+
+    /**
+     * @param regState The modem reported data registration state.
+     * @return {@code true} if allow bring up IMS network in case of moving to non VOPS area.
+     */
+    public boolean allowBringUpNetworkInNonVops(@NetworkRegistrationInfo.RegistrationState
+            int regState) {
+        if (!mFeatureFlags.allowMmtelInNonVops()) return false;
+        int networkType = -1;
+        if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
+            networkType = CarrierConfigManager.Ims.NETWORK_TYPE_HOME;
+        } else if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) {
+            networkType = CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING;
+        }
+        return mEnabledVopsNetworkTypesInNonVops.contains(networkType);
     }
 
     /** {@code True} requires ping test to pass on the target slot before switching to it.*/
@@ -1423,7 +1456,8 @@
         pw.println("Capabilities exempt from single PDN=" + mCapabilitiesExemptFromSingleDataList
                 .stream().map(DataUtils::networkCapabilityToString)
                 .collect(Collectors.joining(",")));
-        pw.println("mShouldKeepNetworkUpInNoVops=" + mShouldKeepNetworkUpInNonVops);
+        pw.println("mShouldKeepNetworkUpInNonVops=" + mShouldKeepNetworkUpInNonVops);
+        pw.println("mEnabledVopsNetworkTypesInNonVops=" + mEnabledVopsNetworkTypesInNonVops);
         pw.println("isPingTestBeforeAutoDataSwitchRequired="
                 + isPingTestBeforeAutoDataSwitchRequired());
         pw.println("Unmetered network types=" + String.join(",", mUnmeteredNetworkTypes));
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index 6b410ce..0c5c9cb 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -99,6 +99,7 @@
 import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback;
 import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback;
 import com.android.internal.telephony.data.TelephonyNetworkAgent.TelephonyNetworkAgentCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.metrics.DataCallSessionStats;
 import com.android.internal.telephony.metrics.TelephonyMetrics;
 import com.android.internal.util.ArrayUtils;
@@ -440,9 +441,9 @@
             // Connectivity service will support NOT_METERED as a mutable and requestable
             // capability.
             NetworkCapabilities.NET_CAPABILITY_NOT_METERED,
-            // Even though MMTEL is an immutable capability, we still make it an mutable capability
-            // here before we have a better solution to deal with network transition from VoPS
-            // to non-VoPS network.
+            // Dynamically add and remove MMTEL capability when network transition between VoPS
+            // and non-VoPS network if the request is not MMTEL. For MMTEL, we retain the capability
+            // to prevent immediate tear down.
             NetworkCapabilities.NET_CAPABILITY_MMTEL
     );
 
@@ -490,6 +491,9 @@
     /** The phone instance. */
     private final @NonNull Phone mPhone;
 
+    /** Feature flags */
+    private final @NonNull FeatureFlags mFlags;
+
     /**
      * The subscription id. This is assigned when the network is created, and not supposed to
      * change afterwards.
@@ -897,7 +901,7 @@
      * @param dataAllowedReason The reason that why setting up this data network is allowed.
      * @param callback The callback to receives data network state update.
      */
-    public DataNetwork(@NonNull Phone phone, @NonNull Looper looper,
+    public DataNetwork(@NonNull Phone phone, FeatureFlags featureFlags, @NonNull Looper looper,
             @NonNull SparseArray<DataServiceManager> dataServiceManagers,
             @NonNull DataProfile dataProfile,
             @NonNull NetworkRequestList networkRequestList,
@@ -911,6 +915,7 @@
         initializeStateMachine();
 
         mPhone = phone;
+        mFlags = featureFlags;
         mSubId = phone.getSubId();
         mRil = mPhone.mCi;
         mLinkProperties = new LinkProperties();
@@ -2141,30 +2146,34 @@
             }
         }
 
-        // Once we set the MMTEL capability, we should never remove it because it's an immutable
+        // If MMTEL capability is requested, we should not remove it because it's an immutable
         // capability defined by connectivity service. When the device enters from VoPS to non-VoPS,
         // we should perform grace tear down from data network controller if needed.
-        if (mNetworkCapabilities != null
-                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
-            // Previous capability has MMTEL, so add it again.
+        if (hasNetworkCapabilityInNetworkRequests(NetworkCapabilities.NET_CAPABILITY_MMTEL)) {
+            // Request has MMTEL, add it again so the network won't be unwanted by connectivity.
             builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-        } else {
+        } else if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+            // Request has IMS capability only.
             // Always add MMTEL capability on IMS network unless network explicitly indicates VoPS
             // not supported.
-            if (mDataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) {
-                builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-                if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
-                    NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
-                    if (nri != null) {
-                        DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
-                        // Check if the network is non-VoPS.
-                        if (dsri != null && dsri.getVopsSupportInfo() != null
-                                && !dsri.getVopsSupportInfo().isVopsSupported()
-                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
-                            builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
-                        }
-                        log("updateNetworkCapabilities: dsri=" + dsri);
+            builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+            if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+                NetworkRegistrationInfo nri = getNetworkRegistrationInfo();
+                if (nri != null) {
+                    DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+                    // Check if the network is non-VoPS.
+                    if (dsri != null && dsri.getVopsSupportInfo() != null
+                            && !dsri.getVopsSupportInfo().isVopsSupported()
+                            // Reflect the actual MMTEL if flag on.
+                            && (mFlags.allowMmtelInNonVops()
+                            // Deceive Connectivity service to satisfy an MMTEL request, this should
+                            // be useless because we reach here if no MMTEL request, then removing
+                            // MMTEL capability shouldn't have any impacts.
+                            || !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                    nri.getNetworkRegistrationState()))) {
+                        builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
                     }
+                    log("updateNetworkCapabilities: dsri=" + dsri);
                 }
             }
         }
@@ -2721,7 +2730,7 @@
     public boolean shouldDelayImsTearDownDueToInCall() {
         return mDataConfigManager.isImsDelayTearDownUntilVoiceCallEndEnabled()
                 && mNetworkCapabilities != null
-                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL)
+                && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                 && mPhone.getImsPhone() != null
                 && mPhone.getImsPhone().getCallTracker().getState()
                 != PhoneConstants.State.IDLE;
@@ -3308,7 +3317,8 @@
                 && !mAttachedNetworkRequestList.isEmpty()) {
             TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0);
             DataProfile dataProfile = mDataNetworkController.getDataProfileManager()
-                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, false);
+                    .getDataProfileForNetworkRequest(networkRequest, targetNetworkType,
+                            mPhone.getServiceState().isUsingNonTerrestrialNetwork(), false);
             // Some carriers have different profiles between cellular and IWLAN. We need to
             // dynamically switch profile, but only when those profiles have same APN name.
             if (dataProfile != null && dataProfile.getApnSetting() != null
diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java
index 3073f49..2d91967 100644
--- a/src/java/com/android/internal/telephony/data/DataNetworkController.java
+++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java
@@ -813,7 +813,7 @@
             mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, transport));
         }
 
-        mDataConfigManager = new DataConfigManager(mPhone, looper);
+        mDataConfigManager = new DataConfigManager(mPhone, looper, featureFlags);
 
         // ========== Anomaly counters ==========
         mImsThrottleCounter = new SlidingWindowEventCounter(
@@ -879,6 +879,7 @@
                 DataProfileManager.class.getName())
                 .makeDataProfileManager(mPhone, this, mDataServiceManagers
                                 .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper,
+                        mFeatureFlags,
                         new DataProfileManagerCallback(this::post) {
                             @Override
                             public void onDataProfilesChanged() {
@@ -899,7 +900,7 @@
                     }
                 });
         mDataRetryManager = new DataRetryManager(mPhone, this,
-                mDataServiceManagers, looper,
+                mDataServiceManagers, looper, mFeatureFlags,
                 new DataRetryManagerCallback(this::post) {
                     @Override
                     public void onDataNetworkSetupRetry(
@@ -1328,6 +1329,7 @@
                 DataProfile candidate = mDataProfileManager
                         .getDataProfileForNetworkRequest(requestList.getFirst(),
                                 TelephonyManager.NETWORK_TYPE_IWLAN,
+                                mServiceState.isUsingNonTerrestrialNetwork(),
                                 false/*ignorePermanentFailure*/);
                 if (candidate != null && !dataNetwork.getDataProfile().equals(candidate)) {
                     logv("But skipped because found better data profile " + candidate
@@ -1491,7 +1493,8 @@
         if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) {
             evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST);
             evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest(
-                    networkRequest, getDataNetworkType(transport), true));
+                    networkRequest, getDataNetworkType(transport),
+                    mServiceState.isUsingNonTerrestrialNetwork(), true));
             networkRequest.setEvaluation(evaluation);
             log(evaluation.toString());
             return evaluation;
@@ -1526,7 +1529,9 @@
             if (nri != null) {
                 DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                 if (dsri != null && dsri.getVopsSupportInfo() != null
-                        && !dsri.getVopsSupportInfo().isVopsSupported()) {
+                        && !dsri.getVopsSupportInfo().isVopsSupported()
+                        && !mDataConfigManager.allowBringUpNetworkInNonVops(
+                                nri.getNetworkRegistrationState())) {
                     evaluation.addDataDisallowedReason(DataDisallowedReason.VOPS_NOT_SUPPORTED);
                 }
             }
@@ -1647,6 +1652,7 @@
         }
         DataProfile dataProfile = mDataProfileManager
                 .getDataProfileForNetworkRequest(networkRequest, networkType,
+                        mServiceState.isUsingNonTerrestrialNetwork(),
                         // If the evaluation is due to environmental changes, then we should ignore
                         // the permanent failure reached earlier.
                         reason.isConditionBased());
@@ -1787,6 +1793,8 @@
             }
         }
 
+        // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL
+        // capability is dynamically added when moving between vops and nonvops area.
         boolean vopsIsRequired = dataNetwork.hasNetworkCapabilityInNetworkRequests(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
 
@@ -1809,7 +1817,8 @@
                         DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
                         if (dsri != null && dsri.getVopsSupportInfo() != null
                                 && !dsri.getVopsSupportInfo().isVopsSupported()
-                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
+                                && !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                        nri.getNetworkRegistrationState())) {
                             evaluation.addDataDisallowedReason(
                                     DataDisallowedReason.VOPS_NOT_SUPPORTED);
                         }
@@ -1989,6 +1998,8 @@
                 }
 
                 // Check if VoPS is required, but the target transport is non-VoPS.
+                // It's recommended for IMS service not requesting MMTEL capability, so that MMTEL
+                // capability is dynamically added when moving between vops and nonvops area.
                 NetworkRequestList networkRequestList =
                         dataNetwork.getAttachedNetworkRequestList();
                 if (networkRequestList.stream().anyMatch(request
@@ -1997,7 +2008,8 @@
                     // Check if the network is non-VoPS.
                     if (dsri != null && dsri.getVopsSupportInfo() != null
                             && !dsri.getVopsSupportInfo().isVopsSupported()
-                            && !mDataConfigManager.shouldKeepNetworkUpInNonVops()) {
+                            && !mDataConfigManager.shouldKeepNetworkUpInNonVops(
+                                    nri.getNetworkRegistrationState())) {
                         dataEvaluation.addDataDisallowedReason(
                                 DataDisallowedReason.VOPS_NOT_SUPPORTED);
                     }
@@ -2541,8 +2553,8 @@
                 + AccessNetworkConstants.transportTypeToString(transport) + " with " + dataProfile
                 + ", and attaching " + networkRequestList.size() + " network requests to it.");
 
-        mDataNetworkList.add(new DataNetwork(mPhone, getLooper(), mDataServiceManagers,
-                dataProfile, networkRequestList, transport, allowedReason,
+        mDataNetworkList.add(new DataNetwork(mPhone, mFeatureFlags, getLooper(),
+                mDataServiceManagers, dataProfile, networkRequestList, transport, allowedReason,
                 new DataNetworkCallback(this::post) {
                     @Override
                     public void onSetupDataFailed(@NonNull DataNetwork dataNetwork,
@@ -3386,7 +3398,8 @@
         }
 
         if (oldNri.getAccessNetworkTechnology() != newNri.getAccessNetworkTechnology()
-                || (!oldNri.isRoaming() && newNri.isRoaming())) {
+                // Some CarrierConfig disallows vops in nonVops area for specified home/roaming.
+                || (oldNri.isRoaming() != newNri.isRoaming())) {
             return true;
         }
 
@@ -3436,7 +3449,8 @@
         if (oldPsNri == null
                 || oldPsNri.getAccessNetworkTechnology() != newPsNri.getAccessNetworkTechnology()
                 || (!oldPsNri.isInService() && newPsNri.isInService())
-                || (oldPsNri.isRoaming() && !newPsNri.isRoaming())) {
+                // Some CarrierConfig allows vops in nonVops area for specified home/roaming.
+                || (oldPsNri.isRoaming() != newPsNri.isRoaming())) {
             return true;
         }
 
diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java
index 23029e3..273dc8b 100644
--- a/src/java/com/android/internal/telephony/data/DataProfileManager.java
+++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java
@@ -48,6 +48,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -113,6 +114,9 @@
     /** SIM state. */
     private @SimState int mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
 
+    /** Feature flags controlling which feature is enabled. */
+    private final @NonNull FeatureFlags mFeatureFlags;
+
     /**
      * Data profile manager callback. This should be only used by {@link DataNetworkController}.
      */
@@ -140,15 +144,18 @@
      * @param dataServiceManager WWAN data service manager.
      * @param looper The looper to be used by the handler. Currently the handler thread is the
      * phone process's main thread.
+     * @param featureFlags Feature flags controlling which feature is enabled.
      * @param callback Data profile manager callback.
      */
     public DataProfileManager(@NonNull Phone phone,
             @NonNull DataNetworkController dataNetworkController,
             @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper,
+            @NonNull FeatureFlags featureFlags,
             @NonNull DataProfileManagerCallback callback) {
         super(looper);
         mPhone = phone;
         mLogTag = "DPM-" + mPhone.getPhoneId();
+        mFeatureFlags = featureFlags;
         mDataNetworkController = dataNetworkController;
         mWwanDataServiceManager = dataServiceManager;
         mDataConfigManager = dataNetworkController.getDataConfigManager();
@@ -626,17 +633,18 @@
      *
      * @param networkRequest The network request.
      * @param networkType The current data network type.
+     * @param isNtn {@code true} if the device is currently attached to non-terrestrial network.
      * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
      * This should be set to true for condition-based retry/setup.
      * @return The data profile. {@code null} if can't find any satisfiable data profile.
      */
     public @Nullable DataProfile getDataProfileForNetworkRequest(
             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
-            boolean ignorePermanentFailure) {
+            boolean isNtn, boolean ignorePermanentFailure) {
         ApnSetting apnSetting = null;
         if (networkRequest.hasAttribute(TelephonyNetworkRequest
                 .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
-            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType,
+            apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, isNtn,
                     ignorePermanentFailure);
         }
 
@@ -696,32 +704,56 @@
      *
      * @param networkRequest The network request.
      * @param networkType The current data network type.
+     * @param isNtn {@code true} if the device is currently attached to non-terrestrial network.
      * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
      * This should be set to true for condition-based retry/setup.
      * @return The APN setting. {@code null} if can't find any satisfiable data profile.
      */
     private @Nullable ApnSetting getApnSettingForNetworkRequest(
             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
-            boolean ignorePermanentFailure) {
+            boolean isNtn, boolean ignorePermanentFailure) {
         if (!networkRequest.hasAttribute(
                 TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
             loge("Network request does not have APN setting attribute.");
             return null;
         }
 
-        // If the preferred data profile can be used, always use it if it can satisfy the network
-        // request with current network type (even though it's been marked as permanent failed.)
-        if (mPreferredDataProfile != null
-                && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
-                && mPreferredDataProfile.getApnSetting() != null
-                && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)) {
-            if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
-                    .getPermanentFailed()) {
-                return mPreferredDataProfile.getApnSetting();
+        if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            // If the preferred data profile can be used, always use it if it can satisfy the
+            // network request with current network type (even though it's been marked as permanent
+            // failed.)
+            if (mPreferredDataProfile != null
+                    && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
+                    && mPreferredDataProfile.getApnSetting() != null
+                    && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)
+                    && ((isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
+                            ApnSetting.INFRASTRUCTURE_SATELLITE))
+                    || (!isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
+                            ApnSetting.INFRASTRUCTURE_CELLULAR)))) {
+                if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
+                        .getPermanentFailed()) {
+                    return mPreferredDataProfile.getApnSetting();
+                }
+                log("The preferred data profile is permanently failed. Only condition based "
+                        + "retry can happen.");
+                return null;
             }
-            log("The preferred data profile is permanently failed. Only condition based retry "
-                    + "can happen.");
-            return null;
+        } else {
+            // If the preferred data profile can be used, always use it if it can satisfy the
+            // network request with current network type (even though it's been marked as permanent
+            // failed.)
+            if (mPreferredDataProfile != null
+                    && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
+                    && mPreferredDataProfile.getApnSetting() != null
+                    && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)) {
+                if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
+                        .getPermanentFailed()) {
+                    return mPreferredDataProfile.getApnSetting();
+                }
+                log("The preferred data profile is permanently failed. Only condition based "
+                        + "retry can happen.");
+                return null;
+            }
         }
 
         // Filter out the data profile that can't satisfy the request.
@@ -743,8 +775,22 @@
 
         // Check if the remaining data profiles can used in current data network type.
         dataProfiles = dataProfiles.stream()
-                .filter(dp -> dp.getApnSetting() != null
-                        && dp.getApnSetting().canSupportNetworkType(networkType))
+                .filter((dp) -> {
+                    if (dp.getApnSetting() == null) return false;
+                    if (!dp.getApnSetting().canSupportNetworkType(networkType)) return false;
+                    if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
+                        if (isNtn && !dp.getApnSetting().isForInfrastructure(
+                                ApnSetting.INFRASTRUCTURE_SATELLITE)) {
+                            return false;
+                        }
+                        if (!isNtn && !dp.getApnSetting().isForInfrastructure(
+                                ApnSetting.INFRASTRUCTURE_CELLULAR)) {
+                            return false;
+                        }
+                    }
+
+                    return true;
+                })
                 .collect(Collectors.toList());
         if (dataProfiles.size() == 0) {
             log("Can't find any data profile for network type "
@@ -818,7 +864,8 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                         .build(), mPhone);
-        return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null;
+        return getDataProfileForNetworkRequest(networkRequest, networkType,
+                mPhone.getServiceState().isUsingNonTerrestrialNetwork(), true) != null;
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java
index 4465fbb..754400e 100644
--- a/src/java/com/android/internal/telephony/data/DataRetryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java
@@ -51,6 +51,7 @@
 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList;
 import com.android.internal.telephony.data.DataProfileManager.DataProfileManagerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.telephony.Rlog;
 
 import java.io.FileDescriptor;
@@ -141,6 +142,9 @@
     /** The phone instance. */
     private final @NonNull Phone mPhone;
 
+    /** Featureflags. */
+    private final @NonNull FeatureFlags mFlags;
+
     /** The RIL instance. */
     private final @NonNull CommandsInterface mRil;
 
@@ -952,10 +956,12 @@
     public DataRetryManager(@NonNull Phone phone,
             @NonNull DataNetworkController dataNetworkController,
             @NonNull SparseArray<DataServiceManager> dataServiceManagers,
-            @NonNull Looper looper, @NonNull DataRetryManagerCallback dataRetryManagerCallback) {
+            @NonNull Looper looper, @NonNull FeatureFlags flags,
+            @NonNull DataRetryManagerCallback dataRetryManagerCallback) {
         super(looper);
         mPhone = phone;
         mRil = phone.mCi;
+        mFlags = flags;
         mLogTag = "DRM-" + mPhone.getPhoneId();
         mDataRetryManagerCallbacks.add(dataRetryManagerCallback);
 
@@ -1480,9 +1486,12 @@
         DataThrottlingEntry entry = new DataThrottlingEntry(dataProfile, networkRequestList,
                 dataNetwork, transport, retryType, expirationTime);
         // Remove previous entry that contains the same data profile. Therefore it should always
-        // contain at maximum all the distinct data profiles of the current subscription.
+        // contain at maximu all the distinct data profiles of the current subscription times each
+        // transport.
         mDataThrottlingEntries.removeIf(
-                throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile));
+                throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile)
+                        && (!mFlags.unthrottleCheckTransport()
+                        || throttlingEntry.transport == transport));
 
         if (mDataThrottlingEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) {
             // If we don't see the anomaly report after U release, we should remove this check for
@@ -1544,7 +1553,8 @@
             // in DataProfileInfo.aidl), so we need to get the equivalent data profile from data
             // profile manager.
             Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream();
-            stream = stream.filter(entry -> entry.expirationTimeMillis > now);
+            stream = stream.filter(entry -> entry.expirationTimeMillis > now
+                    && (!mFlags.unthrottleCheckTransport() || entry.transport == transport));
             if (dataProfile.getApnSetting() != null) {
                 stream = stream
                         .filter(entry -> entry.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 fc0c4f1..259b482 100644
--- a/src/java/com/android/internal/telephony/data/DataUtils.java
+++ b/src/java/com/android/internal/telephony/data/DataUtils.java
@@ -90,6 +90,8 @@
                 return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH;
             case "PRIORITIZE_LATENCY":
                 return NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY;
+            case "RCS":
+                return NetworkCapabilities.NET_CAPABILITY_RCS;
             default:
                 return -1;
         }
@@ -254,6 +256,8 @@
                 return ApnSetting.TYPE_VSIM;
             case NetworkCapabilities.NET_CAPABILITY_BIP:
                 return ApnSetting.TYPE_BIP;
+            case NetworkCapabilities.NET_CAPABILITY_RCS:
+                return ApnSetting.TYPE_RCS;
             default:
                 return ApnSetting.TYPE_NONE;
         }
@@ -295,6 +299,8 @@
                 return NetworkCapabilities.NET_CAPABILITY_VSIM;
             case ApnSetting.TYPE_ENTERPRISE:
                 return NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
+            case ApnSetting.TYPE_RCS:
+                return NetworkCapabilities.NET_CAPABILITY_RCS;
             default:
                 return -1;
         }
diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
index ab759e9..36e6587 100644
--- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java
@@ -1546,7 +1546,7 @@
         // If validation feature is not supported, set it directly. Otherwise,
         // start validation on the subscription first.
         if (!mValidator.isValidationFeatureSupported()) {
-            setAutoSelectedDataSubIdInternal(subIdToValidate);
+            setAutoSelectedDataSubIdInternal(subId);
             sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS);
             return;
         }
diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
index b334b89..2668302 100644
--- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
+++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java
@@ -130,7 +130,9 @@
             new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY,
                     CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID),
             new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH,
-                    CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID)
+                    CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID),
+            new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_RCS,
+                CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN)
     );
 
     /** The phone instance. */
diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
index 9a75b43..5ef8b8a 100644
--- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
+++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java
@@ -21,7 +21,6 @@
 import android.os.AsyncResult;
 import android.os.CancellationSignal;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
@@ -44,8 +43,6 @@
 import java.io.PrintWriter;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
 import java.util.function.Consumer;
 
 
@@ -74,42 +71,63 @@
     private final class TransportSelectorCallbackWrapper implements TransportSelectorCallback {
         @Override
         public void onCreated(@NonNull DomainSelector selector) {
-            mDomainSelector = selector;
-            DomainSelectionConnection.this.onCreated();
+            synchronized (mLock) {
+                mDomainSelector = selector;
+                if (mDisposed) {
+                    mDomainSelector.cancelSelection();
+                    return;
+                }
+                DomainSelectionConnection.this.onCreated();
+            }
         }
 
         @Override
         public void onWlanSelected(boolean useEmergencyPdn) {
-            DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn);
+            synchronized (mLock) {
+                if (mDisposed) return;
+                DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn);
+            }
         }
 
         @Override
         public @NonNull WwanSelectorCallback onWwanSelected() {
-            if (mWwanSelectorCallback == null) {
-                mWwanSelectorCallback = new WwanSelectorCallbackWrapper();
+            synchronized (mLock) {
+                if (mWwanSelectorCallback == null) {
+                    mWwanSelectorCallback = new WwanSelectorCallbackWrapper();
+                }
+                if (mDisposed) {
+                    return mWwanSelectorCallback;
+                }
+                DomainSelectionConnection.this.onWwanSelected();
+                return mWwanSelectorCallback;
             }
-            DomainSelectionConnection.this.onWwanSelected();
-            return mWwanSelectorCallback;
         }
 
         @Override
         public void onWwanSelected(final Consumer<WwanSelectorCallback> consumer) {
-            if (mWwanSelectorCallback == null) {
-                mWwanSelectorCallback = new WwanSelectorCallbackWrapper();
+            synchronized (mLock) {
+                if (mDisposed) return;
+                if (mWwanSelectorCallback == null) {
+                    mWwanSelectorCallback = new WwanSelectorCallbackWrapper();
+                }
+                initHandler();
+                mHandler.post(() -> {
+                    synchronized (mLock) {
+                        if (mDisposed) return;
+                        DomainSelectionConnection.this.onWwanSelected();
+                        consumer.accept(mWwanSelectorCallback);
+                    }
+                });
             }
-            if (mWwanSelectedExecutor == null) {
-                mWwanSelectedExecutor = Executors.newSingleThreadExecutor();
-            }
-            mWwanSelectedExecutor.execute(() -> {
-                DomainSelectionConnection.this.onWwanSelected();
-                consumer.accept(mWwanSelectorCallback);
-            });
         }
 
         @Override
         public void onSelectionTerminated(int cause) {
-            DomainSelectionConnection.this.onSelectionTerminated(cause);
-            dispose();
+            synchronized (mLock) {
+                if (mDisposed) return;
+                DomainSelectionConnection.this.onSelectionTerminated(cause);
+                dispose();
+            }
         }
     }
 
@@ -120,22 +138,38 @@
         public void onRequestEmergencyNetworkScan(@NonNull List<Integer> preferredNetworks,
                 @EmergencyScanType int scanType, @NonNull CancellationSignal signal,
                 @NonNull Consumer<EmergencyRegResult> consumer) {
-            if (signal != null) signal.setOnCancelListener(this);
-            mResultCallback = consumer;
-            initHandler();
-            DomainSelectionConnection.this.onRequestEmergencyNetworkScan(
-                    preferredNetworks.stream().mapToInt(Integer::intValue).toArray(), scanType);
+            synchronized (mLock) {
+                if (mDisposed) return;
+                if (signal != null) signal.setOnCancelListener(this);
+                mResultCallback = consumer;
+                initHandler();
+                mHandler.post(() -> {
+                    synchronized (mLock) {
+                        DomainSelectionConnection.this.onRequestEmergencyNetworkScan(
+                                preferredNetworks.stream().mapToInt(Integer::intValue).toArray(),
+                                scanType);
+                    }
+                });
+            }
         }
 
         @Override
         public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain,
                 boolean useEmergencyPdn) {
-            DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn);
+            synchronized (mLock) {
+                if (mDisposed) return;
+                DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn);
+            }
         }
 
         @Override
         public void onCancel() {
-            DomainSelectionConnection.this.onCancel();
+            synchronized (mLock) {
+                if (mDisposed || mHandler == null) return;
+                mHandler.post(() -> {
+                    DomainSelectionConnection.this.onCancel();
+                });
+            }
         }
     }
 
@@ -156,7 +190,7 @@
                     if (DBG) logd("EVENT_EMERGENCY_NETWORK_SCAN_RESULT result=" + regResult);
                     CompletableFuture.runAsync(
                             () -> mResultCallback.accept(regResult),
-                            mController.getDomainSelectionServiceExecutor()).join();
+                            mController.getDomainSelectionServiceExecutor());
                     break;
                 case EVENT_QUALIFIED_NETWORKS_CHANGED:
                     onQualifiedNetworksChanged();
@@ -170,6 +204,8 @@
 
     protected String mTag = "DomainSelectionConnection";
 
+    private boolean mDisposed = false;
+    private final Object mLock = new Object();
     private final LocalLog mLocalLog = new LocalLog(30);
     private final @NonNull TransportSelectorCallback mTransportSelectorCallback;
 
@@ -196,15 +232,13 @@
     /** The attributes required to determine the domain. */
     private @Nullable DomainSelectionService.SelectionAttributes mSelectionAttributes;
 
-    private @Nullable Looper mLooper;
+    private final @NonNull Looper mLooper;
     protected @Nullable DomainSelectionConnectionHandler mHandler;
     private boolean mRegisteredRegistrant;
     private boolean mIsWaitingForScanResult;
 
     private @NonNull AndroidFuture<Integer> mOnComplete;
 
-    private @Nullable Executor mWwanSelectedExecutor;
-
     /**
      * Creates an instance.
      *
@@ -220,6 +254,7 @@
         mPhone = phone;
         mSelectorType = selectorType;
         mIsEmergency = isEmergency;
+        mLooper = Looper.getMainLooper();
 
         mTransportSelectorCallback = new TransportSelectorCallbackWrapper();
         mOnComplete = new AndroidFuture<>();
@@ -323,6 +358,8 @@
     public void onRequestEmergencyNetworkScan(
             @NonNull @RadioAccessNetworkType int[] preferredNetworks,
             @EmergencyScanType int scanType) {
+        if (mHandler == null) return;
+
         // Can be overridden if required
         if (!mRegisteredRegistrant) {
             mPhone.registerForEmergencyNetworkScan(mHandler,
@@ -376,9 +413,12 @@
      * to clean up all ongoing operations with the framework.
      */
     public void cancelSelection() {
-        if (mDomainSelector == null) return;
-        mDomainSelector.cancelSelection();
-        dispose();
+        synchronized (mLock) {
+            if (mDomainSelector != null) {
+                mDomainSelector.cancelSelection();
+            }
+            dispose();
+        }
     }
 
     /**
@@ -400,9 +440,12 @@
      * Finishes the selection procedure and cleans everything up.
      */
     public void finishSelection() {
-        if (mDomainSelector == null) return;
-        mDomainSelector.finishSelection();
-        dispose();
+        synchronized (mLock) {
+            if (mDomainSelector != null) {
+                mDomainSelector.finishSelection();
+            }
+            dispose();
+        }
     }
 
     /** Indicates that the service connection has been removed. */
@@ -412,23 +455,18 @@
     }
 
     private void dispose() {
+        mDisposed = true;
         if (mRegisteredRegistrant) {
             mPhone.unregisterForEmergencyNetworkScan(mHandler);
             mRegisteredRegistrant = false;
         }
         onCancel(true);
         mController.removeConnection(this);
-        if (mLooper != null) mLooper.quitSafely();
-        mLooper = null;
+        if (mHandler != null) mHandler.removeCallbacksAndMessages(null);
         mHandler = null;
     }
 
     protected void initHandler() {
-        if (mLooper == null) {
-            HandlerThread handlerThread = new HandlerThread(mTag);
-            handlerThread.start();
-            mLooper = handlerThread.getLooper();
-        }
         if (mHandler == null) mHandler = new DomainSelectionConnectionHandler(mLooper);
     }
 
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
index 9b44001..e2418c5 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -935,6 +935,23 @@
     }
 
     /**
+     * Get a list of the {@link EmergencyNumber}s that have the corresponding emergency number.
+     * Note: {@link #getEmergencyNumber(String)} assumes there is ONLY one record for a phone number
+     * when in reality there CAN be multiple instances if the same number is reported by the radio
+     * for a specific mcc and the emergency number database specifies the number without an mcc
+     * specified.
+     *
+     * @param emergencyNumber the emergency number to find.
+     * @return the list of emergency numbers matching.
+     */
+    public List<EmergencyNumber> getEmergencyNumbers(String emergencyNumber) {
+        final String toFind = PhoneNumberUtils.stripSeparators(emergencyNumber);
+        return getEmergencyNumberList().stream()
+                .filter(num -> num.getNumber().equals(toFind))
+                .toList();
+    }
+
+    /**
      * Get the emergency service categories for the corresponding emergency number. The only
      * trusted sources for the categories are the
      * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING} and
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
index a45e956..23473d2 100644
--- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java
@@ -47,7 +47,6 @@
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.telephony.emergency.EmergencyNumber;
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -981,9 +980,10 @@
      * This should be called once an emergency SMS is sent.
      *
      * @param smsId the SMS id on which to end the emergency SMS.
-     * @param emergencyNumber the emergency number which was used for the emergency SMS.
+     * @param success the flag specifying whether an emergency SMS is successfully sent or not.
+     *                {@code true} if SMS is successfully sent, {@code false} otherwise.
      */
-    public void endSms(@NonNull String smsId, EmergencyNumber emergencyNumber) {
+    public void endSms(@NonNull String smsId, boolean success) {
         mOngoingEmergencySmsIds.remove(smsId);
 
         // If the outgoing emergency SMSs are empty, we can try to exit the emergency mode.
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 5b1f36d..dae808a 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -171,6 +171,7 @@
             if(mPhone.getServiceState().getRilDataRadioTechnology()
                     != ServiceState.RIL_RADIO_TECHNOLOGY_NR) {
                 tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
+                notifySmsSentFailedToEmergencyStateTracker(tracker);
                 return;
             }
         }
diff --git a/src/java/com/android/internal/telephony/metrics/ImsStats.java b/src/java/com/android/internal/telephony/metrics/ImsStats.java
index 427595f..2420602 100644
--- a/src/java/com/android/internal/telephony/metrics/ImsStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ImsStats.java
@@ -197,7 +197,7 @@
     @ImsRegistrationState private int mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
 
     private long mLastTimestamp;
-    @Nullable private ImsRegistrationStats mLastRegistrationStats;
+    private ImsRegistrationStats mLastRegistrationStats;
     @TransportType int mLastTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
     // Available features are those reported by ImsService to be available for use.
     private MmTelCapabilities mLastAvailableFeatures = new MmTelCapabilities();
@@ -210,6 +210,10 @@
     public ImsStats(ImsPhone phone) {
         mPhone = phone;
         mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage();
+
+        mLastRegistrationStats = getDefaultImsRegistrationStats();
+        updateImsRegistrationStats();
+        mLastTimestamp = getTimeMillis();
     }
 
     /**
@@ -221,40 +225,46 @@
     public synchronized void conclude() {
         long now = getTimeMillis();
 
-        // Currently not tracking time spent on registering.
-        if (mLastRegistrationState == REGISTRATION_STATE_REGISTERED) {
-            ImsRegistrationStats stats = copyOf(mLastRegistrationStats);
-            long duration = now - mLastTimestamp;
+        long duration = now - mLastTimestamp;
+        if (duration < MIN_REGISTRATION_DURATION_MILLIS) {
+            logw("conclude: discarding transient stats, duration=%d", duration);
+        } else {
+            ImsRegistrationStats stats = copyOfDimensionsOnly(mLastRegistrationStats);
 
-            if (duration < MIN_REGISTRATION_DURATION_MILLIS) {
-                logw("conclude: discarding transient stats, duration=%d", duration);
-            } else {
-                stats.registeredMillis = duration;
+            switch (mLastRegistrationState) {
+                case REGISTRATION_STATE_REGISTERED:
+                    stats.registeredMillis = duration;
 
-                stats.voiceAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
-                stats.videoAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
-                stats.utAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
-                stats.smsAvailableMillis =
-                        mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
+                    stats.voiceAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
+                    stats.videoAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
+                    stats.utAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
+                    stats.smsAvailableMillis =
+                            mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
 
-                MmTelCapabilities lastCapableFeatures =
-                        stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN
-                                ? mLastWlanCapableFeatures
-                                : mLastWwanCapableFeatures;
-                stats.voiceCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
-                stats.videoCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
-                stats.utCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
-                stats.smsCapableMillis =
-                        lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
-
-                mStorage.addImsRegistrationStats(stats);
+                    MmTelCapabilities lastCapableFeatures =
+                            stats.rat == TelephonyManager.NETWORK_TYPE_IWLAN
+                                    ? mLastWlanCapableFeatures
+                                    : mLastWwanCapableFeatures;
+                    stats.voiceCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_VOICE) ? duration : 0;
+                    stats.videoCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_VIDEO) ? duration : 0;
+                    stats.utCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_UT) ? duration : 0;
+                    stats.smsCapableMillis =
+                            lastCapableFeatures.isCapable(CAPABILITY_TYPE_SMS) ? duration : 0;
+                    break;
+                case REGISTRATION_STATE_REGISTERING:
+                    stats.registeringMillis = duration;
+                    break;
+                case REGISTRATION_STATE_NOT_REGISTERED:
+                    stats.unregisteredMillis = duration;
+                    break;
             }
+            mStorage.addImsRegistrationStats(stats);
         }
 
         mLastTimestamp = now;
@@ -271,7 +281,7 @@
                 (newRat == TelephonyManager.NETWORK_TYPE_IWLAN)
                         ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN
                         : AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
-        if (mLastRegistrationStats != null && mLastRegistrationStats.rat != newRat) {
+        if (mLastRegistrationStats.rat != newRat) {
             mLastRegistrationStats.rat = newRat;
             ratChanged = true;
         }
@@ -308,7 +318,7 @@
         conclude();
 
         mLastTransportType = imsRadioTech;
-        mLastRegistrationStats = getDefaultImsRegistrationStats();
+        updateImsRegistrationStats();
         mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech);
         mLastRegistrationState = REGISTRATION_STATE_REGISTERING;
     }
@@ -318,9 +328,9 @@
         conclude();
 
         mLastTransportType = imsRadioTech;
-        // NOTE: mLastRegistrationStats can be null (no registering phase).
-        if (mLastRegistrationStats == null) {
-            mLastRegistrationStats = getDefaultImsRegistrationStats();
+        // NOTE: status can be unregistered (no registering phase)
+        if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED) {
+            updateImsRegistrationStats();
         }
         mLastRegistrationStats.rat = convertTransportTypeToNetworkType(imsRadioTech);
         mLastRegistrationState = REGISTRATION_STATE_REGISTERED;
@@ -331,16 +341,14 @@
         conclude();
 
         // Generate end reason atom.
-        // NOTE: mLastRegistrationStats can be null (no registering phase).
         ImsRegistrationTermination termination = new ImsRegistrationTermination();
-        if (mLastRegistrationStats != null) {
+        if (mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
             termination.carrierId = mLastRegistrationStats.carrierId;
-            termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat);
         } else {
+            // if the registration state is from unregistered to unregistered.
             termination.carrierId = mPhone.getDefaultPhone().getCarrierId();
-            // We cannot tell whether the registration was intended for WWAN or WLAN
-            termination.ratAtEnd = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
+        termination.ratAtEnd = getRatAtEnd(mLastRegistrationStats.rat);
         termination.isMultiSim = SimSlotState.isMultiSim();
         termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED);
         termination.reasonCode = reasonInfo.getCode();
@@ -351,14 +359,14 @@
 
         // Reset state to unregistered.
         mLastRegistrationState = REGISTRATION_STATE_NOT_REGISTERED;
-        mLastRegistrationStats = null;
+        mLastRegistrationStats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         mLastAvailableFeatures = new MmTelCapabilities();
     }
 
     /** Updates the RAT when service state changes. */
     public synchronized void onServiceStateChanged(ServiceState state) {
         if (mLastTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
-                && mLastRegistrationStats != null) {
+                && mLastRegistrationState != REGISTRATION_STATE_NOT_REGISTERED) {
             mLastRegistrationStats.rat =
                     ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS);
         }
@@ -370,7 +378,7 @@
      */
     @NetworkType
     public synchronized int getImsVoiceRadioTech() {
-        if (mLastRegistrationStats == null
+        if (mLastRegistrationState == REGISTRATION_STATE_NOT_REGISTERED
                 || !mLastAvailableFeatures.isCapable(CAPABILITY_TYPE_VOICE)) {
             return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
@@ -404,11 +412,16 @@
     private ImsRegistrationStats getDefaultImsRegistrationStats() {
         Phone phone = mPhone.getDefaultPhone();
         ImsRegistrationStats stats = new ImsRegistrationStats();
-        stats.carrierId = phone.getCarrierId();
-        stats.simSlotIndex = phone.getPhoneId();
+        stats.rat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         return stats;
     }
 
+    private void updateImsRegistrationStats() {
+        Phone phone = mPhone.getDefaultPhone();
+        mLastRegistrationStats.carrierId = phone.getCarrierId();
+        mLastRegistrationStats.simSlotIndex = phone.getPhoneId();
+    }
+
     @Nullable
     private MmTelCapabilities getLastCapableFeaturesForTech(@ImsRegistrationTech int radioTech) {
         switch (radioTech) {
@@ -438,21 +451,12 @@
         }
     }
 
-    private static ImsRegistrationStats copyOf(ImsRegistrationStats source) {
+    private static ImsRegistrationStats copyOfDimensionsOnly(ImsRegistrationStats source) {
         ImsRegistrationStats dest = new ImsRegistrationStats();
 
         dest.carrierId = source.carrierId;
         dest.simSlotIndex = source.simSlotIndex;
         dest.rat = source.rat;
-        dest.registeredMillis = source.registeredMillis;
-        dest.voiceCapableMillis = source.voiceCapableMillis;
-        dest.voiceAvailableMillis = source.voiceAvailableMillis;
-        dest.smsCapableMillis = source.smsCapableMillis;
-        dest.smsAvailableMillis = source.smsAvailableMillis;
-        dest.videoCapableMillis = source.videoCapableMillis;
-        dest.videoAvailableMillis = source.videoAvailableMillis;
-        dest.utCapableMillis = source.utCapableMillis;
-        dest.utAvailableMillis = source.utAvailableMillis;
 
         return dest;
     }
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 1a53ee6..bd7ce2a 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -1077,7 +1077,9 @@
                 roundAndConvertMillisToSeconds(stats.videoCapableMillis),
                 roundAndConvertMillisToSeconds(stats.videoAvailableMillis),
                 roundAndConvertMillisToSeconds(stats.utCapableMillis),
-                roundAndConvertMillisToSeconds(stats.utAvailableMillis));
+                roundAndConvertMillisToSeconds(stats.utAvailableMillis),
+                roundAndConvertMillisToSeconds(stats.registeringMillis),
+                roundAndConvertMillisToSeconds(stats.unregisteredMillis));
     }
 
     private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index d495ca2..1da0c46 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -407,6 +407,8 @@
             existingStats.videoAvailableMillis += stats.videoAvailableMillis;
             existingStats.utCapableMillis += stats.utCapableMillis;
             existingStats.utAvailableMillis += stats.utAvailableMillis;
+            existingStats.registeringMillis += stats.registeringMillis;
+            existingStats.unregisteredMillis += stats.unregisteredMillis;
             existingStats.lastUsedMillis = getWallTimeMillis();
         } else {
             stats.lastUsedMillis = getWallTimeMillis();
@@ -2279,6 +2281,10 @@
                     normalizeDurationTo24H(stats[i].utCapableMillis, intervalMillis);
             stats[i].utAvailableMillis =
                     normalizeDurationTo24H(stats[i].utAvailableMillis, intervalMillis);
+            stats[i].registeringMillis =
+                    normalizeDurationTo24H(stats[i].registeringMillis, intervalMillis);
+            stats[i].unregisteredMillis =
+                    normalizeDurationTo24H(stats[i].unregisteredMillis, intervalMillis);
         }
         return stats;
     }
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index 591114b..6ccc3e6 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -190,50 +190,11 @@
                         (SendSatelliteDatagramArgument) request.argument;
                 onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
 
-                if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                    SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram,
-                            argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
-                            argument.needFullScreenPointingUI, onCompleted);
-                    break;
-                }
-
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.sendSatelliteDatagram(onCompleted, argument.datagram,
-                            argument.needFullScreenPointingUI);
-                } else {
-                    loge("sendSatelliteDatagram: No phone object");
-                    synchronized (mLock) {
-                        // Remove current datagram from pending map
-                        if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) {
-                            mPendingEmergencyDatagramsMap.remove(argument.datagramId);
-                        } else {
-                            mPendingNonEmergencyDatagramsMap.remove(argument.datagramId);
-                        }
-
-                        // Update send status
-                        mDatagramController.updateSendStatus(argument.subId,
-                                SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED,
-                                getPendingDatagramCount(),
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                        mDatagramController.updateSendStatus(argument.subId,
-                                SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                                0, SatelliteManager.SATELLITE_RESULT_SUCCESS);
-
-                        // report phone == null case
-                        reportSendDatagramCompleted(argument,
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                        argument.callback.accept(
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-
-                        // Abort sending all the pending datagrams
-                        abortSendingPendingDatagrams(argument.subId,
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    }
-                }
+                SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram,
+                        argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+                        argument.needFullScreenPointingUI, onCompleted);
                 break;
             }
-
             case EVENT_SEND_SATELLITE_DATAGRAM_DONE: {
                 ar = (AsyncResult) msg.obj;
                 request = (DatagramDispatcherHandlerRequest) ar.userObj;
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index 35c78eb..fd04779 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -424,35 +424,7 @@
                 request = (DatagramReceiverHandlerRequest) msg.obj;
                 onCompleted =
                         obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request);
-
-                if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                    SatelliteModemInterface.getInstance()
-                            .pollPendingSatelliteDatagrams(onCompleted);
-                    break;
-                }
-
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.pollPendingSatelliteDatagrams(onCompleted);
-                } else {
-                    loge("pollPendingSatelliteDatagrams: No phone object");
-                    mDatagramController.updateReceiveStatus(request.subId,
-                            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED,
-                            mDatagramController.getReceivePendingCount(),
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-
-                    mDatagramController.updateReceiveStatus(request.subId,
-                            SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE,
-                            mDatagramController.getReceivePendingCount(),
-                            SatelliteManager.SATELLITE_RESULT_SUCCESS);
-
-                    reportMetrics(null, SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    mControllerMetricsStats.reportIncomingDatagramCount(
-                                    SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    // Send response for current request
-                    ((Consumer<Integer>) request.argument)
-                            .accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                }
+                SatelliteModemInterface.getInstance().pollPendingSatelliteDatagrams(onCompleted);
                 break;
             }
 
@@ -534,15 +506,9 @@
         if (satelliteDatagramListenerHandler == null) {
             satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler(
                     mLooper, validSubId);
-            if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived(
-                        satelliteDatagramListenerHandler,
-                        SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null);
-            } else {
-                Phone phone = SatelliteServiceUtils.getPhone();
-                phone.registerForSatelliteDatagramsReceived(satelliteDatagramListenerHandler,
-                        SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null);
-            }
+            SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived(
+                    satelliteDatagramListenerHandler,
+                    SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null);
         }
 
         satelliteDatagramListenerHandler.addListener(callback);
@@ -568,15 +534,8 @@
 
             if (!handler.hasListeners()) {
                 mSatelliteDatagramListenerHandlers.remove(validSubId);
-                if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                    SatelliteModemInterface.getInstance()
-                            .unregisterForSatelliteDatagramsReceived(handler);
-                } else {
-                    Phone phone = SatelliteServiceUtils.getPhone();
-                    if (phone != null) {
-                        phone.unregisterForSatelliteDatagramsReceived(handler);
-                    }
-                }
+                SatelliteModemInterface.getInstance().unregisterForSatelliteDatagramsReceived(
+                        handler);
             }
         }
     }
diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
index 70d432e..9a6bd69 100644
--- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java
+++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java
@@ -42,7 +42,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.Phone;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -276,31 +275,24 @@
      * Register to start receiving updates for satellite position and datagram transfer state
      * @param subId The subId of the subscription to register for receiving the updates.
      * @param callback The callback to notify of satellite transmission updates.
-     * @param phone The Phone object to unregister for receiving the updates.
      */
     public void registerForSatelliteTransmissionUpdates(int subId,
-            ISatelliteTransmissionUpdateCallback callback, Phone phone) {
+            ISatelliteTransmissionUpdateCallback callback) {
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
         if (handler != null) {
             handler.addListener(callback);
-            return;
         } else {
             handler = new SatelliteTransmissionUpdateHandler(Looper.getMainLooper());
             handler.addListener(callback);
             mSatelliteTransmissionUpdateHandlers.put(subId, handler);
-            if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged(
-                        handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED,
-                        null);
-                SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged(
-                        handler,
-                        SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED,
-                        null);
-            } else {
-                phone.registerForSatellitePositionInfoChanged(handler,
-                        SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null);
-            }
+            SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged(
+                    handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED,
+                    null);
+            SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged(
+                    handler,
+                    SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED,
+                    null);
         }
     }
 
@@ -310,11 +302,10 @@
      * @param subId The subId of the subscription to unregister for receiving the updates.
      * @param result The callback to get the error code in case of failure
      * @param callback The callback that was passed to {@link
-     * #registerForSatelliteTransmissionUpdates(int, ISatelliteTransmissionUpdateCallback, Phone)}.
-     * @param phone The Phone object to unregister for receiving the updates
+     * #registerForSatelliteTransmissionUpdates(int, ISatelliteTransmissionUpdateCallback)}.
      */
     public void unregisterForSatelliteTransmissionUpdates(int subId, Consumer<Integer> result,
-            ISatelliteTransmissionUpdateCallback callback, Phone phone) {
+            ISatelliteTransmissionUpdateCallback callback) {
         SatelliteTransmissionUpdateHandler handler =
                 mSatelliteTransmissionUpdateHandlers.get(subId);
         if (handler != null) {
@@ -323,20 +314,11 @@
                 result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
                 return;
             }
-
             mSatelliteTransmissionUpdateHandlers.remove(subId);
-            if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-                SatelliteModemInterface.getInstance().unregisterForSatellitePositionInfoChanged(
-                        handler);
-                SatelliteModemInterface.getInstance().unregisterForDatagramTransferStateChanged(
-                        handler);
-            } else {
-                if (phone == null) {
-                    result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    return;
-                }
-                phone.unregisterForSatellitePositionInfoChanged(handler);
-            }
+
+            SatelliteModemInterface satelliteModemInterface = SatelliteModemInterface.getInstance();
+            satelliteModemInterface.unregisterForSatellitePositionInfoChanged(handler);
+            satelliteModemInterface.unregisterForDatagramTransferStateChanged(handler);
         }
     }
 
@@ -348,7 +330,7 @@
      * {@link android.telephony.satellite.SatelliteTransmissionUpdateCallback
      * #onSatellitePositionChanged(pointingInfo)}.
      */
-    public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) {
+    public void startSatelliteTransmissionUpdates(@NonNull Message message) {
         if (mStartedSatelliteTransmissionUpdates) {
             logd("startSatelliteTransmissionUpdates: already started");
             AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException(
@@ -356,20 +338,8 @@
             message.sendToTarget();
             return;
         }
-        if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-            SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message);
-            mStartedSatelliteTransmissionUpdates = true;
-            return;
-        }
-        if (phone != null) {
-            phone.startSatellitePositionUpdates(message);
-            mStartedSatelliteTransmissionUpdates = true;
-        } else {
-            loge("startSatelliteTransmissionUpdates: No phone object");
-            AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException(
-                    SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE));
-            message.sendToTarget();
-        }
+        SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message);
+        mStartedSatelliteTransmissionUpdates = true;
     }
 
     /**
@@ -377,20 +347,9 @@
      * Reset the flag mStartedSatelliteTransmissionUpdates
      * This can be called by the pointing UI when the user stops pointing to the satellite.
      */
-    public void stopSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) {
+    public void stopSatelliteTransmissionUpdates(@NonNull Message message) {
         setStartedSatelliteTransmissionUpdates(false);
-        if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) {
-            SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message);
-            return;
-        }
-        if (phone != null) {
-            phone.stopSatellitePositionUpdates(message);
-        } else {
-            loge("startSatelliteTransmissionUpdates: No phone object");
-            AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException(
-                    SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE));
-            message.sendToTarget();
-        }
+        SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message);
     }
 
     /**
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index cb68fcb..896063f 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -18,7 +18,10 @@
 
 import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
 import static android.telephony.SubscriptionManager.isValidSubscriptionId;
+import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
+import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import android.annotation.ArrayRes;
 import android.annotation.NonNull;
@@ -54,10 +57,12 @@
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.satellite.INtnSignalStrengthCallback;
 import android.telephony.satellite.ISatelliteDatagramCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
 import android.telephony.satellite.ISatelliteStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
+import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteManager;
@@ -69,6 +74,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.DeviceStateMonitor;
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.flags.FeatureFlags;
@@ -137,6 +143,11 @@
     private static final int EVENT_SET_SATELLITE_PLMN_INFO_DONE = 29;
     private static final int CMD_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE = 30;
     private static final int EVENT_EVALUATE_SATELLITE_ATTACH_RESTRICTION_CHANGE_DONE = 31;
+    private static final int CMD_REQUEST_NTN_SIGNAL_STRENGTH = 32;
+    private static final int EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE = 33;
+    private static final int EVENT_NTN_SIGNAL_STRENGTH_CHANGED = 34;
+    private static final int CMD_START_SENDING_NTN_SIGNAL_STRENGTH = 35;
+    private static final int EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING = 36;
 
     @NonNull private static SatelliteController sInstance;
     @NonNull private final Context mContext;
@@ -149,6 +160,7 @@
     @NonNull private final SubscriptionManagerService mSubscriptionManagerService;
     private final CommandsInterface mCi;
     private ContentResolver mContentResolver = null;
+    private final DeviceStateMonitor mDSM;
 
     private final Object mRadioStateLock = new Object();
 
@@ -182,16 +194,11 @@
 
     private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService =
             new AtomicBoolean(false);
-    private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone =
-            new AtomicBoolean(false);
     private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService =
             new AtomicBoolean(false);
-    private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone =
-            new AtomicBoolean(false);
     private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService =
             new AtomicBoolean(false);
-    private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone =
-            new AtomicBoolean(false);
+    private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false);
     /**
      * Map key: subId, value: callback to get error code of the provision request.
      */
@@ -203,6 +210,12 @@
      */
     private final ConcurrentHashMap<IBinder, ISatelliteProvisionStateCallback>
             mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>();
+    /**
+     * Map key: binder of the callback, value: callback to receive non-terrestrial signal strength
+     * state changed events.
+     */
+    private final ConcurrentHashMap<IBinder, INtnSignalStrengthCallback>
+            mNtnSignalStrengthChangedListeners = new ConcurrentHashMap<>();
     private final Object mIsSatelliteSupportedLock = new Object();
     @GuardedBy("mIsSatelliteSupportedLock")
     private Boolean mIsSatelliteSupported = null;
@@ -220,6 +233,10 @@
     private final Object mNeedsSatellitePointingLock = new Object();
     @GuardedBy("mNeedsSatellitePointingLock")
     private boolean mNeedsSatellitePointing = false;
+    private final Object mNtnSignalsStrengthLock = new Object();
+    @GuardedBy("mNtnSignalsStrengthLock")
+    private NtnSignalStrength mNtnSignalStrength =
+            new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
     /** Key: subId, value: (key: PLMN, value: set of
      * {@link android.telephony.NetworkRegistrationInfo.ServiceType})
      */
@@ -284,6 +301,7 @@
         mFeatureFlags = featureFlags;
         Phone phone = SatelliteServiceUtils.getPhone();
         mCi = phone.mCi;
+        mDSM = phone.getDeviceStateMonitor();
         // Create the SatelliteModemInterface singleton, which is used to manage connections
         // to the satellite service and HAL interface.
         mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this);
@@ -338,6 +356,8 @@
                         handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
         mCarrierConfigManager.registerCarrierConfigChangeListener(
                         new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
+        mDSM.registerForSignalStrengthReportDecision(this, CMD_START_SENDING_NTN_SIGNAL_STRENGTH,
+                null);
     }
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -611,8 +631,7 @@
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted =
                         obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
-                mPointingAppController.startSatelliteTransmissionUpdates(onCompleted,
-                        request.phone);
+                mPointingAppController.startSatelliteTransmissionUpdates(onCompleted);
                 break;
             }
 
@@ -625,7 +644,7 @@
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted =
                         obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request);
-                mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted, request.phone);
+                mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted);
                 break;
             }
 
@@ -652,26 +671,8 @@
                 onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request);
                 // Log the current time for provision triggered
                 mProvisionMetricsStats.setProvisioningStartTime();
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface.provisionSatelliteService(argument.token,
-                            argument.provisionData, onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.provisionSatelliteService(onCompleted, argument.token);
-                } else {
-                    loge("provisionSatelliteService: No phone object");
-                    argument.callback.accept(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    notifyRequester(request);
-                    mProvisionMetricsStats
-                            .setResultCode(
-                                    SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE)
-                            .reportProvisionMetrics();
-                    mControllerMetricsStats.reportProvisionCount(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                }
+                mSatelliteModemInterface.provisionSatelliteService(argument.token,
+                        argument.provisionData, onCompleted);
                 break;
             }
 
@@ -694,26 +695,7 @@
                 if (argument.callback != null) {
                     mProvisionMetricsStats.setProvisioningStartTime();
                 }
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface
-                            .deprovisionSatelliteService(argument.token, onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.deprovisionSatelliteService(onCompleted, argument.token);
-                } else {
-                    loge("deprovisionSatelliteService: No phone object");
-                    if (argument.callback != null) {
-                        argument.callback.accept(
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                        mProvisionMetricsStats.setResultCode(
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE)
-                                .reportProvisionMetrics();
-                        mControllerMetricsStats.reportDeprovisionCount(
-                                SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-                    }
-                }
+                mSatelliteModemInterface.deprovisionSatelliteService(argument.token, onCompleted);
                 break;
             }
 
@@ -741,7 +723,7 @@
                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled");
                 logd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error);
 
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (argument.enableSatellite) {
                         synchronized (mSatelliteEnabledRequestLock) {
                             mWaitingForRadioDisabled = true;
@@ -770,14 +752,14 @@
                                 // Previous mSatelliteEnabledRequest is successful but waiting for
                                 // all radios to be turned off.
                                 mSatelliteEnabledRequest.callback.accept(
-                                        SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                                        SATELLITE_RESULT_SUCCESS);
                             }
                         }
 
                         synchronized (mIsSatelliteEnabledLock) {
                             if (!mWaitingForSatelliteModemOff) {
                                 moveSatelliteToOffStateAndCleanUpResources(
-                                        SatelliteManager.SATELLITE_RESULT_SUCCESS,
+                                        SATELLITE_RESULT_SUCCESS,
                                         argument.callback);
                             } else {
                                 logd("Wait for satellite modem off before updating satellite"
@@ -794,7 +776,7 @@
                             // Previous mSatelliteEnabledRequest is successful but waiting for
                             // all radios to be turned off.
                             mSatelliteEnabledRequest.callback.accept(
-                                    SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                                    SATELLITE_RESULT_SUCCESS);
                         }
                     }
                     resetSatelliteEnabledRequest();
@@ -804,7 +786,7 @@
                 }
 
                 if (argument.enableSatellite) {
-                    if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                    if (error == SATELLITE_RESULT_SUCCESS) {
                         mControllerMetricsStats.onSatelliteEnabled();
                         mControllerMetricsStats.reportServiceEnablementSuccessCount();
                     } else {
@@ -826,18 +808,7 @@
             case CMD_IS_SATELLITE_ENABLED: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request);
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.isSatellitePowerOn(onCompleted);
-                } else {
-                    loge("isSatelliteEnabled: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted);
                 break;
             }
 
@@ -847,7 +818,7 @@
                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
                         "isSatelliteEnabled");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("isSatelliteEnabled: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -867,19 +838,7 @@
             case CMD_IS_SATELLITE_SUPPORTED: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request);
-
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.isSatelliteSupported(onCompleted);
-                } else {
-                    loge("isSatelliteSupported: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted);
                 break;
             }
 
@@ -888,7 +847,7 @@
                 request = (SatelliteControllerHandlerRequest) ar.userObj;
                 int error =  SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("isSatelliteSupported: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -906,18 +865,7 @@
             case CMD_GET_SATELLITE_CAPABILITIES: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request);
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.getSatelliteCapabilities(onCompleted);
-                } else {
-                    loge("getSatelliteCapabilities: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted);
                 break;
             }
 
@@ -927,7 +875,7 @@
                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
                         "getSatelliteCapabilities");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("getSatelliteCapabilities: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -952,20 +900,8 @@
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted =
                         obtainMessage(EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE, request);
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface
-                            .requestIsSatelliteCommunicationAllowedForCurrentLocation(
-                                    onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.isSatelliteCommunicationAllowedForCurrentLocation(onCompleted);
-                } else {
-                    loge("isSatelliteCommunicationAllowedForCurrentLocation: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface
+                        .requestIsSatelliteCommunicationAllowedForCurrentLocation(onCompleted);
                 break;
             }
 
@@ -975,7 +911,7 @@
                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
                         "isSatelliteCommunicationAllowedForCurrentLocation");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("isSatelliteCommunicationAllowedForCurrentLocation: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -997,19 +933,7 @@
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE,
                         request);
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface
-                            .requestTimeForNextSatelliteVisibility(onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.requestTimeForNextSatelliteVisibility(onCompleted);
-                } else {
-                    loge("requestTimeForNextSatelliteVisibility: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface.requestTimeForNextSatelliteVisibility(onCompleted);
                 break;
             }
 
@@ -1019,7 +943,7 @@
                 int error = SatelliteServiceUtils.getSatelliteError(ar,
                         "requestTimeForNextSatelliteVisibility");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("requestTimeForNextSatelliteVisibility: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -1063,18 +987,7 @@
             case CMD_IS_SATELLITE_PROVISIONED: {
                 request = (SatelliteControllerHandlerRequest) msg.obj;
                 onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request);
-                if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-                    mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted);
-                    break;
-                }
-                Phone phone = request.phone;
-                if (phone != null) {
-                    phone.isSatelliteProvisioned(onCompleted);
-                } else {
-                    loge("isSatelliteProvisioned: No phone object");
-                    ((ResultReceiver) request.argument).send(
-                            SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-                }
+                mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted);
                 break;
             }
 
@@ -1084,7 +997,7 @@
                 int error =  SatelliteServiceUtils.getSatelliteError(ar,
                         "isSatelliteProvisioned");
                 Bundle bundle = new Bundle();
-                if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                if (error == SATELLITE_RESULT_SUCCESS) {
                     if (ar.result == null) {
                         loge("isSatelliteProvisioned: result is null");
                         error = SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
@@ -1153,7 +1066,7 @@
                         "requestSetSatelliteEnabledForCarrier");
 
                 synchronized (mIsSatelliteEnabledLock) {
-                    if (error == SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+                    if (error == SATELLITE_RESULT_SUCCESS) {
                         boolean enableSatellite = mSatelliteAttachRestrictionForCarrierArray
                                 .getOrDefault(argument.subId, Collections.emptySet()).isEmpty();
                         mIsSatelliteAttachEnabledForCarrierArrayPerSub.put(subId, enableSatellite);
@@ -1166,6 +1079,91 @@
                 break;
             }
 
+            case CMD_REQUEST_NTN_SIGNAL_STRENGTH: {
+                logd("CMD_REQUEST_NTN_SIGNAL_STRENGTH");
+                request = (SatelliteControllerHandlerRequest) msg.obj;
+                onCompleted = obtainMessage(EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE, request);
+                mSatelliteModemInterface.requestNtnSignalStrength(onCompleted);
+                break;
+            }
+
+            case EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: {
+                ar = (AsyncResult) msg.obj;
+                request = (SatelliteControllerHandlerRequest) ar.userObj;
+                ResultReceiver result = (ResultReceiver) request.argument;
+                int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
+                        "requestNtnSignalStrength");
+                if (errorCode == SATELLITE_RESULT_SUCCESS) {
+                    NtnSignalStrength ntnSignalStrength = (NtnSignalStrength) ar.result;
+                    if (ntnSignalStrength != null) {
+                        synchronized (mNtnSignalsStrengthLock) {
+                            mNtnSignalStrength = ntnSignalStrength;
+                        }
+                        Bundle bundle = new Bundle();
+                        bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, ntnSignalStrength);
+                        result.send(SATELLITE_RESULT_SUCCESS, bundle);
+                    } else {
+                        synchronized (mNtnSignalsStrengthLock) {
+                            if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
+                                mNtnSignalStrength = new NtnSignalStrength(
+                                        NTN_SIGNAL_STRENGTH_NONE);
+                            }
+                        }
+                        loge("EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE: ntnSignalStrength is null");
+                        result.send(SatelliteManager.SATELLITE_RESULT_REQUEST_FAILED, null);
+                    }
+                } else {
+                    synchronized (mNtnSignalsStrengthLock) {
+                        if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
+                            mNtnSignalStrength = new NtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE);
+                        }
+                    }
+                    result.send(errorCode, null);
+                }
+                break;
+            }
+
+            case EVENT_NTN_SIGNAL_STRENGTH_CHANGED: {
+                ar = (AsyncResult) msg.obj;
+                if (ar.result == null) {
+                    loge("EVENT_NTN_SIGNAL_STRENGTH_CHANGED: result is null");
+                } else {
+                    handleEventNtnSignalStrengthChanged((NtnSignalStrength) ar.result);
+                }
+                break;
+            }
+
+            case CMD_START_SENDING_NTN_SIGNAL_STRENGTH: {
+                ar = (AsyncResult) msg.obj;
+                boolean shouldReport = (boolean) ar.result;
+                logd("CMD_START_SENDING_NTN_SIGNAL_STRENGTH: shouldReport=" + shouldReport);
+                request = new SatelliteControllerHandlerRequest(shouldReport,
+                        SatelliteServiceUtils.getPhone());
+                if (SATELLITE_RESULT_SUCCESS != evaluateOemSatelliteRequestAllowed(true)) {
+                    return;
+                }
+                onCompleted = obtainMessage(EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING,
+                        request);
+                if (shouldReport) {
+                    mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
+                } else {
+                    mSatelliteModemInterface.stopSendingNtnSignalStrength(onCompleted);
+                }
+                break;
+            }
+
+            case EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING: {
+                ar = (AsyncResult) msg.obj;
+                request = (SatelliteControllerHandlerRequest) ar.userObj;
+                int errorCode =  SatelliteServiceUtils.getSatelliteError(ar,
+                        "EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING");
+                if (errorCode != SATELLITE_RESULT_SUCCESS) {
+                    loge(((boolean) request.argument ? "startSendingNtnSignalStrength"
+                            : "stopSendingNtnSignalStrength") + "returns " + errorCode);
+                }
+                break;
+            }
+
             default:
                 Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
                         msg.what);
@@ -1195,28 +1193,9 @@
         logd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite
                 + " enableDemoMode: " + enableDemoMode);
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
@@ -1242,7 +1221,7 @@
                     } else {
                         logd("Enable request matches with current state"
                                 + " enableSatellite = " + enableSatellite);
-                        result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                        result.accept(SATELLITE_RESULT_SUCCESS);
                         return;
                     }
                 }
@@ -1278,7 +1257,7 @@
             }
         }
 
-        sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, null);
     }
 
     /**
@@ -1289,17 +1268,9 @@
      *               if the request is successful or an error code if the request failed.
      */
     public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
@@ -1308,12 +1279,12 @@
                 /* We have already successfully queried the satellite modem. */
                 Bundle bundle = new Bundle();
                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, mIsSatelliteEnabled);
-                result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
+                result.send(SATELLITE_RESULT_SUCCESS, bundle);
                 return;
             }
         }
 
-        sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, null);
     }
 
     /**
@@ -1339,33 +1310,15 @@
      *               if the request is successful or an error code if the request failed.
      */
     public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.send(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, null);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
         final Bundle bundle = new Bundle();
         bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled);
-        result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
+        result.send(SATELLITE_RESULT_SUCCESS, bundle);
     }
 
     /**
@@ -1397,12 +1350,12 @@
                 /* We have already successfully queried the satellite modem. */
                 Bundle bundle = new Bundle();
                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported);
-                result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
+                result.send(SATELLITE_RESULT_SUCCESS, bundle);
                 return;
             }
         }
 
-        sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, null);
     }
 
     /**
@@ -1413,17 +1366,9 @@
      *               if the request is successful or an error code if the request failed.
      */
     public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
@@ -1432,12 +1377,12 @@
                 Bundle bundle = new Bundle();
                 bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES,
                         mSatelliteCapabilities);
-                result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
+                result.send(SATELLITE_RESULT_SUCCESS, bundle);
                 return;
             }
         }
 
-        sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, null);
     }
 
     /**
@@ -1453,35 +1398,16 @@
             @NonNull IIntegerConsumer errorCallback,
             @NonNull ISatelliteTransmissionUpdateCallback callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED);
-            return;
-        }
-
-        Phone phone = SatelliteServiceUtils.getPhone();
         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
-        mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone);
+        mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback);
         sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES,
-                new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone);
+                new SatelliteTransmissionUpdateArgument(result, callback, validSubId), null);
     }
 
     /**
@@ -1496,39 +1422,20 @@
     public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback,
             @NonNull ISatelliteTransmissionUpdateCallback callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(errorCallback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED);
-            return;
-        }
-
-        Phone phone = SatelliteServiceUtils.getPhone();
         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(
-                validSubId, result, callback, phone);
+                validSubId, result, callback);
 
         // Even if handler is null - which means there are no listeners, the modem command to stop
         // satellite transmission updates might have failed. The callers might want to retry
         // sending the command. Thus, we always need to send this command to the modem.
-        sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, phone);
+        sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, null);
     }
 
     /**
@@ -1548,17 +1455,9 @@
             @NonNull String token, @NonNull byte[] provisionData,
             @NonNull IIntegerConsumer callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return null;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return null;
-        }
-        if (!satelliteSupported) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return null;
         }
 
@@ -1570,20 +1469,19 @@
 
         Boolean satelliteProvisioned = isSatelliteProvisioned();
         if (satelliteProvisioned != null && satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+            result.accept(SATELLITE_RESULT_SUCCESS);
             return null;
         }
 
-        Phone phone = SatelliteServiceUtils.getPhone();
         sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE,
                 new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId),
-                phone);
+                null);
 
         ICancellationSignal cancelTransport = CancellationSignal.createTransport();
         CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> {
             sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
                     new ProvisionSatelliteServiceArgument(token, provisionData, null,
-                            validSubId), phone);
+                            validSubId), null);
             mProvisionMetricsStats.setIsCanceled(true);
         });
         return cancelTransport;
@@ -1603,17 +1501,9 @@
     public void deprovisionSatelliteService(int subId,
             @NonNull String token, @NonNull IIntegerConsumer callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
@@ -1623,15 +1513,14 @@
             return;
         }
         if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+            result.accept(SATELLITE_RESULT_SUCCESS);
             return;
         }
 
-        Phone phone = SatelliteServiceUtils.getPhone();
         final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext);
         sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE,
                 new ProvisionSatelliteServiceArgument(token, null, result, validSubId),
-                phone);
+                null);
     }
 
     /**
@@ -1644,19 +1533,13 @@
      */
     @SatelliteManager.SatelliteResult public int registerForSatelliteProvisionStateChanged(
             int subId, @NonNull ISatelliteProvisionStateCallback callback) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
-        }
-        if (!satelliteSupported) {
-            return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            return error;
         }
 
         mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback);
-        return SatelliteManager.SATELLITE_RESULT_SUCCESS;
+        return SATELLITE_RESULT_SUCCESS;
     }
 
     /**
@@ -1684,17 +1567,9 @@
      *               request failed.
      */
     public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
@@ -1703,12 +1578,12 @@
                 Bundle bundle = new Bundle();
                 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED,
                         mIsSatelliteProvisioned);
-                result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
+                result.send(SATELLITE_RESULT_SUCCESS, bundle);
                 return;
             }
         }
 
-        sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, null);
     }
 
     /**
@@ -1731,7 +1606,7 @@
                     + " is not initialized yet");
             return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
         }
-        return SatelliteManager.SATELLITE_RESULT_SUCCESS;
+        return SATELLITE_RESULT_SUCCESS;
     }
 
     /**
@@ -1768,6 +1643,9 @@
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
             return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
         }
+        if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
+            return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
+        }
         return mDatagramController.registerForSatelliteDatagram(subId, callback);
     }
 
@@ -1784,6 +1662,9 @@
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
             return;
         }
+        if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
+            return;
+        }
         mDatagramController.unregisterForSatelliteDatagram(subId, callback);
     }
 
@@ -1800,18 +1681,9 @@
      */
     public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
@@ -1839,18 +1711,9 @@
             SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull IIntegerConsumer callback) {
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED);
-            return;
-        }
-
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.accept(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.accept(error);
             return;
         }
 
@@ -1877,22 +1740,13 @@
      */
     public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
             @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
+        int error = evaluateOemSatelliteRequestAllowed(false);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
-        sendRequestAsync(
-                CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone());
+        sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, null);
     }
 
     /**
@@ -1903,32 +1757,13 @@
      *               be visible if the request is successful or an error code if the request failed.
      */
     public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) {
-        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
-            return;
-        }
-        Boolean satelliteSupported = isSatelliteSupportedInternal();
-        if (satelliteSupported == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteSupported) {
-            result.send(SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED, null);
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
             return;
         }
 
-        Boolean satelliteProvisioned = isSatelliteProvisioned();
-        if (satelliteProvisioned == null) {
-            result.send(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
-            return;
-        }
-        if (!satelliteProvisioned) {
-            result.send(SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED, null);
-            return;
-        }
-
-        Phone phone = SatelliteServiceUtils.getPhone();
-        sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone);
+        sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, null);
     }
 
     /**
@@ -1961,6 +1796,8 @@
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
             result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+            logd("addSatelliteAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is "
+                    + "disabled");
             return;
         }
 
@@ -1969,7 +1806,7 @@
                     subId, Collections.emptySet()).isEmpty()) {
                 mSatelliteAttachRestrictionForCarrierArray.put(subId, new HashSet<>());
             } else if (mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
-                result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                result.accept(SATELLITE_RESULT_SUCCESS);
                 return;
             }
             mSatelliteAttachRestrictionForCarrierArray.get(subId).add(reason);
@@ -1998,6 +1835,8 @@
         Consumer<Integer> result = FunctionalUtils.ignoreRemoteException(callback::accept);
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
             result.accept(SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+            logd("removeSatelliteAttachRestrictionForCarrier: carrierEnabledSatelliteFlag is "
+                    + "disabled");
             return;
         }
 
@@ -2005,7 +1844,7 @@
             if (mSatelliteAttachRestrictionForCarrierArray.getOrDefault(
                     subId, Collections.emptySet()).isEmpty()
                     || !mSatelliteAttachRestrictionForCarrierArray.get(subId).contains(reason)) {
-                result.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                result.accept(SATELLITE_RESULT_SUCCESS);
                 return;
             }
             mSatelliteAttachRestrictionForCarrierArray.get(subId).remove(reason);
@@ -2040,6 +1879,75 @@
     }
 
     /**
+     * Request to get the signal strength of the satellite connection.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param result Result receiver to get the error code of the request and the current signal
+     * strength of the satellite connection.
+     */
+    public void requestNtnSignalStrength(int subId, @NonNull ResultReceiver result) {
+        if (DBG) logd("requestNtnSignalStrength()");
+
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) {
+            result.send(error, null);
+            return;
+        }
+
+        /* In case cache is available, it is not needed to request non-terrestrial signal strength
+        to modem */
+        synchronized (mNtnSignalsStrengthLock) {
+            if (mNtnSignalStrength.getLevel() != NTN_SIGNAL_STRENGTH_NONE) {
+                Bundle bundle = new Bundle();
+                bundle.putParcelable(KEY_NTN_SIGNAL_STRENGTH, mNtnSignalStrength);
+                result.send(SATELLITE_RESULT_SUCCESS, bundle);
+                return;
+            }
+        }
+
+        Phone phone = SatelliteServiceUtils.getPhone();
+        sendRequestAsync(CMD_REQUEST_NTN_SIGNAL_STRENGTH, result, phone);
+    }
+
+    /**
+     * Registers for NTN signal strength changed from satellite modem.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param callback The callback to handle the non-terrestrial network signal strength changed
+     * event.
+     *
+     * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
+     */
+    @SatelliteManager.SatelliteResult public int registerForNtnSignalStrengthChanged(
+            int subId, @NonNull INtnSignalStrengthCallback callback) {
+        if (DBG) logd("registerForNtnSignalStrengthChanged()");
+
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error != SATELLITE_RESULT_SUCCESS) return error;
+
+        mNtnSignalStrengthChangedListeners.put(callback.asBinder(), callback);
+        return SATELLITE_RESULT_SUCCESS;
+    }
+
+    /**
+     * Unregisters for NTN signal strength changed from satellite modem.
+     * If callback was not registered before, the request will be ignored.
+     *
+     * @param subId The subId of the subscription to unregister for provision state changed.
+     * @param callback The callback that was passed to
+     * {@link #registerForNtnSignalStrengthChanged(int, INtnSignalStrengthCallback)}
+     */
+    public void unregisterForNtnSignalStrengthChanged(
+            int subId, @NonNull INtnSignalStrengthCallback callback) {
+        if (DBG) logd("unregisterForNtnSignalStrengthChanged()");
+
+        int error = evaluateOemSatelliteRequestAllowed(true);
+        if (error == SATELLITE_RESULT_SUCCESS) {
+            mNtnSignalStrengthChangedListeners.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.
@@ -2182,6 +2090,7 @@
      */
     public void onCellularRadioPowerOffRequested() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("onCellularRadioPowerOffRequested: oemEnabledSatelliteFlag is disabled");
             return;
         }
 
@@ -2262,6 +2171,7 @@
      */
     public boolean isSatelliteAttachRequired() {
         if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("isSatelliteAttachRequired: oemEnabledSatelliteFlag is disabled");
             return false;
         }
 
@@ -2351,12 +2261,12 @@
                 "handleStartSatelliteTransmissionUpdatesDone");
         arg.errorCallback.accept(errorCode);
 
-        if (errorCode != SatelliteManager.SATELLITE_RESULT_SUCCESS) {
+        if (errorCode != SATELLITE_RESULT_SUCCESS) {
             mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
             // We need to remove the callback from our listener list since the caller might not call
             // stopSatelliteTransmissionUpdates to unregister the callback in case of failure.
             mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId,
-                    arg.errorCallback, arg.callback, request.phone);
+                    arg.errorCallback, arg.callback);
         } else {
             mPointingAppController.setStartedSatelliteTransmissionUpdates(true);
         }
@@ -2433,10 +2343,7 @@
     private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) {
         RequestSatelliteEnabledArgument argument =
                 (RequestSatelliteEnabledArgument) request.argument;
-        Phone phone = request.phone;
-
-        if (!argument.enableSatellite && (mSatelliteModemInterface.isSatelliteServiceSupported()
-                || phone != null)) {
+        if (!argument.enableSatellite && mSatelliteModemInterface.isSatelliteServiceSupported()) {
             synchronized (mIsSatelliteEnabledLock) {
                 mWaitingForDisableSatelliteModemResponse = true;
                 mWaitingForSatelliteModemOff = true;
@@ -2444,18 +2351,8 @@
         }
 
         Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request);
-        if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
-            mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
-                    argument.enableDemoMode, onCompleted);
-            return;
-        }
-
-        if (phone != null) {
-            phone.setSatellitePower(onCompleted, argument.enableSatellite);
-        } else {
-            loge("requestSatelliteEnabled: No phone object");
-            argument.callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-        }
+        mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite,
+                argument.enableDemoMode, onCompleted);
     }
 
     private void handleRequestSatelliteAttachRestrictionForCarrierCmd(
@@ -2483,6 +2380,7 @@
             registerForSatelliteProvisionStateChanged();
             registerForPendingDatagramCount();
             registerForSatelliteModemStateChanged();
+            registerForNtnSignalStrengthChanged();
 
             requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
                     new ResultReceiver(this) {
@@ -2528,15 +2426,6 @@
                         this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null);
                 mRegisteredForProvisionStateChangedWithSatelliteService.set(true);
             }
-        } else {
-            Phone phone = SatelliteServiceUtils.getPhone();
-            if (phone == null) {
-                loge("registerForSatelliteProvisionStateChanged: phone is null");
-            } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) {
-                phone.registerForSatelliteProvisionStateChanged(
-                        this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null);
-                mRegisteredForProvisionStateChangedWithPhone.set(true);
-            }
         }
     }
 
@@ -2547,15 +2436,6 @@
                         this, EVENT_PENDING_DATAGRAMS, null);
                 mRegisteredForPendingDatagramCountWithSatelliteService.set(true);
             }
-        } else {
-            Phone phone = SatelliteServiceUtils.getPhone();
-            if (phone == null) {
-                loge("registerForPendingDatagramCount: satellite phone is "
-                        + "not initialized yet");
-            } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) {
-                phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null);
-                mRegisteredForPendingDatagramCountWithPhone.set(true);
-            }
         }
     }
 
@@ -2566,15 +2446,20 @@
                         this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
                 mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true);
             }
-        } else {
-            Phone phone = SatelliteServiceUtils.getPhone();
-            if (phone == null) {
-                loge("registerForSatelliteModemStateChanged: satellite phone is "
-                        + "not initialized yet");
-            } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) {
-                phone.registerForSatelliteModemStateChanged(
-                        this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null);
-                mRegisteredForSatelliteModemStateChangedWithPhone.set(true);
+        }
+    }
+
+    private void registerForNtnSignalStrengthChanged() {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("registerForNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled");
+            return;
+        }
+
+        if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
+            if (!mRegisteredForNtnSignalStrengthChanged.get()) {
+                mSatelliteModemInterface.registerForNtnSignalStrengthChanged(
+                        this, EVENT_NTN_SIGNAL_STRENGTH_CHANGED, null);
+                mRegisteredForNtnSignalStrengthChanged.set(true);
             }
         }
     }
@@ -2586,16 +2471,16 @@
             mIsSatelliteProvisioned = provisioned;
         }
 
-        List<ISatelliteProvisionStateCallback> toBeRemoved = new ArrayList<>();
+        List<ISatelliteProvisionStateCallback> deadCallersList = new ArrayList<>();
         mSatelliteProvisionStateChangedListeners.values().forEach(listener -> {
             try {
                 listener.onSatelliteProvisionStateChanged(provisioned);
             } catch (RemoteException e) {
                 logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e);
-                toBeRemoved.add(listener);
+                deadCallersList.add(listener);
             }
         });
-        toBeRemoved.forEach(listener -> {
+        deadCallersList.forEach(listener -> {
             mSatelliteProvisionStateChangedListeners.remove(listener.asBinder());
         });
     }
@@ -2610,7 +2495,7 @@
                         || ((mIsSatelliteEnabled == null || isSatelliteEnabled())
                         && !mWaitingForDisableSatelliteModemResponse)) {
                     int error = (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF)
-                            ? SatelliteManager.SATELLITE_RESULT_SUCCESS
+                            ? SATELLITE_RESULT_SUCCESS
                             : SatelliteManager.SATELLITE_RESULT_INVALID_MODEM_STATE;
                     Consumer<Integer> callback = null;
                     synchronized (mSatelliteEnabledRequestLock) {
@@ -2636,6 +2521,31 @@
         }
     }
 
+    private void handleEventNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
+        logd("handleEventNtnSignalStrengthChanged: ntnSignalStrength=" + ntnSignalStrength);
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("handleEventNtnSignalStrengthChanged: oemEnabledSatelliteFlag is disabled");
+            return;
+        }
+
+        synchronized (mNtnSignalsStrengthLock) {
+            mNtnSignalStrength = ntnSignalStrength;
+        }
+
+        List<INtnSignalStrengthCallback> deadCallersList = new ArrayList<>();
+        mNtnSignalStrengthChangedListeners.values().forEach(listener -> {
+            try {
+                listener.onNtnSignalStrengthChanged(ntnSignalStrength);
+            } catch (RemoteException e) {
+                logd("handleEventNtnSignalStrengthChanged RemoteException: " + e);
+                deadCallersList.add(listener);
+            }
+        });
+        deadCallersList.forEach(listener -> {
+            mNtnSignalStrengthChangedListeners.remove(listener.asBinder());
+        });
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     protected void setSettingsKeyForSatelliteMode(int val) {
         logd("setSettingsKeyForSatelliteMode val: " + val);
@@ -2668,7 +2578,7 @@
                 synchronized (mIsSatelliteEnabledLock) {
                     mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite;
                 }
-                mSatelliteEnabledRequest.callback.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+                mSatelliteEnabledRequest.callback.accept(SATELLITE_RESULT_SUCCESS);
                 updateSatelliteEnabledState(
                         mSatelliteEnabledRequest.enableSatellite,
                         "EVENT_SET_SATELLITE_ENABLED_DONE");
@@ -2712,6 +2622,7 @@
     private void configureSatellitePlmnForCarrier(int subId) {
         logd("configureSatellitePlmnForCarrier");
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("configureSatellitePlmnForCarrier: carrierEnabledSatelliteFlag is disabled");
             return;
         }
         synchronized (mSupportedSatelliteServicesLock) {
@@ -2737,6 +2648,8 @@
 
     private void updateSupportedSatelliteServicesForActiveSubscriptions() {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("updateSupportedSatelliteServicesForActiveSubscriptions: "
+                    + "carrierEnabledSatelliteFlag is disabled");
             return;
         }
 
@@ -2764,6 +2677,7 @@
     @NonNull
     private List<String> readSatellitePlmnsFromOverlayConfig() {
         if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+            logd("readSatellitePlmnsFromOverlayConfig: carrierEnabledSatelliteFlag is disabled");
             return new ArrayList<>();
         }
 
@@ -3010,7 +2924,7 @@
 
         if (!isSatelliteSupportedForCarrier(subId)) {
             logd("Satellite for carrier is not supported. Only user setting is stored");
-            callback.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+            callback.accept(SATELLITE_RESULT_SUCCESS);
             return;
         }
 
@@ -3034,10 +2948,41 @@
                 callback.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
             }
         } else {
-            callback.accept(SatelliteManager.SATELLITE_RESULT_SUCCESS);
+            callback.accept(SATELLITE_RESULT_SUCCESS);
         }
     }
 
+    @SatelliteManager.SatelliteResult private int evaluateOemSatelliteRequestAllowed(
+            boolean isProvisionRequired) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("oemEnabledSatelliteFlag is disabled");
+            return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
+        }
+        if (!mSatelliteModemInterface.isSatelliteServiceSupported()) {
+            return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
+        }
+
+        Boolean satelliteSupported = isSatelliteSupportedInternal();
+        if (satelliteSupported == null) {
+            return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
+        }
+        if (!satelliteSupported) {
+            return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
+        }
+
+        if (isProvisionRequired) {
+            Boolean satelliteProvisioned = isSatelliteProvisioned();
+            if (satelliteProvisioned == null) {
+                return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
+            }
+            if (!satelliteProvisioned) {
+                return SatelliteManager.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED;
+            }
+        }
+
+        return SATELLITE_RESULT_SUCCESS;
+    }
+
     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 6ecb642..62f7371 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -31,10 +31,12 @@
 import android.os.RegistrantList;
 import android.os.RemoteException;
 import android.telephony.Rlog;
+import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteManager.SatelliteException;
+import android.telephony.satellite.stub.INtnSignalStrengthConsumer;
 import android.telephony.satellite.stub.ISatellite;
 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer;
 import android.telephony.satellite.stub.ISatelliteListener;
@@ -87,6 +89,8 @@
     @NonNull private final RegistrantList mPendingDatagramsRegistrants = new RegistrantList();
     @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants =
             new RegistrantList();
+    @NonNull private final RegistrantList mNtnSignalStrengthChangedRegistrants =
+            new RegistrantList();
 
     @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() {
         @Override
@@ -136,6 +140,13 @@
             }
             mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState);
         }
+
+        @Override
+        public void onNtnSignalStrengthChanged(
+                android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) {
+            mNtnSignalStrengthChangedRegistrants.notifyResult(
+                    SatelliteServiceUtils.fromModemInterface(ntnSignalStrength));
+        }
     };
 
     /**
@@ -441,6 +452,27 @@
     }
 
     /**
+     * Registers for non-terrestrial signal strength level changed.
+     *
+     * @param h Handler for notification message.
+     * @param what User-defined message code.
+     * @param obj User object.
+     */
+    public void registerForNtnSignalStrengthChanged(
+            @NonNull Handler h, int what, @Nullable Object obj) {
+        mNtnSignalStrengthChangedRegistrants.add(h, what, obj);
+    }
+
+    /**
+     * Unregisters for non-terrestrial signal strength level changed.
+     *
+     * @param h Handler to be removed from the registrant list.
+     */
+    public void unregisterForNtnSignalStrengthChanged(@NonNull Handler h) {
+        mNtnSignalStrengthChangedRegistrants.remove(h);
+    }
+
+    /**
      * Request to enable or disable the satellite service listening mode.
      * Listening mode allows the satellite service to listen for incoming pages.
      *
@@ -1153,6 +1185,102 @@
         }
     }
 
+    /**
+     * Request to get the signal strength of the satellite connection.
+     *
+     * @param message The Message to send to result of the operation to.
+     */
+    public void requestNtnSignalStrength(@NonNull Message message) {
+        if (mSatelliteService != null) {
+            try {
+                mSatelliteService.requestSignalStrength(
+                        new IIntegerConsumer.Stub() {
+                            @Override
+                            public void accept(int result) {
+                                int error = SatelliteServiceUtils.fromSatelliteError(result);
+                                logd("requestNtnSignalStrength: " + error);
+                                Binder.withCleanCallingIdentity(() ->
+                                        sendMessageWithResult(message, null, error));
+                            }
+                        }, new INtnSignalStrengthConsumer.Stub() {
+                            @Override
+                            public void accept(NtnSignalStrength result) {
+                                logd("requestNtnSignalStrength: " + result);
+                                Binder.withCleanCallingIdentity(() -> sendMessageWithResult(
+                                        message, result,
+                                        SatelliteManager.SATELLITE_RESULT_SUCCESS));
+                            }
+                        });
+            } catch (RemoteException e) {
+                loge("requestNtnSignalStrength: RemoteException " + e);
+                sendMessageWithResult(message, null,
+                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+            }
+        } else {
+            loge("requestNtnSignalStrength: Satellite service is unavailable.");
+            sendMessageWithResult(message, null,
+                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
+        }
+    }
+
+    /**
+     * The satellite service should report the NTN signal strength via
+     * ISatelliteListener#onNtnSignalStrengthChanged when the NTN signal strength changes.
+     *
+     * @param message The Message to send to result of the operation to.
+     */
+    public void startSendingNtnSignalStrength(@NonNull Message message) {
+        if (mSatelliteService != null) {
+            try {
+                mSatelliteService.startSendingNtnSignalStrength(new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        int error = SatelliteServiceUtils.fromSatelliteError(result);
+                        logd("startSendingNtnSignalStrength: " + error);
+                        Binder.withCleanCallingIdentity(() ->
+                                sendMessageWithResult(message, null, error));
+                    }
+                });
+            } catch (RemoteException e) {
+                loge("startSendingNtnSignalStrength: RemoteException " + e);
+                sendMessageWithResult(message, null,
+                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+            }
+        } else {
+            loge("startSendingNtnSignalStrength: Satellite service is unavailable.");
+            sendMessageWithResult(message, null,
+                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
+        }
+    }
+
+    /**
+     * The satellite service should stop reporting NTN signal strength to the framework.
+     *
+     * @param message The Message to send to result of the operation to.
+     */
+    public void stopSendingNtnSignalStrength(@NonNull Message message) {
+        if (mSatelliteService != null) {
+            try {
+                mSatelliteService.stopSendingNtnSignalStrength(new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        int error = SatelliteServiceUtils.fromSatelliteError(result);
+                        logd("stopSendingNtnSignalStrength: " + error);
+                        Binder.withCleanCallingIdentity(() ->
+                                sendMessageWithResult(message, null, error));
+                    }
+                });
+            } catch (RemoteException e) {
+                loge("stopSendingNtnSignalStrength: RemoteException " + e);
+                sendMessageWithResult(message, null,
+                        SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
+            }
+        } else {
+            loge("stopSendingNtnSignalStrength: Satellite service is unavailable.");
+            sendMessageWithResult(message, null,
+                    SatelliteManager.SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
+        }
+    }
 
     public boolean isSatelliteServiceSupported() {
         return mIsSatelliteServiceSupported;
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index cad9bfb..b42c7d4 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -31,6 +31,7 @@
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.satellite.AntennaPosition;
+import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.PointingInfo;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
@@ -39,10 +40,8 @@
 import android.telephony.satellite.stub.SatelliteModemState;
 import android.telephony.satellite.stub.SatelliteResult;
 
-import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneFactory;
-import com.android.internal.telephony.RILUtils;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
 import java.util.Arrays;
@@ -214,6 +213,16 @@
     }
 
     /**
+     * Convert non-terrestrial signal strength from service definition to framework definition.
+     * @param ntnSignalStrength The non-terrestrial signal strength from the satellite service.
+     * @return The converted non-terrestrial signal strength for the framework.
+     */
+    @Nullable public static NtnSignalStrength fromModemInterface(
+            android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) {
+        return new NtnSignalStrength(ntnSignalStrength.signalStrengthLevel);
+    }
+
+    /**
      * Convert SatelliteDatagram from framework definition to service definition.
      * @param datagram The SatelliteDatagram from the framework.
      * @return The converted SatelliteDatagram for the satellite service.
@@ -241,11 +250,7 @@
             errorCode = SatelliteManager.SATELLITE_RESULT_SUCCESS;
         } else {
             errorCode = SatelliteManager.SATELLITE_RESULT_ERROR;
-            if (ar.exception instanceof CommandException) {
-                CommandException.Error error = ((CommandException) ar.exception).getCommandError();
-                errorCode = RILUtils.convertToSatelliteError(error);
-                loge(caller + " CommandException: " + ar.exception);
-            } else if (ar.exception instanceof SatelliteManager.SatelliteException) {
+            if (ar.exception instanceof SatelliteManager.SatelliteException) {
                 errorCode = ((SatelliteManager.SatelliteException) ar.exception).getErrorCode();
                 loge(caller + " SatelliteException: " + ar.exception);
             } else {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
index 40e1821..9fd89ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java
@@ -94,7 +94,7 @@
         super.setUp(getClass().getSimpleName());
         mBundle = mContextFixture.getCarrierConfigBundle();
         when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
-
+        when(mUserManager.isUserUnlocked()).thenReturn(true);
         // Capture listener to emulate the carrier config change notification used later
         ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
                 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
@@ -342,7 +342,7 @@
      **/
     @Test
     @SmallTest
-    public void testCarrierConfigChanged() {
+    public void testCarrierConfigChangedWithUserUnlocked() {
         CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         int slotId = mPhone.getPhoneId();
@@ -360,6 +360,57 @@
         assertEquals(1, mCarrierKeyDM.mCarrierId);
     }
 
+    @Test
+    @SmallTest
+    public void testCarrierConfigChangedWithUserLocked() {
+        when(mUserManager.isUserUnlocked()).thenReturn(false);
+        CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        int slotId = mPhone.getPhoneId();
+        PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId);
+        bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
+        bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
+
+        when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
+        when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+        mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+        processAllMessages();
+        assertNull(mCarrierKeyDM.mMccMncForDownload);
+        assertEquals(0, mCarrierKeyDM.mCarrierId);
+    }
+
+    @Test
+    @SmallTest
+    public void testUserLockedAfterCarrierConfigChanged() {
+        // User is locked at beginning
+        when(mUserManager.isUserUnlocked()).thenReturn(false);
+        CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        int slotId = mPhone.getPhoneId();
+        PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId);
+        bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3);
+        bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL);
+
+        // Carrier config change received
+        when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260");
+        when(mTelephonyManager.getSimCarrierId()).thenReturn(1);
+        mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID);
+        processAllMessages();
+
+        // User unlocked event received
+        Intent mIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+        mContext.sendBroadcast(mIntent);
+        when(mUserManager.isUserUnlocked()).thenReturn(true);
+        processAllMessages();
+
+        assertEquals("310260", mCarrierKeyDM.mMccMncForDownload);
+        assertEquals(1, mCarrierKeyDM.mCarrierId);
+    }
+
     /**
      * Tests notifying carrier config change from listener with an empty key.
      * Verify that the carrier keys are removed if IMSI_KEY_DOWNLOAD_URL_STRING is null.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index ea19b62..3c8db99 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -783,7 +783,7 @@
         doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
         doAnswer(invocation -> mNetworkId++).when(mNetwork).getNetId();
         doReturn(mNetwork).when(mConnectivityManager).registerNetworkAgent(
-                any(), any(), any(), any(), any(), any(), anyInt());
+                any(), any(), any(), any(), any(), any(), any(), anyInt());
 
         doReturn(true).when(mEuiccManager).isEnabled();
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 28a37f7..018759a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -20,7 +20,9 @@
 import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
@@ -30,6 +32,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import static java.util.Arrays.asList;
 
@@ -40,22 +43,31 @@
 import android.hardware.radio.V1_5.IndicationFilter;
 import android.net.ConnectivityManager;
 import android.net.TetheringManager;
+import android.os.AsyncResult;
 import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.internal.telephony.flags.FeatureFlags;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Map;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -114,6 +126,7 @@
 
     private static final int STATE_OFF = 0;
     private static final int STATE_ON = 1;
+    private static final long TIMEOUT = 500;
 
     // The keys are the single IndicationFilter flags,
     // The values are the array of states, when one state turn on, the corresponding
@@ -135,6 +148,9 @@
     UiModeManager mUiModeManager;
 
     private DeviceStateMonitor mDSM;
+    private TestSatelliteController mSatelliteControllerUT;
+
+    @Mock private FeatureFlags mFeatureFlags;
 
     // Given a stateType, return the event type that can change the state
     private int state2Event(@StateType int stateType) {
@@ -162,11 +178,12 @@
     @Before
     public void setUp() throws Exception {
         super.setUp(getClass().getSimpleName());
+        MockitoAnnotations.initMocks(this);
         mUiModeManager = mock(UiModeManager.class);
         mContextFixture.setSystemService(Context.UI_MODE_SERVICE, mUiModeManager);
         // We don't even need a mock executor, we just need to not throw.
         doReturn(null).when(mContextFixture.getTestDouble()).getMainExecutor();
-        mDSM = new DeviceStateMonitor(mPhone);
+        mDSM = new DeviceStateMonitor(mPhone, mFeatureFlags);
 
         // Initialize with ALL states off
         updateAllStatesToOff();
@@ -177,6 +194,7 @@
 
     @After
     public void tearDown() throws Exception {
+        mSatelliteControllerUT = null;
         mDSM = null;
         super.tearDown();
     }
@@ -453,4 +471,160 @@
         verify(mSimulatedCommandsVerifier).setUnsolResponseFilter(
                 eq(INDICATION_FILTERS_MINIMUM), nullable(Message.class));
     }
+
+    @Test
+    public void testRegisterForSignalStrengthReportDecisionWithFeatureEnabled() {
+        logd("testRegisterForSignalStrengthReportDecisionWithFeatureEnabled()");
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        mSatelliteControllerUT = new TestSatelliteController(Looper.myLooper(), mDSM);
+
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0);
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        mSatelliteControllerUT.resetCount();
+        sEventDeviceStatusChanged.drainPermits();
+
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+        assertTrue(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(1, mSatelliteControllerUT.getStopEventCount());
+        mSatelliteControllerUT.resetCount();
+
+        mSatelliteControllerUT.resetCount();
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        assertTrue(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(1, mSatelliteControllerUT.getStopEventCount());
+        mSatelliteControllerUT.resetCount();
+
+        updateState(STATE_TYPE_RADIO_ON, 0);
+        assertTrue(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(1, mSatelliteControllerUT.getStopEventCount());
+        mSatelliteControllerUT.resetCount();
+
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+        assertTrue(waitForEventDeviceStatusChanged());
+        assertEquals(1, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+        mSatelliteControllerUT.resetCount();
+
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0);
+        assertTrue(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(1, mSatelliteControllerUT.getStopEventCount());
+    }
+
+    @Test
+    public void testRegisterForSignalStrengthReportDecisionWithFeatureDisabled() {
+        logd("testRegisterForSignalStrengthReportDecisionWithFeatureDisabled()");
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+        mSatelliteControllerUT = new TestSatelliteController(Looper.myLooper(), mDSM);
+
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0);
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        mSatelliteControllerUT.resetCount();
+        sEventDeviceStatusChanged.drainPermits();
+
+
+        /* Sending stop ntn signal strength as radio is off */
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+        assertFalse(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+
+        updateState(STATE_TYPE_SCREEN, STATE_OFF);
+        assertFalse(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+
+        updateState(STATE_TYPE_RADIO_ON, 0);
+        assertFalse(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+
+        updateState(STATE_TYPE_SCREEN, STATE_ON);
+        assertFalse(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+
+        updateState(STATE_TYPE_RADIO_OFF_OR_NOT_AVAILABLE, 0);
+        assertFalse(waitForEventDeviceStatusChanged());
+        assertEquals(0, mSatelliteControllerUT.getStartEventCount());
+        assertEquals(0, mSatelliteControllerUT.getStopEventCount());
+    }
+
+    private static Semaphore sEventDeviceStatusChanged = new Semaphore(0);
+    private boolean waitForEventDeviceStatusChanged() {
+        try {
+            if (!sEventDeviceStatusChanged.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
+                logd("Time out to receive EVENT_DEVICE_STATUS_CHANGED");
+                return false;
+            }
+        } catch (Exception ex) {
+            logd("waitForEventDeviceStatusChanged: ex=" + ex);
+            return false;
+        }
+        return true;
+    }
+
+    private static class TestSatelliteController extends Handler {
+        public static final int EVENT_DEVICE_STATUS_CHANGED = 35;
+        private final DeviceStateMonitor mDsm;
+        private int mStartEventCount;
+        private int mStopEventCount;
+
+        TestSatelliteController(Looper looper, DeviceStateMonitor dsm) {
+            super(looper);
+            mDsm = dsm;
+            mDsm.registerForSignalStrengthReportDecision(this, EVENT_DEVICE_STATUS_CHANGED, null);
+        }
+
+        /**
+         * Resets the count of occurred events.
+         */
+        public void resetCount() {
+            mStartEventCount = 0;
+            mStopEventCount = 0;
+        }
+
+        public int getStartEventCount() {
+            return mStartEventCount;
+        }
+
+        public int getStopEventCount() {
+            return mStopEventCount;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+                case EVENT_DEVICE_STATUS_CHANGED: {
+                    logd("EVENT_DEVICE_STATUS_CHANGED");
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    boolean shouldReport = (boolean) ar.result;
+                    if (shouldReport) {
+                        startSendingNtnSignalStrength();
+                    } else {
+                        stopSendingNtnSignalStrength();
+                    }
+                    try {
+                        sEventDeviceStatusChanged.release();
+                    } catch (Exception ex) {
+                        logd("waitForEventDeviceStatusChanged: ex=" + ex);
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+
+        private void startSendingNtnSignalStrength() {
+            mStartEventCount++;
+        }
+
+        private void stopSendingNtnSignalStrength() {
+            mStopEventCount++;
+        }
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
index f729b80..8dd350f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
@@ -42,11 +42,14 @@
 import android.testing.TestableLooper;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.flags.FeatureFlags;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
 import java.util.Collections;
 import java.util.concurrent.Executor;
@@ -54,17 +57,18 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class DisplayInfoControllerTest extends TelephonyTest {
-
     private static final int PHONE_ID = 0;
     private static final String MCC = "600";
     private static final String MNC = "01";
     private static final String NUMERIC = MCC + MNC;
     private static final String NETWORK = "TestNet";
 
+    // Mocked classes
+    private FeatureFlags mFeatureFlags;
+
     private DisplayInfoController mDic;
     private ServiceStateTracker mSst;
     private ServiceStateTrackerTestHandler mSstHandler;
-    private SignalStrengthController mSsc;
     private PersistableBundle mBundle;
     private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
 
@@ -75,8 +79,8 @@
 
         @Override
         public void onLooperPrepared() {
-            mSsc = new SignalStrengthController(mPhone);
-            doReturn(mSsc).when(mPhone).getSignalStrengthController();
+            SignalStrengthController ssc = new SignalStrengthController(mPhone);
+            doReturn(ssc).when(mPhone).getSignalStrengthController();
             doReturn(new ServiceState()).when(mPhone).getServiceState();
             doReturn(NUMERIC).when(mTelephonyManager).getSimOperatorNumericForPhone(eq(PHONE_ID));
             doReturn(NETWORK).when(mTelephonyManager).getSimOperatorNameForPhone(eq(PHONE_ID));
@@ -101,6 +105,7 @@
         logd("DisplayInfoControllerTest setup!");
         super.setUp(getClass().getSimpleName());
 
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
         doReturn((Executor) Runnable::run).when(mContext).getMainExecutor();
         mBundle = mContextFixture.getCarrierConfigBundle();
         mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName());
@@ -191,7 +196,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -211,7 +216,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -232,7 +237,7 @@
         assertTrue(ss1.getRoaming()); // roam
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -254,7 +259,7 @@
         assertFalse(ss.getRoaming()); // home
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
@@ -275,10 +280,32 @@
         assertTrue(ss1.getRoaming()); // roam
 
         doReturn(mSst).when(mPhone).getServiceStateTracker();
-        mDic = new DisplayInfoController(mPhone);
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
         mDic.updateTelephonyDisplayInfo();
         TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
 
         assertTrue(tdi.isRoaming());
     }
+
+    @Test
+    public void testIsRoamingOverride_HideRoamingIndicator() {
+        doReturn(true).when(mPhone).isPhoneTypeGsm();
+        mBundle.putStringArray(
+                CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC});
+        mBundle.putBoolean(CarrierConfigManager.KEY_SHOW_ROAMING_INDICATOR_BOOL, false);
+        doReturn(true).when(mFeatureFlags).hideRoamingIcon();
+        sendCarrierConfigUpdate();
+
+        changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
+        ServiceState ss1 = mSst.getServiceState();
+
+        assertTrue(ss1.getRoaming()); // roam
+
+        doReturn(mSst).when(mPhone).getServiceStateTracker();
+        mDic = new DisplayInfoController(mPhone, mFeatureFlags);
+        mDic.updateTelephonyDisplayInfo();
+        TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo();
+
+        assertFalse(tdi.isRoaming()); // display override
+    }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
index b073cd4..dc63932 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java
@@ -23,10 +23,12 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
@@ -59,6 +61,8 @@
 import com.android.internal.telephony.domainselection.DomainSelectionConnection;
 import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection;
 import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection;
+import com.android.internal.telephony.emergency.EmergencyStateTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.uicc.IccUtils;
 
 import org.junit.After;
@@ -80,8 +84,8 @@
      */
     private static class TestSmsDispatchersController extends SmsDispatchersController {
         TestSmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
-                SmsUsageMonitor usageMonitor, Looper looper) {
-            super(phone, storageMonitor, usageMonitor, looper);
+                SmsUsageMonitor usageMonitor, Looper looper, FeatureFlags featureFlags) {
+            super(phone, storageMonitor, usageMonitor, looper, featureFlags);
         }
 
         public DomainSelectionConnectionHolder testGetDomainSelectionConnectionHolder(
@@ -104,6 +108,15 @@
             sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri,
                     callingPkg, persistMessage, priority, expectMore, validityPeriod, messageId);
         }
+
+        public void testNotifySmsSentToEmergencyStateTracker(String destAddr, long messageId) {
+            notifySmsSentToEmergencyStateTracker(destAddr, messageId);
+        }
+
+        public void testNotifySmsSentFailedToEmergencyStateTracker(String destAddr,
+                long messageId) {
+            notifySmsSentFailedToEmergencyStateTracker(destAddr, messageId);
+        }
     }
 
     /**
@@ -158,6 +171,7 @@
     private static final String ACTION_TEST_SMS_SENT = "TEST_SMS_SENT";
 
     // Mocked classes
+    private FeatureFlags mFeatureFlags;
     private SMSDispatcher.SmsTracker mTracker;
     private PendingIntent mSentIntent;
     private TestImsSmsDispatcher mImsSmsDispatcher;
@@ -165,6 +179,8 @@
     private TestSmsDispatcher mCdmaSmsDispatcher;
     private SmsDomainSelectionConnection mSmsDsc;
     private EmergencySmsDomainSelectionConnection mEmergencySmsDsc;
+    private EmergencyStateTracker mEmergencyStateTracker;
+    private CompletableFuture<Integer> mEmergencySmsFuture;
 
     private TestSmsDispatchersController mSmsDispatchersController;
     private boolean mInjectionCallbackTriggered = false;
@@ -174,10 +190,10 @@
     public void setUp() throws Exception {
         super.setUp(getClass().getSimpleName());
         mTracker = mock(SMSDispatcher.SmsTracker.class);
+        mFeatureFlags = mock(FeatureFlags.class);
         setupMockPackagePermissionChecks();
         mSmsDispatchersController = new TestSmsDispatchersController(mPhone, mSmsStorageMonitor,
-            mSmsUsageMonitor, mTestableLooper.getLooper());
-        setUpDomainSelectionConnectionAsNotSupported();
+            mSmsUsageMonitor, mTestableLooper.getLooper(), mFeatureFlags);
         processAllMessages();
     }
 
@@ -191,6 +207,7 @@
         mDscFuture = null;
         mSmsDispatchersController.dispose();
         mSmsDispatchersController = null;
+        mFeatureFlags = null;
         super.tearDown();
     }
 
@@ -436,9 +453,11 @@
     public void testSendEmergencyTextWhenDomainPs() throws Exception {
         setUpDomainSelectionConnection();
         setUpSmsDispatchers();
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
 
         mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null,
                 "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true);
@@ -463,12 +482,92 @@
 
     @Test
     @SmallTest
-    public void testNotifyDomainSelectionTerminated() throws Exception {
+    public void testSendEmergencyTextWhenEmergencyStateTrackerReturnsFailure() throws Exception {
         setUpDomainSelectionConnection();
         setUpSmsDispatchers();
+        setUpEmergencyStateTracker(DisconnectCause.OUT_OF_SERVICE);
+
+        mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null,
+                "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
+
+        // Verify the domain selection requested regardless of the result of EmergencyStateTracker.
+        verify(mEmergencySmsDsc).requestDomainSelection(any(), any());
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifySmsSentToEmergencyStateTracker() throws Exception {
+        setUpDomainSelectionEnabled(true);
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
+
+        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L);
+        processAllMessages();
+
+        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
+        verify(mEmergencyStateTracker).endSms(eq("1"), eq(true));
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifySmsSentToEmergencyStateTrackerWithNonEmergencyNumber() throws Exception {
+        setUpDomainSelectionEnabled(true);
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
+
+        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("1234", 1L);
+        processAllMessages();
+
+        verify(mTelephonyManager).isEmergencyNumber(eq("1234"));
+        verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean());
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifySmsSentToEmergencyStateTrackerWithoutEmergencyStateTracker()
+            throws Exception {
+        setUpDomainSelectionEnabled(true);
+        mSmsDispatchersController.testNotifySmsSentToEmergencyStateTracker("911", 1L);
+
+        verify(mTelephonyManager, never()).isEmergencyNumber(anyString());
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifySmsSentFailedToEmergencyStateTracker() throws Exception {
+        setUpDomainSelectionEnabled(true);
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
+
+        mSmsDispatchersController.testNotifySmsSentFailedToEmergencyStateTracker("911", 1L);
+        processAllMessages();
+
+        verify(mTelephonyManager).isEmergencyNumber(eq("911"));
+        verify(mEmergencyStateTracker).endSms(eq("1"), eq(false));
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifySmsSentFailedToEmergencyStateTrackerWithNonEmergencyNumber()
+            throws Exception {
+        setUpDomainSelectionEnabled(true);
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
+
+        mSmsDispatchersController.testNotifySmsSentFailedToEmergencyStateTracker("1234", 1L);
+        processAllMessages();
+
+        verify(mTelephonyManager).isEmergencyNumber(eq("1234"));
+        verify(mEmergencyStateTracker, never()).endSms(anyString(), anyBoolean());
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifyDomainSelectionTerminatedWhenImsAvailableAndNormalSms() throws Exception {
+        setUpDomainSelectionConnection();
+        setUpSmsDispatchers();
+        when(mImsSmsDispatcher.isAvailable()).thenReturn(true);
 
         mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null,
                 "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -483,10 +582,7 @@
 
         DomainSelectionConnection.DomainSelectionConnectionCallback callback = captor.getValue();
         assertNotNull(callback);
-
-        mSmsDispatchersController.post(() -> {
-            callback.onSelectionTerminated(DisconnectCause.LOCAL);
-        });
+        callback.onSelectionTerminated(DisconnectCause.LOCAL);
         processAllMessages();
 
         verify(mSmsDsc, never()).finishSelection();
@@ -494,13 +590,49 @@
         assertFalse(holder.isDomainSelectionRequested());
         assertEquals(0, holder.getPendingRequests().size());
 
-        // We can use the IntentReceiver for receiving the sent result, but it can be reported as
-        // a flaky test since sometimes broadcasts can take a long time if the system is under load.
-        // At this point, we couldn't use the PendingIntent as a mock because it's a final class
-        // so this test checks the method in the IActivityManager when the PendingIntent#send(int)
-        // is called.
-        verify(mIActivityManager).sendIntentSender(any(), any(), any(),
-                eq(SmsManager.RESULT_ERROR_GENERIC_FAILURE), any(), any(), any(), any(), any());
+        verify(mImsSmsDispatcher).sendText(eq("1111"), eq("2222"), eq("text"), eq(mSentIntent),
+                any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false),
+                eq(1L), eq(false));
+    }
+
+    @Test
+    @SmallTest
+    public void testNotifyDomainSelectionTerminatedWhenImsNotAvailableAndEmergencySms()
+            throws Exception {
+        setUpDomainSelectionConnection();
+        setUpSmsDispatchers();
+        setUpEmergencyStateTracker(DisconnectCause.NOT_DISCONNECTED);
+        when(mImsSmsDispatcher.isAvailable()).thenReturn(false);
+        when(mImsSmsDispatcher.isEmergencySmsSupport(anyString())).thenReturn(true);
+
+        mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null,
+                "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
+
+        SmsDispatchersController.DomainSelectionConnectionHolder holder =
+                mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true);
+        ArgumentCaptor<DomainSelectionConnection.DomainSelectionConnectionCallback> captor =
+                ArgumentCaptor.forClass(
+                        DomainSelectionConnection.DomainSelectionConnectionCallback.class);
+        verify(mEmergencySmsDsc).requestDomainSelection(any(), captor.capture());
+        assertNotNull(holder);
+        assertNotNull(holder.getConnection());
+        assertTrue(holder.isDomainSelectionRequested());
+        assertEquals(1, holder.getPendingRequests().size());
+
+        DomainSelectionConnection.DomainSelectionConnectionCallback callback = captor.getValue();
+        assertNotNull(callback);
+        callback.onSelectionTerminated(DisconnectCause.LOCAL);
+        processAllMessages();
+
+        verify(mEmergencySmsDsc, never()).finishSelection();
+        assertNull(holder.getConnection());
+        assertFalse(holder.isDomainSelectionRequested());
+        assertEquals(0, holder.getPendingRequests().size());
+
+        verify(mImsSmsDispatcher).sendText(eq("911"), eq("2222"), eq("text"), eq(mSentIntent),
+                any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false),
+                eq(1L), eq(false));
     }
 
     @Test
@@ -511,6 +643,7 @@
 
         mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null,
                 "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -521,6 +654,7 @@
 
         mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null,
                 "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
 
         verify(mSmsDsc).requestDomainSelection(any(), any());
         assertNotNull(holder.getConnection());
@@ -539,6 +673,23 @@
         assertEquals(0, holder.getPendingRequests().size());
     }
 
+    @Test
+    @SmallTest
+    public void testSendTextWhenFeatureFlagDisabledForSmsDomainSelection() throws Exception {
+        setUpDomainSelectionConnection();
+        setUpSmsDispatchers();
+        when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(false);
+
+        mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null,
+                "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
+
+        // Expect that the domain selection logic will not be executed.
+        SmsDispatchersController.DomainSelectionConnectionHolder holder =
+                mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
+        assertNull(holder);
+    }
+
     private void switchImsSmsFormat(int phoneType) {
         mSimulatedCommands.setImsRegistrationState(new int[]{1, phoneType});
         mSimulatedCommands.notifyImsNetworkStateChanged();
@@ -553,7 +704,7 @@
         assertTrue(mSmsDispatchersController.setImsManager(imsManager));
     }
 
-    private void setUpDomainSelectionConnectionAsNotSupported() {
+    private void setUpDomainSelectionEnabled(boolean enabled) {
         mSmsDispatchersController.setDomainSelectionResolverProxy(
                 new SmsDispatchersController.DomainSelectionResolverProxy() {
                     @Override
@@ -566,9 +717,10 @@
 
                     @Override
                     public boolean isDomainSelectionSupported() {
-                        return false;
+                        return true;
                     }
                 });
+        when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(enabled);
     }
 
     private void setUpDomainSelectionConnection()  {
@@ -589,6 +741,7 @@
                         return true;
                     }
                 });
+        when(mFeatureFlags.smsDomainSelectionEnabled()).thenReturn(true);
 
         mDscFuture = new CompletableFuture<>();
         when(mSmsDsc.requestDomainSelection(
@@ -620,6 +773,18 @@
                         | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT);
     }
 
+    private void setUpEmergencyStateTracker(int result) throws Exception {
+        mEmergencySmsFuture = new CompletableFuture<Integer>();
+        mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class);
+        replaceInstance(SmsDispatchersController.class, "mEmergencyStateTracker",
+                mSmsDispatchersController, mEmergencyStateTracker);
+        when(mEmergencyStateTracker.startEmergencySms(any(Phone.class), anyString(), anyBoolean()))
+                .thenReturn(mEmergencySmsFuture);
+        doNothing().when(mEmergencyStateTracker).endSms(anyString(), anyBoolean());
+        mEmergencySmsFuture.complete(result);
+        when(mTelephonyManager.isEmergencyNumber(eq("911"))).thenReturn(true);
+    }
+
     private void sendDataWithDomainSelection(@NetworkRegistrationInfo.Domain int domain,
             boolean isCdmaMo) throws Exception {
         setUpDomainSelectionConnection();
@@ -628,6 +793,7 @@
         byte[] data = new byte[] { 0x01 };
         mSmsDispatchersController.testSendData(
                 "test-app", "1111", "2222", 8080, data, mSentIntent, null, false);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -663,6 +829,7 @@
 
         mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null,
                 "test-app", false, 0, false, 10, false, 1L, false);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -704,6 +871,7 @@
         ArrayList<PendingIntent> deliveryIntents = new ArrayList<>();
         mSmsDispatchersController.testSendMultipartText("1111", "2222", parts, sentIntents,
                 deliveryIntents, null, "test-app", false, 0, false, 10, 1L);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -746,6 +914,7 @@
         replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker, smsFormat);
 
         mSmsDispatchersController.sendRetrySms(mTracker);
+        processAllMessages();
 
         SmsDispatchersController.DomainSelectionConnectionHolder holder =
                 mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false);
@@ -782,6 +951,7 @@
         mTracker.mUsesImsServiceForIms = true;
 
         mSmsDispatchersController.sendRetrySms(mTracker);
+        processAllMessages();
 
         verify(mSmsDsc, never()).requestDomainSelection(any(), any());
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index d304f5c..435763b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -108,6 +108,7 @@
 import com.android.internal.telephony.data.LinkBandwidthEstimator;
 import com.android.internal.telephony.data.PhoneSwitcher;
 import com.android.internal.telephony.emergency.EmergencyNumberTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
 import com.android.internal.telephony.imsphone.ImsNrSaModeHandler;
 import com.android.internal.telephony.imsphone.ImsPhone;
@@ -183,6 +184,7 @@
     }
 
     // Mocked classes
+    protected FeatureFlags mFeatureFlags;
     protected GsmCdmaPhone mPhone;
     protected GsmCdmaPhone mPhone2;
     protected ImsPhone mImsPhone;
@@ -421,6 +423,7 @@
     protected void setUp(String tag) throws Exception {
         TAG = tag;
         enableStrictMode();
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
         mPhone = Mockito.mock(GsmCdmaPhone.class);
         mPhone2 = Mockito.mock(GsmCdmaPhone.class);
         mImsPhone = Mockito.mock(ImsPhone.class);
@@ -590,7 +593,7 @@
         doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory)
                 .makeIccPhoneBookInterfaceManager(nullable(Phone.class));
         doReturn(mDisplayInfoController).when(mTelephonyComponentFactory)
-                .makeDisplayInfoController(nullable(Phone.class));
+                .makeDisplayInfoController(nullable(Phone.class), any(FeatureFlags.class));
         doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory)
                 .makeWspTypeDecoder(nullable(byte[].class));
         doReturn(mImsCT).when(mTelephonyComponentFactory)
@@ -610,7 +613,7 @@
         doReturn(mCarrierActionAgent).when(mTelephonyComponentFactory)
                 .makeCarrierActionAgent(nullable(Phone.class));
         doReturn(mDeviceStateMonitor).when(mTelephonyComponentFactory)
-                .makeDeviceStateMonitor(nullable(Phone.class));
+                .makeDeviceStateMonitor(nullable(Phone.class), any(FeatureFlags.class));
         doReturn(mAccessNetworksManager).when(mTelephonyComponentFactory)
                 .makeAccessNetworksManager(nullable(Phone.class), any(Looper.class));
         doReturn(mNitzStateMachine).when(mTelephonyComponentFactory)
@@ -625,6 +628,7 @@
         doReturn(mDataProfileManager).when(mTelephonyComponentFactory)
                 .makeDataProfileManager(any(Phone.class), any(DataNetworkController.class),
                         any(DataServiceManager.class), any(Looper.class),
+                        any(FeatureFlags.class),
                         any(DataProfileManager.DataProfileManagerCallback.class));
 
         //mPhone
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java
index b6d77e9..98d3ce5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java
@@ -154,6 +154,9 @@
         assertTrue(createApnSetting(
                 ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_EMERGENCY)
                 .canHandleType(ApnSetting.TYPE_EMERGENCY));
+        assertTrue(createApnSetting(
+                ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_RCS | ApnSetting.TYPE_EMERGENCY)
+                .canHandleType(ApnSetting.TYPE_RCS));
         assertFalse(createApnSetting(ApnSetting.TYPE_ALL)
                 .canHandleType(ApnSetting.TYPE_MCX));
         assertTrue(createApnSetting(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
index 3cc6a8b..4fcf620 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java
@@ -52,7 +52,7 @@
         super.setUp(getClass().getSimpleName());
         mBundle = mContextFixture.getCarrierConfigBundle();
         when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle);
-        mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper());
+        mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper(), mFeatureFlags);
         logd("DataConfigManagerTest -Setup!");
     }
 
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 5e7213b..a09994b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java
@@ -150,6 +150,7 @@
     // Events
     private static final int EVENT_SIM_STATE_CHANGED = 9;
     private static final int EVENT_REEVALUATE_EXISTING_DATA_NETWORKS = 16;
+    private static final int EVENT_SERVICE_STATE_CHANGED = 17;
     private static final int EVENT_VOICE_CALL_ENDED = 18;
     private static final int EVENT_SUBSCRIPTION_OVERRIDE = 23;
 
@@ -209,6 +210,8 @@
                     .setMaxConns(321)
                     .setWaitTime(456)
                     .setMaxConnsTime(789)
+                    .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE
+                            | ApnSetting.INFRASTRUCTURE_CELLULAR)
                     .build())
             .setPreferred(false)
             .build();
@@ -401,6 +404,17 @@
             .setPreferred(false)
             .build();
 
+    private final DataProfile mNtnDataProfile = new DataProfile.Builder()
+            .setApnSetting(new ApnSetting.Builder()
+                    .setEntryName("ntn")
+                    .setApnName("ntn")
+                    .setApnTypeBitmask(ApnSetting.TYPE_RCS)
+                    .setCarrierEnabled(true)
+                    .setInfrastructureBitmask(ApnSetting.INFRASTRUCTURE_SATELLITE)
+                    .build())
+            .setPreferred(false)
+            .build();
+
     /** Data call response map. The first key is the transport type, the second key is the cid. */
     private final Map<Integer, Map<Integer, DataCallResponse>> mDataCallResponses = new HashMap<>();
 
@@ -599,7 +613,7 @@
         doReturn(ss).when(mSST).getServiceState();
         doReturn(ss).when(mPhone).getServiceState();
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
     }
 
@@ -904,7 +918,8 @@
         List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile,
                 mGeneralPurposeDataProfileAlternative, mImsCellularDataProfile,
                 mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile,
-                mTetheringDataProfile);
+                mTetheringDataProfile, mMmsOnWlanDataProfile, mLowLatencyDataProfile,
+                mNtnDataProfile);
 
         doAnswer(invocation -> {
             DataProfile dp = (DataProfile) invocation.getArguments()[0];
@@ -935,23 +950,30 @@
             TelephonyNetworkRequest networkRequest =
                     (TelephonyNetworkRequest) invocation.getArguments()[0];
             int networkType = (int) invocation.getArguments()[1];
-            boolean ignorePermanentFailure = (boolean) invocation.getArguments()[2];
+            boolean isNtn = (boolean) invocation.getArguments()[2];
+            boolean ignorePermanentFailure = (boolean) invocation.getArguments()[3];
 
             for (DataProfile dataProfile : profiles) {
-                if (dataProfile.canSatisfy(networkRequest.getCapabilities())
-                        && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0
-                        || (dataProfile.getApnSetting().getNetworkTypeBitmask()
+                ApnSetting apnSetting = dataProfile.getApnSetting();
+                if (apnSetting != null
+                        && dataProfile.canSatisfy(networkRequest.getCapabilities())
+                        && (apnSetting.getNetworkTypeBitmask() == 0
+                        || (apnSetting.getNetworkTypeBitmask()
                         & ServiceState.getBitmaskForTech(networkType)) != 0)
-                        && (ignorePermanentFailure || (dataProfile.getApnSetting() != null
-                        && !dataProfile.getApnSetting().getPermanentFailed()))) {
+                        && ((isNtn && apnSetting.isForInfrastructure(
+                                ApnSetting.INFRASTRUCTURE_SATELLITE))
+                        || ((!isNtn && apnSetting.isForInfrastructure(
+                                ApnSetting.INFRASTRUCTURE_CELLULAR))))
+                        && (ignorePermanentFailure || !apnSetting.getPermanentFailed())) {
                     return dataProfile;
                 }
             }
             logd("Cannot find data profile to satisfy " + networkRequest + ", network type="
-                    + TelephonyManager.getNetworkTypeName(networkType));
+                    + TelephonyManager.getNetworkTypeName(networkType) + ", ignorePermanentFailure="
+                    + ignorePermanentFailure + ", isNtn=" + isNtn);
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean());
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(anyInt());
@@ -1233,7 +1255,7 @@
                     + TelephonyManager.getNetworkTypeName(networkType));
             return null;
         }).when(mDataProfileManager).getDataProfileForNetworkRequest(
-                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean());
+                any(TelephonyNetworkRequest.class), anyInt(), anyBoolean(), anyBoolean());
 
         // verify the network still connects
         verify(mMockedDataNetworkControllerCallback).onConnectedInternetDataNetworksChanged(any());
@@ -1278,7 +1300,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean());
+                        anyBoolean(), anyBoolean());
 
         NetworkCapabilities netCaps = new NetworkCapabilities();
         netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
@@ -1493,7 +1515,7 @@
         // Now RAT changes from UMTS to GSM
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM),
-                anyBoolean());
+                anyBoolean(), anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyAllDataDisconnected();
@@ -1507,14 +1529,14 @@
         // Now RAT changes from GSM to UMTS
         doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS),
-                anyBoolean());
+                anyBoolean(), anyBoolean());
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
         verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
         doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean());
+                        anyBoolean(), anyBoolean());
         // Now RAT changes from UMTS to LTE
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME);
@@ -3509,7 +3531,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean());
+                        anyBoolean(), anyBoolean());
 
         NetworkCapabilities netCaps = new NetworkCapabilities();
         netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
@@ -3553,8 +3575,12 @@
 
     @Test
     public void testNonVoPStoVoPSImsSetup() throws Exception {
-        // Even allow lingering when NoVops, should have no effect on NoVops -> Vops
-        mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
+        doReturn(true).when(mFeatureFlags).allowMmtelInNonVops();
+        mDataNetworkControllerUT.getDataSettingsManager().setDataRoamingEnabled(true);
+        // Config that allows non-vops bring up when Roaming
+        mCarrierConfig.putIntArray(CarrierConfigManager.Ims
+                .KEY_IMS_PDN_ENABLED_IN_NO_VOPS_SUPPORT_INT_ARRAY, new int[]
+                {CarrierConfigManager.Ims.NETWORK_TYPE_ROAMING});
         carrierConfigChanged();
 
         // VOPS not supported
@@ -3574,6 +3600,30 @@
         processAllMessages();
         verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
+        // Verify bring up in Home is not allowed.
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        processAllMessages();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+        // Verify bring up in Roaming is allowed.
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, dsri);
+        processAllMessages();
+        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
+                NetworkCapabilities.NET_CAPABILITY_MMTEL);
+
+        // Verify the roaming network survives network re-evaluation.
+        mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)
+                .sendToTarget();
+        processAllMessages();
+
+        // Service state changed to Home, non-vops area is no longer allowed
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        processAllMessages();
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
         // VoPS supported
         dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4149,8 +4199,6 @@
 
     @Test
     public void testHandoverDataNetworkNonVops() throws Exception {
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4158,36 +4206,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         mDataNetworkControllerUT.addNetworkRequest(
@@ -4216,8 +4241,6 @@
         mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
         carrierConfigChanged();
 
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4225,36 +4248,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         mDataNetworkControllerUT.addNetworkRequest(
@@ -4280,8 +4280,6 @@
 
     @Test
     public void testNonMmtelImsHandoverDataNetworkNonVops() throws Exception {
-        ServiceState ss = new ServiceState();
-
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -4290,35 +4288,13 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // Bring up the IMS network that does not require MMTEL
@@ -4326,7 +4302,7 @@
                 createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS));
         processAllMessages();
 
-        // Even though the network request does not have MMTEL, but the network support it, so
+        // Even though the network request does not have MMTEL, the WLAN network support it, so
         // the network capabilities should still have MMTEL.
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
@@ -4340,9 +4316,9 @@
                 any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(),
                 any(), any(), anyBoolean(), any(Message.class));
 
-        // The IMS network should still have IMS and MMTEL.
+        // The IMS network should still have IMS, but MMTEL is removed.
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS);
-        verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMTEL);
+        verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL);
     }
 
     @Test
@@ -4351,8 +4327,6 @@
         mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, true);
         carrierConfigChanged();
 
-        ServiceState ss = new ServiceState();
-
         // VoPS network
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4362,35 +4336,13 @@
                         LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
         doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                 .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
 
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // Bring up the IMS network that does require MMTEL
@@ -4403,7 +4355,6 @@
         verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS,
                 NetworkCapabilities.NET_CAPABILITY_MMTEL);
 
-        ss = new ServiceState();
         // Non VoPS network
         dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
@@ -4413,32 +4364,10 @@
                         LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
                 .build();
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .setDataSpecificInfo(dsri)
-                .build());
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
 
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
-                .build());
-
-        ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
-                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
-                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
-                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
-                .build());
-        processServiceStateRegStateForTest(ss);
-        doReturn(ss).when(mSST).getServiceState();
-        doReturn(ss).when(mPhone).getServiceState();
-
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         processAllMessages();
 
         // The IMS network is alive due to KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL = true
@@ -4642,7 +4571,7 @@
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
                 NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null);
         doReturn(ss).when(mSST).getServiceState();
-        mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget();
+        mDataNetworkControllerUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED).sendToTarget();
         mDataNetworkControllerUT.removeNetworkRequest(request);
         mDataNetworkControllerUT.addNetworkRequest(request);
         processAllMessages();
@@ -4664,7 +4593,7 @@
                 createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mEnterpriseDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean());
+                        anyBoolean(), anyBoolean());
         mDataNetworkControllerUT.addNetworkRequest(new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
@@ -4702,7 +4631,7 @@
                 createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE, tdList));
         doReturn(mLowLatencyDataProfile).when(mDataProfileManager)
                 .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(),
-                        anyBoolean());
+                        anyBoolean(), anyBoolean());
         processAllFutureMessages();
 
         dataNetworkList = getDataNetworks();
@@ -4731,12 +4660,11 @@
                 createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_IMS));
         processAllMessages();
         verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile);
-        verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile);
 
         // Mock the designated MMS profile when WLAN is preferred
         doReturn(mMmsOnWlanDataProfile).when(mDataProfileManager).getDataProfileForNetworkRequest(
                 any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_IWLAN),
-                anyBoolean());
+                anyBoolean(), anyBoolean());
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager,
                 createDataCallResponse(2, DataCallResponse.LINK_STATUS_ACTIVE));
 
@@ -4746,4 +4674,16 @@
         processAllMessages();
         verifyConnectedNetworkHasDataProfile(mMmsOnWlanDataProfile);
     }
+
+    @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));
+        processAllMessages();
+        verifyConnectedNetworkHasDataProfile(mNtnDataProfile);
+    }
 }
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 9235e46..a75a699 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -96,7 +96,6 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class DataNetworkTest extends TelephonyTest {
@@ -428,8 +427,8 @@
         setSuccessfulSetupDataResponse(
                 mMockedWwanDataServiceManager, 123, Collections.emptyList(), mDefaultQos);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -443,7 +442,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), networkCapabilitiesCaptor.capture(), any(), any(),
-                anyInt());
+                any(), anyInt());
         // The very first link properties from telephony is an empty link properties. It will be
         // updated later.
         assertThat(linkPropertiesCaptor.getValue()).isEqualTo(new LinkProperties());
@@ -537,8 +536,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -550,7 +549,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), networkCapabilitiesCaptor.capture(), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         // Make sure the initial network capability has NOT_SUSPENDED
         assertThat(networkCapabilitiesCaptor.getValue().hasCapability(
@@ -614,7 +613,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), networkCapabilitiesCaptor.capture(), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         // Make sure the 2nd network agent was created with NOT_SUSPENDED.
         assertThat(networkCapabilitiesCaptor.getValue().hasCapability(
@@ -633,8 +632,8 @@
                 .build(), mPhone));
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         processAllMessages();
@@ -652,20 +651,7 @@
 
     @Test
     public void testCreateImsDataNetwork() throws Exception {
-        NetworkRequestList networkRequestList = new NetworkRequestList();
-        networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
-                .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
-                .build(), mPhone));
-
-        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
-
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mImsDataProfile, networkRequestList,
-                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                DataAllowedReason.NORMAL, mDataNetworkCallback);
-        replaceInstance(DataNetwork.class, "mDataCallSessionStats",
-                mDataNetworkUT, mDataCallSessionStats);
-        processAllMessages();
+        createImsDataNetwork(true/*isMmtel*/);
 
         ArgumentCaptor<LinkProperties> linkPropertiesCaptor =
                 ArgumentCaptor.forClass(LinkProperties.class);
@@ -674,7 +660,7 @@
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), networkCapabilitiesCaptor.capture(), any(), any(),
-                anyInt());
+                any(), anyInt());
         // The very first link properties from telephony is an empty link properties. It will be
         // updated later.
         assertThat(linkPropertiesCaptor.getValue()).isEqualTo(new LinkProperties());
@@ -686,7 +672,7 @@
                 eq(DataCallResponse.PDU_SESSION_ID_NOT_SET), nullable(NetworkSliceInfo.class),
                 any(TrafficDescriptor.class), eq(true), any(Message.class));
         assertThat(mDataNetworkUT.getId()).isEqualTo(123);
-        assertThat(networkRequestList.get(0).getState())
+        assertThat(mDataNetworkUT.getAttachedNetworkRequestList().get(0).getState())
                 .isEqualTo(TelephonyNetworkRequest.REQUEST_STATE_SATISFIED);
         LinkProperties lp = mDataNetworkUT.getLinkProperties();
         assertThat(lp.getAddresses()).containsExactly(
@@ -742,8 +728,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mEnterpriseDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mEnterpriseDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -776,8 +762,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mUrlccDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mUrlccDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -809,8 +795,8 @@
         );
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mEmbbDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mEmbbDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -843,8 +829,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123, tds);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mCbsDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mCbsDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -875,8 +861,8 @@
                         .getBytes())
         );
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mCbsDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mCbsDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -957,9 +943,10 @@
 
         setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mImsDataProfile, networkRequestList, AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
-                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mImsDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN, DataAllowedReason.NORMAL,
+                mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
                 mDataNetworkUT, mDataCallSessionStats);
         processAllMessages();
@@ -1179,8 +1166,8 @@
 
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1278,8 +1265,8 @@
         doReturn(false).when(mDataSettingsManager).isDataEnabled();
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1321,8 +1308,8 @@
         doReturn(false).when(mDataSettingsManager).isDataRoamingEnabled();
         setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.RESTRICTED_REQUEST, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1428,14 +1415,14 @@
 
     @Test
     public void testNetworkAgentConfig() throws Exception {
-        testCreateImsDataNetwork();
+        createImsDataNetwork(false/*IsMmtel*/);
 
         ArgumentCaptor<NetworkAgentConfig> captor = ArgumentCaptor
                 .forClass(NetworkAgentConfig.class);
 
         verify(mConnectivityManager).registerNetworkAgent(any(), any(NetworkInfo.class),
-                any(LinkProperties.class), any(NetworkCapabilities.class), any(), captor.capture(),
-                anyInt());
+                any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
+                captor.capture(), anyInt());
 
         NetworkAgentConfig networkAgentConfig = captor.getValue();
 
@@ -1454,8 +1441,8 @@
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         NetworkCapabilities caps = mDataNetworkUT.getNetworkCapabilities();
@@ -1518,7 +1505,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)).isTrue();
@@ -1540,14 +1527,15 @@
         // Agent not re-created, so register should be called once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)).isTrue();
     }
 
     @Test
-    public void testMovingToNonVops() throws Exception {
+    public void testMovingToNonVopsRequestedMmtel() throws Exception {
+        createImsDataNetwork(true/*isMmtel*/);
         DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
                 .setNrAvailable(true)
                 .setEnDcAvailable(true)
@@ -1557,7 +1545,6 @@
                 .build();
         serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
                 NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
-        testCreateImsDataNetwork();
 
         assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
@@ -1578,6 +1565,37 @@
     }
 
     @Test
+    public void testNonMmtelImsMovingToNonVops() throws Exception {
+        createImsDataNetwork(false/*isMmtel*/);
+        DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8)
+                .setNrAvailable(true)
+                .setEnDcAvailable(true)
+                .setVopsSupportInfo(new LteVopsSupportInfo(
+                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED,
+                        LteVopsSupportInfo.LTE_STATUS_SUPPORTED))
+                .build();
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+
+        assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue();
+
+        dsri = new DataSpecificRegistrationInfo.Builder(8)
+                .setNrAvailable(true)
+                .setEnDcAvailable(true)
+                .setVopsSupportInfo(new LteVopsSupportInfo(
+                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED,
+                        LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED))
+                .build();
+        logd("Trigger non VoPS");
+        serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri);
+        // MMTEL should be removed to reflect the actual Vops status.
+        assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability(
+                NetworkCapabilities.NET_CAPABILITY_MMTEL)).isFalse();
+    }
+
+    @Test
     public void testCssIndicatorChanged() throws Exception {
         setupDataNetwork();
 
@@ -1709,7 +1727,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
         // The new agent should have the new IP address.
         assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly(
                 InetAddresses.parseNumericAddress(IPV4_ADDRESS1),
@@ -1758,7 +1776,7 @@
         // Agent re-created, so register should be called twice.
         verify(mConnectivityManager, times(2)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 linkPropertiesCaptor.capture(), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
         // The new agent should have the new IP address.
         assertThat(linkPropertiesCaptor.getValue().getAllAddresses()).containsExactly(
                 InetAddresses.parseNumericAddress(IPV6_ADDRESS1));
@@ -1808,8 +1826,8 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
 
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                mInternetDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mInternetDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                 DataAllowedReason.NORMAL, mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1849,7 +1867,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
@@ -1893,7 +1911,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
@@ -1938,7 +1956,7 @@
         // Agent should not be re-created, so register should be called ony once.
         verify(mConnectivityManager, times(1)).registerNetworkAgent(any(), any(NetworkInfo.class),
                 any(LinkProperties.class), any(NetworkCapabilities.class), any(), any(),
-                anyInt());
+                any(), anyInt());
 
         // The network should have IPv6 address now
         assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly(
@@ -1951,8 +1969,8 @@
         networkRequestList.add(new TelephonyNetworkRequest(new NetworkRequest.Builder()
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                 .build(), mPhone));
-        mDataNetworkUT = new DataNetwork(mPhone, Looper.myLooper(), mDataServiceManagers,
-                m5gDataProfile, networkRequestList,
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, m5gDataProfile, networkRequestList,
                 AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
                 mDataNetworkCallback);
         replaceInstance(DataNetwork.class, "mDataCallSessionStats",
@@ -1998,4 +2016,22 @@
         verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT),
                 eq(DataCallResponse.LINK_STATUS_INACTIVE));
     }
+
+    private void createImsDataNetwork(boolean isMmtel) throws Exception {
+        NetworkRequestList networkRequestList = new NetworkRequestList();
+        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));
+
+        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mImsDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+                DataAllowedReason.NORMAL, mDataNetworkCallback);
+        replaceInstance(DataNetwork.class, "mDataCallSessionStats",
+                mDataNetworkUT, mDataCallSessionStats);
+        processAllMessages();
+    }
 }
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 5c7e3ec..f9a11be 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.content.ContentValues;
@@ -53,6 +54,7 @@
 import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
 import com.android.internal.telephony.data.DataProfileManager.DataProfileManagerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -81,6 +83,7 @@
     private static final String IMS_APN = "IMS_APN";
     private static final String TETHERING_APN = "DUN_APN";
     private static final String APN_SET_ID_1_APN = "APN_SET_ID_1_APN";
+    private static final String RCS_APN = "RCS_APN";
     private static final String APN_SET_ID_1_TETHERING_APN = "APN_SET_ID_1_TETHERING_APN";
     private static final String MATCH_ALL_APN_SET_ID_IMS_APN = "MATCH_ALL_APN_SET_ID_IMS_APN";
     private static final String PLMN = "330123";
@@ -93,6 +96,8 @@
 
     private DataProfileManager mDataProfileManagerUT;
 
+    private FeatureFlags mFeatureFlags;
+
     private final ApnSettingContentProvider mApnSettingContentProvider =
             new ApnSettingContentProvider();
 
@@ -132,6 +137,7 @@
                 Telephony.Carriers.CARRIER_ID,
                 Telephony.Carriers.SKIP_464XLAT,
                 Telephony.Carriers.ALWAYS_ON,
+                Telephony.Carriers.INFRASTRUCTURE_BITMASK
         };
 
         private int mPreferredApnSet = 0;
@@ -170,7 +176,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 // default internet data profile for RAT CDMA, to test update preferred data profile
                 new Object[]{
@@ -205,7 +212,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         2,                      // id
@@ -239,7 +247,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         3,                      // id
@@ -273,7 +282,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // alwys_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         4,                      // id
@@ -308,7 +318,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 // This APN entry is created to test de-duping.
                 new Object[]{
@@ -344,7 +355,8 @@
                         DEFAULT_APN_SET_ID,     // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         6,                      // id
@@ -379,7 +391,8 @@
                         APN_SET_ID_1,           // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         7,                      // id
@@ -414,7 +427,8 @@
                         APN_SET_ID_1,           // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
                 },
                 new Object[]{
                         8,                      // id
@@ -449,7 +463,44 @@
                         MATCH_ALL_APN_SET_ID,   // apn_set_id
                         -1,                     // carrier_id
                         -1,                     // skip_464xlat
-                        0                       // always_on
+                        0,                      // always_on
+                        1                       // INFRASTRUCTURE_CELLULAR
+                },
+                new Object[]{
+                        9,                      // id
+                        PLMN,                   // numeric
+                        RCS_APN,                // name
+                        RCS_APN,                // apn
+                        "",                     // proxy
+                        "",                     // port
+                        "",                     // mmsc
+                        "",                     // mmsproxy
+                        "",                     // mmsport
+                        "",                     // user
+                        "",                     // password
+                        -1,                     // authtype
+                        "rcs",                  // types
+                        "IPV4V6",               // protocol
+                        "IPV4V6",               // roaming_protocol
+                        1,                      // carrier_enabled
+                        0,                      // profile_id
+                        1,                      // modem_cognitive
+                        0,                      // max_conns
+                        0,                      // wait_time
+                        0,                      // max_conns_time
+                        0,                      // mtu
+                        1280,                   // mtu_v4
+                        1280,                   // mtu_v6
+                        "",                     // mvno_type
+                        "",                     // mnvo_match_data
+                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
+                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
+                        0,                      // lingering_network_type_bitmask
+                        DEFAULT_APN_SET_ID,     // apn_set_id
+                        -1,                     // carrier_id
+                        -1,                     // skip_464xlat
+                        0,                      // always_on
+                        2                       // INFRASTRUCTURE_SATELLITE
                 }
         );
 
@@ -621,6 +672,7 @@
         logd("DataProfileManagerTest +Setup!");
         super.setUp(getClass().getSimpleName());
         mDataProfileManagerCallback = Mockito.mock(DataProfileManagerCallback.class);
+        mFeatureFlags = Mockito.mock(FeatureFlags.class);
         ((MockContentResolver) mContext.getContentResolver()).addProvider(
                 Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider);
 
@@ -632,7 +684,8 @@
             return null;
         }).when(mDataProfileManagerCallback).invokeFromExecutor(any(Runnable.class));
         mDataProfileManagerUT = new DataProfileManager(mPhone, mDataNetworkController,
-                mMockedWwanDataServiceManager, Looper.myLooper(), mDataProfileManagerCallback);
+                mMockedWwanDataServiceManager, Looper.myLooper(), mFeatureFlags,
+                mDataProfileManagerCallback);
         ArgumentCaptor<DataNetworkControllerCallback> dataNetworkControllerCallbackCaptor =
                 ArgumentCaptor.forClass(DataNetworkControllerCallback.class);
         verify(mDataNetworkController).registerDataNetworkControllerCallback(
@@ -663,7 +716,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -674,7 +727,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
@@ -684,7 +737,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(IMS_APN);
 
@@ -693,7 +746,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dp).isNull();
 
         doReturn(new NetworkRegistrationInfo.Builder()
@@ -706,7 +759,7 @@
                 .build();
         tnr = new TelephonyNetworkRequest(request, mPhone);
         dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_NR, false);
+                TelephonyManager.NETWORK_TYPE_NR, false, false);
         assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
         assertThat(dp.getApnSetting().getApnName()).isEqualTo(TETHERING_APN);
     }
@@ -718,7 +771,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_GSM, false);
+                TelephonyManager.NETWORK_TYPE_GSM, false, false);
         // Should not find data profile due to RAT incompatible.
         assertThat(dp).isNull();
     }
@@ -730,14 +783,14 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         logd("Set setLastSetupTimestamp on " + dataProfile);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
 
         // See if another one can be returned.
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
     }
 
@@ -748,7 +801,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -761,7 +814,7 @@
                 .addEnterpriseId(2), ConnectivityManager.TYPE_NONE,
                 0, NetworkRequest.Type.REQUEST), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -777,7 +830,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -793,7 +846,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting()).isNull();
         OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId());
 
@@ -803,13 +856,28 @@
     }
 
     @Test
+    public void testGetDataProfileForSatellite() {
+        when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+
+        NetworkRequest request = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                .build();
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
+                TelephonyManager.NETWORK_TYPE_LTE, true, false);
+
+        assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue();
+        assertThat(dp.getApnSetting().getApnName()).isEqualTo(RCS_APN);
+    }
+
+    @Test
     public void testSetPreferredDataProfile() {
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         dataProfile.setPreferred(true);
@@ -823,14 +891,14 @@
 
         // Test See if the same one can be returned.
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
 
         // Test Another default internet network connected due to RAT changed. Verify the preferred
         // data profile is updated.
         DataProfile legacyRatDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_CDMA, false);
+                tnr, TelephonyManager.NETWORK_TYPE_CDMA, false, false);
         DataNetwork legacyRatInternetNetwork = Mockito.mock(DataNetwork.class);
         doReturn(legacyRatDataProfile).when(legacyRatInternetNetwork).getDataProfile();
         doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr)))
@@ -849,7 +917,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
                         .build(), mPhone);
         DataProfile dunDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                dunTnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         DataNetwork dunInternetNetwork = Mockito.mock(DataNetwork.class);
         doReturn(dunDataProfile).when(dunInternetNetwork).getDataProfile();
         doReturn(new DataNetworkController.NetworkRequestList(List.of(dunTnr)))
@@ -948,7 +1016,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile).isNull();
 
         // expect default EIMS when SIM absent
@@ -957,7 +1025,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
 
         // expect no default IMS when SIM absent
@@ -966,7 +1034,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile).isEqualTo(null);
 
         // Verify null as initial attached data profile is sent to modem
@@ -996,7 +1064,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile).isNull();
 
         // expect default EIMS when SIM absent
@@ -1005,7 +1073,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos");
 
         // expect no default IMS when SIM absent
@@ -1014,7 +1082,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone);
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile).isEqualTo(null);
 
         // Verify in legacy mode, null IA should NOT be sent to modem
@@ -1049,7 +1117,7 @@
                 new TelephonyNetworkRequest(new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
                         .build(), mPhone),
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN);
     }
 
@@ -1061,7 +1129,7 @@
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         // This should get the merged data profile after deduping.
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
     }
 
@@ -1198,7 +1266,7 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                 .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         assertThat(dataProfile.getApn()).isEqualTo("sos");
         assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos");
@@ -1215,7 +1283,7 @@
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                         .build(), mPhone);
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
         dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
         DataNetwork internetNetwork = Mockito.mock(DataNetwork.class);
@@ -1286,7 +1354,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
@@ -1299,7 +1367,7 @@
 
         // The carrier configured data profile should be the preferred APN after APN reset
         dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
-                tnr, TelephonyManager.NETWORK_TYPE_LTE, false);
+                tnr, TelephonyManager.NETWORK_TYPE_LTE, false, false);
         assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1);
         assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();
     }
@@ -1580,7 +1648,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         // Mark the APN as permanent failed.
         dp.getApnSetting().setPermanentFailed(true);
@@ -1588,7 +1656,7 @@
         // Data profile manager should return a different data profile for setup as the previous
         // data profile has been marked as permanent failed.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false)).isNotEqualTo(dp);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNotEqualTo(dp);
     }
 
     @Test
@@ -1603,7 +1671,7 @@
                 .build();
         TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
         DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false);
+                TelephonyManager.NETWORK_TYPE_LTE, false, false);
 
         // Mark the APN as permanent failed.
         dp.getApnSetting().setPermanentFailed(true);
@@ -1611,7 +1679,7 @@
         // Since preferred APN is already set, and that data profile was marked as permanent failed,
         // so this should result in getting nothing.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
-                TelephonyManager.NETWORK_TYPE_LTE, false)).isNull();
+                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNull();
     }
 
     private void changeSimStateTo(@TelephonyManager.SimState int simState) {
@@ -1632,6 +1700,6 @@
         // Verify the we can get the previously permanent failed data profile again.
         assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(
                 new TelephonyNetworkRequest(request, mPhone),
-                TelephonyManager.NETWORK_TYPE_LTE, false)).isNotNull();
+                TelephonyManager.NETWORK_TYPE_LTE, false, false)).isNotNull();
     }
 }
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java
index 4a2eb38..f5981f7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileTest.java
@@ -179,6 +179,7 @@
         assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_MMS)).isFalse();
         assertThat(dp.canSatisfy(new int[]{NetworkCapabilities.NET_CAPABILITY_INTERNET,
                 NetworkCapabilities.NET_CAPABILITY_MMS})).isFalse();
+        assertThat(dp.canSatisfy(new int[]{NetworkCapabilities.NET_CAPABILITY_RCS})).isFalse();
     }
 
     @Test
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 8372d8f..dd95ff0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java
@@ -158,7 +158,8 @@
         mockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN,
                 mMockedWlanDataServiceManager);
         mDataRetryManagerUT = new DataRetryManager(mPhone, mDataNetworkController,
-                mockedDataServiceManagers, Looper.myLooper(), mDataRetryManagerCallbackMock);
+                mockedDataServiceManagers, Looper.myLooper(), mFeatureFlags,
+                mDataRetryManagerCallbackMock);
 
         ArgumentCaptor<DataConfigManagerCallback> dataConfigManagerCallbackCaptor =
                 ArgumentCaptor.forClass(DataConfigManagerCallback.class);
@@ -340,29 +341,30 @@
 
     @Test
     public void testDataSetupUnthrottling() throws Exception {
-        testDataSetupRetryNetworkSuggestedNeverRetry();
+        doReturn(true).when(mFeatureFlags).unthrottleCheckTransport();
+        NetworkRequest request = new NetworkRequest.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+                .build();
+        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
+        DataNetworkController.NetworkRequestList
+                networkRequestList = new DataNetworkController.NetworkRequestList(tnr);
+        mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN, networkRequestList, 123,
+                456);
+        mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile3,
+                AccessNetworkConstants.TRANSPORT_TYPE_WLAN, networkRequestList, 123,
+                456);
+        processAllFutureMessages();
         Mockito.clearInvocations(mDataRetryManagerCallbackMock);
+
         DataNetworkController.NetworkRequestList mockNrl = Mockito.mock(
                 DataNetworkController.NetworkRequestList.class);
         Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries");
         field.setAccessible(true);
         List<DataRetryEntry> mDataRetryEntries =
                 (List<DataRetryEntry>) field.get(mDataRetryManagerUT);
+        assertThat(mDataRetryEntries.size()).isEqualTo(2);
 
-        // schedule 2 setup retries
-        DataSetupRetryEntry scheduledRetry1 = new DataSetupRetryEntry.Builder<>()
-                .setDataProfile(mDataProfile3)
-                .setNetworkRequestList(mockNrl)
-                .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
-                .setSetupRetryType(1)
-                .build();
-        DataSetupRetryEntry scheduledRetry2 = new DataSetupRetryEntry.Builder<>()
-                .setNetworkRequestList(mockNrl)
-                .setDataProfile(mDataProfile3)
-                .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
-                .setSetupRetryType(1)
-                .build();
-        mDataRetryEntries.addAll(List.of(scheduledRetry1, scheduledRetry2));
         // Suppose we set the data profile as permanently failed.
         mDataProfile3.getApnSetting().setPermanentFailed(true);
 
@@ -408,8 +410,21 @@
         assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         // check mDataProfile3-WWAN retry is cancelled, but not the WLAN
-        assertThat(scheduledRetry1.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED);
-        assertThat(scheduledRetry2.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
+        assertThat(mDataRetryEntries.size()).isEqualTo(3);
+        for (DataRetryEntry retry : mDataRetryEntries) {
+            DataSetupRetryEntry setupRetry = (DataSetupRetryEntry) retry;
+            if (setupRetry.transport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+                if (setupRetry.retryDelayMillis == 0) {
+                    assertThat(setupRetry.getState())
+                            .isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
+                } else {
+                    assertThat(setupRetry.getState())
+                            .isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED);
+                }
+            } else {
+                assertThat(setupRetry.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
+            }
+        }
     }
 
     @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 9e78afd..94fd934 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java
@@ -679,6 +679,37 @@
     }
 
     @Test
+    public void testSetAutoSelectedValidationFeatureNotSupported() throws Exception {
+        doReturn(false).when(mCellularNetworkValidator).isValidationFeatureSupported();
+        initialize();
+
+        // Phone 0 has sub 1, phone 1 has sub 2.
+        // Sub 1 is default data sub.
+        // Both are active subscriptions are active sub, as they are in both active slots.
+        setSlotIndexToSubId(0, 1);
+        setSlotIndexToSubId(1, 2);
+        setDefaultDataSubId(1);
+
+        doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService
+                .getSubscriptionInfoInternal(2)).setOpportunistic(1).build())
+                .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2);
+
+        mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1);
+        processAllMessages();
+        mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2);
+        processAllMessages();
+        assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId());
+
+        // Switch to the default sub, verify AutoSelectedDataSubId is the default value.
+        clearInvocations(mSetOpptDataCallback1);
+        mPhoneSwitcherUT.trySetOpportunisticDataSubscription(SubscriptionManager
+                .DEFAULT_SUBSCRIPTION_ID, true, mSetOpptDataCallback1);
+        processAllMessages();
+        assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+                mPhoneSwitcherUT.getAutoSelectedDataSubId());
+    }
+
+    @Test
     @SmallTest
     public void testSetPreferredDataModemCommand() throws Exception {
         doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported();
@@ -1357,7 +1388,7 @@
                 .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2);
 
         // Switch to primary before a primary is selected/inactive.
-        setDefaultDataSubId(-1);
+        setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
         mPhoneSwitcherUT.trySetOpportunisticDataSubscription(
                 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1);
         processAllMessages();
@@ -1992,7 +2023,7 @@
         doReturn(true).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired();
     }
 
-    private void setDefaultDataSubId(int defaultDataSub) throws Exception {
+    private void setDefaultDataSubId(int defaultDataSub) {
         mDefaultDataSub = defaultDataSub;
         doReturn(mDefaultDataSub).when(mSubscriptionManagerService).getDefaultDataSubId();
         for (Phone phone : mPhones) {
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 9752885..26a9fde 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkRequestTest.java
@@ -87,6 +87,24 @@
             .setMaxConnsTime(789)
             .build();
 
+    private static final ApnSetting RCS_APN_SETTING = new ApnSetting.Builder()
+            .setId(2165)
+            .setOperatorNumeric("12345")
+            .setEntryName("rcs")
+            .setApnName("rcs")
+            .setUser("user")
+            .setPassword("passwd")
+            .setApnTypeBitmask(ApnSetting.TYPE_RCS)
+            .setProtocol(ApnSetting.PROTOCOL_IPV6)
+            .setRoamingProtocol(ApnSetting.PROTOCOL_IP)
+            .setCarrierEnabled(true)
+            .setNetworkTypeBitmask(0)
+            .setProfileId(1234)
+            .setMaxConns(321)
+            .setWaitTime(456)
+            .setMaxConnsTime(789)
+            .build();
+
     @Before
     public void setUp() throws Exception {
         logd("TelephonyNetworkRequestTest +Setup!");
@@ -211,6 +229,20 @@
                 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
                 .build();
         assertThat(internetRequest.canBeSatisfiedBy(caps)).isTrue();
+
+        TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                        .build(), mPhone);
+        caps = new NetworkCapabilities.Builder()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+                .build();
+        assertThat(rcsRequest.canBeSatisfiedBy(caps)).isTrue();
     }
 
     @Test
@@ -223,17 +255,25 @@
                 new NetworkRequest.Builder()
                         .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
                         .build(), mPhone);
+        TelephonyNetworkRequest rcsRequest = new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_RCS)
+                        .build(), mPhone);
         DataProfile internetDataProfile = new DataProfile.Builder()
                 .setApnSetting(INTERNET_APN_SETTING)
                 .build();
         DataProfile mmsDataProfile = new DataProfile.Builder()
                 .setApnSetting(MMS_APN_SETTING)
                 .build();
+        DataProfile rcsDataProfile = new DataProfile.Builder()
+                .setApnSetting(RCS_APN_SETTING)
+                .build();
 
         assertThat(internetRequest.canBeSatisfiedBy(internetDataProfile)).isTrue();
         assertThat(internetRequest.canBeSatisfiedBy(mmsDataProfile)).isFalse();
         assertThat(mmsRequest.canBeSatisfiedBy(internetDataProfile)).isFalse();
         assertThat(mmsRequest.canBeSatisfiedBy(mmsDataProfile)).isTrue();
+        assertThat(rcsRequest.canBeSatisfiedBy(rcsDataProfile)).isTrue();
     }
 
     @Test
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 ce59cc6..a2a55ee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java
@@ -131,19 +131,16 @@
     public void testWwanSelectorCallbackAsync() throws Exception {
         mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true,
                 mDomainSelectionController);
-        replaceInstance(DomainSelectionConnection.class, "mWwanSelectedExecutor",
-                mDsc, new Executor() {
-                    public void execute(Runnable command) {
-                        command.run();
-                    }
-                });
 
         TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback();
 
         assertNotNull(transportCallback);
 
+        replaceInstance(DomainSelectionConnection.class, "mLooper",
+                mDsc, mTestableLooper.getLooper());
         Consumer<WwanSelectorCallback> consumer = Mockito.mock(Consumer.class);
         transportCallback.onWwanSelected(consumer);
+        processAllMessages();
 
         verify(consumer).accept(any());
     }
@@ -171,6 +168,7 @@
         Consumer<EmergencyRegResult> consumer = Mockito.mock(Consumer.class);
 
         wwanCallback.onRequestEmergencyNetworkScan(preferredNetworks, scanType, null, consumer);
+        processAllMessages();
 
         ArgumentCaptor<Handler> handlerCaptor = ArgumentCaptor.forClass(Handler.class);
         ArgumentCaptor<Integer> eventCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -220,11 +218,13 @@
         CancellationSignal signal = new CancellationSignal();
         wwanCallback.onRequestEmergencyNetworkScan(new ArrayList<>(),
                 SCAN_TYPE_NO_PREFERENCE, signal, Mockito.mock(Consumer.class));
+        processAllMessages();
 
         verify(mPhone).registerForEmergencyNetworkScan(any(), anyInt(), any());
         verify(mPhone).triggerEmergencyNetworkScan(any(), anyInt(), any());
 
         signal.cancel();
+        processAllMessages();
 
         verify(mPhone).cancelEmergencyNetworkScan(eq(false), any());
     }
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 7c1ac2c..0be1927 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java
@@ -869,7 +869,7 @@
         assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED),
                 Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
 
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
 
         verify(phone0).exitEmergencyMode(any(Message.class));
         assertFalse(emergencyStateTracker.isInEmergencyMode());
@@ -1316,7 +1316,7 @@
 
         assertTrue(emergencyStateTracker.isInEmergencyMode());
 
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
         processAllMessages();
 
         assertFalse(emergencyStateTracker.isInEmergencyMode());
@@ -1353,7 +1353,7 @@
         assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED),
                 Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
 
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
 
         assertTrue(emergencyStateTracker.isInEmergencyMode());
 
@@ -1400,7 +1400,7 @@
         assertTrue(emergencyStateTracker.isInEcm());
         assertFalse(emergencyStateTracker.isInEmergencyCall());
 
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
         processAllMessages();
 
         verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class));
@@ -1455,7 +1455,7 @@
 
         emergencyStateTracker.onEmergencyTransportChanged(
                 EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN);
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
         processAllMessages();
 
         // Enter emergency callback mode and emergency mode changed by SMS end.
@@ -1502,7 +1502,7 @@
         assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED),
                 Integer.valueOf(DisconnectCause.NOT_DISCONNECTED));
 
-        emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber());
+        emergencyStateTracker.endSms(TEST_SMS_ID, true);
 
         assertTrue(emergencyStateTracker.isInEmergencyMode());
 
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
index 504782b..7c7c5b2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java
@@ -308,12 +308,73 @@
         mImsStats.onImsCapabilitiesChanged(
                 REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
 
+        mImsStats.onImsUnregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+
         mImsStats.incTimeMillis(2000L);
         mImsStats.conclude();
 
-        // No atom should be generated
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
+        assertEquals(CARRIER1_ID, termination.carrierId);
+        assertFalse(termination.isMultiSim);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+        assertTrue(termination.setupFailed);
+        assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+        assertEquals(999, termination.extraCode);
+        assertEquals("Timeout", termination.extraMessage);
+
+        // Registering duration should be counted
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+        assertEquals(2000L, stats.unregisteredMillis);
+        verifyNoMoreInteractions(mPersistAtomsStorage);
+    }
+
+    @Test
+    @SmallTest
+    public void conclude_registering() throws Exception {
+        // IMS over LTE
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_VOICE,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_VIDEO,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_UT,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onSetFeatureResponse(
+                CAPABILITY_TYPE_SMS,
+                REGISTRATION_TECH_LTE,
+                ProvisioningManager.PROVISIONING_VALUE_ENABLED);
+        mImsStats.onImsCapabilitiesChanged(
+                REGISTRATION_TECH_LTE, new MmTelCapabilities(CAPABILITY_TYPE_ALL));
+
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WLAN);
+
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.conclude();
+
+        // Registering duration should be counted
         ArgumentCaptor<ImsRegistrationStats> captor =
                 ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture());
+        ImsRegistrationStats stats = captor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, stats.rat);
+        assertEquals(2000L, stats.registeringMillis);
         verifyNoMoreInteractions(mPersistAtomsStorage);
     }
 
@@ -510,6 +571,57 @@
 
     @Test
     @SmallTest
+    public void onImsRegistered_afterImsRegistering() throws Exception {
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.onImsRegistered(TRANSPORT_TYPE_WWAN);
+
+        // Registering duration should be counted
+        ArgumentCaptor<ImsRegistrationStats> captor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(captor.capture());
+        ImsRegistrationStats stats = captor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
+        assertEquals(0L, stats.registeredMillis);
+        assertEquals(2000L, stats.registeringMillis);
+    }
+
+    @Test
+    @SmallTest
+    public void onImsRegistering_afterImsUnregistered() throws Exception {
+        mImsStats.onImsUnregistered(
+                new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
+        mImsStats.incTimeMillis(2000L);
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
+
+        // Atom with termination info should be generated
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationTermination.class);
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
+        assertEquals(CARRIER1_ID, termination.carrierId);
+        assertFalse(termination.isMultiSim);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
+        assertTrue(termination.setupFailed);
+        assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
+        assertEquals(999, termination.extraCode);
+        assertEquals("Timeout", termination.extraMessage);
+
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, stats.rat);
+        assertEquals(2000L, stats.unregisteredMillis);
+        verifyNoMoreInteractions(mPersistAtomsStorage);
+    }
+
+    @Test
+    @SmallTest
     public void onImsUnregistered_setupFailure() throws Exception {
         mImsStats.onImsUnregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
@@ -521,7 +633,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(999, termination.extraCode);
@@ -532,16 +644,26 @@
     @Test
     @SmallTest
     public void onImsUnregistered_setupFailureWithProgress() throws Exception {
-        mImsStats.onImsRegistering(REGISTRATION_TECH_LTE);
+        mImsStats.onImsRegistering(TRANSPORT_TYPE_WWAN);
         mImsStats.incTimeMillis(2000L);
         mImsStats.onImsUnregistered(
                 new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 999, "Timeout"));
 
         // Atom with termination info should be generated
-        ArgumentCaptor<ImsRegistrationTermination> captor =
+        ArgumentCaptor<ImsRegistrationStats> statsCaptor =
+                ArgumentCaptor.forClass(ImsRegistrationStats.class);
+        verify(mPersistAtomsStorage).addImsRegistrationStats(statsCaptor.capture());
+        ImsRegistrationStats stats = statsCaptor.getValue();
+        assertEquals(CARRIER1_ID, stats.carrierId);
+        assertEquals(0, stats.simSlotIndex);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.rat);
+        assertEquals(0L, stats.registeredMillis);
+        assertEquals(2000L, stats.registeringMillis);
+
+        ArgumentCaptor<ImsRegistrationTermination> terminationCaptor =
                 ArgumentCaptor.forClass(ImsRegistrationTermination.class);
-        verify(mPersistAtomsStorage).addImsRegistrationTermination(captor.capture());
-        ImsRegistrationTermination termination = captor.getValue();
+        verify(mPersistAtomsStorage).addImsRegistrationTermination(terminationCaptor.capture());
+        ImsRegistrationTermination termination = terminationCaptor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
         assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
@@ -604,7 +726,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(0, termination.extraCode);
@@ -630,7 +752,7 @@
         ImsRegistrationTermination termination = captor.getValue();
         assertEquals(CARRIER1_ID, termination.carrierId);
         assertFalse(termination.isMultiSim);
-        assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, termination.ratAtEnd);
+        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, termination.ratAtEnd);
         assertTrue(termination.setupFailed);
         assertEquals(ImsReasonInfo.CODE_REGISTRATION_ERROR, termination.reasonCode);
         assertEquals(0, termination.extraCode);
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 e80978d..0b8d658 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -130,7 +130,6 @@
 
     @Test
     public void testSendSatelliteDatagram_usingSatelliteModemInterface_success() throws  Exception {
-        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
 
@@ -243,7 +242,6 @@
 
     @Test
     public void testSendSatelliteDatagram_usingSatelliteModemInterface_failure() throws  Exception {
-        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
         doAnswer(invocation -> {
             Message message = (Message) invocation.getArguments()[3];
 
@@ -282,129 +280,17 @@
     }
 
     @Test
-    public void testSendSatelliteDatagram_usingCommandsInterface_phoneNull() throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null});
-
-        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
-                true, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
-        mInOrder.verify(mMockDatagramController).isPollingInIdleState();
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        verifyNoMoreInteractions(mMockDatagramController);
-
-        assertThat(mResultListener.peek())
-                .isEqualTo(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-    }
-
-    @Test
-    public void testSendSatelliteDatagram_usingCommandsInterface_success() throws  Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
+    public void testSendSatelliteDatagram_DemoMode_Align_Success() throws Exception {
         doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
-            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
+            Message message = (Message) invocation.getArguments()[3];
+            mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
-        }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class),
-                anyBoolean());
-
-        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram,
-                true, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
-        mInOrder.verify(mMockDatagramController).isPollingInIdleState();
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        verifyNoMoreInteractions(mMockDatagramController);
-
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-    }
-
-    @Test
-    public void testSendSatelliteDatagram_usingCommandsInterface_failure() throws  Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
-            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
-                            new AsyncResult(message.obj, null,
-                                    new SatelliteManager.SatelliteException(
-                                            SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR)))
-                    .sendToTarget();
-            return null;
-        }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class),
-                anyBoolean());
-
-        mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
-                true, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController).needsWaitingForSatelliteConnected();
-        mInOrder.verify(mMockDatagramController).isPollingInIdleState();
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR));
-        mInOrder.verify(mMockDatagramController)
-                .updateSendStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        verifyNoMoreInteractions(mMockDatagramController);
-
-        assertThat(mResultListener.peek()).isEqualTo(
-                SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
-    }
-
-    @Test
-    public void testSendSatelliteDatagram_DemoMode_Align_Success() throws Exception {
+        }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
+                anyBoolean(), anyBoolean(), any(Message.class));
         mTestDemoModeDatagramDispatcher.setDemoMode(true);
         mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
-            mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
-                            new AsyncResult(message.obj, null, null))
-                    .sendToTarget();
-            return null;
-        }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class),
-                anyBoolean());
 
         mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
@@ -430,22 +316,19 @@
 
     @Test
     public void testSendSatelliteDatagram_DemoMode_Align_failed() throws Exception {
-        long previousTimer = mTestDemoModeDatagramDispatcher.getSatelliteAlignedTimeoutDuration();
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        mTestDemoModeDatagramDispatcher.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN);
-        mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
-
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
         doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
+            Message message = (Message) invocation.getArguments()[3];
             mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
-        }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class),
-                anyBoolean());
+        }).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);
 
         mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
                 true, mResultListener::offer);
@@ -472,18 +355,16 @@
 
     @Test
     public void testSendSatelliteDatagram_DemoMode_data_type_location_sharing() throws Exception {
-        mTestDemoModeDatagramDispatcher.setDemoMode(true);
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
         doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
+            Message message = (Message) invocation.getArguments()[3];
             mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
                             new AsyncResult(message.obj, null, null))
                     .sendToTarget();
             return null;
-        }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class),
-                anyBoolean());
+        }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
+                anyBoolean(), anyBoolean(), any(Message.class));
+        mTestDemoModeDatagramDispatcher.setDemoMode(true);
+        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
 
         mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram,
                 true, mResultListener::offer);
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 9fe85ef..3578707 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -54,8 +54,6 @@
 import android.util.Pair;
 
 import com.android.internal.telephony.IVoidConsumer;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
 
@@ -255,92 +253,6 @@
     }
 
     @Test
-    public void testPollPendingSatelliteDatagrams_usingCommandsInterface_phoneNull()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null});
-
-        mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED),
-                        eq(0), eq(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE));
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE),
-                        eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-
-        assertThat(mResultListener.peek())
-                .isEqualTo(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-    }
-
-    @Test
-    public void testPollPendingSatelliteDatagrams_usingCommandsInterface_success()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
-            mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/,
-                            new AsyncResult(message.obj, null, null))
-                    .sendToTarget();
-            return null;
-        }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class));
-
-        mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-    }
-
-    @Test
-    public void testPollPendingSatelliteDatagrams_usingCommandsInterface_failure()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-
-            mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/,
-                            new AsyncResult(message.obj, null,
-                                    new SatelliteManager.SatelliteException(
-                                            SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR)))
-                    .sendToTarget();
-            return null;
-        }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class));
-
-        mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer);
-
-        processAllMessages();
-
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0),
-                        eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
-        mInOrder.verify(mMockDatagramController)
-                .updateReceiveStatus(eq(SUB_ID),
-                        eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED),
-                        eq(0), eq(SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR));
-
-        assertThat(mResultListener.peek()).isEqualTo(
-                SatelliteManager.SATELLITE_RESULT_SERVICE_ERROR);
-    }
-
-    @Test
     public void testSatelliteDatagramReceived_receiveNone() {
         mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/,
                 new AsyncResult(null, new Pair<>(null, 0), null))
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 96dcd85..3917a32 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/PointingAppControllerTest.java
@@ -251,13 +251,6 @@
             AsyncResult.forMessage(message, null, exception);
             message.sendToTarget();
             return null;
-        }).when(mPhone).startSatellitePositionUpdates(any(Message.class));
-
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-            AsyncResult.forMessage(message, null, exception);
-            message.sendToTarget();
-            return null;
         }).when(mMockSatelliteModemInterface).startSendingSatellitePointingInfo(any(Message.class));
     }
 
@@ -270,54 +263,21 @@
             AsyncResult.forMessage(message, null, exception);
             message.sendToTarget();
             return null;
-        }).when(mPhone).stopSatellitePositionUpdates(any(Message.class));
-
-        doAnswer(invocation -> {
-            Message message = (Message) invocation.getArguments()[0];
-            AsyncResult.forMessage(message, null, exception);
-            message.sendToTarget();
-            return null;
         }).when(mMockSatelliteModemInterface).stopSendingSatellitePointingInfo(any(Message.class));
     }
 
     @Test
-    public void testStartSatelliteTransmissionUpdates_CommandInterface()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        Message testMessage = mTestSatelliteControllerHandler
-                .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
-        setUpResponseForStartTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        mPointingAppController.startSatelliteTransmissionUpdates(testMessage, mPhone);
-
-        processAllMessages();
-
-        verify(mMockSatelliteModemInterface, never())
-                .startSendingSatellitePointingInfo(eq(testMessage));
-
-        verify(mPhone)
-                .startSatellitePositionUpdates(eq(testMessage));
-
-        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mResultCode);
-
-        assertTrue(mPointingAppController.getStartedSatelliteTransmissionUpdates());
-    }
-
-    @Test
     public void testStartSatelliteTransmissionUpdates_success()
             throws Exception {
-        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
         mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
         Message testMessage = mTestSatelliteControllerHandler
                 .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
         setUpResponseForStartTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        mPointingAppController.startSatelliteTransmissionUpdates(testMessage, mPhone);
+        mPointingAppController.startSatelliteTransmissionUpdates(testMessage);
 
         verify(mMockSatelliteModemInterface)
                 .startSendingSatellitePointingInfo(eq(testMessage));
 
-        verify(mPhone, never())
-                .startSatellitePositionUpdates(eq(testMessage));
-
         processAllMessages();
 
 
@@ -326,90 +286,24 @@
     }
 
     @Test
-    public void testStartSatelliteTransmissionUpdates_phoneNull()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        mPointingAppController.setStartedSatelliteTransmissionUpdates(false);
-        Message testMessage = mTestSatelliteControllerHandler
-                .obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
-
-        mPointingAppController.startSatelliteTransmissionUpdates(testMessage, null);
-        processAllMessages();
-        verify(mMockSatelliteModemInterface, never())
-                .startSendingSatellitePointingInfo(eq(testMessage));
-
-        verify(mPhone, never())
-                .startSatellitePositionUpdates(eq(testMessage));
-
-        assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates());
-
-        assertEquals(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mResultCode);
-    }
-
-    @Test
-    public void testStopSatelliteTransmissionUpdates_CommandInterface()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        setUpResponseForStopTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        Message testMessage = mTestSatelliteControllerHandler
-                .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
-        mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, mPhone);
-
-        processAllMessages();
-
-        verify(mMockSatelliteModemInterface, never())
-                .stopSendingSatellitePointingInfo(eq(testMessage));
-
-        verify(mPhone)
-                .stopSatellitePositionUpdates(eq(testMessage));
-
-        assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates());
-
-        assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mResultCode);
-    }
-
-    @Test
     public void testStopSatelliteTransmissionUpdates_success()
             throws Exception {
         doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
         setUpResponseForStopTransmissionUpdates(SatelliteManager.SATELLITE_RESULT_SUCCESS);
         Message testMessage = mTestSatelliteControllerHandler
                 .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
-        mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, mPhone);
+        mPointingAppController.stopSatelliteTransmissionUpdates(testMessage);
 
         processAllMessages();
 
         verify(mMockSatelliteModemInterface)
                 .stopSendingSatellitePointingInfo(eq(testMessage));
 
-        verify(mPhone, never())
-                .stopSatellitePositionUpdates(eq(testMessage));
-
         assertFalse(mPointingAppController.getStartedSatelliteTransmissionUpdates());
         assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS, mResultCode);
     }
 
     @Test
-    public void testStopSatellitePointingInfo_phoneNull()
-            throws Exception {
-        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
-        Message testMessage = mTestSatelliteControllerHandler
-                .obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, null);
-        mPointingAppController.stopSatelliteTransmissionUpdates(testMessage, null);
-
-        processAllMessages();
-
-        verify(mMockSatelliteModemInterface, never())
-                .stopSendingSatellitePointingInfo(eq(testMessage));
-
-        verify(mPhone, never())
-                .stopSatellitePositionUpdates(eq(testMessage));
-
-        assertEquals(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE, mResultCode);
-
-    }
-
-    @Test
     public void testStartPointingUI() throws Exception {
         ArgumentCaptor<Intent> startedIntentCaptor = ArgumentCaptor.forClass(Intent.class);
         mPointingAppController.startPointingUI(true);
@@ -451,7 +345,7 @@
     @Test
     public void testUpdateSendDatagramTransferState() throws Exception {
         mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID,
-                mSatelliteTransmissionUpdateCallback, mPhone);
+                mSatelliteTransmissionUpdateCallback);
         mPointingAppController.updateSendDatagramTransferState(SUB_ID,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, 1,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
@@ -463,14 +357,14 @@
                 mSatelliteTransmissionUpdateCallback.getErrorCode());
         assertTrue(mSatelliteTransmissionUpdateCallback.inSendDatagramStateCallback);
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(SUB_ID,
-                    mResultListener::offer, mSatelliteTransmissionUpdateCallback, mPhone);
+                    mResultListener::offer, mSatelliteTransmissionUpdateCallback);
         mResultListener.clear();
     }
 
     @Test
     public void testUpdateReceiveDatagramTransferState() throws Exception {
         mPointingAppController.registerForSatelliteTransmissionUpdates(SUB_ID,
-                mSatelliteTransmissionUpdateCallback, mPhone);
+                mSatelliteTransmissionUpdateCallback);
         mPointingAppController.updateReceiveDatagramTransferState(SUB_ID,
                 SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, 2,
                 SatelliteManager.SATELLITE_RESULT_SUCCESS);
@@ -482,62 +376,11 @@
                 mSatelliteTransmissionUpdateCallback.getErrorCode());
         assertTrue(mSatelliteTransmissionUpdateCallback.inReceiveDatagramStateCallback);
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(SUB_ID,
-                    mResultListener::offer, mSatelliteTransmissionUpdateCallback, mPhone);
+                    mResultListener::offer, mSatelliteTransmissionUpdateCallback);
         mResultListener.clear();
     }
 
     @Test
-    public void testRegisterForSatelliteTransmissionUpdates_CommandInterface() throws Exception {
-        mResultListener.clear();
-        mInOrder = inOrder(mPhone);
-        TestSatelliteTransmissionUpdateCallback callback1 = new
-                TestSatelliteTransmissionUpdateCallback();
-        TestSatelliteTransmissionUpdateCallback callback2 = new
-                TestSatelliteTransmissionUpdateCallback();
-        int subId1 = 1;
-        int subId2 = 2;
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1,
-                callback1, mPhone);
-        mInOrder.verify(mPhone).registerForSatellitePositionInfoChanged(any(),
-                eq(1), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1,
-                callback2, mPhone);
-        mInOrder.verify(mPhone, never()).registerForSatellitePositionInfoChanged(any(),
-                eq(1), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2,
-                callback1, mPhone);
-        mInOrder.verify(mPhone).registerForSatellitePositionInfoChanged(any(),
-                eq(1), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2,
-                callback2, mPhone);
-        mInOrder.verify(mPhone, never()).registerForSatellitePositionInfoChanged(any(),
-                eq(1), eq(null));
-        mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1,
-                mResultListener::offer, callback1, mPhone);
-        processAllMessages();
-        //since there are 2 callbacks registered for this sub_id, Handler is not unregistered
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        mResultListener.remove();
-        mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1,
-                mResultListener::offer, callback2, mPhone);
-        mInOrder.verify(mPhone).unregisterForSatellitePositionInfoChanged(any(Handler.class));
-        mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2,
-                mResultListener::offer, callback1, mPhone);
-        processAllMessages();
-        assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
-        mResultListener.remove();
-        mInOrder.verify(mPhone, never()).unregisterForSatellitePositionInfoChanged(
-                any(Handler.class));
-        mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2,
-                mResultListener::offer, callback2, null);
-        processAllMessages();
-        assertThat(mResultListener.peek())
-                .isEqualTo(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
-        mResultListener.remove();
-        mInOrder = null;
-    }
-
-    @Test
     public void testRegisterForSatelliteTransmissionUpdates() throws Exception {
         mResultListener.clear();
         doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
@@ -548,44 +391,40 @@
                 TestSatelliteTransmissionUpdateCallback();
         int subId1 = 3;
         int subId2 = 4;
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1,
-                callback1, mPhone);
+        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, callback1);
         mInOrder.verify(mMockSatelliteModemInterface).registerForSatellitePositionInfoChanged(any(),
                 eq(1), eq(null));
         mInOrder.verify(mMockSatelliteModemInterface).registerForDatagramTransferStateChanged(any(),
                 eq(4), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1,
-                callback2, mPhone);
+        mPointingAppController.registerForSatelliteTransmissionUpdates(subId1, callback2);
         mInOrder.verify(mMockSatelliteModemInterface, never())
                 .registerForSatellitePositionInfoChanged(any(), eq(1), eq(null));
         mInOrder.verify(mMockSatelliteModemInterface, never())
                 .registerForDatagramTransferStateChanged(any(), eq(4), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2,
-                callback1, mPhone);
+        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, callback1);
         mInOrder.verify(mMockSatelliteModemInterface).registerForSatellitePositionInfoChanged(any(),
                 eq(1), eq(null));
         mInOrder.verify(mMockSatelliteModemInterface).registerForDatagramTransferStateChanged(any(),
                 eq(4), eq(null));
-        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2,
-                callback2, mPhone);
+        mPointingAppController.registerForSatelliteTransmissionUpdates(subId2, callback2);
         mInOrder.verify(mMockSatelliteModemInterface, never())
                 .registerForSatellitePositionInfoChanged(any(), eq(1), eq(null));
         mInOrder.verify(mMockSatelliteModemInterface, never())
                 .registerForDatagramTransferStateChanged(any(), eq(4), eq(null));
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1,
-                mResultListener::offer, callback1, mPhone);
+                mResultListener::offer, callback1);
         processAllMessages();
         //since there are 2 callbacks registered for this sub_id, Handler is not unregistered
         assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
         mResultListener.remove();
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId1,
-                mResultListener::offer, callback2, mPhone);
+                mResultListener::offer, callback2);
         mInOrder.verify(mMockSatelliteModemInterface).unregisterForSatellitePositionInfoChanged(
                 any(Handler.class));
         mInOrder.verify(mMockSatelliteModemInterface).unregisterForDatagramTransferStateChanged(
                 any(Handler.class));
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2,
-                mResultListener::offer, callback1, mPhone);
+                mResultListener::offer, callback1);
         processAllMessages();
         assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_RESULT_SUCCESS);
         mResultListener.remove();
@@ -594,7 +433,7 @@
         mInOrder.verify(mMockSatelliteModemInterface, never())
                 .unregisterForDatagramTransferStateChanged(any(Handler.class));
         mPointingAppController.unregisterForSatelliteTransmissionUpdates(subId2,
-                mResultListener::offer, callback2, null);
+                mResultListener::offer, callback2);
         processAllMessages();
         mInOrder.verify(mMockSatelliteModemInterface).unregisterForSatellitePositionInfoChanged(
                 any(Handler.class));
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 3fc935e..2feb34d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -16,7 +16,12 @@
 
 package com.android.internal.telephony.satellite;
 
+import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GOOD;
+import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GREAT;
+import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
+import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_POOR;
 import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED;
+import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_CAPABILITIES;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ENABLED;
@@ -87,10 +92,12 @@
 import android.os.ResultReceiver;
 import android.telephony.CarrierConfigManager;
 import android.telephony.Rlog;
+import android.telephony.satellite.INtnSignalStrengthCallback;
 import android.telephony.satellite.ISatelliteDatagramCallback;
 import android.telephony.satellite.ISatelliteProvisionStateCallback;
 import android.telephony.satellite.ISatelliteStateCallback;
 import android.telephony.satellite.ISatelliteTransmissionUpdateCallback;
+import android.telephony.satellite.NtnSignalStrength;
 import android.telephony.satellite.SatelliteCapabilities;
 import android.telephony.satellite.SatelliteDatagram;
 import android.telephony.satellite.SatelliteManager;
@@ -102,7 +109,6 @@
 import com.android.internal.R;
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.IVoidConsumer;
-import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.TelephonyTest;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
@@ -336,7 +342,7 @@
                     mQueriedSatelliteAllowed = false;
                 }
             } else {
-                logd("mSatelliteSupportReceiver: resultCode=" + resultCode);
+                logd("mSatelliteAllowedReceiver: resultCode=" + resultCode);
                 mQueriedSatelliteAllowed = false;
             }
             try {
@@ -375,6 +381,36 @@
         }
     };
 
+    private @NtnSignalStrength.NtnSignalStrengthLevel int mQueriedNtnSignalStrengthLevel =
+            NTN_SIGNAL_STRENGTH_NONE;
+    private int mQueriedNtnSignalStrengthResultCode = SATELLITE_RESULT_SUCCESS;
+    private Semaphore mRequestNtnSignalStrengthSemaphore = new Semaphore(0);
+    private ResultReceiver mRequestNtnSignalStrengthReceiver = new ResultReceiver(null) {
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            mQueriedNtnSignalStrengthResultCode = resultCode;
+            if (resultCode == SATELLITE_RESULT_SUCCESS) {
+                if (resultData.containsKey(KEY_NTN_SIGNAL_STRENGTH)) {
+                    NtnSignalStrength result = resultData.getParcelable(KEY_NTN_SIGNAL_STRENGTH);
+                    logd("result.getLevel()=" + result.getLevel());
+                    mQueriedNtnSignalStrengthLevel = result.getLevel();
+                } else {
+                    loge("KEY_NTN_SIGNAL_STRENGTH does not exist.");
+                    mQueriedNtnSignalStrengthLevel = NTN_SIGNAL_STRENGTH_NONE;
+                }
+            } else {
+                logd("KEY_NTN_SIGNAL_STRENGTH: resultCode=" + resultCode);
+                mQueriedNtnSignalStrengthLevel = NTN_SIGNAL_STRENGTH_NONE;
+            }
+            try {
+                mRequestNtnSignalStrengthSemaphore.release();
+            } catch (Exception ex) {
+                loge("mRequestNtnSignalStrengthReceiver: Got exception in releasing semaphore, ex="
+                        + ex);
+            }
+        }
+    };
+
     @Before
     public void setUp() throws Exception {
         super.setUp(getClass().getSimpleName());
@@ -961,12 +997,11 @@
         mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer,
                 mStartTransmissionUpdateCallback);
         verify(mMockPointingAppController).registerForSatelliteTransmissionUpdates(anyInt(),
-                eq(mStartTransmissionUpdateCallback), any());
+                eq(mStartTransmissionUpdateCallback));
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
-        verify(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class),
-                any(Phone.class));
+        verify(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class));
         verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(true));
 
         resetSatelliteControllerUT();
@@ -983,7 +1018,7 @@
         assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
                 (long) mIIntegerConsumerResults.get(0));
         verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(),
-                any(),  eq(mStartTransmissionUpdateCallback), any(Phone.class));
+                any(),  eq(mStartTransmissionUpdateCallback));
         verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(false));
     }
 
@@ -1042,12 +1077,11 @@
         mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer,
                 mStopTransmissionUpdateCallback);
         verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(),
-                any(),  eq(mStopTransmissionUpdateCallback), any(Phone.class));
+                any(),  eq(mStopTransmissionUpdateCallback));
         processAllMessages();
         assertTrue(waitForIIntegerConsumerResult(1));
         assertEquals(SATELLITE_RESULT_SUCCESS, (long) mIIntegerConsumerResults.get(0));
-        verify(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class),
-                any(Phone.class));
+        verify(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class));
 
         resetSatelliteControllerUT();
         mIIntegerConsumerResults.clear();
@@ -2005,6 +2039,276 @@
                 SATELLITE_MODEM_STATE_CONNECTED);
     }
 
+    @Test
+    public void testRequestNtnSignalStrengthWithFeatureFlagEnabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        resetSatelliteControllerUT();
+
+        mRequestNtnSignalStrengthSemaphore.drainPermits();
+        setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+
+        @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_GREAT;
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        /* In case request is not successful, result should be NTN_SIGNAL_STRENGTH_NONE */
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE, SATELLITE_RESULT_NOT_SUPPORTED);
+
+        resetSatelliteControllerUT();
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+
+        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+
+        resetSatelliteControllerUT();
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        // reset cache to NTN_SIGNAL_STRENGTH_NONE
+        sendNtnSignalStrengthChangedEvent(NTN_SIGNAL_STRENGTH_NONE, null);
+        processAllMessages();
+        expectedLevel = NTN_SIGNAL_STRENGTH_POOR;
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testRequestNtnSignalStrengthWithFeatureFlagDisabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+
+        resetSatelliteControllerUT();
+        mRequestNtnSignalStrengthSemaphore.drainPermits();
+        doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+
+        @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_GREAT;
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        expectedLevel = NTN_SIGNAL_STRENGTH_POOR;
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_MODEM_ERROR);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+    }
+
+    @Test
+    public void testRegisterForNtnSignalStrengthChangedWithFeatureFlagEnabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        Semaphore semaphore = new Semaphore(0);
+        final NtnSignalStrength[] signalStrength = new NtnSignalStrength[1];
+        INtnSignalStrengthCallback callback =
+                new INtnSignalStrengthCallback.Stub() {
+                    @Override
+                    public void onNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
+                        logd("onNtnSignalStrengthChanged: ntnSignalStrength="
+                                + ntnSignalStrength);
+                        try {
+                            signalStrength[0] = ntnSignalStrength;
+                            semaphore.release();
+                        } catch (Exception ex) {
+                            loge("onNtnSignalStrengthChanged: Got exception in releasing "
+                                    + "semaphore, ex=" + ex);
+                        }
+                    }
+                };
+
+        int errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID,
+                callback);
+        assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, errorCode);
+        @NtnSignalStrength.NtnSignalStrengthLevel int expectedLevel = NTN_SIGNAL_STRENGTH_NONE;
+
+        setUpResponseForRequestIsSatelliteSupported(false,
+                SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+        errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, errorCode);
+        verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_NOT_SUPPORTED);
+
+        resetSatelliteControllerUT();
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_SUCCESS, errorCode);
+        verifyRequestNtnSignalStrength(expectedLevel, SATELLITE_RESULT_SUCCESS);
+
+        expectedLevel = NTN_SIGNAL_STRENGTH_GOOD;
+        sendNtnSignalStrengthChangedEvent(expectedLevel, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForNtnSignalStrengthChanged"));
+        assertEquals(expectedLevel, signalStrength[0].getLevel());
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_GOOD, SATELLITE_RESULT_SUCCESS);
+
+        expectedLevel = NTN_SIGNAL_STRENGTH_POOR;
+        sendNtnSignalStrengthChangedEvent(expectedLevel, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 1, "testRegisterForNtnSignalStrengthChanged"));
+        assertEquals(expectedLevel, signalStrength[0].getLevel());
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_POOR, SATELLITE_RESULT_SUCCESS);
+
+        mSatelliteControllerUT.unregisterForNtnSignalStrengthChanged(SUB_ID, callback);
+        sendNtnSignalStrengthChangedEvent(NTN_SIGNAL_STRENGTH_GREAT, null);
+        processAllMessages();
+        assertFalse(waitForForEvents(
+                semaphore, 1, "testRegisterForNtnSignalStrengthChanged"));
+        /* Even if all listeners are unregistered, the cache is updated with the latest value when a
+         new value event occurs. */
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_GREAT, SATELLITE_RESULT_SUCCESS);
+    }
+
+    @Test
+    public void testRegisterForNtnSignalStrengthChangedWithFeatureFlagDisabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+
+        Semaphore semaphore = new Semaphore(0);
+        final NtnSignalStrength[] signalStrength = new NtnSignalStrength[1];
+        INtnSignalStrengthCallback callback =
+                new INtnSignalStrengthCallback.Stub() {
+                    @Override
+                    public void onNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
+                        logd("onNtnSignalStrengthChanged: ntnSignalStrength="
+                                + ntnSignalStrength);
+                        try {
+                            signalStrength[0] = ntnSignalStrength;
+                            semaphore.release();
+                        } catch (Exception ex) {
+                            loge("onNtnSignalStrengthChanged: Got exception in releasing "
+                                    + "semaphore, ex=" + ex);
+                        }
+                    }
+                };
+
+        int errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID,
+                callback);
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+
+        setUpResponseForRequestIsSatelliteSupported(false,
+                SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED);
+        errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+        setUpResponseForRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_SUCCESS);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        resetSatelliteControllerUT();
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED);
+        errorCode = mSatelliteControllerUT.registerForNtnSignalStrengthChanged(SUB_ID, callback);
+        assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+        verifyRequestNtnSignalStrength(NTN_SIGNAL_STRENGTH_NONE,
+                SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+
+        @NtnSignalStrength.NtnSignalStrengthLevel int expectedNtnSignalStrengthLevel =
+                NTN_SIGNAL_STRENGTH_GOOD;
+        sendNtnSignalStrengthChangedEvent(expectedNtnSignalStrengthLevel, null);
+        processAllMessages();
+        assertTrue(waitForForEvents(
+                semaphore, 0, "testRegisterForNtnSignalStrengthChanged"));
+    }
+
+    @Test
+    public void testSendingNtnSignalStrengthWithFeatureEnabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        int expectedResult = SATELLITE_RESULT_SUCCESS;
+        // startSendingNtnSignalStrength() is requested when screen on event comes.
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestIsSatelliteSupported(true, expectedResult);
+        setUpResponseForRequestIsSatelliteProvisioned(true, expectedResult);
+        verifySatelliteSupported(true, expectedResult);
+        verifySatelliteProvisioned(true, expectedResult);
+        setUpResponseForStartSendingNtnSignalStrength(expectedResult);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(true);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, times(1))
+                .startSendingNtnSignalStrength(any(Message.class));
+
+        // stopSendingNtnSignalStrength() is requested when screen off event comes.
+        reset(mMockSatelliteModemInterface);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForStopSendingNtnSignalStrength(expectedResult);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(false);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, times(1))
+                .stopSendingNtnSignalStrength(any(Message.class));
+
+        // startSendingNtnSignalStrength() is requested but received fail from the service.
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForStartSendingNtnSignalStrength(SATELLITE_RESULT_INVALID_MODEM_STATE);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(true);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, times(1))
+                .startSendingNtnSignalStrength(any(Message.class));
+
+        // stopSendingNtnSignalStrength() is requested but received fail from the service.
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForStopSendingNtnSignalStrength(SATELLITE_RESULT_NO_RESOURCES);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(false);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, times(1))
+                .stopSendingNtnSignalStrength(any(Message.class));
+    }
+
+    @Test
+    public void testSendingNtnSignalStrengthWithFeatureDisabled() {
+        when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+
+        int expectedResult = SATELLITE_RESULT_SUCCESS;
+        // startSendingNtnSignalStrength() is requested when screen on event comes.
+        reset(mMockSatelliteModemInterface);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForRequestIsSatelliteSupported(true, expectedResult);
+        setUpResponseForRequestIsSatelliteProvisioned(true, expectedResult);
+        verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED);
+        verifySatelliteProvisioned(false, SATELLITE_RESULT_REQUEST_NOT_SUPPORTED);
+        setUpResponseForStartSendingNtnSignalStrength(expectedResult);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(true);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, never())
+                .startSendingNtnSignalStrength(any(Message.class));
+
+        // stopSendingNtnSignalStrength() is requested when screen off event comes.
+        reset(mMockSatelliteModemInterface);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported();
+        setUpResponseForStopSendingNtnSignalStrength(expectedResult);
+        sendCmdStartSendingNtnSignalStrengthChangedEvent(false);
+        processAllMessages();
+        verify(mMockSatelliteModemInterface, never())
+                .stopSendingNtnSignalStrength(any(Message.class));
+    }
+
     private void resetSatelliteControllerUTEnabledState() {
         logd("resetSatelliteControllerUTEnabledState");
         setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
@@ -2232,6 +2536,20 @@
         }).when(mMockSatelliteModemInterface).requestSatelliteCapabilities(any(Message.class));
     }
 
+    private void setUpResponseForRequestNtnSignalStrength(
+            @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel,
+            @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, new NtnSignalStrength(ntnSignalStrengthLevel),
+                    exception);
+            message.sendToTarget();
+            return null;
+        }).when(mMockSatelliteModemInterface).requestNtnSignalStrength(any(Message.class));
+    }
+
     private boolean waitForForEvents(
             Semaphore semaphore, int expectedNumberOfEvents, String caller) {
         for (int i = 0; i < expectedNumberOfEvents; i++) {
@@ -2269,8 +2587,7 @@
             AsyncResult.forMessage(message, null, exception);
             message.sendToTarget();
             return null;
-        }).when(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class),
-                any());
+        }).when(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class));
     }
 
     private void setUpResponseForStopSatelliteTransmissionUpdates(
@@ -2282,8 +2599,31 @@
             AsyncResult.forMessage(message, null, exception);
             message.sendToTarget();
             return null;
-        }).when(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class),
-                any());
+        }).when(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class));
+    }
+
+    private void setUpResponseForStartSendingNtnSignalStrength(
+            @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).startSendingNtnSignalStrength(any(Message.class));
+    }
+
+    private void setUpResponseForStopSendingNtnSignalStrength(
+            @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).stopSendingNtnSignalStrength(any(Message.class));
     }
 
     private boolean waitForRequestIsSatelliteSupportedResult(int expectedNumberOfEvents) {
@@ -2396,6 +2736,22 @@
         return true;
     }
 
+    private boolean waitForRequestNtnSignalStrengthResult(int expectedNumberOfEvents) {
+        for (int i = 0; i < expectedNumberOfEvents; i++) {
+            try {
+                if (!mRequestNtnSignalStrengthSemaphore.tryAcquire(TIMEOUT,
+                        TimeUnit.MILLISECONDS)) {
+                    loge("Timeout to receive requestNtnSignalStrength() callback");
+                    return false;
+                }
+            } catch (Exception ex) {
+                loge("requestNtnSignalStrength: Got exception=" + ex);
+                return false;
+            }
+        }
+        return true;
+    }
+
     private boolean waitForIIntegerConsumerResult(int expectedNumberOfEvents) {
         for (int i = 0; i < expectedNumberOfEvents; i++) {
             try {
@@ -2439,6 +2795,17 @@
         assertEquals(provisioned, mQueriedIsSatelliteProvisioned);
     }
 
+    private void verifyRequestNtnSignalStrength(
+            @NtnSignalStrength.NtnSignalStrengthLevel int signalStrengthLevel,
+            int expectedErrorCode) {
+        mRequestNtnSignalStrengthSemaphore.drainPermits();
+        mSatelliteControllerUT.requestNtnSignalStrength(SUB_ID, mRequestNtnSignalStrengthReceiver);
+        processAllMessages();
+        assertTrue(waitForRequestNtnSignalStrengthResult(1));
+        assertEquals(expectedErrorCode, mQueriedNtnSignalStrengthResultCode);
+        assertEquals(signalStrengthLevel, mQueriedNtnSignalStrengthLevel);
+    }
+
     private void sendProvisionedStateChangedEvent(boolean provisioned, Throwable exception) {
         Message msg = mSatelliteControllerUT.obtainMessage(
                 26 /* EVENT_SATELLITE_PROVISION_STATE_CHANGED */);
@@ -2453,6 +2820,33 @@
         msg.sendToTarget();
     }
 
+    private void sendNtnSignalStrengthChangedEvent(
+            @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel,
+            Throwable exception) {
+        Message msg = mSatelliteControllerUT.obtainMessage(
+                34 /* EVENT_NTN_SIGNAL_STRENGTH_CHANGED */);
+        msg.obj = new AsyncResult(null, new NtnSignalStrength(ntnSignalStrengthLevel),
+                exception);
+        msg.sendToTarget();
+    }
+
+    private void sendCmdStartSendingNtnSignalStrengthChangedEvent(boolean shouldReport) {
+        Message msg = mSatelliteControllerUT.obtainMessage(
+                35 /* CMD_START_SENDING_NTN_SIGNAL_STRENGTH */);
+        msg.obj = new AsyncResult(null, shouldReport, null);
+        msg.sendToTarget();
+    }
+
+    private void sendStartSendingNtnSignalStrengthChangedEvent(
+            @NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel,
+            Throwable exception) {
+        Message msg = mSatelliteControllerUT.obtainMessage(
+                36 /* EVENT_START_SENDING_NTN_SIGNAL_STRENGTH_DONE */);
+        msg.obj = new AsyncResult(null, new NtnSignalStrength(ntnSignalStrengthLevel),
+                exception);
+        msg.sendToTarget();
+    }
+
     private void setRadioPower(boolean on) {
         mSimulatedCommands.setRadioPower(on, false, false, null);
     }