Some issues when using the PhotoPicker with PickVisualMediaRequest

John 6
3 min readSep 20, 2023

Previously our APP imported images through request permission and customized UI, after the Photo Picker was released on Android 13, I tried to switch to it but came across some problems, here’s the record.

PhotoPicker Demo

1. Do not support minimal image count limit.

This is hurtful, I gave up using the PhotoPicker due to this, and I have started an issue to track this.

2. Can not change the image count limits after registered (by default)

To use the new PhotoPicker, we need to register an ActivityResultLauncher like this:

val contract = ActivityResultContracts.PickMultipleVisualMedia(maxItems)
mPickVisualMediaLauncher = componentActivity.registerForActivityResult(contract) {
// TODO
}

And the maxItems is an immutable variable, after this launcher is registered, it can not be changed. Someone may think of unregistering first and then registering again to do that, yeah, I did that too. But ActivityResultLauncher does not allow that, or else we get an APP crash caused by this:

java.lang.IllegalStateException: LifecycleOwner DemoActivity@6bd8ed9 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
at androidx.activity.result.ActivityResultRegistry.register(ActivityResultRegistry.java:123)
at androidx.activity.ComponentActivity.registerForActivityResult(ComponentActivity.java:859)

— — —

After work, I suddenly realized that we could change the maxItems at any time by creating our own PickMultipleVisualMedia since the ActivityResultContract.createIntent gets called every time the ActivityResultLauncher.launch function is invoked.

since the ActivityResultContract.createIntent gets called every time the ActivityResultLauncher.launch function is invoked
The createIntent function gets called by ComponentActivity.mActivityResultRegistry.onLaunch

I decide not to change our implementation on the old Android versions, which means I only use the PhotoPicker above Android 12, so that I don’t need GMS to have a fallback. And it worked really well.

/**
* Implementation of [ActivityResultContracts.GetMultipleContents] that allows the caller to change maxItems at anytime
*/
class CustomPickMultipleVisualMedia(private var maxItems:Int):ActivityResultContracts.PickMultipleVisualMedia(maxItems){
fun updateMaxItems(newMaxItems:Int){
maxItems = newMaxItems
}
override fun createIntent(context: Context, input: PickVisualMediaRequest): Intent {
return super.createIntent(context, input).apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
"maxItems: $maxItems".log()
putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxItems)
}
}
}
}

— — — —

This morning I talked to my co-worker about this PhotoPicker stuff, he said that a transparent Activity to do that too, just a little bit silly though.

3. Can not customize the UI

What I want to do is enable EdgeToEdge to the Picker, but after reading the source code, I think it’s not possible to do that from the APP side.

From the log, we can see the PhotoPicker is actually an Activity owned by the system itself, which is named PhotoPickerActivity.

13:52:25.060 ActivityTaskManager             system_server             I  Displayed com.google.android.providers.media.module/com.android.providers.media.photopicker.PhotoPickerActivity: +62ms

It does get affected by the theme named PickerMaterialTheme, but that theme is declared in the Android framework, so there’s no way to change that.

 getTheme().applyStyle(R.style.PickerMaterialTheme, /* force */ false);

4. PickMultipleVisualMedia do not support maxItems = 1

This is odd, I say we have to use PickVisualMedia instead. And here’s the error that I came across.

11:23:25.159 PhotoPickerActivity             com...iders.media.module  E  Finish activity due to an exception while parsing extras
java.lang.IllegalArgumentException: Invalid EXTRA_PICK_IMAGES_MAX value
at com.android.providers.media.photopicker.data.Selection.parseSelectionValuesFromIntent(Selection.java:200)
at com.android.providers.media.photopicker.viewmodel.PickerViewModel.parseValuesFromIntent(PickerViewModel.java:402)
at com.android.providers.media.photopicker.PhotoPickerActivity.onCreate(PhotoPickerActivity.java:169)
at android.app.Activity.performCreate(Activity.java:8595)
at android.app.Activity.performCreate(Activity.java:8573)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)

--

--