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:
@@ -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);
|
||||||
|
Reference in New Issue
Block a user