Merge "Import translations. DO NOT MERGE ANYWHERE" into 24D1-dev
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 8489015..8353861 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -21,10 +21,13 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
+import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_SHARED_PREF;
+
 import android.annotation.ArrayRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.location.Location;
 import android.location.LocationManager;
@@ -56,9 +59,11 @@
 import com.android.internal.telephony.flags.FeatureFlags;
 import com.android.internal.telephony.satellite.SatelliteConfig;
 import com.android.internal.telephony.satellite.SatelliteController;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.phone.PhoneGlobals;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
@@ -115,56 +120,82 @@
     private static SatelliteAccessController sInstance;
 
     /** Feature flags to control behavior and errors. */
-    @NonNull private final FeatureFlags mFeatureFlags;
+    @NonNull
+    private final FeatureFlags mFeatureFlags;
     @GuardedBy("mLock")
-    @Nullable protected SatelliteOnDeviceAccessController mSatelliteOnDeviceAccessController;
-    @NonNull private final LocationManager mLocationManager;
-    @NonNull private final TelecomManager mTelecomManager;
-    @NonNull private final TelephonyCountryDetector mCountryDetector;
-    @NonNull private final SatelliteController mSatelliteController;
-    @NonNull private final ResultReceiver mInternalSatelliteSupportedResultReceiver;
-    @NonNull protected final Object mLock = new Object();
+    @Nullable
+    protected SatelliteOnDeviceAccessController mSatelliteOnDeviceAccessController;
+    @NonNull
+    private final LocationManager mLocationManager;
+    @NonNull
+    private final TelecomManager mTelecomManager;
+    @NonNull
+    private final TelephonyCountryDetector mCountryDetector;
+    @NonNull
+    private final SatelliteController mSatelliteController;
+    @NonNull
+    private final ResultReceiver mInternalSatelliteSupportedResultReceiver;
+    @NonNull
+    protected final Object mLock = new Object();
     @GuardedBy("mLock")
     @NonNull
     private final Set<ResultReceiver> mSatelliteAllowResultReceivers = new HashSet<>();
-    @NonNull private List<String> mSatelliteCountryCodes;
+    @NonNull
+    private List<String> mSatelliteCountryCodes;
     private boolean mIsSatelliteAllowAccessControl;
-    @Nullable private File mSatelliteS2CellFile;
+    @Nullable
+    private File mSatelliteS2CellFile;
     private long mLocationFreshDurationNanos;
     @GuardedBy("mLock")
     private boolean mIsOverlayConfigOverridden = false;
-    @NonNull private List<String> mOverriddenSatelliteCountryCodes;
+    @NonNull
+    private List<String> mOverriddenSatelliteCountryCodes;
     private boolean mOverriddenIsSatelliteAllowAccessControl;
-    @Nullable private File mOverriddenSatelliteS2CellFile;
+    @Nullable
+    private File mOverriddenSatelliteS2CellFile;
     private long mOverriddenLocationFreshDurationNanos;
     @GuardedBy("mLock")
     @NonNull
     private final Map<SatelliteOnDeviceAccessController.LocationToken, Boolean>
             mCachedAccessRestrictionMap = new LinkedHashMap<>() {
-                @Override
-                protected boolean removeEldestEntry(
-                        Entry<SatelliteOnDeviceAccessController.LocationToken, Boolean> eldest) {
-                    return size() > MAX_CACHE_SIZE;
-                }
-            };
+               @Override
+               protected boolean removeEldestEntry(
+                       Entry<SatelliteOnDeviceAccessController.LocationToken, Boolean> eldest) {
+                   return size() > MAX_CACHE_SIZE;
+               }
+           };
     @GuardedBy("mLock")
     @Nullable
     CancellationSignal mLocationRequestCancellationSignal = null;
     private int mS2Level = DEFAULT_S2_LEVEL;
     @GuardedBy("mLock")
-    @Nullable private Location mFreshLastKnownLocation = null;
+    @Nullable
+    private Location mFreshLastKnownLocation = null;
 
     /** These are used for CTS test */
     private Path mCtsSatS2FilePath = null;
-    private static final String GOOGLE_US_SAN_SAT_S2_FILE_NAME = "google_us_san_sat_s2.dat";
+    protected static final String GOOGLE_US_SAN_SAT_S2_FILE_NAME = "google_us_san_sat_s2.dat";
+
+    /** These are for config updater config data */
+    private static final String SATELLITE_ACCESS_CONTROL_DATA_DIR = "satellite_access_control";
+    private static final String CONFIG_UPDATER_S2_CELL_FILE_NAME = "config_updater_sat_s2.dat";
+    private static final int MIN_S2_LEVEL = 0;
+    private static final int MAX_S2_LEVEL = 30;
+    private static final String CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY =
+            "config_updater_satellite_country_codes";
+    private static final String CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY =
+            "config_updater_satellite_is_allow_access_control";
+    private SharedPreferences mSharedPreferences;
 
     /**
      * Create a SatelliteAccessController instance.
      *
-     * @param context The context associated with the {@link SatelliteAccessController} instance.
-     * @param featureFlags The FeatureFlags that are supported.
-     * @param locationManager The LocationManager for querying current location of the device.
-     * @param looper The Looper to run the SatelliteAccessController on.
+     * @param context                           The context associated with the
+     *                                          {@link SatelliteAccessController} instance.
+     * @param featureFlags                      The FeatureFlags that are supported.
+     * @param locationManager                   The LocationManager for querying current location of
+     *                                          the device.
+     * @param looper                            The Looper to run the SatelliteAccessController on.
      * @param satelliteOnDeviceAccessController The on-device satellite access controller instance.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -180,7 +211,11 @@
         mSatelliteOnDeviceAccessController = satelliteOnDeviceAccessController;
         mCountryDetector = TelephonyCountryDetector.getInstance(context);
         mSatelliteController = SatelliteController.getInstance();
+        initSharedPreferences(context);
         loadOverlayConfigs(context);
+        // loadConfigUpdaterConfigs has to be called after loadOverlayConfigs
+        // since config updater config has higher priority and thus can override overlay config
+        loadConfigUpdaterConfigs();
         mSatelliteController.registerForConfigUpdateChanged(this, EVENT_CONFIG_DATA_UPDATED,
                 context);
         if (s2CellFile != null) {
@@ -235,8 +270,8 @@
     /**
      * Request to get whether satellite communication is allowed for the current location.
      *
-     * @param subId The subId of the subscription to check whether satellite communication is
-     *              allowed for the current location for.
+     * @param subId  The subId of the subscription to check whether satellite communication is
+     *               allowed for the current location for.
      * @param result The result receiver that returns whether satellite communication is allowed
      *               for the current location if the request is successful or an error code
      *               if the request failed.
@@ -298,7 +333,7 @@
         return true;
     }
 
-    private File getTestSatelliteS2File(String fileName) {
+    protected File getTestSatelliteS2File(String fileName) {
         logd("getTestSatelliteS2File: fileName=" + fileName);
         if (TextUtils.equals(fileName, GOOGLE_US_SAN_SAT_S2_FILE_NAME)) {
             mCtsSatS2FilePath = copyTestSatS2FileToPhoneDirectory(GOOGLE_US_SAN_SAT_S2_FILE_NAME);
@@ -311,7 +346,8 @@
         return new File(fileName);
     }
 
-    @Nullable private static Path copyTestSatS2FileToPhoneDirectory(String sourceFileName) {
+    @Nullable
+    private static Path copyTestSatS2FileToPhoneDirectory(String sourceFileName) {
         PhoneGlobals phoneGlobals = PhoneGlobals.getInstance();
         File ctsFile = phoneGlobals.getDir("cts", Context.MODE_PRIVATE);
         if (!ctsFile.exists()) {
@@ -334,6 +370,66 @@
         return targetSatS2FilePath;
     }
 
+    @Nullable
+    private static File copySatS2FileToLocalDirectory(@NonNull File sourceFile) {
+        PhoneGlobals phoneGlobals = PhoneGlobals.getInstance();
+        File satelliteAccessControlFile = phoneGlobals.getDir(
+                SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE);
+        if (!satelliteAccessControlFile.exists()) {
+            satelliteAccessControlFile.mkdirs();
+        }
+
+        Path targetDir = satelliteAccessControlFile.toPath();
+        Path targetSatS2FilePath = targetDir.resolve(CONFIG_UPDATER_S2_CELL_FILE_NAME);
+        try {
+            InputStream inputStream = new FileInputStream(sourceFile);
+            if (inputStream == null) {
+                loge("copySatS2FileToPhoneDirectory: Resource=" + sourceFile.getAbsolutePath()
+                        + " not found");
+                return null;
+            } else {
+                Files.copy(inputStream, targetSatS2FilePath, StandardCopyOption.REPLACE_EXISTING);
+            }
+        } catch (IOException ex) {
+            loge("copySatS2FileToPhoneDirectory: ex=" + ex);
+            return null;
+        }
+        return targetSatS2FilePath.toFile();
+    }
+
+    @Nullable
+    private File getConfigUpdaterSatS2CellFileFromLocalDirectory() {
+        PhoneGlobals phoneGlobals = PhoneGlobals.getInstance();
+        File satelliteAccessControlFile = phoneGlobals.getDir(
+                SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE);
+        if (!satelliteAccessControlFile.exists()) {
+            return null;
+        }
+
+        Path satelliteAccessControlFileDir = satelliteAccessControlFile.toPath();
+        Path configUpdaterSatS2FilePath = satelliteAccessControlFileDir.resolve(
+                CONFIG_UPDATER_S2_CELL_FILE_NAME);
+        return configUpdaterSatS2FilePath.toFile();
+    }
+
+    private boolean isS2CellFileValid(@NonNull File s2CellFile) {
+        try {
+            SatelliteOnDeviceAccessController satelliteOnDeviceAccessController =
+                    SatelliteOnDeviceAccessController.create(s2CellFile);
+            int s2Level = satelliteOnDeviceAccessController.getS2Level();
+            if (s2Level < MIN_S2_LEVEL || s2Level > MAX_S2_LEVEL) {
+                loge("isS2CellFileValid: invalid s2 level = " + s2Level);
+                satelliteOnDeviceAccessController.close();
+                return false;
+            }
+            satelliteOnDeviceAccessController.close();
+        } catch (Exception ex) {
+            loge("isS2CellFileValid: Got exception in reading the file, ex=" + ex);
+            return false;
+        }
+        return true;
+    }
+
     private void cleanUpCtsResources() {
         if (mCtsSatS2FilePath != null) {
             try {
@@ -350,61 +446,126 @@
     }
 
     /**
-     * Update country codes, S2CellFile and satellite region allowed by ConfigUpdater
-     * or CarrierConfig
+     * @param countryCodes list of country code (two letters based on the ISO 3166-1).
+     * @return {@code true} if the countryCode is valid {@code false} otherwise.
+     */
+    private boolean isValidCountryCodes(@Nullable List<String> countryCodes) {
+        if (countryCodes == null || countryCodes.isEmpty()) {
+            return false;
+        }
+        for (String countryCode : countryCodes) {
+            if (!TelephonyUtils.isValidCountryCode(countryCode)) {
+                loge("invalid country code : " + countryCode);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean updateSharedPreferencesCountryCodes(
+            @NonNull Context context, @NonNull List<String> value) {
+        if (mSharedPreferences == null) {
+            logd("updateSharedPreferencesCountryCodes: mSharedPreferences is null");
+            initSharedPreferences(context);
+        }
+        if (mSharedPreferences == null) {
+            loge("updateSharedPreferencesCountryCodes: mSharedPreferences is null");
+            return false;
+        }
+        try {
+            mSharedPreferences.edit().putStringSet(
+                    CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, new HashSet<>(value)).apply();
+            return true;
+        } catch (Exception ex) {
+            loge("updateSharedPreferencesCountryCodes error : " + ex);
+            return false;
+        }
+    }
+
+    private boolean updateSharedPreferencesIsAllowAccessControl(
+            @NonNull Context context, boolean value) {
+        if (mSharedPreferences == null) {
+            logd("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null");
+            initSharedPreferences(context);
+        }
+        if (mSharedPreferences == null) {
+            loge("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null");
+            return false;
+        }
+        try {
+            mSharedPreferences.edit().putBoolean(
+                    CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY,
+                    value).apply();
+            return true;
+        } catch (Exception ex) {
+            loge("updateSharedPreferencesAllowRegion : " + ex);
+            return false;
+        }
+    }
+
+    /**
+     * Update country codes and S2CellFile with the new data from ConfigUpdater
      */
     private void updateSatelliteConfigData(Context context) {
         logd("updateSatelliteConfigData");
 
         SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig();
-        if (satelliteConfig != null  && satelliteConfig.getSatelliteS2CellFile(context) != null) {
-            logd("Check mSatelliteS2CellFile from ConfigUpdater");
-            Path pathSatelliteS2CellFile = satelliteConfig.getSatelliteS2CellFile(context);
-            mSatelliteS2CellFile = pathSatelliteS2CellFile.toFile();
-            if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
-                loge("The satellite S2 cell file " + mSatelliteS2CellFile.getAbsolutePath()
-                        + " does not exist");
-                mSatelliteS2CellFile = null;
-            } else {
-                logd("S2 cell file from ConfigUpdater:" + mSatelliteS2CellFile.getAbsolutePath());
-            }
-        }
-
-        if (mSatelliteS2CellFile == null) {
-            logd("Check mSatelliteS2CellFile from device overlay config");
-            String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context);
-            mSatelliteS2CellFile = TextUtils.isEmpty(satelliteS2CellFileName)
-                    ? null : new File(satelliteS2CellFileName);
-            if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
-                loge("The satellite S2 cell file " + mSatelliteS2CellFile.getAbsolutePath()
-                        + " does not exist");
-                mSatelliteS2CellFile = null;
-            }
-        }
-
-        if (mSatelliteS2CellFile == null) {
-            logd("Since mSatelliteS2CellFile is null, don't need to refer other configurations");
+        if (satelliteConfig == null) {
+            loge("satelliteConfig is null");
             return;
         }
 
-        if (satelliteConfig != null
-                && !satelliteConfig.getDeviceSatelliteCountryCodes().isEmpty()) {
-            mSatelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes();
-            logd("update mSatelliteCountryCodes by ConfigUpdater: "
-                    + String.join(",", mSatelliteCountryCodes));
-        } else {
-            mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
+        List<String> satelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes();
+        if (!isValidCountryCodes(satelliteCountryCodes)) {
+            logd("country codes is invalid");
+            return;
         }
 
-        if (satelliteConfig != null && satelliteConfig.isSatelliteDataForAllowedRegion() != null) {
-            mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion();
-            logd("update mIsSatelliteAllowAccessControl by ConfigUpdater: "
-                    + mIsSatelliteAllowAccessControl);
-        } else {
-            mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
+        Boolean isSatelliteDataForAllowedRegion = satelliteConfig.isSatelliteDataForAllowedRegion();
+        if (isSatelliteDataForAllowedRegion == null) {
+            loge("Satellite allowed is not configured with country codes");
+            return;
         }
 
-        // Clean up resources so that the new config data will be used when receiving new requests
+        File configUpdaterS2CellFile = satelliteConfig.getSatelliteS2CellFile(context);
+        if (configUpdaterS2CellFile == null || !configUpdaterS2CellFile.exists()) {
+            logd("No S2 cell file configured or the file does not exist");
+            return;
+        }
+
+        if (!isS2CellFileValid(configUpdaterS2CellFile)) {
+            loge("The configured S2 cell file is not valid");
+            return;
+        }
+
+        File localS2CellFile = copySatS2FileToLocalDirectory(configUpdaterS2CellFile);
+        if (localS2CellFile == null || !localS2CellFile.exists()) {
+            loge("Fail to copy S2 cell file to local directory");
+            return;
+        }
+
+        if (!updateSharedPreferencesCountryCodes(context, satelliteCountryCodes)) {
+            loge("Fail to copy country coeds into shared preferences");
+            localS2CellFile.delete();
+            return;
+        }
+
+        if (!updateSharedPreferencesIsAllowAccessControl(
+                context, isSatelliteDataForAllowedRegion.booleanValue())) {
+            loge("Fail to copy allow access control into shared preferences");
+            localS2CellFile.delete();
+            return;
+        }
+
+        mSatelliteS2CellFile = localS2CellFile;
+        mSatelliteCountryCodes = satelliteCountryCodes;
+        mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion();
+        logd("Use s2 cell file=" + mSatelliteS2CellFile.getAbsolutePath() + ", country codes="
+                + String.join(",", mSatelliteCountryCodes)
+                + ", mIsSatelliteAllowAccessControl=" + mIsSatelliteAllowAccessControl
+                + " from ConfigUpdater");
+
+        // Clean up resources so that the new config data will be used when serving new requests
         cleanupOnDeviceAccessControllerResources();
     }
 
@@ -421,6 +582,36 @@
         mLocationFreshDurationNanos = getSatelliteLocationFreshDurationFromOverlayConfig(context);
     }
 
+    private void loadConfigUpdaterConfigs() {
+        if (mSharedPreferences == null) {
+            loge("loadConfigUpdaterConfigs : mSharedPreferences is null");
+            return;
+        }
+
+        Set<String> countryCodes =
+                mSharedPreferences.getStringSet(CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, null);
+
+        if (countryCodes == null || countryCodes.isEmpty()) {
+            loge("config updater country codes are either null or empty");
+            return;
+        }
+
+        boolean isSatelliteAllowAccessControl =
+                mSharedPreferences.getBoolean(
+                        CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, true);
+
+        File s2CellFile = getConfigUpdaterSatS2CellFileFromLocalDirectory();
+        if (s2CellFile == null) {
+            loge("s2CellFile is null");
+            return;
+        }
+
+        logd("use config updater config data");
+        mSatelliteS2CellFile = s2CellFile;
+        mSatelliteCountryCodes = countryCodes.stream().collect(Collectors.toList());
+        mIsSatelliteAllowAccessControl = isSatelliteAllowAccessControl;
+    }
+
     private long getLocationFreshDurationNanos() {
         synchronized (mLock) {
             if (mIsOverlayConfigOverridden) {
@@ -430,7 +621,8 @@
         }
     }
 
-    @NonNull private List<String> getSatelliteCountryCodes() {
+    @NonNull
+    private List<String> getSatelliteCountryCodes() {
         synchronized (mLock) {
             if (mIsOverlayConfigOverridden) {
                 return mOverriddenSatelliteCountryCodes;
@@ -439,7 +631,8 @@
         }
     }
 
-    @Nullable private File getSatelliteS2CellFile() {
+    @Nullable
+    private File getSatelliteS2CellFile() {
         synchronized (mLock) {
             if (mIsOverlayConfigOverridden) {
                 return mOverriddenSatelliteS2CellFile;
@@ -660,8 +853,8 @@
         }
     }
 
-    private void updateCachedAccessRestrictionMap(@NonNull
-            SatelliteOnDeviceAccessController.LocationToken locationToken,
+    private void updateCachedAccessRestrictionMap(
+            @NonNull SatelliteOnDeviceAccessController.LocationToken locationToken,
             boolean satelliteAllowed) {
         synchronized (mLock) {
             mCachedAccessRestrictionMap.put(locationToken, satelliteAllowed);
@@ -732,7 +925,8 @@
         return false;
     }
 
-    @Nullable private Location getFreshLastKnownLocation() {
+    @Nullable
+    private Location getFreshLastKnownLocation() {
         Location lastKnownLocation = getLastKnownLocation();
         if (lastKnownLocation != null) {
             long lastKnownLocationAge =
@@ -771,11 +965,21 @@
         return result;
     }
 
+    private void initSharedPreferences(@NonNull Context context) {
+        try {
+            mSharedPreferences =
+                    context.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE);
+        } catch (Exception e) {
+            loge("Cannot get default shared preferences: " + e);
+        }
+    }
+
     /**
      * @return {@code true} if successfully initialize the {@link SatelliteOnDeviceAccessController}
      * instance, {@code false} otherwise.
      * @throws IllegalStateException in case of getting any exception in creating the
-     * {@link SatelliteOnDeviceAccessController} instance and the device is using a user build.
+     *                               {@link SatelliteOnDeviceAccessController} instance and the
+     *                               device is using a user build.
      */
     private boolean initSatelliteOnDeviceAccessController() throws IllegalStateException {
         synchronized (mLock) {
@@ -969,7 +1173,7 @@
     /**
      * Posts the specified command to be executed on the main thread and returns immediately.
      *
-     * @param command command to be executed on the main thread
+     * @param command  command to be executed on the main thread
      * @param argument additional parameters required to perform of the operation
      */
     private void sendRequestAsync(int command, @NonNull Object argument) {
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index 8df0603..aabc0fb 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -22,6 +22,7 @@
 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
 
 import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.EVENT_CONFIG_DATA_UPDATED;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessController.GOOGLE_US_SAN_SAT_S2_FILE_NAME;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -30,6 +31,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -45,6 +47,7 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.location.Location;
 import android.location.LocationManager;
@@ -85,12 +88,12 @@
 
 import java.io.File;
 import java.lang.reflect.Field;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -124,14 +127,26 @@
     private SatelliteModemInterface mMockSatelliteModemInterface;
     @Mock
     private Context mMockContext;
-    @Mock private Phone mMockPhone;
-    @Mock private Phone mMockPhone2;
-    @Mock private FeatureFlags mMockFeatureFlags;
-    @Mock private Resources mMockResources;
-    @Mock private SatelliteOnDeviceAccessController mMockSatelliteOnDeviceAccessController;
-    @Mock Location mMockLocation0;
-    @Mock Location mMockLocation1;
-    @Mock File mMockSatS2File;
+    @Mock
+    private Phone mMockPhone;
+    @Mock
+    private Phone mMockPhone2;
+    @Mock
+    private FeatureFlags mMockFeatureFlags;
+    @Mock
+    private Resources mMockResources;
+    @Mock
+    private SatelliteOnDeviceAccessController mMockSatelliteOnDeviceAccessController;
+    @Mock
+    Location mMockLocation0;
+    @Mock
+    Location mMockLocation1;
+    @Mock
+    File mMockSatS2File;
+    @Mock
+    SharedPreferences mMockSharedPreferences;
+    @Mock
+    private SharedPreferences.Editor mMockSharedPreferencesEditor;
 
     private Looper mLooper;
     private TestableLooper mTestableLooper;
@@ -148,7 +163,6 @@
     private ArgumentCaptor<Integer> mConfigUpdateIntCaptor;
     @Captor
     private ArgumentCaptor<Object> mConfigUpdateObjectCaptor;
-
     private boolean mQueriedSatelliteAllowed = false;
     private int mQueriedSatelliteAllowedResultCode = SATELLITE_RESULT_SUCCESS;
     private Semaphore mSatelliteAllowedSemaphore = new Semaphore(0);
@@ -197,7 +211,7 @@
                 mMockLocationManager);
         when(mMockContext.getSystemService(TelecomManager.class)).thenReturn(
                 mMockTelecomManager);
-        mPhones = new Phone[] {mMockPhone, mMockPhone2};
+        mPhones = new Phone[]{mMockPhone, mMockPhone2};
         replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
         replaceInstance(SatelliteController.class, "sInstance", null,
                 mMockSatelliteController);
@@ -231,6 +245,17 @@
         when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(true);
 
+        when(mMockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(
+                mMockSharedPreferences);
+        when(mMockSharedPreferences.getBoolean(anyString(), anyBoolean())).thenReturn(true);
+        when(mMockSharedPreferences.getStringSet(anyString(), any()))
+                .thenReturn(Set.of(TEST_SATELLITE_COUNTRY_CODES));
+        doReturn(mMockSharedPreferencesEditor).when(mMockSharedPreferences).edit();
+        doReturn(mMockSharedPreferencesEditor).when(mMockSharedPreferencesEditor)
+                .putBoolean(anyString(), anyBoolean());
+        doReturn(mMockSharedPreferencesEditor).when(mMockSharedPreferencesEditor)
+                .putStringSet(anyString(), any());
+
         mSatelliteAccessControllerUT = new TestSatelliteAccessController(mMockContext,
                 mMockFeatureFlags, mLooper, mMockLocationManager, mMockTelecomManager,
                 mMockSatelliteOnDeviceAccessController, mMockSatS2File);
@@ -463,7 +488,7 @@
     }
 
     @Test
-    public void testUpdateSatelliteConfigData() {
+    public void testUpdateSatelliteConfigData() throws Exception {
         verify(mMockSatelliteController).registerForConfigUpdateChanged(
                 mConfigUpdateHandlerCaptor.capture(), mConfigUpdateIntCaptor.capture(),
                 mConfigUpdateObjectCaptor.capture());
@@ -472,46 +497,58 @@
         assertSame(mConfigUpdateIntCaptor.getValue(), EVENT_CONFIG_DATA_UPDATED);
         assertSame(mConfigUpdateObjectCaptor.getValue(), mMockContext);
 
-        // Verify the case when the configParser is not exist.
-        SatelliteConfigParser spyConfigParserNull =
-                spy(new SatelliteConfigParser((byte[]) null));
-        doReturn(spyConfigParserNull).when(mMockSatelliteController).getSatelliteConfigParser();
+        // These APIs are executed during loadRemoteConfigs
+        verify(mMockSharedPreferences, times(1)).getStringSet(anyString(), any());
+        verify(mMockSharedPreferences, times(1)).getBoolean(anyString(), anyBoolean());
 
-        sendConfigUpdateChangedEvent(mMockContext);
-
-        assertNull(spyConfigParserNull.getConfig());
-
-        // Verify the case when the configParser exist but empty.
-        SatelliteConfigParser spyConfigParserEmpty =
+        // satelliteConfig is null
+        SatelliteConfigParser spyConfigParser =
                 spy(new SatelliteConfigParser("test".getBytes()));
-        doReturn(spyConfigParserEmpty).when(mMockSatelliteController).getSatelliteConfigParser();
+        doReturn(spyConfigParser).when(mMockSatelliteController).getSatelliteConfigParser();
+        assertNull(spyConfigParser.getConfig());
 
         sendConfigUpdateChangedEvent(mMockContext);
+        verify(mMockSharedPreferences, never()).edit();
 
-        assertNull(spyConfigParserEmpty.getConfig());
+        // satelliteConfig has invalid country codes
+        SatelliteConfig mockConfig = mock(SatelliteConfig.class);
+        doReturn(List.of("USA", "JAP")).when(mockConfig).getDeviceSatelliteCountryCodes();
+        doReturn(mockConfig).when(mMockSatelliteController).getSatelliteConfig();
+        doReturn(false).when(mockConfig).isSatelliteDataForAllowedRegion();
 
-        // Verify the case when the configParser exists and has valid data
-        SatelliteConfig mockSatelliteConfig = mock(SatelliteConfig.class);
-        Path mockTargetSatS2FilePath = mock(Path.class);
-        File mockS2CellFile = mock(File.class);
-        doReturn(mockS2CellFile).when(mockTargetSatS2FilePath).toFile();
-        doReturn(true).when(mockS2CellFile).exists();
-        doReturn(false).when(mockSatelliteConfig).isFileExist(any());
-        doReturn(mockTargetSatS2FilePath).when(mockSatelliteConfig)
-                .copySatS2FileToPhoneDirectory(any(), any());
-        doReturn(Arrays.asList("US")).when(mockSatelliteConfig).getDeviceSatelliteCountryCodes();
-        doReturn(false).when(mockSatelliteConfig).isSatelliteDataForAllowedRegion();
-        doReturn(mockTargetSatS2FilePath).when(mockSatelliteConfig).getSatelliteS2CellFile(any());
-        doReturn(mockSatelliteConfig).when(mMockSatelliteController).getSatelliteConfig();
-
-        mSatelliteAccessControllerUT.setSatelliteOnDeviceAccessController(
-                mMockSatelliteOnDeviceAccessController);
         sendConfigUpdateChangedEvent(mMockContext);
+        verify(mMockSharedPreferences, never()).edit();
 
-        verify(mockSatelliteConfig, times(2)).getDeviceSatelliteCountryCodes();
-        verify(mockSatelliteConfig, times(2)).isSatelliteDataForAllowedRegion();
-        verify(mockSatelliteConfig, times(2)).getSatelliteS2CellFile(any());
-        assertTrue(mSatelliteAccessControllerUT.isSatelliteOnDeviceAccessControllerReset());
+        // satelliteConfig does not have is_allow_access_control data
+        doReturn(List.of(TEST_SATELLITE_COUNTRY_CODES))
+                .when(mockConfig).getDeviceSatelliteCountryCodes();
+        doReturn(null).when(mockConfig).isSatelliteDataForAllowedRegion();
+
+        sendConfigUpdateChangedEvent(mMockContext);
+        verify(mMockSharedPreferences, never()).edit();
+
+        // satelliteConfig doesn't have S2CellFile
+        File mockFile = mock(File.class);
+        doReturn(false).when(mockFile).exists();
+        doReturn(List.of(TEST_SATELLITE_COUNTRY_CODES))
+                .when(mockConfig).getDeviceSatelliteCountryCodes();
+        doReturn(true).when(mockConfig).isSatelliteDataForAllowedRegion();
+        doReturn(mockFile).when(mockConfig).getSatelliteS2CellFile(mMockContext);
+
+        sendConfigUpdateChangedEvent(mMockContext);
+        verify(mMockSharedPreferences, never()).edit();
+
+        // satelliteConfig has valid data
+        doReturn(mockConfig).when(mMockSatelliteController).getSatelliteConfig();
+        File testS2File = mSatelliteAccessControllerUT
+                .getTestSatelliteS2File(GOOGLE_US_SAN_SAT_S2_FILE_NAME);
+        doReturn(List.of(TEST_SATELLITE_COUNTRY_CODES))
+                .when(mockConfig).getDeviceSatelliteCountryCodes();
+        doReturn(true).when(mockConfig).isSatelliteDataForAllowedRegion();
+        doReturn(testS2File).when(mockConfig).getSatelliteS2CellFile(mMockContext);
+
+        sendConfigUpdateChangedEvent(mMockContext);
+        verify(mMockSharedPreferences, times(2)).edit();
     }
 
     private void sendConfigUpdateChangedEvent(Context context) {