Loading res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -9211,6 +9211,10 @@ <!-- Keywords for Directory Access settings --> <string name="keywords_directory_access">directory access</string> <!-- String used to describe the name of a directory in a volume; it must show both names, with the directory name wrapped in parenthesis --> <string name="directory_on_volume"><xliff:g id="volume" example="SD Card">%1$s</xliff:g> (<xliff:g id="directory" example="Movies">%2$s</xliff:g>)</string> <!-- Account type associated with the backup account. Empty for AOSP. [DO NOT TRANSLATE] --> <string name="account_type" translatable="false"></string> <!-- Package to target for Account credential confirmation. This will allow users to src/com/android/settings/applications/AppStorageSettings.java +4 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AppGlobals; import android.app.GrantedUriPermission; import android.app.LoaderManager; import android.content.Context; import android.content.DialogInterface; Loading Loading @@ -399,7 +400,7 @@ public class AppStorageSettings extends AppInfoWithHeader // Gets all URI permissions from am. ActivityManager am = (ActivityManager) getActivity().getSystemService( Context.ACTIVITY_SERVICE); List<UriPermission> perms = List<GrantedUriPermission> perms = am.getGrantedUriPermissions(mAppEntry.info.packageName).getList(); if (perms.isEmpty()) { Loading @@ -411,8 +412,8 @@ public class AppStorageSettings extends AppInfoWithHeader // Group number of URIs by app. Map<CharSequence, MutableInt> uriCounters = new TreeMap<>(); for (UriPermission perm : perms) { String authority = perm.getUri().getAuthority(); for (GrantedUriPermission perm : perms) { String authority = perm.uri.getAuthority(); ProviderInfo provider = pm.resolveContentProvider(authority, 0); CharSequence app = provider.applicationInfo.loadLabel(pm); MutableInt count = uriCounters.get(app); Loading src/com/android/settings/applications/DirectoryAccessDetails.java +87 −41 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_ import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID; Loading Loading @@ -120,8 +121,7 @@ public class DirectoryAccessDetails extends AppInfoBase { addPreferencesFromResource(R.xml.directory_access_details); final PreferenceScreen prefsGroup = getPreferenceScreen(); // Set external directory UUIDs. ArraySet<String> externalDirectoryUuids = null; final Map<String, ExternalVolume> externalVolumes = new HashMap<>(); final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") Loading @@ -146,8 +146,10 @@ public class DirectoryAccessDetails extends AppInfoBase { final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE); final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID); final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY); final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1; if (VERBOSE) { Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir); Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir + " granted:" + granted); } if (!mPackageName.equals(pkg)) { Loading @@ -159,24 +161,37 @@ public class DirectoryAccessDetails extends AppInfoBase { if (uuid == null) { // Primary storage entry: add right away prefsGroup.addPreference( newPreference(context, dir, providerUri, /* uuid= */ null, dir)); prefsGroup.addPreference(newPreference(context, dir, providerUri, /* uuid= */ null, dir, granted)); } else { // External volume entry: save it for later. if (externalDirectoryUuids == null) { externalDirectoryUuids = new ArraySet<>(1); ExternalVolume externalVolume = externalVolumes.get(uuid); if (externalVolume == null) { externalVolume = new ExternalVolume(uuid); externalVolumes.put(uuid, externalVolume); } if (dir == null) { // Whole volume externalVolume.granted = granted; } else { // Directory only externalVolume.children.add(new Pair<>(dir, granted)); } externalDirectoryUuids.add(uuid); } } } // Add entries from external volumes if (externalDirectoryUuids != null) { if (VERBOSE) { Log.v(TAG, "adding external directories: " + externalDirectoryUuids); Log.v(TAG, "external volumes: " + externalVolumes); } if (externalVolumes.isEmpty()) { // We're done! return; } // Add entries from external volumes // Query StorageManager to get the user-friendly volume names. final StorageManager sm = context.getSystemService(StorageManager.class); final List<VolumeInfo> volumes = sm.getVolumes(); Loading @@ -200,23 +215,38 @@ public class DirectoryAccessDetails extends AppInfoBase { Log.v(TAG, "UUID -> name mapping: " + volumeNames); } externalDirectoryUuids.forEach((uuid) ->{ final String name = volumeNames.get(uuid); for (ExternalVolume volume : externalVolumes.values()) { final String volumeName = volumeNames.get(volume.uuid); if (volumeName == null) { Log.w(TAG, "Ignoring entry for invalid UUID: " + volume.uuid); continue; } // First add the pref for the whole volume... // TODO(b/72055774): add separator prefsGroup.addPreference( newPreference(context, name, providerUri, uuid, /* dir= */ null)); prefsGroup.addPreference(newPreference(context, volumeName, providerUri, volume.uuid, /* dir= */ null, volume.granted)); // TODO(b/72055774): make sure children are gone when parent is toggled on - should be // handled automatically if we're refreshing the activity on change, otherwise we'll // need to explicitly remove them // ... then the children prefs volume.children.forEach((pair) -> { final String dir = pair.first; final String name = context.getResources() .getString(R.string.directory_on_volume, volumeName, dir); prefsGroup .addPreference(newPreference(context, name, providerUri, volume.uuid, dir, pair.second)); }); } return; } private SwitchPreference newPreference(Context context, String title, Uri providerUri, String uuid, String dir) { String uuid, String dir, boolean granted) { final SwitchPreference pref = new SwitchPreference(context); pref.setKey(String.format("%s:%s", uuid, dir)); pref.setTitle(title); pref.setChecked(false); pref.setChecked(granted); pref.setOnPreferenceChangeListener((unused, value) -> { resetDoNotAskAgain(context, value, providerUri, uuid, dir); return true; Loading Loading @@ -259,4 +289,20 @@ public class DirectoryAccessDetails extends AppInfoBase { public int getMetricsCategory() { return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL; } private static class ExternalVolume { final String uuid; final List<Pair<String, Boolean>> children = new ArrayList<>(); boolean granted; ExternalVolume(String uuid) { this.uuid = uuid; } @Override public String toString() { return "ExternalVolume: [uuid=" + uuid + ", granted=" + granted + ", children=" + children + "]"; } } } Loading
res/values/strings.xml +4 −0 Original line number Diff line number Diff line Loading @@ -9211,6 +9211,10 @@ <!-- Keywords for Directory Access settings --> <string name="keywords_directory_access">directory access</string> <!-- String used to describe the name of a directory in a volume; it must show both names, with the directory name wrapped in parenthesis --> <string name="directory_on_volume"><xliff:g id="volume" example="SD Card">%1$s</xliff:g> (<xliff:g id="directory" example="Movies">%2$s</xliff:g>)</string> <!-- Account type associated with the backup account. Empty for AOSP. [DO NOT TRANSLATE] --> <string name="account_type" translatable="false"></string> <!-- Package to target for Account credential confirmation. This will allow users to
src/com/android/settings/applications/AppStorageSettings.java +4 −3 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AppGlobals; import android.app.GrantedUriPermission; import android.app.LoaderManager; import android.content.Context; import android.content.DialogInterface; Loading Loading @@ -399,7 +400,7 @@ public class AppStorageSettings extends AppInfoWithHeader // Gets all URI permissions from am. ActivityManager am = (ActivityManager) getActivity().getSystemService( Context.ACTIVITY_SERVICE); List<UriPermission> perms = List<GrantedUriPermission> perms = am.getGrantedUriPermissions(mAppEntry.info.packageName).getList(); if (perms.isEmpty()) { Loading @@ -411,8 +412,8 @@ public class AppStorageSettings extends AppInfoWithHeader // Group number of URIs by app. Map<CharSequence, MutableInt> uriCounters = new TreeMap<>(); for (UriPermission perm : perms) { String authority = perm.getUri().getAuthority(); for (GrantedUriPermission perm : perms) { String authority = perm.uri.getAuthority(); ProviderInfo provider = pm.resolveContentProvider(authority, 0); CharSequence app = provider.applicationInfo.loadLabel(pm); MutableInt count = uriCounters.get(app); Loading
src/com/android/settings/applications/DirectoryAccessDetails.java +87 −41 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.os.storage.StorageVolume.ScopedAccessProviderContract.COL_ import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID; Loading Loading @@ -120,8 +121,7 @@ public class DirectoryAccessDetails extends AppInfoBase { addPreferencesFromResource(R.xml.directory_access_details); final PreferenceScreen prefsGroup = getPreferenceScreen(); // Set external directory UUIDs. ArraySet<String> externalDirectoryUuids = null; final Map<String, ExternalVolume> externalVolumes = new HashMap<>(); final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") Loading @@ -146,8 +146,10 @@ public class DirectoryAccessDetails extends AppInfoBase { final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE); final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID); final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY); final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1; if (VERBOSE) { Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir); Log.v(TAG, "Pkg:" + pkg + " uuid: " + uuid + " dir: " + dir + " granted:" + granted); } if (!mPackageName.equals(pkg)) { Loading @@ -159,24 +161,37 @@ public class DirectoryAccessDetails extends AppInfoBase { if (uuid == null) { // Primary storage entry: add right away prefsGroup.addPreference( newPreference(context, dir, providerUri, /* uuid= */ null, dir)); prefsGroup.addPreference(newPreference(context, dir, providerUri, /* uuid= */ null, dir, granted)); } else { // External volume entry: save it for later. if (externalDirectoryUuids == null) { externalDirectoryUuids = new ArraySet<>(1); ExternalVolume externalVolume = externalVolumes.get(uuid); if (externalVolume == null) { externalVolume = new ExternalVolume(uuid); externalVolumes.put(uuid, externalVolume); } if (dir == null) { // Whole volume externalVolume.granted = granted; } else { // Directory only externalVolume.children.add(new Pair<>(dir, granted)); } externalDirectoryUuids.add(uuid); } } } // Add entries from external volumes if (externalDirectoryUuids != null) { if (VERBOSE) { Log.v(TAG, "adding external directories: " + externalDirectoryUuids); Log.v(TAG, "external volumes: " + externalVolumes); } if (externalVolumes.isEmpty()) { // We're done! return; } // Add entries from external volumes // Query StorageManager to get the user-friendly volume names. final StorageManager sm = context.getSystemService(StorageManager.class); final List<VolumeInfo> volumes = sm.getVolumes(); Loading @@ -200,23 +215,38 @@ public class DirectoryAccessDetails extends AppInfoBase { Log.v(TAG, "UUID -> name mapping: " + volumeNames); } externalDirectoryUuids.forEach((uuid) ->{ final String name = volumeNames.get(uuid); for (ExternalVolume volume : externalVolumes.values()) { final String volumeName = volumeNames.get(volume.uuid); if (volumeName == null) { Log.w(TAG, "Ignoring entry for invalid UUID: " + volume.uuid); continue; } // First add the pref for the whole volume... // TODO(b/72055774): add separator prefsGroup.addPreference( newPreference(context, name, providerUri, uuid, /* dir= */ null)); prefsGroup.addPreference(newPreference(context, volumeName, providerUri, volume.uuid, /* dir= */ null, volume.granted)); // TODO(b/72055774): make sure children are gone when parent is toggled on - should be // handled automatically if we're refreshing the activity on change, otherwise we'll // need to explicitly remove them // ... then the children prefs volume.children.forEach((pair) -> { final String dir = pair.first; final String name = context.getResources() .getString(R.string.directory_on_volume, volumeName, dir); prefsGroup .addPreference(newPreference(context, name, providerUri, volume.uuid, dir, pair.second)); }); } return; } private SwitchPreference newPreference(Context context, String title, Uri providerUri, String uuid, String dir) { String uuid, String dir, boolean granted) { final SwitchPreference pref = new SwitchPreference(context); pref.setKey(String.format("%s:%s", uuid, dir)); pref.setTitle(title); pref.setChecked(false); pref.setChecked(granted); pref.setOnPreferenceChangeListener((unused, value) -> { resetDoNotAskAgain(context, value, providerUri, uuid, dir); return true; Loading Loading @@ -259,4 +289,20 @@ public class DirectoryAccessDetails extends AppInfoBase { public int getMetricsCategory() { return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL; } private static class ExternalVolume { final String uuid; final List<Pair<String, Boolean>> children = new ArrayList<>(); boolean granted; ExternalVolume(String uuid) { this.uuid = uuid; } @Override public String toString() { return "ExternalVolume: [uuid=" + uuid + ", granted=" + granted + ", children=" + children + "]"; } } }