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