[image_picker] Remove MethodCall from most Android code (#3438)

[image_picker] Remove MethodCall from most Android code
diff --git a/packages/image_picker/image_picker_android/CHANGELOG.md b/packages/image_picker/image_picker_android/CHANGELOG.md
index b9ca0c5..77b8879 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/ImageOutputOptions.java b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java
new file mode 100644
index 0000000..89648dc
--- /dev/null
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/ImageOutputOptions.java
@@ -0,0 +1,29 @@
+// 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;
+
+/** Stores settings for image output options. */
+public class ImageOutputOptions {
+  /** The maximum width of the image, if the width should be constrained. */
+  @Nullable public final Double maxWidth;
+  /** The maximum height of the image, if the width should be constrained. */
+  @Nullable public final Double maxHeight;
+  /**
+   * The output quality of the image, as a number from 0 to 100.
+   *
+   * <p>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 983dbab..86e314d 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;
@@ -17,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";
@@ -53,44 +56,31 @@
     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();
   }
 
-  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 (options.maxWidth != null) {
+      editor.putLong(SHARED_PREFERENCE_MAX_WIDTH_KEY, Double.doubleToRawLongBits(options.maxWidth));
     }
-    if (maxHeight != null) {
-      editor.putLong(SHARED_PREFERENCE_MAX_HEIGHT_KEY, Double.doubleToRawLongBits(maxHeight));
+    if (options.maxHeight != null) {
+      editor.putLong(
+          SHARED_PREFERENCE_MAX_HEIGHT_KEY, Double.doubleToRawLongBits(options.maxHeight));
     }
-    if (imageQuality > -1 && imageQuality < 101) {
-      editor.putInt(SHARED_PREFERENCE_IMAGE_QUALITY_KEY, imageQuality);
-    } else {
-      editor.putInt(SHARED_PREFERENCE_IMAGE_QUALITY_KEY, 100);
-    }
+    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 8f89e05..a28611e 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;
@@ -37,8 +37,8 @@
  * <p>When invoked, both the {@link #chooseImageFromGallery} and {@link #takeImageWithCamera}
  * methods go through the same steps:
  *
- * <p>1. Check for an existing {@link #pendingResult}. If a previous pendingResult exists, this
- * means that the chooseImageFromGallery() or takeImageWithCamera() method was called at least
+ * <p>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.
  *
  * <p>2. Check that a required runtime permission has been granted. The takeImageWithCamera() method
@@ -85,6 +85,22 @@
     FRONT
   }
 
+  /** Holds call state during intent handling. */
+  private static 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,8 +131,7 @@
   }
 
   private Uri pendingCameraMediaUri;
-  private MethodChannel.Result pendingResult;
-  private MethodCall methodCall;
+  private @Nullable PendingCallState pendingCallState;
 
   public ImagePickerDelegate(
       final Activity activity,
@@ -129,6 +144,7 @@
         imageResizer,
         null,
         null,
+        null,
         cache,
         new PermissionManager() {
           @Override
@@ -179,8 +195,9 @@
       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 +206,10 @@
     this.externalFilesDirectory = externalFilesDirectory;
     this.imageResizer = imageResizer;
     this.fileProviderName = activity.getPackageName() + ".flutter.image_provider";
-    this.pendingResult = result;
-    this.methodCall = methodCall;
+    if (result != null) {
+      this.pendingCallState =
+          new PendingCallState(pendingImageOptions, pendingVideoOptions, result);
+    }
     this.permissionManager = permissionManager;
     this.fileUriResolver = fileUriResolver;
     this.fileUtils = fileUtils;
@@ -207,12 +226,17 @@
 
   // Save the state of the image picker so it can be retrieved with `retrieveLostImage`.
   void saveStateBeforeResult() {
-    if (methodCall == null) {
+    if (pendingCallState == null) {
       return;
     }
 
-    cache.saveTypeWithMethodCallName(methodCall.method);
-    cache.saveDimensionWithMethodCall(methodCall);
+    cache.saveType(
+        pendingCallState.imageOptions != null
+            ? ImagePickerCache.CacheType.IMAGE
+            : ImagePickerCache.CacheType.VIDEO);
+    if (pendingCallState.imageOptions != null) {
+      cache.saveDimensionWithOutputOptions(pendingCallState.imageOptions);
+    }
     if (pendingCameraMediaUri != null) {
       cache.savePendingCameraMediaUriPath(pendingCameraMediaUri);
     }
@@ -228,10 +252,8 @@
       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));
       }
@@ -246,18 +268,13 @@
     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);
   }
 
@@ -279,8 +296,8 @@
     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;
     }
@@ -297,8 +314,10 @@
 
   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 (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) {
@@ -326,33 +345,23 @@
     }
   }
 
-  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);
   }
 
@@ -395,8 +404,9 @@
         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;
     }
@@ -619,10 +629,10 @@
 
   private void handleMultiImageResult(
       ArrayList<String> paths, boolean shouldDeleteOriginalIfScaled) {
-    if (methodCall != null) {
+    if (pendingCallState != null && pendingCallState.imageOptions != null) {
       ArrayList<String> finalPath = new ArrayList<>();
       for (int i = 0; i < paths.size(); i++) {
-        String finalImagePath = getResizedImagePath(paths.get(i));
+        String finalImagePath = getResizedImagePath(paths.get(i), pendingCallState.imageOptions);
 
         //delete original file if scaled
         if (finalImagePath != null
@@ -639,8 +649,8 @@
   }
 
   private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) {
-    if (methodCall != null) {
-      String finalImagePath = getResizedImagePath(path);
+    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();
@@ -651,26 +661,24 @@
     }
   }
 
-  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) {
-    if (pendingResult != null) {
+  private boolean setPendingOptionsAndResult(
+      @Nullable ImageOutputOptions imageOptions,
+      @Nullable VideoOptions videoOptions,
+      @NonNull MethodChannel.Result result) {
+    if (pendingCallState != null) {
       return false;
     }
 
-    this.methodCall = methodCall;
-    pendingResult = result;
+    pendingCallState = new PendingCallState(imageOptions, videoOptions, result);
 
     // Clean up cache if a new image picker is launched.
     cache.clear();
@@ -683,7 +691,7 @@
   // 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<String> pathList = new ArrayList<>();
@@ -692,17 +700,17 @@
       }
       return;
     }
-    pendingResult.success(imagePath);
-    clearMethodCallAndResult();
+    pendingCallState.result.success(imagePath);
+    pendingCallState = null;
   }
 
   private void finishWithListSuccess(ArrayList<String> imagePaths) {
-    if (pendingResult == null) {
+    if (pendingCallState == null) {
       cache.saveResult(imagePaths, null, null);
       return;
     }
-    pendingResult.success(imagePaths);
-    clearMethodCallAndResult();
+    pendingCallState.result.success(imagePaths);
+    pendingCallState = null;
   }
 
   private void finishWithAlreadyActiveError(MethodChannel.Result result) {
@@ -710,17 +718,12 @@
   }
 
   private void finishWithError(String errorCode, String errorMessage) {
-    if (pendingResult == null) {
+    if (pendingCallState == null) {
       cache.saveResult(null, errorCode, errorMessage);
       return;
     }
-    pendingResult.error(errorCode, errorMessage, null);
-    clearMethodCallAndResult();
-  }
-
-  private void clearMethodCallAndResult() {
-    methodCall = 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/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 a1ee1e2..4a4b311 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 @@
       }
       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 2a93785..e65f0ad 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 @@
    * <p>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 @@
   }
 
   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 @@
     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 0000000..e3d7320
--- /dev/null
+++ b/packages/image_picker/image_picker_android/android/src/main/java/io/flutter/plugins/imagepicker/VideoOptions.java
@@ -0,0 +1,16 @@
+// 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;
+
+/** 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/ImagePickerCacheTest.java b/packages/image_picker/image_picker_android/android/src/test/java/io/flutter/plugins/imagepicker/ImagePickerCacheTest.java
index 7d87166..01bdd67 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<String, Object> preferenceStorage;
 
@@ -106,16 +101,15 @@
   }
 
   @Test
-  public void ImageCache_ShouldBeAbleToSetAndGetQuality() {
-    when(mockMethodCall.argument(MAP_KEY_IMAGE_QUALITY)).thenReturn(IMAGE_QUALITY);
+  public void imageCache_shouldBeAbleToSetAndGetQuality() {
+    final int quality = 90;
     ImagePickerCache cache = new ImagePickerCache(mockActivity);
-    cache.saveDimensionWithMethodCall(mockMethodCall);
+    cache.saveDimensionWithOutputOptions(new ImageOutputOptions(null, null, quality));
     Map<String, Object> 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<String, Object> resultMapWithDefaultQuality = cache.getCacheMap();
     int defaultImageQuality =
         (int) resultMapWithDefaultQuality.get(ImagePickerCache.MAP_KEY_IMAGE_QUALITY);
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 f8fb4db..80666e9 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 @@
     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();
@@ -122,20 +124,23 @@
   }
 
   @Test
-  public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void chooseImageFromGallery_whenPendingResultExists_finishesWithAlreadyActiveError() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
-    delegate.chooseImageFromGallery(mockMethodCall, mockResult);
+    delegate.chooseImageFromGallery(new ImageOutputOptions(null, null, null), false, mockResult);
 
     verifyFinishedWithAlreadyActiveError();
     verifyNoMoreInteractions(mockResult);
   }
 
   @Test
-  public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void chooseMultiImageFromGallery_whenPendingResultExists_finishesWithAlreadyActiveError() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
-    delegate.chooseMultiImageFromGallery(mockMethodCall, mockResult);
+    delegate.chooseMultiImageFromGallery(
+        new ImageOutputOptions(null, null, null), false, mockResult);
 
     verifyFinishedWithAlreadyActiveError();
     verifyNoMoreInteractions(mockResult);
@@ -144,12 +149,12 @@
   @Test
   @Config(sdk = 30)
   public void
-      chooseImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      chooseImageFromGallery_whenHasExternalStoragePermission_launchesChooseFromGalleryIntent() {
     when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE))
         .thenReturn(true);
 
     ImagePickerDelegate delegate = createDelegate();
-    delegate.chooseImageFromGallery(mockMethodCall, mockResult);
+    delegate.chooseImageFromGallery(new ImageOutputOptions(null, null, null), false, mockResult);
 
     verify(mockActivity)
         .startActivityForResult(
@@ -159,13 +164,12 @@
   @Test
   @Config(minSdk = 33)
   public void
-      chooseImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      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(
@@ -175,13 +179,13 @@
   @Test
   @Config(sdk = 30)
   public void
-      chooseMultiImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      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(
@@ -192,13 +196,13 @@
   @Test
   @Config(minSdk = 33)
   public void
-      chooseMultiImageFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      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(
@@ -209,13 +213,12 @@
   @Test
   @Config(sdk = 30)
   public void
-      chooseVideoFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      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(
@@ -225,13 +228,12 @@
   @Test
   @Config(minSdk = 33)
   public void
-      chooseVideoFromGallery_WithPhotoPicker_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
+      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(
@@ -239,22 +241,23 @@
   }
 
   @Test
-  public void takeImageWithCamera_WhenPendingResultExists_FinishesWithAlreadyActiveError() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void takeImageWithCamera_whenPendingResultExists_finishesWithAlreadyActiveError() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
-    delegate.takeImageWithCamera(mockMethodCall, mockResult);
+    delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult);
 
     verifyFinishedWithAlreadyActiveError();
     verifyNoMoreInteractions(mockResult);
   }
 
   @Test
-  public void takeImageWithCamera_WhenHasNoCameraPermission_RequestsForPermission() {
+  public void takeImageWithCamera_whenHasNoCameraPermission_RequestsForPermission() {
     when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(false);
     when(mockPermissionManager.needRequestCameraPermission()).thenReturn(true);
 
     ImagePickerDelegate delegate = createDelegate();
-    delegate.takeImageWithCamera(mockMethodCall, mockResult);
+    delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult);
 
     verify(mockPermissionManager)
         .askForPermission(
@@ -262,11 +265,11 @@
   }
 
   @Test
-  public void takeImageWithCamera_WhenCameraPermissionNotPresent_RequestsForPermission() {
+  public void takeImageWithCamera_whenCameraPermissionNotPresent_RequestsForPermission() {
     when(mockPermissionManager.needRequestCameraPermission()).thenReturn(false);
 
     ImagePickerDelegate delegate = createDelegate();
-    delegate.takeImageWithCamera(mockMethodCall, mockResult);
+    delegate.takeImageWithCamera(new ImageOutputOptions(null, null, null), mockResult);
 
     verify(mockActivity)
         .startActivityForResult(
@@ -275,11 +278,11 @@
 
   @Test
   public void
-      takeImageWithCamera_WhenHasCameraPermission_AndAnActivityCanHandleCameraIntent_LaunchesTakeWithCameraIntent() {
+      takeImageWithCamera_whenHasCameraPermission_andAnActivityCanHandleCameraIntent_launchesTakeWithCameraIntent() {
     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(
@@ -288,13 +291,13 @@
 
   @Test
   public void
-      takeImageWithCamera_WhenHasCameraPermission_AndNoActivityToHandleCameraIntent_FinishesWithNoCamerasAvailableError() {
+      takeImageWithCamera_whenHasCameraPermission_andNoActivityToHandleCameraIntent_finishesWithNoCamerasAvailableError() {
     when(mockPermissionManager.isPermissionGranted(Manifest.permission.CAMERA)).thenReturn(true);
     doThrow(ActivityNotFoundException.class)
         .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);
@@ -302,11 +305,11 @@
   }
 
   @Test
-  public void takeImageWithCamera_WritesImageToCacheDirectory() {
+  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"))),
@@ -314,8 +317,9 @@
   }
 
   @Test
-  public void onRequestPermissionsResult_WhenCameraPermissionDenied_FinishesWithError() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void onRequestPermissionsResult_whenCameraPermissionDenied_finishesWithError() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
     delegate.onRequestPermissionsResult(
         ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION,
@@ -328,9 +332,9 @@
 
   @Test
   public void
-      onRequestTakeVideoPermissionsResult_WhenCameraPermissionGranted_LaunchesTakeVideoWithCameraIntent() {
-
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+      onRequestTakeVideoPermissionsResult_whenCameraPermissionGranted_launchesTakeVideoWithCameraIntent() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(null, DEFAULT_VIDEO_OPTIONS);
     delegate.onRequestPermissionsResult(
         ImagePickerDelegate.REQUEST_CAMERA_VIDEO_PERMISSION,
         new String[] {Manifest.permission.CAMERA},
@@ -343,9 +347,9 @@
 
   @Test
   public void
-      onRequestTakeImagePermissionsResult_WhenCameraPermissionGranted_LaunchesTakeWithCameraIntent() {
-
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+      onRequestTakeImagePermissionsResult_whenCameraPermissionGranted_launchesTakeWithCameraIntent() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
     delegate.onRequestPermissionsResult(
         ImagePickerDelegate.REQUEST_CAMERA_IMAGE_PERMISSION,
         new String[] {Manifest.permission.CAMERA},
@@ -357,8 +361,9 @@
   }
 
   @Test
-  public void onActivityResult_WhenPickFromGalleryCanceled_FinishesWithNull() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void onActivityResult_whenPickFromGalleryCanceled_finishesWithNull() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
     delegate.onActivityResult(
         ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_CANCELED, null);
@@ -368,7 +373,7 @@
   }
 
   @Test
-  public void onActivityResult_WhenPickFromGalleryCanceled_StoresNothingInCache() {
+  public void onActivityResult_whenPickFromGalleryCanceled_storesNothingInCache() {
     ImagePickerDelegate delegate = createDelegate();
 
     delegate.onActivityResult(
@@ -379,8 +384,9 @@
 
   @Test
   public void
-      onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_FinishesWithImagePath() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+      onActivityResult_whenImagePickedFromGallery_andNoResizeNeeded_finishesWithImagePath() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
     delegate.onActivityResult(
         ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
@@ -390,7 +396,7 @@
   }
 
   @Test
-  public void onActivityResult_WhenImagePickedFromGallery_AndNoResizeNeeded_StoresImageInCache() {
+  public void onActivityResult_whenImagePickedFromGallery_andNoResizeNeeded_StoresImageInCache() {
     ImagePickerDelegate delegate = createDelegate();
 
     delegate.onActivityResult(
@@ -404,10 +410,9 @@
 
   @Test
   public void
-      onActivityResult_WhenImagePickedFromGallery_AndResizeNeeded_FinishesWithScaledImagePath() {
-    when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH);
-
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+      onActivityResult_whenImagePickedFromGallery_andResizeNeeded_finishesWithScaledImagePath() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null);
     delegate.onActivityResult(
         ImagePickerDelegate.REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
 
@@ -417,10 +422,9 @@
 
   @Test
   public void
-      onActivityResult_WhenVideoPickedFromGallery_AndResizeParametersSupplied_FinishesWithFilePath() {
-    when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH);
-
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+      onActivityResult_whenVideoPickedFromGallery_andResizeParametersSupplied_finishesWithFilePath() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(new ImageOutputOptions(WIDTH, null, null), null);
     delegate.onActivityResult(
         ImagePickerDelegate.REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY, Activity.RESULT_OK, mockIntent);
 
@@ -429,8 +433,9 @@
   }
 
   @Test
-  public void onActivityResult_WhenTakeImageWithCameraCanceled_FinishesWithNull() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void onActivityResult_whenTakeImageWithCameraCanceled_finishesWithNull() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
 
     delegate.onActivityResult(
         ImagePickerDelegate.REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA, Activity.RESULT_CANCELED, null);
@@ -440,8 +445,9 @@
   }
 
   @Test
-  public void onActivityResult_WhenImageTakenWithCamera_AndNoResizeNeeded_FinishesWithImagePath() {
-    ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();
+  public void onActivityResult_whenImageTakenWithCamera_andNoResizeNeeded_finishesWithImagePath() {
+    ImagePickerDelegate delegate =
+        createDelegateWithPendingResultAndOptions(DEFAULT_IMAGE_OPTIONS, null);
     when(cache.retrievePendingCameraMediaUriPath()).thenReturn("testString");
 
     delegate.onActivityResult(
@@ -453,11 +459,11 @@
 
   @Test
   public void
-      onActivityResult_WhenImageTakenWithCamera_AndResizeNeeded_FinishesWithScaledImagePath() {
-    when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH);
+      onActivityResult_whenImageTakenWithCamera_andResizeNeeded_finishesWithScaledImagePath() {
     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);
 
@@ -467,11 +473,11 @@
 
   @Test
   public void
-      onActivityResult_WhenVideoTakenWithCamera_AndResizeParametersSupplied_FinishesWithFilePath() {
-    when(mockMethodCall.argument("maxWidth")).thenReturn(WIDTH);
+      onActivityResult_whenVideoTakenWithCamera_andResizeParametersSupplied_finishesWithFilePath() {
     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);
 
@@ -481,11 +487,11 @@
 
   @Test
   public void
-      onActivityResult_WhenVideoTakenWithCamera_AndMaxDurationParametersSupplied_FinishesWithFilePath() {
-    when(mockMethodCall.argument("maxDuration")).thenReturn(MAX_DURATION);
+      onActivityResult_whenVideoTakenWithCamera_andMaxDurationParametersSupplied_finishesWithFilePath() {
     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 @@
         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 328c964..8b91351 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 @@
   }
 
   @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 @@
   }
 
   @Test
-  public void onMethodCall_WhenCalledWithUnknownMethod_ThrowsException() {
+  public void onMethodCall_whenCalledWithUnknownMethod_throwsException() {
     IllegalArgumentException e =
         assertThrows(
             IllegalArgumentException.class,
@@ -97,43 +98,59 @@
   }
 
   @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_WhenSourceIsCamera_InvokesTakeImageWithCamera() {
-    MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA);
+  public void onMethodCall_usingPhotoPicker_invokesChooseMultiImageFromGallery() {
+    MethodCall call = buildMethodCall(PICK_MULTI_IMAGE, SOURCE_GALLERY, true);
     plugin.onMethodCall(call, mockResult);
-    verify(mockImagePickerDelegate).takeImageWithCamera(eq(call), any());
+    verify(mockImagePickerDelegate).chooseMultiImageFromGallery(any(), eq(true), any());
     verifyNoInteractions(mockResult);
   }
 
   @Test
-  public void onMethodCall_PickingImage_WhenSourceIsCamera_InvokesTakeImageWithCamera_RearCamera() {
-    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(any(), any());
+    verifyNoInteractions(mockResult);
+  }
+
+  @Test
+  public void onMethodCall_PickingImage_whenSourceIsCamera_invokesTakeImageWithCamera_RearCamera() {
+    MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA, null);
     HashMap<String, Object> arguments = getArgumentMap(call);
     arguments.put("cameraDevice", 0);
     plugin.onMethodCall(call, mockResult);
@@ -142,8 +159,8 @@
 
   @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<String, Object> arguments = getArgumentMap(call);
     arguments.put("cameraDevice", 1);
     plugin.onMethodCall(call, mockResult);
@@ -151,8 +168,8 @@
   }
 
   @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<String, Object> arguments = getArgumentMap(call);
     arguments.put("cameraDevice", 0);
     plugin.onMethodCall(call, mockResult);
@@ -161,8 +178,8 @@
 
   @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<String, Object> arguments = getArgumentMap(call);
     arguments.put("cameraDevice", 1);
     plugin.onMethodCall(call, mockResult);
@@ -170,7 +187,7 @@
   }
 
   @Test
-  public void onResiter_WhenAcitivityIsNull_ShouldNotCrash() {
+  public void onRegister_whenActivityIsNull_shouldNotCrash() {
     when(mockRegistrar.activity()).thenReturn(null);
     ImagePickerPlugin.registerWith((mockRegistrar));
     assertTrue(
@@ -178,14 +195,14 @@
   }
 
   @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 @@
   }
 
   @Test
-  public void onDetachedFromActivity_ShouldReleaseActivityState() {
+  public void onDetachedFromActivity_shouldReleaseActivityState() {
     final BinaryMessenger mockBinaryMessenger = mock(BinaryMessenger.class);
     when(mockPluginBinding.getBinaryMessenger()).thenReturn(mockBinaryMessenger);
 
@@ -217,9 +234,13 @@
     assertNull(plugin.getActivityState());
   }
 
-  private MethodCall buildMethodCall(String method, final int source) {
+  private MethodCall buildMethodCall(
+      String method, final int source, @Nullable Boolean usePhotoPicker) {
     final Map<String, Object> 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 a371003..2287c4a 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 @@
   }
 
   @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() {
+  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"));
   }
 }
diff --git a/packages/image_picker/image_picker_android/pubspec.yaml b/packages/image_picker/image_picker_android/pubspec.yaml
index 1c22e9c..812026d 100755
--- a/packages/image_picker/image_picker_android/pubspec.yaml
+++ b/packages/image_picker/image_picker_android/pubspec.yaml
@@ -3,7 +3,7 @@
 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"