From 43b41aaf782e9ef8917d2f41f01c0f468d63a402 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Wed, 9 Jan 2019 13:34:35 -0800 Subject: Update to a newer version of the Permission Hub mocks. This gives singleton/uncoalesced entries "parent" permissions just like the coalesced ones to be more consistent. It also changes the summary, title, and icon of the entries themselves, including changing to absolute time for entries in the current day and the date for older entries. It also changes the default sort to recency, adds a one minute filter, and continues to remove the Storage permission. Bug: 63532550 Test: Open Permissions Hub Change-Id: Ib37a93d0bc47eaa6a74d5df192e833cfb13949e1 --- res/layout/preference_usage.xml | 27 +++- res/layout/summary_image_view.xml | 30 ---- res/layout/title_summary_image_view.xml | 30 ++++ res/values/dimens.xml | 2 +- res/values/strings.xml | 16 +- .../ui/handheld/ExpandablePreferenceGroup.java | 10 +- .../ui/handheld/PermissionControlPreference.java | 38 +++-- .../ui/handheld/PermissionUsageFragment.java | 161 ++++++++++++++++----- 8 files changed, 220 insertions(+), 94 deletions(-) delete mode 100644 res/layout/summary_image_view.xml create mode 100644 res/layout/title_summary_image_view.xml diff --git a/res/layout/preference_usage.xml b/res/layout/preference_usage.xml index 348dc353..a1eb90f3 100644 --- a/res/layout/preference_usage.xml +++ b/res/layout/preference_usage.xml @@ -38,13 +38,28 @@ android:paddingBottom="16dp" android:orientation="vertical"> - + android:orientation="horizontal"> + + + + + + - - - - - - - - diff --git a/res/layout/title_summary_image_view.xml b/res/layout/title_summary_image_view.xml new file mode 100644 index 00000000..8b3a6641 --- /dev/null +++ b/res/layout/title_summary_image_view.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index c6f2a7e6..49f25574 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -54,7 +54,7 @@ 12dp 8dp - 16dp + 16dp 56dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 7f1dc5e5..1a11beb2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -255,14 +255,11 @@ Permissions usage - - %1$s - Last access %2$s ago - - %1$s - %2$s accesses + Last access: %1$s\n%2$s accesses - %1$s - %2$s accesses (%3$s in background) + Last access: %1$s\n%2$s accesses (%3$s in background) Any permission @@ -282,6 +279,9 @@ Last 15 minutes + + Last 1 minute + No permission usages @@ -300,6 +300,9 @@ Access in last 15 minutes + + Access in last 1 minute + Top permission usage at any time @@ -315,6 +318,9 @@ Top permission usage in last 15 minutes + + Top permission usage in last 1 minute + Apps diff --git a/src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java b/src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java index 1dac8508..333df47e 100644 --- a/src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java +++ b/src/com/android/packageinstaller/permission/ui/handheld/ExpandablePreferenceGroup.java @@ -87,21 +87,21 @@ public class ExpandablePreferenceGroup extends PreferenceGroup { holder.setDividerAllowedAbove(false); holder.setDividerAllowedBelow(false); + holder.findViewById(R.id.title_widget_frame).setVisibility(View.GONE); + ViewGroup summaryFrame = (ViewGroup) holder.findViewById(R.id.summary_widget_frame); if (mSummaryIcons.isEmpty()) { summaryFrame.setVisibility(View.GONE); } else { summaryFrame.removeAllViews(); - int summaryIconSize = mContext.getResources().getDimensionPixelSize( - R.dimen.preference_usage_summary_icon_size); int numIcons = mSummaryIcons.size(); for (int i = 0; i < numIcons; i++) { LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class); - ViewGroup layoutView = (ViewGroup) inflater.inflate(R.layout.summary_image_view, + ViewGroup group = (ViewGroup) inflater.inflate(R.layout.title_summary_image_view, null); - ImageView imageView = layoutView.requireViewById(R.id.icon); + ImageView imageView = group.requireViewById(R.id.icon); imageView.setImageResource(mSummaryIcons.get(i)); - summaryFrame.addView(layoutView); + summaryFrame.addView(group); } } } diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionControlPreference.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionControlPreference.java index da80c2a1..97b9cd42 100644 --- a/src/com/android/packageinstaller/permission/ui/handheld/PermissionControlPreference.java +++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionControlPreference.java @@ -45,6 +45,7 @@ public class PermissionControlPreference extends Preference { private @Nullable Drawable mWidgetIcon; private boolean mUseSmallerIcon; private boolean mEllipsizeEnd; + private @Nullable List mTitleIcons; private @Nullable List mSummaryIcons; public PermissionControlPreference(@NonNull Context context, @@ -54,6 +55,7 @@ public class PermissionControlPreference extends Preference { mWidgetIcon = null; mUseSmallerIcon = false; mEllipsizeEnd = false; + mTitleIcons = null; mSummaryIcons = null; setOnPreferenceClickListener(preference -> { Intent intent = new Intent(context, AppPermissionActivity.class); @@ -111,6 +113,16 @@ public class PermissionControlPreference extends Preference { setSummary(""); } + /** + * Sets this preference to show the given icons to the left of its title. + * + * @param titleIcons the icons to show. + */ + public void setTitleIcons(@NonNull List titleIcons) { + mTitleIcons = titleIcons; + setLayoutResource(R.layout.preference_usage); + } + /** * Sets this preference to show the given icons to the left of its summary. * @@ -144,20 +156,26 @@ public class PermissionControlPreference extends Preference { title.setEllipsize(TextUtils.TruncateAt.END); } - if (mSummaryIcons != null && !mSummaryIcons.isEmpty()) { - ViewGroup summaryFrame = (ViewGroup) holder.findViewById(R.id.summary_widget_frame); - summaryFrame.removeAllViews(); - int summaryIconSize = mContext.getResources().getDimensionPixelSize( - R.dimen.preference_usage_summary_icon_size); - int numIcons = mSummaryIcons.size(); + setIcons(holder, mSummaryIcons, R.id.summary_widget_frame); + setIcons(holder, mTitleIcons, R.id.title_widget_frame); + } + + private void setIcons(PreferenceViewHolder holder, @Nullable List icons, int frameId) { + ViewGroup frame = (ViewGroup) holder.findViewById(frameId); + if (icons != null && !icons.isEmpty()) { + frame.setVisibility(View.VISIBLE); + frame.removeAllViews(); + int numIcons = icons.size(); for (int i = 0; i < numIcons; i++) { LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class); - ViewGroup layoutView = (ViewGroup) inflater.inflate(R.layout.summary_image_view, + ViewGroup group = (ViewGroup) inflater.inflate(R.layout.title_summary_image_view, null); - ImageView imageView = layoutView.requireViewById(R.id.icon); - imageView.setImageResource(mSummaryIcons.get(i)); - summaryFrame.addView(layoutView); + ImageView imageView = group.requireViewById(R.id.icon); + imageView.setImageResource(icons.get(i)); + frame.addView(group); } + } else if (frame != null) { + frame.setVisibility(View.GONE); } } } diff --git a/src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java b/src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java index 9485d2d6..2e4aada1 100644 --- a/src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java +++ b/src/com/android/packageinstaller/permission/ui/handheld/PermissionUsageFragment.java @@ -28,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.text.format.DateFormat; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -68,6 +69,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; /** @@ -81,11 +83,11 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements private static final String LOG_TAG = "PermissionUsageFragment"; @Retention(SOURCE) - @IntDef(value = {SORT_MOST_PERMISSIONS, SORT_MOST_ACCESSES, SORT_RECENT}) + @IntDef(value = {SORT_RECENT, SORT_MOST_PERMISSIONS, SORT_MOST_ACCESSES}) @interface SortOption {} - static final int SORT_MOST_PERMISSIONS = 1; - static final int SORT_MOST_ACCESSES = 2; - static final int SORT_RECENT = 3; + static final int SORT_RECENT = 1; + static final int SORT_MOST_PERMISSIONS = 2; + static final int SORT_MOST_ACCESSES = 3; private static final int MENU_FILTER_BY_PERMISSIONS = MENU_HIDE_SYSTEM + 1; @@ -232,16 +234,20 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements context.getString(R.string.permission_usage_last_15_minutes), R.string.permission_usage_bar_chart_title_last_15_minutes, R.string.permission_usage_list_title_last_15_minutes)); + mFilterAdapterTime.addFilter(new TimeFilterItem(MINUTES.toMillis(1), + context.getString(R.string.permission_usage_last_minute), + R.string.permission_usage_bar_chart_title_last_minute, + R.string.permission_usage_list_title_last_minute)); mFilterSpinnerTime.setSelection(mSavedTimeSpinnerIndex); // Add sort spinner entries. + mSortAdapter.addFilter(new SortItem(context.getString(R.string.sort_spinner_recent), + SORT_RECENT)); mSortAdapter.addFilter( new SortItem(context.getString(R.string.sort_spinner_most_permissions), SORT_MOST_PERMISSIONS)); mSortAdapter.addFilter(new SortItem(context.getString(R.string.sort_spinner_most_accesses), SORT_MOST_ACCESSES)); - mSortAdapter.addFilter(new SortItem(context.getString(R.string.sort_spinner_recent), - SORT_RECENT)); mSortSpinner.setSelection(mSavedSortSpinnerIndex); return root; @@ -378,6 +384,9 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements mHasSystemApps = false; + java.text.DateFormat timeFormat = DateFormat.getTimeFormat(context); + java.text.DateFormat dateFormat = DateFormat.getMediumDateFormat(context); + final int numApps = appPermissionUsages.size(); for (int appNum = 0; appNum < numApps; appNum++) { final AppPermissionUsage appPermissionUsage = appPermissionUsages.get(appNum); @@ -415,23 +424,31 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements if (mFilterGroup != null && !mFilterGroup.equals(groupUsage.getGroup().getName())) { continue; } - // Ignore {READ,WRITE}_EXTERNAL_STORAGE since they're going away. + // 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; + if (isToday(groupUsage.getLastAccessTime())) { + accessTimeString = timeFormat.format(groupUsage.getLastAccessTime()); + } else { + accessTimeString = dateFormat.format(groupUsage.getLastAccessTime()); + } + permissionPrefs.add(createPermissionUsagePreference(context, - appPermissionUsage, groupUsage, sortOption)); + appPermissionUsage, groupUsage, accessTimeString)); } } - PreferenceGroup parent = category; - if (permissionPrefs.size() > 1) { - // Add a "parent" entry for the app that will expand to the individual entries. - parent = createExpandablePreferenceGroup(context, appPermissionUsage); - category.addPreference(parent); + if (permissionPrefs.isEmpty()) { + continue; } + // Add a "parent" entry for the app that will expand to the individual entries. + PreferenceGroup parent = createExpandablePreferenceGroup(context, appPermissionUsage); + category.addPreference(parent); + final int permissionPrefCount = permissionPrefs.size(); for (int i = 0; i < permissionPrefCount; i++) { final PermissionControlPreference permissionPref = permissionPrefs.get(i); @@ -515,6 +532,10 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements 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()); if (count == null) { groups.add(groupUsage.getGroup()); @@ -571,6 +592,10 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements 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()); } @@ -587,36 +612,30 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements * @param context the context * @param appPermissionUsage the permission usage for the app * @param groupUsage the permission item to add - * @param sortOption how the entries should be sorted + * @param accessTimeStr the string representing the access time * * @return the Preference */ private PermissionControlPreference createPermissionUsagePreference(@NonNull Context context, @NonNull AppPermissionUsage appPermissionUsage, - @NonNull GroupUsage groupUsage, @SortOption int sortOption) { + @NonNull GroupUsage groupUsage, @NonNull String accessTimeStr) { final PermissionControlPreference pref = new PermissionControlPreference(context, groupUsage.getGroup()); - pref.setTitle(appPermissionUsage.getApp().getLabel()); final AppPermissionGroup group = groupUsage.getGroup(); - if (sortOption == SORT_MOST_ACCESSES) { - if (groupUsage.getBackgroundAccessCount() == 0) { - pref.setSummary( - context.getString(R.string.permission_usage_summary_num_accesses, - group.getLabel(), groupUsage.getForegroundAccessCount())); - } else { - pref.setSummary( - context.getString( - R.string.permission_usage_summary_num_accesses_background, - group.getLabel(), groupUsage.getAccessCount(), - groupUsage.getBackgroundAccessCount())); - } + pref.setTitle(group.getLabel()); + if (groupUsage.getBackgroundAccessCount() == 0) { + pref.setSummary( + context.getString(R.string.permission_usage_summary, + accessTimeStr, groupUsage.getForegroundAccessCount())); } else { - pref.setSummary(context.getString(R.string.permission_usage_summary_last_access, - group.getLabel(), Utils.getTimeDiffStr(context, System.currentTimeMillis() - - groupUsage.getLastAccessTime()))); + pref.setSummary( + context.getString( + R.string.permission_usage_summary_background, + accessTimeStr, groupUsage.getAccessCount(), + groupUsage.getBackgroundAccessCount())); } - pref.setSummaryIcons(Collections.singletonList(group.getIconResId())); + pref.setTitleIcons(Collections.singletonList(group.getIconResId())); pref.setKey(group.getApp().packageName + "," + group.getName()); pref.useSmallerIcon(); return pref; @@ -653,6 +672,10 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements 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. + if (groupUsage.getGroup().getLabel().equals("Storage")) { + continue; + } if (groupUsage.getAccessCount() > 0) { accessedCount++; } @@ -692,7 +715,7 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements */ private static int compareAccessTime(@NonNull AppPermissionUsage x, @NonNull AppPermissionUsage y) { - final int timeDiff = compareLong(x.getLastAccessTime(), y.getLastAccessTime()); + final int timeDiff = compareLong(getLastAccessTime(x), getLastAccessTime(y)); if (timeDiff != 0) { return timeDiff; } @@ -700,6 +723,29 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements return x.hashCode() - y.hashCode(); } + /** + * Gets the last time the given app used a permission. + * + * @param appPermissionUsage The app permission usage. + * + * @return The last access time. + */ + private static long getLastAccessTime(@NonNull AppPermissionUsage appPermissionUsage) { + long lastAccessTime = 0; + final List 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. * @@ -712,12 +758,11 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements */ private static int compareAccessCount(@NonNull AppPermissionUsage x, @NonNull AppPermissionUsage y) { - final int accessDiff = compareLong(x.getAccessCount(), y.getAccessCount()); + final int accessDiff = compareLong(getAccessCount(x), getAccessCount(y)); if (accessDiff != 0) { return accessDiff; } - // Make sure we lose no data if same - return y.hashCode() - x.hashCode(); + return compareAccessTime(x, y); } /** @@ -740,6 +785,29 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements 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 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. * @@ -775,7 +843,7 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements if (timeDiff != 0) { return timeDiff; } - final int countDiff = y.getGroupUsages().size() - x.getGroupUsages().size(); + final int countDiff = compareAccessUsage(x, y); if (countDiff != 0) { return countDiff; } @@ -809,6 +877,25 @@ public class PermissionUsageFragment extends PermissionsFrameFragment implements return groups; } + /** + * Check whether the given time (in milliseconds) is in the current day. + * + * @param time the time in milliseconds + * + * @return whether the given time is in the current day. + */ + private static boolean isToday(long time) { + Calendar today = Calendar.getInstance(Locale.getDefault()); + today.setTimeInMillis(System.currentTimeMillis()); + today.set(Calendar.HOUR, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + + Calendar date = Calendar.getInstance(Locale.getDefault()); + date.setTimeInMillis(time); + return date.after(today); + } + /** * Show a dialog that allows selecting a permission group by which to filter the entries. */ -- cgit v1.2.3