Android 13 (API 33) introduces a new tool called photo picker 🖼. Today, we will learn how to integrate this into android applications.
It provides a browsable, searchable interface that presents the user with their media library, sorted by date 📆.
Note from official docs:
Upcoming Google Play system updates are expected to include new features related to the photo picker. In one such update, the library will add support for apps that target Android 11 (API level 30) or higher (excluding Android Go devices).
Major features
- Safe, and a built-in method for users to select media files(photos/videos)
- No permissions are required 💃
Media selection limit
- By default maximum number of
media selections allowed
is set to 1.
🛑 During development, I found weird behavior when defining the maximum number 1, it immediately fails with
RESULT_CANCELED(0) 🤯
- No need to worry we can modify it 😊
Provide the limit using the putExtra() method of
I
ntent
EXTRA_PICK_IMAGES_MAX // "android.provider.extra.PICK_IMAGES_MAX" | |
Example | |
Intent(MediaStore.ACTION_PICK_IMAGES).apply { | |
putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 2) // deafult is 1 | |
} |
ℹ️ There is a platform limit on the largest number
that needs to be respected when we specify the maximum number of files
.
MediaStore.getPickImagesMaxLimit()
provides that limit.
val maxLimit = MediaStore.getPickImagesMaxLimit() |
The photo picker opens in half-screen mode when the maximum is set to 1
- Photo picker screenshot
Left side (default limit 1), Right side (when the limit is more than 1)
Restricting MimeType
- By default, the photo picker displays both photos 🖼 and videos 📹
- No need to worry we can restrict it to photos or videos only 😊
Provide the MimeType
by using the setType() method of
Intent
Intent(MediaStore.ACTION_PICK_IMAGES).apply { | |
type = "image/*" | |
// only videos | |
type = "video/*" | |
} |
Let’s code it
- XML-based UI, Photo picker, and ActivityResult API
// create ActivityResultContract | |
val getContent = | |
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> | |
result?.let { nonNullableResult -> | |
when (nonNullableResult.resultCode == RESULT_OK) { | |
true -> { | |
val intent = nonNullableResult.data | |
intent?.data?.let { uri -> | |
// process data | |
} | |
} | |
false -> { | |
} | |
} | |
} | |
} | |
// launch the intent on button click | |
binding.fab.setOnClickListener { | |
Log.d(TAG, "onCreate:${MediaStore.getPickImagesMaxLimit()}") | |
val intent = Intent(MediaStore.ACTION_PICK_IMAGES).apply { | |
type = "image/*" | |
} | |
getContent.launch(intent) | |
} | |
- Compose, Photo picker, and ActivityResult API
@Composable | |
fun PhotoPickerResultComposable() { | |
var result by rememberSaveable { mutableStateOf<Uri?>(null) } | |
val launcher = | |
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { | |
result = it.data?.data | |
} | |
Column( | |
verticalArrangement = Arrangement.Center, | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
OpenPhotoPicker(openLauncher = { launcher.launch(photoIntent) }) | |
AsyncImage( | |
model = result, | |
contentDescription = "Image from photo picker", | |
contentScale = ContentScale.Crop, | |
modifier = Modifier | |
.size(200.dp, 200.dp) | |
.clip(CircleShape) | |
) | |
} | |
} |
Job Offers
Demo
Demo with maximum limit 1
Check the full code here
References
https://developer.android.com/about/versions/13/features/photopicker
https://developer.android.com/about/versions/13
https://android-developers.googleblog.com/2022/06/android-13-beta-3-platform-stability.html
😊😊 👏👏👏👏 HAPPY CODING 👏👏👏👏 😊😊
Stay in touch
This article was originally published on proandroiddev.com on June 10, 2022