Skip to content

Commit 4d11be4

Browse files
[image_picker] Don't store null paths in lost cache (#6678)
If the user cancels image selection on Android, store nothing in the lost image cache rather than storing an array with a null path. While we could potentially keep this behavior and instead handle it differently on the Dart side, returning some new "cancelled" `LostDataResponse`, that would be semi-breaking; e.g., the current example's lost data handling would actually throw as written if we had a new non-`isEmpty`, non-exception, null-`file` response. Since nobody has requested the ability to specifically detect a "lost cancel" as being different from not having started the process of picking anything, this doesn't make that potentially-client-breaking change. If it turns out there's a use case for that in the future, we can revisit that (but should not do it by storing a null entry in a file array anyway). Fixes flutter/flutter#114551
1 parent ca974ab commit 4d11be4

File tree

4 files changed

+40
-5
lines changed

4 files changed

+40
-5
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.5+4
2+
3+
* Fixes null cast exception when restoring a cancelled selection.
4+
15
## 0.8.5+3
26

37
* Updates minimum Flutter version to 2.10.

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import android.net.Uri;
1616
import android.os.Build;
1717
import android.provider.MediaStore;
18+
import androidx.annotation.Nullable;
1819
import androidx.annotation.VisibleForTesting;
1920
import androidx.core.app.ActivityCompat;
2021
import androidx.core.content.FileProvider;
@@ -621,11 +622,18 @@ private boolean setPendingMethodCallAndResult(
621622
return true;
622623
}
623624

624-
private void finishWithSuccess(String imagePath) {
625+
// Handles completion of selection with a single result.
626+
//
627+
// A null imagePath indicates that the image picker was cancelled without
628+
// selection.
629+
private void finishWithSuccess(@Nullable String imagePath) {
625630
if (pendingResult == null) {
626-
ArrayList<String> pathList = new ArrayList<>();
627-
pathList.add(imagePath);
628-
cache.saveResult(pathList, null, null);
631+
// Only save data for later retrieval if something was actually selected.
632+
if (imagePath != null) {
633+
ArrayList<String> pathList = new ArrayList<>();
634+
pathList.add(imagePath);
635+
cache.saveResult(pathList, null, null);
636+
}
629637
return;
630638
}
631639
pendingResult.success(imagePath);

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import static org.mockito.Mockito.doNothing;
1414
import static org.mockito.Mockito.doThrow;
1515
import static org.mockito.Mockito.mock;
16+
import static org.mockito.Mockito.never;
1617
import static org.mockito.Mockito.times;
1718
import static org.mockito.Mockito.verify;
1819
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -275,6 +276,16 @@ public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() {
275276
verifyNoMoreInteractions(mockResult);
276277
}
277278

279+
@Test
280+
public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() {
281+
ImagePickerDelegate delegate = createDelegate();
282+
283+
delegate.onActivityResult(
284+
ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_CANCELED, null);
285+
286+
verify(cache, never()).saveResult(any(), any(), any());
287+
}
288+
278289
@Test
279290
public void
280291
onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_FinishesWithImagePath() {
@@ -287,6 +298,18 @@ public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() {
287298
verifyNoMoreInteractions(mockResult);
288299
}
289300

301+
@Test
302+
public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_StoresImageInCache() {
303+
ImagePickerDelegate delegate = createDelegate();
304+
305+
delegate.onActivityResult(
306+
ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
307+
308+
ArgumentCaptor<ArrayList<String>> pathListCapture = ArgumentCaptor.forClass(ArrayList.class);
309+
verify(cache, times(1)).saveResult(pathListCapture.capture(), any(), any());
310+
assertEquals("pathFromUri", pathListCapture.getValue().get(0));
311+
}
312+
290313
@Test
291314
public void
292315
onActivityResult_WhenImagePickedFromGallery_AndResizeNeeded_FinishesWithScaledImagePath() {

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/plugins/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.5+3
5+
version: 0.8.5+4
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"

0 commit comments

Comments
 (0)