[camera] android-rework part 9: Final implementation of camera class (#4059)
This PR adds the final implementation for the Camera class that incorporates all the features from previous parts.
diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md
index 6948980..68188d6 100644
--- a/packages/camera/camera/CHANGELOG.md
+++ b/packages/camera/camera/CHANGELOG.md
@@ -1,5 +1,8 @@
-## NEXT
+## 0.9.0
+* Complete rewrite of Android plugin to fix many capture, focus, flash, orientation and exposure issues.
+* Fixed crash when opening front-facing cameras on some legacy android devices like Sony XZ.
+* Android Flash mode works with full precapture sequence.
* Updated Android lint settings.
## 0.8.1+7
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
index 4c1370f..4724d22 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java
@@ -4,27 +4,19 @@
package io.flutter.plugins.camera;
-import static io.flutter.plugins.camera.CameraUtils.computeBestPreviewSize;
-
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.ImageFormat;
-import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
-import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
-import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.media.CamcorderProfile;
@@ -35,27 +27,43 @@
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
-import android.os.SystemClock;
import android.util.Log;
-import android.util.Range;
-import android.util.Rational;
import android.util.Size;
+import android.view.Display;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugin.common.EventChannel;
+import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
-import io.flutter.plugins.camera.PictureCaptureRequest.State;
+import io.flutter.plugins.camera.features.CameraFeature;
+import io.flutter.plugins.camera.features.CameraFeatureFactory;
+import io.flutter.plugins.camera.features.CameraFeatures;
+import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
+import io.flutter.plugins.camera.features.autofocus.FocusMode;
+import io.flutter.plugins.camera.features.exposurelock.ExposureLockFeature;
+import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
+import io.flutter.plugins.camera.features.exposureoffset.ExposureOffsetFeature;
+import io.flutter.plugins.camera.features.exposurepoint.ExposurePointFeature;
+import io.flutter.plugins.camera.features.flash.FlashFeature;
+import io.flutter.plugins.camera.features.flash.FlashMode;
+import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
+import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
+import io.flutter.plugins.camera.features.zoomlevel.ZoomLevelFeature;
import io.flutter.plugins.camera.media.MediaRecorderBuilder;
-import io.flutter.plugins.camera.types.ExposureMode;
-import io.flutter.plugins.camera.types.FlashMode;
-import io.flutter.plugins.camera.types.FocusMode;
-import io.flutter.plugins.camera.types.ResolutionPreset;
+import io.flutter.plugins.camera.types.CaptureTimeoutsWrapper;
import io.flutter.view.TextureRegistry.SurfaceTextureEntry;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -71,151 +79,173 @@
void onError(String errorCode, String errorMessage);
}
-public class Camera {
+class Camera
+ implements CameraCaptureCallback.CameraCaptureStateListener,
+ ImageReader.OnImageAvailableListener,
+ LifecycleObserver {
private static final String TAG = "Camera";
- /** Timeout for the pre-capture sequence. */
- private static final long PRECAPTURE_TIMEOUT_MS = 1000;
-
- private final SurfaceTextureEntry flutterTexture;
- private final CameraManager cameraManager;
- private final DeviceOrientationManager deviceOrientationListener;
- private final boolean isFrontFacing;
- private final int sensorOrientation;
- private final String cameraName;
- private final Size captureSize;
- private final Size previewSize;
- private final boolean enableAudio;
- private final Context applicationContext;
- private final CamcorderProfile recordingProfile;
- private final DartMessenger dartMessenger;
- private final CameraZoom cameraZoom;
- private final CameraCharacteristics cameraCharacteristics;
-
- private CameraDevice cameraDevice;
- private CameraCaptureSession cameraCaptureSession;
- private ImageReader pictureImageReader;
- private ImageReader imageStreamReader;
- private CaptureRequest.Builder captureRequestBuilder;
- private MediaRecorder mediaRecorder;
- private boolean recordingVideo;
- private File videoRecordingFile;
- private FlashMode flashMode;
- private ExposureMode exposureMode;
- private FocusMode focusMode;
- private PictureCaptureRequest pictureCaptureRequest;
- private CameraRegions cameraRegions;
- private int exposureOffset;
- private boolean useAutoFocus = true;
- private Range<Integer> fpsRange;
- private PlatformChannel.DeviceOrientation lockedCaptureOrientation;
- private long preCaptureStartTime;
-
private static final HashMap<String, Integer> supportedImageFormats;
- // Current supported outputs
+
+ // Current supported outputs.
static {
supportedImageFormats = new HashMap<>();
- supportedImageFormats.put("yuv420", 35);
- supportedImageFormats.put("jpeg", 256);
+ supportedImageFormats.put("yuv420", ImageFormat.YUV_420_888);
+ supportedImageFormats.put("jpeg", ImageFormat.JPEG);
}
+ /**
+ * Holds all of the camera features/settings and will be used to update the request builder when
+ * one changes.
+ */
+ private final CameraFeatures cameraFeatures;
+
+ private final SurfaceTextureEntry flutterTexture;
+ private final boolean enableAudio;
+ private final Context applicationContext;
+ private final DartMessenger dartMessenger;
+ private final CameraProperties cameraProperties;
+ private final CameraFeatureFactory cameraFeatureFactory;
+ private final Activity activity;
+ /** A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. */
+ private final CameraCaptureCallback cameraCaptureCallback;
+ /** A {@link Handler} for running tasks in the background. */
+ private Handler backgroundHandler;
+
+ /** An additional thread for running tasks that shouldn't block the UI. */
+ private HandlerThread backgroundHandlerThread;
+
+ private CameraDevice cameraDevice;
+ private CameraCaptureSession captureSession;
+ private ImageReader pictureImageReader;
+ private ImageReader imageStreamReader;
+ /** {@link CaptureRequest.Builder} for the camera preview */
+ private CaptureRequest.Builder previewRequestBuilder;
+
+ private MediaRecorder mediaRecorder;
+ /** True when recording video. */
+ private boolean recordingVideo;
+
+ private File captureFile;
+
+ /** Holds the current capture timeouts */
+ private CaptureTimeoutsWrapper captureTimeouts;
+
+ private MethodChannel.Result flutterResult;
+
public Camera(
final Activity activity,
final SurfaceTextureEntry flutterTexture,
+ final CameraFeatureFactory cameraFeatureFactory,
final DartMessenger dartMessenger,
- final String cameraName,
- final String resolutionPreset,
- final boolean enableAudio)
- throws CameraAccessException {
+ final CameraProperties cameraProperties,
+ final ResolutionPreset resolutionPreset,
+ final boolean enableAudio) {
+
if (activity == null) {
throw new IllegalStateException("No activity available!");
}
- this.cameraName = cameraName;
+ this.activity = activity;
this.enableAudio = enableAudio;
this.flutterTexture = flutterTexture;
this.dartMessenger = dartMessenger;
- this.cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
this.applicationContext = activity.getApplicationContext();
- this.flashMode = FlashMode.auto;
- this.exposureMode = ExposureMode.auto;
- this.focusMode = FocusMode.auto;
- this.exposureOffset = 0;
+ this.cameraProperties = cameraProperties;
+ this.cameraFeatureFactory = cameraFeatureFactory;
+ this.cameraFeatures =
+ CameraFeatures.init(
+ cameraFeatureFactory, cameraProperties, activity, dartMessenger, resolutionPreset);
- cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName);
- initFps(cameraCharacteristics);
- sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
- isFrontFacing =
- cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
- == CameraMetadata.LENS_FACING_FRONT;
- ResolutionPreset preset = ResolutionPreset.valueOf(resolutionPreset);
- recordingProfile =
- CameraUtils.getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset);
- captureSize = new Size(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight);
- previewSize = computeBestPreviewSize(cameraName, preset);
- cameraZoom =
- new CameraZoom(
- cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE),
- cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM));
+ // Create capture callback.
+ captureTimeouts = new CaptureTimeoutsWrapper(3000, 3000);
+ cameraCaptureCallback = CameraCaptureCallback.create(this, captureTimeouts);
- deviceOrientationListener =
- new DeviceOrientationManager(activity, dartMessenger, isFrontFacing, sensorOrientation);
- deviceOrientationListener.start();
+ startBackgroundThread();
}
- private void initFps(CameraCharacteristics cameraCharacteristics) {
- try {
- Range<Integer>[] ranges =
- cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
- if (ranges != null) {
- for (Range<Integer> range : ranges) {
- int upper = range.getUpper();
- Log.i("Camera", "[FPS Range Available] is:" + range);
- if (upper >= 10) {
- if (fpsRange == null || upper > fpsRange.getUpper()) {
- fpsRange = range;
- }
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
+ @Override
+ public void onConverged() {
+ takePictureAfterPrecapture();
+ }
+
+ @Override
+ public void onPrecapture() {
+ runPrecaptureSequence();
+ }
+
+ /**
+ * Updates the builder settings with all of the available features.
+ *
+ * @param requestBuilder request builder to update.
+ */
+ private void updateBuilderSettings(CaptureRequest.Builder requestBuilder) {
+ for (CameraFeature feature : cameraFeatures.getAllFeatures()) {
+ Log.d(TAG, "Updating builder with feature: " + feature.getDebugName());
+ feature.updateBuilder(requestBuilder);
}
- Log.i("Camera", "[FPS Range] is:" + fpsRange);
}
private void prepareMediaRecorder(String outputFilePath) throws IOException {
+ Log.i(TAG, "prepareMediaRecorder");
+
if (mediaRecorder != null) {
mediaRecorder.release();
}
+ final PlatformChannel.DeviceOrientation lockedOrientation =
+ ((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
+ .getLockedCaptureOrientation();
+
mediaRecorder =
- new MediaRecorderBuilder(recordingProfile, outputFilePath)
+ new MediaRecorderBuilder(getRecordingProfile(), outputFilePath)
.setEnableAudio(enableAudio)
.setMediaOrientation(
- lockedCaptureOrientation == null
- ? deviceOrientationListener.getMediaOrientation()
- : deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation))
+ lockedOrientation == null
+ ? getDeviceOrientationManager().getVideoOrientation()
+ : getDeviceOrientationManager().getVideoOrientation(lockedOrientation))
.build();
}
@SuppressLint("MissingPermission")
public void open(String imageFormatGroup) throws CameraAccessException {
+ final ResolutionFeature resolutionFeature = cameraFeatures.getResolution();
+
+ if (!resolutionFeature.checkIsSupported()) {
+ // Tell the user that the camera they are trying to open is not supported,
+ // as its {@link android.media.CamcorderProfile} cannot be fetched due to the name
+ // not being a valid parsable integer.
+ dartMessenger.sendCameraErrorEvent(
+ "Camera with name \""
+ + cameraProperties.getCameraName()
+ + "\" is not supported by this plugin.");
+ return;
+ }
+
+ // Always capture using JPEG format.
pictureImageReader =
ImageReader.newInstance(
- captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2);
+ resolutionFeature.getCaptureSize().getWidth(),
+ resolutionFeature.getCaptureSize().getHeight(),
+ ImageFormat.JPEG,
+ 1);
+ // For image streaming, use the provided image format or fall back to YUV420.
Integer imageFormat = supportedImageFormats.get(imageFormatGroup);
if (imageFormat == null) {
Log.w(TAG, "The selected imageFormatGroup is not supported by Android. Defaulting to yuv420");
imageFormat = ImageFormat.YUV_420_888;
}
-
- // Used to steam image byte data to dart side.
imageStreamReader =
- ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), imageFormat, 2);
+ ImageReader.newInstance(
+ resolutionFeature.getPreviewSize().getWidth(),
+ resolutionFeature.getPreviewSize().getHeight(),
+ imageFormat,
+ 1);
+ // Open the camera.
+ CameraManager cameraManager = CameraUtils.getCameraManager(activity);
cameraManager.openCamera(
- cameraName,
+ cameraProperties.getCameraName(),
new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice device) {
@@ -223,12 +253,12 @@
try {
startPreview();
dartMessenger.sendCameraInitializedEvent(
- previewSize.getWidth(),
- previewSize.getHeight(),
- exposureMode,
- focusMode,
- isExposurePointSupported(),
- isFocusPointSupported());
+ resolutionFeature.getPreviewSize().getWidth(),
+ resolutionFeature.getPreviewSize().getHeight(),
+ cameraFeatures.getExposureLock().getValue(),
+ cameraFeatures.getAutoFocus().getValue(),
+ cameraFeatures.getExposurePoint().checkIsSupported(),
+ cameraFeatures.getFocusPoint().checkIsSupported());
} catch (CameraAccessException e) {
dartMessenger.sendCameraErrorEvent(e.getMessage());
close();
@@ -237,18 +267,24 @@
@Override
public void onClosed(@NonNull CameraDevice camera) {
+ Log.i(TAG, "open | onClosed");
+
dartMessenger.sendCameraClosingEvent();
super.onClosed(camera);
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
+ Log.i(TAG, "open | onDisconnected");
+
close();
dartMessenger.sendCameraErrorEvent("The camera was disconnected.");
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int errorCode) {
+ Log.i(TAG, "open | onError");
+
close();
String errorDescription;
switch (errorCode) {
@@ -273,7 +309,7 @@
dartMessenger.sendCameraErrorEvent(errorDescription);
}
},
- null);
+ backgroundHandler);
}
private void createCaptureSession(int templateType, Surface... surfaces)
@@ -288,39 +324,45 @@
closeCaptureSession();
// Create a new capture builder.
- captureRequestBuilder = cameraDevice.createCaptureRequest(templateType);
+ previewRequestBuilder = cameraDevice.createCaptureRequest(templateType);
- // Build Flutter surface to render to
+ // Build Flutter surface to render to.
+ ResolutionFeature resolutionFeature = cameraFeatures.getResolution();
SurfaceTexture surfaceTexture = flutterTexture.surfaceTexture();
- surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
+ surfaceTexture.setDefaultBufferSize(
+ resolutionFeature.getPreviewSize().getWidth(),
+ resolutionFeature.getPreviewSize().getHeight());
Surface flutterSurface = new Surface(surfaceTexture);
- captureRequestBuilder.addTarget(flutterSurface);
+ previewRequestBuilder.addTarget(flutterSurface);
List<Surface> remainingSurfaces = Arrays.asList(surfaces);
if (templateType != CameraDevice.TEMPLATE_PREVIEW) {
// If it is not preview mode, add all surfaces as targets.
for (Surface surface : remainingSurfaces) {
- captureRequestBuilder.addTarget(surface);
+ previewRequestBuilder.addTarget(surface);
}
}
- cameraRegions = new CameraRegions(getRegionBoundaries());
+ // Update camera regions.
+ Size cameraBoundaries =
+ CameraRegionUtils.getCameraBoundaries(cameraProperties, previewRequestBuilder);
+ cameraFeatures.getExposurePoint().setCameraBoundaries(cameraBoundaries);
+ cameraFeatures.getFocusPoint().setCameraBoundaries(cameraBoundaries);
- // Prepare the callback
+ // Prepare the callback.
CameraCaptureSession.StateCallback callback =
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
+ // Camera was already closed.
if (cameraDevice == null) {
dartMessenger.sendCameraErrorEvent("The camera was closed during configuration.");
return;
}
- cameraCaptureSession = session;
+ captureSession = session;
- updateFpsRange();
- updateFocus(focusMode);
- updateFlash(flashMode);
- updateExposure(exposureMode);
+ Log.i(TAG, "Updating builder settings");
+ updateBuilderSettings(previewRequestBuilder);
refreshPreviewCaptureSession(
onSuccessCallback, (code, message) -> dartMessenger.sendCameraErrorEvent(message));
@@ -332,9 +374,9 @@
}
};
- // Start the session
+ // Start the session.
if (VERSION.SDK_INT >= VERSION_CODES.P) {
- // Collect all surfaces we want to render to.
+ // Collect all surfaces to render to.
List<OutputConfiguration> configs = new ArrayList<>();
configs.add(new OutputConfiguration(flutterSurface));
for (Surface surface : remainingSurfaces) {
@@ -342,7 +384,7 @@
}
createCaptureSessionWithSessionConfig(configs, callback);
} else {
- // Collect all surfaces we want to render to.
+ // Collect all surfaces to render to.
List<Surface> surfaceList = new ArrayList<>();
surfaceList.add(flutterSurface);
surfaceList.addAll(remainingSurfaces);
@@ -367,276 +409,273 @@
private void createCaptureSession(
List<Surface> surfaces, CameraCaptureSession.StateCallback callback)
throws CameraAccessException {
- cameraDevice.createCaptureSession(surfaces, callback, null);
+ cameraDevice.createCaptureSession(surfaces, callback, backgroundHandler);
}
+ // Send a repeating request to refresh capture session.
private void refreshPreviewCaptureSession(
@Nullable Runnable onSuccessCallback, @NonNull ErrorCallback onErrorCallback) {
- if (cameraCaptureSession == null) {
+ if (captureSession == null) {
+ Log.i(
+ TAG,
+ "[refreshPreviewCaptureSession] captureSession not yet initialized, "
+ + "skipping preview capture session refresh.");
return;
}
try {
- cameraCaptureSession.setRepeatingRequest(
- captureRequestBuilder.build(),
- pictureCaptureCallback,
- new Handler(Looper.getMainLooper()));
+ captureSession.setRepeatingRequest(
+ previewRequestBuilder.build(), cameraCaptureCallback, backgroundHandler);
if (onSuccessCallback != null) {
onSuccessCallback.run();
}
- } catch (CameraAccessException | IllegalStateException | IllegalArgumentException e) {
+
+ } catch (CameraAccessException e) {
onErrorCallback.onError("cameraAccess", e.getMessage());
}
}
- private void writeToFile(ByteBuffer buffer, File file) throws IOException {
- try (FileOutputStream outputStream = new FileOutputStream(file)) {
- while (0 < buffer.remaining()) {
- outputStream.getChannel().write(buffer);
- }
- }
- }
-
public void takePicture(@NonNull final Result result) {
- // Only take 1 picture at a time
- if (pictureCaptureRequest != null && !pictureCaptureRequest.isFinished()) {
+ // Only take one picture at a time.
+ if (cameraCaptureCallback.getCameraState() != CameraState.STATE_PREVIEW) {
result.error("captureAlreadyActive", "Picture is currently already being captured", null);
return;
}
- // Store the result
- this.pictureCaptureRequest = new PictureCaptureRequest(result);
- // Create temporary file
+ flutterResult = result;
+
+ // Create temporary file.
final File outputDir = applicationContext.getCacheDir();
- final File file;
try {
- file = File.createTempFile("CAP", ".jpg", outputDir);
+ captureFile = File.createTempFile("CAP", ".jpg", outputDir);
+ captureTimeouts.reset();
} catch (IOException | SecurityException e) {
- pictureCaptureRequest.error("cannotCreateFile", e.getMessage(), null);
+ dartMessenger.error(flutterResult, "cannotCreateFile", e.getMessage(), null);
return;
}
- // Listen for picture being taken
- pictureImageReader.setOnImageAvailableListener(
- reader -> {
- try (Image image = reader.acquireLatestImage()) {
- ByteBuffer buffer = image.getPlanes()[0].getBuffer();
- writeToFile(buffer, file);
- pictureCaptureRequest.finish(file.getAbsolutePath());
- } catch (IOException e) {
- pictureCaptureRequest.error("IOError", "Failed saving image", null);
- }
- },
- null);
+ // Listen for picture being taken.
+ pictureImageReader.setOnImageAvailableListener(this, backgroundHandler);
- if (useAutoFocus) {
+ final AutoFocusFeature autoFocusFeature = cameraFeatures.getAutoFocus();
+ final boolean isAutoFocusSupported = autoFocusFeature.checkIsSupported();
+ if (isAutoFocusSupported && autoFocusFeature.getValue() == FocusMode.auto) {
runPictureAutoFocus();
} else {
- runPicturePreCapture();
+ runPrecaptureSequence();
}
}
- private final CameraCaptureSession.CaptureCallback pictureCaptureCallback =
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull TotalCaptureResult result) {
- processCapture(result);
- }
-
- @Override
- public void onCaptureProgressed(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull CaptureResult partialResult) {
- processCapture(partialResult);
- }
-
- @Override
- public void onCaptureFailed(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull CaptureFailure failure) {
- if (pictureCaptureRequest == null || pictureCaptureRequest.isFinished()) {
- return;
- }
- String reason;
- boolean fatalFailure = false;
- switch (failure.getReason()) {
- case CaptureFailure.REASON_ERROR:
- reason = "An error happened in the framework";
- break;
- case CaptureFailure.REASON_FLUSHED:
- reason = "The capture has failed due to an abortCaptures() call";
- fatalFailure = true;
- break;
- default:
- reason = "Unknown reason";
- }
- Log.w("Camera", "pictureCaptureCallback.onCaptureFailed(): " + reason);
- if (fatalFailure) pictureCaptureRequest.error("captureFailure", reason, null);
- }
-
- private void processCapture(CaptureResult result) {
- if (pictureCaptureRequest == null) {
- return;
- }
-
- Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
- Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
- switch (pictureCaptureRequest.getState()) {
- case focusing:
- if (afState == null) {
- return;
- } else if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED
- || afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
- // Some devices might return null here, in which case we will also continue.
- if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
- runPictureCapture();
- } else {
- runPicturePreCapture();
- }
- }
- break;
- case preCapture:
- // Some devices might return null here, in which case we will also continue.
- if (aeState == null
- || aeState == CaptureRequest.CONTROL_AE_STATE_PRECAPTURE
- || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED
- || aeState == CaptureRequest.CONTROL_AE_STATE_CONVERGED) {
- pictureCaptureRequest.setState(State.waitingPreCaptureReady);
- setPreCaptureStartTime();
- }
- break;
- case waitingPreCaptureReady:
- if (aeState == null || aeState != CaptureRequest.CONTROL_AE_STATE_PRECAPTURE) {
- runPictureCapture();
- } else {
- if (hitPreCaptureTimeout()) {
- unlockAutoFocus();
- }
- }
- }
- }
- };
-
- private void runPictureAutoFocus() {
- assert (pictureCaptureRequest != null);
-
- pictureCaptureRequest.setState(PictureCaptureRequest.State.focusing);
- lockAutoFocus(pictureCaptureCallback);
- }
-
- private void runPicturePreCapture() {
- assert (pictureCaptureRequest != null);
- pictureCaptureRequest.setState(PictureCaptureRequest.State.preCapture);
-
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
- CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
-
- refreshPreviewCaptureSession(
- () ->
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
- CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE),
- (code, message) -> pictureCaptureRequest.error(code, message, null));
- }
-
- private void runPictureCapture() {
- assert (pictureCaptureRequest != null);
- pictureCaptureRequest.setState(PictureCaptureRequest.State.capturing);
+ /**
+ * Run the precapture sequence for capturing a still image. This method should be called when a
+ * response is received in {@link #cameraCaptureCallback} from lockFocus().
+ */
+ private void runPrecaptureSequence() {
+ Log.i(TAG, "runPrecaptureSequence");
try {
- final CaptureRequest.Builder captureBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
- captureBuilder.addTarget(pictureImageReader.getSurface());
- captureBuilder.set(
- CaptureRequest.SCALER_CROP_REGION,
- captureRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION));
- captureBuilder.set(
- CaptureRequest.JPEG_ORIENTATION,
- lockedCaptureOrientation == null
- ? deviceOrientationListener.getMediaOrientation()
- : deviceOrientationListener.getMediaOrientation(lockedCaptureOrientation));
+ // First set precapture state to idle or else it can hang in STATE_WAITING_PRECAPTURE_START.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
+ captureSession.capture(
+ previewRequestBuilder.build(), cameraCaptureCallback, backgroundHandler);
- switch (flashMode) {
- case off:
- captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- captureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
- break;
- case auto:
- captureBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
- break;
- case always:
- default:
- captureBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
- break;
- }
- cameraCaptureSession.stopRepeating();
- cameraCaptureSession.capture(
- captureBuilder.build(),
- new CameraCaptureSession.CaptureCallback() {
- @Override
- public void onCaptureCompleted(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull TotalCaptureResult result) {
- unlockAutoFocus();
- }
- },
- null);
+ // Repeating request to refresh preview session.
+ refreshPreviewCaptureSession(
+ null,
+ (code, message) -> dartMessenger.error(flutterResult, "cameraAccess", message, null));
+
+ // Start precapture.
+ cameraCaptureCallback.setCameraState(CameraState.STATE_WAITING_PRECAPTURE_START);
+
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
+
+ // Trigger one capture to start AE sequence.
+ captureSession.capture(
+ previewRequestBuilder.build(), cameraCaptureCallback, backgroundHandler);
+
} catch (CameraAccessException e) {
- pictureCaptureRequest.error("cameraAccess", e.getMessage(), null);
+ e.printStackTrace();
}
}
- private void lockAutoFocus(CaptureCallback callback) {
- captureRequestBuilder.set(
+ /**
+ * Capture a still picture. This method should be called when a response is received {@link
+ * #cameraCaptureCallback} from both lockFocus().
+ */
+ private void takePictureAfterPrecapture() {
+ Log.i(TAG, "captureStillPicture");
+ cameraCaptureCallback.setCameraState(CameraState.STATE_CAPTURING);
+
+ if (cameraDevice == null) {
+ return;
+ }
+ // This is the CaptureRequest.Builder that is used to take a picture.
+ CaptureRequest.Builder stillBuilder;
+ try {
+ stillBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ } catch (CameraAccessException e) {
+ dartMessenger.error(flutterResult, "cameraAccess", e.getMessage(), null);
+ return;
+ }
+ stillBuilder.addTarget(pictureImageReader.getSurface());
+
+ // Zoom.
+ stillBuilder.set(
+ CaptureRequest.SCALER_CROP_REGION,
+ previewRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION));
+
+ // Have all features update the builder.
+ updateBuilderSettings(stillBuilder);
+
+ // Orientation.
+ final PlatformChannel.DeviceOrientation lockedOrientation =
+ ((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
+ .getLockedCaptureOrientation();
+ stillBuilder.set(
+ CaptureRequest.JPEG_ORIENTATION,
+ lockedOrientation == null
+ ? getDeviceOrientationManager().getPhotoOrientation()
+ : getDeviceOrientationManager().getPhotoOrientation(lockedOrientation));
+
+ CameraCaptureSession.CaptureCallback captureCallback =
+ new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(
+ @NonNull CameraCaptureSession session,
+ @NonNull CaptureRequest request,
+ @NonNull TotalCaptureResult result) {
+ unlockAutoFocus();
+ }
+ };
+
+ try {
+ captureSession.stopRepeating();
+ captureSession.abortCaptures();
+ Log.i(TAG, "sending capture request");
+ captureSession.capture(stillBuilder.build(), captureCallback, backgroundHandler);
+ } catch (CameraAccessException e) {
+ dartMessenger.error(flutterResult, "cameraAccess", e.getMessage(), null);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private Display getDefaultDisplay() {
+ return activity.getWindowManager().getDefaultDisplay();
+ }
+
+ /** Starts a background thread and its {@link Handler}. */
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ public void startBackgroundThread() {
+ backgroundHandlerThread = new HandlerThread("CameraBackground");
+ try {
+ backgroundHandlerThread.start();
+ } catch (IllegalThreadStateException e) {
+ // Ignore exception in case the thread has already started.
+ }
+ backgroundHandler = new Handler(backgroundHandlerThread.getLooper());
+ }
+
+ /** Stops the background thread and its {@link Handler}. */
+ @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
+ public void stopBackgroundThread() {
+ if (backgroundHandlerThread != null) {
+ backgroundHandlerThread.quitSafely();
+ try {
+ backgroundHandlerThread.join();
+ } catch (InterruptedException e) {
+ dartMessenger.error(flutterResult, "cameraAccess", e.getMessage(), null);
+ }
+ }
+ backgroundHandlerThread = null;
+ backgroundHandler = null;
+ }
+
+ /** Start capturing a picture, doing autofocus first. */
+ private void runPictureAutoFocus() {
+ Log.i(TAG, "runPictureAutoFocus");
+
+ cameraCaptureCallback.setCameraState(CameraState.STATE_WAITING_FOCUS);
+ lockAutoFocus();
+ }
+
+ private void lockAutoFocus() {
+ Log.i(TAG, "lockAutoFocus");
+ if (captureSession == null) {
+ Log.i(TAG, "[unlockAutoFocus] captureSession null, returning");
+ return;
+ }
+
+ // Trigger AF to start.
+ previewRequestBuilder.set(
CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
- refreshPreviewCaptureSession(
- null, (code, message) -> pictureCaptureRequest.error(code, message, null));
+ try {
+ captureSession.capture(previewRequestBuilder.build(), null, backgroundHandler);
+ } catch (CameraAccessException e) {
+ dartMessenger.sendCameraErrorEvent(e.getMessage());
+ }
}
+ /** Cancel and reset auto focus state and refresh the preview session. */
private void unlockAutoFocus() {
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
- updateFocus(focusMode);
- try {
- cameraCaptureSession.capture(captureRequestBuilder.build(), null, null);
- } catch (CameraAccessException ignored) {
+ Log.i(TAG, "unlockAutoFocus");
+ if (captureSession == null) {
+ Log.i(TAG, "[unlockAutoFocus] captureSession null, returning");
+ return;
}
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+ try {
+ // Cancel existing AF state.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
+ captureSession.capture(previewRequestBuilder.build(), null, backgroundHandler);
+
+ // Set AF state to idle again.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
+
+ captureSession.capture(previewRequestBuilder.build(), null, backgroundHandler);
+ } catch (CameraAccessException e) {
+ dartMessenger.sendCameraErrorEvent(e.getMessage());
+ return;
+ }
refreshPreviewCaptureSession(
null,
- (errorCode, errorMessage) -> pictureCaptureRequest.error(errorCode, errorMessage, null));
+ (errorCode, errorMessage) ->
+ dartMessenger.error(flutterResult, errorCode, errorMessage, null));
}
- public void startVideoRecording(Result result) {
+ public void startVideoRecording(@NonNull Result result) {
final File outputDir = applicationContext.getCacheDir();
try {
- videoRecordingFile = File.createTempFile("REC", ".mp4", outputDir);
+ captureFile = File.createTempFile("REC", ".mp4", outputDir);
} catch (IOException | SecurityException e) {
result.error("cannotCreateFile", e.getMessage(), null);
return;
}
-
try {
- prepareMediaRecorder(videoRecordingFile.getAbsolutePath());
- recordingVideo = true;
+ prepareMediaRecorder(captureFile.getAbsolutePath());
+ } catch (IOException e) {
+ recordingVideo = false;
+ captureFile = null;
+ result.error("videoRecordingFailed", e.getMessage(), null);
+ return;
+ }
+ // Re-create autofocus feature so it's using video focus mode now.
+ cameraFeatures.setAutoFocus(
+ cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
+ recordingVideo = true;
+ try {
createCaptureSession(
CameraDevice.TEMPLATE_RECORD, () -> mediaRecorder.start(), mediaRecorder.getSurface());
result.success(null);
- } catch (CameraAccessException | IOException e) {
+ } catch (CameraAccessException e) {
recordingVideo = false;
- videoRecordingFile = null;
+ captureFile = null;
result.error("videoRecordingFailed", e.getMessage(), null);
}
}
@@ -646,24 +685,25 @@
result.success(null);
return;
}
-
+ // Re-create autofocus feature so it's using continuous capture focus mode now.
+ cameraFeatures.setAutoFocus(
+ cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false));
+ recordingVideo = false;
try {
- recordingVideo = false;
-
- try {
- cameraCaptureSession.abortCaptures();
- mediaRecorder.stop();
- } catch (CameraAccessException | IllegalStateException e) {
- // Ignore exceptions and try to continue (changes are camera session already aborted capture)
- }
-
- mediaRecorder.reset();
+ captureSession.abortCaptures();
+ mediaRecorder.stop();
+ } catch (CameraAccessException | IllegalStateException e) {
+ // Ignore exceptions and try to continue (changes are camera session already aborted capture).
+ }
+ mediaRecorder.reset();
+ try {
startPreview();
- result.success(videoRecordingFile.getAbsolutePath());
- videoRecordingFile = null;
} catch (CameraAccessException | IllegalStateException e) {
result.error("videoRecordingFailed", e.getMessage(), null);
+ return;
}
+ result.success(captureFile.getAbsolutePath());
+ captureFile = null;
}
public void pauseVideoRecording(@NonNull final Result result) {
@@ -709,259 +749,185 @@
result.success(null);
}
- public void setFlashMode(@NonNull final Result result, FlashMode mode)
- throws CameraAccessException {
- // Get the flash availability
- Boolean flashAvailable =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ /**
+ * Method handler for setting new flash modes.
+ *
+ * @param result Flutter result.
+ * @param newMode new mode.
+ */
+ public void setFlashMode(@NonNull final Result result, @NonNull FlashMode newMode) {
+ // Save the new flash mode setting.
+ final FlashFeature flashFeature = cameraFeatures.getFlash();
+ flashFeature.setValue(newMode);
+ flashFeature.updateBuilder(previewRequestBuilder);
- // Check if flash is available.
- if (flashAvailable == null || !flashAvailable) {
- result.error("setFlashModeFailed", "Device does not have flash capabilities", null);
- return;
- }
-
- // If switching directly from torch to auto or on, make sure we turn off the torch.
- if (flashMode == FlashMode.torch && mode != FlashMode.torch && mode != FlashMode.off) {
- updateFlash(FlashMode.off);
-
- this.cameraCaptureSession.setRepeatingRequest(
- captureRequestBuilder.build(),
- new CaptureCallback() {
- private boolean isFinished = false;
-
- @Override
- public void onCaptureCompleted(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull TotalCaptureResult captureResult) {
- if (isFinished) {
- return;
- }
-
- updateFlash(mode);
- refreshPreviewCaptureSession(
- () -> {
- result.success(null);
- isFinished = true;
- },
- (code, message) ->
- result.error("setFlashModeFailed", "Could not set flash mode.", null));
- }
-
- @Override
- public void onCaptureFailed(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull CaptureFailure failure) {
- if (isFinished) {
- return;
- }
-
- result.error("setFlashModeFailed", "Could not set flash mode.", null);
- isFinished = true;
- }
- },
- null);
- } else {
- updateFlash(mode);
-
- refreshPreviewCaptureSession(
- () -> result.success(null),
- (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null));
- }
- }
-
- public void setExposureMode(@NonNull final Result result, ExposureMode mode)
- throws CameraAccessException {
- updateExposure(mode);
- cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
- result.success(null);
- }
-
- public void setExposurePoint(@NonNull final Result result, Double x, Double y)
- throws CameraAccessException {
- // Check if exposure point functionality is available.
- if (!isExposurePointSupported()) {
- result.error(
- "setExposurePointFailed", "Device does not have exposure point capabilities", null);
- return;
- }
- // Check if the current region boundaries are known
- if (cameraRegions.getMaxBoundaries() == null) {
- result.error("setExposurePointFailed", "Could not determine max region boundaries", null);
- return;
- }
- // Set the metering rectangle
- if (x == null || y == null) cameraRegions.resetAutoExposureMeteringRectangle();
- else cameraRegions.setAutoExposureMeteringRectangleFromPoint(y, 1 - x);
- // Apply it
- updateExposure(exposureMode);
refreshPreviewCaptureSession(
- () -> result.success(null), (code, message) -> result.error("CameraAccess", message, null));
+ () -> result.success(null),
+ (code, message) -> result.error("setFlashModeFailed", "Could not set flash mode.", null));
}
- public void setFocusMode(@NonNull final Result result, FocusMode mode)
- throws CameraAccessException {
- this.focusMode = mode;
+ /**
+ * Method handler for setting new exposure modes.
+ *
+ * @param result Flutter result.
+ * @param newMode new mode.
+ */
+ public void setExposureMode(@NonNull final Result result, @NonNull ExposureMode newMode) {
+ final ExposureLockFeature exposureLockFeature = cameraFeatures.getExposureLock();
+ exposureLockFeature.setValue(newMode);
+ exposureLockFeature.updateBuilder(previewRequestBuilder);
- updateFocus(mode);
+ refreshPreviewCaptureSession(
+ () -> result.success(null),
+ (code, message) ->
+ result.error("setExposureModeFailed", "Could not set exposure mode.", null));
+ }
- switch (mode) {
- case auto:
- refreshPreviewCaptureSession(
- null, (code, message) -> result.error("setFocusMode", message, null));
- break;
+ /**
+ * Sets new exposure point from dart.
+ *
+ * @param result Flutter result.
+ * @param point The exposure point.
+ */
+ public void setExposurePoint(@NonNull final Result result, @Nullable Point point) {
+ final ExposurePointFeature exposurePointFeature = cameraFeatures.getExposurePoint();
+ exposurePointFeature.setValue(point);
+ exposurePointFeature.updateBuilder(previewRequestBuilder);
+
+ refreshPreviewCaptureSession(
+ () -> result.success(null),
+ (code, message) ->
+ result.error("setExposurePointFailed", "Could not set exposure point.", null));
+ }
+
+ /** Return the max exposure offset value supported by the camera to dart. */
+ public double getMaxExposureOffset() {
+ return cameraFeatures.getExposureOffset().getMaxExposureOffset();
+ }
+
+ /** Return the min exposure offset value supported by the camera to dart. */
+ public double getMinExposureOffset() {
+ return cameraFeatures.getExposureOffset().getMinExposureOffset();
+ }
+
+ /** Return the exposure offset step size to dart. */
+ public double getExposureOffsetStepSize() {
+ return cameraFeatures.getExposureOffset().getExposureOffsetStepSize();
+ }
+
+ /**
+ * Sets new focus mode from dart.
+ *
+ * @param result Flutter result.
+ * @param newMode New mode.
+ */
+ public void setFocusMode(final Result result, @NonNull FocusMode newMode) {
+ final AutoFocusFeature autoFocusFeature = cameraFeatures.getAutoFocus();
+ autoFocusFeature.setValue(newMode);
+ autoFocusFeature.updateBuilder(previewRequestBuilder);
+
+ /*
+ * For focus mode an extra step of actually locking/unlocking the
+ * focus has to be done, in order to ensure it goes into the correct state.
+ */
+ switch (newMode) {
case locked:
- lockAutoFocus(
- new CaptureCallback() {
- @Override
- public void onCaptureCompleted(
- @NonNull CameraCaptureSession session,
- @NonNull CaptureRequest request,
- @NonNull TotalCaptureResult result) {
- unlockAutoFocus();
- }
- });
+ // Perform a single focus trigger.
+ lockAutoFocus();
+ if (captureSession == null) {
+ Log.i(TAG, "[unlockAutoFocus] captureSession null, returning");
+ return;
+ }
+
+ // Set AF state to idle again.
+ previewRequestBuilder.set(
+ CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
+
+ try {
+ captureSession.setRepeatingRequest(
+ previewRequestBuilder.build(), null, backgroundHandler);
+ } catch (CameraAccessException e) {
+ if (result != null) {
+ result.error("setFocusModeFailed", "Error setting focus mode: " + e.getMessage(), null);
+ }
+ return;
+ }
+ break;
+ case auto:
+ // Cancel current AF trigger and set AF to idle again.
+ unlockAutoFocus();
break;
}
- result.success(null);
- }
- public void setFocusPoint(@NonNull final Result result, Double x, Double y)
- throws CameraAccessException {
- // Check if focus point functionality is available.
- if (!isFocusPointSupported()) {
- result.error("setFocusPointFailed", "Device does not have focus point capabilities", null);
- return;
+ if (result != null) {
+ result.success(null);
}
-
- // Check if the current region boundaries are known
- if (cameraRegions.getMaxBoundaries() == null) {
- result.error("setFocusPointFailed", "Could not determine max region boundaries", null);
- return;
- }
-
- // Set the metering rectangle
- if (x == null || y == null) {
- cameraRegions.resetAutoFocusMeteringRectangle();
- } else {
- cameraRegions.setAutoFocusMeteringRectangleFromPoint(y, 1 - x);
- }
-
- // Apply the new metering rectangle
- setFocusMode(result, focusMode);
}
- @TargetApi(VERSION_CODES.P)
- private boolean supportsDistortionCorrection() throws CameraAccessException {
- int[] availableDistortionCorrectionModes =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES);
- if (availableDistortionCorrectionModes == null) availableDistortionCorrectionModes = new int[0];
- long nonOffModesSupported =
- Arrays.stream(availableDistortionCorrectionModes)
- .filter((value) -> value != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF)
- .count();
- return nonOffModesSupported > 0;
+ /**
+ * Sets new focus point from dart.
+ *
+ * @param result Flutter result.
+ * @param point the new coordinates.
+ */
+ public void setFocusPoint(@NonNull final Result result, @Nullable Point point) {
+ final FocusPointFeature focusPointFeature = cameraFeatures.getFocusPoint();
+ focusPointFeature.setValue(point);
+ focusPointFeature.updateBuilder(previewRequestBuilder);
+
+ refreshPreviewCaptureSession(
+ () -> result.success(null),
+ (code, message) -> result.error("setFocusPointFailed", "Could not set focus point.", null));
+
+ this.setFocusMode(null, cameraFeatures.getAutoFocus().getValue());
}
- private Size getRegionBoundaries() throws CameraAccessException {
- // No distortion correction support
- if (android.os.Build.VERSION.SDK_INT < VERSION_CODES.P || !supportsDistortionCorrection()) {
- return cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
- }
- // Get the current distortion correction mode
- Integer distortionCorrectionMode =
- captureRequestBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE);
- // Return the correct boundaries depending on the mode
- android.graphics.Rect rect;
- if (distortionCorrectionMode == null
- || distortionCorrectionMode == CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) {
- rect =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- } else {
- rect =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- }
- return rect == null ? null : new Size(rect.width(), rect.height());
- }
+ /**
+ * Sets a new exposure offset from dart. From dart the offset comes as a double, like +1.3 or
+ * -1.3.
+ *
+ * @param result flutter result.
+ * @param offset new value.
+ */
+ public void setExposureOffset(@NonNull final Result result, double offset) {
+ final ExposureOffsetFeature exposureOffsetFeature = cameraFeatures.getExposureOffset();
+ exposureOffsetFeature.setValue(offset);
+ exposureOffsetFeature.updateBuilder(previewRequestBuilder);
- private boolean isExposurePointSupported() throws CameraAccessException {
- Integer supportedRegions =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
- return supportedRegions != null && supportedRegions > 0;
- }
-
- private boolean isFocusPointSupported() throws CameraAccessException {
- Integer supportedRegions =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
- return supportedRegions != null && supportedRegions > 0;
- }
-
- public double getMinExposureOffset() throws CameraAccessException {
- Range<Integer> range =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
- double minStepped = range == null ? 0 : range.getLower();
- double stepSize = getExposureOffsetStepSize();
- return minStepped * stepSize;
- }
-
- public double getMaxExposureOffset() throws CameraAccessException {
- Range<Integer> range =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
- double maxStepped = range == null ? 0 : range.getUpper();
- double stepSize = getExposureOffsetStepSize();
- return maxStepped * stepSize;
- }
-
- public double getExposureOffsetStepSize() throws CameraAccessException {
- Rational stepSize =
- cameraManager
- .getCameraCharacteristics(cameraDevice.getId())
- .get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
- return stepSize == null ? 0.0 : stepSize.doubleValue();
- }
-
- public void setExposureOffset(@NonNull final Result result, double offset)
- throws CameraAccessException {
- // Set the exposure offset
- double stepSize = getExposureOffsetStepSize();
- exposureOffset = (int) (offset / stepSize);
- // Apply it
- updateExposure(exposureMode);
- this.cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
- result.success(offset);
+ refreshPreviewCaptureSession(
+ () -> result.success(null),
+ (code, message) ->
+ result.error("setExposureOffsetFailed", "Could not set exposure offset.", null));
}
public float getMaxZoomLevel() {
- return cameraZoom.maxZoom;
+ return cameraFeatures.getZoomLevel().getMaximumZoomLevel();
}
public float getMinZoomLevel() {
- return CameraZoom.DEFAULT_ZOOM_FACTOR;
+ return cameraFeatures.getZoomLevel().getMinimumZoomLevel();
}
+ /** Shortcut to get current recording profile. */
+ CamcorderProfile getRecordingProfile() {
+ return cameraFeatures.getResolution().getRecordingProfile();
+ }
+
+ /** Shortut to get deviceOrientationListener. */
+ DeviceOrientationManager getDeviceOrientationManager() {
+ return cameraFeatures.getSensorOrientation().getDeviceOrientationManager();
+ }
+
+ /**
+ * Sets zoom level from dart.
+ *
+ * @param result Flutter result.
+ * @param zoom new value.
+ */
public void setZoomLevel(@NonNull final Result result, float zoom) throws CameraAccessException {
- float maxZoom = cameraZoom.maxZoom;
- float minZoom = CameraZoom.DEFAULT_ZOOM_FACTOR;
+ final ZoomLevelFeature zoomLevel = cameraFeatures.getZoomLevel();
+ float maxZoom = zoomLevel.getMaximumZoomLevel();
+ float minZoom = zoomLevel.getMinimumZoomLevel();
if (zoom > maxZoom || zoom < minZoom) {
String errorMessage =
@@ -974,122 +940,31 @@
return;
}
- //Zoom area is calculated relative to sensor area (activeRect)
- if (captureRequestBuilder != null) {
- final Rect computedZoom = cameraZoom.computeZoom(zoom);
- captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom);
- cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, null);
- }
+ zoomLevel.setValue(zoom);
+ zoomLevel.updateBuilder(previewRequestBuilder);
- result.success(null);
+ refreshPreviewCaptureSession(
+ () -> result.success(null),
+ (code, message) -> result.error("setZoomLevelFailed", "Could not set zoom level.", null));
}
+ /**
+ * Lock capture orientation from dart.
+ *
+ * @param orientation new orientation.
+ */
public void lockCaptureOrientation(PlatformChannel.DeviceOrientation orientation) {
- this.lockedCaptureOrientation = orientation;
+ cameraFeatures.getSensorOrientation().lockCaptureOrientation(orientation);
}
+ /** Unlock capture orientation from dart. */
public void unlockCaptureOrientation() {
- this.lockedCaptureOrientation = null;
- }
-
- private void updateFpsRange() {
- if (fpsRange == null) {
- return;
- }
-
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
- }
-
- private void updateFocus(FocusMode mode) {
- if (useAutoFocus) {
- int[] modes = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
- // Auto focus is not supported
- if (modes == null
- || modes.length == 0
- || (modes.length == 1 && modes[0] == CameraCharacteristics.CONTROL_AF_MODE_OFF)) {
- useAutoFocus = false;
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
- } else {
- // Applying auto focus
- switch (mode) {
- case locked:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
- break;
- case auto:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_MODE,
- recordingVideo
- ? CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO
- : CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- default:
- break;
- }
- MeteringRectangle afRect = cameraRegions.getAFMeteringRectangle();
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AF_REGIONS,
- afRect == null ? null : new MeteringRectangle[] {afRect});
- }
- } else {
- captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
- }
- }
-
- private void updateExposure(ExposureMode mode) {
- exposureMode = mode;
-
- // Applying auto exposure
- MeteringRectangle aeRect = cameraRegions.getAEMeteringRectangle();
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_REGIONS,
- aeRect == null ? null : new MeteringRectangle[] {cameraRegions.getAEMeteringRectangle()});
-
- switch (mode) {
- case locked:
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
- break;
- case auto:
- default:
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
- break;
- }
-
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureOffset);
- }
-
- private void updateFlash(FlashMode mode) {
- // Get flash
- flashMode = mode;
-
- // Applying flash modes
- switch (flashMode) {
- case off:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
- break;
- case auto:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
- captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
- break;
- case always:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
- captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
- break;
- case torch:
- default:
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- captureRequestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
- break;
- }
+ cameraFeatures.getSensorOrientation().unlockCaptureOrientation();
}
public void startPreview() throws CameraAccessException {
if (pictureImageReader == null || pictureImageReader.getSurface() == null) return;
+ Log.i(TAG, "startPreview");
createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, pictureImageReader.getSurface());
}
@@ -1097,6 +972,7 @@
public void startPreviewWithImageStream(EventChannel imageStreamChannel)
throws CameraAccessException {
createCaptureSession(CameraDevice.TEMPLATE_RECORD, imageStreamReader.getSurface());
+ Log.i(TAG, "startPreviewWithImageStream");
imageStreamChannel.setStreamHandler(
new EventChannel.StreamHandler() {
@@ -1107,15 +983,43 @@
@Override
public void onCancel(Object o) {
- imageStreamReader.setOnImageAvailableListener(null, null);
+ imageStreamReader.setOnImageAvailableListener(null, backgroundHandler);
}
});
}
+ /**
+ * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
+ * still image is ready to be saved.
+ */
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Log.i(TAG, "onImageAvailable");
+
+ backgroundHandler.post(
+ new ImageSaver(
+ // Use acquireNextImage since image reader is only for one image.
+ reader.acquireNextImage(),
+ captureFile,
+ new ImageSaver.Callback() {
+ @Override
+ public void onComplete(String absolutePath) {
+ dartMessenger.finish(flutterResult, absolutePath);
+ }
+
+ @Override
+ public void onError(String errorCode, String errorMessage) {
+ dartMessenger.error(flutterResult, errorCode, errorMessage, null);
+ }
+ }));
+ cameraCaptureCallback.setCameraState(CameraState.STATE_PREVIEW);
+ }
+
private void setImageStreamImageAvailableListener(final EventChannel.EventSink imageStreamSink) {
imageStreamReader.setOnImageAvailableListener(
reader -> {
- Image img = reader.acquireLatestImage();
+ // Use acquireNextImage since image reader is only for one image.
+ Image img = reader.acquireNextImage();
if (img == null) return;
List<Map<String, Object>> planes = new ArrayList<>();
@@ -1139,41 +1043,24 @@
imageBuffer.put("format", img.getFormat());
imageBuffer.put("planes", planes);
- imageStreamSink.success(imageBuffer);
+ final Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(() -> imageStreamSink.success(imageBuffer));
img.close();
},
- null);
- }
-
- public void stopImageStream() throws CameraAccessException {
- if (imageStreamReader != null) {
- imageStreamReader.setOnImageAvailableListener(null, null);
- }
- startPreview();
- }
-
- /** Sets the time the pre-capture sequence started. */
- private void setPreCaptureStartTime() {
- preCaptureStartTime = SystemClock.elapsedRealtime();
- }
-
- /**
- * Check if the timeout for the pre-capture sequence has been reached.
- *
- * @return true if the timeout is reached; otherwise false is returned.
- */
- private boolean hitPreCaptureTimeout() {
- return (SystemClock.elapsedRealtime() - preCaptureStartTime) > PRECAPTURE_TIMEOUT_MS;
+ backgroundHandler);
}
private void closeCaptureSession() {
- if (cameraCaptureSession != null) {
- cameraCaptureSession.close();
- cameraCaptureSession = null;
+ if (captureSession != null) {
+ Log.i(TAG, "closeCaptureSession");
+
+ captureSession.close();
+ captureSession = null;
}
}
public void close() {
+ Log.i(TAG, "close");
closeCaptureSession();
if (cameraDevice != null) {
@@ -1193,11 +1080,15 @@
mediaRecorder.release();
mediaRecorder = null;
}
+
+ stopBackgroundThread();
}
public void dispose() {
+ Log.i(TAG, "dispose");
+
close();
flutterTexture.release();
- deviceOrientationListener.stop();
+ getDeviceOrientationManager().stop();
}
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java
index 75730ab..ef3a2b9 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraPlugin.java
@@ -8,9 +8,11 @@
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
+import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry;
import io.flutter.view.TextureRegistry;
@@ -51,7 +53,8 @@
registrar.activity(),
registrar.messenger(),
registrar::addRequestPermissionsResultListener,
- registrar.view());
+ registrar.view(),
+ null);
}
@Override
@@ -70,18 +73,17 @@
binding.getActivity(),
flutterPluginBinding.getBinaryMessenger(),
binding::addRequestPermissionsResultListener,
- flutterPluginBinding.getTextureRegistry());
+ flutterPluginBinding.getTextureRegistry(),
+ FlutterLifecycleAdapter.getActivityLifecycle(binding));
}
@Override
public void onDetachedFromActivity() {
- if (methodCallHandler == null) {
- // Could be on too low of an SDK to have started listening originally.
- return;
+ // Could be on too low of an SDK to have started listening originally.
+ if (methodCallHandler != null) {
+ methodCallHandler.stopListening();
+ methodCallHandler = null;
}
-
- methodCallHandler.stopListening();
- methodCallHandler = null;
}
@Override
@@ -98,7 +100,8 @@
Activity activity,
BinaryMessenger messenger,
PermissionsRegistry permissionsRegistry,
- TextureRegistry textureRegistry) {
+ TextureRegistry textureRegistry,
+ @Nullable Lifecycle lifecycle) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If the sdk is less than 21 (min sdk for Camera2) we don't register the plugin.
return;
@@ -106,6 +109,11 @@
methodCallHandler =
new MethodCallHandlerImpl(
- activity, messenger, new CameraPermissions(), permissionsRegistry, textureRegistry);
+ activity,
+ messenger,
+ new CameraPermissions(),
+ permissionsRegistry,
+ textureRegistry,
+ lifecycle);
}
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java
index ff8a49f..951a279 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java
@@ -11,6 +11,7 @@
import android.util.Size;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import java.util.Arrays;
/**
@@ -69,11 +70,32 @@
* boundaries.
*/
public static MeteringRectangle convertPointToMeteringRectangle(
- @NonNull Size boundaries, double x, double y) {
+ @NonNull Size boundaries,
+ double x,
+ double y,
+ @NonNull PlatformChannel.DeviceOrientation orientation) {
assert (boundaries.getWidth() > 0 && boundaries.getHeight() > 0);
assert (x >= 0 && x <= 1);
assert (y >= 0 && y <= 1);
-
+ // Rotate the coordinates to match the device orientation.
+ double oldX = x, oldY = y;
+ switch (orientation) {
+ case PORTRAIT_UP: // 90 ccw.
+ y = 1 - oldX;
+ x = oldY;
+ break;
+ case PORTRAIT_DOWN: // 90 cw.
+ x = 1 - oldY;
+ y = oldX;
+ break;
+ case LANDSCAPE_LEFT:
+ // No rotation required.
+ break;
+ case LANDSCAPE_RIGHT: // 180.
+ x = 1 - x;
+ y = 1 - y;
+ break;
+ }
// Interpolate the target coordinate.
int targetX = (int) Math.round(x * ((double) (boundaries.getWidth() - 1)));
int targetY = (int) Math.round(y * ((double) (boundaries.getHeight() - 1)));
@@ -98,7 +120,6 @@
if (targetY > maxTargetY) {
targetY = maxTargetY;
}
-
// Build the metering rectangle.
return MeteringRectangleFactory.create(targetX, targetY, targetWidth, targetHeight, 1);
}
@@ -130,7 +151,7 @@
* @param width width >= 0.
* @param height height >= 0.
* @param meteringWeight weight between {@value MeteringRectangle#METERING_WEIGHT_MIN} and
- * {@value MeteringRectangle#METERING_WEIGHT_MAX} inclusively
+ * {@value MeteringRectangle#METERING_WEIGHT_MAX} inclusively.
* @return new instance of the {@link MeteringRectangle} class.
* @throws IllegalArgumentException if any of the parameters were negative.
*/
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java
deleted file mode 100644
index 60c866c..0000000
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegions.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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.camera;
-
-import android.hardware.camera2.params.MeteringRectangle;
-import android.util.Size;
-
-public final class CameraRegions {
- private MeteringRectangle aeMeteringRectangle;
- private MeteringRectangle afMeteringRectangle;
- private Size maxBoundaries;
-
- public CameraRegions(Size maxBoundaries) {
- assert (maxBoundaries == null || maxBoundaries.getWidth() > 0);
- assert (maxBoundaries == null || maxBoundaries.getHeight() > 0);
- this.maxBoundaries = maxBoundaries;
- }
-
- public MeteringRectangle getAEMeteringRectangle() {
- return aeMeteringRectangle;
- }
-
- public MeteringRectangle getAFMeteringRectangle() {
- return afMeteringRectangle;
- }
-
- public Size getMaxBoundaries() {
- return this.maxBoundaries;
- }
-
- public void resetAutoExposureMeteringRectangle() {
- this.aeMeteringRectangle = null;
- }
-
- public void setAutoExposureMeteringRectangleFromPoint(double x, double y) {
- this.aeMeteringRectangle = getMeteringRectangleForPoint(maxBoundaries, x, y);
- }
-
- public void resetAutoFocusMeteringRectangle() {
- this.afMeteringRectangle = null;
- }
-
- public void setAutoFocusMeteringRectangleFromPoint(double x, double y) {
- this.afMeteringRectangle = getMeteringRectangleForPoint(maxBoundaries, x, y);
- }
-
- public MeteringRectangle getMeteringRectangleForPoint(Size maxBoundaries, double x, double y) {
- assert (x >= 0 && x <= 1);
- assert (y >= 0 && y <= 1);
- if (maxBoundaries == null)
- throw new IllegalStateException(
- "Functionality for managing metering rectangles is unavailable as this CameraRegions instance was initialized with null boundaries.");
-
- // Interpolate the target coordinate
- int targetX = (int) Math.round(x * ((double) (maxBoundaries.getWidth() - 1)));
- int targetY = (int) Math.round(y * ((double) (maxBoundaries.getHeight() - 1)));
- // Determine the dimensions of the metering triangle (10th of the viewport)
- int targetWidth = (int) Math.round(((double) maxBoundaries.getWidth()) / 10d);
- int targetHeight = (int) Math.round(((double) maxBoundaries.getHeight()) / 10d);
- // Adjust target coordinate to represent top-left corner of metering rectangle
- targetX -= targetWidth / 2;
- targetY -= targetHeight / 2;
- // Adjust target coordinate as to not fall out of bounds
- if (targetX < 0) targetX = 0;
- if (targetY < 0) targetY = 0;
- int maxTargetX = maxBoundaries.getWidth() - 1 - targetWidth;
- int maxTargetY = maxBoundaries.getHeight() - 1 - targetHeight;
- if (targetX > maxTargetX) targetX = maxTargetX;
- if (targetY > maxTargetY) targetY = maxTargetY;
-
- // Build the metering rectangle
- return new MeteringRectangle(targetX, targetY, targetWidth, targetHeight, 1);
- }
-}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java
index b4d4689..003d80a 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java
@@ -6,20 +6,12 @@
import android.app.Activity;
import android.content.Context;
-import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.params.StreamConfigurationMap;
-import android.media.CamcorderProfile;
-import android.util.Size;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
-import io.flutter.plugins.camera.types.ResolutionPreset;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,23 +21,24 @@
private CameraUtils() {}
- static PlatformChannel.DeviceOrientation getDeviceOrientationFromDegrees(int degrees) {
- // Round to the nearest 90 degrees.
- degrees = (int) (Math.round(degrees / 90.0) * 90) % 360;
- // Determine the corresponding device orientation.
- switch (degrees) {
- case 90:
- return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT;
- case 180:
- return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN;
- case 270:
- return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT;
- case 0:
- default:
- return PlatformChannel.DeviceOrientation.PORTRAIT_UP;
- }
+ /**
+ * Gets the {@link CameraManager} singleton.
+ *
+ * @param context The context to get the {@link CameraManager} singleton from.
+ * @return The {@link CameraManager} singleton.
+ */
+ static CameraManager getCameraManager(Context context) {
+ return (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
}
+ /**
+ * Serializes the {@link PlatformChannel.DeviceOrientation} to a string value.
+ *
+ * @param orientation The orientation to serialize.
+ * @return The serialized orientation.
+ * @throws UnsupportedOperationException when the provided orientation not have a corresponding
+ * string value.
+ */
static String serializeDeviceOrientation(PlatformChannel.DeviceOrientation orientation) {
if (orientation == null)
throw new UnsupportedOperationException("Could not serialize null device orientation.");
@@ -64,6 +57,15 @@
}
}
+ /**
+ * Deserializes a string value to its corresponding {@link PlatformChannel.DeviceOrientation}
+ * value.
+ *
+ * @param orientation The string value to deserialize.
+ * @return The deserialized orientation.
+ * @throws UnsupportedOperationException when the provided string value does not have a
+ * corresponding {@link PlatformChannel.DeviceOrientation}.
+ */
static PlatformChannel.DeviceOrientation deserializeDeviceOrientation(String orientation) {
if (orientation == null)
throw new UnsupportedOperationException("Could not deserialize null device orientation.");
@@ -82,23 +84,13 @@
}
}
- static Size computeBestPreviewSize(String cameraName, ResolutionPreset preset) {
- if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
- preset = ResolutionPreset.high;
- }
-
- CamcorderProfile profile =
- getBestAvailableCamcorderProfileForResolutionPreset(cameraName, preset);
- return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
- }
-
- static Size computeBestCaptureSize(StreamConfigurationMap streamConfigurationMap) {
- // For still image captures, we use the largest available size.
- return Collections.max(
- Arrays.asList(streamConfigurationMap.getOutputSizes(ImageFormat.JPEG)),
- new CompareSizesByArea());
- }
-
+ /**
+ * Gets all the available cameras for the device.
+ *
+ * @param activity The current Android activity.
+ * @return A map of all the available cameras, with their name as their key.
+ * @throws CameraAccessException when the camera could not be accessed.
+ */
public static List<Map<String, Object>> getAvailableCameras(Activity activity)
throws CameraAccessException {
CameraManager cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
@@ -127,52 +119,4 @@
}
return cameras;
}
-
- static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset(
- String cameraName, ResolutionPreset preset) {
- int cameraId = Integer.parseInt(cameraName);
- switch (preset) {
- // All of these cases deliberately fall through to get the best available profile.
- case max:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
- }
- case ultraHigh:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_2160P);
- }
- case veryHigh:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_1080P);
- }
- case high:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_720P);
- }
- case medium:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_480P);
- }
- case low:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_QVGA);
- }
- default:
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW)) {
- return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_LOW);
- } else {
- throw new IllegalArgumentException(
- "No capture session available for current capture session.");
- }
- }
- }
-
- private static class CompareSizesByArea implements Comparator<Size> {
- @Override
- public int compare(Size lhs, Size rhs) {
- // We cast here to ensure the multiplications won't overflow.
- return Long.signum(
- (long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
- }
- }
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java
index 93b963e..dc62fce 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java
@@ -11,8 +11,8 @@
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugins.camera.types.ExposureMode;
-import io.flutter.plugins.camera.types.FocusMode;
+import io.flutter.plugins.camera.features.autofocus.FocusMode;
+import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
import java.util.HashMap;
import java.util.Map;
@@ -178,4 +178,28 @@
}
});
}
+
+ /**
+ * Send a success payload to a {@link MethodChannel.Result} on the main thread.
+ *
+ * @param payload The payload to send.
+ */
+ public void finish(MethodChannel.Result result, Object payload) {
+ handler.post(() -> result.success(payload));
+ }
+
+ /**
+ * Send an error payload to a {@link MethodChannel.Result} on the main thread.
+ *
+ * @param errorCode error code.
+ * @param errorMessage error message.
+ * @param errorDetails error details.
+ */
+ public void error(
+ MethodChannel.Result result,
+ String errorCode,
+ @Nullable String errorMessage,
+ @Nullable Object errorDetails) {
+ handler.post(() -> result.error(errorCode, errorMessage, errorDetails));
+ }
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java
deleted file mode 100644
index 634596d..0000000
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DeviceOrientationManager.java
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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.camera;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.hardware.SensorManager;
-import android.provider.Settings;
-import android.view.Display;
-import android.view.OrientationEventListener;
-import android.view.Surface;
-import android.view.WindowManager;
-import io.flutter.embedding.engine.systemchannels.PlatformChannel;
-
-class DeviceOrientationManager {
-
- private static final IntentFilter orientationIntentFilter =
- new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
-
- private final Activity activity;
- private final DartMessenger messenger;
- private final boolean isFrontFacing;
- private final int sensorOrientation;
- private PlatformChannel.DeviceOrientation lastOrientation;
- private OrientationEventListener orientationEventListener;
- private BroadcastReceiver broadcastReceiver;
-
- public DeviceOrientationManager(
- Activity activity, DartMessenger messenger, boolean isFrontFacing, int sensorOrientation) {
- this.activity = activity;
- this.messenger = messenger;
- this.isFrontFacing = isFrontFacing;
- this.sensorOrientation = sensorOrientation;
- }
-
- public void start() {
- startSensorListener();
- startUIListener();
- }
-
- public void stop() {
- stopSensorListener();
- stopUIListener();
- }
-
- public int getMediaOrientation() {
- return this.getMediaOrientation(this.lastOrientation);
- }
-
- public int getMediaOrientation(PlatformChannel.DeviceOrientation orientation) {
- int angle = 0;
-
- // Fallback to device orientation when the orientation value is null
- if (orientation == null) {
- orientation = getUIOrientation();
- }
-
- switch (orientation) {
- case PORTRAIT_UP:
- angle = 0;
- break;
- case PORTRAIT_DOWN:
- angle = 180;
- break;
- case LANDSCAPE_LEFT:
- angle = 90;
- break;
- case LANDSCAPE_RIGHT:
- angle = 270;
- break;
- }
- if (isFrontFacing) angle *= -1;
- return (angle + sensorOrientation + 360) % 360;
- }
-
- private void startSensorListener() {
- if (orientationEventListener != null) return;
- orientationEventListener =
- new OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) {
- @Override
- public void onOrientationChanged(int angle) {
- if (!isSystemAutoRotationLocked()) {
- PlatformChannel.DeviceOrientation newOrientation = calculateSensorOrientation(angle);
- if (!newOrientation.equals(lastOrientation)) {
- lastOrientation = newOrientation;
- messenger.sendDeviceOrientationChangeEvent(newOrientation);
- }
- }
- }
- };
- if (orientationEventListener.canDetectOrientation()) {
- orientationEventListener.enable();
- }
- }
-
- private void startUIListener() {
- if (broadcastReceiver != null) return;
- broadcastReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (isSystemAutoRotationLocked()) {
- PlatformChannel.DeviceOrientation orientation = getUIOrientation();
- if (!orientation.equals(lastOrientation)) {
- lastOrientation = orientation;
- messenger.sendDeviceOrientationChangeEvent(orientation);
- }
- }
- }
- };
- activity.registerReceiver(broadcastReceiver, orientationIntentFilter);
- broadcastReceiver.onReceive(activity, null);
- }
-
- private void stopSensorListener() {
- if (orientationEventListener == null) return;
- orientationEventListener.disable();
- orientationEventListener = null;
- }
-
- private void stopUIListener() {
- if (broadcastReceiver == null) return;
- activity.unregisterReceiver(broadcastReceiver);
- broadcastReceiver = null;
- }
-
- private boolean isSystemAutoRotationLocked() {
- return android.provider.Settings.System.getInt(
- activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0)
- != 1;
- }
-
- private PlatformChannel.DeviceOrientation getUIOrientation() {
- final int rotation = getDisplay().getRotation();
- final int orientation = activity.getResources().getConfiguration().orientation;
-
- switch (orientation) {
- case Configuration.ORIENTATION_PORTRAIT:
- if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) {
- return PlatformChannel.DeviceOrientation.PORTRAIT_UP;
- } else {
- return PlatformChannel.DeviceOrientation.PORTRAIT_DOWN;
- }
- case Configuration.ORIENTATION_LANDSCAPE:
- if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) {
- return PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT;
- } else {
- return PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT;
- }
- default:
- return PlatformChannel.DeviceOrientation.PORTRAIT_UP;
- }
- }
-
- private PlatformChannel.DeviceOrientation calculateSensorOrientation(int angle) {
- final int tolerance = 45;
- angle += tolerance;
-
- // Orientation is 0 in the default orientation mode. This is portait-mode for phones
- // and landscape for tablets. We have to compensate for this by calculating the default
- // orientation, and apply an offset accordingly.
- int defaultDeviceOrientation = getDeviceDefaultOrientation();
- if (defaultDeviceOrientation == Configuration.ORIENTATION_LANDSCAPE) {
- angle += 90;
- }
- // Determine the orientation
- angle = angle % 360;
- return new PlatformChannel.DeviceOrientation[] {
- PlatformChannel.DeviceOrientation.PORTRAIT_UP,
- PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT,
- PlatformChannel.DeviceOrientation.PORTRAIT_DOWN,
- PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT,
- }
- [angle / 90];
- }
-
- private int getDeviceDefaultOrientation() {
- Configuration config = activity.getResources().getConfiguration();
- int rotation = getDisplay().getRotation();
- if (((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180)
- && config.orientation == Configuration.ORIENTATION_LANDSCAPE)
- || ((rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270)
- && config.orientation == Configuration.ORIENTATION_PORTRAIT)) {
- return Configuration.ORIENTATION_LANDSCAPE;
- } else {
- return Configuration.ORIENTATION_PORTRAIT;
- }
- }
-
- @SuppressWarnings("deprecation")
- private Display getDisplay() {
- return ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
- }
-}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
index 50bca63..893785f 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java
@@ -10,6 +10,8 @@
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
@@ -17,14 +19,17 @@
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugins.camera.CameraPermissions.PermissionsRegistry;
-import io.flutter.plugins.camera.types.ExposureMode;
-import io.flutter.plugins.camera.types.FlashMode;
-import io.flutter.plugins.camera.types.FocusMode;
+import io.flutter.plugins.camera.features.CameraFeatureFactoryImpl;
+import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.autofocus.FocusMode;
+import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
+import io.flutter.plugins.camera.features.flash.FlashMode;
+import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
import io.flutter.view.TextureRegistry;
import java.util.HashMap;
import java.util.Map;
-final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler {
+final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler, LifecycleObserver {
private final Activity activity;
private final BinaryMessenger messenger;
private final CameraPermissions cameraPermissions;
@@ -32,6 +37,7 @@
private final TextureRegistry textureRegistry;
private final MethodChannel methodChannel;
private final EventChannel imageStreamChannel;
+ private final Lifecycle lifecycle;
private @Nullable Camera camera;
MethodCallHandlerImpl(
@@ -39,12 +45,14 @@
BinaryMessenger messenger,
CameraPermissions cameraPermissions,
PermissionsRegistry permissionsAdder,
- TextureRegistry textureRegistry) {
+ TextureRegistry textureRegistry,
+ @Nullable Lifecycle lifecycle) {
this.activity = activity;
this.messenger = messenger;
this.cameraPermissions = cameraPermissions;
this.permissionsRegistry = permissionsAdder;
this.textureRegistry = textureRegistry;
+ this.lifecycle = lifecycle;
methodChannel = new MethodChannel(messenger, "plugins.flutter.io/camera");
imageStreamChannel = new EventChannel(messenger, "plugins.flutter.io/camera/imageStream");
@@ -172,7 +180,7 @@
y = call.argument("y");
}
try {
- camera.setExposurePoint(result, x, y);
+ camera.setExposurePoint(result, new Point(x, y));
} catch (Exception e) {
handleException(e, result);
}
@@ -239,7 +247,7 @@
y = call.argument("y");
}
try {
- camera.setFocusPoint(result, x, y);
+ camera.setFocusPoint(result, new Point(x, y));
} catch (Exception e) {
handleException(e, result);
}
@@ -351,22 +359,36 @@
private void instantiateCamera(MethodCall call, Result result) throws CameraAccessException {
String cameraName = call.argument("cameraName");
- String resolutionPreset = call.argument("resolutionPreset");
+ String preset = call.argument("resolutionPreset");
boolean enableAudio = call.argument("enableAudio");
+
TextureRegistry.SurfaceTextureEntry flutterSurfaceTexture =
textureRegistry.createSurfaceTexture();
DartMessenger dartMessenger =
new DartMessenger(
messenger, flutterSurfaceTexture.id(), new Handler(Looper.getMainLooper()));
+ CameraProperties cameraProperties =
+ new CameraPropertiesImpl(cameraName, CameraUtils.getCameraManager(activity));
+ ResolutionPreset resolutionPreset = ResolutionPreset.valueOf(preset);
+
+ if (camera != null && lifecycle != null) {
+ lifecycle.removeObserver(camera);
+ }
+
camera =
new Camera(
activity,
flutterSurfaceTexture,
+ new CameraFeatureFactoryImpl(),
dartMessenger,
- cameraName,
+ cameraProperties,
resolutionPreset,
enableAudio);
+ if (lifecycle != null) {
+ lifecycle.addObserver(camera);
+ }
+
Map<String, Object> reply = new HashMap<>();
reply.put("cameraId", flutterSurfaceTexture.id());
result.success(reply);
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java
deleted file mode 100644
index 4c11e2d..0000000
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/PictureCaptureRequest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.camera;
-
-import android.os.Handler;
-import android.os.Looper;
-import androidx.annotation.Nullable;
-import io.flutter.plugin.common.MethodChannel;
-
-class PictureCaptureRequest {
-
- enum State {
- idle,
- focusing,
- preCapture,
- waitingPreCaptureReady,
- capturing,
- finished,
- error,
- }
-
- private final Runnable timeoutCallback =
- new Runnable() {
- @Override
- public void run() {
- error("captureTimeout", "Picture capture request timed out", state.toString());
- }
- };
-
- private final MethodChannel.Result result;
- private final TimeoutHandler timeoutHandler;
- private State state;
-
- public PictureCaptureRequest(MethodChannel.Result result) {
- this(result, new TimeoutHandler());
- }
-
- public PictureCaptureRequest(MethodChannel.Result result, TimeoutHandler timeoutHandler) {
- this.result = result;
- this.state = State.idle;
- this.timeoutHandler = timeoutHandler;
- }
-
- public void setState(State state) {
- if (isFinished()) throw new IllegalStateException("Request has already been finished");
- this.state = state;
- if (state != State.idle && state != State.finished && state != State.error) {
- this.timeoutHandler.resetTimeout(timeoutCallback);
- } else {
- this.timeoutHandler.clearTimeout(timeoutCallback);
- }
- }
-
- public State getState() {
- return state;
- }
-
- public boolean isFinished() {
- return state == State.finished || state == State.error;
- }
-
- public void finish(String absolutePath) {
- if (isFinished()) throw new IllegalStateException("Request has already been finished");
- this.timeoutHandler.clearTimeout(timeoutCallback);
- result.success(absolutePath);
- state = State.finished;
- }
-
- public void error(
- String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
- if (isFinished()) throw new IllegalStateException("Request has already been finished");
- this.timeoutHandler.clearTimeout(timeoutCallback);
- result.error(errorCode, errorMessage, errorDetails);
- state = State.error;
- }
-
- static class TimeoutHandler {
- private static final int REQUEST_TIMEOUT = 5000;
- private final Handler handler;
-
- TimeoutHandler() {
- this.handler = new Handler(Looper.getMainLooper());
- }
-
- public void resetTimeout(Runnable runnable) {
- clearTimeout(runnable);
- handler.postDelayed(runnable, REQUEST_TIMEOUT);
- }
-
- public void clearTimeout(Runnable runnable) {
- handler.removeCallbacks(runnable);
- }
- }
-}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactory.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactory.java
index 8d10c44..b91f9a1 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactory.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactory.java
@@ -84,9 +84,13 @@
*
* @param cameraProperties instance of the CameraProperties class containing information about the
* cameras features.
+ * @param sensorOrientationFeature instance of the SensorOrientationFeature class containing
+ * information about the sensor and device orientation.
* @return newly created instance of the FocusPointFeature class.
*/
- FocusPointFeature createFocusPointFeature(@NonNull CameraProperties cameraProperties);
+ FocusPointFeature createFocusPointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature);
/**
* Creates a new instance of the FPS range feature.
@@ -126,9 +130,13 @@
*
* @param cameraProperties instance of the CameraProperties class containing information about the
* cameras features.
+ * @param sensorOrientationFeature instance of the SensorOrientationFeature class containing
+ * information about the sensor and device orientation.
* @return newly created instance of the ExposurePointFeature class.
*/
- ExposurePointFeature createExposurePointFeature(@NonNull CameraProperties cameraProperties);
+ ExposurePointFeature createExposurePointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature);
/**
* Creates a new instance of the noise reduction feature.
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactoryImpl.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactoryImpl.java
index b12ad36..95a8c06 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactoryImpl.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatureFactoryImpl.java
@@ -59,8 +59,10 @@
}
@Override
- public FocusPointFeature createFocusPointFeature(@NonNull CameraProperties cameraProperties) {
- return new FocusPointFeature(cameraProperties);
+ public FocusPointFeature createFocusPointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature) {
+ return new FocusPointFeature(cameraProperties, sensorOrientationFeature);
}
@Override
@@ -83,8 +85,9 @@
@Override
public ExposurePointFeature createExposurePointFeature(
- @NonNull CameraProperties cameraProperties) {
- return new ExposurePointFeature(cameraProperties);
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature) {
+ return new ExposurePointFeature(cameraProperties, sensorOrientationFeature);
}
@Override
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatures.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatures.java
index 0ee8969..659fd15 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatures.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeatures.java
@@ -4,6 +4,9 @@
package io.flutter.plugins.camera.features;
+import android.app.Activity;
+import io.flutter.plugins.camera.CameraProperties;
+import io.flutter.plugins.camera.DartMessenger;
import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
import io.flutter.plugins.camera.features.exposurelock.ExposureLockFeature;
import io.flutter.plugins.camera.features.exposureoffset.ExposureOffsetFeature;
@@ -13,6 +16,7 @@
import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
import io.flutter.plugins.camera.features.zoomlevel.ZoomLevelFeature;
import java.util.Collection;
@@ -37,6 +41,39 @@
private static final String SENSOR_ORIENTATION = "SENSOR_ORIENTATION";
private static final String ZOOM_LEVEL = "ZOOM_LEVEL";
+ public static CameraFeatures init(
+ CameraFeatureFactory cameraFeatureFactory,
+ CameraProperties cameraProperties,
+ Activity activity,
+ DartMessenger dartMessenger,
+ ResolutionPreset resolutionPreset) {
+ CameraFeatures cameraFeatures = new CameraFeatures();
+ cameraFeatures.setAutoFocus(
+ cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false));
+ cameraFeatures.setExposureLock(
+ cameraFeatureFactory.createExposureLockFeature(cameraProperties));
+ cameraFeatures.setExposureOffset(
+ cameraFeatureFactory.createExposureOffsetFeature(cameraProperties));
+ SensorOrientationFeature sensorOrientationFeature =
+ cameraFeatureFactory.createSensorOrientationFeature(
+ cameraProperties, activity, dartMessenger);
+ cameraFeatures.setSensorOrientation(sensorOrientationFeature);
+ cameraFeatures.setExposurePoint(
+ cameraFeatureFactory.createExposurePointFeature(
+ cameraProperties, sensorOrientationFeature));
+ cameraFeatures.setFlash(cameraFeatureFactory.createFlashFeature(cameraProperties));
+ cameraFeatures.setFocusPoint(
+ cameraFeatureFactory.createFocusPointFeature(cameraProperties, sensorOrientationFeature));
+ cameraFeatures.setFpsRange(cameraFeatureFactory.createFpsRangeFeature(cameraProperties));
+ cameraFeatures.setNoiseReduction(
+ cameraFeatureFactory.createNoiseReductionFeature(cameraProperties));
+ cameraFeatures.setResolution(
+ cameraFeatureFactory.createResolutionFeature(
+ cameraProperties, resolutionPreset, cameraProperties.getCameraName()));
+ cameraFeatures.setZoomLevel(cameraFeatureFactory.createZoomLevelFeature(cameraProperties));
+ return cameraFeatures;
+ }
+
private Map<String, CameraFeature> featureMap = new HashMap<>();
/**
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeature.java
index 8c2ee61..336e756 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeature.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeature.java
@@ -8,10 +8,12 @@
import android.hardware.camera2.params.MeteringRectangle;
import android.util.Size;
import androidx.annotation.NonNull;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.CameraRegionUtils;
import io.flutter.plugins.camera.features.CameraFeature;
import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
/** Exposure point controls where in the frame exposure metering will come from. */
public class ExposurePointFeature extends CameraFeature<Point> {
@@ -19,14 +21,17 @@
private Size cameraBoundaries;
private Point exposurePoint;
private MeteringRectangle exposureRectangle;
+ private final SensorOrientationFeature sensorOrientationFeature;
/**
* Creates a new instance of the {@link ExposurePointFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
*/
- public ExposurePointFeature(CameraProperties cameraProperties) {
+ public ExposurePointFeature(
+ CameraProperties cameraProperties, SensorOrientationFeature sensorOrientationFeature) {
super(cameraProperties);
+ this.sensorOrientationFeature = sensorOrientationFeature;
}
/**
@@ -80,9 +85,15 @@
if (this.exposurePoint == null) {
this.exposureRectangle = null;
} else {
+ PlatformChannel.DeviceOrientation orientation =
+ this.sensorOrientationFeature.getLockedCaptureOrientation();
+ if (orientation == null) {
+ orientation =
+ this.sensorOrientationFeature.getDeviceOrientationManager().getLastUIOrientation();
+ }
this.exposureRectangle =
CameraRegionUtils.convertPointToMeteringRectangle(
- this.cameraBoundaries, this.exposurePoint.x, this.exposurePoint.y);
+ this.cameraBoundaries, this.exposurePoint.x, this.exposurePoint.y, orientation);
}
}
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java
index 92fcfa9..a3a0172 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java
@@ -8,10 +8,12 @@
import android.hardware.camera2.params.MeteringRectangle;
import android.util.Size;
import androidx.annotation.NonNull;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.CameraRegionUtils;
import io.flutter.plugins.camera.features.CameraFeature;
import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
/** Focus point controls where in the frame focus will come from. */
public class FocusPointFeature extends CameraFeature<Point> {
@@ -19,14 +21,17 @@
private Size cameraBoundaries;
private Point focusPoint;
private MeteringRectangle focusRectangle;
+ private final SensorOrientationFeature sensorOrientationFeature;
/**
* Creates a new instance of the {@link FocusPointFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
*/
- public FocusPointFeature(CameraProperties cameraProperties) {
+ public FocusPointFeature(
+ CameraProperties cameraProperties, SensorOrientationFeature sensorOrientationFeature) {
super(cameraProperties);
+ this.sensorOrientationFeature = sensorOrientationFeature;
}
/**
@@ -80,9 +85,15 @@
if (this.focusPoint == null) {
this.focusRectangle = null;
} else {
+ PlatformChannel.DeviceOrientation orientation =
+ this.sensorOrientationFeature.getLockedCaptureOrientation();
+ if (orientation == null) {
+ orientation =
+ this.sensorOrientationFeature.getDeviceOrientationManager().getLastUIOrientation();
+ }
this.focusRectangle =
CameraRegionUtils.convertPointToMeteringRectangle(
- this.cameraBoundaries, this.focusPoint.x, this.focusPoint.y);
+ this.cameraBoundaries, this.focusPoint.x, this.focusPoint.y, orientation);
}
}
}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java
index 847a817..408575b 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java
@@ -20,9 +20,15 @@
public class NoiseReductionFeature extends CameraFeature<NoiseReductionMode> {
private NoiseReductionMode currentSetting = NoiseReductionMode.fast;
- private static final HashMap<NoiseReductionMode, Integer> NOISE_REDUCTION_MODES = new HashMap<>();
+ private final HashMap<NoiseReductionMode, Integer> NOISE_REDUCTION_MODES = new HashMap<>();
- static {
+ /**
+ * Creates a new instance of the {@link NoiseReductionFeature}.
+ *
+ * @param cameraProperties Collection of the characteristics for the current camera device.
+ */
+ public NoiseReductionFeature(CameraProperties cameraProperties) {
+ super(cameraProperties);
NOISE_REDUCTION_MODES.put(NoiseReductionMode.off, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
NOISE_REDUCTION_MODES.put(NoiseReductionMode.fast, CaptureRequest.NOISE_REDUCTION_MODE_FAST);
NOISE_REDUCTION_MODES.put(
@@ -35,15 +41,6 @@
}
}
- /**
- * Creates a new instance of the {@link NoiseReductionFeature}.
- *
- * @param cameraProperties Collection of the characteristics for the current camera device.
- */
- public NoiseReductionFeature(CameraProperties cameraProperties) {
- super(cameraProperties);
- }
-
@Override
public String getDebugName() {
return "NoiseReductionFeature";
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManager.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManager.java
index 2a04caa..dd1e489 100644
--- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManager.java
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManager.java
@@ -10,10 +10,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
-import android.hardware.SensorManager;
-import android.provider.Settings;
import android.view.Display;
-import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.WindowManager;
import androidx.annotation.NonNull;
@@ -35,7 +32,6 @@
private final boolean isFrontFacing;
private final int sensorOrientation;
private PlatformChannel.DeviceOrientation lastOrientation;
- private OrientationEventListener orientationEventListener;
private BroadcastReceiver broadcastReceiver;
/** Factory method to create a device orientation manager. */
@@ -63,7 +59,7 @@
*
* <p>When orientation information is updated the new orientation is send to the client using the
* {@link DartMessenger}. This latest value can also be retrieved through the {@link
- * #getMediaOrientation()} accessor.
+ * #getVideoOrientation()} accessor.
*
* <p>If the device's ACCELEROMETER_ROTATION setting is enabled the {@link
* DeviceOrientationManager} will report orientation updates based on the sensor information. If
@@ -71,55 +67,106 @@
* the deliver orientation updates based on the UI orientation.
*/
public void start() {
- startSensorListener();
- startUIListener();
+ if (broadcastReceiver != null) {
+ return;
+ }
+ broadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleUIOrientationChange();
+ }
+ };
+ activity.registerReceiver(broadcastReceiver, orientationIntentFilter);
+ broadcastReceiver.onReceive(activity, null);
}
/** Stops listening for orientation updates. */
public void stop() {
- stopSensorListener();
- stopUIListener();
+ if (broadcastReceiver == null) {
+ return;
+ }
+ activity.unregisterReceiver(broadcastReceiver);
+ broadcastReceiver = null;
}
/**
- * Returns the last captured orientation in degrees based on sensor or UI information.
+ * Returns the device's photo orientation in degrees based on the sensor orientation and the last
+ * known UI orientation.
*
- * <p>The orientation is returned in degrees and could be one of the following values:
+ * <p>Returns one of 0, 90, 180 or 270.
*
- * <ul>
- * <li>0: Indicates the device is currently in portrait.
- * <li>90: Indicates the device is currently in landscape left.
- * <li>180: Indicates the device is currently in portrait down.
- * <li>270: Indicates the device is currently in landscape right.
- * </ul>
- *
- * @return The last captured orientation in degrees
+ * @return The device's photo orientation in degrees.
*/
- public int getMediaOrientation() {
- return this.getMediaOrientation(this.lastOrientation);
+ public int getPhotoOrientation() {
+ return this.getPhotoOrientation(this.lastOrientation);
}
/**
- * Returns the device's orientation in degrees based on the supplied {@link
- * PlatformChannel.DeviceOrientation} value.
+ * Returns the device's photo orientation in degrees based on the sensor orientation and the
+ * supplied {@link PlatformChannel.DeviceOrientation} value.
*
- * <p>
- *
- * <ul>
- * <li>PORTRAIT_UP: converts to 0 degrees.
- * <li>LANDSCAPE_LEFT: converts to 90 degrees.
- * <li>PORTRAIT_DOWN: converts to 180 degrees.
- * <li>LANDSCAPE_RIGHT: converts to 270 degrees.
- * </ul>
+ * <p>Returns one of 0, 90, 180 or 270.
*
* @param orientation The {@link PlatformChannel.DeviceOrientation} value that is to be converted
* into degrees.
- * @return The device's orientation in degrees.
+ * @return The device's photo orientation in degrees.
*/
- public int getMediaOrientation(PlatformChannel.DeviceOrientation orientation) {
+ public int getPhotoOrientation(PlatformChannel.DeviceOrientation orientation) {
+ int angle = 0;
+ // Fallback to device orientation when the orientation value is null.
+ if (orientation == null) {
+ orientation = getUIOrientation();
+ }
+
+ switch (orientation) {
+ case PORTRAIT_UP:
+ angle = 90;
+ break;
+ case PORTRAIT_DOWN:
+ angle = 270;
+ break;
+ case LANDSCAPE_LEFT:
+ angle = isFrontFacing ? 180 : 0;
+ break;
+ case LANDSCAPE_RIGHT:
+ angle = isFrontFacing ? 0 : 180;
+ break;
+ }
+
+ // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X).
+ // This has to be taken into account so the JPEG is rotated properly.
+ // For devices with orientation of 90, this simply returns the mapping from ORIENTATIONS.
+ // For devices with orientation of 270, the JPEG is rotated 180 degrees instead.
+ return (angle + sensorOrientation + 270) % 360;
+ }
+
+ /**
+ * Returns the device's video orientation in degrees based on the sensor orientation and the last
+ * known UI orientation.
+ *
+ * <p>Returns one of 0, 90, 180 or 270.
+ *
+ * @return The device's video orientation in degrees.
+ */
+ public int getVideoOrientation() {
+ return this.getVideoOrientation(this.lastOrientation);
+ }
+
+ /**
+ * Returns the device's video orientation in degrees based on the sensor orientation and the
+ * supplied {@link PlatformChannel.DeviceOrientation} value.
+ *
+ * <p>Returns one of 0, 90, 180 or 270.
+ *
+ * @param orientation The {@link PlatformChannel.DeviceOrientation} value that is to be converted
+ * into degrees.
+ * @return The device's video orientation in degrees.
+ */
+ public int getVideoOrientation(PlatformChannel.DeviceOrientation orientation) {
int angle = 0;
- // Fallback to device orientation when the orientation value is null
+ // Fallback to device orientation when the orientation value is null.
if (orientation == null) {
orientation = getUIOrientation();
}
@@ -146,51 +193,9 @@
return (angle + sensorOrientation + 360) % 360;
}
- private void startSensorListener() {
- if (orientationEventListener != null) {
- return;
- }
- orientationEventListener =
- new OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) {
- @Override
- public void onOrientationChanged(int angle) {
- handleSensorOrientationChange(angle);
- }
- };
- if (orientationEventListener.canDetectOrientation()) {
- orientationEventListener.enable();
- }
- }
-
- private void startUIListener() {
- if (broadcastReceiver != null) {
- return;
- }
- broadcastReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleUIOrientationChange();
- }
- };
- activity.registerReceiver(broadcastReceiver, orientationIntentFilter);
- broadcastReceiver.onReceive(activity, null);
- }
-
- /**
- * Handles orientation changes based on information from the device's sensors.
- *
- * <p>This method is visible for testing purposes only and should never be used outside this
- * class.
- *
- * @param angle of the current orientation.
- */
- @VisibleForTesting
- void handleSensorOrientationChange(int angle) {
- if (!isAccelerometerRotationLocked()) {
- PlatformChannel.DeviceOrientation orientation = calculateSensorOrientation(angle);
- lastOrientation = handleOrientationChange(orientation, lastOrientation, messenger);
- }
+ /** @return the last received UI orientation. */
+ public PlatformChannel.DeviceOrientation getLastUIOrientation() {
+ return this.lastOrientation;
}
/**
@@ -201,10 +206,9 @@
*/
@VisibleForTesting
void handleUIOrientationChange() {
- if (isAccelerometerRotationLocked()) {
- PlatformChannel.DeviceOrientation orientation = getUIOrientation();
- lastOrientation = handleOrientationChange(orientation, lastOrientation, messenger);
- }
+ PlatformChannel.DeviceOrientation orientation = getUIOrientation();
+ handleOrientationChange(orientation, lastOrientation, messenger);
+ lastOrientation = orientation;
}
/**
@@ -215,37 +219,13 @@
* class.
*/
@VisibleForTesting
- static DeviceOrientation handleOrientationChange(
+ static void handleOrientationChange(
DeviceOrientation newOrientation,
DeviceOrientation previousOrientation,
DartMessenger messenger) {
if (!newOrientation.equals(previousOrientation)) {
messenger.sendDeviceOrientationChangeEvent(newOrientation);
}
-
- return newOrientation;
- }
-
- private void stopSensorListener() {
- if (orientationEventListener == null) {
- return;
- }
- orientationEventListener.disable();
- orientationEventListener = null;
- }
-
- private void stopUIListener() {
- if (broadcastReceiver == null) {
- return;
- }
- activity.unregisterReceiver(broadcastReceiver);
- broadcastReceiver = null;
- }
-
- private boolean isAccelerometerRotationLocked() {
- return android.provider.Settings.System.getInt(
- activity.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0)
- != 1;
}
/**
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java
index 2c03817..40db12e 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java
@@ -41,7 +41,7 @@
}
@Test
- public void ctor_Should_return_valid_instance() throws CameraAccessException {
+ public void ctor_shouldReturnValidInstance() throws CameraAccessException {
verify(mockCameraManager, times(1)).getCameraCharacteristics(CAMERA_NAME);
assertNotNull(cameraProperties);
}
@@ -76,8 +76,7 @@
}
@Test
- public void
- getControlAutoExposureCompensationStep_Should_return_double_When_rational_is_not_null() {
+ public void getControlAutoExposureCompensationStep_shouldReturnDoubleWhenRationalIsNotNull() {
double expectedStep = 3.1415926535;
Rational mockRational = mock(Rational.class);
@@ -92,7 +91,7 @@
}
@Test
- public void getControlAutoExposureCompensationStep_Should_return_zero_When_rational_is_null() {
+ public void getControlAutoExposureCompensationStep_shouldReturnZeroWhenRationalIsNull() {
double expectedStep = 0.0;
when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP))
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_convertPointToMeteringRectangleTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_convertPointToMeteringRectangleTest.java
new file mode 100644
index 0000000..2c6d9d9
--- /dev/null
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_convertPointToMeteringRectangleTest.java
@@ -0,0 +1,197 @@
+// 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.camera;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+import android.hardware.camera2.params.MeteringRectangle;
+import android.util.Size;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockedStatic;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class CameraRegionUtils_convertPointToMeteringRectangleTest {
+ private MockedStatic<CameraRegionUtils.MeteringRectangleFactory> mockedMeteringRectangleFactory;
+ private Size mockCameraBoundaries;
+
+ @Before
+ public void setUp() {
+ this.mockCameraBoundaries = mock(Size.class);
+ when(this.mockCameraBoundaries.getWidth()).thenReturn(100);
+ when(this.mockCameraBoundaries.getHeight()).thenReturn(100);
+ mockedMeteringRectangleFactory = mockStatic(CameraRegionUtils.MeteringRectangleFactory.class);
+
+ mockedMeteringRectangleFactory
+ .when(
+ () ->
+ CameraRegionUtils.MeteringRectangleFactory.create(
+ anyInt(), anyInt(), anyInt(), anyInt(), anyInt()))
+ .thenAnswer(
+ new Answer<MeteringRectangle>() {
+ @Override
+ public MeteringRectangle answer(InvocationOnMock createInvocation) throws Throwable {
+ MeteringRectangle mockMeteringRectangle = mock(MeteringRectangle.class);
+ when(mockMeteringRectangle.getX()).thenReturn(createInvocation.getArgument(0));
+ when(mockMeteringRectangle.getY()).thenReturn(createInvocation.getArgument(1));
+ when(mockMeteringRectangle.getWidth()).thenReturn(createInvocation.getArgument(2));
+ when(mockMeteringRectangle.getHeight()).thenReturn(createInvocation.getArgument(3));
+ when(mockMeteringRectangle.getMeteringWeight())
+ .thenReturn(createInvocation.getArgument(4));
+ when(mockMeteringRectangle.equals(any()))
+ .thenAnswer(
+ new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock equalsInvocation)
+ throws Throwable {
+ MeteringRectangle otherMockMeteringRectangle =
+ equalsInvocation.getArgument(0);
+ return mockMeteringRectangle.getX() == otherMockMeteringRectangle.getX()
+ && mockMeteringRectangle.getY() == otherMockMeteringRectangle.getY()
+ && mockMeteringRectangle.getWidth()
+ == otherMockMeteringRectangle.getWidth()
+ && mockMeteringRectangle.getHeight()
+ == otherMockMeteringRectangle.getHeight()
+ && mockMeteringRectangle.getMeteringWeight()
+ == otherMockMeteringRectangle.getMeteringWeight();
+ }
+ });
+ return mockMeteringRectangle;
+ }
+ });
+ }
+
+ @After
+ public void tearDown() {
+ mockedMeteringRectangleFactory.close();
+ }
+
+ @Test
+ public void convertPointToMeteringRectangle_shouldReturnValidMeteringRectangleForCenterCoord() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0.5, 0.5, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(45, 45, 10, 10, 1).equals(r));
+ }
+
+ @Test
+ public void convertPointToMeteringRectangle_shouldReturnValidMeteringRectangleForTopLeftCoord() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0, 0, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 0, 10, 10, 1).equals(r));
+ }
+
+ @Test
+ public void convertPointToMeteringRectangle_ShouldReturnValidMeteringRectangleForTopRightCoord() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 0, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 0, 10, 10, 1).equals(r));
+ }
+
+ @Test
+ public void
+ convertPointToMeteringRectangle_shouldReturnValidMeteringRectangleForBottomLeftCoord() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0, 1, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 89, 10, 10, 1).equals(r));
+ }
+
+ @Test
+ public void
+ convertPointToMeteringRectangle_shouldReturnValidMeteringRectangleForBottomRightCoord() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 1, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 89, 10, 10, 1).equals(r));
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowForXUpperBound() {
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1.5, 0, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowForXLowerBound() {
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, -0.5, 0, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowForYUpperBound() {
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0, 1.5, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowForYLowerBound() {
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0, -0.5, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test()
+ public void
+ convertPointToMeteringRectangle_shouldRotateMeteringRectangleAccordingToUiOrientationForPortraitUp() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 1, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 0, 10, 10, 1).equals(r));
+ }
+
+ @Test()
+ public void
+ convertPointToMeteringRectangle_shouldRotateMeteringRectangleAccordingToUiOrientationForPortraitDown() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 1, PlatformChannel.DeviceOrientation.PORTRAIT_DOWN);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 89, 10, 10, 1).equals(r));
+ }
+
+ @Test()
+ public void
+ convertPointToMeteringRectangle_shouldRotateMeteringRectangleAccordingToUiOrientationForLandscapeLeft() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 1, PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 89, 10, 10, 1).equals(r));
+ }
+
+ @Test()
+ public void
+ convertPointToMeteringRectangle_shouldRotateMeteringRectangleAccordingToUiOrientationForLandscapeRight() {
+ MeteringRectangle r =
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 1, 1, PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT);
+ assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 0, 10, 10, 1).equals(r));
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowFor0WidthBoundary() {
+ Size mockCameraBoundaries = mock(Size.class);
+ when(mockCameraBoundaries.getWidth()).thenReturn(0);
+ when(mockCameraBoundaries.getHeight()).thenReturn(50);
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ mockCameraBoundaries, 0, -0.5, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void convertPointToMeteringRectangle_shouldThrowFor0HeightBoundary() {
+ Size mockCameraBoundaries = mock(Size.class);
+ when(mockCameraBoundaries.getWidth()).thenReturn(50);
+ when(mockCameraBoundaries.getHeight()).thenReturn(0);
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ this.mockCameraBoundaries, 0, -0.5, PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_getCameraBoundariesTest.java
similarity index 61%
rename from packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java
rename to packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_getCameraBoundariesTest.java
index 2d65c4e..4c01649 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtils_getCameraBoundariesTest.java
@@ -4,8 +4,6 @@
package io.flutter.plugins.camera;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
@@ -15,17 +13,15 @@
import android.graphics.Rect;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.params.MeteringRectangle;
import android.os.Build;
import android.util.Size;
import io.flutter.plugins.camera.utils.TestUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-public class CameraRegionUtilsTest {
+public class CameraRegionUtils_getCameraBoundariesTest {
Size mockCameraBoundaries;
@@ -37,8 +33,7 @@
}
@Test
- public void
- getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_running_pre_android_p() {
+ public void getCameraBoundaries_shouldReturnSensorInfoPixelArraySizeWhenRunningPreAndroidP() {
updateSdkVersion(Build.VERSION_CODES.O_MR1);
try {
@@ -58,7 +53,7 @@
@Test
public void
- getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_distortion_correction_is_null() {
+ getCameraBoundaries_shouldReturnSensorInfoPixelArraySizeWhenDistortionCorrectionIsNull() {
updateSdkVersion(Build.VERSION_CODES.P);
try {
@@ -80,7 +75,7 @@
@Test
public void
- getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_distortion_correction_is_off() {
+ getCameraBoundaries_shouldReturnSensorInfoPixelArraySizeWhenDistortionCorrectionIsOff() {
updateSdkVersion(Build.VERSION_CODES.P);
try {
@@ -103,7 +98,7 @@
@Test
public void
- getCameraBoundaries_should_return_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_to_null() {
+ getCameraBoundaries_shouldReturnInfoPreCorrectionActiveArraySizeWhenDistortionCorrectionModeIsSetToNull() {
updateSdkVersion(Build.VERSION_CODES.P);
try {
@@ -150,7 +145,7 @@
@Test
public void
- getCameraBoundaries_should_return_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_to_off() {
+ getCameraBoundaries_shouldReturnInfoPreCorrectionActiveArraySizeWhenDistortionCorrectionModeIsSetToOff() {
updateSdkVersion(Build.VERSION_CODES.P);
try {
@@ -199,7 +194,7 @@
@Test
public void
- getCameraBoundaries_should_return_sensor_info_active_array_size_when_distortion_correction_mode_is_set() {
+ getCameraBoundaries_shouldReturnSensorInfoActiveArraySizeWhenDistortionCorrectionModeIsSet() {
updateSdkVersion(Build.VERSION_CODES.P);
try {
@@ -246,107 +241,6 @@
}
}
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_x_upper_bound() {
- CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 1.5, 0);
- }
-
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_x_lower_bound() {
- CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, -0.5, 0);
- }
-
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_y_upper_bound() {
- CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 0, 1.5);
- }
-
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_y_lower_bound() {
- CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 0, -0.5);
- }
-
- @Test
- public void getMeteringRectangleForPoint_should_return_valid_MeteringRectangle() {
- try (MockedStatic<CameraRegionUtils.MeteringRectangleFactory> mockedMeteringRectangleFactory =
- mockStatic(CameraRegionUtils.MeteringRectangleFactory.class)) {
-
- mockedMeteringRectangleFactory
- .when(
- () ->
- CameraRegionUtils.MeteringRectangleFactory.create(
- anyInt(), anyInt(), anyInt(), anyInt(), anyInt()))
- .thenAnswer(
- new Answer<MeteringRectangle>() {
- @Override
- public MeteringRectangle answer(InvocationOnMock createInvocation)
- throws Throwable {
- MeteringRectangle mockMeteringRectangle = mock(MeteringRectangle.class);
- when(mockMeteringRectangle.getX()).thenReturn(createInvocation.getArgument(0));
- when(mockMeteringRectangle.getY()).thenReturn(createInvocation.getArgument(1));
- when(mockMeteringRectangle.getWidth())
- .thenReturn(createInvocation.getArgument(2));
- when(mockMeteringRectangle.getHeight())
- .thenReturn(createInvocation.getArgument(3));
- when(mockMeteringRectangle.getMeteringWeight())
- .thenReturn(createInvocation.getArgument(4));
- when(mockMeteringRectangle.equals(any()))
- .thenAnswer(
- new Answer<Boolean>() {
- @Override
- public Boolean answer(InvocationOnMock equalsInvocation)
- throws Throwable {
- MeteringRectangle otherMockMeteringRectangle =
- equalsInvocation.getArgument(0);
- return mockMeteringRectangle.getX()
- == otherMockMeteringRectangle.getX()
- && mockMeteringRectangle.getY()
- == otherMockMeteringRectangle.getY()
- && mockMeteringRectangle.getWidth()
- == otherMockMeteringRectangle.getWidth()
- && mockMeteringRectangle.getHeight()
- == otherMockMeteringRectangle.getHeight()
- && mockMeteringRectangle.getMeteringWeight()
- == otherMockMeteringRectangle.getMeteringWeight();
- }
- });
- return mockMeteringRectangle;
- }
- });
-
- MeteringRectangle r;
- // Center
- r = CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 0.5, 0.5);
- assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(45, 45, 10, 10, 1).equals(r));
-
- // Top left
- r = CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 0.0, 0.0);
- assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 0, 10, 10, 1).equals(r));
-
- // Bottom right
- r = CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 1.0, 1.0);
- assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 89, 10, 10, 1).equals(r));
-
- // Top left
- r = CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 0.0, 1.0);
- assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(0, 89, 10, 10, 1).equals(r));
-
- // Top right
- r = CameraRegionUtils.convertPointToMeteringRectangle(this.mockCameraBoundaries, 1.0, 0.0);
- assertTrue(CameraRegionUtils.MeteringRectangleFactory.create(89, 0, 10, 10, 1).equals(r));
- }
- }
-
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_0_width_boundary() {
- new io.flutter.plugins.camera.CameraRegions(new Size(0, 50));
- }
-
- @Test(expected = AssertionError.class)
- public void getMeteringRectangleForPoint_should_throw_for_0_height_boundary() {
- new io.flutter.plugins.camera.CameraRegions(new Size(100, 0));
- }
-
private static void updateSdkVersion(int version) {
TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", version);
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
new file mode 100644
index 0000000..cab2ae8
--- /dev/null
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraTest.java
@@ -0,0 +1,843 @@
+// 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.camera;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.media.CamcorderProfile;
+import android.media.MediaRecorder;
+import android.os.Build;
+import androidx.annotation.NonNull;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugins.camera.features.CameraFeatureFactory;
+import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.autofocus.AutoFocusFeature;
+import io.flutter.plugins.camera.features.autofocus.FocusMode;
+import io.flutter.plugins.camera.features.exposurelock.ExposureLockFeature;
+import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
+import io.flutter.plugins.camera.features.exposureoffset.ExposureOffsetFeature;
+import io.flutter.plugins.camera.features.exposurepoint.ExposurePointFeature;
+import io.flutter.plugins.camera.features.flash.FlashFeature;
+import io.flutter.plugins.camera.features.flash.FlashMode;
+import io.flutter.plugins.camera.features.focuspoint.FocusPointFeature;
+import io.flutter.plugins.camera.features.fpsrange.FpsRangeFeature;
+import io.flutter.plugins.camera.features.noisereduction.NoiseReductionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionFeature;
+import io.flutter.plugins.camera.features.resolution.ResolutionPreset;
+import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
+import io.flutter.plugins.camera.features.zoomlevel.ZoomLevelFeature;
+import io.flutter.plugins.camera.utils.TestUtils;
+import io.flutter.view.TextureRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CameraTest {
+ private CameraProperties mockCameraProperties;
+ private CameraFeatureFactory mockCameraFeatureFactory;
+ private DartMessenger mockDartMessenger;
+ private Camera camera;
+ private CameraCaptureSession mockCaptureSession;
+ private CaptureRequest.Builder mockPreviewRequestBuilder;
+
+ @Before
+ public void before() {
+ mockCameraProperties = mock(CameraProperties.class);
+ mockCameraFeatureFactory = new TestCameraFeatureFactory();
+ mockDartMessenger = mock(DartMessenger.class);
+ mockCaptureSession = mock(CameraCaptureSession.class);
+ mockPreviewRequestBuilder = mock(CaptureRequest.Builder.class);
+
+ final Activity mockActivity = mock(Activity.class);
+ final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
+ mock(TextureRegistry.SurfaceTextureEntry.class);
+ final String cameraName = "1";
+ final ResolutionPreset resolutionPreset = ResolutionPreset.high;
+ final boolean enableAudio = false;
+
+ when(mockCameraProperties.getCameraName()).thenReturn(cameraName);
+
+ camera =
+ new Camera(
+ mockActivity,
+ mockFlutterTexture,
+ mockCameraFeatureFactory,
+ mockDartMessenger,
+ mockCameraProperties,
+ resolutionPreset,
+ enableAudio);
+
+ TestUtils.setPrivateField(camera, "captureSession", mockCaptureSession);
+ TestUtils.setPrivateField(camera, "previewRequestBuilder", mockPreviewRequestBuilder);
+ }
+
+ @After
+ public void after() {
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 0);
+ }
+
+ @Test
+ public void shouldCreateCameraPluginAndSetAllFeatures() {
+ final Activity mockActivity = mock(Activity.class);
+ final TextureRegistry.SurfaceTextureEntry mockFlutterTexture =
+ mock(TextureRegistry.SurfaceTextureEntry.class);
+ final CameraFeatureFactory mockCameraFeatureFactory = mock(CameraFeatureFactory.class);
+ final String cameraName = "1";
+ final ResolutionPreset resolutionPreset = ResolutionPreset.high;
+ final boolean enableAudio = false;
+
+ when(mockCameraProperties.getCameraName()).thenReturn(cameraName);
+ SensorOrientationFeature mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ when(mockCameraFeatureFactory.createSensorOrientationFeature(any(), any(), any()))
+ .thenReturn(mockSensorOrientationFeature);
+
+ Camera camera =
+ new Camera(
+ mockActivity,
+ mockFlutterTexture,
+ mockCameraFeatureFactory,
+ mockDartMessenger,
+ mockCameraProperties,
+ resolutionPreset,
+ enableAudio);
+
+ verify(mockCameraFeatureFactory, times(1))
+ .createSensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
+ verify(mockCameraFeatureFactory, times(1)).createAutoFocusFeature(mockCameraProperties, false);
+ verify(mockCameraFeatureFactory, times(1)).createExposureLockFeature(mockCameraProperties);
+ verify(mockCameraFeatureFactory, times(1))
+ .createExposurePointFeature(eq(mockCameraProperties), eq(mockSensorOrientationFeature));
+ verify(mockCameraFeatureFactory, times(1)).createExposureOffsetFeature(mockCameraProperties);
+ verify(mockCameraFeatureFactory, times(1)).createFlashFeature(mockCameraProperties);
+ verify(mockCameraFeatureFactory, times(1))
+ .createFocusPointFeature(eq(mockCameraProperties), eq(mockSensorOrientationFeature));
+ verify(mockCameraFeatureFactory, times(1)).createFpsRangeFeature(mockCameraProperties);
+ verify(mockCameraFeatureFactory, times(1)).createNoiseReductionFeature(mockCameraProperties);
+ verify(mockCameraFeatureFactory, times(1))
+ .createResolutionFeature(mockCameraProperties, resolutionPreset, cameraName);
+ verify(mockCameraFeatureFactory, times(1)).createZoomLevelFeature(mockCameraProperties);
+ assertNotNull("should create a camera", camera);
+ }
+
+ @Test
+ public void getDeviceOrientationManager() {
+ SensorOrientationFeature mockSensorOrientationFeature =
+ mockCameraFeatureFactory.createSensorOrientationFeature(mockCameraProperties, null, null);
+ DeviceOrientationManager mockDeviceOrientationManager = mock(DeviceOrientationManager.class);
+
+ when(mockSensorOrientationFeature.getDeviceOrientationManager())
+ .thenReturn(mockDeviceOrientationManager);
+
+ DeviceOrientationManager actualDeviceOrientationManager = camera.getDeviceOrientationManager();
+
+ verify(mockSensorOrientationFeature, times(1)).getDeviceOrientationManager();
+ assertEquals(mockDeviceOrientationManager, actualDeviceOrientationManager);
+ }
+
+ @Test
+ public void getExposureOffsetStepSize() {
+ ExposureOffsetFeature mockExposureOffsetFeature =
+ mockCameraFeatureFactory.createExposureOffsetFeature(mockCameraProperties);
+ double stepSize = 2.3;
+
+ when(mockExposureOffsetFeature.getExposureOffsetStepSize()).thenReturn(stepSize);
+
+ double actualSize = camera.getExposureOffsetStepSize();
+
+ verify(mockExposureOffsetFeature, times(1)).getExposureOffsetStepSize();
+ assertEquals(stepSize, actualSize, 0);
+ }
+
+ @Test
+ public void getMaxExposureOffset() {
+ ExposureOffsetFeature mockExposureOffsetFeature =
+ mockCameraFeatureFactory.createExposureOffsetFeature(mockCameraProperties);
+ double expectedMaxOffset = 42.0;
+
+ when(mockExposureOffsetFeature.getMaxExposureOffset()).thenReturn(expectedMaxOffset);
+
+ double actualMaxOffset = camera.getMaxExposureOffset();
+
+ verify(mockExposureOffsetFeature, times(1)).getMaxExposureOffset();
+ assertEquals(expectedMaxOffset, actualMaxOffset, 0);
+ }
+
+ @Test
+ public void getMinExposureOffset() {
+ ExposureOffsetFeature mockExposureOffsetFeature =
+ mockCameraFeatureFactory.createExposureOffsetFeature(mockCameraProperties);
+ double expectedMinOffset = 21.5;
+
+ when(mockExposureOffsetFeature.getMinExposureOffset()).thenReturn(21.5);
+
+ double actualMinOffset = camera.getMinExposureOffset();
+
+ verify(mockExposureOffsetFeature, times(1)).getMinExposureOffset();
+ assertEquals(expectedMinOffset, actualMinOffset, 0);
+ }
+
+ @Test
+ public void getMaxZoomLevel() {
+ ZoomLevelFeature mockZoomLevelFeature =
+ mockCameraFeatureFactory.createZoomLevelFeature(mockCameraProperties);
+ float expectedMaxZoomLevel = 4.2f;
+
+ when(mockZoomLevelFeature.getMaximumZoomLevel()).thenReturn(expectedMaxZoomLevel);
+
+ float actualMaxZoomLevel = camera.getMaxZoomLevel();
+
+ verify(mockZoomLevelFeature, times(1)).getMaximumZoomLevel();
+ assertEquals(expectedMaxZoomLevel, actualMaxZoomLevel, 0);
+ }
+
+ @Test
+ public void getMinZoomLevel() {
+ ZoomLevelFeature mockZoomLevelFeature =
+ mockCameraFeatureFactory.createZoomLevelFeature(mockCameraProperties);
+ float expectedMinZoomLevel = 4.2f;
+
+ when(mockZoomLevelFeature.getMinimumZoomLevel()).thenReturn(expectedMinZoomLevel);
+
+ float actualMinZoomLevel = camera.getMinZoomLevel();
+
+ verify(mockZoomLevelFeature, times(1)).getMinimumZoomLevel();
+ assertEquals(expectedMinZoomLevel, actualMinZoomLevel, 0);
+ }
+
+ @Test
+ public void getRecordingProfile() {
+ ResolutionFeature mockResolutionFeature =
+ mockCameraFeatureFactory.createResolutionFeature(mockCameraProperties, null, null);
+ CamcorderProfile mockCamcorderProfile = mock(CamcorderProfile.class);
+
+ when(mockResolutionFeature.getRecordingProfile()).thenReturn(mockCamcorderProfile);
+
+ CamcorderProfile actualRecordingProfile = camera.getRecordingProfile();
+
+ verify(mockResolutionFeature, times(1)).getRecordingProfile();
+ assertEquals(mockCamcorderProfile, actualRecordingProfile);
+ }
+
+ @Test
+ public void setExposureMode_shouldUpdateExposureLockFeature() {
+ ExposureLockFeature mockExposureLockFeature =
+ mockCameraFeatureFactory.createExposureLockFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ ExposureMode exposureMode = ExposureMode.locked;
+
+ camera.setExposureMode(mockResult, exposureMode);
+
+ verify(mockExposureLockFeature, times(1)).setValue(exposureMode);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setExposureMode_shouldUpdateBuilder() {
+ ExposureLockFeature mockExposureLockFeature =
+ mockCameraFeatureFactory.createExposureLockFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ ExposureMode exposureMode = ExposureMode.locked;
+
+ camera.setExposureMode(mockResult, exposureMode);
+
+ verify(mockExposureLockFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setExposureMode_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ ExposureMode exposureMode = ExposureMode.locked;
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setExposureMode(mockResult, exposureMode);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1))
+ .error("setExposureModeFailed", "Could not set exposure mode.", null);
+ }
+
+ @Test
+ public void setExposurePoint_shouldUpdateExposurePointFeature() {
+ SensorOrientationFeature mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ ExposurePointFeature mockExposurePointFeature =
+ mockCameraFeatureFactory.createExposurePointFeature(
+ mockCameraProperties, mockSensorOrientationFeature);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+
+ camera.setExposurePoint(mockResult, point);
+
+ verify(mockExposurePointFeature, times(1)).setValue(point);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setExposurePoint_shouldUpdateBuilder() {
+ SensorOrientationFeature mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ ExposurePointFeature mockExposurePointFeature =
+ mockCameraFeatureFactory.createExposurePointFeature(
+ mockCameraProperties, mockSensorOrientationFeature);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+
+ camera.setExposurePoint(mockResult, point);
+
+ verify(mockExposurePointFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setExposurePoint_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setExposurePoint(mockResult, point);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1))
+ .error("setExposurePointFailed", "Could not set exposure point.", null);
+ }
+
+ @Test
+ public void setFlashMode_shouldUpdateFlashFeature() {
+ FlashFeature mockFlashFeature =
+ mockCameraFeatureFactory.createFlashFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ FlashMode flashMode = FlashMode.always;
+
+ camera.setFlashMode(mockResult, flashMode);
+
+ verify(mockFlashFeature, times(1)).setValue(flashMode);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setFlashMode_shouldUpdateBuilder() {
+ FlashFeature mockFlashFeature =
+ mockCameraFeatureFactory.createFlashFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ FlashMode flashMode = FlashMode.always;
+
+ camera.setFlashMode(mockResult, flashMode);
+
+ verify(mockFlashFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setFlashMode_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ FlashMode flashMode = FlashMode.always;
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setFlashMode(mockResult, flashMode);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1)).error("setFlashModeFailed", "Could not set flash mode.", null);
+ }
+
+ @Test
+ public void setFocusPoint_shouldUpdateFocusPointFeature() {
+ SensorOrientationFeature mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ FocusPointFeature mockFocusPointFeature =
+ mockCameraFeatureFactory.createFocusPointFeature(
+ mockCameraProperties, mockSensorOrientationFeature);
+ AutoFocusFeature mockAutoFocusFeature =
+ mockCameraFeatureFactory.createAutoFocusFeature(mockCameraProperties, false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+ when(mockAutoFocusFeature.getValue()).thenReturn(FocusMode.auto);
+
+ camera.setFocusPoint(mockResult, point);
+
+ verify(mockFocusPointFeature, times(1)).setValue(point);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setFocusPoint_shouldUpdateBuilder() {
+ SensorOrientationFeature mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ FocusPointFeature mockFocusPointFeature =
+ mockCameraFeatureFactory.createFocusPointFeature(
+ mockCameraProperties, mockSensorOrientationFeature);
+ AutoFocusFeature mockAutoFocusFeature =
+ mockCameraFeatureFactory.createAutoFocusFeature(mockCameraProperties, false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+ when(mockAutoFocusFeature.getValue()).thenReturn(FocusMode.auto);
+
+ camera.setFocusPoint(mockResult, point);
+
+ verify(mockFocusPointFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setFocusPoint_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ AutoFocusFeature mockAutoFocusFeature =
+ mockCameraFeatureFactory.createAutoFocusFeature(mockCameraProperties, false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ Point point = new Point(42d, 42d);
+ when(mockAutoFocusFeature.getValue()).thenReturn(FocusMode.auto);
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setFocusPoint(mockResult, point);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1)).error("setFocusPointFailed", "Could not set focus point.", null);
+ }
+
+ @Test
+ public void setZoomLevel_shouldUpdateZoomLevelFeature() throws CameraAccessException {
+ ZoomLevelFeature mockZoomLevelFeature =
+ mockCameraFeatureFactory.createZoomLevelFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ float zoomLevel = 1.0f;
+
+ when(mockZoomLevelFeature.getValue()).thenReturn(zoomLevel);
+ when(mockZoomLevelFeature.getMinimumZoomLevel()).thenReturn(0f);
+ when(mockZoomLevelFeature.getMaximumZoomLevel()).thenReturn(2f);
+
+ camera.setZoomLevel(mockResult, zoomLevel);
+
+ verify(mockZoomLevelFeature, times(1)).setValue(zoomLevel);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setZoomLevel_shouldUpdateBuilder() throws CameraAccessException {
+ ZoomLevelFeature mockZoomLevelFeature =
+ mockCameraFeatureFactory.createZoomLevelFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ float zoomLevel = 1.0f;
+
+ when(mockZoomLevelFeature.getValue()).thenReturn(zoomLevel);
+ when(mockZoomLevelFeature.getMinimumZoomLevel()).thenReturn(0f);
+ when(mockZoomLevelFeature.getMaximumZoomLevel()).thenReturn(2f);
+
+ camera.setZoomLevel(mockResult, zoomLevel);
+
+ verify(mockZoomLevelFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setZoomLevel_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ ZoomLevelFeature mockZoomLevelFeature =
+ mockCameraFeatureFactory.createZoomLevelFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ float zoomLevel = 1.0f;
+
+ when(mockZoomLevelFeature.getValue()).thenReturn(zoomLevel);
+ when(mockZoomLevelFeature.getMinimumZoomLevel()).thenReturn(0f);
+ when(mockZoomLevelFeature.getMaximumZoomLevel()).thenReturn(2f);
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setZoomLevel(mockResult, zoomLevel);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1)).error("setZoomLevelFailed", "Could not set zoom level.", null);
+ }
+
+ @Test
+ public void pauseVideoRecording_shouldSendNullResultWhenNotRecording() {
+ TestUtils.setPrivateField(camera, "recordingVideo", false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.pauseVideoRecording(mockResult);
+
+ verify(mockResult, times(1)).success(null);
+ verify(mockResult, never()).error(any(), any(), any());
+ }
+
+ @Test
+ public void pauseVideoRecording_shouldCallPauseWhenRecordingAndOnAPIN() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ TestUtils.setPrivateField(camera, "mediaRecorder", mockMediaRecorder);
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 24);
+
+ camera.pauseVideoRecording(mockResult);
+
+ verify(mockMediaRecorder, times(1)).pause();
+ verify(mockResult, times(1)).success(null);
+ verify(mockResult, never()).error(any(), any(), any());
+ }
+
+ @Test
+ public void pauseVideoRecording_shouldSendVideoRecordingFailedErrorWhenVersionCodeSmallerThenN() {
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 23);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.pauseVideoRecording(mockResult);
+
+ verify(mockResult, times(1))
+ .error("videoRecordingFailed", "pauseVideoRecording requires Android API +24.", null);
+ verify(mockResult, never()).success(any());
+ }
+
+ @Test
+ public void
+ pauseVideoRecording_shouldSendVideoRecordingFailedErrorWhenMediaRecorderPauseThrowsIllegalStateException() {
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ TestUtils.setPrivateField(camera, "mediaRecorder", mockMediaRecorder);
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 24);
+
+ IllegalStateException expectedException = new IllegalStateException("Test error message");
+
+ doThrow(expectedException).when(mockMediaRecorder).pause();
+
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.pauseVideoRecording(mockResult);
+
+ verify(mockResult, times(1)).error("videoRecordingFailed", "Test error message", null);
+ verify(mockResult, never()).success(any());
+ }
+
+ @Test
+ public void resumeVideoRecording_shouldSendNullResultWhenNotRecording() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ TestUtils.setPrivateField(camera, "recordingVideo", false);
+
+ camera.resumeVideoRecording(mockResult);
+
+ verify(mockResult, times(1)).success(null);
+ verify(mockResult, never()).error(any(), any(), any());
+ }
+
+ @Test
+ public void resumeVideoRecording_shouldCallPauseWhenRecordingAndOnAPIN() {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ TestUtils.setPrivateField(camera, "mediaRecorder", mockMediaRecorder);
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 24);
+
+ camera.resumeVideoRecording(mockResult);
+
+ verify(mockMediaRecorder, times(1)).resume();
+ verify(mockResult, times(1)).success(null);
+ verify(mockResult, never()).error(any(), any(), any());
+ }
+
+ @Test
+ public void
+ resumeVideoRecording_shouldSendVideoRecordingFailedErrorWhenVersionCodeSmallerThanN() {
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 23);
+
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.resumeVideoRecording(mockResult);
+
+ verify(mockResult, times(1))
+ .error("videoRecordingFailed", "resumeVideoRecording requires Android API +24.", null);
+ verify(mockResult, never()).success(any());
+ }
+
+ @Test
+ public void
+ resumeVideoRecording_shouldSendVideoRecordingFailedErrorWhenMediaRecorderPauseThrowsIllegalStateException() {
+ MediaRecorder mockMediaRecorder = mock(MediaRecorder.class);
+ TestUtils.setPrivateField(camera, "mediaRecorder", mockMediaRecorder);
+ TestUtils.setPrivateField(camera, "recordingVideo", true);
+ TestUtils.setFinalStatic(Build.VERSION.class, "SDK_INT", 24);
+
+ IllegalStateException expectedException = new IllegalStateException("Test error message");
+
+ doThrow(expectedException).when(mockMediaRecorder).resume();
+
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.resumeVideoRecording(mockResult);
+
+ verify(mockResult, times(1)).error("videoRecordingFailed", "Test error message", null);
+ verify(mockResult, never()).success(any());
+ }
+
+ @Test
+ public void setFocusMode_shouldUpdateAutoFocusFeature() {
+ AutoFocusFeature mockAutoFocusFeature =
+ mockCameraFeatureFactory.createAutoFocusFeature(mockCameraProperties, false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.setFocusMode(mockResult, FocusMode.auto);
+
+ verify(mockAutoFocusFeature, times(1)).setValue(FocusMode.auto);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setFocusMode_shouldUpdateBuilder() {
+ AutoFocusFeature mockAutoFocusFeature =
+ mockCameraFeatureFactory.createAutoFocusFeature(mockCameraProperties, false);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.setFocusMode(mockResult, FocusMode.auto);
+
+ verify(mockAutoFocusFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setFocusMode_shouldUnlockAutoFocusForAutoMode() {
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.auto);
+ verify(mockPreviewRequestBuilder, times(1))
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
+ verify(mockPreviewRequestBuilder, times(1))
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
+ }
+
+ @Test
+ public void setFocusMode_shouldSkipUnlockAutoFocusWhenNullCaptureSession() {
+ TestUtils.setPrivateField(camera, "captureSession", null);
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.auto);
+ verify(mockPreviewRequestBuilder, never())
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
+ verify(mockPreviewRequestBuilder, never())
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
+ }
+
+ @Test
+ public void setFocusMode_shouldSendErrorEventOnUnlockAutoFocusCameraAccessException()
+ throws CameraAccessException {
+ when(mockCaptureSession.capture(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.auto);
+ verify(mockDartMessenger, times(1)).sendCameraErrorEvent(any());
+ }
+
+ @Test
+ public void setFocusMode_shouldLockAutoFocusForLockedMode() throws CameraAccessException {
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.locked);
+ verify(mockPreviewRequestBuilder, times(1))
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
+ verify(mockCaptureSession, times(1)).capture(any(), any(), any());
+ verify(mockCaptureSession, times(1)).setRepeatingRequest(any(), any(), any());
+ }
+
+ @Test
+ public void setFocusMode_shouldSkipLockAutoFocusWhenNullCaptureSession() {
+ TestUtils.setPrivateField(camera, "captureSession", null);
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.locked);
+ verify(mockPreviewRequestBuilder, never())
+ .set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
+ }
+
+ @Test
+ public void setFocusMode_shouldSendErrorEventOnLockAutoFocusCameraAccessException()
+ throws CameraAccessException {
+ when(mockCaptureSession.capture(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+ camera.setFocusMode(mock(MethodChannel.Result.class), FocusMode.locked);
+ verify(mockDartMessenger, times(1)).sendCameraErrorEvent(any());
+ }
+
+ @Test
+ public void setFocusMode_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setFocusMode(mockResult, FocusMode.locked);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1))
+ .error("setFocusModeFailed", "Error setting focus mode: null", null);
+ }
+
+ @Test
+ public void setExposureOffset_shouldUpdateExposureOffsetFeature() {
+ ExposureOffsetFeature mockExposureOffsetFeature =
+ mockCameraFeatureFactory.createExposureOffsetFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.setExposureOffset(mockResult, 1.0);
+
+ verify(mockExposureOffsetFeature, times(1)).setValue(1.0);
+ verify(mockResult, never()).error(any(), any(), any());
+ verify(mockResult, times(1)).success(null);
+ }
+
+ @Test
+ public void setExposureOffset_shouldAndUpdateBuilder() {
+ ExposureOffsetFeature mockExposureOffsetFeature =
+ mockCameraFeatureFactory.createExposureOffsetFeature(mockCameraProperties);
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+
+ camera.setExposureOffset(mockResult, 1.0);
+
+ verify(mockExposureOffsetFeature, times(1)).updateBuilder(any());
+ }
+
+ @Test
+ public void setExposureOffset_shouldCallErrorOnResultOnCameraAccessException()
+ throws CameraAccessException {
+ MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
+ when(mockCaptureSession.setRepeatingRequest(any(), any(), any()))
+ .thenThrow(new CameraAccessException(0, ""));
+
+ camera.setExposureOffset(mockResult, 1.0);
+
+ verify(mockResult, never()).success(any());
+ verify(mockResult, times(1))
+ .error("setExposureOffsetFailed", "Could not set exposure offset.", null);
+ }
+
+ @Test
+ public void lockCaptureOrientation_shouldLockCaptureOrientation() {
+ final Activity mockActivity = mock(Activity.class);
+ SensorOrientationFeature mockSensorOrientationFeature =
+ mockCameraFeatureFactory.createSensorOrientationFeature(
+ mockCameraProperties, mockActivity, mockDartMessenger);
+
+ camera.lockCaptureOrientation(PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+
+ verify(mockSensorOrientationFeature, times(1))
+ .lockCaptureOrientation(PlatformChannel.DeviceOrientation.PORTRAIT_UP);
+ }
+
+ @Test
+ public void unlockCaptureOrientation_shouldUnlockCaptureOrientation() {
+ final Activity mockActivity = mock(Activity.class);
+ SensorOrientationFeature mockSensorOrientationFeature =
+ mockCameraFeatureFactory.createSensorOrientationFeature(
+ mockCameraProperties, mockActivity, mockDartMessenger);
+
+ camera.unlockCaptureOrientation();
+
+ verify(mockSensorOrientationFeature, times(1)).unlockCaptureOrientation();
+ }
+
+ private static class TestCameraFeatureFactory implements CameraFeatureFactory {
+ private final AutoFocusFeature mockAutoFocusFeature;
+ private final ExposureLockFeature mockExposureLockFeature;
+ private final ExposureOffsetFeature mockExposureOffsetFeature;
+ private final ExposurePointFeature mockExposurePointFeature;
+ private final FlashFeature mockFlashFeature;
+ private final FocusPointFeature mockFocusPointFeature;
+ private final FpsRangeFeature mockFpsRangeFeature;
+ private final NoiseReductionFeature mockNoiseReductionFeature;
+ private final ResolutionFeature mockResolutionFeature;
+ private final SensorOrientationFeature mockSensorOrientationFeature;
+ private final ZoomLevelFeature mockZoomLevelFeature;
+
+ public TestCameraFeatureFactory() {
+ this.mockAutoFocusFeature = mock(AutoFocusFeature.class);
+ this.mockExposureLockFeature = mock(ExposureLockFeature.class);
+ this.mockExposureOffsetFeature = mock(ExposureOffsetFeature.class);
+ this.mockExposurePointFeature = mock(ExposurePointFeature.class);
+ this.mockFlashFeature = mock(FlashFeature.class);
+ this.mockFocusPointFeature = mock(FocusPointFeature.class);
+ this.mockFpsRangeFeature = mock(FpsRangeFeature.class);
+ this.mockNoiseReductionFeature = mock(NoiseReductionFeature.class);
+ this.mockResolutionFeature = mock(ResolutionFeature.class);
+ this.mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ this.mockZoomLevelFeature = mock(ZoomLevelFeature.class);
+ }
+
+ @Override
+ public AutoFocusFeature createAutoFocusFeature(
+ @NonNull CameraProperties cameraProperties, boolean recordingVideo) {
+ return mockAutoFocusFeature;
+ }
+
+ @Override
+ public ExposureLockFeature createExposureLockFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockExposureLockFeature;
+ }
+
+ @Override
+ public ExposureOffsetFeature createExposureOffsetFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockExposureOffsetFeature;
+ }
+
+ @Override
+ public FlashFeature createFlashFeature(@NonNull CameraProperties cameraProperties) {
+ return mockFlashFeature;
+ }
+
+ @Override
+ public ResolutionFeature createResolutionFeature(
+ @NonNull CameraProperties cameraProperties,
+ ResolutionPreset initialSetting,
+ String cameraName) {
+ return mockResolutionFeature;
+ }
+
+ @Override
+ public FocusPointFeature createFocusPointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrienttionFeature) {
+ return mockFocusPointFeature;
+ }
+
+ @Override
+ public FpsRangeFeature createFpsRangeFeature(@NonNull CameraProperties cameraProperties) {
+ return mockFpsRangeFeature;
+ }
+
+ @Override
+ public SensorOrientationFeature createSensorOrientationFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull Activity activity,
+ @NonNull DartMessenger dartMessenger) {
+ return mockSensorOrientationFeature;
+ }
+
+ @Override
+ public ZoomLevelFeature createZoomLevelFeature(@NonNull CameraProperties cameraProperties) {
+ return mockZoomLevelFeature;
+ }
+
+ @Override
+ public ExposurePointFeature createExposurePointFeature(
+ @NonNull CameraProperties cameraProperties,
+ @NonNull SensorOrientationFeature sensorOrientationFeature) {
+ return mockExposurePointFeature;
+ }
+
+ @Override
+ public NoiseReductionFeature createNoiseReductionFeature(
+ @NonNull CameraProperties cameraProperties) {
+ return mockNoiseReductionFeature;
+ }
+ }
+}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java
index b97192b..6b714ce 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraUtilsTest.java
@@ -12,7 +12,7 @@
public class CameraUtilsTest {
@Test
- public void serializeDeviceOrientation_serializes_correctly() {
+ public void serializeDeviceOrientation_serializesCorrectly() {
assertEquals(
"portraitUp",
CameraUtils.serializeDeviceOrientation(PlatformChannel.DeviceOrientation.PORTRAIT_UP));
@@ -33,7 +33,7 @@
}
@Test
- public void deserializeDeviceOrientation_deserializes_correctly() {
+ public void deserializeDeviceOrientation_deserializesCorrectly() {
assertEquals(
PlatformChannel.DeviceOrientation.PORTRAIT_UP,
CameraUtils.deserializeDeviceOrientation("portraitUp"));
@@ -49,54 +49,7 @@
}
@Test(expected = UnsupportedOperationException.class)
- public void deserializeDeviceOrientation_throws_for_null() {
+ public void deserializeDeviceOrientation_throwsForNull() {
CameraUtils.deserializeDeviceOrientation(null);
}
-
- @Test
- public void getDeviceOrientationFromDegrees_converts_correctly() {
- // Portrait UP
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_UP,
- CameraUtils.getDeviceOrientationFromDegrees(0));
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_UP,
- CameraUtils.getDeviceOrientationFromDegrees(315));
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_UP,
- CameraUtils.getDeviceOrientationFromDegrees(44));
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_UP,
- CameraUtils.getDeviceOrientationFromDegrees(-45));
- // Portrait DOWN
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_DOWN,
- CameraUtils.getDeviceOrientationFromDegrees(180));
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_DOWN,
- CameraUtils.getDeviceOrientationFromDegrees(135));
- assertEquals(
- PlatformChannel.DeviceOrientation.PORTRAIT_DOWN,
- CameraUtils.getDeviceOrientationFromDegrees(224));
- // Landscape LEFT
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT,
- CameraUtils.getDeviceOrientationFromDegrees(90));
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT,
- CameraUtils.getDeviceOrientationFromDegrees(45));
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT,
- CameraUtils.getDeviceOrientationFromDegrees(134));
- // Landscape RIGHT
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT,
- CameraUtils.getDeviceOrientationFromDegrees(270));
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT,
- CameraUtils.getDeviceOrientationFromDegrees(225));
- assertEquals(
- PlatformChannel.DeviceOrientation.LANDSCAPE_RIGHT,
- CameraUtils.getDeviceOrientationFromDegrees(314));
- }
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java
index 1385c2e..d3e4955 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraZoomTest.java
@@ -19,7 +19,7 @@
public class CameraZoomTest {
@Test
- public void ctor_when_parameters_are_valid() {
+ public void ctor_whenParametersAreValid() {
final Rect sensorSize = new Rect(0, 0, 0, 0);
final Float maxZoom = 4.0f;
final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom);
@@ -31,7 +31,7 @@
}
@Test
- public void ctor_when_sensor_size_is_null() {
+ public void ctor_whenSensorSizeIsNull() {
final Rect sensorSize = null;
final Float maxZoom = 4.0f;
final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom);
@@ -42,7 +42,7 @@
}
@Test
- public void ctor_when_max_zoom_is_null() {
+ public void ctor_whenMaxZoomIsNull() {
final Rect sensorSize = new Rect(0, 0, 0, 0);
final Float maxZoom = null;
final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom);
@@ -53,7 +53,7 @@
}
@Test
- public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() {
+ public void ctor_whenMaxZoomIsSmallerThenDefaultZoomFactor() {
final Rect sensorSize = new Rect(0, 0, 0, 0);
final Float maxZoom = 0.5f;
final CameraZoom cameraZoom = new CameraZoom(sensorSize, maxZoom);
@@ -64,7 +64,7 @@
}
@Test
- public void setZoom_when_no_support_should_not_set_scaler_crop_region() {
+ public void setZoom_whenNoSupportShouldNotSetScalerCropRegion() {
final CameraZoom cameraZoom = new CameraZoom(null, null);
final Rect computedZoom = cameraZoom.computeZoom(2f);
@@ -72,7 +72,7 @@
}
@Test
- public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() {
+ public void setZoom_whenSensorSizeEqualsZeroShouldReturnCropRegionOfZero() {
final Rect sensorSize = new Rect(0, 0, 0, 0);
final CameraZoom cameraZoom = new CameraZoom(sensorSize, 20f);
final Rect computedZoom = cameraZoom.computeZoom(18f);
@@ -85,7 +85,7 @@
}
@Test
- public void setZoom_when_sensor_size_is_valid_should_return_crop_region() {
+ public void setZoom_whenSensorSizeIsValidShouldReturnCropRegion() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final CameraZoom cameraZoom = new CameraZoom(sensorSize, 20f);
final Rect computedZoom = cameraZoom.computeZoom(18f);
@@ -98,7 +98,7 @@
}
@Test
- public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() {
+ public void setZoom_whenZoomIsGreaterThenMaxZoomClampToMaxZoom() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final CameraZoom cameraZoom = new CameraZoom(sensorSize, 10f);
final Rect computedZoom = cameraZoom.computeZoom(25f);
@@ -111,7 +111,7 @@
}
@Test
- public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() {
+ public void setZoom_whenZoomIsSmallerThenMinZoomClampToMinZoom() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final CameraZoom cameraZoom = new CameraZoom(sensorSize, 10f);
final Rect computedZoom = cameraZoom.computeZoom(0.5f);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java
index 25f5df9..0a2fc43 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/DartMessengerTest.java
@@ -16,8 +16,8 @@
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.StandardMethodCodec;
-import io.flutter.plugins.camera.types.ExposureMode;
-import io.flutter.plugins.camera.types.FocusMode;
+import io.flutter.plugins.camera.features.autofocus.FocusMode;
+import io.flutter.plugins.camera.features.exposurelock.ExposureMode;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/ImageSaverTests.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/ImageSaverTests.java
index d2c9f44..0358ce6 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/ImageSaverTests.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/ImageSaverTests.java
@@ -80,7 +80,7 @@
}
@Test
- public void run_writes_bytes_to_file_and_finishes_with_path() throws IOException {
+ public void runWritesBytesToFileAndFinishesWithPath() throws IOException {
imageSaver.run();
verify(mockFileOutputStream, times(1)).write(new byte[] {0x42, 0x00, 0x13});
@@ -89,7 +89,7 @@
}
@Test
- public void run_calls_error_on_write_ioexception() throws IOException {
+ public void runCallsErrorOnWriteIoexception() throws IOException {
doThrow(new IOException()).when(mockFileOutputStream).write(any());
imageSaver.run();
verify(mockCallback, times(1)).onError("IOError", "Failed saving image");
@@ -97,7 +97,7 @@
}
@Test
- public void run_calls_error_on_close_ioexception() throws IOException {
+ public void runCallsErrorOnCloseIoexception() throws IOException {
doThrow(new IOException("message")).when(mockFileOutputStream).close();
imageSaver.run();
verify(mockCallback, times(1)).onError("cameraAccess", "message");
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java
deleted file mode 100644
index f257a7f..0000000
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/PictureCaptureRequestTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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.camera;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import io.flutter.plugin.common.MethodChannel;
-import org.junit.Test;
-
-public class PictureCaptureRequestTest {
-
- @Test
- public void state_is_idle_by_default() {
- PictureCaptureRequest req = new PictureCaptureRequest(null);
- assertEquals("Default state is idle", req.getState(), PictureCaptureRequest.State.idle);
- }
-
- @Test
- public void setState_sets_state() {
- PictureCaptureRequest req = new PictureCaptureRequest(null);
- req.setState(PictureCaptureRequest.State.focusing);
- assertEquals("State is focusing", req.getState(), PictureCaptureRequest.State.focusing);
- req.setState(PictureCaptureRequest.State.preCapture);
- assertEquals("State is preCapture", req.getState(), PictureCaptureRequest.State.preCapture);
- req.setState(PictureCaptureRequest.State.waitingPreCaptureReady);
- assertEquals(
- "State is waitingPreCaptureReady",
- req.getState(),
- PictureCaptureRequest.State.waitingPreCaptureReady);
- req.setState(PictureCaptureRequest.State.capturing);
- assertEquals(
- "State is awaitingPreCapture", req.getState(), PictureCaptureRequest.State.capturing);
- }
-
- @Test
- public void setState_resets_timeout() {
- PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
- mock(PictureCaptureRequest.TimeoutHandler.class);
- PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler);
- req.setState(PictureCaptureRequest.State.focusing);
- req.setState(PictureCaptureRequest.State.preCapture);
- req.setState(PictureCaptureRequest.State.waitingPreCaptureReady);
- req.setState(PictureCaptureRequest.State.capturing);
- verify(mockTimeoutHandler, times(4)).resetTimeout(any());
- verify(mockTimeoutHandler, never()).clearTimeout(any());
- }
-
- @Test
- public void setState_clears_timeout() {
- PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
- mock(PictureCaptureRequest.TimeoutHandler.class);
- PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler);
- req.setState(PictureCaptureRequest.State.idle);
- req.setState(PictureCaptureRequest.State.finished);
- req = new PictureCaptureRequest(null, mockTimeoutHandler);
- req.setState(PictureCaptureRequest.State.error);
- verify(mockTimeoutHandler, never()).resetTimeout(any());
- verify(mockTimeoutHandler, times(3)).clearTimeout(any());
- }
-
- @Test
- public void finish_sets_result_and_state() {
- // Setup
- MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
- PictureCaptureRequest req = new PictureCaptureRequest(mockResult);
- // Act
- req.finish("/test/path");
- // Test
- verify(mockResult).success("/test/path");
- assertEquals("State is finished", req.getState(), PictureCaptureRequest.State.finished);
- }
-
- @Test
- public void finish_clears_timeout() {
- PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
- mock(PictureCaptureRequest.TimeoutHandler.class);
- MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
- PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler);
- req.finish("/test/path");
- verify(mockTimeoutHandler, never()).resetTimeout(any());
- verify(mockTimeoutHandler).clearTimeout(any());
- }
-
- @Test
- public void isFinished_is_true_When_state_is_finished_or_error() {
- // Setup
- PictureCaptureRequest req = new PictureCaptureRequest(null);
- // Test false states
- req.setState(PictureCaptureRequest.State.idle);
- assertFalse(req.isFinished());
- req.setState(PictureCaptureRequest.State.preCapture);
- assertFalse(req.isFinished());
- req.setState(PictureCaptureRequest.State.capturing);
- assertFalse(req.isFinished());
- // Test true states
- req.setState(PictureCaptureRequest.State.finished);
- assertTrue(req.isFinished());
- req = new PictureCaptureRequest(null); // Refresh
- req.setState(PictureCaptureRequest.State.error);
- assertTrue(req.isFinished());
- }
-
- @Test(expected = IllegalStateException.class)
- public void finish_throws_When_already_finished() {
- // Setup
- PictureCaptureRequest req = new PictureCaptureRequest(null);
- req.setState(PictureCaptureRequest.State.finished);
- // Act
- req.finish("/test/path");
- }
-
- @Test
- public void error_sets_result_and_state() {
- // Setup
- MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
- PictureCaptureRequest req = new PictureCaptureRequest(mockResult);
- // Act
- req.error("ERROR_CODE", "Error Message", null);
- // Test
- verify(mockResult).error("ERROR_CODE", "Error Message", null);
- assertEquals("State is error", req.getState(), PictureCaptureRequest.State.error);
- }
-
- @Test
- public void error_clears_timeout() {
- PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
- mock(PictureCaptureRequest.TimeoutHandler.class);
- MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
- PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler);
- req.error("ERROR_CODE", "Error Message", null);
- verify(mockTimeoutHandler, never()).resetTimeout(any());
- verify(mockTimeoutHandler).clearTimeout(any());
- }
-
- @Test(expected = IllegalStateException.class)
- public void error_throws_When_already_finished() {
- // Setup
- PictureCaptureRequest req = new PictureCaptureRequest(null);
- req.setState(PictureCaptureRequest.State.finished);
- // Act
- req.error(null, null, null);
- }
-}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/AutoFocusFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/AutoFocusFeatureTest.java
index 84e4ad0..fd8ef7c 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/AutoFocusFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/AutoFocusFeatureTest.java
@@ -28,7 +28,7 @@
};
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -36,7 +36,7 @@
}
@Test
- public void getValue_should_return_auto_if_not_set() {
+ public void getValue_shouldReturnAutoIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -44,7 +44,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
FocusMode expectedValue = FocusMode.locked;
@@ -56,7 +56,7 @@
}
@Test
- public void checkIsSupported_should_return_false_when_minimum_focus_distance_is_zero() {
+ public void checkIsSupported_shouldReturnFalseWhenMinimumFocusDistanceIsZero() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -67,7 +67,7 @@
}
@Test
- public void checkIsSupported_should_return_false_when_minimum_focus_distance_is_null() {
+ public void checkIsSupported_shouldReturnFalseWhenMinimumFocusDistanceIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -78,7 +78,7 @@
}
@Test
- public void checkIsSupport_should_return_false_when_no_focus_modes_are_available() {
+ public void checkIsSupport_shouldReturnFalseWhenNoFocusModesAreAvailable() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -89,7 +89,7 @@
}
@Test
- public void checkIsSupport_should_return_false_when_only_focus_off_is_available() {
+ public void checkIsSupport_shouldReturnFalseWhenOnlyFocusOffIsAvailable() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -100,7 +100,7 @@
}
@Test
- public void checkIsSupport_should_return_true_when_only_multiple_focus_modes_are_available() {
+ public void checkIsSupport_shouldReturnTrueWhenOnlyMultipleFocusModesAreAvailable() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -111,7 +111,7 @@
}
@Test
- public void updateBuilder_should_return_when_checkIsSupported_is_false() {
+ public void updateBuilderShouldReturnWhenCheckIsSupportedIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -125,7 +125,7 @@
}
@Test
- public void updateBuilder_should_set_control_mode_to_auto_when_focus_is_locked() {
+ public void updateBuilder_shouldSetControlModeToAutoWhenFocusIsLocked() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
@@ -142,7 +142,7 @@
@Test
public void
- updateBuilder_should_set_control_mode_to_continuous_video_when_focus_is_auto_and_recording_video() {
+ updateBuilder_shouldSetControlModeToContinuousVideoWhenFocusIsAutoAndRecordingVideo() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, true);
@@ -159,7 +159,7 @@
@Test
public void
- updateBuilder_should_set_control_mode_to_continuous_video_when_focus_is_auto_and_not_recording_video() {
+ updateBuilder_shouldSetControlModeToContinuousVideoWhenFocusIsAutoAndNotRecordingVideo() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
AutoFocusFeature autoFocusFeature = new AutoFocusFeature(mockCameraProperties, false);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/FocusModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/FocusModeTest.java
index 70d52d4..f68ae71 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/FocusModeTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/autofocus/FocusModeTest.java
@@ -11,7 +11,7 @@
public class FocusModeTest {
@Test
- public void getValueForString_returns_correct_values() {
+ public void getValueForString_returnsCorrectValues() {
assertEquals(
"Returns FocusMode.auto for 'auto'", FocusMode.getValueForString("auto"), FocusMode.auto);
assertEquals(
@@ -21,13 +21,13 @@
}
@Test
- public void getValueForString_returns_null_for_nonexistant_value() {
+ public void getValueForString_returnsNullForNonexistantValue() {
assertEquals(
"Returns null for 'nonexistant'", FocusMode.getValueForString("nonexistant"), null);
}
@Test
- public void toString_returns_correct_value() {
+ public void toString_returnsCorrectValue() {
assertEquals("Returns 'auto' for FocusMode.auto", FocusMode.auto.toString(), "auto");
assertEquals("Returns 'locked' for FocusMode.locked", FocusMode.locked.toString(), "locked");
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureLockFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureLockFeatureTest.java
index d9e0a8d..1cda0a8 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureLockFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureLockFeatureTest.java
@@ -16,7 +16,7 @@
public class ExposureLockFeatureTest {
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
@@ -24,7 +24,7 @@
}
@Test
- public void getValue_should_return_auto_if_not_set() {
+ public void getValue_shouldReturnAutoIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
@@ -32,7 +32,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
ExposureMode expectedValue = ExposureMode.locked;
@@ -44,7 +44,7 @@
}
@Test
- public void checkIsSupported_should_return_true() {
+ public void checkIsSupported_shouldReturnTrue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
@@ -52,8 +52,7 @@
}
@Test
- public void
- updateBuilder_should_set_control_ae_lock_to_false_when_auto_exposure_is_set_to_auto() {
+ public void updateBuilder_shouldSetControlAeLockToFalseWhenAutoExposureIsSetToAuto() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
@@ -65,8 +64,7 @@
}
@Test
- public void
- updateBuilder_should_set_control_ae_lock_to_false_when_auto_exposure_is_set_to_locked() {
+ public void updateBuilder_shouldSetControlAeLockToFalseWhenAutoExposureIsSetToLocked() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
ExposureLockFeature exposureLockFeature = new ExposureLockFeature(mockCameraProperties);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureModeTest.java
index ad1d3d9..d5d4769 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureModeTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurelock/ExposureModeTest.java
@@ -11,7 +11,7 @@
public class ExposureModeTest {
@Test
- public void getValueForString_returns_correct_values() {
+ public void getValueForString_returnsCorrectValues() {
assertEquals(
"Returns ExposureMode.auto for 'auto'",
ExposureMode.getValueForString("auto"),
@@ -23,13 +23,13 @@
}
@Test
- public void getValueForString_returns_null_for_nonexistant_value() {
+ public void getValueForString_returnsNullForNonexistantValue() {
assertEquals(
"Returns null for 'nonexistant'", ExposureMode.getValueForString("nonexistant"), null);
}
@Test
- public void toString_returns_correct_value() {
+ public void toString_returnsCorrectValue() {
assertEquals("Returns 'auto' for ExposureMode.auto", ExposureMode.auto.toString(), "auto");
assertEquals(
"Returns 'locked' for ExposureMode.locked", ExposureMode.locked.toString(), "locked");
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposureoffset/ExposureOffsetFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposureoffset/ExposureOffsetFeatureTest.java
index 40d17fd..ee428f3 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposureoffset/ExposureOffsetFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposureoffset/ExposureOffsetFeatureTest.java
@@ -17,7 +17,7 @@
public class ExposureOffsetFeatureTest {
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
@@ -25,7 +25,7 @@
}
@Test
- public void getValue_should_return_zero_if_not_set() {
+ public void getValue_shouldReturnZeroIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
@@ -35,7 +35,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
double expectedValue = 4.0;
@@ -49,8 +49,7 @@
}
@Test
- public void
- getExposureOffsetStepSize_should_return_the_control_exposure_compensation_step_value() {
+ public void getExposureOffsetStepSize_shouldReturnTheControlExposureCompensationStepValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
@@ -60,7 +59,7 @@
}
@Test
- public void checkIsSupported_should_return_true() {
+ public void checkIsSupported_shouldReturnTrue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
@@ -68,7 +67,7 @@
}
@Test
- public void updateBuilder_should_set_control_ae_exposure_compensation_to_offset() {
+ public void updateBuilder_shouldSetControlAeExposureCompensationToOffset() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
ExposureOffsetFeature exposureOffsetFeature = new ExposureOffsetFeature(mockCameraProperties);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeatureTest.java
index 4a515c6..b34a04f 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeatureTest.java
@@ -19,9 +19,12 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.MeteringRectangle;
import android.util.Size;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.CameraRegionUtils;
import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
@@ -30,35 +33,44 @@
public class ExposurePointFeatureTest {
Size mockCameraBoundaries;
+ SensorOrientationFeature mockSensorOrientationFeature;
+ DeviceOrientationManager mockDeviceOrientationManager;
@Before
public void setUp() {
this.mockCameraBoundaries = mock(Size.class);
when(this.mockCameraBoundaries.getWidth()).thenReturn(100);
when(this.mockCameraBoundaries.getHeight()).thenReturn(100);
+ mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ mockDeviceOrientationManager = mock(DeviceOrientationManager.class);
+ when(mockSensorOrientationFeature.getDeviceOrientationManager())
+ .thenReturn(mockDeviceOrientationManager);
+ when(mockDeviceOrientationManager.getLastUIOrientation())
+ .thenReturn(PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- CameraRegionUtils mockCameraRegions = mock(CameraRegionUtils.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
assertEquals("ExposurePointFeature", exposurePointFeature.getDebugName());
}
@Test
- public void getValue_should_return_null_if_not_set() {
+ public void getValue_shouldReturnNullIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
- Point actualPoint = exposurePointFeature.getValue();
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
assertNull(exposurePointFeature.getValue());
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
Point expectedPoint = new Point(0.0, 0.0);
@@ -69,9 +81,10 @@
}
@Test
- public void setValue_should_reset_point_when_x_coord_is_null() {
+ public void setValue_shouldResetPointWhenXCoordIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
exposurePointFeature.setValue(new Point(null, 0.0));
@@ -80,9 +93,10 @@
}
@Test
- public void setValue_should_reset_point_when_y_coord_is_null() {
+ public void setValue_shouldResetPointWhenYCoordIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
exposurePointFeature.setValue(new Point(0.0, null));
@@ -91,9 +105,10 @@
}
@Test
- public void setValue_should_set_point_when_valid_coords_are_supplied() {
+ public void setValue_shouldSetPointWhenValidCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
Point point = new Point(0.0, 0.0);
@@ -103,11 +118,11 @@
}
@Test
- public void
- setValue_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ public void setValue_shouldDetermineMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries);
@@ -117,16 +132,22 @@
exposurePointFeature.setValue(new Point(0.5, 0.5));
mockedCameraRegionUtils.verify(
- () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5),
+ () ->
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT),
times(1));
}
}
@Test(expected = AssertionError.class)
- public void setValue_should_throw_assertion_error_when_no_valid_boundaries_are_set() {
+ public void setValue_shouldThrowAssertionErrorWhenNoValidBoundariesAreSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
try (MockedStatic<CameraRegionUtils> mockedCameraRegionUtils =
Mockito.mockStatic(CameraRegionUtils.class)) {
@@ -135,10 +156,11 @@
}
@Test
- public void setValue_should_not_determine_metering_rectangle_when_null_coords_are_set() {
+ public void setValue_shouldNotDetermineMeteringRectangleWhenNullCoordsAreSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries);
@@ -155,10 +177,11 @@
@Test
public void
- setCameraBoundaries_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ setCameraBoundaries_shouldDetermineMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
exposurePointFeature.setValue(new Point(0.5, 0.5));
Size mockedCameraBoundaries = mock(Size.class);
@@ -169,15 +192,21 @@
exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries);
mockedCameraRegionUtils.verify(
- () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5),
+ () ->
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT),
times(1));
}
}
@Test
- public void checkIsSupported_should_return_false_when_max_regions_is_null() {
+ public void checkIsSupported_shouldReturnFalseWhenMaxRegionsIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(null);
@@ -186,9 +215,10 @@
}
@Test
- public void checkIsSupported_should_return_false_when_max_regions_is_zero() {
+ public void checkIsSupported_shouldReturnFalseWhenMaxRegionsIsZero() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(0);
@@ -197,9 +227,10 @@
}
@Test
- public void checkIsSupported_should_return_true_when_max_regions_is_bigger_then_zero() {
+ public void checkIsSupported_shouldReturnTrueWhenMaxRegionsIsBiggerThenZero() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
@@ -208,10 +239,11 @@
}
@Test
- public void updateBuilder_should_return_when_checkIsSupported_is_false() {
+ public void updateBuilder_shouldReturnWhenCheckIsSupportedIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(0);
@@ -221,12 +253,12 @@
}
@Test
- public void
- updateBuilder_should_set_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ public void updateBuilder_shouldSetMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class);
@@ -236,7 +268,10 @@
.when(
() ->
CameraRegionUtils.convertPointToMeteringRectangle(
- mockedCameraBoundaries, 0.5, 0.5))
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT))
.thenReturn(mockedMeteringRectangle);
exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries);
exposurePointFeature.setValue(new Point(0.5, 0.5));
@@ -249,13 +284,12 @@
}
@Test
- public void
- updateBuilder_should_not_set_metering_rectangle_when_no_valid_boundaries_are_supplied() {
+ public void updateBuilder_shouldNotSetMeteringRectangleWhenNoValidBoundariesAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
- MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.updateBuilder(mockCaptureRequestBuilder);
@@ -263,11 +297,12 @@
}
@Test
- public void updateBuilder_should_not_set_metering_rectangle_when_no_valid_coords_are_supplied() {
+ public void updateBuilder_shouldNotSetMeteringRectangleWhenNoValidCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties);
+ ExposurePointFeature exposurePointFeature =
+ new ExposurePointFeature(mockCameraProperties, mockSensorOrientationFeature);
exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries);
exposurePointFeature.setValue(null);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java
index eccfb07..f2b4ffc 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java
@@ -20,7 +20,7 @@
public class FlashFeatureTest {
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -28,7 +28,7 @@
}
@Test
- public void getValue_should_return_auto_if_not_set() {
+ public void getValue_shouldReturnAutoIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -36,7 +36,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
FlashMode expectedValue = FlashMode.torch;
@@ -48,7 +48,7 @@
}
@Test
- public void checkIsSupported_should_return_false_when_flash_info_available_is_null() {
+ public void checkIsSupported_shouldReturnFalseWhenFlashInfoAvailableIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -58,7 +58,7 @@
}
@Test
- public void checkIsSupported_should_return_false_when_flash_info_available_is_false() {
+ public void checkIsSupported_shouldReturnFalseWhenFlashInfoAvailableIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -68,7 +68,7 @@
}
@Test
- public void checkIsSupported_should_return_true_when_flash_info_available_is_true() {
+ public void checkIsSupported_shouldReturnTrueWhenFlashInfoAvailableIsTrue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -78,7 +78,7 @@
}
@Test
- public void updateBuilder_should_return_when_checkIsSupported_is_false() {
+ public void updateBuilder_shouldReturnWhenCheckIsSupportedIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -91,7 +91,7 @@
}
@Test
- public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_off() {
+ public void updateBuilder_shouldSetAeModeAndFlashModeWhenFlashModeIsOff() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -107,7 +107,7 @@
}
@Test
- public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_always() {
+ public void updateBuilder_shouldSetAeModeAndFlashModeWhenFlashModeIsAlways() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -123,7 +123,7 @@
}
@Test
- public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_torch() {
+ public void updateBuilder_shouldSetAeModeAndFlashModeWhenFlashModeIsTorch() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
@@ -139,7 +139,7 @@
}
@Test
- public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_auto() {
+ public void updateBuilder_shouldSetAeModeAndFlashModeWhenFlashModeIsAuto() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FlashFeature flashFeature = new FlashFeature(mockCameraProperties);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeatureTest.java
index d158336..f03dc9f 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeatureTest.java
@@ -19,9 +19,12 @@
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.MeteringRectangle;
import android.util.Size;
+import io.flutter.embedding.engine.systemchannels.PlatformChannel;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.CameraRegionUtils;
import io.flutter.plugins.camera.features.Point;
+import io.flutter.plugins.camera.features.sensororientation.DeviceOrientationManager;
+import io.flutter.plugins.camera.features.sensororientation.SensorOrientationFeature;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
@@ -30,35 +33,45 @@
public class FocusPointFeatureTest {
Size mockCameraBoundaries;
+ SensorOrientationFeature mockSensorOrientationFeature;
+ DeviceOrientationManager mockDeviceOrientationManager;
@Before
public void setUp() {
this.mockCameraBoundaries = mock(Size.class);
when(this.mockCameraBoundaries.getWidth()).thenReturn(100);
when(this.mockCameraBoundaries.getHeight()).thenReturn(100);
+ mockSensorOrientationFeature = mock(SensorOrientationFeature.class);
+ mockDeviceOrientationManager = mock(DeviceOrientationManager.class);
+ when(mockSensorOrientationFeature.getDeviceOrientationManager())
+ .thenReturn(mockDeviceOrientationManager);
+ when(mockDeviceOrientationManager.getLastUIOrientation())
+ .thenReturn(PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT);
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- CameraRegionUtils mockCameraRegions = mock(CameraRegionUtils.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
assertEquals("FocusPointFeature", focusPointFeature.getDebugName());
}
@Test
- public void getValue_should_return_null_if_not_set() {
+ public void getValue_shouldReturnNullIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
Point actualPoint = focusPointFeature.getValue();
assertNull(focusPointFeature.getValue());
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
Point expectedPoint = new Point(0.0, 0.0);
@@ -69,9 +82,10 @@
}
@Test
- public void setValue_should_reset_point_when_x_coord_is_null() {
+ public void setValue_shouldResetPointWhenXCoordIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
focusPointFeature.setValue(new Point(null, 0.0));
@@ -80,9 +94,10 @@
}
@Test
- public void setValue_should_reset_point_when_y_coord_is_null() {
+ public void setValue_shouldResetPointWhenYCoordIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
focusPointFeature.setValue(new Point(0.0, null));
@@ -91,9 +106,10 @@
}
@Test
- public void setValue_should_set_point_when_valid_coords_are_supplied() {
+ public void setValue_shouldSetPointWhenValidCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
Point point = new Point(0.0, 0.0);
@@ -103,11 +119,11 @@
}
@Test
- public void
- setValue_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ public void setValue_shouldDetermineMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
focusPointFeature.setCameraBoundaries(mockedCameraBoundaries);
@@ -117,16 +133,22 @@
focusPointFeature.setValue(new Point(0.5, 0.5));
mockedCameraRegionUtils.verify(
- () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5),
+ () ->
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT),
times(1));
}
}
@Test(expected = AssertionError.class)
- public void setValue_should_throw_assertion_error_when_no_valid_boundaries_are_set() {
+ public void setValue_shouldThrowAssertionErrorWhenNoValidBoundariesAreSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
try (MockedStatic<CameraRegionUtils> mockedCameraRegionUtils =
Mockito.mockStatic(CameraRegionUtils.class)) {
@@ -135,10 +157,11 @@
}
@Test
- public void setValue_should_not_determine_metering_rectangle_when_null_coords_are_set() {
+ public void setValue_shouldNotDetermineMeteringRectangleWhenNullCoordsAreSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
focusPointFeature.setCameraBoundaries(mockedCameraBoundaries);
@@ -155,10 +178,11 @@
@Test
public void
- setCameraBoundaries_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ setCameraBoundaries_shouldDetermineMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
focusPointFeature.setValue(new Point(0.5, 0.5));
Size mockedCameraBoundaries = mock(Size.class);
@@ -169,15 +193,21 @@
focusPointFeature.setCameraBoundaries(mockedCameraBoundaries);
mockedCameraRegionUtils.verify(
- () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5),
+ () ->
+ CameraRegionUtils.convertPointToMeteringRectangle(
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT),
times(1));
}
}
@Test
- public void checkIsSupported_should_return_false_when_max_regions_is_null() {
+ public void checkIsSupported_shouldReturnFalseWhenMaxRegionsIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(null);
@@ -186,9 +216,10 @@
}
@Test
- public void checkIsSupported_should_return_false_when_max_regions_is_zero() {
+ public void checkIsSupported_shouldReturnFalseWhenMaxRegionsIsZero() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(0);
@@ -197,9 +228,10 @@
}
@Test
- public void checkIsSupported_should_return_true_when_max_regions_is_bigger_then_zero() {
+ public void checkIsSupported_shouldReturnTrueWhenMaxRegionsIsBiggerThenZero() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(new Size(100, 100));
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
@@ -208,10 +240,11 @@
}
@Test
- public void updateBuilder_should_return_when_checkIsSupported_is_false() {
+ public void updateBuilder_shouldReturnWhenCheckIsSupportedIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(0);
@@ -221,12 +254,12 @@
}
@Test
- public void
- updateBuilder_should_set_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() {
+ public void updateBuilder_shouldSetMeteringRectangleWhenValidBoundariesAndCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
Size mockedCameraBoundaries = mock(Size.class);
MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class);
@@ -236,7 +269,10 @@
.when(
() ->
CameraRegionUtils.convertPointToMeteringRectangle(
- mockedCameraBoundaries, 0.5, 0.5))
+ mockedCameraBoundaries,
+ 0.5,
+ 0.5,
+ PlatformChannel.DeviceOrientation.LANDSCAPE_LEFT))
.thenReturn(mockedMeteringRectangle);
focusPointFeature.setCameraBoundaries(mockedCameraBoundaries);
focusPointFeature.setValue(new Point(0.5, 0.5));
@@ -249,12 +285,12 @@
}
@Test
- public void
- updateBuilder_should_not_set_metering_rectangle_when_no_valid_boundaries_are_supplied() {
+ public void updateBuilder_shouldNotSetMeteringRectangleWhenNoValidBoundariesAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class);
focusPointFeature.updateBuilder(mockCaptureRequestBuilder);
@@ -263,11 +299,12 @@
}
@Test
- public void updateBuilder_should_not_set_metering_rectangle_when_no_valid_coords_are_supplied() {
+ public void updateBuilder_shouldNotSetMeteringRectangleWhenNoValidCoordsAreSupplied() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1);
CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class);
- FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties);
+ FocusPointFeature focusPointFeature =
+ new FocusPointFeature(mockCameraProperties, mockSensorOrientationFeature);
focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries);
focusPointFeature.setValue(null);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeaturePixel4aTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeaturePixel4aTest.java
index 7b6e70f..93cfe55 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeaturePixel4aTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeaturePixel4aTest.java
@@ -18,7 +18,7 @@
@RunWith(RobolectricTestRunner.class)
public class FpsRangeFeaturePixel4aTest {
@Test
- public void ctor_should_initialize_fps_range_with_30_when_device_is_pixel_4a() {
+ public void ctor_shouldInitializeFpsRangeWith30WhenDeviceIsPixel4a() {
TestUtils.setFinalStatic(Build.class, "BRAND", "google");
TestUtils.setFinalStatic(Build.class, "MODEL", "Pixel 4a");
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeatureTest.java
index 77937b5..2bb4d84 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/fpsrange/FpsRangeFeatureTest.java
@@ -35,19 +35,19 @@
}
@Test
- public void ctor_should_initialize_fps_range_with_highest_upper_value_from_range_array() {
+ public void ctor_shouldInitializeFpsRangeWithHighestUpperValueFromRangeArray() {
FpsRangeFeature fpsRangeFeature = createTestInstance();
assertEquals(13, (int) fpsRangeFeature.getValue().getUpper());
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
FpsRangeFeature fpsRangeFeature = createTestInstance();
assertEquals("FpsRangeFeature", fpsRangeFeature.getDebugName());
}
@Test
- public void getValue_should_return_highest_upper_range_if_not_set() {
+ public void getValue_shouldReturnHighestUpperRangeIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FpsRangeFeature fpsRangeFeature = createTestInstance();
@@ -55,7 +55,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
FpsRangeFeature fpsRangeFeature = new FpsRangeFeature(mockCameraProperties);
@SuppressWarnings("unchecked")
@@ -68,14 +68,14 @@
}
@Test
- public void checkIsSupported_should_return_true() {
+ public void checkIsSupported_shouldReturnTrue() {
FpsRangeFeature fpsRangeFeature = createTestInstance();
assertTrue(fpsRangeFeature.checkIsSupported());
}
@Test
@SuppressWarnings("unchecked")
- public void updateBuilder_should_set_ae_target_fps_range() {
+ public void updateBuilder_shouldSetAeTargetFpsRange() {
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
FpsRangeFeature fpsRangeFeature = createTestInstance();
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java
index eb1a639..b89aad0 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java
@@ -37,7 +37,7 @@
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -45,7 +45,7 @@
}
@Test
- public void getValue_should_return_fast_if_not_set() {
+ public void getValue_shouldReturnFastIfNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -53,7 +53,7 @@
}
@Test
- public void getValue_should_echo_the_set_value() {
+ public void getValue_shouldEchoTheSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
NoiseReductionMode expectedValue = NoiseReductionMode.fast;
@@ -65,7 +65,7 @@
}
@Test
- public void checkIsSupported_should_return_false_when_available_noise_reduction_modes_is_null() {
+ public void checkIsSupported_shouldReturnFalseWhenAvailableNoiseReductionModesIsNull() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -76,7 +76,7 @@
@Test
public void
- checkIsSupported_should_return_false_when_available_noise_reduction_modes_returns_an_empty_array() {
+ checkIsSupported_shouldReturnFalseWhenAvailableNoiseReductionModesReturnsAnEmptyArray() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -87,7 +87,7 @@
@Test
public void
- checkIsSupported_should_return_true_when_available_noise_reduction_modes_returns_at_least_one_item() {
+ checkIsSupported_shouldReturnTrueWhenAvailableNoiseReductionModesReturnsAtLeastOneItem() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -97,7 +97,7 @@
}
@Test
- public void updateBuilder_should_return_when_checkIsSupported_is_false() {
+ public void updateBuilder_shouldReturnWhenCheckIsSupportedIsFalse() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class);
NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties);
@@ -110,29 +110,28 @@
}
@Test
- public void updateBuilder_should_set_noise_reduction_mode_off_when_off() {
+ public void updateBuilder_shouldSetNoiseReductionModeOffWhenOff() {
testUpdateBuilderWith(NoiseReductionMode.off, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
}
@Test
- public void updateBuilder_should_set_noise_reduction_mode_fast_when_fast() {
+ public void updateBuilder_shouldSetNoiseReductionModeFastWhenFast() {
testUpdateBuilderWith(NoiseReductionMode.fast, CaptureRequest.NOISE_REDUCTION_MODE_FAST);
}
@Test
- public void updateBuilder_should_set_noise_reduction_mode_high_quality_when_high_quality() {
+ public void updateBuilder_shouldSetNoiseReductionModeHighQualityWhenHighQuality() {
testUpdateBuilderWith(
NoiseReductionMode.highQuality, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
}
@Test
- public void updateBuilder_should_set_noise_reduction_mode_minimal_when_minimal() {
+ public void updateBuilder_shouldSetNoiseReductionModeMinimalWhenMinimal() {
testUpdateBuilderWith(NoiseReductionMode.minimal, CaptureRequest.NOISE_REDUCTION_MODE_MINIMAL);
}
@Test
- public void
- updateBuilder_should_set_noise_reduction_mode_zero_shutter_lag_when_zero_shutter_lag() {
+ public void updateBuilder_shouldSetNoiseReductionModeZeroShutterLagWhenZeroShutterLag() {
testUpdateBuilderWith(
NoiseReductionMode.zeroShutterLag, CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
index bb9cb61..e09223d 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/resolution/ResolutionFeatureTest.java
@@ -79,7 +79,7 @@
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ResolutionFeature resolutionFeature =
new ResolutionFeature(mockCameraProperties, ResolutionPreset.max, cameraName);
@@ -88,7 +88,7 @@
}
@Test
- public void getValue_should_return_initial_value_when_not_set() {
+ public void getValue_shouldReturnInitialValueWhenNotSet() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ResolutionFeature resolutionFeature =
new ResolutionFeature(mockCameraProperties, ResolutionPreset.max, cameraName);
@@ -97,7 +97,7 @@
}
@Test
- public void getValue_should_echo_setValue() {
+ public void getValue_shouldEchoSetValue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ResolutionFeature resolutionFeature =
new ResolutionFeature(mockCameraProperties, ResolutionPreset.max, cameraName);
@@ -108,7 +108,7 @@
}
@Test
- public void checkIsSupport_returns_true() {
+ public void checkIsSupport_returnsTrue() {
CameraProperties mockCameraProperties = mock(CameraProperties.class);
ResolutionFeature resolutionFeature =
new ResolutionFeature(mockCameraProperties, ResolutionPreset.max, cameraName);
@@ -117,7 +117,7 @@
}
@Test
- public void getBestAvailableCamcorderProfileForResolutionPreset_should_fall_through() {
+ public void getBestAvailableCamcorderProfileForResolutionPreset_shouldFallThrough() {
mockedStaticProfile
.when(() -> CamcorderProfile.hasProfile(1, CamcorderProfile.QUALITY_HIGH))
.thenReturn(false);
@@ -147,42 +147,42 @@
}
@Test
- public void computeBestPreviewSize_should_use_720P_when_resolution_preset_max() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetMax() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.max);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
@Test
- public void computeBestPreviewSize_should_use_720P_when_resolution_preset_ultraHigh() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetUltraHigh() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.ultraHigh);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
@Test
- public void computeBestPreviewSize_should_use_720P_when_resolution_preset_veryHigh() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetVeryHigh() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.veryHigh);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
@Test
- public void computeBestPreviewSize_should_use_720P_when_resolution_preset_high() {
+ public void computeBestPreviewSize_shouldUse720PWhenResolutionPresetHigh() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.high);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_720P));
}
@Test
- public void computeBestPreviewSize_should_use_480P_when_resolution_preset_medium() {
+ public void computeBestPreviewSize_shouldUse480PWhenResolutionPresetMedium() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.medium);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_480P));
}
@Test
- public void computeBestPreviewSize_should_use_QVGA_when_resolution_preset_low() {
+ public void computeBestPreviewSize_shouldUseQVGAWhenResolutionPresetLow() {
ResolutionFeature.computeBestPreviewSize(1, ResolutionPreset.low);
mockedStaticProfile.verify(() -> CamcorderProfile.get(1, CamcorderProfile.QUALITY_QVGA));
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
index 6e8d04d..58f17cb 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/DeviceOrientationManagerTest.java
@@ -50,15 +50,15 @@
}
@Test
- public void getMediaOrientation_when_natural_screen_orientation_equals_portrait_up() {
+ public void getVideoOrientation_whenNaturalScreenOrientationEqualsPortraitUp() {
int degreesPortraitUp =
- deviceOrientationManager.getMediaOrientation(DeviceOrientation.PORTRAIT_UP);
+ deviceOrientationManager.getVideoOrientation(DeviceOrientation.PORTRAIT_UP);
int degreesPortraitDown =
- deviceOrientationManager.getMediaOrientation(DeviceOrientation.PORTRAIT_DOWN);
+ deviceOrientationManager.getVideoOrientation(DeviceOrientation.PORTRAIT_DOWN);
int degreesLandscapeLeft =
- deviceOrientationManager.getMediaOrientation(DeviceOrientation.LANDSCAPE_LEFT);
+ deviceOrientationManager.getVideoOrientation(DeviceOrientation.LANDSCAPE_LEFT);
int degreesLandscapeRight =
- deviceOrientationManager.getMediaOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
+ deviceOrientationManager.getVideoOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
assertEquals(0, degreesPortraitUp);
assertEquals(90, degreesLandscapeLeft);
@@ -67,17 +67,17 @@
}
@Test
- public void getMediaOrientation_when_natural_screen_orientation_equals_landscape_left() {
+ public void getVideoOrientation_whenNaturalScreenOrientationEqualsLandscapeLeft() {
DeviceOrientationManager orientationManager =
DeviceOrientationManager.create(mockActivity, mockDartMessenger, false, 90);
- int degreesPortraitUp = orientationManager.getMediaOrientation(DeviceOrientation.PORTRAIT_UP);
+ int degreesPortraitUp = orientationManager.getVideoOrientation(DeviceOrientation.PORTRAIT_UP);
int degreesPortraitDown =
- orientationManager.getMediaOrientation(DeviceOrientation.PORTRAIT_DOWN);
+ orientationManager.getVideoOrientation(DeviceOrientation.PORTRAIT_DOWN);
int degreesLandscapeLeft =
- orientationManager.getMediaOrientation(DeviceOrientation.LANDSCAPE_LEFT);
+ orientationManager.getVideoOrientation(DeviceOrientation.LANDSCAPE_LEFT);
int degreesLandscapeRight =
- orientationManager.getMediaOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
+ orientationManager.getVideoOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
assertEquals(90, degreesPortraitUp);
assertEquals(180, degreesLandscapeLeft);
@@ -86,50 +86,61 @@
}
@Test
- public void getMediaOrientation_should_fallback_to_sensor_orientation_when_orientation_is_null() {
+ public void getVideoOrientation_shouldFallbackToSensorOrientationWhenOrientationIsNull() {
setUpUIOrientationMocks(Configuration.ORIENTATION_LANDSCAPE, Surface.ROTATION_0);
- int degrees = deviceOrientationManager.getMediaOrientation(null);
+ int degrees = deviceOrientationManager.getVideoOrientation(null);
assertEquals(90, degrees);
}
@Test
- public void handleSensorOrientationChange_should_send_message_when_sensor_access_is_allowed() {
- try (MockedStatic<Settings.System> mockedSystem = mockStatic(Settings.System.class)) {
- mockedSystem
- .when(
- () ->
- Settings.System.getInt(any(), eq(Settings.System.ACCELEROMETER_ROTATION), eq(0)))
- .thenReturn(1);
- setUpUIOrientationMocks(Configuration.ORIENTATION_PORTRAIT, Surface.ROTATION_0);
+ public void getPhotoOrientation_whenNaturalScreenOrientationEqualsPortraitUp() {
+ int degreesPortraitUp =
+ deviceOrientationManager.getPhotoOrientation(DeviceOrientation.PORTRAIT_UP);
+ int degreesPortraitDown =
+ deviceOrientationManager.getPhotoOrientation(DeviceOrientation.PORTRAIT_DOWN);
+ int degreesLandscapeLeft =
+ deviceOrientationManager.getPhotoOrientation(DeviceOrientation.LANDSCAPE_LEFT);
+ int degreesLandscapeRight =
+ deviceOrientationManager.getPhotoOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
- deviceOrientationManager.handleSensorOrientationChange(90);
- }
-
- verify(mockDartMessenger, times(1))
- .sendDeviceOrientationChangeEvent(DeviceOrientation.LANDSCAPE_LEFT);
+ assertEquals(0, degreesPortraitUp);
+ assertEquals(90, degreesLandscapeRight);
+ assertEquals(180, degreesPortraitDown);
+ assertEquals(270, degreesLandscapeLeft);
}
@Test
- public void
- handleSensorOrientationChange_should_send_message_when_sensor_access_is_not_allowed() {
- try (MockedStatic<Settings.System> mockedSystem = mockStatic(Settings.System.class)) {
- mockedSystem
- .when(
- () ->
- Settings.System.getInt(any(), eq(Settings.System.ACCELEROMETER_ROTATION), eq(0)))
- .thenReturn(0);
- setUpUIOrientationMocks(Configuration.ORIENTATION_PORTRAIT, Surface.ROTATION_0);
+ public void getPhotoOrientation_whenNaturalScreenOrientationEqualsLandscapeLeft() {
+ DeviceOrientationManager orientationManager =
+ DeviceOrientationManager.create(mockActivity, mockDartMessenger, false, 90);
- deviceOrientationManager.handleSensorOrientationChange(90);
- }
+ int degreesPortraitUp = orientationManager.getPhotoOrientation(DeviceOrientation.PORTRAIT_UP);
+ int degreesPortraitDown =
+ orientationManager.getPhotoOrientation(DeviceOrientation.PORTRAIT_DOWN);
+ int degreesLandscapeLeft =
+ orientationManager.getPhotoOrientation(DeviceOrientation.LANDSCAPE_LEFT);
+ int degreesLandscapeRight =
+ orientationManager.getPhotoOrientation(DeviceOrientation.LANDSCAPE_RIGHT);
- verify(mockDartMessenger, never()).sendDeviceOrientationChangeEvent(any());
+ assertEquals(90, degreesPortraitUp);
+ assertEquals(180, degreesLandscapeRight);
+ assertEquals(270, degreesPortraitDown);
+ assertEquals(0, degreesLandscapeLeft);
}
@Test
- public void handleUIOrientationChange_should_send_message_when_sensor_access_is_allowed() {
+ public void getPhotoOrientation_shouldFallbackToCurrentOrientationWhenOrientationIsNull() {
+ setUpUIOrientationMocks(Configuration.ORIENTATION_LANDSCAPE, Surface.ROTATION_0);
+
+ int degrees = deviceOrientationManager.getPhotoOrientation(null);
+
+ assertEquals(270, degrees);
+ }
+
+ @Test
+ public void handleUIOrientationChange_shouldSendMessageWhenSensorAccessIsAllowed() {
try (MockedStatic<Settings.System> mockedSystem = mockStatic(Settings.System.class)) {
mockedSystem
.when(
@@ -146,45 +157,25 @@
}
@Test
- public void handleUIOrientationChange_should_send_message_when_sensor_access_is_not_allowed() {
- try (MockedStatic<Settings.System> mockedSystem = mockStatic(Settings.System.class)) {
- mockedSystem
- .when(
- () ->
- Settings.System.getInt(any(), eq(Settings.System.ACCELEROMETER_ROTATION), eq(0)))
- .thenReturn(1);
- setUpUIOrientationMocks(Configuration.ORIENTATION_LANDSCAPE, Surface.ROTATION_0);
-
- deviceOrientationManager.handleUIOrientationChange();
- }
-
- verify(mockDartMessenger, never()).sendDeviceOrientationChangeEvent(any());
- }
-
- @Test
- public void handleOrientationChange_should_send_message_when_orientation_is_updated() {
+ public void handleOrientationChange_shouldSendMessageWhenOrientationIsUpdated() {
DeviceOrientation previousOrientation = DeviceOrientation.PORTRAIT_UP;
DeviceOrientation newOrientation = DeviceOrientation.LANDSCAPE_LEFT;
- DeviceOrientation orientation =
- DeviceOrientationManager.handleOrientationChange(
- newOrientation, previousOrientation, mockDartMessenger);
+ DeviceOrientationManager.handleOrientationChange(
+ newOrientation, previousOrientation, mockDartMessenger);
verify(mockDartMessenger, times(1)).sendDeviceOrientationChangeEvent(newOrientation);
- assertEquals(newOrientation, orientation);
}
@Test
- public void handleOrientationChange_should_not_send_message_when_orientation_is_not_updated() {
+ public void handleOrientationChange_shouldNotSendMessageWhenOrientationIsNotUpdated() {
DeviceOrientation previousOrientation = DeviceOrientation.PORTRAIT_UP;
DeviceOrientation newOrientation = DeviceOrientation.PORTRAIT_UP;
- DeviceOrientation orientation =
- DeviceOrientationManager.handleOrientationChange(
- newOrientation, previousOrientation, mockDartMessenger);
+ DeviceOrientationManager.handleOrientationChange(
+ newOrientation, previousOrientation, mockDartMessenger);
verify(mockDartMessenger, never()).sendDeviceOrientationChangeEvent(any());
- assertEquals(newOrientation, orientation);
}
@Test
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/SensorOrientationFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/SensorOrientationFeatureTest.java
index ce2bb7b..2c3a5ab 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/SensorOrientationFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/sensororientation/SensorOrientationFeatureTest.java
@@ -52,7 +52,7 @@
}
@Test
- public void ctor_should_start_device_orientation_manager() {
+ public void ctor_shouldStartDeviceOrientationManager() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -60,7 +60,7 @@
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -68,7 +68,7 @@
}
@Test
- public void getValue_should_return_null_if_not_set() {
+ public void getValue_shouldReturnNullIfNotSet() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -76,7 +76,7 @@
}
@Test
- public void getValue_should_echo_setValue() {
+ public void getValue_shouldEchoSetValue() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -86,7 +86,7 @@
}
@Test
- public void checkIsSupport_returns_true() {
+ public void checkIsSupport_returnsTrue() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -94,8 +94,7 @@
}
@Test
- public void
- getDeviceOrientationManager_should_return_initialized_DartOrientationManager_instance() {
+ public void getDeviceOrientationManager_shouldReturnInitializedDartOrientationManagerInstance() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -104,7 +103,7 @@
}
@Test
- public void lockCaptureOrientation_should_lock_to_specified_orientation() {
+ public void lockCaptureOrientation_shouldLockToSpecifiedOrientation() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
@@ -115,7 +114,7 @@
}
@Test
- public void unlockCaptureOrientation_should_set_lock_to_null() {
+ public void unlockCaptureOrientation_shouldSetLockToNull() {
SensorOrientationFeature sensorOrientationFeature =
new SensorOrientationFeature(mockCameraProperties, mockActivity, mockDartMessenger);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java
index c76708a..9f05cc2 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java
@@ -50,7 +50,7 @@
}
@Test
- public void ctor_when_parameters_are_valid() {
+ public void ctor_whenParametersAreValid() {
when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray);
when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f);
@@ -63,7 +63,7 @@
}
@Test
- public void ctor_when_sensor_size_is_null() {
+ public void ctor_whenSensorSizeIsNull() {
when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(null);
when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f);
@@ -77,7 +77,7 @@
}
@Test
- public void ctor_when_max_zoom_is_null() {
+ public void ctor_whenMaxZoomIsNull() {
when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray);
when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(null);
@@ -91,7 +91,7 @@
}
@Test
- public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() {
+ public void ctor_whenMaxZoomIsSmallerThenDefaultZoomFactor() {
when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray);
when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(0.5f);
@@ -105,21 +105,21 @@
}
@Test
- public void getDebugName_should_return_the_name_of_the_feature() {
+ public void getDebugName_shouldReturnTheNameOfTheFeature() {
ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties);
assertEquals("ZoomLevelFeature", zoomLevelFeature.getDebugName());
}
@Test
- public void getValue_should_return_null_if_not_set() {
+ public void getValue_shouldReturnNullIfNotSet() {
ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties);
assertEquals(1.0, (float) zoomLevelFeature.getValue(), 0);
}
@Test
- public void getValue_should_echo_setValue() {
+ public void getValue_shouldEchoSetValue() {
ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties);
zoomLevelFeature.setValue(2.3f);
@@ -128,14 +128,14 @@
}
@Test
- public void checkIsSupport_returns_false_by_default() {
+ public void checkIsSupport_returnsFalseByDefault() {
ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties);
assertFalse(zoomLevelFeature.checkIsSupported());
}
@Test
- public void updateBuilder_should_set_scalar_crop_region_when_checkIsSupport_is_true() {
+ public void updateBuilder_shouldSetScalarCropRegionWhenCheckIsSupportIsTrue() {
when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray);
when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java
index f83e5fb..28160ff 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java
@@ -15,7 +15,7 @@
@RunWith(RobolectricTestRunner.class)
public class ZoomUtilsTest {
@Test
- public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() {
+ public void setZoom_whenSensorSizeEqualsZeroShouldReturnCropRegionOfZero() {
final Rect sensorSize = new Rect(0, 0, 0, 0);
final Rect computedZoom = ZoomUtils.computeZoom(18f, sensorSize, 1f, 20f);
@@ -27,7 +27,7 @@
}
@Test
- public void setZoom_when_sensor_size_is_valid_should_return_crop_region() {
+ public void setZoom_whenSensorSizeIsValidShouldReturnCropRegion() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final Rect computedZoom = ZoomUtils.computeZoom(18f, sensorSize, 1f, 20f);
@@ -39,7 +39,7 @@
}
@Test
- public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() {
+ public void setZoom_whenZoomIsGreaterThenMaxZoomClampToMaxZoom() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final Rect computedZoom = ZoomUtils.computeZoom(25f, sensorSize, 1f, 10f);
@@ -51,7 +51,7 @@
}
@Test
- public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() {
+ public void setZoom_whenZoomIsSmallerThenMinZoomClampToMinZoom() {
final Rect sensorSize = new Rect(0, 0, 100, 100);
final Rect computedZoom = ZoomUtils.computeZoom(0.5f, sensorSize, 1f, 10f);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
index 9b8b54c..5425409 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/media/MediaRecorderBuilderTest.java
@@ -24,7 +24,7 @@
}
@Test
- public void build_Should_set_values_in_correct_order_When_audio_is_disabled() throws IOException {
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsDisabled() throws IOException {
CamcorderProfile recorderProfile = getEmptyCamcorderProfile();
MediaRecorderBuilder.MediaRecorderFactory mockFactory =
mock(MediaRecorderBuilder.MediaRecorderFactory.class);
@@ -55,7 +55,7 @@
}
@Test
- public void build_Should_set_values_in_correct_order_When_audio_is_enabled() throws IOException {
+ public void build_shouldSetValuesInCorrectOrderWhenAudioIsEnabled() throws IOException {
CamcorderProfile recorderProfile = getEmptyCamcorderProfile();
MediaRecorderBuilder.MediaRecorderFactory mockFactory =
mock(MediaRecorderBuilder.MediaRecorderFactory.class);
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java
index 5f4bd9f..dbef851 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/ExposureModeTest.java
@@ -11,7 +11,7 @@
public class ExposureModeTest {
@Test
- public void getValueForString_returns_correct_values() {
+ public void getValueForString_returnsCorrectValues() {
assertEquals(
"Returns ExposureMode.auto for 'auto'",
ExposureMode.getValueForString("auto"),
@@ -23,13 +23,13 @@
}
@Test
- public void getValueForString_returns_null_for_nonexistant_value() {
+ public void getValueForString_returnsNullForNonexistantValue() {
assertEquals(
"Returns null for 'nonexistant'", ExposureMode.getValueForString("nonexistant"), null);
}
@Test
- public void toString_returns_correct_value() {
+ public void toString_returnsCorrectValue() {
assertEquals("Returns 'auto' for ExposureMode.auto", ExposureMode.auto.toString(), "auto");
assertEquals(
"Returns 'locked' for ExposureMode.locked", ExposureMode.locked.toString(), "locked");
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java
index 5a53648..7ae175e 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FlashModeTest.java
@@ -11,7 +11,7 @@
public class FlashModeTest {
@Test
- public void getValueForString_returns_correct_values() {
+ public void getValueForString_returnsCorrectValues() {
assertEquals(
"Returns FlashMode.off for 'off'", FlashMode.getValueForString("off"), FlashMode.off);
assertEquals(
@@ -27,13 +27,13 @@
}
@Test
- public void getValueForString_returns_null_for_nonexistant_value() {
+ public void getValueForString_returnsNullForNonexistantValue() {
assertEquals(
"Returns null for 'nonexistant'", FlashMode.getValueForString("nonexistant"), null);
}
@Test
- public void toString_returns_correct_value() {
+ public void toString_returnsCorrectValue() {
assertEquals("Returns 'off' for FlashMode.off", FlashMode.off.toString(), "off");
assertEquals("Returns 'auto' for FlashMode.auto", FlashMode.auto.toString(), "auto");
assertEquals("Returns 'always' for FlashMode.always", FlashMode.always.toString(), "always");
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java
index 58e6d7c..1d7b95c 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/FocusModeTest.java
@@ -11,7 +11,7 @@
public class FocusModeTest {
@Test
- public void getValueForString_returns_correct_values() {
+ public void getValueForString_returnsCorrectValues() {
assertEquals(
"Returns FocusMode.auto for 'auto'", FocusMode.getValueForString("auto"), FocusMode.auto);
assertEquals(
@@ -21,13 +21,13 @@
}
@Test
- public void getValueForString_returns_null_for_nonexistant_value() {
+ public void getValueForString_returnsNullForNonexistantValue() {
assertEquals(
"Returns null for 'nonexistant'", FocusMode.getValueForString("nonexistant"), null);
}
@Test
- public void toString_returns_correct_value() {
+ public void toString_returnsCorrectValue() {
assertEquals("Returns 'auto' for FocusMode.auto", FocusMode.auto.toString(), "auto");
assertEquals("Returns 'locked' for FocusMode.locked", FocusMode.locked.toString(), "locked");
}
diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/utils/TestUtils.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/utils/TestUtils.java
index 9fc6695..dbf9d11 100644
--- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/utils/TestUtils.java
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/utils/TestUtils.java
@@ -23,4 +23,14 @@
Assert.fail("Unable to mock static field: " + fieldName);
}
}
+
+ public static <T> void setPrivateField(T instance, String fieldName, Object newValue) {
+ try {
+ Field field = instance.getClass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(instance, newValue);
+ } catch (Exception e) {
+ Assert.fail("Unable to mock private field: " + fieldName);
+ }
+ }
}
diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart
index 3284a9b..37869fe 100644
--- a/packages/camera/camera/lib/src/camera_controller.dart
+++ b/packages/camera/camera/lib/src/camera_controller.dart
@@ -118,7 +118,7 @@
/// Whether setting the focus point is supported.
final bool focusPointSupported;
- /// The current device orientation.
+ /// The current device UI orientation.
final DeviceOrientation deviceOrientation;
/// The currently locked capture orientation.
diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart
index ad3175a..1df9f8e 100644
--- a/packages/camera/camera/lib/src/camera_preview.dart
+++ b/packages/camera/camera/lib/src/camera_preview.dart
@@ -61,9 +61,9 @@
int _getQuarterTurns() {
Map<DeviceOrientation, int> turns = {
DeviceOrientation.portraitUp: 0,
- DeviceOrientation.landscapeLeft: 1,
+ DeviceOrientation.landscapeRight: 1,
DeviceOrientation.portraitDown: 2,
- DeviceOrientation.landscapeRight: 3,
+ DeviceOrientation.landscapeLeft: 3,
};
return turns[_getApplicableOrientation()]!;
}
diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml
index 5716165..a7c6a61 100644
--- a/packages/camera/camera/pubspec.yaml
+++ b/packages/camera/camera/pubspec.yaml
@@ -4,7 +4,7 @@
and streaming image buffers to dart.
repository: https://github.com/flutter/plugins/tree/master/packages/camera/camera
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
-version: 0.8.1+7
+version: 0.9.0
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -25,6 +25,7 @@
sdk: flutter
pedantic: ^1.10.0
quiver: ^3.0.0
+ flutter_plugin_android_lifecycle: ^2.0.2
dev_dependencies:
flutter_test:
diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart
index d579341..8275461 100644
--- a/packages/camera/camera/test/camera_preview_test.dart
+++ b/packages/camera/camera/test/camera_preview_test.dart
@@ -146,7 +146,7 @@
RotatedBox rotatedBox =
tester.widget<RotatedBox>(find.byType(RotatedBox));
- expect(rotatedBox.quarterTurns, 1);
+ expect(rotatedBox.quarterTurns, 3);
debugDefaultTargetPlatformOverride = null;
});
@@ -179,7 +179,7 @@
RotatedBox rotatedBox =
tester.widget<RotatedBox>(find.byType(RotatedBox));
- expect(rotatedBox.quarterTurns, 3);
+ expect(rotatedBox.quarterTurns, 1);
debugDefaultTargetPlatformOverride = null;
});
diff --git a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart
index c6cedd1..ac1c66e 100644
--- a/packages/camera/camera_platform_interface/lib/src/events/device_event.dart
+++ b/packages/camera/camera_platform_interface/lib/src/events/device_event.dart
@@ -20,8 +20,7 @@
/// They can be (and in fact, are) filtered by the `instanceof`-operator.
abstract class DeviceEvent {}
-/// The [DeviceOrientationChangedEvent] is fired every time the user changes the
-/// physical orientation of the device.
+/// The [DeviceOrientationChangedEvent] is fired every time the orientation of the device UI changes.
class DeviceOrientationChangedEvent extends DeviceEvent {
/// The new orientation of the device
final DeviceOrientation orientation;
diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart
index 9e84e8f..7a7bbf3 100644
--- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart
+++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart
@@ -96,11 +96,10 @@
throw UnimplementedError('onCameraTimeLimitReached() is not implemented.');
}
- /// The device orientation changed.
+ /// The ui orientation changed.
///
/// Implementations for this:
/// - Should support all 4 orientations.
- /// - Should not emit new values when the screen orientation is locked.
Stream<DeviceOrientationChangedEvent> onDeviceOrientationChanged() {
throw UnimplementedError(
'onDeviceOrientationChanged() is not implemented.');