From 44da036b8c12a2850d29dabeb4479994a9512a48 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 9 Mar 2023 15:32:20 -0500 Subject: [PATCH 1/6] Move MethodCall out of ImagePickerCache --- .../imagepicker/ImageOutputOptions.java | 25 ++++++++++++++++ .../plugins/imagepicker/ImagePickerCache.java | 29 +++++-------------- .../imagepicker/ImagePickerDelegate.java | 8 ++++- .../imagepicker/ImagePickerCacheTest.java | 14 +++------ 4 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java new file mode 100644 index 00000000000..3349c3cf0c9 --- /dev/null +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java @@ -0,0 +1,25 @@ +package io.flutter.plugins.imagepicker; + +import androidx.annotation.Nullable; + +/** Stores settings for image output options. */ +public class ImageOutputOptions { + /** The maximum width of the image, if the width should be constrained. */ + @Nullable final Double maxWidth; + /** The maximum height of the image, if the width should be constrained. */ + @Nullable final Double maxHeight; + /** + * The output quality of the image, as a number from 0 to 100. + * + *

Defaults to 100. + */ + final int quality; + + public ImageOutputOptions( + @Nullable Double maxWidth, @Nullable Double maxHeight, @Nullable Integer quality) { + this.maxWidth = maxWidth; + this.maxHeight = maxHeight; + // Treat any invalid value as full quality. + this.quality = quality == null || quality < 0 || quality > 100 ? 100 : quality; + } +} diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java index 983dbabf66c..2b5c41b790b 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java @@ -9,7 +9,6 @@ import android.net.Uri; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import io.flutter.plugin.common.MethodCall; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -67,30 +66,16 @@ private void setType(String type) { prefs.edit().putString(SHARED_PREFERENCE_TYPE_KEY, type).apply(); } - void saveDimensionWithMethodCall(MethodCall methodCall) { - Double maxWidth = methodCall.argument(MAP_KEY_MAX_WIDTH); - Double maxHeight = methodCall.argument(MAP_KEY_MAX_HEIGHT); - int imageQuality = - methodCall.argument(MAP_KEY_IMAGE_QUALITY) == null - ? 100 - : (int) methodCall.argument(MAP_KEY_IMAGE_QUALITY); - - setMaxDimension(maxWidth, maxHeight, imageQuality); - } - - private void setMaxDimension(Double maxWidth, Double maxHeight, int imageQuality) { + void saveDimensionWithOutputOptions(ImageOutputOptions options) { SharedPreferences.Editor editor = prefs.edit(); - if (maxWidth != null) { - editor.putLong(SHARED_PREFERENCE_MAX_WIDTH_KEY, Double.doubleToRawLongBits(maxWidth)); - } - if (maxHeight != null) { - editor.putLong(SHARED_PREFERENCE_MAX_HEIGHT_KEY, Double.doubleToRawLongBits(maxHeight)); + if (options.maxWidth != null) { + editor.putLong(SHARED_PREFERENCE_MAX_WIDTH_KEY, Double.doubleToRawLongBits(options.maxWidth)); } - if (imageQuality > -1 && imageQuality < 101) { - editor.putInt(SHARED_PREFERENCE_IMAGE_QUALITY_KEY, imageQuality); - } else { - editor.putInt(SHARED_PREFERENCE_IMAGE_QUALITY_KEY, 100); + if (options.maxHeight != null) { + editor.putLong( + SHARED_PREFERENCE_MAX_HEIGHT_KEY, Double.doubleToRawLongBits(options.maxHeight)); } + editor.putInt(SHARED_PREFERENCE_IMAGE_QUALITY_KEY, options.quality); editor.apply(); } diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index 8f89e05276c..dc09b47a0cc 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -211,8 +211,14 @@ void saveStateBeforeResult() { return; } + ImageOutputOptions outputOptions = + new ImageOutputOptions( + methodCall.argument("maxWidth"), + methodCall.argument("maxHeight"), + methodCall.argument("imageQuality")); + cache.saveTypeWithMethodCallName(methodCall.method); - cache.saveDimensionWithMethodCall(methodCall); + cache.saveDimensionWithOutputOptions(outputOptions); if (pendingCameraMediaUri != null) { cache.savePendingCameraMediaUriPath(pendingCameraMediaUri); } diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java index 7d871665978..4b915f283a5 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java @@ -4,7 +4,6 @@ package io.flutter.plugins.imagepicker; -import static io.flutter.plugins.imagepicker.ImagePickerCache.MAP_KEY_IMAGE_QUALITY; import static io.flutter.plugins.imagepicker.ImagePickerCache.SHARED_PREFERENCES_NAME; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; @@ -16,7 +15,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import io.flutter.plugin.common.MethodCall; import java.util.HashMap; import java.util.Map; import org.junit.After; @@ -26,12 +24,9 @@ import org.mockito.MockitoAnnotations; public class ImagePickerCacheTest { - private static final int IMAGE_QUALITY = 90; - @Mock Activity mockActivity; @Mock SharedPreferences mockPreference; @Mock SharedPreferences.Editor mockEditor; - @Mock MethodCall mockMethodCall; static Map preferenceStorage; @@ -107,15 +102,14 @@ public void tearDown() throws Exception { @Test public void ImageCache_ShouldBeAbleToSetAndGetQuality() { - when(mockMethodCall.argument(MAP_KEY_IMAGE_QUALITY)).thenReturn(IMAGE_QUALITY); + final int quality = 90; ImagePickerCache cache = new ImagePickerCache(mockActivity); - cache.saveDimensionWithMethodCall(mockMethodCall); + cache.saveDimensionWithOutputOptions(new ImageOutputOptions(null, null, quality)); Map resultMap = cache.getCacheMap(); int imageQuality = (int) resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); - assertThat(imageQuality, equalTo(IMAGE_QUALITY)); + assertThat(imageQuality, equalTo(quality)); - when(mockMethodCall.argument(MAP_KEY_IMAGE_QUALITY)).thenReturn(null); - cache.saveDimensionWithMethodCall(mockMethodCall); + cache.saveDimensionWithOutputOptions(new ImageOutputOptions(null, null, null)); Map resultMapWithDefaultQuality = cache.getCacheMap(); int defaultImageQuality = (int) resultMapWithDefaultQuality.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); From 12041c3a6c3305f30d992c7ef1ef853603618b7b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 10 Mar 2023 11:47:29 -0500 Subject: [PATCH 2/6] Remove MethodCall from delegate --- .../imagepicker/ImageOutputOptions.java | 4 +- .../plugins/imagepicker/ImagePickerCache.java | 19 ++- .../imagepicker/ImagePickerDelegate.java | 121 ++++++++---------- .../imagepicker/ImagePickerPlugin.java | 28 +++- .../plugins/imagepicker/ImageResizer.java | 18 +-- .../plugins/imagepicker/VideoOptions.java | 12 ++ .../imagepicker/ImagePickerDelegateTest.java | 113 ++++++++-------- .../imagepicker/ImagePickerPluginTest.java | 73 +++++++---- .../plugins/imagepicker/ImageResizerTest.java | 28 ++-- 9 files changed, 228 insertions(+), 188 deletions(-) create mode 100644 packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java index 3349c3cf0c9..44567afb9f8 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java @@ -5,9 +5,9 @@ /** Stores settings for image output options. */ public class ImageOutputOptions { /** The maximum width of the image, if the width should be constrained. */ - @Nullable final Double maxWidth; + @Nullable public final Double maxWidth; /** The maximum height of the image, if the width should be constrained. */ - @Nullable final Double maxHeight; + @Nullable public final Double maxHeight; /** * The output quality of the image, as a number from 0 to 100. * diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java index 2b5c41b790b..86e314d44e0 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerCache.java @@ -16,6 +16,10 @@ import java.util.Set; class ImagePickerCache { + public enum CacheType { + IMAGE, + VIDEO + } static final String MAP_KEY_PATH = "path"; static final String MAP_KEY_PATH_LIST = "pathList"; @@ -52,17 +56,18 @@ class ImagePickerCache { prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); } - void saveTypeWithMethodCallName(String methodCallName) { - if (methodCallName.equals(ImagePickerPlugin.METHOD_CALL_IMAGE) - | methodCallName.equals(ImagePickerPlugin.METHOD_CALL_MULTI_IMAGE)) { - setType("image"); - } else if (methodCallName.equals(ImagePickerPlugin.METHOD_CALL_VIDEO)) { - setType("video"); + void saveType(CacheType type) { + switch (type) { + case IMAGE: + setType("image"); + break; + case VIDEO: + setType("video"); + break; } } private void setType(String type) { - prefs.edit().putString(SHARED_PREFERENCE_TYPE_KEY, type).apply(); } diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index dc09b47a0cc..4b75f715e0e 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -17,11 +17,11 @@ import android.provider.MediaStore; import androidx.activity.result.PickVisualMediaRequest; import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.app.ActivityCompat; import androidx.core.content.FileProvider; -import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry; import java.io.File; @@ -115,8 +115,9 @@ interface OnPathReadyListener { } private Uri pendingCameraMediaUri; - private MethodChannel.Result pendingResult; - private MethodCall methodCall; + private @Nullable ImageOutputOptions pendingImageOptions; + private @Nullable VideoOptions pendingVideoOptions; + private @Nullable MethodChannel.Result pendingResult; public ImagePickerDelegate( final Activity activity, @@ -129,6 +130,7 @@ public ImagePickerDelegate( imageResizer, null, null, + null, cache, new PermissionManager() { @Override @@ -179,8 +181,9 @@ public void onScanCompleted(String path, Uri uri) { final Activity activity, final File externalFilesDirectory, final ImageResizer imageResizer, - final MethodChannel.Result result, - final MethodCall methodCall, + final @Nullable ImageOutputOptions pendingImageOptions, + final @Nullable VideoOptions pendingVideoOptions, + final @Nullable MethodChannel.Result result, final ImagePickerCache cache, final PermissionManager permissionManager, final FileUriResolver fileUriResolver, @@ -189,8 +192,9 @@ public void onScanCompleted(String path, Uri uri) { this.externalFilesDirectory = externalFilesDirectory; this.imageResizer = imageResizer; this.fileProviderName = activity.getPackageName() + ".flutter.image_provider"; + this.pendingImageOptions = pendingImageOptions; + this.pendingVideoOptions = pendingVideoOptions; this.pendingResult = result; - this.methodCall = methodCall; this.permissionManager = permissionManager; this.fileUriResolver = fileUriResolver; this.fileUtils = fileUtils; @@ -207,18 +211,17 @@ CameraDevice getCameraDevice() { // Save the state of the image picker so it can be retrieved with `retrieveLostImage`. void saveStateBeforeResult() { - if (methodCall == null) { + if (pendingResult == null) { return; } - ImageOutputOptions outputOptions = - new ImageOutputOptions( - methodCall.argument("maxWidth"), - methodCall.argument("maxHeight"), - methodCall.argument("imageQuality")); - - cache.saveTypeWithMethodCallName(methodCall.method); - cache.saveDimensionWithOutputOptions(outputOptions); + cache.saveType( + pendingImageOptions != null + ? ImagePickerCache.CacheType.IMAGE + : ImagePickerCache.CacheType.VIDEO); + if (pendingImageOptions != null) { + cache.saveDimensionWithOutputOptions(pendingImageOptions); + } if (pendingCameraMediaUri != null) { cache.savePendingCameraMediaUriPath(pendingCameraMediaUri); } @@ -234,10 +237,8 @@ void retrieveLostImage(MethodChannel.Result result) { for (String path : pathList) { Double maxWidth = (Double) resultMap.get(ImagePickerCache.MAP_KEY_MAX_WIDTH); Double maxHeight = (Double) resultMap.get(ImagePickerCache.MAP_KEY_MAX_HEIGHT); - int imageQuality = - resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY) == null - ? 100 - : (int) resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); + Integer boxedImageQuality = (Integer) resultMap.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY); + int imageQuality = boxedImageQuality == null ? 100 : boxedImageQuality; newPathList.add(imageResizer.resizeImageIfNeeded(path, maxWidth, maxHeight, imageQuality)); } @@ -252,18 +253,13 @@ void retrieveLostImage(MethodChannel.Result result) { cache.clear(); } - public void chooseVideoFromGallery(MethodCall methodCall, MethodChannel.Result result) { - if (!setPendingMethodCallAndResult(methodCall, result)) { + public void chooseVideoFromGallery( + VideoOptions options, boolean usePhotoPicker, MethodChannel.Result result) { + if (!setPendingOptionsAndResult(null, options, result)) { finishWithAlreadyActiveError(result); return; } - Boolean usePhotoPicker = methodCall.argument("useAndroidPhotoPicker"); - - if (usePhotoPicker == null) { - usePhotoPicker = false; - } - launchPickVideoFromGalleryIntent(usePhotoPicker); } @@ -285,8 +281,8 @@ private void launchPickVideoFromGalleryIntent(Boolean useAndroidPhotoPicker) { activity.startActivityForResult(pickVideoIntent, REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY); } - public void takeVideoWithCamera(MethodCall methodCall, MethodChannel.Result result) { - if (!setPendingMethodCallAndResult(methodCall, result)) { + public void takeVideoWithCamera(VideoOptions options, MethodChannel.Result result) { + if (!setPendingOptionsAndResult(null, options, result)) { finishWithAlreadyActiveError(result); return; } @@ -303,8 +299,8 @@ public void takeVideoWithCamera(MethodCall methodCall, MethodChannel.Result resu private void launchTakeVideoWithCameraIntent() { Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - if (this.methodCall != null && this.methodCall.argument("maxDuration") != null) { - int maxSeconds = this.methodCall.argument("maxDuration"); + if (this.pendingVideoOptions != null && this.pendingVideoOptions.maxDuration != null) { + int maxSeconds = this.pendingVideoOptions.maxDuration; intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, maxSeconds); } if (cameraDevice == CameraDevice.FRONT) { @@ -332,33 +328,23 @@ private void launchTakeVideoWithCameraIntent() { } } - public void chooseImageFromGallery(MethodCall methodCall, MethodChannel.Result result) { - if (!setPendingMethodCallAndResult(methodCall, result)) { + public void chooseImageFromGallery( + @NonNull ImageOutputOptions options, boolean usePhotoPicker, MethodChannel.Result result) { + if (!setPendingOptionsAndResult(options, null, result)) { finishWithAlreadyActiveError(result); return; } - Boolean usePhotoPicker = methodCall.argument("useAndroidPhotoPicker"); - - if (usePhotoPicker == null) { - usePhotoPicker = false; - } - launchPickImageFromGalleryIntent(usePhotoPicker); } - public void chooseMultiImageFromGallery(MethodCall methodCall, MethodChannel.Result result) { - if (!setPendingMethodCallAndResult(methodCall, result)) { + public void chooseMultiImageFromGallery( + @NonNull ImageOutputOptions options, boolean usePhotoPicker, MethodChannel.Result result) { + if (!setPendingOptionsAndResult(options, null, result)) { finishWithAlreadyActiveError(result); return; } - Boolean usePhotoPicker = methodCall.argument("useAndroidPhotoPicker"); - - if (usePhotoPicker == null) { - usePhotoPicker = false; - } - launchMultiPickImageFromGalleryIntent(usePhotoPicker); } @@ -401,8 +387,9 @@ private void launchMultiPickImageFromGalleryIntent(Boolean useAndroidPhotoPicker pickMultiImageIntent, REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY); } - public void takeImageWithCamera(MethodCall methodCall, MethodChannel.Result result) { - if (!setPendingMethodCallAndResult(methodCall, result)) { + public void takeImageWithCamera( + @NonNull ImageOutputOptions options, MethodChannel.Result result) { + if (!setPendingOptionsAndResult(options, null, result)) { finishWithAlreadyActiveError(result); return; } @@ -625,10 +612,10 @@ public void onPathReady(String path) { private void handleMultiImageResult( ArrayList paths, boolean shouldDeleteOriginalIfScaled) { - if (methodCall != null) { + if (pendingImageOptions != null) { ArrayList finalPath = new ArrayList<>(); for (int i = 0; i < paths.size(); i++) { - String finalImagePath = getResizedImagePath(paths.get(i)); + String finalImagePath = getResizedImagePath(paths.get(i), pendingImageOptions); //delete original file if scaled if (finalImagePath != null @@ -645,8 +632,8 @@ private void handleMultiImageResult( } private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) { - if (methodCall != null) { - String finalImagePath = getResizedImagePath(path); + if (pendingImageOptions != null) { + String finalImagePath = getResizedImagePath(path, pendingImageOptions); //delete original file if scaled if (finalImagePath != null && !finalImagePath.equals(path) && shouldDeleteOriginalIfScaled) { new File(path).delete(); @@ -657,25 +644,25 @@ private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled } } - private String getResizedImagePath(String path) { - Double maxWidth = methodCall.argument("maxWidth"); - Double maxHeight = methodCall.argument("maxHeight"); - Integer imageQuality = methodCall.argument("imageQuality"); - - return imageResizer.resizeImageIfNeeded(path, maxWidth, maxHeight, imageQuality); + private String getResizedImagePath(String path, @NonNull ImageOutputOptions outputOptions) { + return imageResizer.resizeImageIfNeeded( + path, outputOptions.maxWidth, outputOptions.maxHeight, outputOptions.quality); } private void handleVideoResult(String path) { finishWithSuccess(path); } - private boolean setPendingMethodCallAndResult( - MethodCall methodCall, MethodChannel.Result result) { + private boolean setPendingOptionsAndResult( + @Nullable ImageOutputOptions imageOptions, + @Nullable VideoOptions videoOptions, + @NonNull MethodChannel.Result result) { if (pendingResult != null) { return false; } - this.methodCall = methodCall; + pendingImageOptions = imageOptions; + pendingVideoOptions = videoOptions; pendingResult = result; // Clean up cache if a new image picker is launched. @@ -699,7 +686,7 @@ private void finishWithSuccess(@Nullable String imagePath) { return; } pendingResult.success(imagePath); - clearMethodCallAndResult(); + clearOptionsAndResult(); } private void finishWithListSuccess(ArrayList imagePaths) { @@ -708,7 +695,7 @@ private void finishWithListSuccess(ArrayList imagePaths) { return; } pendingResult.success(imagePaths); - clearMethodCallAndResult(); + clearOptionsAndResult(); } private void finishWithAlreadyActiveError(MethodChannel.Result result) { @@ -721,11 +708,11 @@ private void finishWithError(String errorCode, String errorMessage) { return; } pendingResult.error(errorCode, errorMessage, null); - clearMethodCallAndResult(); + clearOptionsAndResult(); } - private void clearMethodCallAndResult() { - methodCall = null; + private void clearOptionsAndResult() { + pendingImageOptions = null; pendingResult = null; } diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java index a1ee1e2f404..4a4b3114c5b 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerPlugin.java @@ -351,31 +351,49 @@ public void onMethodCall(MethodCall call, MethodChannel.Result rawResult) { } delegate.setCameraDevice(device); } + + Boolean usePhotoPicker = call.argument("useAndroidPhotoPicker"); + if (usePhotoPicker == null) { + usePhotoPicker = false; + } + switch (call.method) { case METHOD_CALL_IMAGE: imageSource = call.argument("source"); + ImageOutputOptions imageOptions = + new ImageOutputOptions( + call.argument("maxWidth"), + call.argument("maxHeight"), + call.argument("imageQuality")); switch (imageSource) { case SOURCE_GALLERY: - delegate.chooseImageFromGallery(call, result); + delegate.chooseImageFromGallery(imageOptions, usePhotoPicker, result); break; case SOURCE_CAMERA: - delegate.takeImageWithCamera(call, result); + delegate.takeImageWithCamera(imageOptions, result); break; default: throw new IllegalArgumentException("Invalid image source: " + imageSource); } break; case METHOD_CALL_MULTI_IMAGE: - delegate.chooseMultiImageFromGallery(call, result); + delegate.chooseMultiImageFromGallery( + new ImageOutputOptions( + call.argument("maxWidth"), + call.argument("maxHeight"), + call.argument("imageQuality")), + usePhotoPicker, + result); break; case METHOD_CALL_VIDEO: imageSource = call.argument("source"); + VideoOptions videoOptions = new VideoOptions(call.argument("maxDuration")); switch (imageSource) { case SOURCE_GALLERY: - delegate.chooseVideoFromGallery(call, result); + delegate.chooseVideoFromGallery(videoOptions, usePhotoPicker, result); break; case SOURCE_CAMERA: - delegate.takeVideoWithCamera(call, result); + delegate.takeVideoWithCamera(videoOptions, result); break; default: throw new IllegalArgumentException("Invalid video source: " + imageSource); diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java index 2a93785678a..e65f0ad07a1 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageResizer.java @@ -29,16 +29,12 @@ class ImageResizer { *

If no resizing is needed, returns the path for the original image. */ String resizeImageIfNeeded( - String imagePath, - @Nullable Double maxWidth, - @Nullable Double maxHeight, - @Nullable Integer imageQuality) { + String imagePath, @Nullable Double maxWidth, @Nullable Double maxHeight, int imageQuality) { Bitmap bmp = decodeFile(imagePath); if (bmp == null) { return null; } - boolean shouldScale = - maxWidth != null || maxHeight != null || isImageQualityValid(imageQuality); + boolean shouldScale = maxWidth != null || maxHeight != null || imageQuality < 100; if (!shouldScale) { return imagePath; } @@ -54,15 +50,11 @@ String resizeImageIfNeeded( } private File resizedImage( - Bitmap bmp, Double maxWidth, Double maxHeight, Integer imageQuality, String outputImageName) + Bitmap bmp, Double maxWidth, Double maxHeight, int imageQuality, String outputImageName) throws IOException { double originalWidth = bmp.getWidth() * 1.0; double originalHeight = bmp.getHeight() * 1.0; - if (!isImageQualityValid(imageQuality)) { - imageQuality = 100; - } - boolean hasMaxWidth = maxWidth != null; boolean hasMaxHeight = maxHeight != null; @@ -128,10 +120,6 @@ private Bitmap createScaledBitmap(Bitmap bmp, int width, int height, boolean fil return Bitmap.createScaledBitmap(bmp, width, height, filter); } - private boolean isImageQualityValid(Integer imageQuality) { - return imageQuality != null && imageQuality > 0 && imageQuality < 100; - } - private File createImageOnExternalDirectory(String name, Bitmap bitmap, int imageQuality) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java new file mode 100644 index 00000000000..59784a96e83 --- /dev/null +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java @@ -0,0 +1,12 @@ +package io.flutter.plugins.imagepicker; + +import androidx.annotation.Nullable; + +/** Stores settings for video selection and output options. */ +public class VideoOptions { + @Nullable public final Integer maxDuration; + + public VideoOptions(@Nullable Integer maxDuration) { + this.maxDuration = maxDuration; + } +} diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index f8fb4dbb241..d31542ca384 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -26,7 +26,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; -import io.flutter.plugin.common.MethodCall; +import androidx.annotation.Nullable; import io.flutter.plugin.common.MethodChannel; import java.io.File; import java.util.ArrayList; @@ -48,12 +48,14 @@ public class ImagePickerDelegateTest { private static final Double WIDTH = 10.0; private static final Double HEIGHT = 10.0; - private static final Double MAX_DURATION = 10.0; + private static final int MAX_DURATION = 10; private static final Integer IMAGE_QUALITY = 90; + private static final ImageOutputOptions DEFAULT_IMAGE_OPTIONS = + new ImageOutputOptions(null, null, null); + private static final VideoOptions DEFAULT_VIDEO_OPTIONS = new VideoOptions(null); @Mock Activity mockActivity; @Mock ImageResizer mockImageResizer; - @Mock MethodCall mockMethodCall; @Mock MethodChannel.Result mockResult; @Mock ImagePickerDelegate.PermissionManager mockPermissionManager; @Mock FileUtils mockFileUtils; @@ -92,15 +94,15 @@ public void setUp() { when(mockFileUtils.getPathFromUri(any(Context.class), any(Uri.class))) .thenReturn("pathFromUri"); - when(mockImageResizer.resizeImageIfNeeded("pathFromUri", null, null, null)) + when(mockImageResizer.resizeImageIfNeeded("pathFromUri", null, null, 100)) .thenReturn("originalPath"); when(mockImageResizer.resizeImageIfNeeded("pathFromUri", null, null, IMAGE_QUALITY)) .thenReturn("originalPath"); - when(mockImageResizer.resizeImageIfNeeded("pathFromUri", WIDTH, HEIGHT, null)) + when(mockImageResizer.resizeImageIfNeeded("pathFromUri", WIDTH, HEIGHT, 100)) .thenReturn("scaledPath"); - when(mockImageResizer.resizeImageIfNeeded("pathFromUri", WIDTH, null, null)) + when(mockImageResizer.resizeImageIfNeeded("pathFromUri", WIDTH, null, 100)) .thenReturn("scaledPath"); - when(mockImageResizer.resizeImageIfNeeded("pathFromUri", null, HEIGHT, null)) + when(mockImageResizer.resizeImageIfNeeded("pathFromUri", null, HEIGHT, 100)) .thenReturn("scaledPath"); mockFileUriResolver = new MockFileUriResolver(); @@ -123,9 +125,10 @@ public void whenConstructed_setsCorrectFileProviderName() { @Test public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); - delegate.chooseImageFromGallery(mockMethodCall, mockResult); + delegate.chooseImageFromGallery(new ImageOutputOptions(null, null, null), false, mockResult); verifyFinishedWithAlreadyActiveError(); verifyNoMoreInteractions(mockResult); @@ -133,9 +136,11 @@ public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyAc @Test public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); - delegate.chooseMultiImageFromGallery(mockMethodCall, mockResult); + delegate.chooseMultiImageFromGallery( + new ImageOutputOptions(null, null, null), false, mockResult); verifyFinishedWithAlreadyActiveError(); verifyNoMoreInteractions(mockResult); @@ -149,7 +154,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre .thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseImageFromGallery(mockMethodCall, mockResult); + delegate.chooseImageFromGallery(new ImageOutputOptions(null, null, null), false, mockResult); verify(mockActivity) .startActivityForResult( @@ -162,10 +167,9 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre chooseImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); - when(mockMethodCall.argument("useAndroidPhotoPicker")).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseImageFromGallery(mockMethodCall, mockResult); + delegate.chooseImageFromGallery(new ImageOutputOptions(null, null, null), true, mockResult); verify(mockActivity) .startActivityForResult( @@ -178,10 +182,10 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre chooseMultiImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); - when(mockMethodCall.argument("useAndroidPhotoPicker")).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseMultiImageFromGallery(mockMethodCall, mockResult); + delegate.chooseMultiImageFromGallery( + new ImageOutputOptions(null, null, null), true, mockResult); verify(mockActivity) .startActivityForResult( @@ -195,10 +199,10 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre chooseMultiImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); - when(mockMethodCall.argument("useAndroidPhotoPicker")).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseMultiImageFromGallery(mockMethodCall, mockResult); + delegate.chooseMultiImageFromGallery( + new ImageOutputOptions(null, null, null), false, mockResult); verify(mockActivity) .startActivityForResult( @@ -212,10 +216,9 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre chooseVideoFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); - when(mockMethodCall.argument("useAndroidPhotoPicker")).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseVideoFromGallery(mockMethodCall, mockResult); + delegate.chooseVideoFromGallery(new VideoOptions(null), true, mockResult); verify(mockActivity) .startActivityForResult( @@ -228,10 +231,9 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre chooseVideoFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); - when(mockMethodCall.argument("useAndroidPhotoPicker")).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.chooseVideoFromGallery(mockMethodCall, mockResult); + delegate.chooseVideoFromGallery(new VideoOptions(null), true, mockResult); verify(mockActivity) .startActivityForResult( @@ -240,9 +242,10 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test public void takeImageWithCamera_WhenPendingResultExists_FinishesWithAlreadyActiveError() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); verifyFinishedWithAlreadyActiveError(); verifyNoMoreInteractions(mockResult); @@ -254,7 +257,7 @@ public void takeImageWithCamera_WhenHasNoCameraPermission_RequestsForPermission( when(mockPermissionManager.needRequestCameraPermission()).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); verify(mockPermissionManager) .askForPermission( @@ -266,7 +269,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockPermissionManager.needRequestCameraPermission()).thenReturn(false); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); verify(mockActivity) .startActivityForResult( @@ -279,7 +282,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); verify(mockActivity) .startActivityForResult( @@ -294,7 +297,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis .when(mockActivity) .startActivityForResult(any(Intent.class), anyInt()); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); verify(mockResult) .error("no_available_camera", "No cameras available for taking pictures.", null); @@ -306,7 +309,7 @@ public void takeImageWithCamera_WritesImageToCacheDirectory() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); - delegate.takeImageWithCamera(mockMethodCall, mockResult); + delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult); mockStaticFile.verify( () -> File.createTempFile(any(), eq(".jpg"), eq(new File("/image_picker_cache"))), @@ -315,7 +318,8 @@ public void takeImageWithCamera_WritesImageToCacheDirectory() { @Test public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithError() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onRequestPermissionsResult( ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, @@ -329,8 +333,8 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr @Test public void onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() { - - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(null, DEFAULT_VIDEO_OPTIONS); delegate.onRequestPermissionsResult( ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION, new String[] {Manifest.permission.CAMERA}, @@ -344,8 +348,8 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr @Test public void onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() { - - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onRequestPermissionsResult( ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION, new String[] {Manifest.permission.CAMERA}, @@ -358,7 +362,8 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr @Test public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_CANCELED, null); @@ -380,7 +385,8 @@ public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() @Test public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_FinishesWithImagePath() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent); @@ -405,9 +411,8 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores @Test public void onActivityResult_WhenImagePickedFromGallery_AndResizeNeeded_FinishesWithScaledImagePath() { - when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH); - - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent); @@ -418,9 +423,8 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores @Test public void onActivityResult_WhenVideoPickedFromGallery_AndResizeParametersSupplied_FinishesWithFilePath() { - when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH); - - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY, Activity.RESULT_OK, mockIntent); @@ -430,7 +434,8 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores @Test public void onActivityResult_WhenTakeImageWithCameraCanceled_FinishesWithNull() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA, Activity.RESULT_CANCELED, null); @@ -441,7 +446,8 @@ public void onActivityResult_WhenTakeImageWithCameraCanceled_FinishesWithNull() @Test public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_FinishesWithImagePath() { - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); delegate.onActivityResult( @@ -454,10 +460,10 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void onActivityResult_WhenImageTakenWithCamera_AndResizeNeeded_FinishesWithScaledImagePath() { - when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH); when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA, Activity.RESULT_OK, mockIntent); @@ -468,10 +474,10 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void onActivityResult_WhenVideoTakenWithCamera_AndResizeParametersSupplied_FinishesWithFilePath() { - when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH); when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA, Activity.RESULT_OK, mockIntent); @@ -482,10 +488,10 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void onActivityResult_WhenVideoTakenWithCamera_AndMaxDurationParametersSupplied_FinishesWithFilePath() { - when(mockMethodCall.argument("maxDuration")).thenReturn(MAX_DURATION); when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); - ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall(); + ImagePickerDelegate delegate = + createDelegateWithPendingResultAndOptions(null, new VideoOptions(MAX_DURATION)); delegate.onActivityResult( ImagePickerDelegate.REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA, Activity.RESULT_OK, mockIntent); @@ -529,19 +535,22 @@ private ImagePickerDelegate createDelegate() { mockImageResizer, null, null, + null, cache, mockPermissionManager, mockFileUriResolver, mockFileUtils); } - private ImagePickerDelegate createDelegateWithPendingResultAndMethodCall() { + private ImagePickerDelegate createDelegateWithPendingResultAndOptions( + @Nullable ImageOutputOptions imageOptions, @Nullable VideoOptions videoOptions) { return new ImagePickerDelegate( mockActivity, new File("/image_picker_cache"), mockImageResizer, + imageOptions, + videoOptions, mockResult, - mockMethodCall, cache, mockPermissionManager, mockFileUriResolver, diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java index 328c964c860..8b9135128e7 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerPluginTest.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.app.Application; +import androidx.annotation.Nullable; import androidx.lifecycle.Lifecycle; import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; @@ -75,8 +76,8 @@ public void tearDown() throws Exception { } @Test - public void onMethodCall_WhenActivityIsNull_FinishesWithForegroundActivityRequiredError() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY); + public void onMethodCall_whenActivityIsNull_finishesWithForegroundActivityRequiredError() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY, false); ImagePickerPlugin imagePickerPluginWithNullActivity = new ImagePickerPlugin(mockImagePickerDelegate, null); imagePickerPluginWithNullActivity.onMethodCall(call, mockResult); @@ -86,7 +87,7 @@ public void onMethodCall_WhenActivityIsNull_FinishesWithForegroundActivityRequir } @Test - public void onMethodCall_WhenCalledWithUnknownMethod_ThrowsException() { + public void onMethodCall_whenCalledWithUnknownMethod_throwsException() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, @@ -97,43 +98,59 @@ public void onMethodCall_WhenCalledWithUnknownMethod_ThrowsException() { } @Test - public void onMethodCall_WhenCalledWithUnknownImageSource_ThrowsException() { + public void onMethodCall_whenCalledWithUnknownImageSource_throwsException() { IllegalArgumentException e = assertThrows( IllegalArgumentException.class, - () -> plugin.onMethodCall(buildMethodCall(PICK_IMAGE, -1), mockResult)); + () -> plugin.onMethodCall(buildMethodCall(PICK_IMAGE, -1, false), mockResult)); assertEquals(e.getMessage(), "Invalid image source: -1"); verifyNoInteractions(mockImagePickerDelegate); verifyNoInteractions(mockResult); } @Test - public void onMethodCall_WhenSourceIsGallery_InvokesChooseImageFromGallery() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY); + public void onMethodCall_whenSourceIsGallery_invokesChooseImageFromGallery() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY, false); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).chooseImageFromGallery(eq(call), any()); + verify(mockImagePickerDelegate).chooseImageFromGallery(any(), eq(false), any()); verifyNoInteractions(mockResult); } @Test - public void onMethodCall_InvokesChooseMultiImageFromGallery() { + public void onMethodCall_whenSourceIsGalleryUsingPhotoPicker_invokesChooseImageFromGallery() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_GALLERY, true); + plugin.onMethodCall(call, mockResult); + verify(mockImagePickerDelegate).chooseImageFromGallery(any(), eq(true), any()); + verifyNoInteractions(mockResult); + } + + @Test + public void onMethodCall_invokesChooseMultiImageFromGallery() { MethodCall call = buildMethodCall(PICK_MULTI_IMAGE); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).chooseMultiImageFromGallery(eq(call), any()); + verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(false), any()); + verifyNoInteractions(mockResult); + } + + @Test + public void onMethodCall_usingPhotoPicker_invokesChooseMultiImageFromGallery() { + MethodCall call = buildMethodCall(PICK_MULTI_IMAGE, SOURCE_GALLERY, true); + plugin.onMethodCall(call, mockResult); + verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(true), any()); verifyNoInteractions(mockResult); } @Test - public void onMethodCall_WhenSourceIsCamera_InvokesTakeImageWithCamera() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); + public void onMethodCall_whenSourceIsCamera_invokesTakeImageWithCamera() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null); plugin.onMethodCall(call, mockResult); - verify(mockImagePickerDelegate).takeImageWithCamera(eq(call), any()); + verify(mockImagePickerDelegate).takeImageWithCamera(any(), any()); verifyNoInteractions(mockResult); } @Test - public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCamera_RearCamera() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); + public void onMethodCall_PickingImage_whenSourceIsCamera_invokesTakeImageWithCamera_RearCamera() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null); HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 0); plugin.onMethodCall(call, mockResult); @@ -142,8 +159,8 @@ public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCam @Test public void - onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCamera_FrontCamera() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); + onMethodCall_PickingImage_whenSourceIsCamera_invokesTakeImageWithCamera_FrontCamera() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null); HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 1); plugin.onMethodCall(call, mockResult); @@ -151,8 +168,8 @@ public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCam } @Test - public void onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCamera_RearCamera() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); + public void onMethodCall_PickingVideo_whenSourceIsCamera_invokesTakeImageWithCamera_RearCamera() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null); HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 0); plugin.onMethodCall(call, mockResult); @@ -161,8 +178,8 @@ public void onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCam @Test public void - onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCamera_FrontCamera() { - MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA); + onMethodCall_PickingVideo_whenSourceIsCamera_invokesTakeImageWithCamera_FrontCamera() { + MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null); HashMap arguments = getArgumentMap(call); arguments.put("cameraDevice", 1); plugin.onMethodCall(call, mockResult); @@ -170,7 +187,7 @@ public void onMethodCall_PickingVideo_WhenSourceIsCamera_InvokesTakeImageWithCam } @Test - public void onResiter_WhenAcitivityIsNull_ShouldNotCrash() { + public void onRegister_whenActivityIsNull_shouldNotCrash() { when(mockRegistrar.activity()).thenReturn(null); ImagePickerPlugin.registerWith((mockRegistrar)); assertTrue( @@ -178,14 +195,14 @@ public void onResiter_WhenAcitivityIsNull_ShouldNotCrash() { } @Test - public void onConstructor_WhenContextTypeIsActivity_ShouldNotCrash() { + public void onConstructor_whenContextTypeIsActivity_shouldNotCrash() { new ImagePickerPlugin(mockImagePickerDelegate, mockActivity); assertTrue( "No exception thrown when ImagePickerPlugin() ran with context instanceof Activity", true); } @Test - public void constructDelegate_ShouldUseInternalCacheDirectory() { + public void constructDelegate_shouldUseInternalCacheDirectory() { File mockDirectory = new File("/mockpath"); when(mockActivity.getCacheDir()).thenReturn(mockDirectory); @@ -199,7 +216,7 @@ public void constructDelegate_ShouldUseInternalCacheDirectory() { } @Test - public void onDetachedFromActivity_ShouldReleaseActivityState() { + public void onDetachedFromActivity_shouldReleaseActivityState() { final BinaryMessenger mockBinaryMessenger = mock(BinaryMessenger.class); when(mockPluginBinding.getBinaryMessenger()).thenReturn(mockBinaryMessenger); @@ -217,9 +234,13 @@ public void onDetachedFromActivity_ShouldReleaseActivityState() { assertNull(plugin.getActivityState()); } - private MethodCall buildMethodCall(String method, final int source) { + private MethodCall buildMethodCall( + String method, final int source, @Nullable Boolean usePhotoPicker) { final Map arguments = new HashMap<>(); arguments.put("source", source); + if (usePhotoPicker != null) { + arguments.put("useAndroidPhotoPicker", usePhotoPicker); + } return new MethodCall(method, arguments); } diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java index a3710038379..c05a48b3d19 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java @@ -48,34 +48,34 @@ public void tearDown() throws Exception { } @Test - public void onResizeImageIfNeeded_WhenQualityIsNull_ShoultNotResize_ReturnTheUnscaledFile() { - String outoutFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, null); - assertThat(outoutFile, equalTo(imageFile.getPath())); + public void onResizeImageIfNeeded_WhenQualityIsMax_ShouldNotResize_ReturnTheUnscaledFile() { + String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, 100); + assertThat(outputFile, equalTo(imageFile.getPath())); } @Test - public void onResizeImageIfNeeded_WhenQualityIsNotNull_ShoulResize_ReturnResizedFile() { - String outoutFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, 50); - assertThat(outoutFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); + public void onResizeImageIfNeeded_WhenQualityIsNotMax_ShouldResize_ReturnResizedFile() { + String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, 50); + assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test - public void onResizeImageIfNeeded_WhenWidthIsNotNull_ShoulResize_ReturnResizedFile() { - String outoutFile = resizer.resizeImageIfNeeded(imageFile.getPath(), 50.0, null, null); - assertThat(outoutFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); + public void onResizeImageIfNeeded_WhenWidthIsNotNull_ShouldResize_ReturnResizedFile() { + String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), 50.0, null, 100); + assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test - public void onResizeImageIfNeeded_WhenHeightIsNotNull_ShoulResize_ReturnResizedFile() { - String outoutFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, null); - assertThat(outoutFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); + public void onResizeImageIfNeeded_WhenHeightIsNotNull_ShouldResize_ReturnResizedFile() { + String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, 100); + assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test public void onResizeImageIfNeeded_WhenParentDirectoryDoesNotExists_ShouldNotCrash() { File nonExistentDirectory = new File(externalDirectory, "/nonExistent"); ImageResizer invalidResizer = new ImageResizer(nonExistentDirectory, new ExifDataCopier()); - String outoutFile = invalidResizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, null); - assertThat(outoutFile, equalTo(nonExistentDirectory.getPath() + "/scaled_pngImage.png")); + String outputFile = invalidResizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, 100); + assertThat(outputFile, equalTo(nonExistentDirectory.getPath() + "/scaled_pngImage.png")); } } From b3b3b55cc9027c207cb5a70d2d8713dbb820d9f8 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 10 Mar 2023 12:14:22 -0500 Subject: [PATCH 3/6] Consolidate state, fix test names --- .../image_picker_android/CHANGELOG.md | 4 + .../imagepicker/ImagePickerDelegate.java | 82 +++++++++++-------- .../imagepicker/ImagePickerDelegateTest.java | 56 ++++++------- .../image_picker_android/pubspec.yaml | 2 +- 4 files changed, 79 insertions(+), 65 deletions(-) diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md index b9ca0c5533f..77b8879117a 100644 --- a/packages/image_picker/image_picker_android/CHANGELOG.md +++ b/packages/image_picker/image_picker_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.6+1 + +* Refactors code in preparation for adopting Pigeon. + ## 0.8.6 * Adds `usePhotoPickerAndroid` options. diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index 4b75f715e0e..9791d1fd08c 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -37,8 +37,8 @@ *

When invoked, both the {@link #chooseImageFromGallery} and {@link #takeImageWithCamera} * methods go through the same steps: * - *

1. Check for an existing {@link #pendingResult}. If a previous pendingResult exists, this - * means that the chooseImageFromGallery() or takeImageWithCamera() method was called at least + *

1. Check for an existing {@link #pendingCallState}. If a previous pendingCallState exists, + * this means that the chooseImageFromGallery() or takeImageWithCamera() method was called at least * twice. In this case, stop executing and finish with an error. * *

2. Check that a required runtime permission has been granted. The takeImageWithCamera() method @@ -85,6 +85,22 @@ public enum CameraDevice { FRONT } + /** Holds call state during intent handling. */ + private class PendingCallState { + public final @Nullable ImageOutputOptions imageOptions; + public final @Nullable VideoOptions videoOptions; + public final @NonNull MethodChannel.Result result; + + private PendingCallState( + @Nullable ImageOutputOptions imageOptions, + @Nullable VideoOptions videoOptions, + @NonNull MethodChannel.Result result) { + this.imageOptions = imageOptions; + this.videoOptions = videoOptions; + this.result = result; + } + } + @VisibleForTesting final String fileProviderName; private final Activity activity; @@ -115,9 +131,7 @@ interface OnPathReadyListener { } private Uri pendingCameraMediaUri; - private @Nullable ImageOutputOptions pendingImageOptions; - private @Nullable VideoOptions pendingVideoOptions; - private @Nullable MethodChannel.Result pendingResult; + private @Nullable PendingCallState pendingCallState; public ImagePickerDelegate( final Activity activity, @@ -192,9 +206,10 @@ public void onScanCompleted(String path, Uri uri) { this.externalFilesDirectory = externalFilesDirectory; this.imageResizer = imageResizer; this.fileProviderName = activity.getPackageName() + ".flutter.image_provider"; - this.pendingImageOptions = pendingImageOptions; - this.pendingVideoOptions = pendingVideoOptions; - this.pendingResult = result; + if (result != null) { + this.pendingCallState = + new PendingCallState(pendingImageOptions, pendingVideoOptions, result); + } this.permissionManager = permissionManager; this.fileUriResolver = fileUriResolver; this.fileUtils = fileUtils; @@ -211,16 +226,16 @@ CameraDevice getCameraDevice() { // Save the state of the image picker so it can be retrieved with `retrieveLostImage`. void saveStateBeforeResult() { - if (pendingResult == null) { + if (pendingCallState == null) { return; } cache.saveType( - pendingImageOptions != null + pendingCallState.imageOptions != null ? ImagePickerCache.CacheType.IMAGE : ImagePickerCache.CacheType.VIDEO); - if (pendingImageOptions != null) { - cache.saveDimensionWithOutputOptions(pendingImageOptions); + if (pendingCallState.imageOptions != null) { + cache.saveDimensionWithOutputOptions(pendingCallState.imageOptions); } if (pendingCameraMediaUri != null) { cache.savePendingCameraMediaUriPath(pendingCameraMediaUri); @@ -299,8 +314,10 @@ public void takeVideoWithCamera(VideoOptions options, MethodChannel.Result resul private void launchTakeVideoWithCameraIntent() { Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - if (this.pendingVideoOptions != null && this.pendingVideoOptions.maxDuration != null) { - int maxSeconds = this.pendingVideoOptions.maxDuration; + if (pendingCallState != null + && pendingCallState.videoOptions != null + && pendingCallState.videoOptions.maxDuration != null) { + int maxSeconds = pendingCallState.videoOptions.maxDuration; intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, maxSeconds); } if (cameraDevice == CameraDevice.FRONT) { @@ -612,10 +629,10 @@ public void onPathReady(String path) { private void handleMultiImageResult( ArrayList paths, boolean shouldDeleteOriginalIfScaled) { - if (pendingImageOptions != null) { + if (pendingCallState != null && pendingCallState.imageOptions != null) { ArrayList finalPath = new ArrayList<>(); for (int i = 0; i < paths.size(); i++) { - String finalImagePath = getResizedImagePath(paths.get(i), pendingImageOptions); + String finalImagePath = getResizedImagePath(paths.get(i), pendingCallState.imageOptions); //delete original file if scaled if (finalImagePath != null @@ -632,8 +649,8 @@ private void handleMultiImageResult( } private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) { - if (pendingImageOptions != null) { - String finalImagePath = getResizedImagePath(path, pendingImageOptions); + if (pendingCallState != null && pendingCallState.imageOptions != null) { + String finalImagePath = getResizedImagePath(path, pendingCallState.imageOptions); //delete original file if scaled if (finalImagePath != null && !finalImagePath.equals(path) && shouldDeleteOriginalIfScaled) { new File(path).delete(); @@ -657,13 +674,11 @@ private boolean setPendingOptionsAndResult( @Nullable ImageOutputOptions imageOptions, @Nullable VideoOptions videoOptions, @NonNull MethodChannel.Result result) { - if (pendingResult != null) { + if (pendingCallState != null) { return false; } - pendingImageOptions = imageOptions; - pendingVideoOptions = videoOptions; - pendingResult = result; + pendingCallState = new PendingCallState(imageOptions, videoOptions, result); // Clean up cache if a new image picker is launched. cache.clear(); @@ -676,7 +691,7 @@ private boolean setPendingOptionsAndResult( // A null imagePath indicates that the image picker was cancelled without // selection. private void finishWithSuccess(@Nullable String imagePath) { - if (pendingResult == null) { + if (pendingCallState == null) { // Only save data for later retrieval if something was actually selected. if (imagePath != null) { ArrayList pathList = new ArrayList<>(); @@ -685,17 +700,17 @@ private void finishWithSuccess(@Nullable String imagePath) { } return; } - pendingResult.success(imagePath); - clearOptionsAndResult(); + pendingCallState.result.success(imagePath); + pendingCallState = null; } private void finishWithListSuccess(ArrayList imagePaths) { - if (pendingResult == null) { + if (pendingCallState == null) { cache.saveResult(imagePaths, null, null); return; } - pendingResult.success(imagePaths); - clearOptionsAndResult(); + pendingCallState.result.success(imagePaths); + pendingCallState = null; } private void finishWithAlreadyActiveError(MethodChannel.Result result) { @@ -703,17 +718,12 @@ private void finishWithAlreadyActiveError(MethodChannel.Result result) { } private void finishWithError(String errorCode, String errorMessage) { - if (pendingResult == null) { + if (pendingCallState == null) { cache.saveResult(null, errorCode, errorMessage); return; } - pendingResult.error(errorCode, errorMessage, null); - clearOptionsAndResult(); - } - - private void clearOptionsAndResult() { - pendingImageOptions = null; - pendingResult = null; + pendingCallState.result.error(errorCode, errorMessage, null); + pendingCallState = null; } private void useFrontCamera(Intent intent) { diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java index d31542ca384..80666e963e2 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerDelegateTest.java @@ -124,7 +124,7 @@ public void whenConstructed_setsCorrectFileProviderName() { } @Test - public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() { + public void chooseImageFromGallery_whenPendingResultExists_finishesWithAlreadyActiveError() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -135,7 +135,7 @@ public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyAc } @Test - public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() { + public void chooseMultiImageFromGallery_whenPendingResultExists_finishesWithAlreadyActiveError() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -149,7 +149,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(sdk = 30) public void - chooseImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseImageFromGallery_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -164,7 +164,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(minSdk = 33) public void - chooseImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseImageFromGallery_WithPhotoPicker_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -179,7 +179,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(sdk = 30) public void - chooseMultiImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseMultiImageFromGallery_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -196,7 +196,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(minSdk = 33) public void - chooseMultiImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseMultiImageFromGallery_WithPhotoPicker_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -213,7 +213,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(sdk = 30) public void - chooseVideoFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseVideoFromGallery_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -228,7 +228,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre @Test @Config(minSdk = 33) public void - chooseVideoFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() { + chooseVideoFromGallery_WithPhotoPicker_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) .thenReturn(true); @@ -241,7 +241,7 @@ public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlre } @Test - public void takeImageWithCamera_WhenPendingResultExists_FinishesWithAlreadyActiveError() { + public void takeImageWithCamera_whenPendingResultExists_finishesWithAlreadyActiveError() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -252,7 +252,7 @@ public void takeImageWithCamera_WhenPendingResultExists_FinishesWithAlreadyActiv } @Test - public void takeImageWithCamera_WhenHasNoCameraPermission_RequestsForPermission() { + public void takeImageWithCamera_whenHasNoCameraPermission_RequestsForPermission() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(false); when(mockPermissionManager.needRequestCameraPermission()).thenReturn(true); @@ -265,7 +265,7 @@ public void takeImageWithCamera_WhenHasNoCameraPermission_RequestsForPermission( } @Test - public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermission() { + public void takeImageWithCamera_whenCameraPermissionNotPresent_RequestsForPermission() { when(mockPermissionManager.needRequestCameraPermission()).thenReturn(false); ImagePickerDelegate delegate = createDelegate(); @@ -278,7 +278,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis @Test public void - takeImageWithCamera_WhenHasCameraPermission_AndAnActivityCanHandleCameraIntent_LaunchesTakeWithCameraIntent() { + takeImageWithCamera_whenHasCameraPermission_andAnActivityCanHandleCameraIntent_launchesTakeWithCameraIntent() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); @@ -291,7 +291,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis @Test public void - takeImageWithCamera_WhenHasCameraPermission_AndNoActivityToHandleCameraIntent_FinishesWithNoCamerasAvailableError() { + takeImageWithCamera_whenHasCameraPermission_andNoActivityToHandleCameraIntent_finishesWithNoCamerasAvailableError() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); doThrow(ActivityNotFoundException.class) .when(mockActivity) @@ -305,7 +305,7 @@ public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermis } @Test - public void takeImageWithCamera_WritesImageToCacheDirectory() { + public void takeImageWithCamera_writesImageToCacheDirectory() { when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true); ImagePickerDelegate delegate = createDelegate(); @@ -317,7 +317,7 @@ public void takeImageWithCamera_WritesImageToCacheDirectory() { } @Test - public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithError() { + public void onRequestPermissionsResult_whenCameraPermissionDenied_finishesWithError() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -332,7 +332,7 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr @Test public void - onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() { + onRequestTakeVideoPermissionsResult_whenCameraPermissionGranted_launchesTakeVideoWithCameraIntent() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(null, DEFAULT_VIDEO_OPTIONS); delegate.onRequestPermissionsResult( @@ -347,7 +347,7 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr @Test public void - onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() { + onRequestTakeImagePermissionsResult_whenCameraPermissionGranted_launchesTakeWithCameraIntent() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); delegate.onRequestPermissionsResult( @@ -361,7 +361,7 @@ public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithEr } @Test - public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() { + public void onActivityResult_whenPickFromGalleryCanceled_finishesWithNull() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -373,7 +373,7 @@ public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() { } @Test - public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() { + public void onActivityResult_whenPickFromGalleryCanceled_storesNothingInCache() { ImagePickerDelegate delegate = createDelegate(); delegate.onActivityResult( @@ -384,7 +384,7 @@ public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() @Test public void - onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_FinishesWithImagePath() { + onActivityResult_whenImagePickedFromGallery_andNoResizeNeeded_finishesWithImagePath() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -396,7 +396,7 @@ public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() } @Test - public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_StoresImageInCache() { + public void onActivityResult_whenImagePickedFromGallery_andNoResizeNeeded_StoresImageInCache() { ImagePickerDelegate delegate = createDelegate(); delegate.onActivityResult( @@ -410,7 +410,7 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores @Test public void - onActivityResult_WhenImagePickedFromGallery_AndResizeNeeded_FinishesWithScaledImagePath() { + onActivityResult_whenImagePickedFromGallery_andResizeNeeded_finishesWithScaledImagePath() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( @@ -422,7 +422,7 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores @Test public void - onActivityResult_WhenVideoPickedFromGallery_AndResizeParametersSupplied_FinishesWithFilePath() { + onActivityResult_whenVideoPickedFromGallery_andResizeParametersSupplied_finishesWithFilePath() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null); delegate.onActivityResult( @@ -433,7 +433,7 @@ public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_Stores } @Test - public void onActivityResult_WhenTakeImageWithCameraCanceled_FinishesWithNull() { + public void onActivityResult_whenTakeImageWithCameraCanceled_finishesWithNull() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); @@ -445,7 +445,7 @@ public void onActivityResult_WhenTakeImageWithCameraCanceled_FinishesWithNull() } @Test - public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_FinishesWithImagePath() { + public void onActivityResult_whenImageTakenWithCamera_andNoResizeNeeded_finishesWithImagePath() { ImagePickerDelegate delegate = createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null); when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); @@ -459,7 +459,7 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void - onActivityResult_WhenImageTakenWithCamera_AndResizeNeeded_FinishesWithScaledImagePath() { + onActivityResult_whenImageTakenWithCamera_andResizeNeeded_finishesWithScaledImagePath() { when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); ImagePickerDelegate delegate = @@ -473,7 +473,7 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void - onActivityResult_WhenVideoTakenWithCamera_AndResizeParametersSupplied_FinishesWithFilePath() { + onActivityResult_whenVideoTakenWithCamera_andResizeParametersSupplied_finishesWithFilePath() { when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); ImagePickerDelegate delegate = @@ -487,7 +487,7 @@ public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_Finishes @Test public void - onActivityResult_WhenVideoTakenWithCamera_AndMaxDurationParametersSupplied_FinishesWithFilePath() { + onActivityResult_whenVideoTakenWithCamera_andMaxDurationParametersSupplied_finishesWithFilePath() { when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString"); ImagePickerDelegate delegate = diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml index 1c22e9c9366..812026de317 100755 --- a/packages/image_picker/image_picker_android/pubspec.yaml +++ b/packages/image_picker/image_picker_android/pubspec.yaml @@ -3,7 +3,7 @@ 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.6 +version: 0.8.6+1 environment: sdk: ">=2.17.0 <3.0.0" From 442031adff8cd1e4df211e5b21c544f548332522 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 10 Mar 2023 12:16:16 -0500 Subject: [PATCH 4/6] More test name fixes --- .../plugins/imagepicker/ImagePickerCacheTest.java | 2 +- .../flutter/plugins/imagepicker/ImageResizerTest.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java index 4b915f283a5..01bdd6768dc 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java @@ -101,7 +101,7 @@ public void tearDown() throws Exception { } @Test - public void ImageCache_ShouldBeAbleToSetAndGetQuality() { + public void imageCache_shouldBeAbleToSetAndGetQuality() { final int quality = 90; ImagePickerCache cache = new ImagePickerCache(mockActivity); cache.saveDimensionWithOutputOptions(new ImageOutputOptions(null, null, quality)); diff --git a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java index c05a48b3d19..2287c4abc17 100644 --- a/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java +++ b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImageResizerTest.java @@ -48,31 +48,31 @@ public void tearDown() throws Exception { } @Test - public void onResizeImageIfNeeded_WhenQualityIsMax_ShouldNotResize_ReturnTheUnscaledFile() { + public void onResizeImageIfNeeded_whenQualityIsMax_shouldNotResize_returnTheUnscaledFile() { String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, 100); assertThat(outputFile, equalTo(imageFile.getPath())); } @Test - public void onResizeImageIfNeeded_WhenQualityIsNotMax_ShouldResize_ReturnResizedFile() { + public void onResizeImageIfNeeded_whenQualityIsNotMax_shouldResize_returnResizedFile() { String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, null, 50); assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test - public void onResizeImageIfNeeded_WhenWidthIsNotNull_ShouldResize_ReturnResizedFile() { + public void onResizeImageIfNeeded_whenWidthIsNotNull_shouldResize_returnResizedFile() { String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), 50.0, null, 100); assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test - public void onResizeImageIfNeeded_WhenHeightIsNotNull_ShouldResize_ReturnResizedFile() { + public void onResizeImageIfNeeded_whenHeightIsNotNull_shouldResize_returnResizedFile() { String outputFile = resizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, 100); assertThat(outputFile, equalTo(externalDirectory.getPath() + "/scaled_pngImage.png")); } @Test - public void onResizeImageIfNeeded_WhenParentDirectoryDoesNotExists_ShouldNotCrash() { + public void onResizeImageIfNeeded_whenParentDirectoryDoesNotExists_shouldNotCrash() { File nonExistentDirectory = new File(externalDirectory, "/nonExistent"); ImageResizer invalidResizer = new ImageResizer(nonExistentDirectory, new ExifDataCopier()); String outputFile = invalidResizer.resizeImageIfNeeded(imageFile.getPath(), null, 50.0, 100); From 889e0bda9652ef37700026949ec431bb9e3b7573 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 10 Mar 2023 12:17:23 -0500 Subject: [PATCH 5/6] static --- .../io/flutter/plugins/imagepicker/ImagePickerDelegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java index 9791d1fd08c..a28611e5b5d 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImagePickerDelegate.java @@ -86,7 +86,7 @@ public enum CameraDevice { } /** Holds call state during intent handling. */ - private class PendingCallState { + private static class PendingCallState { public final @Nullable ImageOutputOptions imageOptions; public final @Nullable VideoOptions videoOptions; public final @NonNull MethodChannel.Result result; From 0df3a0227a9304322763ecebf1ab90fb7cde0053 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 10 Mar 2023 12:52:02 -0500 Subject: [PATCH 6/6] License --- .../io/flutter/plugins/imagepicker/ImageOutputOptions.java | 4 ++++ .../java/io/flutter/plugins/imagepicker/VideoOptions.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java index 44567afb9f8..89648dcd24b 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// 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 androidx.annotation.Nullable; diff --git a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java index 59784a96e83..e3d73204d45 100644 --- a/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java +++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java @@ -1,3 +1,7 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// 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 androidx.annotation.Nullable;