Be Careful with Scoped Directory Access

Android 7.0 added scoped directory access. This API allows you to ask the user for blanket access to a common public directory on an arbitrary StorageVolume , such as a USB OTG drive or other removable storage. If the user grants access, you get a Uri back, akin to as if you had used ACTION_OPEN_DOCUMENT_TREE and the user happened to have chosen that particular directory. The difference is that you are choosing the directory, from a list of candidates, rather than granting the user full freedom to choose any directory or other “document tree” that the user wants.

However, there is a UX flaw with scoped directory access.

The flow of the permission dialogs resembles that of Android 6.0’s runtime permissions:

When you first ask for access, the user can allow or deny

If the user denied access, and you later ask for access again, the dialog now has a “Don’t ask again” checkbox

If the user checked that checkbox and denied access again, any future attempts you make to request access will be denied immediately, without the user seeing a dialog

One problem is that we have no good way of knowing that the user has previously denied our request, let alone checked the “Don’t ask again” checkbox. With Android 6.0’s runtime permissions, we have checkSelfPermission() and shouldShowPermissionRequestRationale() for those things. We have no equivalents for scoped directory access.

However, the bigger problem is that once the user checks “Don’t ask again” and denies access, the user has no further recourse. With runtime permissions, the user can always go into the Permissions area of your app’s page in Settings and manually grant permissions. There is no equivalent of this for the scoped directory access API.

On one device (a Nexus 5X running the 7.1 preview), the user can use “Clear Data” to reset these dialogs, causing future dialogs to appear again even if “Don’t ask again” had been checked. Of course, “Clear Data” has somewhat broader impact than this, and the user might not appreciate wiping out all the app’s local data.

Worse, on two test devices (a Nexus 5X running 7.0 and a Google Pixel running 7.1), not only does “Clear Data” not fix this, but a full uninstall of the app does not fix this. AFAICT, nothing short of a factory reset would allow the app to ask the user for permission and the user have an opportunity again to grant permission.

Admitttedly, this is an edge case, but it is one that you should keep in mind if you are using createAccessIntent() and the scoped directory access API. I filed this issue to try to get some resolution to how the user is supposed to manually revert the “Don’t ask again” status.

Nervous about how the newest version of Android affects your app? Consider subscribing, then asking questions in the office hours chats!

— Nov 18, 2016