Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/image_picker/image_picker_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.8.13+16

* Fixes gallery image/video selection on Android API 36+ returning no paths when
`useAndroidPhotoPicker` was false. The plugin now uses the Android Photo Picker on API 36 and
above regardless of that flag, avoiding a broken `ACTION_GET_CONTENT` result from the system UI.

## 0.8.13+15

* Updates build files from Groovy to Kotlin.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ public void chooseMediaFromGallery(

private void launchPickMediaFromGalleryIntent(Messages.GeneralOptions generalOptions) {
Intent pickMediaIntent;
if (generalOptions.getUsePhotoPicker()) {
if (ImagePickerUtils.effectiveUsePhotoPicker(generalOptions.getUsePhotoPicker())) {
if (generalOptions.getAllowMultiple()) {
int limit = ImagePickerUtils.getLimitFromOption(generalOptions);

Expand Down Expand Up @@ -342,7 +342,7 @@ public void chooseVideoFromGallery(

private void launchPickVideoFromGalleryIntent(Boolean usePhotoPicker) {
Intent pickVideoIntent;
if (usePhotoPicker) {
if (ImagePickerUtils.effectiveUsePhotoPicker(usePhotoPicker)) {
pickVideoIntent =
new ActivityResultContracts.PickVisualMedia()
.createIntent(
Expand Down Expand Up @@ -441,7 +441,7 @@ public void chooseMultiImageFromGallery(

private void launchPickImageFromGalleryIntent(Boolean usePhotoPicker) {
Intent pickImageIntent;
if (usePhotoPicker) {
if (ImagePickerUtils.effectiveUsePhotoPicker(usePhotoPicker)) {
pickImageIntent =
new ActivityResultContracts.PickVisualMedia()
.createIntent(
Expand All @@ -458,7 +458,7 @@ private void launchPickImageFromGalleryIntent(Boolean usePhotoPicker) {

private void launchMultiPickImageFromGalleryIntent(Boolean usePhotoPicker, int limit) {
Intent pickMultiImageIntent;
if (usePhotoPicker) {
if (ImagePickerUtils.effectiveUsePhotoPicker(usePhotoPicker)) {
pickMultiImageIntent =
new ActivityResultContracts.PickMultipleVisualMedia(limit)
.createIntent(
Expand Down Expand Up @@ -490,7 +490,7 @@ public void chooseMultiVideoFromGallery(

private void launchMultiPickVideoFromGalleryIntent(Boolean usePhotoPicker, int limit) {
Intent pickMultiVideoIntent;
if (usePhotoPicker) {
if (ImagePickerUtils.effectiveUsePhotoPicker(usePhotoPicker)) {
pickMultiVideoIntent =
new ActivityResultContracts.PickMultipleVisualMedia(limit)
.createIntent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.util.Arrays;

final class ImagePickerUtils {
private static final int API_LEVEL_36 = 36;

/** returns true, if permission present in manifest, otherwise false */
private static boolean isPermissionPresentInManifest(Context context, String permissionName) {
try {
Expand Down Expand Up @@ -86,4 +88,22 @@ static int getLimitFromOption(Messages.GeneralOptions generalOptions) {

return effectiveLimit;
}

/**
* Returns whether gallery/media selection should use {@link
* androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia} (Android Photo
* Picker) instead of {@link android.content.Intent#ACTION_GET_CONTENT}.
*
* <p>On Android API 36+, {@code ACTION_GET_CONTENT} for images may be handled by the system
* photo picker's {@code PhotopickerGetContentActivity}. That path combined with {@code
* startActivityForResult} can return {@link android.app.Activity#RESULT_OK} without {@link
* android.content.Intent#getData()} or usable {@link android.content.ClipData}, so the plugin
* would complete with no paths. The {@code PickVisualMedia} contract uses the Activity Result API
* and receives URIs reliably.
*
* <p>See <a href="https://github.com/flutter/flutter/issues/182071">flutter/flutter#182071</a>.
*/
static boolean effectiveUsePhotoPicker(boolean usePhotoPickerFromDart) {
return Build.VERSION.SDK_INT >= API_LEVEL_36 || usePhotoPickerFromDart;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package io.flutter.plugins.imagepicker;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
public class ImagePickerUtilsTest {

@Test
@Config(sdk = 35)
public void effectiveUsePhotoPicker_belowApi36_usesDartPreference() {
assertFalse(ImagePickerUtils.effectiveUsePhotoPicker(false));
assertTrue(ImagePickerUtils.effectiveUsePhotoPicker(true));
}

@Test
@Config(sdk = 36)
public void effectiveUsePhotoPicker_onApi36_alwaysUsesPhotoPicker() {
assertTrue(ImagePickerUtils.effectiveUsePhotoPicker(false));
assertTrue(ImagePickerUtils.effectiveUsePhotoPicker(true));
}
}
2 changes: 1 addition & 1 deletion packages/image_picker/image_picker_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: image_picker_android
description: Android implementation of the image_picker plugin.
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
version: 0.8.13+15
version: 0.8.13+16

environment:
sdk: ^3.9.0
Expand Down