SAFFAQ: The Storage Access Framework FAQ
Given the impending demise of
you have two primary means of getting access to documents that your
app wishes to use:
Have other apps push
Urivalues to you, via activities in your app with
<intent-filter>elements for common operations, such as
Urivalues into your app – akin to using “file open” or “file save” dialogs – via the Storage Access Framework
With that in mind, here are some fictionally-asked questions about using the Storage Access Framework.
How Do I Ask the User for a Document?
On API Level 19+ devices, create an
with a MIME type indicating what sort of document you want,
CATEGORY_OPENABLE as a category. Start
startActivityForResult(). If you get
Uri in the delivered
Intent will point
to the document in question. Then, you can use
DocumentFile, and kin to work with the document,
as I outlined in an earlier blog post.
Why Do People Seem All Angst-y About This, Then?
Well, there are issues.
First is the API Level 19+ requirement. Some developers are already
up to a
minSdkVersion of 19 or higher, but plenty of others are not.
The fallback mechanism is
ACTION_GET_CONTENT and a MIME type.
Google, in its infinite wisdom, thinks that the UI presented by the Storage Access Framework should be optimized for things like Google Drive. As a result, the user has to know to do a bunch of clicks to actually get to where their files are (what we call external storage, what the user calls internal storage).
If you need long-term access to the document, beyond just your current
process, you need to use
takePersistableUriPermission() to try to
get that long-term access. However, you may not get it, because it
may not be offered. At the same time, though, you may lose access to the
document for other reasons (e.g., the user deleted it), so this should
not be a huge impediment.
What If I Want a Wide Range of Possible MIME Types?
EXTRA_MIME_TYPES on the
Intent, as a
String of concrete
or wildcard MIME types.
What If I Want a Bunch of Documents at Once?
EXTRA_ALLOW_MULTIPLE to the
with a value of
true. Now, instead of getting a single
you may get back several
Uri values. You access these through the
ClipData object you get by calling
getClipData() on the
getItemCount() on the
tells you how many documents the user opened, and
(for a value of
i) gives you the
Uri for that position
What If I Want to Create a Document?
ACTION_CREATE_DOCUMENT instead of
ACTION_OPEN_DOCUMENT, and make
sure that you use a concrete MIME type (e.g.,
Otherwise, it works the same as with
ACTION_OPEN_DOCUMENT: you get a
Uri back representing the newly-created document, and you can use
ContentResolver to get an
OutputStream onto which you can write your
What If I Want to Create a Bunch of Documents?
If the “bunch of documents” can (or should) reside in one directory,
ACTION_OPEN_DOCUMENT_TREE on API Level 21+ devices. This amounts
to a “directory picker”. You get a
Uri back representing a tree
of documents, and you can use methods on
DocumentFile to create
new documents in that directory.
What If I Want to Create a Bunch of Documents on Older Devices?
ACTION_CREATE_DOCUMENT several times, on API Level 19+
What If I Want to Create a Bunch of Documents on Seriously Old Devices?
There is no great way that I can think of to accomplish this through
Intents and such.
How Do I Delete a Document?
delete() on a
DocumentFile for the document. That, in turn,
calls the static
deleteDocument() method on
How Do I Delete a Directory?
delete() on the
DocumentFile. I do not know if this
is supported, but it is worth a shot.
Why Do We Have to BLEEEEEEEEEEEEEEEP With All This?
Partly, the reason is security. Privacy advocates have been complaining for years about how apps can run around and mess with everything on external storage, causing various issues. For example, apps with read access to external storage can examine photos for geotags; coupled with the photo’s timestamp, you now know where the user was at the time that the photo was taken. Hence, over the years, Google has been progressively tightening down Android with respect to file access.
Partly, the reason is that the documents the user wants may not necessarily be on external storage, and so developers who fixate on local files will harm the broader Android ecosystem.
For example, if Android on Chrome OS continues to expand, external storage for ARC apps is not the Chromebook’s hard drive. Rather, it is more like the external storage for an emulator, accessible only by apps and through development tools. Worse, the current ARC environment has each app walled off in its own AVD-style container, so one app cannot access another app’s external storage. Presumably, the vision is for apps to be using the Storage Access Framework, where the ARC environment can bridge between the Android app and the Chrome OS file areas that Chromebook users are used to working with.
Similarly, if we start seeing Android more in desktop-style settings,
desktops in an organization often rely upon a file server, such as a
Windows SMB server. Android can offer access to that via the Storage
Access Framework, as an SMB server is not significantly different than
is Google Drive from the standpoint of Android. However, once again, this
requires developers to start thinking in terms of documents identified
Uri values, more so than thinking purely about local
Need an extra hand with your Android app development project? CommonsWare can help — reach out for details!