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.BroadcastReceiver; 7 import android.content.Context; 8 import android.content.Intent; 9 import android.content.IntentFilter; 10 import android.location.LocationManager; 11 import android.os.UserHandle; 12 import android.os.UserManager; 13 import android.permission.PermissionControllerManager; 14 15 import androidx.annotation.VisibleForTesting; 16 import androidx.preference.Preference; 17 18 import com.android.settings.R; 19 import com.android.settings.Utils; 20 import com.android.settings.core.BasePreferenceController; 21 import com.android.settingslib.core.lifecycle.LifecycleObserver; 22 import com.android.settingslib.core.lifecycle.events.OnStart; 23 import com.android.settingslib.core.lifecycle.events.OnStop; 24 25 import java.util.Arrays; 26 import java.util.List; 27 import java.util.concurrent.atomic.AtomicInteger; 28 29 public class TopLevelLocationPreferenceController extends BasePreferenceController implements 30 LifecycleObserver, OnStart, OnStop { 31 private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = 32 new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 33 private final LocationManager mLocationManager; 34 /** Total number of apps that has location permission. */ 35 private int mNumTotal = -1; 36 private int mNumTotalLoading = 0; 37 private BroadcastReceiver mReceiver; 38 private Preference mPreference; 39 private AtomicInteger loadingInProgress = new AtomicInteger(0); 40 TopLevelLocationPreferenceController(Context context, String preferenceKey)41 public TopLevelLocationPreferenceController(Context context, String preferenceKey) { 42 super(context, preferenceKey); 43 mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 44 } 45 46 @Override getAvailabilityStatus()47 public int getAvailabilityStatus() { 48 return AVAILABLE; 49 } 50 51 @Override getSummary()52 public CharSequence getSummary() { 53 if (mLocationManager.isLocationEnabled()) { 54 if (mNumTotal == -1) { 55 return mContext.getString(R.string.location_settings_loading_app_permission_stats); 56 } 57 return mContext.getResources().getQuantityString( 58 R.plurals.location_settings_summary_location_on, 59 mNumTotal, mNumTotal); 60 } else { 61 return mContext.getString(R.string.location_settings_summary_location_off); 62 } 63 } 64 65 @VisibleForTesting setLocationAppCount(int numApps)66 void setLocationAppCount(int numApps) { 67 mNumTotal = numApps; 68 refreshSummary(mPreference); 69 } 70 71 @Override updateState(Preference preference)72 public void updateState(Preference preference) { 73 super.updateState(preference); 74 mPreference = preference; 75 refreshSummary(preference); 76 // Bail out if location has been disabled, or there's another loading request in progress. 77 if (!mLocationManager.isLocationEnabled() || 78 loadingInProgress.get() != 0) { 79 return; 80 } 81 mNumTotalLoading = 0; 82 // Retrieve a list of users inside the current user profile group. 83 final List<UserHandle> users = mContext.getSystemService( 84 UserManager.class).getUserProfiles(); 85 loadingInProgress.set(users.size()); 86 for (UserHandle user : users) { 87 final Context userContext = Utils.createPackageContextAsUser(mContext, 88 user.getIdentifier()); 89 if (userContext == null) { 90 if (loadingInProgress.decrementAndGet() == 0) { 91 setLocationAppCount(mNumTotalLoading); 92 } 93 continue; 94 } 95 final PermissionControllerManager permController = 96 userContext.getSystemService(PermissionControllerManager.class); 97 permController.countPermissionApps( 98 Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), 99 PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED, 100 (numApps) -> { 101 mNumTotalLoading += numApps; 102 if (loadingInProgress.decrementAndGet() == 0) { 103 setLocationAppCount(mNumTotalLoading); 104 } 105 }, null); 106 } 107 } 108 109 @Override onStart()110 public void onStart() { 111 if (mReceiver == null) { 112 mReceiver = new BroadcastReceiver() { 113 @Override 114 public void onReceive(Context context, Intent intent) { 115 refreshLocationMode(); 116 } 117 }; 118 } 119 mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED); 120 refreshLocationMode(); 121 } 122 123 @Override onStop()124 public void onStop() { 125 mContext.unregisterReceiver(mReceiver); 126 } 127 refreshLocationMode()128 private void refreshLocationMode() { 129 if (mPreference != null) { 130 updateState(mPreference); 131 } 132 } 133 } 134