Display app stats for location permission

Bug: 120221631
Test: manually
Change-Id: I53f43079807759c50eeb62029bb0d8d1f84e1118
This commit is contained in:
Lifu Tang
2018-12-11 13:50:34 -08:00
parent 811d95c373
commit 3da8f8d31d
8 changed files with 226 additions and 29 deletions

View File

@@ -1,18 +1,38 @@
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.permission.RuntimePermissionPresenter;
import android.provider.Settings;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicInteger;
public class AppLocationPermissionPreferenceController extends
AbstractPreferenceController implements PreferenceControllerMixin {
LocationBasePreferenceController implements PreferenceControllerMixin {
private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
/** Total number of apps that has location permission. */
private int mNumTotal = -1;
/** Total number of apps that has background location permission. */
private int mNumBackground = -1;
private final LocationManager mLocationManager;
private Preference mPreference;
public AppLocationPermissionPreferenceController(Context context) {
super(context);
public AppLocationPermissionPreferenceController(Context context, Lifecycle lifecycle) {
super(context, lifecycle);
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
@Override
@@ -25,4 +45,53 @@ public class AppLocationPermissionPreferenceController extends
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, 1) == 1;
}
@Override
public CharSequence getSummary() {
if (mLocationManager.isLocationEnabled()) {
if (mNumTotal == -1 || mNumBackground == -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);
} else {
return mContext.getString(R.string.location_app_permission_summary_location_off);
}
}
@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()) {
return;
}
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
(numApps) -> {
mNumTotal = numApps;
if (loadingInProgress.decrementAndGet() == 0) {
refreshSummary(preference);
}
}, null);
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
Collections.singletonList(ACCESS_BACKGROUND_LOCATION), true, false,
(numApps) -> {
mNumBackground = numApps;
if (loadingInProgress.decrementAndGet() == 0) {
refreshSummary(preference);
}
}, null);
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
// 'null' is checked inside updateState(), so no need to check here.
updateState(mPreference);
}
}

View File

@@ -35,15 +35,15 @@ import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
/**
* A class that listens to location settings change and modifies location settings
* settings.
*/
public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
public class LocationEnabler implements LifecycleObserver, OnStart, OnStop {
private static final String TAG = "LocationEnabler";
@VisibleForTesting
@@ -73,7 +73,7 @@ public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
}
@Override
public void onResume() {
public void onStart() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
@Override
@@ -90,12 +90,8 @@ public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
}
@Override
public void onPause() {
try {
mContext.unregisterReceiver(mReceiver);
} catch (RuntimeException e) {
// Ignore exceptions caused by race condition
}
public void onStop() {
mContext.unregisterReceiver(mReceiver);
}
void refreshLocationMode() {

View File

@@ -122,7 +122,7 @@ public class LocationSettings extends DashboardFragment {
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, LocationSettings fragment, Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new AppLocationPermissionPreferenceController(context));
controllers.add(new AppLocationPermissionPreferenceController(context, lifecycle));
controllers.add(new LocationForWorkPreferenceController(context, lifecycle));
controllers.add(new RecentLocationAccessPreferenceController(context));
controllers.add(new LocationScanningPreferenceController(context));

View File

@@ -0,0 +1,99 @@
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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.permission.RuntimePermissionPresenter;
import androidx.preference.Preference;
import com.android.settings.R;
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.Collections;
public class TopLevelLocationPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop {
private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
private final LocationManager mLocationManager;
/** Total number of apps that has location permission. */
private int mNumTotal = -1;
private BroadcastReceiver mReceiver;
private Preference mPreference;
public TopLevelLocationPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public CharSequence getSummary() {
if (mLocationManager.isLocationEnabled()) {
if (mNumTotal == -1) {
return mContext.getString(R.string.location_settings_loading_app_permission_stats);
}
return mContext.getResources().getQuantityString(
R.plurals.location_settings_summary_location_on,
mNumTotal, mNumTotal);
} else {
return mContext.getString(R.string.location_settings_summary_location_off);
}
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
mPreference = preference;
refreshSummary(preference);
// Bail out if location has been disabled.
if (!mLocationManager.isLocationEnabled()) {
return;
}
RuntimePermissionPresenter.getInstance(mContext).countPermissionApps(
Arrays.asList(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), false, false,
(numApps) -> {
mNumTotal = numApps;
refreshSummary(preference);
}, null);
}
@Override
public void onStart() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
refreshLocationMode();
}
};
}
mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
refreshLocationMode();
}
@Override
public void onStop() {
mContext.unregisterReceiver(mReceiver);
}
private void refreshLocationMode() {
// 'null' is checked inside updateState(), so no need to check here.
updateState(mPreference);
}
}