Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 965c73d4 authored by Joel Galenson's avatar Joel Galenson
Browse files

Add the bar chart back to Permissions Hub.

This uses the new design, which changes the bar labels.

We also apply a tiebreak scheme for the bars so that we can be
consistent with Settings.

Test: View bar chart and click entries.
Change-Id: Iec0e77611026cabe89c813c9b1f1c302e12e8fcd
parent 0eab37f2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES += \
    SettingsLibAppPreference \
    SettingsLibSearchWidget \
    SettingsLibLayoutPreference \
    SettingsLibBarChartPreference \
    SettingsLibActionBarShadow \
    SettingsLibProgressBar

+3 −3
Original line number Diff line number Diff line
@@ -329,9 +329,9 @@
    <string name="permission_usage_bar_chart_title_last_minute">Permission usage in last 1 minute</string>

    <!-- Label for the bars on the chart that shows how many apps have used various permissions [CHAR LIMIT=10] -->
    <plurals name="app_permission_usage_bar_label">
        <item quantity="one">Used by:\n1 app</item>
        <item quantity="other">Used by:\n<xliff:g id="number" example="7">%s</xliff:g> apps</item>
    <plurals name="permission_usage_bar_label">
        <item quantity="one">1 app</item>
        <item quantity="other"><xliff:g id="number" example="7">%s</xliff:g> apps</item>
    </plurals>

    <!-- Label for the button to bring the user to view the details of recent permission accesses [CHAR LIMIT=42] -->
+111 −7
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.packageinstaller.permission.ui.handheld;

import static android.Manifest.permission_group.CAMERA;
import static android.Manifest.permission_group.LOCATION;
import static android.Manifest.permission_group.MICROPHONE;

import static java.lang.annotation.RetentionPolicy.SOURCE;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
@@ -26,6 +30,7 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -58,6 +63,9 @@ import com.android.packageinstaller.permission.utils.Utils;
import com.android.permissioncontroller.R;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.widget.ActionBarShadowController;
import com.android.settingslib.widget.BarChartInfo;
import com.android.settingslib.widget.BarChartPreference;
import com.android.settingslib.widget.BarViewInfo;

import java.lang.annotation.Retention;
import java.text.Collator;
@@ -105,6 +113,11 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements
    private static final String FINISHED_INITIAL_LOAD_KEY = PermissionUsageFragment.class.getName()
            + KEY_FINISHED_INITIAL_LOAD;

    /**
     * The maximum number of columns shown in the bar chart.
     */
    private static final int MAXIMUM_NUM_BARS = 4;

    private @NonNull PermissionUsages mPermissionUsages;

    private Collator mCollator;
@@ -199,22 +212,28 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements
        mFilterTimes = new ArrayList<>();
        mFilterTimes.add(new TimeFilterItem(Long.MAX_VALUE,
                context.getString(R.string.permission_usage_any_time),
                R.string.permission_usage_list_title_any_time));
                R.string.permission_usage_list_title_any_time,
                R.string.permission_usage_bar_chart_title_any_time));
        mFilterTimes.add(new TimeFilterItem(DAYS.toMillis(7),
                context.getString(R.string.permission_usage_last_7_days),
                R.string.permission_usage_list_title_last_7_days));
                R.string.permission_usage_list_title_last_7_days,
                R.string.permission_usage_bar_chart_title_last_7_days));
        mFilterTimes.add(new TimeFilterItem(DAYS.toMillis(1),
                context.getString(R.string.permission_usage_last_day),
                R.string.permission_usage_list_title_last_day));
                R.string.permission_usage_list_title_last_day,
                R.string.permission_usage_bar_chart_title_last_day));
        mFilterTimes.add(new TimeFilterItem(HOURS.toMillis(1),
                context.getString(R.string.permission_usage_last_hour),
                R.string.permission_usage_list_title_last_hour));
                R.string.permission_usage_list_title_last_hour,
                R.string.permission_usage_bar_chart_title_last_hour));
        mFilterTimes.add(new TimeFilterItem(MINUTES.toMillis(15),
                context.getString(R.string.permission_usage_last_15_minutes),
                R.string.permission_usage_list_title_last_15_minutes));
                R.string.permission_usage_list_title_last_15_minutes,
                R.string.permission_usage_bar_chart_title_last_15_minutes));
        mFilterTimes.add(new TimeFilterItem(MINUTES.toMillis(1),
                context.getString(R.string.permission_usage_last_minute),
                R.string.permission_usage_list_title_last_minute));
                R.string.permission_usage_list_title_last_minute,
                R.string.permission_usage_bar_chart_title_last_minute));

        long numMillis = getArguments().getLong(Intent.EXTRA_DURATION_MILLIS);
        long supremum = Long.MAX_VALUE;
@@ -397,6 +416,7 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements

        // Update header.
        if (mFilterGroup == null) {
            screen.addPreference(createBarChart(usages, timeFilterItem, context));
            hideHeader();
        } else {
            AppPermissionGroup group = getGroup(mFilterGroup);
@@ -517,6 +537,83 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements
            setProgressBarVisible(true);
        }
    }
    /**
     * Create a bar chart showing the permissions that are used by the most apps.
     *
     * @param usages the usages
     * @param timeFilterItem the time filter, or null if no filter is set
     * @param context the context
     *
     * @return the Preference representing the bar chart
     */
    private BarChartPreference createBarChart(
            @NonNull List<Pair<AppPermissionUsage, GroupUsage>> usages,
            @Nullable TimeFilterItem timeFilterItem, @NonNull Context context) {
        ArrayList<AppPermissionGroup> groups = new ArrayList<>();
        ArrayMap<String, Integer> groupToAppCount = new ArrayMap<>();
        int usageCount = usages.size();
        for (int i = 0; i < usageCount; i++) {
            Pair<AppPermissionUsage, GroupUsage> usage = usages.get(i);
            GroupUsage groupUsage = usage.second;
            Integer count = groupToAppCount.get(groupUsage.getGroup().getName());
            if (count == null) {
                groups.add(groupUsage.getGroup());
                groupToAppCount.put(groupUsage.getGroup().getName(), 1);
            } else {
                groupToAppCount.put(groupUsage.getGroup().getName(), count + 1);
            }
        }

        groups.sort((x, y) -> {
            String xName = x.getName();
            String yName = y.getName();
            int usageDiff = compareLong(groupToAppCount.get(xName), groupToAppCount.get(yName));
            if (usageDiff != 0) {
                return usageDiff;
            }
            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());
        });

        BarChartInfo.Builder builder = new BarChartInfo.Builder();
        if (timeFilterItem != null) {
            builder.setTitle(timeFilterItem.getGraphTitleRes());
        }

        int numBarsToShow = Math.min(groups.size(), MAXIMUM_NUM_BARS);
        for (int i = 0; i < numBarsToShow; i++) {
            AppPermissionGroup group = groups.get(i);
            int count = groupToAppCount.get(group.getName());
            Drawable icon = Utils.applyTint(context,
                    Utils.loadDrawable(context.getPackageManager(), group.getIconPkg(),
                            group.getIconResId()), android.R.attr.colorControlNormal);
            BarViewInfo barViewInfo = new BarViewInfo(icon, count, group.getLabel(),
                    context.getResources().getQuantityString(R.plurals.permission_usage_bar_label,
                            count, count), group.getLabel());
            barViewInfo.setClickListener(v -> {
                mFilterGroup = group.getName();
                // We already loaded all data, so don't reload
                updateUI();
            });
            builder.addBarViewInfo(barViewInfo);
        }

        BarChartPreference barChart = new BarChartPreference(context, null);
        barChart.initializeBarChart(builder.build());
        return barChart;
    }

    /**
     * Create an expandable preference group that can hold children.
@@ -916,11 +1013,14 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements
        private final long mTime;
        private final @NonNull String mLabel;
        private final @StringRes int mListTitleRes;
        private final @StringRes int mGraphTitleRes;

        TimeFilterItem(long time, @NonNull String label, @StringRes int listTitleRes) {
        TimeFilterItem(long time, @NonNull String label, @StringRes int listTitleRes,
                @StringRes int graphTitleRes) {
            mTime = time;
            mLabel = label;
            mListTitleRes = listTitleRes;
            mGraphTitleRes = graphTitleRes;
        }

        /**
@@ -939,5 +1039,9 @@ public class PermissionUsageFragment extends SettingsWithLargeHeader implements
        public @StringRes int getListTitleRes() {
            return mListTitleRes;
        }

        public @StringRes int getGraphTitleRes() {
            return mGraphTitleRes;
        }
    }
}