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