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

Commit d3a6d5e8 authored by Lifu Tang's avatar Lifu Tang
Browse files

Update location app stats

- Count apps in both primary and work profiles
- Show the number of any location permitted app instead of background
  allowed apps on Location settings page
- Update the text at the top-level settings page

Bug: 129296799
Bug: 129358133
Bug: 129358508
Bug: 131432116
Test: build, flash, and test manually
Change-Id: I1a4284257a8a284140b81685efc98a2cc4a74619
parent c7564be5
Loading
Loading
Loading
Loading
+9 −13
Original line number Diff line number Diff line
@@ -842,8 +842,8 @@
    <string name="location_settings_summary_location_off">Off</string>
    <!-- Summary for Location settings when location is on, explaining how many apps have location permission [CHAR LIMIT=NONE]-->
    <plurals name="location_settings_summary_location_on">
        <item quantity="one">On - <xliff:g id="count">%1$d</xliff:g> app can access location</item>
        <item quantity="other">On - <xliff:g id="count">%1$d</xliff:g> apps can access location</item>
        <item quantity="one">On - <xliff:g id="count">%1$d</xliff:g> app has access to location</item>
        <item quantity="other">On - <xliff:g id="count">%1$d</xliff:g> apps have access to location</item>
    </plurals>
    <!-- Location settings, loading the number of apps which have location permission [CHAR LIMIT=30] -->
    <string name="location_settings_loading_app_permission_stats">Loading\u2026</string>
@@ -3838,29 +3838,25 @@
    <!-- Summary for app permission on Location settings page when location is off [CHAR LIMIT=NONE] -->
    <string name="location_app_permission_summary_location_off">Location is off</string>
    <!--
    Summary for Location settings when location is on, explaining how many apps have unlimited
    location permission.
    "Unlimited access" means the app can access the device location even when it's not being used
    (on background), while "limited" means the app can only access the device location when the user
    is using it (foreground only).
    Summary for Location settings when location is on, explaining how many apps have location
    permission.
    Please note that the distinction between singular and plural of this sentence only depends on
    the quantity of "background_location_app_count" ("has" vs "have"). The quantity of
    the quantity of "permitted_location_app_count" ("has" vs "have"). The quantity of
    "total_location_app_count" is almost always greater than 1, so "apps" is always in plural form.
    [CHAR LIMIT=NONE]-->
    <plurals name="location_app_permission_summary_location_on">
        <item quantity="one">
            <xliff:g id="background_location_app_count">%1$d</xliff:g>
            <xliff:g id="permitted_location_app_count">%1$d</xliff:g>
            of
            <xliff:g id="total_location_app_count">%2$d</xliff:g>
            apps has unlimited access</item>
            apps has access to location</item>
        <item quantity="other">
            <xliff:g id="background_location_app_count">%1$d</xliff:g>
            <xliff:g id="permitted_location_app_count">%1$d</xliff:g>
            of
            <xliff:g id="total_location_app_count">%2$d</xliff:g>
            apps have unlimited access</item>
            apps have access to location</item>
    </plurals>
    <!-- [CHAR LIMIT=50] Location settings screen, sub category for recent location access -->
    <string name="location_category_recent_location_access">Recent location access</string>
+60 −29
Original line number Diff line number Diff line
package com.android.settings.location;

import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;

import android.content.Context;
import android.location.LocationManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionControllerManager;
import android.provider.Settings;

@@ -13,11 +14,12 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class AppLocationPermissionPreferenceController extends
@@ -29,7 +31,12 @@ public class AppLocationPermissionPreferenceController extends
    int mNumTotal = -1;
    /** Total number of apps that has background location permission. */
    @VisibleForTesting
    int mNumBackground = -1;
    int mNumHasLocation = -1;

    final AtomicInteger loadingInProgress = new AtomicInteger(0);
    private int mNumTotalLoading = 0;
    private int mNumHasLocationLoading = 0;

    private final LocationManager mLocationManager;
    private Preference mPreference;

@@ -52,52 +59,76 @@ public class AppLocationPermissionPreferenceController extends
    @Override
    public CharSequence getSummary() {
        if (mLocationManager.isLocationEnabled()) {
            if (mNumTotal == -1 || mNumBackground == -1) {
            if (mNumTotal == -1 || mNumHasLocation == -1) {
                return mContext.getString(R.string.location_settings_loading_app_permission_stats);
            }
            return mContext.getResources().getQuantityString(
                    R.plurals.location_app_permission_summary_location_on, mNumBackground,
                    mNumBackground, mNumTotal);
                    R.plurals.location_app_permission_summary_location_on, mNumHasLocation,
                    mNumHasLocation, mNumTotal);
        } else {
            return mContext.getString(R.string.location_app_permission_summary_location_off);
        }
    }

    private void setAppCounts(int numTotal, int numHasLocation) {
        mNumTotal = numTotal;
        mNumHasLocation = numHasLocation;
        refreshSummary(mPreference);
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        mPreference = preference;
        final AtomicInteger loadingInProgress = new AtomicInteger(2);
        refreshSummary(preference);
        // Bail out if location has been disabled.
        if (!mLocationManager.isLocationEnabled()) {
        // Bail out if location has been disabled, or there's another loading request in progress.
        if (!mLocationManager.isLocationEnabled() ||
                loadingInProgress.get() != 0) {
            return;
        }
        PermissionControllerManager permController =
                mContext.getSystemService(PermissionControllerManager.class);
        mNumTotalLoading = 0;
        mNumHasLocationLoading = 0;
        // Retrieve a list of users inside the current user profile group.
        final List<UserHandle> users = mContext.getSystemService(
                UserManager.class).getUserProfiles();
        loadingInProgress.set(2 * users.size());
        for (UserHandle user : users) {
            final Context userContext = Utils.createPackageContextAsUser(mContext,
                    user.getIdentifier());
            if (userContext == null) {
                for (int i = 0; i < 2; ++i) {
                    if (loadingInProgress.decrementAndGet() == 0) {
                        setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
                    }
                }
                continue;
            }
            final PermissionControllerManager permController =
                    userContext.getSystemService(PermissionControllerManager.class);
            permController.countPermissionApps(
                    Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), 0,
                    (numApps) -> {
                    mNumTotal = numApps;
                        mNumTotalLoading += numApps;
                        if (loadingInProgress.decrementAndGet() == 0) {
                        refreshSummary(preference);
                            setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
                        }
                    }, null);

            permController.countPermissionApps(
                Collections.singletonList(ACCESS_BACKGROUND_LOCATION),
                    Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
                    PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED,
                    (numApps) -> {
                    mNumBackground = numApps;
                        mNumHasLocationLoading += numApps;
                        if (loadingInProgress.decrementAndGet() == 0) {
                        refreshSummary(preference);
                            setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
                        }
                    }, null);
        }
    }

    @Override
    public void onLocationModeChanged(int mode, boolean restricted) {
        // 'null' is checked inside updateState(), so no need to check here.
        if (mPreference != null) {
            updateState(mPreference);
        }
    }
}
+39 −10
Original line number Diff line number Diff line
@@ -8,18 +8,23 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.permission.PermissionControllerManager;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class TopLevelLocationPreferenceController extends BasePreferenceController implements
        LifecycleObserver, OnStart, OnStop {
@@ -28,8 +33,10 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll
    private final LocationManager mLocationManager;
    /** Total number of apps that has location permission. */
    private int mNumTotal = -1;
    private int mNumTotalLoading = 0;
    private BroadcastReceiver mReceiver;
    private Preference mPreference;
    private AtomicInteger loadingInProgress = new AtomicInteger(0);

    public TopLevelLocationPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
@@ -66,17 +73,38 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll
        super.updateState(preference);
        mPreference = preference;
        refreshSummary(preference);
        // Bail out if location has been disabled.
        if (!mLocationManager.isLocationEnabled()) {
        // Bail out if location has been disabled, or there's another loading request in progress.
        if (!mLocationManager.isLocationEnabled() ||
                loadingInProgress.get() != 0) {
            return;
        }
        mContext.getSystemService(PermissionControllerManager.class).countPermissionApps(
        mNumTotalLoading = 0;
        // Retrieve a list of users inside the current user profile group.
        final List<UserHandle> users = mContext.getSystemService(
                UserManager.class).getUserProfiles();
        loadingInProgress.set(users.size());
        for (UserHandle user : users) {
            final Context userContext = Utils.createPackageContextAsUser(mContext,
                    user.getIdentifier());
            if (userContext == null) {
                if (loadingInProgress.decrementAndGet() == 0) {
                    setLocationAppCount(mNumTotalLoading);
                }
                continue;
            }
            final PermissionControllerManager permController =
                    userContext.getSystemService(PermissionControllerManager.class);
            permController.countPermissionApps(
                    Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
                    PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED,
                    (numApps) -> {
                    setLocationAppCount(numApps);
                        mNumTotalLoading += numApps;
                        if (loadingInProgress.decrementAndGet() == 0) {
                            setLocationAppCount(mNumTotalLoading);
                        }
                    }, null);
        }
    }

    @Override
    public void onStart() {
@@ -98,7 +126,8 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll
    }

    private void refreshLocationMode() {
        // 'null' is checked inside updateState(), so no need to check here.
        if (mPreference != null) {
            updateState(mPreference);
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ public class AppLocationPermissionPreferenceControllerTest {
    @Test
    public void getSummary_whenLocationAppCountIsOne_shouldShowSingularString() {
        mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
        mController.mNumBackground = 1;
        mController.mNumHasLocation = 1;
        mController.mNumTotal = 1;

        assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getQuantityString(
@@ -86,7 +86,7 @@ public class AppLocationPermissionPreferenceControllerTest {
    @Test
    public void getSummary_whenLocationAppCountIsGreaterThanOne_shouldShowPluralString() {
        mLocationManager.setLocationEnabledForUser(true, android.os.Process.myUserHandle());
        mController.mNumBackground = 5;
        mController.mNumHasLocation = 5;
        mController.mNumTotal = 10;

        assertThat(mController.getSummary()).isEqualTo(mContext.getResources().getQuantityString(