From 2ac876945bfb388fed8b796c6d8c8e7f2e97f0d4 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 29 Mar 2016 19:06:02 -0700 Subject: [PATCH] Minor tweaks on Scoped Directory Access: - Only allow entire directory access on non-primary volumes. - Do not display primary storage label on scoped access. BUG: 27743842 BUG: 27676858 Change-Id: I9884fb1e2df3534fceebc5d5bef44adfb758724c --- .../android/os/storage/StorageVolume.java | 41 +++++++++++-------- packages/DocumentsUI/res/values/strings.xml | 3 ++ .../OpenExternalDirectoryActivity.java | 15 ++++++- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index c028e150b2179..7b0d2a4797024 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -315,27 +315,34 @@ public final class StorageVolume implements Parcelable { * To gain access to descendants (child, grandchild, etc) documents, use * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)}, or * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI. - * - * If your application only needs to store internal data, consider using + *

+ * If your application only needs to store internal data, consider using * {@link Context#getExternalFilesDirs(String) Context.getExternalFilesDirs}, - * {@link Context#getExternalCacheDirs()}, or - * {@link Context#getExternalMediaDirs()}, which require no permissions to read or write. - * - * NOTE: requesting access to the entire volume is not recommended and it will - * result in a stronger message displayed to the user, which may cause the user to reject - * the request. - * - * @param directoryName must be one of - * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS}, - * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS}, - * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES}, - * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS}, - * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}, or - * {code null} to request access to the entire volume. + * {@link Context#getExternalCacheDirs()}, or {@link Context#getExternalMediaDirs()}, which + * require no permissions to read or write. + *

+ * Access to the entire volume is only available for non-primary volumes (for the primary + * volume, apps can use the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} and + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions) and should be used + * with caution, since users are more likely to deny access when asked for entire volume access + * rather than specific directories. * + * @param directoryName must be one of {@link Environment#DIRECTORY_MUSIC}, + * {@link Environment#DIRECTORY_PODCASTS}, {@link Environment#DIRECTORY_RINGTONES}, + * {@link Environment#DIRECTORY_ALARMS}, {@link Environment#DIRECTORY_NOTIFICATIONS}, + * {@link Environment#DIRECTORY_PICTURES}, {@link Environment#DIRECTORY_MOVIES}, + * {@link Environment#DIRECTORY_DOWNLOADS}, {@link Environment#DIRECTORY_DCIM}, or + * {@link Environment#DIRECTORY_DOCUMENTS}, or {code null} to request access to the + * entire volume. + * @return intent to request access, or {@code null} if the requested directory is invalid for + * that volume. * @see DocumentsContract */ - public Intent createAccessIntent(String directoryName) { + public @Nullable Intent createAccessIntent(String directoryName) { + if ((isPrimary() && directoryName == null) || + (directoryName != null && !Environment.isStandardDirectory(directoryName))) { + return null; + } final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY); intent.putExtra(EXTRA_STORAGE_VOLUME, this); intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName); diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index b26ee9778d332..fb557caf84f2a 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -204,6 +204,9 @@ Grant ^1 access to ^2 directory on ^3? + + Grant ^1 + access to ^2 directory? Grant ^1 access to your data, including photos and videos, on ^2? diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java index 2fe2756e91691..854be0bee826f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java @@ -86,6 +86,7 @@ public class OpenExternalDirectoryActivity extends Activity { private static final String EXTRA_VOLUME_LABEL = "com.android.documentsui.VOLUME_LABEL"; private static final String EXTRA_VOLUME_UUID = "com.android.documentsui.VOLUME_UUID"; private static final String EXTRA_IS_ROOT = "com.android.documentsui.IS_ROOT"; + private static final String EXTRA_IS_PRIMARY = "com.android.documentsui.IS_PRIMARY"; // Special directory name representing the full volume static final String DIRECTORY_ROOT = "ROOT_DIRECTORY"; @@ -157,6 +158,13 @@ public class OpenExternalDirectoryActivity extends Activity { Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory " + directoryName + ", and user " + userId); final boolean isRoot = directoryName.equals(DIRECTORY_ROOT); + final boolean isPrimary = storageVolume.isPrimary(); + + if (isRoot && isPrimary) { + if (DEBUG) Log.d(TAG, "root access requested on primary volume"); + return false; + } + final File volumeRoot = storageVolume.getPathFile(); File file; try { @@ -235,6 +243,7 @@ public class OpenExternalDirectoryActivity extends Activity { args.putString(EXTRA_VOLUME_UUID, volumeUuid); args.putString(EXTRA_APP_LABEL, appLabel); args.putBoolean(EXTRA_IS_ROOT, isRoot); + args.putBoolean(EXTRA_IS_PRIMARY, isPrimary); final FragmentManager fm = activity.getFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); @@ -352,6 +361,7 @@ public class OpenExternalDirectoryActivity extends Activity { private String mVolumeLabel; private String mAppLabel; private boolean mIsRoot; + private boolean mIsPrimary; private CheckBox mDontAskAgain; private OpenExternalDirectoryActivity mActivity; private AlertDialog mDialog; @@ -367,6 +377,7 @@ public class OpenExternalDirectoryActivity extends Activity { mVolumeLabel = args.getString(EXTRA_VOLUME_LABEL); mAppLabel = args.getString(EXTRA_APP_LABEL); mIsRoot = args.getBoolean(EXTRA_IS_ROOT); + mIsPrimary= args.getBoolean(EXTRA_IS_PRIMARY); } mActivity = (OpenExternalDirectoryActivity) getActivity(); } @@ -435,7 +446,9 @@ public class OpenExternalDirectoryActivity extends Activity { message = TextUtils.expandTemplate(getText( R.string.open_external_dialog_root_request), mAppLabel, mVolumeLabel); } else { - message = TextUtils.expandTemplate(getText(R.string.open_external_dialog_request), + message = TextUtils.expandTemplate( + getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume + : R.string.open_external_dialog_request), mAppLabel, directory, mVolumeLabel); } final TextView messageField = (TextView) view.findViewById(R.id.message);