Merge "reduce number of location query" into 24D1-dev am: b6f8618819

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telephony/+/27552336

Change-Id: I75f1168b1968bc21865ee49ba835156dbcbf5cbc
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index e22f51a..e6a143b 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -13930,6 +13930,32 @@
     }
 
     /**
+     * This API can be used by only CTS to set the cache whether satellite communication is allowed.
+     *
+     * @param state a state indicates whether satellite access allowed state should be cached and
+     * the allowed state.
+     * @return {@code true} if the setting is successful, {@code false} otherwise.
+     */
+    public boolean setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            Log.d(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache: "
+                    + "oemEnabledSatelliteFlag is disabled");
+            return false;
+        }
+
+        Log.d(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache: "
+                + "state=" + state);
+        TelephonyPermissions.enforceShellOnly(
+                Binder.getCallingUid(),
+                "setIsSatelliteCommunicationAllowedForCurrentLocationCache");
+        TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+                "setIsSatelliteCommunicationAllowedForCurrentLocationCache");
+        return mSatelliteAccessController.setIsSatelliteCommunicationAllowedForCurrentLocationCache(
+                state);
+    }
+
+    /**
      * Sets the service defined in ComponentName to be bound.
      *
      * This should only be used for testing.
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 9f67c75..6969275 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -207,6 +207,8 @@
             "set-oem-enabled-satellite-provision-status";
     private static final String SET_SHOULD_SEND_DATAGRAM_TO_MODEM_IN_DEMO_MODE =
             "set-should-send-datagram-to-modem-in-demo-mode";
+    private static final String SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE =
+            "set-is-satellite-communication-allowed-for-current-location-cache";
 
     private static final String DOMAIN_SELECTION_SUBCOMMAND = "domainselection";
     private static final String DOMAIN_SELECTION_SET_SERVICE_OVERRIDE = "set-dss-override";
@@ -418,6 +420,8 @@
                 return handleSetCountryCodes();
             case SET_OEM_ENABLED_SATELLITE_PROVISION_STATUS:
                 return handleSetOemEnabledSatelliteProvisionStatus();
+            case SET_IS_SATELLITE_COMMUNICATION_ALLOWED_FOR_CURRENT_LOCATION_CACHE:
+                return handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -3699,6 +3703,61 @@
         return 0;
     }
 
+    private int handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache() {
+        PrintWriter errPw = getErrPrintWriter();
+        String opt;
+        String state;
+
+        if ((opt = getNextArg()) == null) {
+            errPw.println(
+                    "adb shell cmd phone set-is-satellite-communication-allowed-for-current"
+                            + "-location-cache :"
+                            + " Invalid Argument");
+            return -1;
+        } else {
+            switch (opt) {
+                case "-a": {
+                    state = "cache_allowed";
+                    break;
+                }
+                case "-n": {
+                    state = "cache_clear_and_not_allowed";
+                    break;
+                }
+                case "-c": {
+                    state = "clear_cache_only";
+                    break;
+                }
+                default:
+                    errPw.println(
+                            "adb shell cmd phone set-is-satellite-communication-allowed-for-current"
+                                    + "-location-cache :"
+                                    + " Invalid Argument");
+                    return -1;
+            }
+        }
+
+        Log.d(LOG_TAG, "handleSetIsSatelliteCommunicationAllowedForCurrentLocationCache("
+                + state + ")");
+
+        try {
+            boolean result = mInterface.setIsSatelliteCommunicationAllowedForCurrentLocationCache(
+                    state);
+            if (VDBG) {
+                Log.v(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache "
+                        + "returns: "
+                        + result);
+            }
+            getOutPrintWriter().println(result);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "setIsSatelliteCommunicationAllowedForCurrentLocationCache("
+                    + state + "), error = " + e.getMessage());
+            errPw.println("Exception: " + e.getMessage());
+            return -1;
+        }
+        return 0;
+    }
+
     /**
      * Sample inputStr = "US,UK,CA;2,1,3"
      * Sample output: {[US,2], [UK,1], [CA,3]}
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index d8c54eb..97a170b 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -76,6 +76,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -208,6 +209,10 @@
     @GuardedBy("mSatelliteCommunicationAllowStateLock")
     private boolean mCurrentSatelliteAllowedState = false;
 
+    private static final long NANOS_IN_DAY = Duration.ofDays(1).toNanos();
+    private boolean mLatestSatelliteCommunicationAllowed;
+    private long mLatestSatelliteCommunicationAllowedSetTime;
+
     /**
      * Create a SatelliteAccessController instance.
      *
@@ -790,7 +795,7 @@
                         sendSatelliteAllowResultToReceivers(resultCode, bundle, false);
                     } else {
                         logd("Satellite is provisioned");
-                        checkSatelliteAccessRestrictionForCurrentLocation();
+                        checkSatelliteAccessRestrictionUsingGPS();
                     }
                 } else {
                     loge("KEY_SATELLITE_PROVISIONED does not exist.");
@@ -841,6 +846,55 @@
     }
 
     /**
+     * Telephony-internal logic to verify if satellite access is restricted from the location query.
+     */
+    private void checkSatelliteAccessRestrictionUsingGPS() {
+        logv("checkSatelliteAccessRestrictionUsingGPS:");
+        if (isInEmergency()) {
+            executeLocationQuery();
+        } else {
+            if (mLocationManager.isLocationEnabled()) {
+                logd("location query is allowed");
+                if (isCommunicationAllowedCacheValid()) {
+                    Bundle bundle = new Bundle();
+                    bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED,
+                            mLatestSatelliteCommunicationAllowed);
+                    sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
+                            mLatestSatelliteCommunicationAllowed);
+                } else {
+                    executeLocationQuery();
+                }
+            } else {
+                logv("location query is not allowed");
+                Bundle bundle = new Bundle();
+                bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
+                sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, false);
+            }
+        }
+    }
+
+    /* returns true,if the latest query was executed in 24Hr, or returns false. */
+    private boolean isCommunicationAllowedCacheValid() {
+        if (mLatestSatelliteCommunicationAllowedSetTime > 0) {
+            long currentTime = SystemClock.elapsedRealtimeNanos();
+            if ((currentTime - mLatestSatelliteCommunicationAllowedSetTime) <= NANOS_IN_DAY) {
+                logv("isCommunicationAllowedCacheValid: cache is valid");
+                return true;
+            }
+        }
+        logv("isCommunicationAllowedCacheValid: cache is expired");
+        return false;
+    }
+
+    private void executeLocationQuery() {
+        logv("executeLocationQuery");
+        synchronized (mLock) {
+            mFreshLastKnownLocation = getFreshLastKnownLocation();
+            checkSatelliteAccessRestrictionUsingOnDeviceData();
+        }
+    }
+
+    /**
      * This function synchronously checks if satellite is allowed at current location using cached
      * country codes.
      */
@@ -917,7 +971,18 @@
             if (location != null) {
                 checkSatelliteAccessRestrictionForLocation(location);
             } else {
-                checkSatelliteAccessRestrictionUsingCachedCountryCodes();
+                logd("current location is not available");
+                Bundle bundle = new Bundle();
+                if (isCommunicationAllowedCacheValid()) {
+                    logd("onCurrentLocationAvailable: 24Hr cache is still valid, using it");
+                    bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED,
+                            mLatestSatelliteCommunicationAllowed);
+                    sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
+                            mLatestSatelliteCommunicationAllowed);
+                } else {
+                    bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
+                    sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, false);
+                }
             }
         }
     }
@@ -935,7 +1000,10 @@
                 } else {
                     if (!initSatelliteOnDeviceAccessController()) {
                         loge("Failed to init SatelliteOnDeviceAccessController");
-                        checkSatelliteAccessRestrictionUsingCachedCountryCodes();
+                        Bundle bundle = new Bundle();
+                        bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
+                        sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
+                                false);
                         return;
                     }
                     satelliteAllowed = mSatelliteOnDeviceAccessController
@@ -946,11 +1014,23 @@
                 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, satelliteAllowed);
                 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
                         satelliteAllowed);
+                mLatestSatelliteCommunicationAllowed = satelliteAllowed;
+                mLatestSatelliteCommunicationAllowedSetTime = SystemClock.elapsedRealtimeNanos();
             } catch (Exception ex) {
                 loge("checkSatelliteAccessRestrictionForLocation: ex=" + ex);
                 reportAnomaly(UUID_ON_DEVICE_LOOKUP_EXCEPTION,
                         "On-device satellite lookup exception");
-                checkSatelliteAccessRestrictionUsingCachedCountryCodes();
+                Bundle bundle = new Bundle();
+                if (isCommunicationAllowedCacheValid()) {
+                    bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED,
+                            mLatestSatelliteCommunicationAllowed);
+                    logd("checkSatelliteAccessRestrictionForLocation: 24Hr cache is still valid, "
+                            + "using it");
+                } else {
+                    bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false);
+                }
+                sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle,
+                        mLatestSatelliteCommunicationAllowed);
             }
         }
     }
@@ -1326,6 +1406,49 @@
         mSatelliteCommunicationAllowedStateChangedListeners.remove(callback.asBinder());
     }
 
+    /**
+     * This API can be used by only CTS to set the cache whether satellite communication is allowed.
+     *
+     * @param state a state indicates whether satellite access allowed state should be cached and
+     * the allowed state.
+     * @return {@code true} if the setting is successful, {@code false} otherwise.
+     */
+    public boolean setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state) {
+        if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+            logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: "
+                    + "oemEnabledSatelliteFlag is disabled");
+            return false;
+        }
+
+        if (!isMockModemAllowed()) {
+            logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: "
+                    + "mock modem not allowed.");
+            return false;
+        }
+
+        logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: state=" + state);
+
+        synchronized (mSatelliteCommunicationAllowStateLock) {
+            if ("cache_allowed".equalsIgnoreCase(state)) {
+                mLatestSatelliteCommunicationAllowedSetTime = SystemClock.elapsedRealtimeNanos();
+                mLatestSatelliteCommunicationAllowed = true;
+                mCurrentSatelliteAllowedState = true;
+            } else if ("cache_clear_and_not_allowed".equalsIgnoreCase(state)) {
+                mLatestSatelliteCommunicationAllowedSetTime = 0;
+                mLatestSatelliteCommunicationAllowed = false;
+                mCurrentSatelliteAllowedState = false;
+            } else if ("clear_cache_only".equalsIgnoreCase(state)) {
+                mLatestSatelliteCommunicationAllowedSetTime = 0;
+                mLatestSatelliteCommunicationAllowed = false;
+            } else {
+                loge("setIsSatelliteCommunicationAllowedForCurrentLocationCache: invalid state="
+                        + state);
+                return false;
+            }
+        }
+        return true;
+    }
+
     private void notifySatelliteCommunicationAllowedStateChanged(boolean allowState) {
         logd("notifySatelliteCommunicationAllowedStateChanged: allowState=" + allowState);
 
@@ -1354,4 +1477,8 @@
     private static void loge(@NonNull String log) {
         Rlog.e(TAG, log);
     }
+
+    private static void logv(@NonNull String log) {
+        Rlog.v(TAG, log);
+    }
 }
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index 62d9d8c..f2427b1 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -323,22 +323,11 @@
                 mSatelliteAllowedSemaphore, 1));
         assertEquals(SATELLITE_RESULT_MODEM_ERROR, mQueriedSatelliteAllowedResultCode);
 
-        // Network country codes are available.
-        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
-        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
-        clearAllInvocations();
-        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(listOf("US", "CA"));
-        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
-                SUB_ID, mSatelliteAllowedReceiver);
-        mTestableLooper.processAllMessages();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
-                mSatelliteAllowedSemaphore, 1));
-        assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteAllowedResultCode);
-        assertTrue(mQueriedSatelliteAllowed);
-
         // Network country codes are not available. TelecomManager.isInEmergencyCall() returns true.
         // On-device access controller will be used. Last known location is available and fresh.
         clearAllInvocations();
+        setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+        setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_RESULT_SUCCESS);
         when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(EMPTY_STRING_LIST);
         when(mMockTelecomManager.isInEmergencyCall()).thenReturn(true);
         mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
@@ -424,12 +413,11 @@
         assertFalse(mSatelliteAccessControllerUT.isWaitForCurrentLocationTimerStarted());
         verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
-        verifyCountryDetectorApisCalled();
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
         assertEquals(SATELLITE_RESULT_SUCCESS,
                 mQueriedSatelliteAllowedResultCode);
-        assertFalse(mQueriedSatelliteAllowed);
+        assertTrue(mQueriedSatelliteAllowed);
 
         // Network country codes are not available. TelecomManager.isInEmergencyCall() returns
         // false. No phone is in ECM. Last known location is not fresh. Cached country codes should
@@ -452,43 +440,11 @@
                 any(Consumer.class));
         verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
                 any(SatelliteOnDeviceAccessController.LocationToken.class));
-        verifyCountryDetectorApisCalled();
         assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
                 mSatelliteAllowedSemaphore, 1));
         assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteAllowedResultCode);
         assertFalse(mQueriedSatelliteAllowed);
 
-        // Network country codes are not available. TelecomManager.isInEmergencyCall() returns
-        // false. No phone is in ECM. Last known location is not fresh. Cached country codes should
-        // be used for verifying satellite allow. Cached country codes are available.
-        clearAllInvocations();
-        when(mMockCountryDetector.getCurrentNetworkCountryIso()).thenReturn(EMPTY_STRING_LIST);
-        when(mMockCountryDetector.getCachedLocationCountryIsoInfo())
-                .thenReturn(new Pair<>("US", 5L));
-        Map<String, Long> cachedNetworkCountryCodes = new HashMap<>();
-        cachedNetworkCountryCodes.put("UK", 1L);
-        cachedNetworkCountryCodes.put("US", 3L);
-        when(mMockCountryDetector.getCachedNetworkCountryIsoInfo())
-                .thenReturn(cachedNetworkCountryCodes);
-        when(mMockTelecomManager.isInEmergencyCall()).thenReturn(false);
-        when(mMockPhone.isInEcm()).thenReturn(false);
-        when(mMockPhone2.isInEcm()).thenReturn(false);
-        mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
-        when(mMockLocation0.getElapsedRealtimeNanos()).thenReturn(0L);
-        when(mMockLocation1.getElapsedRealtimeNanos()).thenReturn(0L);
-        mSatelliteAccessControllerUT.requestIsCommunicationAllowedForCurrentLocation(
-                SUB_ID, mSatelliteAllowedReceiver);
-        mTestableLooper.processAllMessages();
-        verify(mMockLocationManager, never()).getCurrentLocation(anyString(),
-                any(LocationRequest.class), any(CancellationSignal.class), any(Executor.class),
-                any(Consumer.class));
-        verify(mMockSatelliteOnDeviceAccessController, never()).isSatCommunicationAllowedAtLocation(
-                any(SatelliteOnDeviceAccessController.LocationToken.class));
-        verifyCountryDetectorApisCalled();
-        assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(
-                mSatelliteAllowedSemaphore, 1));
-        assertEquals(SATELLITE_RESULT_SUCCESS, mQueriedSatelliteAllowedResultCode);
-        assertTrue(mQueriedSatelliteAllowed);
     }
 
     @Test