Android 13 introduces granular storage permissions and the photo picker tool for accessing media files
Table of Contents
Starting with Android 13, READ_EXTERNAL_STORAGE
permission has been deprecated in favor of better alternative APIs for accessing media files from Android storage. If your app targets Android 13 (API level 33) or higher and needs to access media files that other apps have created, you need to update the code to make use of the new set of APIs which are introduced with the Android 13 release
In this article, we will see two different approaches for accessing media files from Android storage. Which approach to choose depends on the use case and business requirements. Here are the 2 ways:
1. Photo picker (No permission Required):
This tool provides a way for users to select media files, without needing to grant access to their entire media library.
Use Case:
If your app only needs to access images, photos, and videos, you can consider using Android Photo Picker. Android system will take care of displaying the Media chooser UI
Photo picker has been backported to all Android devices having Android OS 11 and 12 (excluding Android Go devices), so users will get a uniform and standard experience on all the Android devices
Limitation:
Photo picker comes with a few limitations, e.g. it works only with Visual media types and not the Audio type
In the next section of this article, we will see the photo picker implementation
2. Request Granular Media Permission
Use Case:
While it is recommended to use the new photo picker over requesting access to all media files, your app may have a use case requiring this broad access (e.g. gallery photo backup). For these specific usages, new permissions are introduced that provide access to specific types of media files, including images, video, or audio
Starting from Target 13, you must request one or more of the following granular media permissions instead of the
READ_EXTERNAL_STORAGE permission:
READ_MEDIA_IMAGES
for accessing imagesREAD_MEDIA_VIDEO
for accessing videosREAD_MEDIA_AUDIO
for accessing audio files
Check out this decision tree to help you decide what approach to choose:
Now that we are clear on what approach to choose in which case, we will now look into the implementation details of both approaches
Photo Picker Implementation
The photo picker provides a browsable, searchable interface that presents the user with their media library, sorted by date from newest to oldest. This tool provides a safe, built-in way for users to select images and videos, without needing to grant your app access to their entire media library.
In addition, the “Albums” section lets users browse by helpful categories like Screenshots or Downloads. The photo picker is customizable by specifying if users should see only photos or only videos, or by setting a maximum number of items they can select.
The tool updates automatically, offering expanded functionality to your app’s users over time without requiring any code changes.
Implementation
To use the photo picker support library, include version 1.6.0 or higher of the
androidx.activity library. It’s a simple intent to be launched and it will use the photo picker when available and fallback to ACTION_OPEN_DOCUMENT on older devices:
The support library uses the following activity result contracts to launch the photo picker:
PickVisualMedia: To select a single image or video.
PickMultipleVisualMedia, to select multiple images or videos.
If the photo picker isn’t available on a device, the support library automatically invokes the ACTION_OPEN_DOCUMENT
intent action instead.
Select a single media item
To select a single media item, use the PickVisualMedia
activity result contract, as shown in the following code snippet:
// Registers a photo picker activity launcher in single-select mode. val pickMedia = registerForActivityResult(PickVisualMedia()) { uri -> // Callback is invoked after the user selects a media item or closes the // photo picker. if (uri != null) { Log.d("PhotoPicker", "Selected URI: $uri") } else { Log.d("PhotoPicker", "No media selected") } } // Include only one of the following calls to launch(), depending on the types // of media that you want to allow the user to choose from. // Launch the photo picker and allow the user to choose images and videos. pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo)) // Launch the photo picker and allow the user to choose only images. pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly)) // Launch the photo picker and allow the user to choose only videos. pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.VideoOnly)) // Launch the photo picker and allow the user to choose only images/videos of a // specific MIME type, such as GIFs. val mimeType = "image/gif" pickMedia.launch(PickVisualMediaRequest(PickVisualMedia.SingleMimeType(mimeType)))
Select multiple media items
To select multiple media items, set a maximum number of selectable media files, as shown in the following code snippet.
// Registers a photo picker activity launcher in multi-select mode. // In this example, the app allows the user to select up to 5 media files. val pickMultipleMedia = registerForActivityResult(PickMultipleVisualMedia(5)) { uris -> // Callback is invoked after the user selects media items or closes the // photo picker. if (uris.isNotEmpty()) { Log.d("PhotoPicker", "Number of items selected: ${uris.size}") } else { Log.d("PhotoPicker", "No media selected") } } // For this example, launch the photo picker and allow the user to choose images // and videos. If you want the user to select a specific type of media file, // use the overloaded versions of launch(), as shown in the section about how // to select a single media item. pickMultipleMedia.launch(PickVisualMediaRequest(PickVisualMedia.ImageAndVideo))
The platform limits the maximum number of files that you can ask the user to select in the photo picker. To access this limit, call
getPickImagesMaxLimit(). On devices where the photo picker isn’t supported, this limit is ignored.
You can verify whether the photo picker is available on a given device by calling
isPhotoPickerAvailable.
Persist media file access
By default, the system grants your app access to media files until the device is restarted or until your app stops. If your app performs some long-running work and needs to retain access to files for a longer period of time then you can call the
takePersistableUriPermission() method
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)
Granular media permissions
Starting in API level 33, if your app accesses other apps’ media files, don’t request READ_EXTERNAL_STORAGE
permission. Instead, request one or more of these permissions: READ_MEDIA_IMAGES
, READ_MEDIA_VIDEO
, READ_MEDIA_AUDIO
Implementation
To access media files that other apps have created, you must declare the appropriate storage-related permissions. The following code snippet demonstrates how to declare the appropriate storage permissions:
<!-- Required only if your app needs to access images or photos that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Required only if your app needs to access videos that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- Required only if your app needs to access audio files that other apps created. --> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- If your app doesn't need to access media files that other apps created, set the "maxSdkVersion" attribute to "28" instead. --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
If you request both the READ_MEDIA_IMAGES
permission and the READ_MEDIA_VIDEO
permission at the same time, only one system permission dialog appears.
If the user previously granted your app the READ_EXTERNAL_STORAGE
permission, the system automatically grants granular media permissions to your app.
I hope this article has helped you. If it did, don’t forget to add a comment below and share this article