Loading src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java +12 −3 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ImageView; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup; Loading @@ -41,13 +42,12 @@ public class ExpandablePreferenceGroup extends PreferenceGroup { private @NonNull List<Integer> mSummaryIcons; private @NonNull List<Integer> mSummaryIcons; private boolean mExpanded; private boolean mExpanded; public ExpandablePreferenceGroup(@NonNull Context context, public ExpandablePreferenceGroup(@NonNull Context context) { @NonNull List<Integer> summaryIcons) { super(context, null); super(context, null); mContext = context; mContext = context; mPreferences = new ArrayList<>(); mPreferences = new ArrayList<>(); mSummaryIcons = summaryIcons; mSummaryIcons = new ArrayList<>(); mExpanded = false; mExpanded = false; setLayoutResource(R.layout.preference_usage); setLayoutResource(R.layout.preference_usage); Loading Loading @@ -111,4 +111,13 @@ public class ExpandablePreferenceGroup extends PreferenceGroup { mPreferences.add(preference); mPreferences.add(preference); return true; return true; } } /** * Show the given icon next to this preference's summary. * * @param resId the the resourceId of the drawable to use as the icon. */ public void addSummaryIcon(@DrawableRes int resId) { mSummaryIcons.add(resId); } } } src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java +110 −203 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.LayoutInflater; import android.view.Menu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuInflater; Loading @@ -48,7 +49,6 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StringRes; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen; import com.android.packageinstaller.permission.model.AppPermissionGroup; import com.android.packageinstaller.permission.model.AppPermissionGroup; Loading Loading @@ -357,13 +357,45 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } screen.removeAll(); screen.removeAll(); // Update bar chart mHasSystemApps = false; List<Pair<AppPermissionUsage, GroupUsage>> usages = new ArrayList<>(); int numApps = appPermissionUsages.size(); for (int appNum = 0; appNum < numApps; appNum++) { AppPermissionUsage appUsage = appPermissionUsages.get(appNum); List<GroupUsage> appGroups = appUsage.getGroupUsages(); int numGroups = appGroups.size(); for (int groupNum = 0; groupNum < numGroups; groupNum++) { GroupUsage groupUsage = appGroups.get(groupNum); if (groupUsage.getAccessCount() <= 0) { continue; } final boolean isSystemApp = Utils.isSystem(appUsage.getApp(), mLauncherPkgs); if (!mHasSystemApps) { if (isSystemApp) { mHasSystemApps = true; getActivity().invalidateOptionsMenu(); } } if (isSystemApp && !mShowSystem) { continue; } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } usages.add(Pair.create(appUsage, appGroups.get(groupNum))); } } // Update bar chart. final TimeFilterItem timeFilterItem = getSelectedFilterItem(); final TimeFilterItem timeFilterItem = getSelectedFilterItem(); final BarChartPreference barChart = createBarChart(appPermissionUsages, final BarChartPreference barChart = createBarChart(usages, timeFilterItem, context); timeFilterItem, context); screen.addPreference(barChart); screen.addPreference(barChart); // Add the preferences. // Add the preference header. PreferenceCategory category = new PreferenceCategory(context); PreferenceCategory category = new PreferenceCategory(context); screen.addPreference(category); screen.addPreference(category); if (timeFilterItem != null) { if (timeFilterItem != null) { Loading @@ -372,63 +404,32 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements // Sort the apps. // Sort the apps. final int sortOption = getSelectedSortOption(); final int sortOption = getSelectedSortOption(); if (sortOption == SORT_MOST_PERMISSIONS) { if (sortOption == SORT_RECENT) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessUsage); usages.sort(PermissionUsageFragment::compareAccessRecency); } else if (sortOption == SORT_MOST_PERMISSIONS) { usages.sort(PermissionUsageFragment::compareAccessUsage); } else if (sortOption == SORT_MOST_ACCESSES) { } else if (sortOption == SORT_MOST_ACCESSES) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessCount); usages.sort(PermissionUsageFragment::compareAccessCount); } else if (sortOption == SORT_RECENT) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessRecency); } else { } else { Log.w(LOG_TAG, "Unexpected sort option: " + sortOption); Log.w(LOG_TAG, "Unexpected sort option: " + sortOption); } } mHasSystemApps = false; java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context); java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context); java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(context); java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(context); final int numApps = appPermissionUsages.size(); ExpandablePreferenceGroup parent = null; for (int appNum = 0; appNum < numApps; appNum++) { AppPermissionUsage lastAppPermissionUsage = null; final AppPermissionUsage appPermissionUsage = appPermissionUsages.get(appNum); if (appPermissionUsage.getAccessCount() <= 0) { continue; } final boolean isSystemApp = Utils.isSystem(appPermissionUsage.getApp(), mLauncherPkgs); if (!mHasSystemApps) { if (isSystemApp) { mHasSystemApps = true; getActivity().invalidateOptionsMenu(); } } if (isSystemApp && !mShowSystem) { continue; } if (sortOption == SORT_MOST_ACCESSES) { appPermissionUsage.getGroupUsages().sort( PermissionUsageFragment::compareAccessCount); } else { appPermissionUsage.getGroupUsages().sort( PermissionUsageFragment::compareAccessTime); } final List<GroupUsage> appGroups = appPermissionUsage.getGroupUsages(); final int numUsages = usages.size(); for (int usageNum = 0; usageNum < numUsages; usageNum++) { final Pair<AppPermissionUsage, GroupUsage> usage = usages.get(usageNum); AppPermissionUsage appPermissionUsage = usage.first; GroupUsage groupUsage = usage.second; final List<PermissionControlPreference> permissionPrefs = new ArrayList<>(); final int numGroups = appGroups.size(); for (int groupNum = 0; groupNum < numGroups; groupNum++) { final GroupUsage groupUsage = appGroups.get(groupNum); if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) { if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) { continue; continue; } } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } if (groupUsage.getAccessCount() > 0) { String accessTimeString = null; String accessTimeString = null; if (isToday(groupUsage.getLastAccessTime())) { if (isToday(groupUsage.getLastAccessTime())) { accessTimeString = timeFormat.format(groupUsage.getLastAccessTime()); accessTimeString = timeFormat.format(groupUsage.getLastAccessTime()); Loading @@ -436,27 +437,17 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements accessTimeString = dateFormat.format(groupUsage.getLastAccessTime()); accessTimeString = dateFormat.format(groupUsage.getLastAccessTime()); } } permissionPrefs.add(createPermissionUsagePreference(context, if (lastAppPermissionUsage != appPermissionUsage) { appPermissionUsage, groupUsage, accessTimeString)); } } if (permissionPrefs.isEmpty()) { continue; } // Add a "parent" entry for the app that will expand to the individual entries. // Add a "parent" entry for the app that will expand to the individual entries. PreferenceGroup parent = createExpandablePreferenceGroup(context, appPermissionUsage); parent = createExpandablePreferenceGroup(context, appPermissionUsage, sortOption == SORT_RECENT ? accessTimeString : null); category.addPreference(parent); category.addPreference(parent); lastAppPermissionUsage = appPermissionUsage; final int permissionPrefCount = permissionPrefs.size(); for (int i = 0; i < permissionPrefCount; i++) { final PermissionControlPreference permissionPref = permissionPrefs.get(i); if (permissionPrefs.size() == 1) { permissionPref.setIcon(appPermissionUsage.getApp().getIcon()); } parent.addPreference(permissionPrefs.get(i)); } } parent.addPreference(createPermissionUsagePreference(context, appPermissionUsage, groupUsage, accessTimeString)); parent.addSummaryIcon(groupUsage.getGroup().getIconResId()); } } } } Loading Loading @@ -497,13 +488,14 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements /** /** * Create a bar chart showing the permissions that are used by the most apps. * Create a bar chart showing the permissions that are used by the most apps. * * * @param appPermissionUsages app permission usages * @param usages the usages * @param timeFilterItem the time filter, or null if no filter is set * @param timeFilterItem the time filter, or null if no filter is set * @param context the context * @param context the context * * * @return the Preference representing the bar chart * @return the Preference representing the bar chart */ */ private BarChartPreference createBarChart(@NonNull List<AppPermissionUsage> appPermissionUsages, private BarChartPreference createBarChart( @NonNull List<Pair<AppPermissionUsage, GroupUsage>> usages, @Nullable TimeFilterItem timeFilterItem, @NonNull Context context) { @Nullable TimeFilterItem timeFilterItem, @NonNull Context context) { BarChartInfo.Builder builder = new BarChartInfo.Builder(); BarChartInfo.Builder builder = new BarChartInfo.Builder(); BarChartPreference barChart = new BarChartPreference(context, null); BarChartPreference barChart = new BarChartPreference(context, null); Loading @@ -521,21 +513,10 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements final ArrayList<AppPermissionGroup> groups = new ArrayList<>(); final ArrayList<AppPermissionGroup> groups = new ArrayList<>(); final ArrayMap<String, Integer> groupToAppCount = new ArrayMap<>(); final ArrayMap<String, Integer> groupToAppCount = new ArrayMap<>(); final int appCount = appPermissionUsages.size(); final int usageCount = usages.size(); for (int i = 0; i < appCount; i++) { for (int i = 0; i < usageCount; i++) { final AppPermissionUsage appPermissionUsage = appPermissionUsages.get(i); final Pair<AppPermissionUsage, GroupUsage> usage = usages.get(i); final List<AppPermissionUsage.GroupUsage> groupUsages = GroupUsage groupUsage = usage.second; appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int j = 0; j < groupCount; j++) { final GroupUsage groupUsage = groupUsages.get(j); if (groupUsage.getAccessCount() <= 0) { continue; } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } final Integer count = groupToAppCount.get(groupUsage.getGroup().getName()); final Integer count = groupToAppCount.get(groupUsage.getGroup().getName()); if (count == null) { if (count == null) { groups.add(groupUsage.getGroup()); groups.add(groupUsage.getGroup()); Loading @@ -544,7 +525,6 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements groupToAppCount.put(groupUsage.getGroup().getName(), count + 1); groupToAppCount.put(groupUsage.getGroup().getName(), count + 1); } } } } } groups.sort((x, y) -> { groups.sort((x, y) -> { final int usageDiff = compareLong(groupToAppCount.get(x.getName()), final int usageDiff = compareLong(groupToAppCount.get(x.getName()), Loading Loading @@ -586,24 +566,14 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements * * * @return the expandable preference group. * @return the expandable preference group. */ */ private PreferenceGroup createExpandablePreferenceGroup(@NonNull Context context, private ExpandablePreferenceGroup createExpandablePreferenceGroup(@NonNull Context context, @NonNull AppPermissionUsage appPermissionUsage) { @NonNull AppPermissionUsage appPermissionUsage, @Nullable String summaryString) { final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); ExpandablePreferenceGroup preference = new ExpandablePreferenceGroup(context); final List<Integer> permissionIcons = new ArrayList<>(groupUsages.size()); final int permissionUsageCount = groupUsages.size(); for (int i = 0; i < permissionUsageCount; i++) { final AppPermissionUsage.GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } if (groupUsage.getAccessCount() > 0) { permissionIcons.add(groupUsage.getGroup().getIconResId()); } } PreferenceGroup preference = new ExpandablePreferenceGroup(context, permissionIcons); preference.setTitle(appPermissionUsage.getApp().getLabel()); preference.setTitle(appPermissionUsage.getApp().getLabel()); preference.setIcon(appPermissionUsage.getApp().getIcon()); preference.setIcon(appPermissionUsage.getApp().getIcon()); if (summaryString != null) { preference.setSummary(summaryString); } return preference; return preference; } } Loading Loading @@ -643,22 +613,24 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by their permission usage. * Compare two usages by the number of apps that accessed each group. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * We ignore the GroupUsage here to ensure that we keep all usages by the same app together. * @param y an AppPermissionUsage. * * @param x a usage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessUsage(@NonNull AppPermissionUsage x, private static int compareAccessUsage(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int groupDiff = getAccessedGroupCount(y) - getAccessedGroupCount(x); final int groupDiff = getAccessedGroupCount(y.first) - getAccessedGroupCount(x.first); if (groupDiff != 0) { if (groupDiff != 0) { return groupDiff; return groupDiff; } } return compareAccessTime(x, y); return compareAccessTime(x.first, y.first); } } /** /** Loading @@ -685,18 +657,19 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by their access time. * Compare two usages by their access time. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessTime(@NonNull AppPermissionUsage.GroupUsage x, private static int compareAccessTime(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage.GroupUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int timeDiff = compareLong(x.getLastAccessTime(), y.getLastAccessTime()); final int timeDiff = compareLong(x.second.getLastAccessTime(), y.second.getLastAccessTime()); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; } } Loading @@ -716,7 +689,7 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements */ */ private static int compareAccessTime(@NonNull AppPermissionUsage x, private static int compareAccessTime(@NonNull AppPermissionUsage x, @NonNull AppPermissionUsage y) { @NonNull AppPermissionUsage y) { final int timeDiff = compareLong(getLastAccessTime(x), getLastAccessTime(y)); final int timeDiff = compareLong(x.getLastAccessTime(), y.getLastAccessTime()); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; } } Loading @@ -725,90 +698,24 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Gets the last time the given app used a permission. * Compare two usages by their access count. * * @param appPermissionUsage The app permission usage. * * @return The last access time. */ private static long getLastAccessTime(@NonNull AppPermissionUsage appPermissionUsage) { long lastAccessTime = 0; final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int i = 0; i < groupCount; i++) { final GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. // We can replace this with AppPermissionUsage.getLastAccessTime then. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } lastAccessTime = Math.max(lastAccessTime, groupUsage.getLastAccessTime()); } return lastAccessTime; } /** * Compare two AppPermissionUsage by their access count. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessCount(@NonNull AppPermissionUsage x, private static int compareAccessCount(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int accessDiff = compareLong(getAccessCount(x), getAccessCount(y)); final int accessDiff = compareLong(x.second.getAccessCount(), y.second.getAccessCount()); if (accessDiff != 0) { if (accessDiff != 0) { return accessDiff; return accessDiff; } } return compareAccessTime(x, y); return compareAccessTime(x, y); } } /** * Compare two AppPermissionUsage by their access count. * * Can be used as a {@link java.util.Comparator}. * * @param x an AppPermissionUsage. * @param y an AppPermissionUsage. * * @return see {@link java.util.Comparator#compare(Object, Object)}. */ private static int compareAccessCount(@NonNull AppPermissionUsage.GroupUsage x, @NonNull GroupUsage y) { final int accessDiff = compareLong(x.getAccessCount(), y.getAccessCount()); if (accessDiff != 0) { return accessDiff; } // Make sure we lose no data if same return y.hashCode() - x.hashCode(); } /** * Gets the number of permission usages. * * @param appPermissionUsage The app permission usage. * * @return The number of permission usages. */ private static long getAccessCount(@NonNull AppPermissionUsage appPermissionUsage) { long accessCount = 0; final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int i = 0; i < groupCount; i++) { final GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. // We can replace this with AppPermissionUsage.getAccessCount then. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } accessCount += groupUsage.getAccessCount(); } return accessCount; } /** /** * Compare two longs. * Compare two longs. * * Loading @@ -829,17 +736,17 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by recency of access. * Compare two usages by recency of access. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessRecency(@NonNull AppPermissionUsage x, private static int compareAccessRecency(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int timeDiff = compareAccessTime(x, y); final int timeDiff = compareAccessTime(x, y); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; Loading Loading
src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java +12 −3 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ImageView; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.NonNull; import androidx.preference.Preference; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceGroup; Loading @@ -41,13 +42,12 @@ public class ExpandablePreferenceGroup extends PreferenceGroup { private @NonNull List<Integer> mSummaryIcons; private @NonNull List<Integer> mSummaryIcons; private boolean mExpanded; private boolean mExpanded; public ExpandablePreferenceGroup(@NonNull Context context, public ExpandablePreferenceGroup(@NonNull Context context) { @NonNull List<Integer> summaryIcons) { super(context, null); super(context, null); mContext = context; mContext = context; mPreferences = new ArrayList<>(); mPreferences = new ArrayList<>(); mSummaryIcons = summaryIcons; mSummaryIcons = new ArrayList<>(); mExpanded = false; mExpanded = false; setLayoutResource(R.layout.preference_usage); setLayoutResource(R.layout.preference_usage); Loading Loading @@ -111,4 +111,13 @@ public class ExpandablePreferenceGroup extends PreferenceGroup { mPreferences.add(preference); mPreferences.add(preference); return true; return true; } } /** * Show the given icon next to this preference's summary. * * @param resId the the resourceId of the drawable to use as the icon. */ public void addSummaryIcon(@DrawableRes int resId) { mSummaryIcons.add(resId); } } }
src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java +110 −203 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.LayoutInflater; import android.view.Menu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuInflater; Loading @@ -48,7 +49,6 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StringRes; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen; import com.android.packageinstaller.permission.model.AppPermissionGroup; import com.android.packageinstaller.permission.model.AppPermissionGroup; Loading Loading @@ -357,13 +357,45 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } screen.removeAll(); screen.removeAll(); // Update bar chart mHasSystemApps = false; List<Pair<AppPermissionUsage, GroupUsage>> usages = new ArrayList<>(); int numApps = appPermissionUsages.size(); for (int appNum = 0; appNum < numApps; appNum++) { AppPermissionUsage appUsage = appPermissionUsages.get(appNum); List<GroupUsage> appGroups = appUsage.getGroupUsages(); int numGroups = appGroups.size(); for (int groupNum = 0; groupNum < numGroups; groupNum++) { GroupUsage groupUsage = appGroups.get(groupNum); if (groupUsage.getAccessCount() <= 0) { continue; } final boolean isSystemApp = Utils.isSystem(appUsage.getApp(), mLauncherPkgs); if (!mHasSystemApps) { if (isSystemApp) { mHasSystemApps = true; getActivity().invalidateOptionsMenu(); } } if (isSystemApp && !mShowSystem) { continue; } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } usages.add(Pair.create(appUsage, appGroups.get(groupNum))); } } // Update bar chart. final TimeFilterItem timeFilterItem = getSelectedFilterItem(); final TimeFilterItem timeFilterItem = getSelectedFilterItem(); final BarChartPreference barChart = createBarChart(appPermissionUsages, final BarChartPreference barChart = createBarChart(usages, timeFilterItem, context); timeFilterItem, context); screen.addPreference(barChart); screen.addPreference(barChart); // Add the preferences. // Add the preference header. PreferenceCategory category = new PreferenceCategory(context); PreferenceCategory category = new PreferenceCategory(context); screen.addPreference(category); screen.addPreference(category); if (timeFilterItem != null) { if (timeFilterItem != null) { Loading @@ -372,63 +404,32 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements // Sort the apps. // Sort the apps. final int sortOption = getSelectedSortOption(); final int sortOption = getSelectedSortOption(); if (sortOption == SORT_MOST_PERMISSIONS) { if (sortOption == SORT_RECENT) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessUsage); usages.sort(PermissionUsageFragment::compareAccessRecency); } else if (sortOption == SORT_MOST_PERMISSIONS) { usages.sort(PermissionUsageFragment::compareAccessUsage); } else if (sortOption == SORT_MOST_ACCESSES) { } else if (sortOption == SORT_MOST_ACCESSES) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessCount); usages.sort(PermissionUsageFragment::compareAccessCount); } else if (sortOption == SORT_RECENT) { appPermissionUsages.sort(PermissionUsageFragment::compareAccessRecency); } else { } else { Log.w(LOG_TAG, "Unexpected sort option: " + sortOption); Log.w(LOG_TAG, "Unexpected sort option: " + sortOption); } } mHasSystemApps = false; java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context); java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context); java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(context); java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(context); final int numApps = appPermissionUsages.size(); ExpandablePreferenceGroup parent = null; for (int appNum = 0; appNum < numApps; appNum++) { AppPermissionUsage lastAppPermissionUsage = null; final AppPermissionUsage appPermissionUsage = appPermissionUsages.get(appNum); if (appPermissionUsage.getAccessCount() <= 0) { continue; } final boolean isSystemApp = Utils.isSystem(appPermissionUsage.getApp(), mLauncherPkgs); if (!mHasSystemApps) { if (isSystemApp) { mHasSystemApps = true; getActivity().invalidateOptionsMenu(); } } if (isSystemApp && !mShowSystem) { continue; } if (sortOption == SORT_MOST_ACCESSES) { appPermissionUsage.getGroupUsages().sort( PermissionUsageFragment::compareAccessCount); } else { appPermissionUsage.getGroupUsages().sort( PermissionUsageFragment::compareAccessTime); } final List<GroupUsage> appGroups = appPermissionUsage.getGroupUsages(); final int numUsages = usages.size(); for (int usageNum = 0; usageNum < numUsages; usageNum++) { final Pair<AppPermissionUsage, GroupUsage> usage = usages.get(usageNum); AppPermissionUsage appPermissionUsage = usage.first; GroupUsage groupUsage = usage.second; final List<PermissionControlPreference> permissionPrefs = new ArrayList<>(); final int numGroups = appGroups.size(); for (int groupNum = 0; groupNum < numGroups; groupNum++) { final GroupUsage groupUsage = appGroups.get(groupNum); if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) { if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) { continue; continue; } } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } if (groupUsage.getAccessCount() > 0) { String accessTimeString = null; String accessTimeString = null; if (isToday(groupUsage.getLastAccessTime())) { if (isToday(groupUsage.getLastAccessTime())) { accessTimeString = timeFormat.format(groupUsage.getLastAccessTime()); accessTimeString = timeFormat.format(groupUsage.getLastAccessTime()); Loading @@ -436,27 +437,17 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements accessTimeString = dateFormat.format(groupUsage.getLastAccessTime()); accessTimeString = dateFormat.format(groupUsage.getLastAccessTime()); } } permissionPrefs.add(createPermissionUsagePreference(context, if (lastAppPermissionUsage != appPermissionUsage) { appPermissionUsage, groupUsage, accessTimeString)); } } if (permissionPrefs.isEmpty()) { continue; } // Add a "parent" entry for the app that will expand to the individual entries. // Add a "parent" entry for the app that will expand to the individual entries. PreferenceGroup parent = createExpandablePreferenceGroup(context, appPermissionUsage); parent = createExpandablePreferenceGroup(context, appPermissionUsage, sortOption == SORT_RECENT ? accessTimeString : null); category.addPreference(parent); category.addPreference(parent); lastAppPermissionUsage = appPermissionUsage; final int permissionPrefCount = permissionPrefs.size(); for (int i = 0; i < permissionPrefCount; i++) { final PermissionControlPreference permissionPref = permissionPrefs.get(i); if (permissionPrefs.size() == 1) { permissionPref.setIcon(appPermissionUsage.getApp().getIcon()); } parent.addPreference(permissionPrefs.get(i)); } } parent.addPreference(createPermissionUsagePreference(context, appPermissionUsage, groupUsage, accessTimeString)); parent.addSummaryIcon(groupUsage.getGroup().getIconResId()); } } } } Loading Loading @@ -497,13 +488,14 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements /** /** * Create a bar chart showing the permissions that are used by the most apps. * Create a bar chart showing the permissions that are used by the most apps. * * * @param appPermissionUsages app permission usages * @param usages the usages * @param timeFilterItem the time filter, or null if no filter is set * @param timeFilterItem the time filter, or null if no filter is set * @param context the context * @param context the context * * * @return the Preference representing the bar chart * @return the Preference representing the bar chart */ */ private BarChartPreference createBarChart(@NonNull List<AppPermissionUsage> appPermissionUsages, private BarChartPreference createBarChart( @NonNull List<Pair<AppPermissionUsage, GroupUsage>> usages, @Nullable TimeFilterItem timeFilterItem, @NonNull Context context) { @Nullable TimeFilterItem timeFilterItem, @NonNull Context context) { BarChartInfo.Builder builder = new BarChartInfo.Builder(); BarChartInfo.Builder builder = new BarChartInfo.Builder(); BarChartPreference barChart = new BarChartPreference(context, null); BarChartPreference barChart = new BarChartPreference(context, null); Loading @@ -521,21 +513,10 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements final ArrayList<AppPermissionGroup> groups = new ArrayList<>(); final ArrayList<AppPermissionGroup> groups = new ArrayList<>(); final ArrayMap<String, Integer> groupToAppCount = new ArrayMap<>(); final ArrayMap<String, Integer> groupToAppCount = new ArrayMap<>(); final int appCount = appPermissionUsages.size(); final int usageCount = usages.size(); for (int i = 0; i < appCount; i++) { for (int i = 0; i < usageCount; i++) { final AppPermissionUsage appPermissionUsage = appPermissionUsages.get(i); final Pair<AppPermissionUsage, GroupUsage> usage = usages.get(i); final List<AppPermissionUsage.GroupUsage> groupUsages = GroupUsage groupUsage = usage.second; appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int j = 0; j < groupCount; j++) { final GroupUsage groupUsage = groupUsages.get(j); if (groupUsage.getAccessCount() <= 0) { continue; } // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } final Integer count = groupToAppCount.get(groupUsage.getGroup().getName()); final Integer count = groupToAppCount.get(groupUsage.getGroup().getName()); if (count == null) { if (count == null) { groups.add(groupUsage.getGroup()); groups.add(groupUsage.getGroup()); Loading @@ -544,7 +525,6 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements groupToAppCount.put(groupUsage.getGroup().getName(), count + 1); groupToAppCount.put(groupUsage.getGroup().getName(), count + 1); } } } } } groups.sort((x, y) -> { groups.sort((x, y) -> { final int usageDiff = compareLong(groupToAppCount.get(x.getName()), final int usageDiff = compareLong(groupToAppCount.get(x.getName()), Loading Loading @@ -586,24 +566,14 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements * * * @return the expandable preference group. * @return the expandable preference group. */ */ private PreferenceGroup createExpandablePreferenceGroup(@NonNull Context context, private ExpandablePreferenceGroup createExpandablePreferenceGroup(@NonNull Context context, @NonNull AppPermissionUsage appPermissionUsage) { @NonNull AppPermissionUsage appPermissionUsage, @Nullable String summaryString) { final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); ExpandablePreferenceGroup preference = new ExpandablePreferenceGroup(context); final List<Integer> permissionIcons = new ArrayList<>(groupUsages.size()); final int permissionUsageCount = groupUsages.size(); for (int i = 0; i < permissionUsageCount; i++) { final AppPermissionUsage.GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } if (groupUsage.getAccessCount() > 0) { permissionIcons.add(groupUsage.getGroup().getIconResId()); } } PreferenceGroup preference = new ExpandablePreferenceGroup(context, permissionIcons); preference.setTitle(appPermissionUsage.getApp().getLabel()); preference.setTitle(appPermissionUsage.getApp().getLabel()); preference.setIcon(appPermissionUsage.getApp().getIcon()); preference.setIcon(appPermissionUsage.getApp().getIcon()); if (summaryString != null) { preference.setSummary(summaryString); } return preference; return preference; } } Loading Loading @@ -643,22 +613,24 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by their permission usage. * Compare two usages by the number of apps that accessed each group. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * We ignore the GroupUsage here to ensure that we keep all usages by the same app together. * @param y an AppPermissionUsage. * * @param x a usage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessUsage(@NonNull AppPermissionUsage x, private static int compareAccessUsage(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int groupDiff = getAccessedGroupCount(y) - getAccessedGroupCount(x); final int groupDiff = getAccessedGroupCount(y.first) - getAccessedGroupCount(x.first); if (groupDiff != 0) { if (groupDiff != 0) { return groupDiff; return groupDiff; } } return compareAccessTime(x, y); return compareAccessTime(x.first, y.first); } } /** /** Loading @@ -685,18 +657,19 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by their access time. * Compare two usages by their access time. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessTime(@NonNull AppPermissionUsage.GroupUsage x, private static int compareAccessTime(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage.GroupUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int timeDiff = compareLong(x.getLastAccessTime(), y.getLastAccessTime()); final int timeDiff = compareLong(x.second.getLastAccessTime(), y.second.getLastAccessTime()); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; } } Loading @@ -716,7 +689,7 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements */ */ private static int compareAccessTime(@NonNull AppPermissionUsage x, private static int compareAccessTime(@NonNull AppPermissionUsage x, @NonNull AppPermissionUsage y) { @NonNull AppPermissionUsage y) { final int timeDiff = compareLong(getLastAccessTime(x), getLastAccessTime(y)); final int timeDiff = compareLong(x.getLastAccessTime(), y.getLastAccessTime()); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; } } Loading @@ -725,90 +698,24 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Gets the last time the given app used a permission. * Compare two usages by their access count. * * @param appPermissionUsage The app permission usage. * * @return The last access time. */ private static long getLastAccessTime(@NonNull AppPermissionUsage appPermissionUsage) { long lastAccessTime = 0; final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int i = 0; i < groupCount; i++) { final GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. // We can replace this with AppPermissionUsage.getLastAccessTime then. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } lastAccessTime = Math.max(lastAccessTime, groupUsage.getLastAccessTime()); } return lastAccessTime; } /** * Compare two AppPermissionUsage by their access count. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessCount(@NonNull AppPermissionUsage x, private static int compareAccessCount(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int accessDiff = compareLong(getAccessCount(x), getAccessCount(y)); final int accessDiff = compareLong(x.second.getAccessCount(), y.second.getAccessCount()); if (accessDiff != 0) { if (accessDiff != 0) { return accessDiff; return accessDiff; } } return compareAccessTime(x, y); return compareAccessTime(x, y); } } /** * Compare two AppPermissionUsage by their access count. * * Can be used as a {@link java.util.Comparator}. * * @param x an AppPermissionUsage. * @param y an AppPermissionUsage. * * @return see {@link java.util.Comparator#compare(Object, Object)}. */ private static int compareAccessCount(@NonNull AppPermissionUsage.GroupUsage x, @NonNull GroupUsage y) { final int accessDiff = compareLong(x.getAccessCount(), y.getAccessCount()); if (accessDiff != 0) { return accessDiff; } // Make sure we lose no data if same return y.hashCode() - x.hashCode(); } /** * Gets the number of permission usages. * * @param appPermissionUsage The app permission usage. * * @return The number of permission usages. */ private static long getAccessCount(@NonNull AppPermissionUsage appPermissionUsage) { long accessCount = 0; final List<GroupUsage> groupUsages = appPermissionUsage.getGroupUsages(); final int groupCount = groupUsages.size(); for (int i = 0; i < groupCount; i++) { final GroupUsage groupUsage = groupUsages.get(i); // STOPSHIP: Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. // We can replace this with AppPermissionUsage.getAccessCount then. if (groupUsage.getGroup().getLabel().equals("Storage")) { continue; } accessCount += groupUsage.getAccessCount(); } return accessCount; } /** /** * Compare two longs. * Compare two longs. * * Loading @@ -829,17 +736,17 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements } } /** /** * Compare two AppPermissionUsage by recency of access. * Compare two usages by recency of access. * * * Can be used as a {@link java.util.Comparator}. * Can be used as a {@link java.util.Comparator}. * * * @param x an AppPermissionUsage. * @param x a usage. * @param y an AppPermissionUsage. * @param y a usage. * * * @return see {@link java.util.Comparator#compare(Object, Object)}. * @return see {@link java.util.Comparator#compare(Object, Object)}. */ */ private static int compareAccessRecency(@NonNull AppPermissionUsage x, private static int compareAccessRecency(@NonNull Pair<AppPermissionUsage, GroupUsage> x, @NonNull AppPermissionUsage y) { @NonNull Pair<AppPermissionUsage, GroupUsage> y) { final int timeDiff = compareAccessTime(x, y); final int timeDiff = compareAccessTime(x, y); if (timeDiff != 0) { if (timeDiff != 0) { return timeDiff; return timeDiff; Loading