Add logic to SatelliteAccessController class

Bug: 313773568
Test: atest SatelliteAccessControllerTest
atest SatelliteManagerTestOnMockService

Change-Id: I5eb3651baed905187cb27040a2135199e9f5c24d
diff --git a/utils/satellite/README.md b/utils/satellite/README.md
index e219823..77ee0fb 100644
--- a/utils/satellite/README.md
+++ b/utils/satellite/README.md
@@ -8,7 +8,7 @@
 - `src/write` S2 write code used by tools to write the s2 cells into a
   binary file. This code is also used by `TeleServiceTests`.
 - `src/readonly` S2 read-only code used by the above read-write code and the class
- `S2RangeFileBasedSatelliteLocationLookup`.
+ `S2RangeSatelliteOnDeviceAccessController`.
 
 `tools`
 - `src/main` Contains the tools for generating binary satellite s2 file, and tools
@@ -29,7 +29,7 @@
   list of S2 cells ID.
 - Command: `$satellite_createsats2file --input-file <s2cells.txt> --s2-level <12>
   --is-allowed-list <true> --output-file <sats2.dat>`
-  - `--input-file` Each line in the file contains a `signed-64bit` number which represents
+  - `--input-file` Each line in the file contains a `unsigned-64bit` number which represents
     the ID of a S2 cell.
   - `--s2-level` The S2 level of all the cells in the input file.
   - `--is-allowed-list` Should be either `trrue` or `false`
@@ -51,7 +51,7 @@
   - [(prefix=0b100_11111111, suffix=1000), (prefix=0b100_11111111, suffix=2000))
   - [(prefix=0b100_11111111, suffix=2000), (prefix=0b100_11111111, suffix=3000))
   - [(prefix=0b101_11111111, suffix=1000), (prefix=0b101_11111111, suffix=2000))
-- Run the test tool: `$satellite_createtestsats2file /tmp/foo.dat`
+- Run the test tool: `satellite_createsats2file_test /tmp/foo.dat`
   - This command will generate the binary satellite S2 cell file `/tmp/foo.dat` with
   the above S2 ranges.
 
@@ -59,4 +59,9 @@
 - Dump the input binary satellite S2 cell file into human-readable text format.
 - Run the tool: `$satellite_dumpsats2file /tmp/foo.dat /tmp/foo`
   - `/tmp/foo.dat` Input binary satellite S2 cell file.
-  - `/tmp/foo` Output directory which contains the output text files.
\ No newline at end of file
+  - `/tmp/foo` Output directory which contains the output text files.
+
+`satellite_location_lookup`
+- Check if a location is present in the input satellite S2 file.
+- Run the tool: `$satellite_location_lookup --input-file <...> --lat-degrees <...>
+  --lng-degrees <...>`
\ No newline at end of file
diff --git a/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java b/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
index 4b8a026..3cf2c78 100644
--- a/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
+++ b/utils/satellite/s2storage/src/testutils/java/com/android/telephony/sats2range/testutils/TestUtils.java
@@ -107,19 +107,22 @@
         try (PrintStream printer = new PrintStream(outputFile)) {
             // Range 1
             for (int suffix = 1000; suffix < 2000; suffix++) {
-                printer.println(String.valueOf(fileFormat.createCellId(0b100_11111111, suffix)));
+                printer.println(
+                        Long.toUnsignedString(fileFormat.createCellId(0b100_11111111, suffix)));
             }
 
             // Range 2
             for (int suffix = 2001; suffix < 3000; suffix++) {
-                printer.println(String.valueOf(fileFormat.createCellId(0b100_11111111, suffix)));
+                printer.println(
+                        Long.toUnsignedString(fileFormat.createCellId(0b100_11111111, suffix)));
             }
 
             // Range 3
             for (int suffix = 1000; suffix < 2000; suffix++) {
-                printer.println(String.valueOf(fileFormat.createCellId(0b101_11111111, suffix)));
+                printer.println(
+                        Long.toUnsignedString(fileFormat.createCellId(0b101_11111111, suffix)));
             }
-            printer.print(String.valueOf(fileFormat.createCellId(0b101_11111111, 2000)));
+            printer.print(Long.toUnsignedString(fileFormat.createCellId(0b101_11111111, 2000)));
 
             printer.close();
         }
@@ -130,13 +133,13 @@
             File outputFile, SatS2RangeFileFormat fileFormat) throws Exception {
         try (PrintStream printer = new PrintStream(outputFile)) {
             // Valid line
-            printer.println(String.valueOf(fileFormat.createCellId(0b100_11111111, 100)));
+            printer.println(Long.toUnsignedString(fileFormat.createCellId(0b100_11111111, 100)));
 
             // Invalid line
             printer.print("Invalid line");
 
             // Another valid line
-            printer.println(String.valueOf(fileFormat.createCellId(0b100_11111111, 200)));
+            printer.println(Long.toUnsignedString(fileFormat.createCellId(0b100_11111111, 200)));
 
             printer.close();
         }
diff --git a/utils/satellite/tools/Android.bp b/utils/satellite/tools/Android.bp
index 9aacdd9..d48b911 100644
--- a/utils/satellite/tools/Android.bp
+++ b/utils/satellite/tools/Android.bp
@@ -39,6 +39,15 @@
     ],
 }
 
+// A tool to look up a location in the input binary satellite S2 file.
+java_binary_host {
+    name: "satellite_location_lookup",
+    main_class: "com.android.telephony.tools.sats2.SatS2LocationLookup",
+    static_libs: [
+        "satellite-s2storage-tools",
+    ],
+}
+
 // A tool to create a test satellite S2 file.
 java_binary_host {
     name: "satellite_createsats2file_test",
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 b701a7b..bc25d6b 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
@@ -30,18 +30,19 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Scanner;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 /** A util class for creating a satellite S2 file from the list of S2 cells. */
 public final class SatS2FileCreator {
     /**
      * @param inputFile The input text file containing the list of S2 Cell IDs. Each line in the
-     *                  file contains a number in the range of a signed-64bit number which
+     *                  file contains a number in the range of an unsigned-64bit number which
      *                  represents the ID of a S2 cell.
      * @param s2Level The S2 level of all S2 cells in the input file.
      * @param isAllowedList {@code true} means the input file contains an allowed list of S2 cells.
@@ -57,12 +58,12 @@
         System.out.println("Number of S2 cells read from file:" + s2Cells.size());
 
         // Convert the input list of S2 Cells into the list of sorted S2CellId
-        List<S2CellId> sortedS2CellIds = s2Cells.stream()
-                .map(x -> new S2CellId(x))
-                .collect(Collectors.toList());
+        System.out.println("Denormalizing S2 Cell IDs to the expected s2 level=" + s2Level);
+        List<S2CellId> sortedS2CellIds = denormalize(s2Cells, s2Level);
         // IDs of S2CellId are converted to unsigned long numbers, which will be then used to
         // compare S2CellId.
         Collections.sort(sortedS2CellIds);
+        System.out.println("Number of S2 cell IDs:" + sortedS2CellIds.size());
 
         // Compress the list of S2CellId into S2 ranges
         List<SatS2Range> satS2Ranges = createSatS2Ranges(sortedS2CellIds, s2Level);
@@ -132,25 +133,56 @@
      * Read a list of S2 cells from the inputFile.
      *
      * @param inputFile A file containing the list of S2 cells. Each line in the inputFile contains
-     *                  a long number - the ID of a S2 cell.
+     *                  an unsigned long number - the ID of a S2 cell.
      * @return A list of S2 cells.
      */
     private static List<Long> readS2CellsFromFile(String inputFile) throws Exception {
         List<Long> s2Cells = new ArrayList();
         InputStream inputStream = new FileInputStream(inputFile);
         try (Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) {
-            while (scanner.hasNextLong()) {
-                s2Cells.add(scanner.nextLong());
-            }
-            if (scanner.hasNextLine()) {
-                throw new IllegalStateException("Input s2 cell file has invalid format, "
-                        + "current line=" + scanner.nextLine());
+            while (scanner.hasNextLine()) {
+                String line = scanner.nextLine();
+                try {
+                    s2Cells.add(Long.parseUnsignedLong(line));
+                } catch (Exception ex) {
+                    throw new IllegalStateException("Input s2 cell file has invalid format, "
+                            + "current line=" + line);
+                }
             }
         }
         return s2Cells;
     }
 
     /**
+     * Convert the list of S2 Cell numbers into the list of S2 Cell IDs at the expected level.
+     */
+    private static List<S2CellId> denormalize(List<Long> s2CellNumbers, int s2Level) {
+        Set<S2CellId> result = new HashSet<>();
+        for (long s2CellNumber : s2CellNumbers) {
+            S2CellId s2CellId = new S2CellId(s2CellNumber);
+            if (s2CellId.level() == s2Level) {
+                if (!result.contains(s2CellId)) {
+                    result.add(s2CellId);
+                }
+            } else if (s2CellId.level() < s2Level) {
+                S2CellId childEnd = s2CellId.childEnd(s2Level);
+                for (s2CellId = s2CellId.childBegin(s2Level); !s2CellId.equals(childEnd);
+                        s2CellId = s2CellId.next()) {
+                    if (!result.contains(s2CellId)) {
+                        result.add(s2CellId);
+                    }
+                }
+            } else {
+                S2CellId parent = s2CellId.parent(s2Level);
+                if (!result.contains(parent)) {
+                    result.add(parent);
+                }
+            }
+        }
+        return new ArrayList(result);
+    }
+
+    /**
      * Compress the list of sorted S2CellId into S2 ranges.
      *
      * @param sortedS2CellIds List of S2CellId sorted in ascending order.
diff --git a/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2LocationLookup.java b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2LocationLookup.java
new file mode 100644
index 0000000..444ff8d
--- /dev/null
+++ b/utils/satellite/tools/src/main/java/com/android/telephony/tools/sats2/SatS2LocationLookup.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.tools.sats2;
+
+import com.android.telephony.sats2range.read.SatS2RangeFileReader;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.google.common.geometry.S2CellId;
+import com.google.common.geometry.S2LatLng;
+
+import java.io.File;
+
+/** A util class for checking if a location is in the input satellite S2 file. */
+public final class SatS2LocationLookup {
+    /**
+     *  A util method for checking if a location is in the input satellite S2 file.
+     */
+    public static void main(String[] args) throws Exception {
+        Arguments arguments = new Arguments();
+        JCommander.newBuilder()
+                .addObject(arguments)
+                .build()
+                .parse(args);
+
+        try (SatS2RangeFileReader satS2RangeFileReader =
+                     SatS2RangeFileReader.open(new File(arguments.inputFile))) {
+            S2CellId s2CellId = getS2CellId(arguments.latDegrees, arguments.lngDegrees,
+                    satS2RangeFileReader.getS2Level());
+            System.out.println("s2CellId=" + Long.toUnsignedString(s2CellId.id()));
+            if (satS2RangeFileReader.findEntryByCellId(s2CellId.id()) == null) {
+                System.out.println("The input file does not contain the input location");
+            } else {
+                System.out.println("The input file contains the input location");
+            }
+        }
+    }
+
+    private static S2CellId getS2CellId(double latDegrees, double lngDegrees, int s2Level) {
+        // Create the leaf S2 cell containing the given S2LatLng
+        S2CellId cellId = S2CellId.fromLatLng(S2LatLng.fromDegrees(latDegrees, lngDegrees));
+
+        // Return the S2 cell at the expected S2 level
+        return cellId.parent(s2Level);
+    }
+
+    private static class Arguments {
+        @Parameter(names = "--input-file",
+                description = "sat s2 file",
+                required = true)
+        public String inputFile;
+
+        @Parameter(names = "--lat-degrees",
+                description = "lat degress of the location",
+                required = true)
+        public double latDegrees;
+
+        @Parameter(names = "--lng-degrees",
+                description = "lng degress of the location",
+                required = true)
+        public double lngDegrees;
+    }
+}