Merge "Suppress Notifications for Hidden Subs" into main
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 452df67..1bd3ed4 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -297,7 +297,7 @@
     <string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"Baliteke <xliff:g id="CARRIER_NAME">%1$s</xliff:g> bidezko deiak eta datu-zerbitzuak blokeatuta egotea <xliff:g id="PHONE_NUMBER">%2$s</xliff:g> telefono-zenbakia erabiltzean."</string>
     <string name="limited_sim_function_notification_message" msgid="5338638075496721160">"Baliteke <xliff:g id="CARRIER_NAME">%1$s</xliff:g> bidezko deiak eta datu-zerbitzuak blokeatuta egotea beste SIM txartel bat erabiltzean."</string>
     <string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"SIP-eko kontu zaharkituak aurkitu eta kendu dira"</string>
-    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"SIP bidezko deiak jadanik ez dira bateragarriak Android-en plataformarekin.\nZeneuzkan SIP-eko kontuak (<xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g>) kendu egin dira.\nBerretsi deietarako ezarri duzun kontu lehenetsia."</string>
+    <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"SIP bidezko deiak jadanik ez dira onartzen Android-en plataforman.\nZeneuzkan SIP-eko kontuak (<xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g>) kendu egin dira.\nBerretsi deietarako ezarri duzun kontu lehenetsia."</string>
     <string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"Joan ezarpenetara"</string>
     <string name="data_usage_title" msgid="8438592133893837464">"Aplikazioak erabilitako datuak"</string>
     <string name="data_usage_template" msgid="6287906680674061783">"Datuen <xliff:g id="ID_1">%1$s</xliff:g> erabili dira data hauen artean: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index c6c26b0..3a908d2 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -23,6 +23,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.compat.CompatChanges;
 import android.content.BroadcastReceiver;
@@ -899,8 +900,11 @@
             mServiceConnection[phoneId] = serviceConnection;
         }
         try {
-            if (mContext.bindService(carrierService, serviceConnection,
-                    Context.BIND_AUTO_CREATE)) {
+            if (mFeatureFlags.supportCarrierServicesForHsum()
+                    ? mContext.bindServiceAsUser(carrierService, serviceConnection,
+                    Context.BIND_AUTO_CREATE, UserHandle.of(ActivityManager.getCurrentUser()))
+                    : mContext.bindService(carrierService, serviceConnection,
+                            Context.BIND_AUTO_CREATE)) {
                 if (eventId == EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG) {
                     mServiceBoundForNoSimConfig[phoneId] = true;
                 } else {
@@ -1261,7 +1265,10 @@
     @Nullable
     private String getPackageVersion(@NonNull String packageName) {
         try {
-            PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
+            PackageInfo info = mFeatureFlags.supportCarrierServicesForHsum()
+                    ? mContext.getPackageManager().getPackageInfoAsUser(packageName, 0,
+                    ActivityManager.getCurrentUser())
+                    : mContext.getPackageManager().getPackageInfo(packageName, 0);
             return Long.toString(info.getLongVersionCode());
         } catch (PackageManager.NameNotFoundException e) {
             return null;
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 559effa..daa4957 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -3679,9 +3679,6 @@
             return null;
         }
 
-        enforceTelephonyFeatureWithException(callingPackage,
-                PackageManager.FEATURE_TELEPHONY_GSM, "getImeiForSlot");
-
         final long identity = Binder.clearCallingIdentity();
         try {
             return phone.getImei();
@@ -3698,9 +3695,6 @@
             throw new SecurityException("Caller does not have permission");
         }
 
-        enforceTelephonyFeatureWithException(callingPackage,
-                PackageManager.FEATURE_TELEPHONY_GSM, "getPrimaryImei");
-
         final long identity = Binder.clearCallingIdentity();
         try {
             for (Phone phone : PhoneFactory.getPhones()) {
@@ -3716,9 +3710,6 @@
 
     @Override
     public String getTypeAllocationCodeForSlot(int slotIndex) {
-        enforceTelephonyFeatureWithException(getCurrentPackageName(),
-                PackageManager.FEATURE_TELEPHONY_GSM, "getTypeAllocationCodeForSlot");
-
         Phone phone = PhoneFactory.getPhone(slotIndex);
         String tac = null;
         if (phone != null) {
@@ -7746,6 +7737,12 @@
     @Override
     public List<String> getPackagesWithCarrierPrivileges(int phoneId) {
         enforceReadPrivilegedPermission("getPackagesWithCarrierPrivileges");
+
+        enforceTelephonyFeatureWithException(
+                getCurrentPackageName(),
+                PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION,
+                "getPackagesWithCarrierPrivileges");
+
         Phone phone = PhoneFactory.getPhone(phoneId);
         if (phone == null) {
             return Collections.emptyList();
@@ -11703,10 +11700,10 @@
     @Override
     public boolean setBoundGbaServiceOverride(int subId, String packageName) {
         enforceModifyPermission();
-
+        int userId = ActivityManager.getCurrentUser();
         final long identity = Binder.clearCallingIdentity();
         try {
-            return getGbaManager(subId).overrideServicePackage(packageName);
+            return getGbaManager(subId).overrideServicePackage(packageName, userId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -13568,10 +13565,10 @@
     }
 
     /**
-     * Inform that Device is aligned to satellite for demo mode.
+     * Inform whether the device is aligned with the satellite in both real and demo mode.
      *
-     * @param isAligned {@code true} Device is aligned with the satellite for demo mode
-     *                  {@code false} Device fails to align with the satellite for demo mode.
+     * @param isAligned {@code true} Device is aligned with the satellite.
+     *                  {@code false} Device fails to align with the satellite.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      */
@@ -14447,6 +14444,26 @@
     }
 
     /**
+     * Deliver the list of deprovisioned satellite subscriber ids.
+     *
+     * @param list List of deprovisioned satellite subscriber ids.
+     * @param result The result receiver that returns whether deliver success or fail.
+     *
+     * @throws SecurityException if the caller doesn't have the required permission.
+     */
+    @Override
+    public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list,
+            @NonNull ResultReceiver result) {
+        enforceSatelliteCommunicationPermission("deprovisionSatellite");
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mSatelliteController.deprovisionSatellite(list, result);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    /**
      * This API can be used by only CTS to override the cached value for the device overlay config
      * value :
      * config_satellite_gateway_service_package and
@@ -14505,4 +14522,17 @@
         enforceReadPrivilegedPermission("getTestEuiccUiComponent");
         return mTestEuiccUiComponent;
     }
+
+    /**
+     * This API can be used only for test purpose to override the carrier roaming Ntn eligibility
+     *
+     * @param state        to update Ntn Eligibility.
+     * @param resetRequired to reset the overridden flag in satellite controller.
+     * @return {@code true} if the shell command is successful, {@code false} otherwise.
+     */
+    public boolean overrideCarrierRoamingNtnEligibilityChanged(boolean state,
+            boolean resetRequired) {
+        return mSatelliteAccessController.overrideCarrierRoamingNtnEligibilityChanged(state,
+                resetRequired);
+    }
 }
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index b9b2f58..840f961 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -212,6 +212,9 @@
     private static final String SET_SATELLITE_SUBSCRIBERID_LIST_CHANGED_INTENT_COMPONENT =
             "set-satellite-subscriberid-list-changed-intent-component";
 
+    private static final String SET_SATELLITE_ACCESS_RESTRICTION_CHECKING_RESULT =
+            "set-satellite-access-restriction-checking-result";
+
     private static final String DOMAIN_SELECTION_SUBCOMMAND = "domainselection";
     private static final String DOMAIN_SELECTION_SET_SERVICE_OVERRIDE = "set-dss-override";
     private static final String DOMAIN_SELECTION_CLEAR_SERVICE_OVERRIDE = "clear-dss-override";
@@ -426,6 +429,8 @@
                 return handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache();
             case SET_SATELLITE_SUBSCRIBERID_LIST_CHANGED_INTENT_COMPONENT:
                 return handleSetSatelliteSubscriberIdListChangedIntentComponent();
+            case SET_SATELLITE_ACCESS_RESTRICTION_CHECKING_RESULT:
+                return handleOverrideCarrierRoamingNtnEligibilityChanged();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -3716,7 +3721,6 @@
         PrintWriter errPw = getErrPrintWriter();
         String opt;
         String state;
-
         if ((opt = getNextArg()) == null) {
             errPw.println(
                     "adb shell cmd phone set-is-satellite-communication-allowed-for-current"
@@ -4071,4 +4075,48 @@
         }
         return jSonString;
     }
+
+    /**
+     * This method override the check for carrier roaming Ntn eligibility.
+     * <ul>
+     * <li> `adb shell cmd phone set-satellite-access-restriction-checking-result true` will set
+     * override eligibility to true.</li>
+     * <li> `adb shell cmd phone set-satellite-access-restriction-checking-result false` will
+     * override eligibility to false.</li>
+     * <li> `adb shell cmd phone set-satellite-access-restriction-checking-result` will reset the
+     * override data set through adb command.</li>
+     * </ul>
+     *
+     * @return {@code true} is command executed successfully otherwise {@code false}.
+     */
+    private int handleOverrideCarrierRoamingNtnEligibilityChanged() {
+        PrintWriter errPw = getErrPrintWriter();
+        String opt;
+        boolean state = false;
+        boolean isRestRequired = false;
+        try {
+            if ((opt = getNextArg()) == null) {
+                isRestRequired = true;
+            } else {
+                if ("true".equalsIgnoreCase(opt)) {
+                    state = true;
+                }
+            }
+            boolean result = mInterface.overrideCarrierRoamingNtnEligibilityChanged(state,
+                    isRestRequired);
+            if (VDBG) {
+                Log.v(LOG_TAG, "handleSetSatelliteAccessRestrictionCheckingResult "
+                        + "returns: "
+                        + result);
+            }
+            getOutPrintWriter().println(result);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "handleSetSatelliteAccessRestrictionCheckingResult("
+                    + state + "), error = " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        Log.d(LOG_TAG, "handleSetSatelliteAccessRestrictionCheckingResult(" + state + ")");
+        return 0;
+    }
 }
diff --git a/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java b/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
index 4490460..c5ecfd9 100644
--- a/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessController.java
@@ -15,11 +15,17 @@
  */
 package com.android.phone.satellite.accesscontrol;
 
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.telephony.Rlog;
 
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.storage.s2.S2LevelRange;
+
 import com.android.telephony.sats2range.read.SatS2RangeFileReader;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 
 import com.google.common.geometry.S2CellId;
 import com.google.common.geometry.S2LatLng;
@@ -36,31 +42,42 @@
     private static final String TAG = "S2RangeSatelliteOnDeviceAccessController";
     private static final boolean DBG = false;
 
-    @NonNull private final SatS2RangeFileReader mSatS2RangeFileReader;
+    @NonNull
+    private final SatS2RangeFileReader mSatS2RangeFileReader;
 
     private final int mS2Level;
 
+    /** Feature flags to control behavior and errors. */
+    @NonNull
+    private final FeatureFlags mFeatureFlags;
+
     private S2RangeSatelliteOnDeviceAccessController(
-            @NonNull SatS2RangeFileReader satS2RangeFileReader, int s2Level) {
+            @NonNull SatS2RangeFileReader satS2RangeFileReader,
+            int s2Level,
+            @NonNull FeatureFlags featureFlags) {
         mSatS2RangeFileReader = Objects.requireNonNull(satS2RangeFileReader);
         mS2Level = s2Level;
+        mFeatureFlags = featureFlags;
     }
 
     /**
      * Returns a new {@link S2RangeSatelliteOnDeviceAccessController} using the specified data file.
      *
      * @param file The input file that contains the S2-range-based access restriction information.
-     * @throws IOException in the event of a problem while reading the underlying file.
+     * @throws IOException              in the event of a problem while reading the underlying file.
      * @throws IllegalArgumentException if either the S2 level defined by
-     * {@code config_oem_enabled_satellite_s2cell_level} or the satellite access allow defined by
-     * {@code config_oem_enabled_satellite_access_allow} does not match the values included in the
-     * header of the input file.
+     *                                  {@code config_oem_enabled_satellite_s2cell_level} or the
+     *                                  satellite access allow defined by
+     *                                  {@code config_oem_enabled_satellite_access_allow} does not
+     *                                  match the values included in the
+     *                                  header of the input file.
      */
     public static S2RangeSatelliteOnDeviceAccessController create(
-            @NonNull File file) throws IOException, IllegalArgumentException {
+            @NonNull File file, FeatureFlags featureFlags)
+            throws IOException, IllegalArgumentException {
         SatS2RangeFileReader reader = SatS2RangeFileReader.open(file);
         int s2Level = reader.getS2Level();
-        return new S2RangeSatelliteOnDeviceAccessController(reader, s2Level);
+        return new S2RangeSatelliteOnDeviceAccessController(reader, s2Level, featureFlags);
     }
 
     public static LocationToken createLocationTokenForLatLng(
@@ -84,7 +101,7 @@
     }
 
     private boolean isSatCommunicationAllowedAtLocation(long s2CellId) throws IOException {
-        S2LevelRange entry = mSatS2RangeFileReader.findEntryByCellId(s2CellId);
+        SuffixTableRange entry = mSatS2RangeFileReader.findEntryByCellId(s2CellId);
         if (mSatS2RangeFileReader.isAllowedList()) {
             // The file contains an allowed list of S2 cells. Thus, satellite is allowed if an
             // entry is found
@@ -158,4 +175,21 @@
             return Objects.hash(mS2CellId);
         }
     }
+
+    @Override
+    @Nullable
+    public Integer getRegionalConfigIdForLocation(LocationToken locationToken)
+            throws IOException {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            logd("getAccessControlConfigIdForLocation: carrierRoamingNbIotNtn is disabled");
+            return null;
+        }
+
+        if (!isSatCommunicationAllowedAtLocation(locationToken)) {
+            logd("getRegionalConfigIdForLocation: isSatCommunicationAllowedAtLocation is false");
+            return null;
+        }
+
+        return DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+    }
 }
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index f9bf0e8..c720917 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -145,6 +145,8 @@
     protected static final int EVENT_COUNTRY_CODE_CHANGED = 5;
     protected static final int EVENT_LOCATION_SETTINGS_ENABLED = 6;
 
+    public static final int DEFAULT_REGIONAL_SATELLITE_CONFIG_ID = 0;
+
     private static SatelliteAccessController sInstance;
 
     /** Feature flags to control behavior and errors. */
@@ -209,6 +211,9 @@
     @GuardedBy("mLock")
     @Nullable
     private Location mFreshLastKnownLocation = null;
+    @GuardedBy("mLock")
+    @Nullable
+    private Integer mRegionalConfigId = null;
 
     /** These are used for CTS test */
     private Path mCtsSatS2FilePath = null;
@@ -611,7 +616,7 @@
     private boolean isS2CellFileValid(@NonNull File s2CellFile) {
         try {
             SatelliteOnDeviceAccessController satelliteOnDeviceAccessController =
-                    SatelliteOnDeviceAccessController.create(s2CellFile);
+                    SatelliteOnDeviceAccessController.create(s2CellFile, mFeatureFlags);
             int s2Level = satelliteOnDeviceAccessController.getS2Level();
             if (s2Level < MIN_S2_LEVEL || s2Level > MAX_S2_LEVEL) {
                 ploge("isS2CellFileValid: invalid s2 level = " + s2Level);
@@ -1242,14 +1247,6 @@
 
     private void executeLocationQuery() {
         plogd("executeLocationQuery");
-        synchronized (mPossibleChangeInSatelliteAllowedRegionLock) {
-            if (isSatelliteAllowedRegionPossiblyChanged()) {
-                mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos =
-                        getElapsedRealtimeNanos();
-                plogd("mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos is set "
-                        + mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
-            }
-        }
         synchronized (mLock) {
             mFreshLastKnownLocation = getFreshLastKnownLocation();
             checkSatelliteAccessRestrictionUsingOnDeviceData();
@@ -1321,6 +1318,16 @@
                         + "Request for current location was already sent to LocationManager");
                 return;
             }
+
+            synchronized (mPossibleChangeInSatelliteAllowedRegionLock) {
+                if (isSatelliteAllowedRegionPossiblyChanged()) {
+                    mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos =
+                            getElapsedRealtimeNanos();
+                    plogd("mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos is set "
+                            + mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
+                }
+            }
+
             mLocationRequestCancellationSignal = new CancellationSignal();
             mLocationQueryStartTimeMillis = System.currentTimeMillis();
             mLocationManager.getCurrentLocation(LocationManager.FUSED_PROVIDER,
@@ -1372,7 +1379,7 @@
         }
     }
 
-    private void checkSatelliteAccessRestrictionForLocation(@NonNull Location location) {
+    protected void checkSatelliteAccessRestrictionForLocation(@NonNull Location location) {
         synchronized (mLock) {
             try {
                 SatelliteOnDeviceAccessController.LocationToken locationToken =
@@ -1391,8 +1398,18 @@
                                 false);
                         return;
                     }
-                    satelliteAllowed = mSatelliteOnDeviceAccessController
-                            .isSatCommunicationAllowedAtLocation(locationToken);
+
+                    if (mFeatureFlags.carrierRoamingNbIotNtn()) {
+                        synchronized (mLock) {
+                            mRegionalConfigId = mSatelliteOnDeviceAccessController
+                                    .getRegionalConfigIdForLocation(locationToken);
+                            plogd("mRegionalConfigId is " + mRegionalConfigId);
+                            satelliteAllowed = (mRegionalConfigId != null);
+                        }
+                    } else {
+                        satelliteAllowed = mSatelliteOnDeviceAccessController
+                                .isSatCommunicationAllowedAtLocation(locationToken);
+                    }
                     updateCachedAccessRestrictionMap(locationToken, satelliteAllowed);
                 }
                 mAccessControllerMetricsStats.setOnDeviceLookupTime(mOnDeviceLookupStartTimeMillis);
@@ -1580,7 +1597,8 @@
 
             try {
                 mSatelliteOnDeviceAccessController =
-                        SatelliteOnDeviceAccessController.create(getSatelliteS2CellFile());
+                        SatelliteOnDeviceAccessController.create(
+                                getSatelliteS2CellFile(), mFeatureFlags);
                 restartKeepOnDeviceAccessControllerResourcesTimer();
                 mS2Level = mSatelliteOnDeviceAccessController.getS2Level();
                 plogd("mS2Level=" + mS2Level);
@@ -2020,6 +2038,32 @@
         }
     }
 
+    /**
+     * This API can be used only for test purpose to override the carrier roaming Ntn eligibility
+     *
+     * @param state         to update Ntn Eligibility.
+     * @param resetRequired to reset the overridden flag in satellite controller.
+     * @return {@code true} if the shell command is successful, {@code false} otherwise.
+     */
+    public boolean overrideCarrierRoamingNtnEligibilityChanged(boolean state,
+            boolean resetRequired) {
+        if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+            logd("overrideCarrierRoamingNtnEligibilityChanged: "
+                    + "carrierRoamingNbIotNtn is disabled");
+            return false;
+        }
+
+        if (!isMockModemAllowed()) {
+            logd("overrideCarrierRoamingNtnEligibilityChanged: "
+                    + "mock modem not allowed.");
+            return false;
+        }
+
+        logd("calling overrideCarrierRoamingNtnEligibilityChanged");
+        return mSatelliteController.overrideCarrierRoamingNtnEligibilityChanged(state,
+                resetRequired);
+    }
+
     private void plogv(@NonNull String log) {
         Rlog.v(TAG, log);
         if (mPersistentLogger != null) {
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteOnDeviceAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteOnDeviceAccessController.java
index 520699f..2d7cf96 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteOnDeviceAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteOnDeviceAccessController.java
@@ -16,6 +16,9 @@
 package com.android.phone.satellite.accesscontrol;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.telephony.flags.FeatureFlags;
 
 import java.io.Closeable;
 import java.io.File;
@@ -34,13 +37,15 @@
      * but at the cost of some memory, or close it immediately after a single use.
      *
      * @param file The input file that contains the location-based access restriction information.
-     * @throws IOException in the unlikely event of errors when reading underlying file(s)
+     * @throws IOException              in the unlikely event of errors when reading underlying
+     *                                  file(s)
      * @throws IllegalArgumentException if the input file format does not match the format defined
-     * by the device overlay configs.
+     *                                  by the device overlay configs.
      */
     public static SatelliteOnDeviceAccessController create(
-            @NonNull File file) throws IOException, IllegalArgumentException {
-        return S2RangeSatelliteOnDeviceAccessController.create(file);
+            @NonNull File file, @NonNull FeatureFlags featureFlags)
+            throws IOException, IllegalArgumentException {
+        return S2RangeSatelliteOnDeviceAccessController.create(file, featureFlags);
     }
 
     /**
@@ -83,4 +88,14 @@
         /** This will print out the location information */
         public abstract String toPiiString();
     }
+
+    /**
+     * Returns an unsigned integer if a regional access control config ID is found for the current
+     * location, {@code null} otherwise.
+     *
+     * @throws IOException in the unlikely event of errors when reading the underlying file
+     */
+    @Nullable
+    public abstract Integer getRegionalConfigIdForLocation(LocationToken locationToken)
+            throws IOException;
 }
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 48786dc..e753e20 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -1046,7 +1046,7 @@
     }
 
     private static Integer getSatelliteErrorString() {
-        if (SatelliteController.getInstance().isSatelliteEnabled()) {
+        if (SatelliteController.getInstance().isSatelliteEnabledOrBeingEnabled()) {
             return R.string.incall_error_satellite_enabled;
         }
         return R.string.incall_error_carrier_roaming_satellite_mode;
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index c39d121..c7d97f5 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -434,7 +434,7 @@
             boolean isVideoEnabledByPlatform = ImsManager.getInstance(mPhone.getContext(),
                     mPhone.getPhoneId()).isVtEnabledByPlatform();
 
-            if (!mIsPrimaryUser) {
+            if (!mDoesUserSupportVideoCalling) {
                 Log.i(this, "Disabling video calling for secondary user.");
                 mIsVideoCapable = false;
                 isVideoEnabledByPlatform = false;
@@ -1214,7 +1214,7 @@
                 Log.i(this, "TelecomAccountRegistry: User changed, re-registering phone accounts.");
 
                 UserHandle currentUser = intent.getParcelableExtra(Intent.EXTRA_USER);
-                mIsPrimaryUser = currentUser == null ? true : currentUser.isSystem();
+                mDoesUserSupportVideoCalling = currentUser == null ? true : currentUser.isSystem();
 
                 // Any time the user changes, re-register the accounts.
                 tearDownAccounts();
@@ -1287,7 +1287,8 @@
     private int mSubscriptionListenerState = LISTENER_STATE_UNREGISTERED;
     private int mServiceState = ServiceState.STATE_POWER_OFF;
     private int mActiveDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    private boolean mIsPrimaryUser = UserHandle.of(ActivityManager.getCurrentUser()).isSystem();
+    private boolean mDoesUserSupportVideoCalling =
+            UserHandle.of(ActivityManager.getCurrentUser()).isSystem();
     private ExponentialBackoff mRegisterSubscriptionListenerBackoff;
     private ExponentialBackoff mTelecomReadyBackoff;
     private final HandlerThread mHandlerThread = new HandlerThread("TelecomAccountRegistry");
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 6a4ea3e..e7f91d4 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1185,8 +1185,7 @@
         boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
                 || (isRadioPowerDownOnBluetooth() && !isPhoneWifiCallingEnabled);
 
-        if (mSatelliteController.isSatelliteEnabled()
-                || mSatelliteController.isSatelliteBeingEnabled()) {
+        if (mSatelliteController.isSatelliteEnabledOrBeingEnabled()) {
             Log.d(this, "onCreateOutgoingConnection, "
                     + " needToTurnOnRadio=" + needToTurnOnRadio
                     + " needToTurnOffSatellite=" + needToTurnOffSatellite
@@ -1287,8 +1286,7 @@
                         // reporting the OUT_OF_SERVICE state.
                         return phone.getState() == PhoneConstants.State.OFFHOOK
                                 || (phone.getServiceStateTracker().isRadioOn()
-                                && (!mSatelliteController.isSatelliteEnabled()
-                                    && !mSatelliteController.isSatelliteBeingEnabled()));
+                                && !mSatelliteController.isSatelliteEnabledOrBeingEnabled());
                     } else {
                         SubscriptionInfoInternal subInfo = SubscriptionManagerService
                                 .getInstance().getSubscriptionInfoInternal(phone.getSubId());
@@ -2152,8 +2150,7 @@
     }
 
     private boolean shouldExitSatelliteModeForEmergencyCall(boolean isEmergencyNumber) {
-        if (!mSatelliteController.isSatelliteEnabled()
-                && !mSatelliteController.isSatelliteBeingEnabled()) {
+        if (!mSatelliteController.isSatelliteEnabledOrBeingEnabled()) {
             return false;
         }
 
diff --git a/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
index 2ace0ad..23f6ee9 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_SatelliteControl.xml
@@ -145,6 +145,12 @@
             android:layout_height="wrap_content"
             android:paddingRight="4dp"
             android:text="@string/provisionSatellite"/>
+        <Button
+            android:id="@+id/deprovisionSatellite"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/deprovisionSatellite"/>
          <Button
             android:id="@+id/Back"
             android:onClick="Back"
diff --git a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
index f4ed82e..9aec52b 100644
--- a/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
+++ b/testapps/TestSatelliteApp/res/layout/activity_TestSatelliteWrapper.xml
@@ -173,6 +173,24 @@
             android:layout_height="wrap_content"
             android:paddingRight="4dp"
             android:text="@string/unregisterForModemStateChanged"/>
+        <Button
+            android:id="@+id/requestSatelliteSubscriberProvisionStatusWrapper"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/requestSatelliteSubscriberProvisionStatus"/>
+        <Button
+            android:id="@+id/provisionSatelliteWrapper"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/provisionSatellite"/>
+        <Button
+            android:id="@+id/deprovisionSatelliteWrapper"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingRight="4dp"
+            android:text="@string/deprovisionSatellite"/>
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
index b0aa492..54f2722 100644
--- a/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
+++ b/testapps/TestSatelliteApp/res/values/donottranslate_strings.xml
@@ -96,6 +96,7 @@
 
     <string name="requestSatelliteSubscriberProvisionStatus">requestSatelliteSubscriberProvisionStatus</string>
     <string name="provisionSatellite">provisionSatellite</string>
+    <string name="deprovisionSatellite">deprovisionSatellite</string>
 
     <string name="Back">Back</string>
     <string name="ClearLog">Clear Log</string>
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
index 15c8fd8..08984be 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/Provisioning.java
@@ -24,12 +24,14 @@
 import android.os.OutcomeReceiver;
 import android.telephony.satellite.SatelliteManager;
 import android.telephony.satellite.SatelliteProvisionStateCallback;
+import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
 import android.telephony.satellite.stub.SatelliteResult;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
 
+import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
@@ -82,6 +84,12 @@
             Log.d(TAG, "onSatelliteProvisionStateChanged in SatelliteTestApp: provisioned="
                     + mProvisioned);
         }
+
+        @Override
+        public void onSatelliteSubscriptionProvisionStateChanged(
+                List<SatelliteSubscriberProvisionStatus> list) {
+            Log.d(TAG, "onSatelliteSubscriptionProvisionStateChanged in SatelliteTestApp" + list);
+        }
     }
 
     private void provisionServiceApp(View view) {
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
index 5d47929..484a6d1 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SatelliteControl.java
@@ -35,6 +35,7 @@
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.List;
+import android.util.Log;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
@@ -44,7 +45,7 @@
  */
 public class SatelliteControl extends Activity {
 
-    private static final long TIMEOUT = 3000;
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(3);
 
     private SatelliteManager mSatelliteManager;
     private SubscriptionManager mSubscriptionManager;
@@ -94,6 +95,8 @@
                 .setOnClickListener(this::requestSatelliteSubscriberProvisionStatusApp);
         findViewById(R.id.provisionSatellite)
                 .setOnClickListener(this::provisionSatelliteApp);
+        findViewById(R.id.deprovisionSatellite)
+                .setOnClickListener(this::deprovisionSatelliteApp);
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
@@ -110,18 +113,24 @@
                         .setEmergencyMode(true)
                         .build(), Runnable::run, error::offer);
         TextView textView = findViewById(R.id.text_id);
+        Log.d("SatelliteTestApp", "enableSatelliteApp: isDemoMode=" + isDemoMode);
         try {
             Integer value = error.poll(TIMEOUT, TimeUnit.MILLISECONDS);
             if (value == null) {
                 textView.setText("Timed out to enable the satellite");
+                Log.d("SatelliteTestApp", "Timed out to enable the satellite");
             } else if (value != SatelliteResult.SATELLITE_RESULT_SUCCESS) {
                 textView.setText("Failed to enable the satellite, error ="
                         + SatelliteErrorUtils.mapError(value));
+                Log.d("SatelliteTestApp", "Failed to enable the satellite, error ="
+                        + SatelliteErrorUtils.mapError(value));
             } else {
                 textView.setText("Successfully enabled the satellite");
+                Log.d("SatelliteTestApp", "Successfully enabled the satellite");
             }
         } catch (InterruptedException e) {
             textView.setText("Enable SatelliteService exception caught =" + e);
+            Log.d("SatelliteTestApp", "Enable SatelliteService exception caught =" + e);
         }
     }
 
@@ -460,4 +469,36 @@
         }
         mSatelliteManager.provisionSatellite(list, Runnable::run, receiver);
     }
+
+    private void deprovisionSatelliteApp(View view) {
+        final AtomicReference<Boolean> enabled = new AtomicReference<>();
+        final AtomicReference<Integer> errorCode = new AtomicReference<>();
+        OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> receiver =
+                new OutcomeReceiver<>() {
+                    @Override
+                    public void onResult(Boolean result) {
+                        enabled.set(result);
+                        TextView textView = findViewById(R.id.text_id);
+                        if (enabled.get()) {
+                            textView.setText("deprovisionSatellite is true");
+                        } else {
+                            textView.setText("Status for deprovisionSatellite result : "
+                                    + enabled.get());
+                        }
+                    }
+
+                    @Override
+                    public void onError(SatelliteManager.SatelliteException exception) {
+                        errorCode.set(exception.getErrorCode());
+                        TextView textView = findViewById(R.id.text_id);
+                        textView.setText("Status for deprovisionSatellite error : "
+                                + SatelliteErrorUtils.mapError(errorCode.get()));
+                    }
+                };
+        List<SatelliteSubscriberInfo> list = new ArrayList<>();
+        for (SatelliteSubscriberProvisionStatus status : mSatelliteSubscriberProvisionStatuses) {
+            list.add(status.getSatelliteSubscriberInfo());
+        }
+        mSatelliteManager.deprovisionSatellite(list, Runnable::run, receiver);
+    }
 }
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
index ede2377..bc60c9b 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/SendReceive.java
@@ -290,7 +290,7 @@
             satellitePositionTextView.setText("startSatelliteTransmissionUpdates exception caught ="
                         + e);
         }
-        //Device is aligned with the satellite for demo mode
+        //Device is aligned with the satellite
         mSatelliteManager.setDeviceAlignedWithSatellite(true);
     }
 }
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
index 9c75a84..225fba0 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteService.java
@@ -60,7 +60,7 @@
     private static final int SATELLITE_ALWAYS_VISIBLE = 0;
     /** SatelliteCapabilities constant indicating that the radio technology is proprietary. */
     private static final int[] SUPPORTED_RADIO_TECHNOLOGIES =
-            new int[]{NTRadioTechnology.PROPRIETARY};
+            new int[]{NTRadioTechnology.NB_IOT_NTN};
     /** SatelliteCapabilities constant indicating that pointing to satellite is required. */
     private static final boolean POINTING_TO_SATELLITE_REQUIRED = true;
     /** SatelliteCapabilities constant indicating the maximum number of characters per datagram. */
@@ -208,14 +208,14 @@
 
     private void enableSatellite(@NonNull IIntegerConsumer errorCallback) {
         mIsEnabled = true;
-        updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE);
         runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS));
+        updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IN_SERVICE);
     }
 
     private void disableSatellite(@NonNull IIntegerConsumer errorCallback) {
         mIsEnabled = false;
-        updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_OFF);
         runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS));
+        updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_OFF);
     }
 
     @Override
@@ -494,6 +494,7 @@
      * @param modemState The {@link SatelliteModemState} to update.
      */
     private void updateSatelliteModemState(int modemState) {
+        logd("updateSatelliteModemState: new modemState=" + modemState);
         if (modemState == mModemState) {
             return;
         }
diff --git a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
index d8e6e7c..97cb9c3 100644
--- a/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
+++ b/testapps/TestSatelliteApp/src/com/android/phone/testapps/satellitetestapp/TestSatelliteWrapper.java
@@ -30,6 +30,8 @@
 import android.telephony.satellite.wrapper.SatelliteCommunicationAllowedStateCallbackWrapper;
 import android.telephony.satellite.wrapper.SatelliteManagerWrapper;
 import android.telephony.satellite.wrapper.SatelliteModemStateCallbackWrapper2;
+import android.telephony.satellite.wrapper.SatelliteSubscriberInfoWrapper;
+import android.telephony.satellite.wrapper.SatelliteSubscriberProvisionStatusWrapper;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -62,6 +64,8 @@
     private SatelliteCapabilitiesCallbackWrapper mSatelliteCapabilitiesCallback;
     private SubscriptionManager mSubscriptionManager;
     private int mSubId;
+    private List<SatelliteSubscriberProvisionStatusWrapper> mSatelliteSubscriberProvisionStatuses =
+            new ArrayList<>();
 
     private ListView mLogListView;
 
@@ -117,6 +121,12 @@
                 .setOnClickListener(this::registerForModemStateChanged);
         findViewById(R.id.unregisterForModemStateChanged)
                 .setOnClickListener(this::unregisterForModemStateChanged);
+        findViewById(R.id.requestSatelliteSubscriberProvisionStatusWrapper)
+                .setOnClickListener(this::requestSatelliteSubscriberProvisionStatus);
+        findViewById(R.id.provisionSatelliteWrapper)
+                .setOnClickListener(this::provisionSatellite);
+        findViewById(R.id.deprovisionSatelliteWrapper)
+                .setOnClickListener(this::deprovisionSatellite);
 
         findViewById(R.id.Back).setOnClickListener(new OnClickListener() {
             @Override
@@ -389,7 +399,137 @@
         }
     }
 
+    private void requestSatelliteSubscriberProvisionStatus(View view) {
+        addLogMessage("requestSatelliteSubscriberProvisionStatus");
+        logd("requestSatelliteSubscriberProvisionStatus");
 
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            addLogMessage("requestSatelliteSubscriberProvisionStatus: Subscription ID is invalid");
+            logd("requestSatelliteSubscriberProvisionStatus: Subscription ID is invalid");
+            return;
+        }
+
+        OutcomeReceiver<List<SatelliteSubscriberProvisionStatusWrapper>,
+                SatelliteManagerWrapper.SatelliteExceptionWrapper> receiver =
+                new OutcomeReceiver<>() {
+                    @Override
+                    public void onResult(List<SatelliteSubscriberProvisionStatusWrapper> result) {
+                        mSatelliteSubscriberProvisionStatuses = result;
+                        logd("requestSatelliteSubscriberProvisionStatus: onResult=" + result);
+                        addLogMessage(
+                                "requestSatelliteSubscriberProvisionStatus: onResult=" + result);
+                    }
+
+                    @Override
+                    public void onError(
+                            SatelliteManagerWrapper.SatelliteExceptionWrapper exception) {
+                        if (exception != null) {
+                            String onError = "requestSatelliteSubscriberProvisionStatus exception: "
+                                    + translateResultCodeToString(exception.getErrorCode());
+                            logd(onError);
+                            addLogMessage(onError);
+                        }
+                    }
+                };
+
+        try {
+            mSatelliteManagerWrapper.requestSatelliteSubscriberProvisionStatus(mExecutor, receiver);
+        } catch (SecurityException | IllegalArgumentException ex) {
+            String errorMessage = "requestSatelliteSubscriberProvisionStatus: " + ex.getMessage();
+            logd(errorMessage);
+            addLogMessage(errorMessage);
+        }
+    }
+
+    private void provisionSatellite(View view) {
+        addLogMessage("provisionSatellite");
+        logd("provisionSatellite");
+
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            addLogMessage("provisionSatellite: Subscription ID is invalid");
+            logd("provisionSatellite: Subscription ID is invalid");
+            return;
+        }
+
+        OutcomeReceiver<Boolean,
+                SatelliteManagerWrapper.SatelliteExceptionWrapper> receiver =
+                new OutcomeReceiver<>() {
+                    @Override
+                    public void onResult(Boolean result) {
+                        logd("provisionSatellite: onResult=" + result);
+                        addLogMessage("provisionSatellite: onResult=" + result);
+                    }
+
+                    @Override
+                    public void onError(
+                            SatelliteManagerWrapper.SatelliteExceptionWrapper exception) {
+                        if (exception != null) {
+                            String onError = "provisionSatellite exception: "
+                                    + translateResultCodeToString(exception.getErrorCode());
+                            logd(onError);
+                            addLogMessage(onError);
+                        }
+                    }
+                };
+
+        List<SatelliteSubscriberInfoWrapper> list = new ArrayList<>();
+        for (SatelliteSubscriberProvisionStatusWrapper status :
+                mSatelliteSubscriberProvisionStatuses) {
+            list.add(status.getSatelliteSubscriberInfo());
+        }
+        try {
+            mSatelliteManagerWrapper.provisionSatellite(list, mExecutor, receiver);
+        } catch (SecurityException | IllegalArgumentException ex) {
+            String errorMessage = "provisionSatellite: " + ex.getMessage();
+            logd(errorMessage);
+            addLogMessage(errorMessage);
+        }
+    }
+
+    private void deprovisionSatellite(View view) {
+        addLogMessage("deprovisionSatellite");
+        logd("deprovisionSatellite");
+
+        if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+            addLogMessage("deprovisionSatellite: Subscription ID is invalid");
+            logd("deprovisionSatellite: Subscription ID is invalid");
+            return;
+        }
+
+        OutcomeReceiver<Boolean,
+                SatelliteManagerWrapper.SatelliteExceptionWrapper> receiver =
+                new OutcomeReceiver<>() {
+                    @Override
+                    public void onResult(Boolean result) {
+                        logd("deprovisionSatellite: onResult=" + result);
+                        addLogMessage("deprovisionSatellite: onResult=" + result);
+                    }
+
+                    @Override
+                    public void onError(
+                            SatelliteManagerWrapper.SatelliteExceptionWrapper exception) {
+                        if (exception != null) {
+                            String onError = "deprovisionSatellite exception: "
+                                    + translateResultCodeToString(exception.getErrorCode());
+                            logd(onError);
+                            addLogMessage(onError);
+                        }
+                    }
+                };
+
+        List<SatelliteSubscriberInfoWrapper> list = new ArrayList<>();
+        for (SatelliteSubscriberProvisionStatusWrapper status :
+                mSatelliteSubscriberProvisionStatuses) {
+            list.add(status.getSatelliteSubscriberInfo());
+        }
+        try {
+            mSatelliteManagerWrapper.deprovisionSatellite(list, mExecutor, receiver);
+        } catch (SecurityException | IllegalArgumentException ex) {
+            String errorMessage = "deprovisionSatellite: " + ex.getMessage();
+            logd(errorMessage);
+            addLogMessage(errorMessage);
+        }
+    }
 
     public class NtnSignalStrengthCallback implements NtnSignalStrengthCallbackWrapper {
         @Override
diff --git a/tests/src/com/android/phone/CarrierConfigLoaderTest.java b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
index bda2313..99064dd 100644
--- a/tests/src/com/android/phone/CarrierConfigLoaderTest.java
+++ b/tests/src/com/android/phone/CarrierConfigLoaderTest.java
@@ -57,7 +57,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.TelephonyTestBase;
+import com.android.internal.telephony.GsmCdmaPhone;
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.subscription.SubscriptionManagerService;
 
@@ -104,6 +107,7 @@
     @Mock SharedPreferences mSharedPreferences;
     @Mock TelephonyRegistryManager mTelephonyRegistryManager;
     @Mock FeatureFlags mFeatureFlags;
+    @Mock GsmCdmaPhone mMockPhone;
 
     private TelephonyManager mTelephonyManager;
     private CarrierConfigLoader mCarrierConfigLoader;
@@ -118,6 +122,9 @@
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
+        Phone[] mPhones = new Phone[]{mMockPhone};
+        replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+        replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true);
         doReturn(Context.PERMISSION_ENFORCER_SERVICE).when(mContext).getSystemServiceName(
                 eq(PermissionEnforcer.class));
         doReturn(mFakePermissionEnforcer).when(mContext).getSystemService(
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
index 16a256d..678d069 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/S2RangeSatelliteOnDeviceAccessControllerTest.java
@@ -16,13 +16,22 @@
 
 package com.android.phone.satellite.accesscontrol;
 
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.storage.s2.S2LevelRange;
+
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.utils.TestUtils;
 import com.android.telephony.sats2range.write.SatS2RangeFileWriter;
 
@@ -33,6 +42,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.io.File;
@@ -44,6 +54,9 @@
 public class S2RangeSatelliteOnDeviceAccessControllerTest {
     private File mFile;
 
+    @Mock
+    private FeatureFlags mMockFeatureFlags;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -79,7 +92,7 @@
         // Validate the output block file
         SatelliteOnDeviceAccessController accessController = null;
         try {
-            accessController = SatelliteOnDeviceAccessController.create(mFile);
+            accessController = SatelliteOnDeviceAccessController.create(mFile, mMockFeatureFlags);
             int s2Level = accessController.getS2Level();
 
             // Verify an edge cell of range 1 not in the output file
@@ -88,9 +101,23 @@
             SatelliteOnDeviceAccessController.LocationToken locationToken =
                     SatelliteOnDeviceAccessController.createLocationTokenForLatLng(
                             s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
+
+            // Verify if the return value is null, when the carrierRoamingNbIotNtn is disabled.
+            doReturn(false).when(mMockFeatureFlags).carrierRoamingNbIotNtn();
+            assertNull(accessController.getRegionalConfigIdForLocation(locationToken));
+
+            doReturn(true).when(mMockFeatureFlags).carrierRoamingNbIotNtn();
             boolean isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
             assertTrue(isAllowed != isAllowedList);
 
+            Integer configId = accessController.getRegionalConfigIdForLocation(locationToken);
+            if (isAllowedList) {
+                assertNull(configId);
+            } else {
+                assertNotNull(configId);
+                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+            }
+
             // Verify cells in range1 present in the output file
             for (int suffix = 1000; suffix < 2000; suffix++) {
                 s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1000, suffix));
@@ -98,9 +125,17 @@
 
                 // Lookup using location token
                 locationToken = SatelliteOnDeviceAccessController.createLocationTokenForLatLng(
-                                s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
+                        s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
                 isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
                 assertTrue(isAllowed == isAllowedList);
+
+                configId = accessController.getRegionalConfigIdForLocation(locationToken);
+                if (isAllowedList) {
+                    assertNotNull(configId);
+                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+                } else {
+                    assertNull(configId);
+                }
             }
 
             // Verify the middle cell not in the output file
@@ -111,6 +146,14 @@
             isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
             assertTrue(isAllowed != isAllowedList);
 
+            configId = accessController.getRegionalConfigIdForLocation(locationToken);
+            if (isAllowedList) {
+                assertNull(configId);
+            } else {
+                assertNotNull(configId);
+                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+            }
+
             // Verify cells in range2 present in the output file
             for (int suffix = 2001; suffix < 3000; suffix++) {
                 s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1000, suffix));
@@ -119,6 +162,14 @@
                         s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
                 isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
                 assertTrue(isAllowed == isAllowedList);
+
+                configId = accessController.getRegionalConfigIdForLocation(locationToken);
+                if (isAllowedList) {
+                    assertNotNull(configId);
+                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+                } else {
+                    assertNull(configId);
+                }
             }
 
             // Verify an edge cell of range 2 not in the output file
@@ -129,6 +180,14 @@
             isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
             assertTrue(isAllowed != isAllowedList);
 
+            configId = accessController.getRegionalConfigIdForLocation(locationToken);
+            if (isAllowedList) {
+                assertNull(configId);
+            } else {
+                assertNotNull(configId);
+                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+            }
+
             // Verify an edge cell of range 3 not in the output file
             s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1001, 999));
             s2LatLng = s2CellId.toLatLng();
@@ -137,6 +196,14 @@
             isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
             assertTrue(isAllowed != isAllowedList);
 
+            configId = accessController.getRegionalConfigIdForLocation(locationToken);
+            if (isAllowedList) {
+                assertNull(configId);
+            } else {
+                assertNotNull(configId);
+                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+            }
+
             // Verify cells in range1 present in the output file
             for (int suffix = 1000; suffix < 2000; suffix++) {
                 s2CellId = new S2CellId(TestUtils.createCellId(fileFormat, 1, 1001, suffix));
@@ -145,6 +212,14 @@
                         s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
                 isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
                 assertTrue(isAllowed == isAllowedList);
+
+                configId = accessController.getRegionalConfigIdForLocation(locationToken);
+                if (isAllowedList) {
+                    assertNotNull(configId);
+                    assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+                } else {
+                    assertNull(configId);
+                }
             }
 
             // Verify an edge cell of range 3 not in the output file
@@ -154,6 +229,15 @@
                     s2LatLng.latDegrees(), s2LatLng.lngDegrees(), s2Level);
             isAllowed = accessController.isSatCommunicationAllowedAtLocation(locationToken);
             assertTrue(isAllowed != isAllowedList);
+
+            configId = accessController.getRegionalConfigIdForLocation(locationToken);
+            if (isAllowedList) {
+                assertNull(configId);
+            } else {
+                assertNotNull(configId);
+                assertEquals(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID, (int) configId);
+            }
+
         } catch (Exception ex) {
             fail("Unexpected exception when validating the output ex=" + ex);
         } finally {
@@ -166,24 +250,24 @@
     private SatS2RangeFileFormat createSatS2File(
             File file, boolean isAllowedList) throws Exception {
         SatS2RangeFileFormat fileFormat;
-        S2LevelRange range1, range2, range3;
+        SuffixTableRange range1, range2, range3;
         try (SatS2RangeFileWriter satS2RangeFileWriter = SatS2RangeFileWriter.open(
                 file, TestUtils.createS2RangeFileFormat(isAllowedList))) {
             fileFormat = satS2RangeFileWriter.getFileFormat();
 
             // Two ranges that share a prefix.
-            range1 = new S2LevelRange(
+            range1 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1000, 1000),
                     TestUtils.createCellId(fileFormat, 1, 1000, 2000));
-            range2 = new S2LevelRange(
+            range2 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1000, 2001),
                     TestUtils.createCellId(fileFormat, 1, 1000, 3000));
             // This range has a different prefix, so will be in a different suffix table.
-            range3 = new S2LevelRange(
+            range3 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1001, 1000),
                     TestUtils.createCellId(fileFormat, 1, 1001, 2000));
 
-            List<S2LevelRange> ranges = new ArrayList<>();
+            List<SuffixTableRange> ranges = new ArrayList<>();
             ranges.add(range1);
             ranges.add(range2);
             ranges.add(range3);
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index 3d2c953..971f87a 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -29,6 +29,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.ALLOWED_STATE_CACHE_VALID_DURATION_NANOS;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_REGIONAL_SATELLITE_CONFIG_ID;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_COUNTRY_CODE_CHANGED;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.CMD_IS_SATELLITE_COMMUNICATION_ALLOWED;
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.DEFAULT_DELAY_MINUTES_BEFORE_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION;
@@ -319,8 +320,9 @@
         when(mMockLocation0.getLongitude()).thenReturn(0.0);
         when(mMockLocation1.getLatitude()).thenReturn(1.0);
         when(mMockLocation1.getLongitude()).thenReturn(1.0);
-        when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
-                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(true);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
 
         when(mMockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(
                 mMockSharedPreferences);
@@ -339,6 +341,7 @@
         when(mMockFeatureFlags.satellitePersistentLogging()).thenReturn(true);
         when(mMockFeatureFlags.geofenceEnhancementForBetterUx()).thenReturn(true);
         when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        when(mMockFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
 
         mSatelliteAccessControllerUT = new TestSatelliteAccessController(mMockContext,
                 mMockFeatureFlags, mLooper, mMockLocationManager, mMockTelecomManager,
@@ -442,7 +445,7 @@
         assertFalse(mSatelliteAccessControllerUT
                 .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_US)));
         assertFalse(mSatelliteAccessControllerUT.isSatelliteAccessAllowedForLocation(
-                        List.of(TEST_SATELLITE_COUNTRY_CODE_US, TEST_SATELLITE_COUNTRY_CODE_KR)));
+                List.of(TEST_SATELLITE_COUNTRY_CODE_US, TEST_SATELLITE_COUNTRY_CODE_KR)));
         assertTrue(mSatelliteAccessControllerUT
                 .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_KR)));
 
@@ -488,8 +491,9 @@
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
         doReturn(true).when(mMockLocationManager).isLocationEnabled();
-        when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
-                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(true);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
         replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
                 mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
         doReturn(true).when(mMockCachedAccessRestrictionMap).containsKey(any());
@@ -725,7 +729,7 @@
         mTestableLooper.processAllMessages();
         assertTrue(
                 mSatelliteAccessControllerUT.isKeepOnDeviceAccessControllerResourcesTimerStarted());
-        verify(mMockSatelliteOnDeviceAccessController).isSatCommunicationAllowedAtLocation(
+        verify(mMockSatelliteOnDeviceAccessController).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
@@ -770,7 +774,7 @@
         sendLocationRequestResult(mMockLocation0);
         assertFalse(mSatelliteAccessControllerUT.isWaitForCurrentLocationTimerStarted());
         // The LocationToken should be already in the cache
-        verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
+        verify(mMockSatelliteOnDeviceAccessController, never()).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
@@ -802,7 +806,7 @@
                 mSatelliteAccessControllerUT.getWaitForCurrentLocationTimeoutMillis());
         mTestableLooper.processAllMessages();
         assertFalse(mSatelliteAccessControllerUT.isWaitForCurrentLocationTimerStarted());
-        verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
+        verify(mMockSatelliteOnDeviceAccessController, never()).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
@@ -828,7 +832,7 @@
         verify(mMockLocationManager, never()).getCurrentLocation(anyString(),
                 any(LocationRequest.class), any(CancellationSignal.class), any(Executor.class),
                 any(Consumer.class));
-        verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
+        verify(mMockSatelliteOnDeviceAccessController, never()).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
@@ -837,6 +841,92 @@
     }
 
     @Test
+    public void testLocationQueryThrottleTimeUpdate() {
+        long firstMccChangedTime = 1;
+        long lastKnownLocationElapsedRealtime =
+                firstMccChangedTime + TEST_LOCATION_QUERY_THROTTLE_INTERVAL_NANOS;
+
+        // OEM-enabled satellite is supported
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        verify(mMockCountryDetector).registerForCountryCodeChanged(
+                mCountryDetectorHandlerCaptor.capture(), mCountryDetectorIntCaptor.capture(),
+                mCountryDetectorObjCaptor.capture());
+
+        assertSame(mCountryDetectorHandlerCaptor.getValue(), mSatelliteAccessControllerUT);
+        assertSame(mCountryDetectorIntCaptor.getValue(), EVENT_COUNTRY_CODE_CHANGED);
+        assertNull(mCountryDetectorObjCaptor.getValue());
+
+        // Setup to invoke GPS query
+        clearInvocations(mMockSatelliteOnDeviceAccessController);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockLocationManager).isLocationEnabled();
+        when(mMockLocationManager.getLastKnownLocation(LocationManager.FUSED_PROVIDER))
+                .thenReturn(null);
+        when(mMockLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER))
+                .thenReturn(null);
+
+        // When mcc changed first, so queried a location with GPS,
+        // verify if the mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos
+        // is the same with firstMccChangedTime.
+        // verify mMockLocationManager.getCurrentLocation() is invoked
+        // verify time(mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos) is
+        // firstMccChangedTime
+        clearInvocations(mMockLocationManager);
+        mSatelliteAccessControllerUT.elapsedRealtimeNanos = firstMccChangedTime;
+        sendCommandValidateCountryCodeChangeEvent(mMockContext);
+        verify(mMockLocationManager, times(1))
+                .getCurrentLocation(any(), any(), any(), any(), any());
+        assertEquals(firstMccChangedTime, mSatelliteAccessControllerUT
+                .mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
+
+        // set current time less than throttle_interval
+        // verify mMockLocationManager.getCurrentLocation() is not invoked
+        // verify time(mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos) is not updated
+        clearInvocations(mMockLocationManager);
+        doReturn(lastKnownLocationElapsedRealtime).when(mMockLocation1).getElapsedRealtimeNanos();
+        mSatelliteAccessControllerUT.elapsedRealtimeNanos =
+                (firstMccChangedTime + TEST_LOCATION_QUERY_THROTTLE_INTERVAL_NANOS - 1);
+        sendCommandValidateCountryCodeChangeEvent(mMockContext);
+        verify(mMockLocationManager, never())
+                .getCurrentLocation(any(), any(), any(), any(), any());
+        assertEquals(firstMccChangedTime, mSatelliteAccessControllerUT
+                .mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
+
+        // Test the scenario when last know location is fresh and
+        // current time is greater than the location query throttle interval
+        // verify mMockLocationManager.getCurrentLocation() is not invoked
+        // verify time(mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos) is not updated
+        clearInvocations(mMockLocationManager);
+        doReturn(lastKnownLocationElapsedRealtime).when(mMockLocation1).getElapsedRealtimeNanos();
+        mSatelliteAccessControllerUT.elapsedRealtimeNanos =
+                (lastKnownLocationElapsedRealtime + TEST_LOCATION_FRESH_DURATION_NANOS - 1);
+        sendCommandValidateCountryCodeChangeEvent(mMockContext);
+        verify(mMockLocationManager, never())
+                .getCurrentLocation(any(), any(), any(), any(), any());
+        assertEquals(firstMccChangedTime, mSatelliteAccessControllerUT
+                .mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
+
+        // Test the scenario when last know location is not fresh and
+        // current time is greater than the location query throttle interval
+        // verify mMockLocationManager.getCurrentLocation() is invoked
+        // verify time(mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos) is updated
+        logd("youngcha 1");
+        clearInvocations(mMockLocationManager);
+        mSatelliteAccessControllerUT.setLocationRequestCancellationSignalAsNull(true);
+        mSatelliteAccessControllerUT.elapsedRealtimeNanos =
+                (lastKnownLocationElapsedRealtime + TEST_LOCATION_FRESH_DURATION_NANOS + 1);
+        sendCommandValidateCountryCodeChangeEvent(mMockContext);
+        verify(mMockLocationManager, times(1))
+                .getCurrentLocation(any(), any(), any(), any(), any());
+        assertEquals(lastKnownLocationElapsedRealtime + TEST_LOCATION_FRESH_DURATION_NANOS + 1,
+                mSatelliteAccessControllerUT
+                        .mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos);
+    }
+
+
+    @Test
     public void testAllowLocationQueryForSatelliteAllowedCheck() {
         mSatelliteAccessControllerUT.mLatestSatelliteCommunicationAllowedSetTime = 1;
 
@@ -893,7 +983,7 @@
         assertNull(mCountryDetectorObjCaptor.getValue());
 
         // Normal case that invokes
-        // mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation
+        // mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation
         clearInvocations(mMockSatelliteOnDeviceAccessController);
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
@@ -901,14 +991,14 @@
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS;
         sendCommandValidateCountryCodeChangeEvent(mMockContext);
         verify(mMockSatelliteOnDeviceAccessController,
-                times(1)).isSatCommunicationAllowedAtLocation(
+                times(1)).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
 
         // Case that isCommunicationAllowedCacheValid is true
         clearInvocations(mMockSatelliteOnDeviceAccessController);
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         sendCommandValidateCountryCodeChangeEvent(mMockContext);
-        verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
+        verify(mMockSatelliteOnDeviceAccessController, never()).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
 
         // Case that mLatestCacheEnforcedValidateTimeNanos is over
@@ -925,11 +1015,11 @@
         when(mMockLocation0.getLongitude()).thenReturn(2.0);
         when(mMockLocation1.getLatitude()).thenReturn(3.0);
         when(mMockLocation1.getLongitude()).thenReturn(3.0);
-        when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
-                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(false);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(null);
         sendCommandValidateCountryCodeChangeEvent(mMockContext);
         verify(mMockSatelliteOnDeviceAccessController,
-                times(1)).isSatCommunicationAllowedAtLocation(
+                times(1)).getRegionalConfigIdForLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
     }
 
@@ -1049,8 +1139,9 @@
                 .thenReturn(TEST_SATELLITE_ALLOW);
         setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
         setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
-        when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
-                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(true);
+        when(mMockSatelliteOnDeviceAccessController.getRegionalConfigIdForLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class)))
+                .thenReturn(DEFAULT_REGIONAL_SATELLITE_CONFIG_ID);
         replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
                 mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
         doReturn(false).when(mMockCachedAccessRestrictionMap).containsKey(any());
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index b6b1a36..a3497b6 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -1440,7 +1440,7 @@
     @Test
     @SmallTest
     public void testCreateOutgoingEmergencyConnection_exitingSatellite_placeCall() {
-        when(mSatelliteController.isSatelliteEnabled()).thenReturn(true);
+        when(mSatelliteController.isSatelliteEnabledOrBeingEnabled()).thenReturn(true);
         doReturn(true).when(mMockResources).getBoolean(anyInt());
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
                 anyString());
@@ -1456,7 +1456,7 @@
         when(mSST.isRadioOn()).thenReturn(true);
         assertFalse(callback.getValue()
                 .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
-        when(mSatelliteController.isSatelliteEnabled()).thenReturn(false);
+        when(mSatelliteController.isSatelliteEnabledOrBeingEnabled()).thenReturn(false);
         assertTrue(callback.getValue()
                 .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
 
@@ -1481,7 +1481,7 @@
     public void testCreateOutgoingEmergencyConnection_exitingSatellite_EmergencySatellite()
             throws Exception {
         doReturn(true).when(mFeatureFlags).carrierRoamingNbIotNtn();
-        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+        doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled();
 
         // Set config_turn_off_oem_enabled_satellite_during_emergency_call as false
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(anyString());
@@ -1500,7 +1500,7 @@
     @SmallTest
     public void testCreateOutgoingEmergencyConnection_exitingSatellite_OEM() throws Exception {
         doReturn(true).when(mFeatureFlags).carrierRoamingNbIotNtn();
-        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+        doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled();
 
         // Set config_turn_off_oem_enabled_satellite_during_emergency_call as false
         doReturn(false).when(mMockResources).getBoolean(anyInt());
@@ -1539,7 +1539,7 @@
     @SmallTest
     public void testCreateOutgoingEmergencyConnection_exitingSatellite_Carrier() throws Exception {
         doReturn(true).when(mFeatureFlags).carrierRoamingNbIotNtn();
-        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+        doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled();
 
         // Set config_turn_off_oem_enabled_satellite_during_emergency_call as false
         doReturn(false).when(mMockResources).getBoolean(anyInt());
@@ -3753,7 +3753,7 @@
     @Test
     public void testNormalCallSatelliteEnabled() {
         setupForCallTest();
-        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+        doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled();
 
         mConnection = mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
                 createConnectionRequest(PHONE_ACCOUNT_HANDLE_1, "1234", TELECOM_CALL_ID1));
@@ -3766,7 +3766,7 @@
     @Test
     public void testEmergencyCallSatelliteEnabled_blockEmergencyCall() {
         setupForCallTest();
-        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
+        doReturn(true).when(mSatelliteController).isSatelliteEnabledOrBeingEnabled();
         doReturn(false).when(mMockResources).getBoolean(anyInt());
         doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
                 anyString());
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index 8a83ab0..51493d3 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -127,6 +127,7 @@
 import android.testing.TestableLooper;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.Display;
 
 import androidx.test.filters.SmallTest;
 
@@ -230,6 +231,11 @@
             public Resources getResources() {
                 return mResources;
             }
+
+            @Override
+            public int getDisplayId() {
+                return Display.DEFAULT_DISPLAY;
+            }
         };
 
         if (Looper.myLooper() == null) {
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
index 9aa56b2..2feccbf 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/PopulatedSuffixTableBlock.java
@@ -20,7 +20,6 @@
 import static com.android.storage.s2.S2Support.cellIdToString;
 import static com.android.storage.util.Conditions.checkStateInRange;
 
-import com.android.storage.s2.S2LevelRange;
 import com.android.storage.table.packed.read.IntValueTypedPackedTable;
 import com.android.storage.table.reader.IntValueTable;
 
@@ -141,7 +140,7 @@
 
         private final IntValueTable.TableEntry mSuffixTableEntry;
 
-        private S2LevelRange mSuffixTableRange;
+        private SuffixTableRange mSuffixTableRange;
 
         Entry(IntValueTable.TableEntry suffixTableEntry) {
             mSuffixTableEntry = Objects.requireNonNull(suffixTableEntry);
@@ -154,7 +153,7 @@
 
         /** Returns the data for this entry. */
         @Override
-        public S2LevelRange getSuffixTableRange() {
+        public SuffixTableRange getSuffixTableRange() {
             // Creating SuffixTableRange is relatively expensive so it is created lazily and
             // memoized.
             if (mSuffixTableRange == null) {
@@ -190,7 +189,7 @@
                     endCellIdSuffix = 0;
                 }
                 long endCellId = mFileFormat.createCellId(endCellPrefixValue, endCellIdSuffix);
-                mSuffixTableRange = new S2LevelRange(startCellId, endCellId);
+                mSuffixTableRange = new SuffixTableRange(startCellId, endCellId);
             }
             return mSuffixTableRange;
         }
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileReader.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileReader.java
index ecfa0a9..2c6c4af 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileReader.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SatS2RangeFileReader.java
@@ -19,7 +19,6 @@
 import com.android.storage.block.read.Block;
 import com.android.storage.block.read.BlockFileReader;
 import com.android.storage.block.read.BlockInfo;
-import com.android.storage.s2.S2LevelRange;
 import com.android.storage.s2.S2Support;
 import com.android.storage.util.Conditions;
 import com.android.storage.util.Visitor;
@@ -144,11 +143,11 @@
     }
 
     /**
-     * Finds an {@link S2LevelRange} associated with a range covering {@code cellId}.
+     * Finds an {@link SuffixTableRange} associated with a range covering {@code cellId}.
      * Returns {@code null} if no range exists. Throws {@link IllegalArgumentException} if
      * {@code cellId} is not the correct S2 level for the file. See {@link #getS2Level()}.
      */
-    public S2LevelRange findEntryByCellId(long cellId) throws IOException {
+    public SuffixTableRange findEntryByCellId(long cellId) throws IOException {
         checkNotClosed();
         int dataS2Level = mFileFormat.getS2Level();
         int searchS2Level = S2Support.getS2Level(cellId);
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableBlock.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableBlock.java
index 90ddd89..ffd28d5 100644
--- a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableBlock.java
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableBlock.java
@@ -20,7 +20,6 @@
 import static com.android.storage.s2.S2Support.getS2Level;
 
 import com.android.storage.block.read.BlockData;
-import com.android.storage.s2.S2LevelRange;
 import com.android.storage.table.packed.read.IntValueTypedPackedTable;
 import com.android.storage.util.BitwiseUtils;
 import com.android.storage.util.Visitor;
@@ -180,6 +179,6 @@
         public abstract int getIndex();
 
         /** Returns the data for this entry. */
-        public abstract S2LevelRange getSuffixTableRange();
+        public abstract SuffixTableRange getSuffixTableRange();
     }
 }
diff --git a/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
new file mode 100644
index 0000000..88f1b2e
--- /dev/null
+++ b/utils/satellite/s2storage/src/readonly/java/com/android/telephony/sats2range/read/SuffixTableRange.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephony.sats2range.read;
+
+import static com.android.storage.s2.S2Support.cellIdToString;
+
+import com.android.storage.s2.S2LevelRange;
+
+import java.util.Objects;
+
+public final class SuffixTableRange extends S2LevelRange {
+    private static final int DEAFAULT_ENTRY_VALUE = -1;
+    private final int mEntryValue;
+
+    // For backward compatibility
+    public SuffixTableRange(long startCellId, long endCellId) {
+        this(startCellId, endCellId, DEAFAULT_ENTRY_VALUE);
+    }
+
+    public SuffixTableRange(long startCellId, long endCellId, int entryValue) {
+        super(startCellId, endCellId);
+        mEntryValue = entryValue;
+    }
+
+    /** Returns the entry value associated with this range. */
+    public int getEntryValue() {
+        return mEntryValue;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        if (super.equals(o)) {
+            int entryValue = ((SuffixTableRange) o).mEntryValue;
+            return mEntryValue == entryValue;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStartCellId, mEndCellId, mEntryValue);
+    }
+
+    @Override
+    public String toString() {
+        return "SuffixTableRange{"
+                + "mS2Level=" + mS2Level
+                + ", mStartCellId=" + cellIdToString(mStartCellId)
+                + ", mEndCellId=" + cellIdToString(mEndCellId)
+                + ", mEntryValue=" + mEntryValue
+                + '}';
+    }
+}
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
index bbfaef7..2797b77 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SatS2RangeFileReaderTest.java
@@ -18,9 +18,9 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.storage.s2.S2LevelRange;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SatS2RangeFileReader;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.utils.TestUtils;
 import com.android.telephony.sats2range.write.SatS2RangeFileWriter;
 
@@ -38,24 +38,24 @@
 
         SatS2RangeFileFormat fileFormat;
         boolean isAllowedList = true;
-        S2LevelRange expectedRange1, expectedRange2, expectedRange3;
+        SuffixTableRange expectedRange1, expectedRange2, expectedRange3;
         try (SatS2RangeFileWriter satS2RangeFileWriter = SatS2RangeFileWriter.open(
                 file, TestUtils.createS2RangeFileFormat(isAllowedList))) {
             fileFormat = satS2RangeFileWriter.getFileFormat();
 
             // Two ranges that share a prefix.
-            expectedRange1 = new S2LevelRange(
+            expectedRange1 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1000, 1000),
                     TestUtils.createCellId(fileFormat, 1, 1000, 2000));
-            expectedRange2 = new S2LevelRange(
+            expectedRange2 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1000, 2000),
                     TestUtils.createCellId(fileFormat, 1, 1000, 3000));
             // This range has a different prefix, so will be in a different suffix table.
-            expectedRange3 = new S2LevelRange(
+            expectedRange3 = new SuffixTableRange(
                     TestUtils.createCellId(fileFormat, 1, 1001, 1000),
                     TestUtils.createCellId(fileFormat, 1, 1001, 2000));
 
-            List<S2LevelRange> ranges = new ArrayList<>();
+            List<SuffixTableRange> ranges = new ArrayList<>();
             ranges.add(expectedRange1);
             ranges.add(expectedRange2);
             ranges.add(expectedRange3);
@@ -65,15 +65,15 @@
         try (SatS2RangeFileReader satS2RangeFileReader = SatS2RangeFileReader.open(file)) {
             assertEquals(isAllowedList, satS2RangeFileReader.isAllowedList());
 
-            S2LevelRange range1 = satS2RangeFileReader.findEntryByCellId(
+            SuffixTableRange range1 = satS2RangeFileReader.findEntryByCellId(
                     TestUtils.createCellId(fileFormat, 1, 1000, 1500));
             assertEquals(expectedRange1, range1);
 
-            S2LevelRange range2 = satS2RangeFileReader.findEntryByCellId(
+            SuffixTableRange range2 = satS2RangeFileReader.findEntryByCellId(
                     TestUtils.createCellId(fileFormat, 1, 1000, 2500));
             assertEquals(expectedRange2, range2);
 
-            S2LevelRange range3 = satS2RangeFileReader.findEntryByCellId(
+            SuffixTableRange range3 = satS2RangeFileReader.findEntryByCellId(
                     TestUtils.createCellId(fileFormat, 1, 1001, 1500));
             assertEquals(expectedRange3, range3);
         }
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableBlockTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableBlockTest.java
index 04b915b..7b9ce4a 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableBlockTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableBlockTest.java
@@ -24,9 +24,9 @@
 import static org.mockito.ArgumentMatchers.argThat;
 
 import com.android.storage.block.write.BlockWriter;
-import com.android.storage.s2.S2LevelRange;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SuffixTableBlock;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.read.SuffixTableSharedData;
 import com.android.telephony.sats2range.utils.TestUtils;
 import com.android.telephony.sats2range.write.SuffixTableWriter;
@@ -78,12 +78,14 @@
         long invalidEndCellId = fileFormat.createCellId(tablePrefixValue + 1, maxSuffixValue);
         long validEndCellId = fileFormat.createCellId(tablePrefixValue, maxSuffixValue);
         {
-            S2LevelRange badStartCellId = new S2LevelRange(invalidStartCellId, validEndCellId);
+            SuffixTableRange badStartCellId = new SuffixTableRange(invalidStartCellId,
+                    validEndCellId);
             assertThrows(IllegalArgumentException.class,
                     () -> suffixTableWriter.addRange(badStartCellId));
         }
         {
-            S2LevelRange badEndCellId = new S2LevelRange(validStartCellId, invalidEndCellId);
+            SuffixTableRange badEndCellId = new SuffixTableRange(validStartCellId,
+                    invalidEndCellId);
             assertThrows(IllegalArgumentException.class,
                     () -> suffixTableWriter.addRange(badEndCellId));
         }
@@ -101,13 +103,13 @@
 
         SuffixTableWriter suffixTableWriter =
                 SuffixTableWriter.createPopulated(fileFormat, suffixTableSharedData);
-        S2LevelRange suffixTableRange1 = new S2LevelRange(
+        SuffixTableRange suffixTableRange1 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefixValue, 1000),
                 fileFormat.createCellId(tablePrefixValue, 1001));
         suffixTableWriter.addRange(suffixTableRange1);
 
         // It's fine to add a range that starts adjacent to the last one.
-        S2LevelRange suffixTableRange2 = new S2LevelRange(
+        SuffixTableRange suffixTableRange2 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefixValue, 1001),
                 fileFormat.createCellId(tablePrefixValue, 1002));
         suffixTableWriter.addRange(suffixTableRange2);
@@ -117,7 +119,7 @@
                 () -> suffixTableWriter.addRange(suffixTableRange2));
 
         // Try similar checks at the top end of the table.
-        S2LevelRange suffixTableRange3 = new S2LevelRange(
+        SuffixTableRange suffixTableRange3 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefixValue, maxSuffixValue - 1),
                 fileFormat.createCellId(tablePrefixValue, maxSuffixValue));
         suffixTableWriter.addRange(suffixTableRange3);
@@ -131,7 +133,7 @@
                 () -> suffixTableWriter.addRange(suffixTableRange3));
 
         // Now "complete" the table: there can be no entry after this one.
-        S2LevelRange suffixTableRange4 = new S2LevelRange(
+        SuffixTableRange suffixTableRange4 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefixValue, maxSuffixValue),
                 fileFormat.createCellId(tablePrefixValue + 1, 0));
         suffixTableWriter.addRange(suffixTableRange4);
@@ -180,23 +182,23 @@
 
         long entry1StartCellId = fileFormat.createCellId(tablePrefix, 1000);
         long entry1EndCellId = fileFormat.createCellId(tablePrefix, 2000);
-        S2LevelRange entry1 = new S2LevelRange(entry1StartCellId, entry1EndCellId);
+        SuffixTableRange entry1 = new SuffixTableRange(entry1StartCellId, entry1EndCellId);
         suffixTableWriter.addRange(entry1);
 
         long entry2StartCellId = fileFormat.createCellId(tablePrefix, 2000);
         long entry2EndCellId = fileFormat.createCellId(tablePrefix, 3000);
-        S2LevelRange entry2 = new S2LevelRange(entry2StartCellId, entry2EndCellId);
+        SuffixTableRange entry2 = new SuffixTableRange(entry2StartCellId, entry2EndCellId);
         suffixTableWriter.addRange(entry2);
 
         // There is a deliberate gap here between entry2 and entry3.
         long entry3StartCellId = fileFormat.createCellId(tablePrefix, 4000);
         long entry3EndCellId = fileFormat.createCellId(tablePrefix, 5000);
-        S2LevelRange entry3 = new S2LevelRange(entry3StartCellId, entry3EndCellId);
+        SuffixTableRange entry3 = new SuffixTableRange(entry3StartCellId, entry3EndCellId);
         suffixTableWriter.addRange(entry3);
 
         long entry4StartCellId = fileFormat.createCellId(tablePrefix, maxSuffix - 999);
         long entry4EndCellId = fileFormat.createCellId(tablePrefix + 1, 0);
-        S2LevelRange entry4 = new S2LevelRange(entry4StartCellId, entry4EndCellId);
+        SuffixTableRange entry4 = new SuffixTableRange(entry4StartCellId, entry4EndCellId);
         suffixTableWriter.addRange(entry4);
 
         BlockWriter.ReadBack blockReadback = suffixTableWriter.close();
@@ -251,7 +253,7 @@
                 SuffixTableWriter.createPopulated(fileFormat, suffixTableSharedData);
         long entry1StartCellId = fileFormat.createCellId(tablePrefix, 1000);
         long entry1EndCellId = fileFormat.createCellId(tablePrefix, 2000);
-        S2LevelRange entry1 = new S2LevelRange(entry1StartCellId, entry1EndCellId);
+        SuffixTableRange entry1 = new SuffixTableRange(entry1StartCellId, entry1EndCellId);
         suffixTableWriter.addRange(entry1);
         BlockWriter.ReadBack blockReadback = suffixTableWriter.close();
 
@@ -276,12 +278,12 @@
         SuffixTableWriter suffixTableWriter =
                 SuffixTableWriter.createPopulated(fileFormat, sharedData);
 
-        S2LevelRange entry1 = new S2LevelRange(
+        SuffixTableRange entry1 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefix, 1001),
                 fileFormat.createCellId(tablePrefix, 1101));
         suffixTableWriter.addRange(entry1);
 
-        S2LevelRange entry2 = new S2LevelRange(
+        SuffixTableRange entry2 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefix, 2001),
                 fileFormat.createCellId(tablePrefix, 2101));
         suffixTableWriter.addRange(entry2);
@@ -302,7 +304,7 @@
         inOrder.verify(mockVisitor).end();
     }
 
-    private S2LevelRange findEntryByCellId(SatS2RangeFileFormat fileFormat,
+    private SuffixTableRange findEntryByCellId(SatS2RangeFileFormat fileFormat,
             SuffixTableBlock suffixTableBlock, int prefix, int suffix) {
         long cellId = fileFormat.createCellId(prefix, suffix);
         SuffixTableBlock.Entry entry = suffixTableBlock.findEntryByCellId(cellId);
diff --git a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableExtraInfoTest.java b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableExtraInfoTest.java
index f992ae7..f978bd5 100644
--- a/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableExtraInfoTest.java
+++ b/utils/satellite/s2storage/src/test/java/com/android/telephony/sats2range/SuffixTableExtraInfoTest.java
@@ -20,9 +20,9 @@
 
 import com.android.storage.block.read.BlockInfo;
 import com.android.storage.block.write.BlockWriter;
-import com.android.storage.s2.S2LevelRange;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SuffixTableExtraInfo;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.read.SuffixTableSharedData;
 import com.android.telephony.sats2range.utils.TestUtils;
 import com.android.telephony.sats2range.write.SuffixTableWriter;
@@ -54,13 +54,13 @@
                 SuffixTableWriter.createPopulated(fileFormat, suffixTableSharedData);
 
         int tablePrefix = suffixTableSharedData.getTablePrefix();
-        S2LevelRange range1 = new S2LevelRange(
+        SuffixTableRange range1 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefix, 1000),
                 fileFormat.createCellId(tablePrefix, 1001));
-        S2LevelRange range2 = new S2LevelRange(
+        SuffixTableRange range2 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefix, 1002),
                 fileFormat.createCellId(tablePrefix, 1003));
-        S2LevelRange range3 = new S2LevelRange(
+        SuffixTableRange range3 = new SuffixTableRange(
                 fileFormat.createCellId(tablePrefix, 1004),
                 fileFormat.createCellId(tablePrefix, 1005));
 
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
index 9b3c20e..3018aec 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SatS2RangeFileWriter.java
@@ -19,9 +19,9 @@
 import com.android.storage.block.write.BlockFileWriter;
 import com.android.storage.block.write.BlockWriter;
 import com.android.storage.block.write.EmptyBlockWriter;
-import com.android.storage.s2.S2LevelRange;
 import com.android.storage.s2.S2Support;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.read.SuffixTableSharedData;
 
 import java.io.File;
@@ -64,8 +64,8 @@
      * needed to fit them into suffix blocks. The ranges must be of the expected S2 level
      * and ordered by cell ID.
      */
-    public void createSortedSuffixBlocks(Iterator<S2LevelRange> ranges) throws IOException {
-        PushBackIterator<S2LevelRange> pushBackIterator = new PushBackIterator<>(ranges);
+    public void createSortedSuffixBlocks(Iterator<SuffixTableRange> ranges) throws IOException {
+        PushBackIterator<SuffixTableRange> pushBackIterator = new PushBackIterator<>(ranges);
 
         // For each prefix value, collect all the ranges that match.
         for (int currentPrefix = 0;
@@ -74,7 +74,7 @@
 
             // Step 1:
             // populate samePrefixRanges, which holds ranges that have a prefix of currentPrefix.
-            List<S2LevelRange> samePrefixRanges =
+            List<SuffixTableRange> samePrefixRanges =
                     collectSamePrefixRanges(pushBackIterator, currentPrefix);
 
             // Step 2: Write samePrefixRanges to a suffix table.
@@ -88,11 +88,11 @@
         }
     }
 
-    private List<S2LevelRange> collectSamePrefixRanges(
-            PushBackIterator<S2LevelRange> pushBackIterator, int currentPrefix) {
-        List<S2LevelRange> samePrefixRanges = new ArrayList<>();
+    private List<SuffixTableRange> collectSamePrefixRanges(
+            PushBackIterator<SuffixTableRange> pushBackIterator, int currentPrefix) {
+        List<SuffixTableRange> samePrefixRanges = new ArrayList<>();
         while (pushBackIterator.hasNext()) {
-            S2LevelRange currentRange = pushBackIterator.next();
+            SuffixTableRange currentRange = pushBackIterator.next();
 
             long startCellId = currentRange.getStartCellId();
             if (mFileFormat.getS2Level() != S2Support.getS2Level(startCellId)) {
@@ -123,17 +123,18 @@
                 // Create a range for the current prefix.
                 {
                     long newEndCellId = mFileFormat.createCellId(startCellPrefix + 1, 0);
-                    S2LevelRange satS2Range = new S2LevelRange(startCellId, newEndCellId);
+                    SuffixTableRange satS2Range = new SuffixTableRange(startCellId, newEndCellId);
                     samePrefixRanges.add(satS2Range);
                 }
 
-                Deque<S2LevelRange> otherRanges = new ArrayDeque<>();
+                Deque<SuffixTableRange> otherRanges = new ArrayDeque<>();
                 // Intermediate prefixes.
                 startCellPrefix = startCellPrefix + 1;
                 while (startCellPrefix != endCellPrefixValue) {
                     long newStartCellId = mFileFormat.createCellId(startCellPrefix, 0);
                     long newEndCellId = mFileFormat.createCellId(startCellPrefix + 1, 0);
-                    S2LevelRange satS2Range = new S2LevelRange(newStartCellId, newEndCellId);
+                    SuffixTableRange satS2Range = new SuffixTableRange(newStartCellId,
+                            newEndCellId);
                     otherRanges.add(satS2Range);
                     startCellPrefix++;
                 }
@@ -142,7 +143,8 @@
                 {
                     long newStartCellId = mFileFormat.createCellId(endCellPrefixValue, 0);
                     if (newStartCellId != endCellId) {
-                        S2LevelRange satS2Range = new S2LevelRange(newStartCellId, endCellId);
+                        SuffixTableRange satS2Range = new SuffixTableRange(newStartCellId,
+                                endCellId);
                         otherRanges.add(satS2Range);
                     }
                 }
@@ -160,7 +162,7 @@
     }
 
     private BlockWriter writeSamePrefixRanges(
-            int currentPrefix, List<S2LevelRange> samePrefixRanges) throws IOException {
+            int currentPrefix, List<SuffixTableRange> samePrefixRanges) throws IOException {
         BlockWriter blockWriter;
         if (samePrefixRanges.size() == 0) {
             // Add an empty block.
@@ -170,8 +172,8 @@
             SuffixTableSharedData sharedData = new SuffixTableSharedData(currentPrefix);
             SuffixTableWriter suffixTableWriter =
                     SuffixTableWriter.createPopulated(mFileFormat, sharedData);
-            S2LevelRange lastRange = null;
-            for (S2LevelRange currentRange : samePrefixRanges) {
+            SuffixTableRange lastRange = null;
+            for (SuffixTableRange currentRange : samePrefixRanges) {
                 // Validate ranges don't overlap.
                 if (lastRange != null) {
                     if (lastRange.overlaps(currentRange)) {
@@ -188,12 +190,13 @@
                 int rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
                 while (rangeLength > maxRangeLength) {
                     long newEndCellId = S2Support.offsetCellId(startCellId, maxRangeLength);
-                    S2LevelRange suffixTableRange = new S2LevelRange(startCellId, newEndCellId);
+                    SuffixTableRange suffixTableRange = new SuffixTableRange(startCellId,
+                            newEndCellId);
                     suffixTableWriter.addRange(suffixTableRange);
                     startCellId = newEndCellId;
                     rangeLength = mFileFormat.calculateRangeLength(startCellId, endCellId);
                 }
-                S2LevelRange suffixTableRange = new S2LevelRange(startCellId, endCellId);
+                SuffixTableRange suffixTableRange = new SuffixTableRange(startCellId, endCellId);
                 suffixTableWriter.addRange(suffixTableRange);
             }
             blockWriter = suffixTableWriter;
diff --git a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableWriter.java b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableWriter.java
index dc265d5..31b35eb 100644
--- a/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableWriter.java
+++ b/utils/satellite/s2storage/src/write/java/com/android/telephony/sats2range/write/SuffixTableWriter.java
@@ -22,11 +22,11 @@
 import com.android.storage.block.write.BlockWriter;
 import com.android.storage.block.write.EmptyBlockWriter;
 import com.android.storage.io.write.TypedOutputStream;
-import com.android.storage.s2.S2LevelRange;
 import com.android.storage.s2.S2Support;
 import com.android.storage.table.packed.write.PackedTableWriter;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SuffixTableExtraInfo;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.read.SuffixTableSharedData;
 
 import java.io.ByteArrayOutputStream;
@@ -42,7 +42,7 @@
  * To write empty tables use {@link #createEmptyBlockWriter()}.
  * To write populated tables use {@link
  * #createPopulated(SatS2RangeFileFormat, SuffixTableSharedData)} and add entries with
- * {@link #addRange(S2LevelRange)}
+ * {@link #addRange(SuffixTableRange)}
  */
 public final class SuffixTableWriter implements BlockWriter {
 
@@ -54,7 +54,7 @@
 
     private final File mFile;
 
-    private S2LevelRange mLastRangeAdded;
+    private SuffixTableRange mLastRangeAdded;
 
     private SuffixTableWriter(SatS2RangeFileFormat fileFormat, SuffixTableSharedData sharedData)
             throws IOException {
@@ -90,7 +90,7 @@
      * called at least once. See {@link SuffixTableWriter#createEmptyBlockWriter()} for empty
      * tables.
      */
-    public void addRange(S2LevelRange suffixTableRange) throws IOException {
+    public void addRange(SuffixTableRange suffixTableRange) throws IOException {
         checkIsOpen();
 
         long rangeStartCellId = suffixTableRange.getStartCellId();
diff --git a/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/CreateTestSatS2File.java b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/CreateTestSatS2File.java
index f9a9347..41ce416 100644
--- a/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/CreateTestSatS2File.java
+++ b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/CreateTestSatS2File.java
@@ -16,8 +16,8 @@
 
 package com.android.telephony.tools.sats2;
 
-import com.android.storage.s2.S2LevelRange;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.write.SatS2RangeFileWriter;
 
 import java.io.File;
@@ -42,18 +42,18 @@
         try (SatS2RangeFileWriter satS2RangeFileWriter =
                      SatS2RangeFileWriter.open(file, fileFormat)) {
             // Two ranges that share a prefix.
-            S2LevelRange range1 = new S2LevelRange(
+            SuffixTableRange range1 = new SuffixTableRange(
                     fileFormat.createCellId(0b100_11111111, 1000),
                     fileFormat.createCellId(0b100_11111111, 2000));
-            S2LevelRange range2 = new S2LevelRange(
+            SuffixTableRange range2 = new SuffixTableRange(
                     fileFormat.createCellId(0b100_11111111, 2000),
                     fileFormat.createCellId(0b100_11111111, 3000));
             // This range has a different face, so a different prefix, and will be in a different
             // suffix table.
-            S2LevelRange range3 = new S2LevelRange(
+            SuffixTableRange range3 = new SuffixTableRange(
                     fileFormat.createCellId(0b101_11111111, 1000),
                     fileFormat.createCellId(0b101_11111111, 2000));
-            List<S2LevelRange> allRanges = listOf(range1, range2, range3);
+            List<SuffixTableRange> allRanges = listOf(range1, range2, range3);
             satS2RangeFileWriter.createSortedSuffixBlocks(allRanges.iterator());
         }
     }
diff --git a/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2FileCreator.java b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2FileCreator.java
index dd7d8c0..1ed9680 100644
--- a/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2FileCreator.java
+++ b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2FileCreator.java
@@ -16,9 +16,9 @@
 
 package com.android.telephony.tools.sats2;
 
-import com.android.storage.s2.S2LevelRange;
 import com.android.telephony.sats2range.read.SatS2RangeFileFormat;
 import com.android.telephony.sats2range.read.SatS2RangeFileReader;
+import com.android.telephony.sats2range.read.SuffixTableRange;
 import com.android.telephony.sats2range.write.SatS2RangeFileWriter;
 
 import com.google.common.base.Stopwatch;
@@ -73,15 +73,15 @@
                 FileFormats.getFileFormatForLevel(s2Level, isAllowedList);
         try (SatS2RangeFileWriter satS2RangeFileWriter =
                      SatS2RangeFileWriter.open(new File(outputFile), fileFormat)) {
-            Iterator<S2LevelRange> s2LevelRangeIterator = satS2Ranges
+            Iterator<SuffixTableRange> suffixTableRangeIterator = satS2Ranges
                     .stream()
-                    .map(x -> new S2LevelRange(x.rangeStart.id(), x.rangeEnd.id()))
+                    .map(x -> new SuffixTableRange(x.rangeStart.id(), x.rangeEnd.id()))
                     .iterator();
             /*
              * Group the sorted ranges into contiguous suffix blocks. Big ranges might get split as
              * needed to fit them into suffix blocks.
              */
-            satS2RangeFileWriter.createSortedSuffixBlocks(s2LevelRangeIterator);
+            satS2RangeFileWriter.createSortedSuffixBlocks(suffixTableRangeIterator);
         }
 
         // Validate the output block file