Changed DirectoryAccessDetails to handle children directory on external volumes.

Test: manual verification

Bug: 63720392

Change-Id: Ief4ee0fe271212e2eccbdcedea8ebb3374c4e69b
This commit is contained in:
Felipe Leme
2018-01-24 12:17:29 -08:00
parent 7c80b5ed39
commit 025883da78
3 changed files with 95 additions and 44 deletions

View File

@@ -9230,6 +9230,10 @@
<!-- Keywords for Directory Access settings --> <!-- Keywords for Directory Access settings -->
<string name="keywords_directory_access">directory access</string> <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] --> <!-- Account type associated with the backup account. Empty for AOSP. [DO NOT TRANSLATE] -->
<string name="account_type" translatable="false"></string> <string name="account_type" translatable="false"></string>
<!-- Package to target for Account credential confirmation. This will allow users to <!-- Package to target for Account credential confirmation. This will allow users to

View File

@@ -22,6 +22,7 @@ import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.AppGlobals; import android.app.AppGlobals;
import android.app.GrantedUriPermission;
import android.app.LoaderManager; import android.app.LoaderManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@@ -399,7 +400,7 @@ public class AppStorageSettings extends AppInfoWithHeader
// Gets all URI permissions from am. // Gets all URI permissions from am.
ActivityManager am = (ActivityManager) getActivity().getSystemService( ActivityManager am = (ActivityManager) getActivity().getSystemService(
Context.ACTIVITY_SERVICE); Context.ACTIVITY_SERVICE);
List<UriPermission> perms = List<GrantedUriPermission> perms =
am.getGrantedUriPermissions(mAppEntry.info.packageName).getList(); am.getGrantedUriPermissions(mAppEntry.info.packageName).getList();
if (perms.isEmpty()) { if (perms.isEmpty()) {
@@ -411,8 +412,8 @@ public class AppStorageSettings extends AppInfoWithHeader
// Group number of URIs by app. // Group number of URIs by app.
Map<CharSequence, MutableInt> uriCounters = new TreeMap<>(); Map<CharSequence, MutableInt> uriCounters = new TreeMap<>();
for (UriPermission perm : perms) { for (GrantedUriPermission perm : perms) {
String authority = perm.getUri().getAuthority(); String authority = perm.uri.getAuthority();
ProviderInfo provider = pm.resolveContentProvider(authority, 0); ProviderInfo provider = pm.resolveContentProvider(authority, 0);
CharSequence app = provider.applicationInfo.loadLabel(pm); CharSequence app = provider.applicationInfo.loadLabel(pm);
MutableInt count = uriCounters.get(app); MutableInt count = uriCounters.get(app);

View File

@@ -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;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS; 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_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_PACKAGE;
import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID;
@@ -120,8 +121,7 @@ public class DirectoryAccessDetails extends AppInfoBase {
addPreferencesFromResource(R.xml.directory_access_details); addPreferencesFromResource(R.xml.directory_access_details);
final PreferenceScreen prefsGroup = getPreferenceScreen(); final PreferenceScreen prefsGroup = getPreferenceScreen();
// Set external directory UUIDs. final Map<String, ExternalVolume> externalVolumes = new HashMap<>();
ArraySet<String> externalDirectoryUuids = null;
final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*")
@@ -146,8 +146,10 @@ public class DirectoryAccessDetails extends AppInfoBase {
final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE); final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE);
final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID); final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID);
final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY); final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY);
final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1;
if (VERBOSE) { 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)) { if (!mPackageName.equals(pkg)) {
@@ -159,64 +161,92 @@ public class DirectoryAccessDetails extends AppInfoBase {
if (uuid == null) { if (uuid == null) {
// Primary storage entry: add right away // Primary storage entry: add right away
prefsGroup.addPreference( prefsGroup.addPreference(newPreference(context, dir, providerUri,
newPreference(context, dir, providerUri, /* uuid= */ null, dir)); /* uuid= */ null, dir, granted));
} else { } else {
// External volume entry: save it for later. // External volume entry: save it for later.
if (externalDirectoryUuids == null) { ExternalVolume externalVolume = externalVolumes.get(uuid);
externalDirectoryUuids = new ArraySet<>(1); 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);
} }
} }
} }
if (VERBOSE) {
Log.v(TAG, "external volumes: " + externalVolumes);
}
if (externalVolumes.isEmpty()) {
// We're done!
return;
}
// Add entries from external volumes // Add entries from external volumes
if (externalDirectoryUuids != null) {
if (VERBOSE) {
Log.v(TAG, "adding external directories: " + externalDirectoryUuids);
}
// Query StorageManager to get the user-friendly volume names. // Query StorageManager to get the user-friendly volume names.
final StorageManager sm = context.getSystemService(StorageManager.class); final StorageManager sm = context.getSystemService(StorageManager.class);
final List<VolumeInfo> volumes = sm.getVolumes(); final List<VolumeInfo> volumes = sm.getVolumes();
if (volumes.isEmpty()) { if (volumes.isEmpty()) {
Log.w(TAG, "StorageManager returned no secondary volumes"); Log.w(TAG, "StorageManager returned no secondary volumes");
return; return;
} }
final Map<String, String> volumeNames = new HashMap<>(volumes.size()); final Map<String, String> volumeNames = new HashMap<>(volumes.size());
for (VolumeInfo volume : volumes) { for (VolumeInfo volume : volumes) {
final String uuid = volume.getFsUuid(); final String uuid = volume.getFsUuid();
if (uuid == null) continue; // Primary storage; not used. if (uuid == null) continue; // Primary storage; not used.
String name = sm.getBestVolumeDescription(volume); String name = sm.getBestVolumeDescription(volume);
if (name == null) { if (name == null) {
Log.w(TAG, "No description for " + volume + "; using uuid instead: " + uuid); Log.w(TAG, "No description for " + volume + "; using uuid instead: " + uuid);
name = uuid; name = uuid;
}
volumeNames.put(uuid, name);
}
if (VERBOSE) {
Log.v(TAG, "UUID -> name mapping: " + volumeNames);
} }
volumeNames.put(uuid, name);
}
if (VERBOSE) {
Log.v(TAG, "UUID -> name mapping: " + volumeNames);
}
externalDirectoryUuids.forEach((uuid) ->{ for (ExternalVolume volume : externalVolumes.values()) {
final String name = volumeNames.get(uuid); final String volumeName = volumeNames.get(volume.uuid);
// TODO(b/72055774): add separator if (volumeName == null) {
prefsGroup.addPreference( Log.w(TAG, "Ignoring entry for invalid UUID: " + volume.uuid);
newPreference(context, name, providerUri, uuid, /* dir= */ null)); continue;
}
// First add the pref for the whole volume...
// TODO(b/72055774): add separator
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, 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); final SwitchPreference pref = new SwitchPreference(context);
pref.setKey(String.format("%s:%s", uuid, dir)); pref.setKey(String.format("%s:%s", uuid, dir));
pref.setTitle(title); pref.setTitle(title);
pref.setChecked(false); pref.setChecked(granted);
pref.setOnPreferenceChangeListener((unused, value) -> { pref.setOnPreferenceChangeListener((unused, value) -> {
resetDoNotAskAgain(context, value, providerUri, uuid, dir); resetDoNotAskAgain(context, value, providerUri, uuid, dir);
return true; return true;
@@ -259,4 +289,20 @@ public class DirectoryAccessDetails extends AppInfoBase {
public int getMetricsCategory() { public int getMetricsCategory() {
return MetricsEvent.APPLICATIONS_DIRECTORY_ACCESS_DETAIL; 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 + "]";
}
}
} }