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
247 lines
9.5 KiB
Java
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;
|
|
}
|
|
}
|