Use network country code to disallow satellite

Bug: 358375489
Flag: com.android.internal.telephony.flags.oem_enabled_satellite_flag
Test: atest SatelliteAccessControllerTest(http://ab/I91500010308418737-passed)
Test: Manually verified the pixel satellite is not supported when the network-mcc is not in the allowed list. (more details are at b/358375489#comment4)

Change-Id: I8de6860313253af12ebb1961dc468ca80d2dd9ef
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 75a1fb4..1e3aa2f 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -771,7 +771,8 @@
         mConfigUpdaterMetricsStats.reportConfigUpdateSuccess();
     }
 
-    private void loadOverlayConfigs(@NonNull Context context) {
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    protected void loadOverlayConfigs(@NonNull Context context) {
         mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
         mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
         String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context);
@@ -911,6 +912,30 @@
         }
     }
 
+    /**
+     * At country borders, a multi-SIM device might connect to multiple cellular base
+     * stations and thus might have multiple different MCCs.
+     * In such cases, framework is not sure whether the region should be disallowed or not,
+     * and thus the geofence data will be used to decide whether to allow satellite.
+     */
+    private boolean isRegionDisallowed(List<String> networkCountryIsoList) {
+        if (networkCountryIsoList.isEmpty()) {
+            plogd("isRegionDisallowed : true : it's not sure if empty is disallowed");
+            return false;
+        }
+
+        for (String countryCode : networkCountryIsoList) {
+            if (isSatelliteAccessAllowedForLocation(List.of(countryCode))) {
+                plogd("isRegionDisallowed : false : Country Code " + countryCode
+                        + " is in the list from the configuration");
+                return false;
+            }
+        }
+
+        plogd("isRegionDisallowed : true : " + networkCountryIsoList);
+        return true;
+    }
+
     private void handleIsSatelliteSupportedResult(int resultCode, Bundle resultData) {
         plogd("handleIsSatelliteSupportedResult: resultCode=" + resultCode);
         synchronized (mLock) {
@@ -925,7 +950,19 @@
                         sendSatelliteAllowResultToReceivers(resultCode, bundle, false);
                     } else {
                         plogd("Satellite is supported");
-                        checkSatelliteAccessRestrictionUsingGPS();
+                        List<String> networkCountryIsoList =
+                                mCountryDetector.getCurrentNetworkCountryIso();
+                        if (isRegionDisallowed(networkCountryIsoList)) {
+                            Bundle bundle = new Bundle();
+                            bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
+                            mAccessControllerMetricsStats.setAccessControlType(
+                                    SatelliteConstants.ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE)
+                                    .setCountryCodes(networkCountryIsoList);
+                            sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
+                                    false);
+                        } else {
+                            checkSatelliteAccessRestrictionUsingGPS();
+                        }
                     }
                 } else {
                     ploge("KEY_SATELLITE_SUPPORTED does not exist.");
@@ -1336,7 +1373,8 @@
         return true;
     }
 
-    private boolean isSatelliteAccessAllowedForLocation(
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    protected boolean isSatelliteAccessAllowedForLocation(
             @NonNull List<String> networkCountryIsoList) {
         if (isSatelliteAllowAccessControl()) {
             // The current country is unidentified, we're uncertain and thus returning false
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index cbca7b7..87c73ac 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -115,8 +115,14 @@
 public class SatelliteAccessControllerTest {
     private static final String TAG = "SatelliteAccessControllerTest";
     private static final String[] TEST_SATELLITE_COUNTRY_CODES = {"US", "CA", "UK"};
+    private static final String[] TEST_SATELLITE_COUNTRY_CODES_EMPTY = {""};
+    private static final String TEST_SATELLITE_COUNTRY_CODE_US = "US";
+    private static final String TEST_SATELLITE_COUNTRY_CODE_KR = "KR";
+    private static final String TEST_SATELLITE_COUNTRY_CODE_JP = "JP";
+
     private static final String TEST_SATELLITE_S2_FILE = "sat_s2_file.dat";
     private static final boolean TEST_SATELLITE_ALLOW = true;
+    private static final boolean TEST_SATELLITE_NOT_ALLOW = false;
     private static final int TEST_LOCATION_FRESH_DURATION_SECONDS = 10;
     private static final long TEST_LOCATION_FRESH_DURATION_NANOS =
             TimeUnit.SECONDS.toNanos(TEST_LOCATION_FRESH_DURATION_SECONDS);
@@ -332,6 +338,269 @@
     }
 
     @Test
+    public void testIsSatelliteAccessAllowedForLocation() {
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+        // Test disallowList case
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_oem_enabled_satellite_access_allow))
+                .thenReturn(TEST_SATELLITE_NOT_ALLOW);
+
+        // configuration is EMPTY then we return true with any network country code.
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES_EMPTY);
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        assertTrue(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_US)));
+        assertTrue(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_JP)));
+
+        // configuration is ["US", "CA", "UK"]
+        // - if network country code is ["US"] or ["US","KR"] or [EMPTY] return false;
+        // - if network country code is ["KR"] return true;
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES);
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        assertFalse(mSatelliteAccessControllerUT.isSatelliteAccessAllowedForLocation(List.of()));
+        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)));
+        assertTrue(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_KR)));
+
+        // Test allowList case
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_oem_enabled_satellite_access_allow))
+                .thenReturn(TEST_SATELLITE_ALLOW);
+
+        // configuration is [EMPTY] then return false in case of any network country code
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES_EMPTY);
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        assertFalse(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_US)));
+        assertFalse(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_JP)));
+
+        // configuration is ["US", "CA", "UK"]
+        // - if network country code is [EMPTY] or ["US","KR"] or [KR] return false;
+        // - if network country code is ["US"] return true;
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES);
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        assertFalse(mSatelliteAccessControllerUT.isSatelliteAccessAllowedForLocation(List.of()));
+        assertFalse(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_KR)));
+        assertFalse(mSatelliteAccessControllerUT.isSatelliteAccessAllowedForLocation(
+                List.of(TEST_SATELLITE_COUNTRY_CODE_US, TEST_SATELLITE_COUNTRY_CODE_KR)));
+        assertTrue(mSatelliteAccessControllerUT
+                .isSatelliteAccessAllowedForLocation(List.of(TEST_SATELLITE_COUNTRY_CODE_US)));
+    }
+
+    @Test
+    public void testIsRegionDisallowed() throws Exception {
+        // setup to make the return value of mQueriedSatelliteAllowed 'true'
+        when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_oem_enabled_satellite_access_allow))
+                .thenReturn(TEST_SATELLITE_ALLOW);
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
+        doReturn(true).when(mMockLocationManager).isLocationEnabled();
+        when(mMockSatelliteOnDeviceAccessController.isSatCommunicationAllowedAtLocation(
+                any(SatelliteOnDeviceAccessController.LocationToken.class))).thenReturn(true);
+        replaceInstance(SatelliteAccessController.class, "mCachedAccessRestrictionMap",
+                mSatelliteAccessControllerUT, mMockCachedAccessRestrictionMap);
+        doReturn(true).when(mMockCachedAccessRestrictionMap).containsKey(any());
+        doReturn(true).when(mMockCachedAccessRestrictionMap).get(any());
+
+        // get allowed country codes EMPTY from resources
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES_EMPTY);
+
+        // allow case that network country codes [US] with [EMPTY] configuration
+        // location will not be compared and mQueriedSatelliteAllowed will be set false
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_US));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(0)).containsKey(any());
+        assertFalse(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [EMPTY] with [EMPTY] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(List.of());
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // get allowed country codes [US, CA, UK] from resources
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES);
+
+        // allow case that network country codes [US, CA, UK] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODES));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [US] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_US));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [US, KR] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(
+                List.of(TEST_SATELLITE_COUNTRY_CODE_US, TEST_SATELLITE_COUNTRY_CODE_KR));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [US] with [EMPTY] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(List.of());
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [KR, JP] with [US, CA, UK] configuration
+        // location will not be compared and mQueriedSatelliteAllowed will be set false
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(
+                List.of(TEST_SATELLITE_COUNTRY_CODE_KR, TEST_SATELLITE_COUNTRY_CODE_JP));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(0)).containsKey(any());
+        assertFalse(mQueriedSatelliteAllowed);
+
+        // allow case that network country codes [KR] with [US, CA, UK] configuration
+        // location will not be compared and mQueriedSatelliteAllowed will be set false
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_KR));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(0)).containsKey(any());
+        assertFalse(mQueriedSatelliteAllowed);
+
+
+        // set disallowed list case
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_oem_enabled_satellite_access_allow))
+                .thenReturn(TEST_SATELLITE_NOT_ALLOW);
+        // get disallowed country codes list [EMPTY] from resources
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES_EMPTY);
+
+        // disallow case that network country codes [US] with [EMPTY] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_US));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // get disallowed country codes list ["US", "CA", "UK"] from resources
+        when(mMockResources.getStringArray(
+                com.android.internal.R.array.config_oem_enabled_satellite_country_codes))
+                .thenReturn(TEST_SATELLITE_COUNTRY_CODES);
+
+        // disallow case that network country codes [EMPTY] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODES_EMPTY));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // disallow case that network country codes [US, JP] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(
+                List.of(TEST_SATELLITE_COUNTRY_CODE_US, TEST_SATELLITE_COUNTRY_CODE_JP));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // disallow case that network country codes [JP] with [US, CA, UK] configuration
+        // location will be compared and mQueriedSatelliteAllowed will be set true
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_JP));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(1)).containsKey(any());
+        assertTrue(mQueriedSatelliteAllowed);
+
+        // disallow case that network country codes [US] with [US, CA, UK] configuration
+        // location will not be compared and mQueriedSatelliteAllowed will be set false
+        clearInvocations(mMockCachedAccessRestrictionMap);
+        when(mMockCountryDetector.getCurrentNetworkCountryIso())
+                .thenReturn(List.of(TEST_SATELLITE_COUNTRY_CODE_US));
+        mSatelliteAccessControllerUT.loadOverlayConfigs(mMockContext);
+        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
+                SUB_ID, mSatelliteAllowedReceiver);
+        mTestableLooper.processAllMessages();
+        verify(mMockCachedAccessRestrictionMap, times(0)).containsKey(any());
+        assertFalse(mQueriedSatelliteAllowed);
+    }
+
+    @Test
     public void testRequestIsSatelliteCommunicationAllowedForCurrentLocation() throws Exception {
         // OEM-enabled satellite is not supported
         when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
@@ -409,6 +678,8 @@
         when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(EMPTY_STRING_LIST);
         when(mMockTelecomManager.isInEmergencyCall()).thenReturn(false);
         when(mMockPhone.isInEcm()).thenReturn(true);
+        when(mMockPhone.getContext()).thenReturn(mMockContext);
+        when(mMockPhone2.getContext()).thenReturn(mMockContext);
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
         when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(0L);
         when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);