From 623aa3bdc181a0c89ad93af33192e20d67e0b868 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 13:28:21 +0200 Subject: [PATCH 1/3] Fix image picker crash when cache directory is deleted. --- .../imagepicker/ImagePickerDelegate.java | 1 + .../imagepicker/ImagePickerDelegateTest.java | 95 ++++++++++++------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index c4a686f5ce13..8b904f5d769d 100644 --- a/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -401,6 +401,7 @@ private File createTemporaryWritableFile(String suffix) { File image; try { + externalFilesDirectory.mkdirs(); image = File.createTempFile(filename, suffix, externalFilesDirectory); } catch (IOException e) { throw new RuntimeException(e); diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index f8be66833b17..03da0b246075 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -155,11 +155,18 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); + + delegate.takeImageWithCamera(mockMethodCall, mockResult); + + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + } } @Test @@ -169,11 +176,18 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); + + delegate.takeImageWithCamera(mockMethodCall, mockResult); + + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + } } @Test @@ -195,17 +209,18 @@ public void takeImageWithCamera_WritesImageToCacheDirectory() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - MockedStatic mockStaticFile = Mockito.mockStatic(File.class); - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); + try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); - ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + ImagePickerDelegate delegate = createDelegate(); + delegate.takeImageWithCamera(mockMethodCall, mockResult); - mockStaticFile.verify( - () -> File.createTempFile(any(), eq(".jpg"), eq(new File("/image_picker_cache"))), - times(1)); + mockStaticFile.verify( + () -> File.createTempFile(any(), eq(".jpg"), eq(new File("/image_picker_cache"))), + times(1)); + } } @Test @@ -225,32 +240,44 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr public void onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() { when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); - delegate.onRequestPermissionsResult( - ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION, - new String[] {Manifest.permission.CAMERA}, - new int[] {PackageManager.PERMISSION_GRANTED}); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA)); + try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); + + delegate.onRequestPermissionsResult( + ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION, + new String[] {Manifest.permission.CAMERA}, + new int[] {PackageManager.PERMISSION_GRANTED}); + + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA)); + } } @Test public void onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() { when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); - delegate.onRequestPermissionsResult( - ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, - new String[] {Manifest.permission.CAMERA}, - new int[] {PackageManager.PERMISSION_GRANTED}); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); + + delegate.onRequestPermissionsResult( + ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, + new String[] {Manifest.permission.CAMERA}, + new int[] {PackageManager.PERMISSION_GRANTED}); + + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); + } } @Test @@ -380,7 +407,7 @@ private ImagePickerDelegate createDelegate() { private ImagePickerDelegate createDelegateWithPendingResultAndMethodCall() { return new ImagePickerDelegate( mockActivity, - null, + new File("/image_picker_cache"), mockImageResizer, mockResult, mockMethodCall, From e37b075fcbf07b5b8daf30c6d5aad3211a65fb75 Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 13:34:45 +0200 Subject: [PATCH 2/3] Update pubspec and changelog --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ packages/image_picker/image_picker/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 8385aff7e48c..0e49912b4ed4 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.1+3 + +* Fix image picker causing a crash when the cache directory is deleted. + ## 0.8.1+2 * Update the example app to support the multi-image feature. diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 620d118142fb..bcda757b4bbf 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.1+2 +version: 0.8.1+3 environment: sdk: ">=2.12.0 <3.0.0" From 952c088598dbafd96fc3edf2c9942437fad28b5b Mon Sep 17 00:00:00 2001 From: "Bodhi Mulders (BeMacized)" Date: Wed, 30 Jun 2021 15:38:27 +0200 Subject: [PATCH 3/3] Implemented PR feedback --- .../imagepicker/ImagePickerDelegateTest.java | 102 +++++++----------- 1 file changed, 41 insertions(+), 61 deletions(-) diff --git a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index 03da0b246075..1b55a7569eac 100644 --- a/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker/example/android/app/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -23,6 +23,7 @@ import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import java.io.File; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -47,6 +48,7 @@ public class ImagePickerDelegateTest { @Mock ImagePickerCache cache; ImagePickerDelegate.FileUriResolver mockFileUriResolver; + MockedStatic mockStaticFile; private static class MockFileUriResolver implements ImagePickerDelegate.FileUriResolver { @Override @@ -64,6 +66,11 @@ public void getFullImagePath(Uri imageUri, ImagePickerDelegate.OnPathReadyListen public void setUp() { MockitoAnnotations.initMocks(this); + mockStaticFile = Mockito.mockStatic(File.class); + mockStaticFile + .when(() -> File.createTempFile(any(), any(), any())) + .thenReturn(new File("/tmpfile")); + when(mockActivity.getPackageName()).thenReturn("com.example.test"); when(mockActivity.getPackageManager()).thenReturn(mock(PackageManager.class)); @@ -87,6 +94,11 @@ public void setUp() { when(mockIntent.getData()).thenReturn(mockUri); } + @After + public void tearDown() { + mockStaticFile.close(); + } + @Test public void whenConstructed_setsCorrectFileProviderName() { ImagePickerDelegate delegate = createDelegate(); @@ -155,18 +167,11 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); + delegate.takeImageWithCamera(mockMethodCall, mockResult); - try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); - - delegate.takeImageWithCamera(mockMethodCall, mockResult); - - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); - } + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); } @Test @@ -176,18 +181,11 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); + delegate.takeImageWithCamera(mockMethodCall, mockResult); - try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); - - delegate.takeImageWithCamera(mockMethodCall, mockResult); - - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); - } + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); } @Test @@ -209,18 +207,12 @@ public void takeImageWithCamera_WritesImageToCacheDirectory() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); - - ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + ImagePickerDelegate delegate = createDelegate(); + delegate.takeImageWithCamera(mockMethodCall, mockResult); - mockStaticFile.verify( - () -> File.createTempFile(any(), eq(".jpg"), eq(new File("/image_picker_cache"))), - times(1)); - } + mockStaticFile.verify( + () -> File.createTempFile(any(), eq(".jpg"), eq(new File("/image_picker_cache"))), + times(1)); } @Test @@ -240,44 +232,32 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr public void onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() { when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); - - try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); - delegate.onRequestPermissionsResult( - ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION, - new String[] {Manifest.permission.CAMERA}, - new int[] {PackageManager.PERMISSION_GRANTED}); + ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + delegate.onRequestPermissionsResult( + ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION, + new String[] {Manifest.permission.CAMERA}, + new int[] {PackageManager.PERMISSION_GRANTED}); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA)); - } + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA)); } @Test public void onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() { when(mockIntentResolver.resolveActivity(any(Intent.class))).thenReturn(true); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); - - try (MockedStatic mockStaticFile = Mockito.mockStatic(File.class)) { - mockStaticFile - .when(() -> File.createTempFile(any(), any(), any())) - .thenReturn(new File("/tmpfile")); - delegate.onRequestPermissionsResult( - ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, - new String[] {Manifest.permission.CAMERA}, - new int[] {PackageManager.PERMISSION_GRANTED}); + ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + delegate.onRequestPermissionsResult( + ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, + new String[] {Manifest.permission.CAMERA}, + new int[] {PackageManager.PERMISSION_GRANTED}); - verify(mockActivity) - .startActivityForResult( - any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); - } + verify(mockActivity) + .startActivityForResult( + any(Intent.class), eq(ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA)); } @Test