New Photo Picker API ( No permissions !)

Oğuzhan Aslan
6 min readOct 24, 2022
aImage from Unsplash

More and more applications are getting into our lives as the time goes by. It is for sure that trend of the applications is changing into more visual content. So, It is safe to say that asking users to select an image or video , or in other words visual content, is a common use-case for most of the applications. There are multiple ways to ask a user to pick a content from his/her gallery. In this article, I will show you new PhotoPicker API along with 2 old ways to implement such a behaviour in your applications.

Why there is a need for a new API ?

Previously accessing a media file stored in the device of the user has 3 ways basically.

1 — Access the External storage and read the media files

This way requires too much work just to implement a media file pick operation. You need to grant permission to read, Read the files with ContentResolver and implement your logic and so on.

I’m not going to get into details for simplicity but you can check here to learn more.

2 — Use a MediaStore media picker intent

You can use Intent.ACTION_PICK intent to open a picker.

Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)or Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)

We can now call Activity.startActivityForResult() to get the selected ones’ URIs (result will be sent to theActivity.onActivityResult()). Even further, we can create a custom launcher to implement this in a more modern way.

After you call the launch() method in this class, you will see such a screen and whenever the user is done by selecting ( image, video, etc ) , the selected URIs will be sent to the callback function of the contract. (To learn more about result contracts visit here.)

The strange thing is that normally MediaStore API requires read/write permissions, depending on the API version of the Android that it is working on. Even in the official documentations it is stated that :

To access media files that other apps have created, you must declare the appropriate storage-related permissions, and the files must reside in one of the following media collections:

MediaStore.Images

MediaStore.Video

MediaStore.Audio

As long as a file is viewable from the MediaStore.Images, MediaStore.Video, or MediaStore.Audio queries, it's also viewable using the MediaStore.Files query.

However, even if the contract I have mentioned above uses the MediaStore and accesses the media files that other apps have created. I did not face any issue with permission while I was testing the code. But, I have read that there may be permission problems in earlier versions of android ( API 23–24 etc. ).

3 — Use document picker intent

This may be the oldest way to ask the user to pick an image, a video, etc. You just need an intent such as this :

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)

And the rest is the same with the 2nd way. Similarly, we can create an activity result contract for this as well.

After you call the launch() method with this class, you will see such a screen

This way , on the other hand, for sure does not requires any permission because it uses Storage Access Framework internally.

All of these relatively old way requires a bit too much effort just to pick a couple of visual media files. Moreover, some of them requires permissions as well ( at least one of them does. ), which brings even more complexity into our code. Even more, With these older ways it is hard to limit user selection count, if not it is error prone since most of the params for the intents are just strings.

Due to these issues, we have a new API called PhotoPicker. The API is available on devices that meet the following criteria :

But do not worry the API is also compatible with older versions as well and requires any additional code.

Before Start

before we get any further, add be sure you have at least one of these dependencies depending on your development language.

// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

The activity_version here should be above 1.6.0 version.

And do not forget to target API 33.

android {
compileSdk 33

defaultConfig {
targetSdk 33
// rest of your code
}

The rest is really simple.

The API comes with 2 activity result contracts

I think names are pretty much self-explanatory, but I might add that both can be used for image and video picking. Additionally, PickMultipleVisualMedia requires an integer parameter which is the number of files that is required to be selected by the user.

Above, you can see an example usage of the contract in a compose project ( do not worry source code will be included at the end of this article.). After you add any of these contracts, you are free to ask the user to pick some images ( or videos ). Like this

As you might notice that the launch() method takes a PickVisualMediaRequest and that also request VisualMediaType . Currently there are 4 types are defined and these are

  • ImageOnly
  • VideoOnly
  • ImageAndVideo
  • SimpleMemeType

In the code above opens a bottom sheet like this

The UI might change slightly with other VisualMediaTypes but the general logic is the same. Similarly, when the user is done with the selection, the callback function of the launcher is called with the URI or URIs of the file(s) that is selected.

If you would remember I said that this API requires some criteria to work on a device. What happens when the device does not satisfy that ?

Well, no worries the API just invokes the ACTION_OPEN_DOCUMENT intent action instead ( remember the 2nd one of the older ways). So the document picking screen will show up, but this time we do not need an additional contract like we did previously but this time the API invokes the same callback function you have provided in the contract (PickVisualMedia or PickMultipleVisualMedia) .

You can also check whether or not the Photo Picker API is available. To do that, you can add this line to your code

ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable()

Footnotes

In the official documentation, it is stated that

By default, the system grants your app access to media files until the device is restarted or until your app stops.

Which means if you have a use-case that requires long running time. You need the access for a longer period of time. To do that so, add this line whenever you get the URI or whenever you need the access time to be longer.

val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
context.contentResolver.takePersistableUriPermission(uri, flag)

All in all, This is the basics of the new Photo Picker API. I hope you will use the API in your applications and I also hope you have enjoyed this article. Do not forget to stay tuned for the upcoming articles.

Love you all.

Stay tuned for upcoming blogs.

Take care.

Linkedin

--

--