page.title=Scoped Directory Access page.keywords=preview,sdk,scoped directory access page.tags=androidn @jd:body
Apps such as photo apps usually just need access to specific directories in
external storage, such as the Pictures
directory. Existing
approaches to accessing external storage aren't designed to easily provide
targeted directory access for these types of apps. For example:
Android N provides a new simplified API to access common external storage directories.
Use the StorageManager
class to get the appropriate
StorageVolume
instance. Then, create an intent by calling the
StorageVolume.createAccessIntent()
method of that instance.
Use this intent to access external storage directories. To get a list of
all available volumes, including removable media volumes, use
StorageManager.getVolumesList()
.
If you have information about a specific file, use
StorageManager.getStorageVolume(File)
to get the
StorageVolume
that contains the file. Call
createAccessIntent()
on this StorageVolume
to access
the external storage directory for the file.
On secondary volumes, such as external SD cards, pass in null when calling
StorageVolume.createAccessIntent()
to request access to the entire
volume, instead of a specific directory.
StorageVolume.createAccessIntent()
returns null if you pass in
null to the primary volume, or if you pass in an invalid directory name.
The following code snippet is an example of how to open the
Pictures
directory in the primary shared storage:
StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE); StorageVolume volume = sm.getPrimaryVolume(); Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code);
The system attempts to grant access to the external directory, and if necessary confirms access with the user using a simplified UI:
If the user grants access, the system calls your
onActivityResult()
override with a result code of
Activity.RESULT_OK
, and intent data that contains the URI. Use
the provided URI to access directory information, similar to using URIs
returned by the
Storage
Access Framework.
If the user doesn't grant access, the system calls your
onActivityResult()
override with a result code of
Activity.RESULT_CANCELED
, and null intent data.
Note: Getting access to a specific external directory also gains access to subdirectories within that directory.
To use Scoped Directory Access to access directories on removable media, first add a {@link android.content.BroadcastReceiver} that listens for the {@link android.os.Environment#MEDIA_MOUNTED} notification, for example:
<receiver android:name=".MediaMountedReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.MEDIA_MOUNTED" /> <data android:scheme="file" /> </intent-filter> </receiver>
When the user mounts removable media, like an SD card, the system sends a
{@link android.os.Environment#MEDIA_MOUNTED} notification. This notification
provides a StorageVolume
object in the intent data that you can
use to access directories on the removable media. The following example
accesses the Pictures
directory on removable media:
// BroadcastReceiver has already cached the MEDIA_MOUNTED // notification Intent in mediaMountedIntent StorageVolume volume = (StorageVolume) mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME); volume.createAccessIntent(Environment.DIRECTORY_PICTURES); startActivityForResult(intent, request_code);
Where possible, persist the external directory access URI so you don't have
to repeatedly ask the user for access. Once the user has granted access, call
getContentResolver().takePersistableUriPermssion()
with the
directory access URI. The system will persist the URI and subsequent access
requests will return RESULT_OK
and not show confirmation UI to the
user.
If the user denies access to an external directory, do not immediately request access again. Repeatedly insisting on access results in a poor user experience. If a request is denied by the user, and the app requests access again, the UI displays a Don't ask again checkbox:
If the user selects Don't ask again and denies the request, all future requests for the given directory from your app will be automatically denied, and no request UI will be presented to the user.