Have you ever had a requirement where users can select photos or videos from their gallery, well in order to support such kind of functionality it was important to ask permission from the user to access media files.
What’s changing now?
A permission-less approach to select media files where the app will only have access to those images which user is selecting instead of getting access to all the media files (images/videos)
PickVisualMedia
When you want the user to select a single media file then you may use the PickVisualMedia, it will return the Uri that you can use later on to display that media on screen.
Let’s see the codebase with respect to Jetpack Compose by adding such capability through the composable
val mediaPicker = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickVisualMedia(), onResult = { uri -> imageUri = uri })
Use the Activity Result API to define the contract as ActivityResultContracts.PickVisualMedia(), once user select the media you will get the uri in onResult lambda
The next step is to convert URI to bitmap, this is purely optional you can even use URI with coil library.
//This logic is only for image not for video LaunchedEffect(key1 = imageUri) { imageUri?.let { uri -> bitmap = if (Build.VERSION.SDK_INT < 28) { MediaStore.Images .Media.getBitmap(localContext.contentResolver,uri) } else { val source = ImageDecoder .createSource(localContext.contentResolver,uri) ImageDecoder.decodeBitmap(source) } } }
Finally to show the selected image you may set the bitmap to Image composable.
Image(bitmap = bitmap.asImageBitmap(), contentDescription = "Selected image")
Here bitmap is a nullable mutable state object like below
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
Now the final question is how to start the experience so that user can select images or videos from the gallery.
On a button click you may use the object defined using the Activity Result API for us its “mediaPicker” and call the launch() method.
Select only Image
Button(onClick = { mediaPicker .launch(PickVisualMediaRequest( ActivityResultContracts.PickVisualMedia.ImageOnly ) )} ) { Text(text = "Pick image only") }
Select only video
Button(onClick = { mediaPicker .launch(PickVisualMediaRequest( ActivityResultContracts.PickVisualMedia.VideoOnly ) )} ) { Text(text = "Pick video only") }
Select an image or video
Button(onClick = { mediaPicker .launch(PickVisualMediaRequest( ActivityResultContracts.PickVisualMedia.ImageAndVideo ) )} ) { Text(text = "Pick image or video") }
Job Offers
In a similar way when you want users to select multiple images or videos then instead of “ActivityResultContracts.PickVisualMedia()” you may use “PickMultipleVisualMedia()”
val mediaPicker = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickMultipleVisualMedia(), onResult = { uriList -> //handle list of Uris })
With ActivityX 1.7.0 release, the Photo Picker support library will use a back-ported version provided by Google Play services on devices running Android KitKat (4.4) and later.
To enable back-ported photo picker, add the following service to the Manifest file
<service android:name="com.google.android.gms.metadata.ModuleDependencies" android:enabled="false" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" /> </intent-filter> <meta-data android:name="photopicker_activity:0:required" android:value="" /> </service>
That’s it, with those little steps, you have added support for picking media files from the gallery without explicitly asking for permission.
This article was previously published on proandroiddev.com