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:
WRITE_EXTERNAL_STORAGEin your manifest allows access to all public directories on external storage, which might be more access than what your app needs.
Android 7.0 provides a simplified API to access common external storage directories.
StorageManager class to get the
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
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
createAccessIntent() to request access to the entire
volume, instead of a specific directory.
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.getPrimaryStorageVolume(); 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
with a result code of
RESULT_OK, and intent data that contains the URI. Use
the provided URI to access directory information, similar to using URIs
returned by the
Getting access to a specific external directory also gains access to subdirectories within that directory.
<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
MEDIA_MOUNTED notification. This notification
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
with the returned
takePersistableUriPermission() 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.