Files
packages_apps_Settings/src/com/android/settings/privacy/PermissionBarChartPreferenceController.java
Joel Galenson 2102faf3e3 Do not special case the storage permission group.
We are now not showing storage usages in Permission Controller,
including in the API Settings uses.  We can thus remove this code so
that Settings will reflect what Permissions Hub shows.

Bug: 130567526
Test: See the same graph here and in the dashboard.
Change-Id: Iaa7d95b05f4321543ed42833ac3a7babdb9914f0
2019-04-16 15:44:52 -07:00

247 lines
9.5 KiB
Java

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.privacy;
import static android.Manifest.permission_group.CAMERA;
import static android.Manifest.permission_group.LOCATION;
import static android.Manifest.permission_group.MICROPHONE;
import static java.util.concurrent.TimeUnit.DAYS;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.permission.PermissionControllerManager;
import android.permission.RuntimePermissionUsageInfo;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.widget.BarChartInfo;
import com.android.settingslib.widget.BarChartPreference;
import com.android.settingslib.widget.BarViewInfo;
import java.util.ArrayList;
import java.util.List;
public class PermissionBarChartPreferenceController extends BasePreferenceController implements
PermissionControllerManager.OnPermissionUsageResultCallback, LifecycleObserver, OnCreate,
OnStart, OnSaveInstanceState {
private static final String TAG = "BarChartPreferenceCtl";
private static final String KEY_PERMISSION_USAGE = "usage_infos";
@VisibleForTesting
List<RuntimePermissionUsageInfo> mOldUsageInfos;
private PackageManager mPackageManager;
private PrivacyDashboardFragment mParent;
private BarChartPreference mBarChartPreference;
public PermissionBarChartPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mOldUsageInfos = new ArrayList<>();
mPackageManager = context.getPackageManager();
}
public void setFragment(PrivacyDashboardFragment fragment) {
mParent = fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mOldUsageInfos = savedInstanceState.getParcelableArrayList(KEY_PERMISSION_USAGE);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelableList(KEY_PERMISSION_USAGE, mOldUsageInfos);
}
@Override
public int getAvailabilityStatus() {
return Boolean.parseBoolean(
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PRIVACY,
com.android.settings.Utils.PROPERTY_PERMISSIONS_HUB_ENABLED)) ?
AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mBarChartPreference = screen.findPreference(getPreferenceKey());
final BarChartInfo info = new BarChartInfo.Builder()
.setTitle(R.string.permission_bar_chart_title)
.setDetails(R.string.permission_bar_chart_details)
.setEmptyText(R.string.permission_bar_chart_empty_text)
.setDetailsOnClickListener((View v) -> {
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
mContext.startActivity(intent);
})
.build();
mBarChartPreference.initializeBarChart(info);
if (!mOldUsageInfos.isEmpty()) {
mBarChartPreference.setBarViewInfos(createBarViews(mOldUsageInfos));
}
}
@Override
public void onStart() {
if (!isAvailable()) {
return;
}
// We don't hide chart when we have existing data.
mBarChartPreference.updateLoadingState(mOldUsageInfos.isEmpty() /* isLoading */);
// But we still need to hint user with progress bar that we are updating new usage data.
mParent.setLoadingEnabled(true /* enabled */);
retrievePermissionUsageData();
}
@Override
public void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> usageInfos) {
usageInfos.sort((x, y) -> {
int usageDiff = y.getAppAccessCount() - x.getAppAccessCount();
if (usageDiff != 0) {
return usageDiff;
}
String xName = x.getName();
String yName = y.getName();
if (xName.equals(LOCATION)) {
return -1;
} else if (yName.equals(LOCATION)) {
return 1;
} else if (xName.equals(MICROPHONE)) {
return -1;
} else if (yName.equals(MICROPHONE)) {
return 1;
} else if (xName.equals(CAMERA)) {
return -1;
} else if (yName.equals(CAMERA)) {
return 1;
}
return x.getName().compareTo(y.getName());
});
// If the result is different, we need to update bar views.
if (!areSamePermissionGroups(usageInfos)) {
mBarChartPreference.setBarViewInfos(createBarViews(usageInfos));
mOldUsageInfos = usageInfos;
}
mBarChartPreference.updateLoadingState(false /* isLoading */);
mParent.setLoadingEnabled(false /* enabled */);
}
private void retrievePermissionUsageData() {
mContext.getSystemService(PermissionControllerManager.class).getPermissionUsages(
false /* countSystem */, (int) DAYS.toMillis(1),
mContext.getMainExecutor() /* executor */, this /* callback */);
}
private BarViewInfo[] createBarViews(List<RuntimePermissionUsageInfo> usageInfos) {
if (usageInfos.isEmpty()) {
return null;
}
final BarViewInfo[] barViewInfos = new BarViewInfo[
Math.min(BarChartPreference.MAXIMUM_BAR_VIEWS, usageInfos.size())];
for (int index = 0; index < barViewInfos.length; index++) {
final RuntimePermissionUsageInfo permissionGroupInfo = usageInfos.get(index);
final int count = permissionGroupInfo.getAppAccessCount();
final CharSequence permLabel = getPermissionGroupLabel(permissionGroupInfo.getName());
barViewInfos[index] = new BarViewInfo(
getPermissionGroupIcon(permissionGroupInfo.getName()), count, permLabel,
mContext.getResources().getQuantityString(R.plurals.permission_bar_chart_label,
count, count), permLabel);
// Set the click listener for each bar view.
// The listener will navigate user to permission usage app.
barViewInfos[index].setClickListener((View v) -> {
final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE);
intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, permissionGroupInfo.getName());
intent.putExtra(Intent.EXTRA_DURATION_MILLIS, DAYS.toMillis(1));
mContext.startActivity(intent);
});
}
return barViewInfos;
}
private Drawable getPermissionGroupIcon(String permissionGroup) {
Drawable icon = null;
try {
icon = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
.loadIcon(mPackageManager);
icon.setTintList(Utils.getColorAttr(mContext, android.R.attr.textColorSecondary));
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Cannot find group icon for " + permissionGroup, e);
}
return icon;
}
private CharSequence getPermissionGroupLabel(String permissionGroup) {
CharSequence label = null;
try {
label = mPackageManager.getPermissionGroupInfo(permissionGroup, 0)
.loadLabel(mPackageManager);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Cannot find group label for " + permissionGroup, e);
}
return label;
}
private boolean areSamePermissionGroups(List<RuntimePermissionUsageInfo> newUsageInfos) {
if (newUsageInfos.size() != mOldUsageInfos.size()) {
return false;
}
for (int index = 0; index < newUsageInfos.size(); index++) {
final RuntimePermissionUsageInfo newInfo = newUsageInfos.get(index);
final RuntimePermissionUsageInfo oldInfo = mOldUsageInfos.get(index);
if (!newInfo.getName().equals(oldInfo.getName()) ||
newInfo.getAppAccessCount() != oldInfo.getAppAccessCount()) {
return false;
}
}
return true;
}
}