Final (?!?!?!?!) Directory Access improvements.

- Hide children items when parent is granted access (and vice versa).
- Added dividers in between volumes.

Test: manual verification
Test: atest CtsAppSecurityHostTestCases:ScopedDirectoryAccessTest#testResetDoNotAskAgain,testResetGranted

Bug: 72055774

Change-Id: Ie4ad117d1f8a53bf7dbf7747e768a301b0d03604
This commit is contained in:
Felipe Leme
2018-03-30 10:34:23 -07:00
parent f3789adffd
commit 68acecff56

View File

@@ -44,8 +44,10 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
import android.support.v14.preference.SwitchPreference; import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroupAdapter;
import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
import android.text.TextUtils; import android.text.TextUtils;
import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
@@ -63,8 +65,10 @@ import com.android.settingslib.applications.AppUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access). * Detailed settings for an app's directory access permissions (A.K.A Scoped Directory Access).
@@ -135,10 +139,9 @@ public class DirectoryAccessDetails extends AppInfoBase {
} }
final int count = cursor.getCount(); final int count = cursor.getCount();
if (count == 0) { if (count == 0) {
if (DEBUG) { // This setting screen should not be reached if there was no permission, so just
Log.d(TAG, "No permissions for " + mPackageName); // ignore it
} Log.w(TAG, "No permissions for " + mPackageName);
// TODO(b/72055774): display empty message
return; return;
} }
@@ -162,7 +165,7 @@ 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(newPreference(context, dir, providerUri, prefsGroup.addPreference(newPreference(context, dir, providerUri,
/* uuid= */ null, dir, granted)); /* uuid= */ null, dir, granted, /* children= */ null));
} else { } else {
// External volume entry: save it for later. // External volume entry: save it for later.
ExternalVolume externalVolume = externalVolumes.get(uuid); ExternalVolume externalVolume = externalVolumes.get(uuid);
@@ -222,46 +225,55 @@ public class DirectoryAccessDetails extends AppInfoBase {
continue; continue;
} }
// First add the pref for the whole volume... // First add the pref for the whole volume...
// TODO(b/72055774): add separator final PreferenceCategory category = new PreferenceCategory(context);
prefsGroup.addPreference(newPreference(context, volumeName, providerUri, volume.uuid, prefsGroup.addPreference(category);
/* dir= */ null, volume.granted)); final Set<SwitchPreference> children = new HashSet<>(volume.children.size());
// TODO(b/72055774): make sure children are gone when parent is toggled on - should be category.addPreference(newPreference(context, volumeName, providerUri, volume.uuid,
// handled automatically if we're refreshing the activity on change, otherwise we'll /* dir= */ null, volume.granted, children));
// need to explicitly remove them
// ... then the children prefs // ... then the children prefs
volume.children.forEach((pair) -> { volume.children.forEach((pair) -> {
final String dir = pair.first; final String dir = pair.first;
final String name = context.getResources() final String name = context.getResources()
.getString(R.string.directory_on_volume, volumeName, dir); .getString(R.string.directory_on_volume, volumeName, dir);
prefsGroup final SwitchPreference childPref =
.addPreference(newPreference(context, name, providerUri, volume.uuid, newPreference(context, name, providerUri, volume.uuid, dir, pair.second,
dir, pair.second)); /* children= */ null);
category.addPreference(childPref);
children.add(childPref);
}); });
} }
} }
private SwitchPreference newPreference(Context context, String title, Uri providerUri, private SwitchPreference newPreference(Context context, String title, Uri providerUri,
String uuid, String dir, boolean granted) { String uuid, String dir, boolean granted, @Nullable Set<SwitchPreference> children) {
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(granted); pref.setChecked(granted);
pref.setOnPreferenceChangeListener((unused, value) -> { pref.setOnPreferenceChangeListener((unused, value) -> {
resetDoNotAskAgain(context, value, providerUri, uuid, dir); if (!Boolean.class.isInstance(value)) {
// Sanity check
Log.wtf(TAG, "Invalid value from switch: " + value);
return true;
}
final boolean newValue = ((Boolean) value).booleanValue();
resetDoNotAskAgain(context, newValue, providerUri, uuid, dir);
if (children != null) {
// When parent is granted, children should be hidden; and vice versa
final boolean newChildValue = !newValue;
for (SwitchPreference child : children) {
child.setVisible(newChildValue);
}
}
return true; return true;
}); });
return pref; return pref;
} }
private void resetDoNotAskAgain(Context context, Object value, Uri providerUri, private void resetDoNotAskAgain(Context context, boolean newValue, Uri providerUri,
@Nullable String uuid, @Nullable String directory) { @Nullable String uuid, @Nullable String directory) {
if (!Boolean.class.isInstance(value)) {
// Sanity check
Log.wtf(TAG, "Invalid value from switch: " + value);
return;
}
final boolean newValue = ((Boolean) value).booleanValue();
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Asking " + providerUri + " to update " + uuid + "/" + directory + " to " Log.d(TAG, "Asking " + providerUri + " to update " + uuid + "/" + directory + " to "
+ newValue); + newValue);