Skip to content

Commit 9056c1c

Browse files
gmackallTecHaxter
authored andcommitted
[image_picker_android] Refactor getting of paths from intent to single helper (flutter#5009)
Fixes flutter/flutter#104168
1 parent c46230a commit 9056c1c

File tree

4 files changed

+95
-58
lines changed

4 files changed

+95
-58
lines changed

packages/image_picker/image_picker_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.8.12+1
2+
3+
* Fixes another app crash case on Android 12+, and refactors getting of paths from intents.
4+
15
## 0.8.12
26

37
* Fixes app crashes on Android 12+ caused by selecting images with size 0.

packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -638,24 +638,57 @@ public boolean onActivityResult(
638638
return true;
639639
}
640640

641-
private void handleChooseImageResult(int resultCode, Intent data) {
642-
if (resultCode == Activity.RESULT_OK && data != null) {
643-
Uri uri = data.getData();
644-
// On several pre-Android 13 devices using Android Photo Picker, the Uri from getData() could be null.
645-
if (uri == null) {
646-
ClipData clipData = data.getClipData();
647-
if (clipData != null && clipData.getItemCount() == 1) {
648-
uri = clipData.getItemAt(0).getUri();
641+
@Nullable
642+
private ArrayList<MediaPath> getPathsFromIntent(@NonNull Intent data, boolean includeMimeType) {
643+
ArrayList<MediaPath> paths = new ArrayList<>();
644+
645+
Uri uri = data.getData();
646+
// On several pre-Android 13 devices using Android Photo Picker, the Uri from getData() could
647+
// be null.
648+
if (uri == null) {
649+
ClipData clipData = data.getClipData();
650+
651+
// If data.getData() and data.getClipData() are both null, we are in an error state. By
652+
// convention we return null from here, and then finish with an error from the corresponding
653+
// handler.
654+
if (clipData == null) {
655+
return null;
656+
}
657+
658+
for (int i = 0; i < data.getClipData().getItemCount(); i++) {
659+
uri = data.getClipData().getItemAt(i).getUri();
660+
// Same error state as above.
661+
if (uri == null) {
662+
return null;
663+
}
664+
String path = fileUtils.getPathFromUri(activity, uri);
665+
// Again, same error state as above.
666+
if (path == null) {
667+
return null;
649668
}
669+
String mimeType = includeMimeType ? activity.getContentResolver().getType(uri) : null;
670+
paths.add(new MediaPath(path, mimeType));
671+
}
672+
} else {
673+
String path = fileUtils.getPathFromUri(activity, uri);
674+
if (path == null) {
675+
return null;
650676
}
677+
paths.add(new MediaPath(path, null));
678+
}
679+
return paths;
680+
}
681+
682+
private void handleChooseImageResult(int resultCode, Intent data) {
683+
if (resultCode == Activity.RESULT_OK && data != null) {
684+
ArrayList<MediaPath> paths = getPathsFromIntent(data, false);
651685
// If there's no valid Uri, return an error
652-
if (uri == null) {
686+
if (paths == null) {
653687
finishWithError("no_valid_image_uri", "Cannot find the selected image.");
654688
return;
655689
}
656690

657-
String path = fileUtils.getPathFromUri(activity, uri);
658-
handleImageResult(path, false);
691+
handleMediaResult(paths);
659692
return;
660693
}
661694

@@ -683,20 +716,13 @@ public MediaPath(@NonNull String path, @Nullable String mimeType) {
683716

684717
private void handleChooseMediaResult(int resultCode, Intent intent) {
685718
if (resultCode == Activity.RESULT_OK && intent != null) {
686-
ArrayList<MediaPath> paths = new ArrayList<>();
687-
if (intent.getClipData() != null) {
688-
for (int i = 0; i < intent.getClipData().getItemCount(); i++) {
689-
Uri uri = intent.getClipData().getItemAt(i).getUri();
690-
String path = fileUtils.getPathFromUri(activity, uri);
691-
String mimeType = activity.getContentResolver().getType(uri);
692-
paths.add(new MediaPath(path, mimeType));
693-
}
694-
} else {
695-
Uri uri = intent.getData();
696-
if (uri != null) {
697-
paths.add(new MediaPath(fileUtils.getPathFromUri(activity, uri), null));
698-
}
719+
ArrayList<MediaPath> paths = getPathsFromIntent(intent, true);
720+
// If there's no valid Uri, return an error
721+
if (paths == null) {
722+
finishWithError("no_valid_media_uri", "Cannot find the selected media.");
723+
return;
699724
}
725+
700726
handleMediaResult(paths);
701727
return;
702728
}
@@ -707,17 +733,14 @@ private void handleChooseMediaResult(int resultCode, Intent intent) {
707733

708734
private void handleChooseMultiImageResult(int resultCode, Intent intent) {
709735
if (resultCode == Activity.RESULT_OK && intent != null) {
710-
ArrayList<MediaPath> paths = new ArrayList<>();
711-
if (intent.getClipData() != null) {
712-
for (int i = 0; i < intent.getClipData().getItemCount(); i++) {
713-
paths.add(
714-
new MediaPath(
715-
fileUtils.getPathFromUri(activity, intent.getClipData().getItemAt(i).getUri()),
716-
null));
717-
}
718-
} else {
719-
paths.add(new MediaPath(fileUtils.getPathFromUri(activity, intent.getData()), null));
736+
ArrayList<MediaPath> paths = getPathsFromIntent(intent, false);
737+
// If there's no valid Uri, return an error
738+
if (paths == null) {
739+
finishWithError(
740+
"missing_valid_image_uri", "Cannot find at least one of the selected images.");
741+
return;
720742
}
743+
721744
handleMediaResult(paths);
722745
return;
723746
}
@@ -728,22 +751,14 @@ private void handleChooseMultiImageResult(int resultCode, Intent intent) {
728751

729752
private void handleChooseVideoResult(int resultCode, Intent data) {
730753
if (resultCode == Activity.RESULT_OK && data != null) {
731-
Uri uri = data.getData();
732-
// On several pre-Android 13 devices using Android Photo Picker, the Uri from getData() could be null.
733-
if (uri == null) {
734-
ClipData clipData = data.getClipData();
735-
if (clipData != null && clipData.getItemCount() == 1) {
736-
uri = clipData.getItemAt(0).getUri();
737-
}
738-
}
754+
ArrayList<MediaPath> paths = getPathsFromIntent(data, false);
739755
// If there's no valid Uri, return an error
740-
if (uri == null) {
756+
if (paths == null || paths.size() < 1) {
741757
finishWithError("no_valid_video_uri", "Cannot find the selected video.");
742758
return;
743759
}
744760

745-
String path = fileUtils.getPathFromUri(activity, uri);
746-
handleVideoResult(path);
761+
finishWithSuccess(paths.get(0).path);
747762
return;
748763
}
749764

@@ -774,7 +789,7 @@ private void handleCaptureVideoResult(int resultCode) {
774789
localPendingCameraMediaUrl != null
775790
? localPendingCameraMediaUrl
776791
: Uri.parse(cache.retrievePendingCameraMediaUriPath()),
777-
this::handleVideoResult);
792+
this::finishWithSuccess);
778793
return;
779794
}
780795

@@ -837,10 +852,6 @@ private void handleMediaResult(@NonNull ArrayList<MediaPath> paths) {
837852
}
838853
}
839854

840-
private void handleVideoResult(String path) {
841-
finishWithSuccess(path);
842-
}
843-
844855
private boolean setPendingOptionsAndResult(
845856
@Nullable ImageSelectionOptions imageOptions,
846857
@Nullable VideoSelectionOptions videoOptions,

packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,31 @@ public void onActivityResult_withUnknownRequest_returnsFalse() {
815815
}
816816

817817
@Test
818-
public void
819-
onActivityResult_whenImagePickedFromGallery_finishesWithEmptyListIfIntentDataIsNull() {
818+
public void onActivityResult_whenImagePickedFromGallery_finishesWithErrorIfClipDataIsNull() {
819+
when(mockIntent.getData()).thenReturn(null);
820+
when(mockIntent.getClipData()).thenReturn(null);
821+
822+
Mockito.doAnswer(
823+
invocation -> {
824+
((Runnable) invocation.getArgument(0)).run();
825+
return null;
826+
})
827+
.when(mockExecutor)
828+
.execute(any(Runnable.class));
829+
ImagePickerDelegate delegate =
830+
createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
831+
832+
delegate.onActivityResult(
833+
ImagePickerDelegate.REQUEST_CODE_CHOOSE_MEDIA_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
834+
835+
ArgumentCaptor<FlutterError> errorCaptor = ArgumentCaptor.forClass(FlutterError.class);
836+
verify(mockResult).error(errorCaptor.capture());
837+
assertEquals("no_valid_media_uri", errorCaptor.getValue().code);
838+
assertEquals("Cannot find the selected media.", errorCaptor.getValue().getMessage());
839+
}
840+
841+
@Test
842+
public void onActivityResult_whenImagePickedFromGallery_finishesWithErrorIfClipDataUriIsNull() {
820843
setupMockClipDataNullUri();
821844
when(mockIntent.getData()).thenReturn(null);
822845
when(mockIntent.getClipData()).thenReturn(null);
@@ -834,11 +857,10 @@ public void onActivityResult_withUnknownRequest_returnsFalse() {
834857
delegate.onActivityResult(
835858
ImagePickerDelegate.REQUEST_CODE_CHOOSE_MEDIA_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
836859

837-
@SuppressWarnings("unchecked")
838-
ArgumentCaptor<List<String>> pathListCapture = ArgumentCaptor.forClass(List.class);
839-
verify(mockResult).success(pathListCapture.capture());
840-
assertEquals(0, pathListCapture.getValue().size());
841-
verifyNoMoreInteractions(mockResult);
860+
ArgumentCaptor<FlutterError> errorCaptor = ArgumentCaptor.forClass(FlutterError.class);
861+
verify(mockResult).error(errorCaptor.capture());
862+
assertEquals("no_valid_media_uri", errorCaptor.getValue().code);
863+
assertEquals("Cannot find the selected media.", errorCaptor.getValue().getMessage());
842864
}
843865

844866
private ImagePickerDelegate createDelegate() {

packages/image_picker/image_picker_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: image_picker_android
22
description: Android implementation of the image_picker plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/image_picker/image_picker_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
5-
version: 0.8.12
5+
version: 0.8.12+1
66

77
environment:
88
sdk: ^3.3.0

0 commit comments

Comments
 (0)