[MUSIC PLAYING]
Hi.
My name is Lisa Wray, and I'm on the Developer Relations team
at Google.
Today, I'm going to be talking about the storage access
framework in KitKat.
Specifically, the client app side.
In our last episode about the storage access framework,
we saw the new system documents UI
that lets the user of your app browse content
from all apps on the device that share documents.
Today, we're going to walk through how to launch the UI
and how to handle the results in your app.
There's more to it than there used to be.
New in Android KitKat are document editing,
writing, and saving in place, and document creation
and deletion.
Here's a quick picture of the flow.
As you can see, document providers and clients
don't interact directly, just as before.
A client requests permission to interact with files, read,
edit, create, et cetera.
The system picker goes to each registered provider
and shows the user the matching content.
Finally, the user selects a document,
and the system grants the client app permissions just
for that URI.
Let's talk about ACTION_OPEN_DOCUMENT.
This isn't much different than what you may have done before.
You're going to create an intent.
CATEGORY_OPENABLE means we only want
results that can be opened-- basically
documents-- as opposed to a list of contacts or time zones.
The type is the document MIME type you want.
Here, I'm asking for any type of image.
And then launch your intent with a request code.
This can be any value you like, but it
should be unique within your app.
And we've launched the file picker.
Next, the user selects a document,
and it's back to your app.
Retrieving a URI is also the same as before.
We get a callback in onActivityResult.
We check the request code matches,
and the result came back OK.
Now, we don't get back the specific document directly,
here.
We get a URI pointing to it using intent getData.
If you've done this before with the getContent or pick intents,
nothing's changed.
And this might look familiar too.
With a URI, we can get metadata about the image.
Here this query applies to only one document,
and we want all the rows, so that's
what all those nulls are for.
Here I'm getting its display name-- note
that this is not the same as its file name-- and its size.
You can't count on getting a reliable size for a document,
because it might be stored remotely, for example.
So always check that it isn't null before you try
and get the size.
But forget metadata.
You probably want to open this image.
Here's a shortcut.
You can use ContentResolver openFileDescriptor.
You pass in the URI and the access mode you want,
and you get back a parcelFileDescriptor,
which is a wrapper around a FileDescriptor.
For images, there's a handy method
in BitmapFactory, decodeFileDescriptor.
Don't do this on the UI thread.
Do in the background.
Use an async task.
There's an example of this in the storage client sample code
that we're posting.
And finally, it's best practice to wrap the close in a try
finally block, so it's guaranteed to close.
And then you can set this image to an image view.
And here it is.
Now wait, you're saying, I want to do something else,
or I don't have an image.
Easy.
You can get an inputStream from the ContentResolver
and do whatever you want with it.
Here I'm reading the lines of my file into a string.
So here's a new one.
We weren't able to do this before.
You can get an outputStream from the ContentResolver.
By default, it uses write mode.
You want to ask for the least amount of access you need,
so don't ask for read/write if all you need is write.
When I'm done, I just let the document provider
know I'm done by closing the stream, which
you have to do anyway.
Simple.
So we could open one document before.
What about lots of documents at the same time?
All you have to do to let the user select multiples
is add EXTRA_ALLOW_MULTIPLE to your intent.
If you want, you can specify multiple MIME types.
This time we get back clip data.
It's then stored in intent getClipData,
and you can get the URIs using clipData getItems and then
item getUri.
Note that you still have to check
intent getData, the same as a single URI,
because if the user picks just one document,
it doesn't matter if you allowed multiple selection,
it's still coming back the first way, in intent getData.
So you have to check both.
Creating a document is also new in Android KitKat,
and it's really straightforward.
You give your intent a MIME type, a file name,
and you launch it with a unique request code.
The rest is taken care of for you.
You get back its URI in onActivityResult, and that way,
you can continue to write to it or whatever else you want.
And deleting a document is even easier.
You can't launch an intent to delete a document,
but if you have its URI, which you would
if you've opened or created it, then you can ask to delete it,
and DocumentsContract does this for you.
Again, in a document's metadata, you
can check document column flags.
If that contains support delete, you'll
know whether to enable or disable
your Delete button or Menu option.
One more thing to mention.
When you open a file for reading or writing,
the system gives you a URI permission grant for that file.
It lasts until your device restarts.
However, you might want to access
that file again directly from your applications.
Say you're an image editing app, and you
want to show the user the last five images they've edited.
If the device is turned off in the meantime,
you won't have access to those.
You could send the user back to the document picker,
but that's far from ideal.
Instead, you can persist the permissions
the system gave you.
Now they'll last no matter whether the phone is
turned off or on.
The system won't do this automatically for you.
Your app has to explicitly request
that the permissions be persisted.
This is a security measure, though, so it's a good thing.
One last note.
You may have saved the most recent URIs your app accessed,
but you should still always use ContentResolver.getPersistedUriPermissions
to check that you have the freshest data.
Other applications could delete documents,
apps could be removed, so make this check
to make sure your data's right.
That's all for now.
Hope you enjoyed learning about the new storage access
features in Android KitKat.
Thanks for watching, and happy document sharing.