1 package com.android.settings.location;
2 
3 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
4 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
5 
6 import android.content.Context;
7 import android.location.LocationManager;
8 import android.os.UserHandle;
9 import android.os.UserManager;
10 import android.permission.PermissionControllerManager;
11 import android.provider.Settings;
12 
13 import androidx.annotation.VisibleForTesting;
14 import androidx.preference.Preference;
15 
16 import com.android.settings.R;
17 import com.android.settings.Utils;
18 import com.android.settings.core.PreferenceControllerMixin;
19 
20 import java.util.Arrays;
21 import java.util.List;
22 import java.util.concurrent.atomic.AtomicInteger;
23 
24 public class AppLocationPermissionPreferenceController extends
25         LocationBasePreferenceController implements PreferenceControllerMixin {
26 
27     /** Total number of apps that has location permission. */
28     @VisibleForTesting
29     int mNumTotal = -1;
30     /** Total number of apps that has background location permission. */
31     @VisibleForTesting
32     int mNumHasLocation = -1;
33 
34     final AtomicInteger loadingInProgress = new AtomicInteger(0);
35     private int mNumTotalLoading = 0;
36     private int mNumHasLocationLoading = 0;
37 
38     private final LocationManager mLocationManager;
39     private Preference mPreference;
40 
AppLocationPermissionPreferenceController(Context context, String key)41     public AppLocationPermissionPreferenceController(Context context, String key) {
42         super(context, key);
43         mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
44     }
45 
46     @Override
getAvailabilityStatus()47     public int getAvailabilityStatus() {
48         return Settings.Global.getInt(mContext.getContentResolver(),
49                 Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, 1) == 1 ? AVAILABLE
50                 : UNSUPPORTED_ON_DEVICE;
51     }
52 
53     @Override
getSummary()54     public CharSequence getSummary() {
55         if (mLocationManager.isLocationEnabled()) {
56             if (mNumTotal == -1 || mNumHasLocation == -1) {
57                 return mContext.getString(R.string.location_settings_loading_app_permission_stats);
58             }
59             return mContext.getResources().getQuantityString(
60                     R.plurals.location_app_permission_summary_location_on, mNumHasLocation,
61                     mNumHasLocation, mNumTotal);
62         } else {
63             return mContext.getString(R.string.location_app_permission_summary_location_off);
64         }
65     }
66 
setAppCounts(int numTotal, int numHasLocation)67     private void setAppCounts(int numTotal, int numHasLocation) {
68         mNumTotal = numTotal;
69         mNumHasLocation = numHasLocation;
70         refreshSummary(mPreference);
71     }
72 
73     @Override
updateState(Preference preference)74     public void updateState(Preference preference) {
75         super.updateState(preference);
76         mPreference = preference;
77         refreshSummary(preference);
78         // Bail out if location has been disabled, or there's another loading request in progress.
79         if (!mLocationManager.isLocationEnabled() ||
80                 loadingInProgress.get() != 0) {
81             return;
82         }
83         mNumTotalLoading = 0;
84         mNumHasLocationLoading = 0;
85         // Retrieve a list of users inside the current user profile group.
86         final List<UserHandle> users = mContext.getSystemService(
87                 UserManager.class).getUserProfiles();
88         loadingInProgress.set(2 * users.size());
89         for (UserHandle user : users) {
90             final Context userContext = Utils.createPackageContextAsUser(mContext,
91                     user.getIdentifier());
92             if (userContext == null) {
93                 for (int i = 0; i < 2; ++i) {
94                     if (loadingInProgress.decrementAndGet() == 0) {
95                         setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
96                     }
97                 }
98                 continue;
99             }
100             final PermissionControllerManager permController =
101                     userContext.getSystemService(PermissionControllerManager.class);
102             permController.countPermissionApps(
103                     Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), 0,
104                     (numApps) -> {
105                         mNumTotalLoading += numApps;
106                         if (loadingInProgress.decrementAndGet() == 0) {
107                             setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
108                         }
109                     }, null);
110             permController.countPermissionApps(
111                     Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
112                     PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED,
113                     (numApps) -> {
114                         mNumHasLocationLoading += numApps;
115                         if (loadingInProgress.decrementAndGet() == 0) {
116                             setAppCounts(mNumTotalLoading, mNumHasLocationLoading);
117                         }
118                     }, null);
119         }
120     }
121 
122     @Override
onLocationModeChanged(int mode, boolean restricted)123     public void onLocationModeChanged(int mode, boolean restricted) {
124         if (mPreference != null) {
125             updateState(mPreference);
126         }
127     }
128 }
129