Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 639fc5cc authored by Ludovic Barman's avatar Ludovic Barman
Browse files

BugFix: Density-based coarsening: Set the accuracy to the approximate edge of the S2 cell.

Currently the accuracy of coarsened locations is set to the size of the grid. With the new algorithm, the coarsening will depend on the population density. The accuracy (which is a proxy for the size of the blue disc in maps apps) should scale with the size of the coarsened region.

Because the S2 cell library does not have a function to calculate the edge length, we use the average area to estimate the edge. This approximation assumes that all S2 cells are squares.

Tests:
- atest FrameworksMockingServicesTests:LocationFudgerTest

Change-Id: If172fff9cf1d74b4f86f0e9832d946b35d468362
Test: manual atest on Pixel 7 pro (see above)
Bug: 376198890
Flag: android.location.flags.density_based_coarse_locations
parent d4815549
Loading
Loading
Loading
Loading
+27 −1
Original line number Diff line number Diff line
@@ -68,6 +68,17 @@ public class LocationFudger {
    private static final double MAX_LATITUDE =
            90.0 - (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR);

    // The average edge length in km of an S2 cell, indexed by S2 levels 0 to
    // 13. Level 13 is the highest level used for coarsening.
    // This approximation assumes the S2 cells are squares.
    // For density-based coarsening, we use the edge to set the accuracy of the
    // coarsened location.
    // The values are from http://s2geometry.io/resources/s2cell_statistics.html
    // We take square root of the average area.
    private static final float[] S2_CELL_AVG_EDGE_PER_LEVEL = new float[] {
            9220.14f, 4610.07f, 2305.04f, 1152.52f, 576.26f, 288.13f, 144.06f,
            72.03f, 36.02f, 20.79f, 9f, 5.05f, 2.25f, 1.13f, 0.57f};

    private final float mAccuracyM;
    private final Clock mClock;
    private final Random mRandom;
@@ -194,12 +205,14 @@ public class LocationFudger {
        // The new algorithm is applied if and only if (1) the flag is on, (2) the cache has been
        // set, and (3) the cache has successfully queried the provider for the default coarsening
        // value.
        float accuracy = mAccuracyM;
        if (Flags.populationDensityProvider() && Flags.densityBasedCoarseLocations()
                && cacheCopy != null) {
            if (cacheCopy.hasDefaultValue()) {
                // New algorithm that snaps to the center of a S2 cell.
                int level = cacheCopy.getCoarseningLevel(latitude, longitude);
                coarsened = snapToCenterOfS2Cell(latitude, longitude, level);
                accuracy = getS2CellApproximateEdge(level);
            } else {
                // Try to fetch the default value. The answer won't come in time, but will be used
                // for the next location to coarsen.
@@ -214,7 +227,7 @@ public class LocationFudger {

        coarse.setLatitude(coarsened[LAT_INDEX]);
        coarse.setLongitude(coarsened[LNG_INDEX]);
        coarse.setAccuracy(Math.max(mAccuracyM, coarse.getAccuracy()));
        coarse.setAccuracy(Math.max(accuracy, coarse.getAccuracy()));

        synchronized (this) {
            mCachedFineLocation = fine;
@@ -224,6 +237,19 @@ public class LocationFudger {
        return coarse;
    }

    // Returns the average edge length in meters of an S2 cell at the given
    // level. This is computed as if the S2 cell were a square. We do not need
    // an exact value, only a rough approximation.
    @VisibleForTesting
    protected float getS2CellApproximateEdge(int level) {
        if (level < 0) {
            level = 0;
        } else if (level >= S2_CELL_AVG_EDGE_PER_LEVEL.length) {
            level = S2_CELL_AVG_EDGE_PER_LEVEL.length - 1;
        }
        return S2_CELL_AVG_EDGE_PER_LEVEL[level] * 1000;
    }

    // quantize location by snapping to a grid. this is the primary means of obfuscation. it
    // gives nice consistent results and is very effective at hiding the true location (as
    // long as you are not sitting on a grid boundary, which the random offsets mitigate).
+27 −0
Original line number Diff line number Diff line
@@ -271,4 +271,31 @@ public class LocationFudgerTest {
        assertThat(center[0]).isEqualTo(expected[0]);
        assertThat(center[1]).isEqualTo(expected[1]);
    }

    @Test
    public void getS2CellApproximateEdge_returnsCorrectRadius() {
        int level = 10;

        float radius = mFudger.getS2CellApproximateEdge(level);

        assertThat(radius).isEqualTo(9000);  // in meters
    }

    @Test
    public void getS2CellApproximateEdge_doesNotThrow() {
        int level = -1;

        mFudger.getS2CellApproximateEdge(level);

        // No exception thrown.
    }

    @Test
    public void getS2CellApproximateEdge_doesNotThrow2() {
        int level = 14;

        mFudger.getS2CellApproximateEdge(level);

        // No exception thrown.
    }
}