diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index 0907c1eeecc9..65c6d26edb49 100644 --- a/packages/camera/camera/android/build.gradle +++ b/packages/camera/camera/android/build.gradle @@ -49,7 +49,7 @@ android { dependencies { compileOnly 'androidx.annotation:annotation:1.1.0' testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-inline:3.5.13' + testImplementation 'org.mockito:mockito-inline:3.11.1' testImplementation 'androidx.test:core:1.3.0' testImplementation 'org.robolectric:robolectric:4.3' } 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 new file mode 100644 index 000000000000..ff8a49f1d148 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraRegionUtils.java @@ -0,0 +1,161 @@ +// 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.annotation.TargetApi; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.MeteringRectangle; +import android.os.Build; +import android.util.Size; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import java.util.Arrays; + +/** + * Utility class offering functions to calculate values regarding the camera boundaries. + * + *

The functions are used to calculate focus and exposure settings. + */ +public final class CameraRegionUtils { + + /** + * Obtains the boundaries for the currently active camera, that can be used for calculating + * MeteringRectangle instances required for setting focus or exposure settings. + * + * @param cameraProperties - Collection of the characteristics for the current camera device. + * @param requestBuilder - The request builder for the current capture request. + * @return The boundaries for the current camera device. + */ + public static Size getCameraBoundaries( + @NonNull CameraProperties cameraProperties, @NonNull CaptureRequest.Builder requestBuilder) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P + && supportsDistortionCorrection(cameraProperties)) { + // Get the current distortion correction mode. + Integer distortionCorrectionMode = + requestBuilder.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 = cameraProperties.getSensorInfoPreCorrectionActiveArraySize(); + } else { + rect = cameraProperties.getSensorInfoActiveArraySize(); + } + + return SizeFactory.create(rect.width(), rect.height()); + } else { + // No distortion correction support. + return cameraProperties.getSensorInfoPixelArraySize(); + } + } + + /** + * Converts a point into a {@link MeteringRectangle} with the supplied coordinates as the center + * point. + * + *

Since the Camera API (due to cross-platform constraints) only accepts a point when + * configuring a specific focus or exposure area and Android requires a rectangle to configure + * these settings there is a need to convert the point into a rectangle. This method will create + * the required rectangle with an arbitrarily size that is a 10th of the current viewport and the + * coordinates as the center point. + * + * @param boundaries - The camera boundaries to calculate the metering rectangle for. + * @param x x - 1 >= coordinate >= 0. + * @param y y - 1 >= coordinate >= 0. + * @return The dimensions of the metering rectangle based on the supplied coordinates and + * boundaries. + */ + public static MeteringRectangle convertPointToMeteringRectangle( + @NonNull Size boundaries, double x, double y) { + assert (boundaries.getWidth() > 0 && boundaries.getHeight() > 0); + assert (x >= 0 && x <= 1); + assert (y >= 0 && y <= 1); + + // Interpolate the target coordinate. + int targetX = (int) Math.round(x * ((double) (boundaries.getWidth() - 1))); + int targetY = (int) Math.round(y * ((double) (boundaries.getHeight() - 1))); + // Determine the dimensions of the metering rectangle (10th of the viewport). + int targetWidth = (int) Math.round(((double) boundaries.getWidth()) / 10d); + int targetHeight = (int) Math.round(((double) boundaries.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 = boundaries.getWidth() - 1 - targetWidth; + int maxTargetY = boundaries.getHeight() - 1 - targetHeight; + if (targetX > maxTargetX) { + targetX = maxTargetX; + } + if (targetY > maxTargetY) { + targetY = maxTargetY; + } + + // Build the metering rectangle. + return MeteringRectangleFactory.create(targetX, targetY, targetWidth, targetHeight, 1); + } + + @TargetApi(Build.VERSION_CODES.P) + private static boolean supportsDistortionCorrection(CameraProperties cameraProperties) { + int[] availableDistortionCorrectionModes = + cameraProperties.getDistortionCorrectionAvailableModes(); + if (availableDistortionCorrectionModes == null) { + availableDistortionCorrectionModes = new int[0]; + } + long nonOffModesSupported = + Arrays.stream(availableDistortionCorrectionModes) + .filter((value) -> value != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) + .count(); + return nonOffModesSupported > 0; + } + + /** Factory class that assists in creating a {@link MeteringRectangle} instance. */ + static class MeteringRectangleFactory { + /** + * Creates a new instance of the {@link MeteringRectangle} class. + * + *

This method is visible for testing purposes only and should never be used outside this * + * class. + * + * @param x coordinate >= 0. + * @param y coordinate >= 0. + * @param width width >= 0. + * @param height height >= 0. + * @param meteringWeight weight between {@value MeteringRectangle#METERING_WEIGHT_MIN} and + * {@value MeteringRectangle#METERING_WEIGHT_MAX} inclusively + * @return new instance of the {@link MeteringRectangle} class. + * @throws IllegalArgumentException if any of the parameters were negative. + */ + @VisibleForTesting + public static MeteringRectangle create( + int x, int y, int width, int height, int meteringWeight) { + return new MeteringRectangle(x, y, width, height, meteringWeight); + } + } + + /** Factory class that assists in creating a {@link Size} instance. */ + static class SizeFactory { + /** + * Creates a new instance of the {@link Size} class. + * + *

This method is visible for testing purposes only and should never be used outside this * + * class. + * + * @param width width >= 0. + * @param height height >= 0. + * @return new instance of the {@link Size} class. + */ + @VisibleForTesting + public static Size create(int width, int height) { + return new Size(width, height); + } + } +} 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 f729d33c8528..8c2ee6167846 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 @@ -6,28 +6,37 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.MeteringRectangle; -import android.util.Log; +import android.util.Size; import androidx.annotation.NonNull; 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.types.CameraRegions; /** Exposure point controls where in the frame exposure metering will come from. */ public class ExposurePointFeature extends CameraFeature { - private final CameraRegions cameraRegions; - private Point currentSetting = new Point(0.0, 0.0); + private Size cameraBoundaries; + private Point exposurePoint; + private MeteringRectangle exposureRectangle; /** * Creates a new instance of the {@link ExposurePointFeature}. * * @param cameraProperties Collection of the characteristics for the current camera device. - * @param cameraRegions Utility class to assist in calculating exposure boundaries. */ - public ExposurePointFeature(CameraProperties cameraProperties, CameraRegions cameraRegions) { + public ExposurePointFeature(CameraProperties cameraProperties) { super(cameraProperties); - this.cameraRegions = cameraRegions; + } + + /** + * Sets the camera boundaries that are required for the exposure point feature to function. + * + * @param cameraBoundaries - The camera boundaries to set. + */ + public void setCameraBoundaries(@NonNull Size cameraBoundaries) { + this.cameraBoundaries = cameraBoundaries; + this.buildExposureRectangle(); } @Override @@ -37,18 +46,13 @@ public String getDebugName() { @Override public Point getValue() { - return currentSetting; + return exposurePoint; } @Override - public void setValue(@NonNull Point value) { - this.currentSetting = value; - - if (value.x == null || value.y == null) { - cameraRegions.resetAutoExposureMeteringRectangle(); - } else { - cameraRegions.setAutoExposureMeteringRectangleFromPoint(value.x, value.y); - } + public void setValue(Point value) { + this.exposurePoint = (value == null || value.x == null || value.y == null) ? null : value; + this.buildExposureRectangle(); } // Whether or not this camera can set the exposure point. @@ -63,16 +67,22 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) { if (!checkIsSupported()) { return; } - - MeteringRectangle aeRect = null; - try { - aeRect = cameraRegions.getAEMeteringRectangle(); - } catch (Exception e) { - Log.w("Camera", "Unable to retrieve the Auto Exposure metering rectangle.", e); - } - requestBuilder.set( CaptureRequest.CONTROL_AE_REGIONS, - aeRect == null ? null : new MeteringRectangle[] {aeRect}); + exposureRectangle == null ? null : new MeteringRectangle[] {exposureRectangle}); + } + + private void buildExposureRectangle() { + if (this.cameraBoundaries == null) { + throw new AssertionError( + "The cameraBoundaries should be set (using `ExposurePointFeature.setCameraBoundaries(Size)`) before updating the exposure point."); + } + if (this.exposurePoint == null) { + this.exposureRectangle = null; + } else { + this.exposureRectangle = + CameraRegionUtils.convertPointToMeteringRectangle( + this.cameraBoundaries, this.exposurePoint.x, this.exposurePoint.y); + } } } 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 new file mode 100644 index 000000000000..92fcfa9f1132 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeature.java @@ -0,0 +1,88 @@ +// 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.features.focuspoint; + +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.MeteringRectangle; +import android.util.Size; +import androidx.annotation.NonNull; +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; + +/** Focus point controls where in the frame focus will come from. */ +public class FocusPointFeature extends CameraFeature { + + private Size cameraBoundaries; + private Point focusPoint; + private MeteringRectangle focusRectangle; + + /** + * Creates a new instance of the {@link FocusPointFeature}. + * + * @param cameraProperties Collection of the characteristics for the current camera device. + */ + public FocusPointFeature(CameraProperties cameraProperties) { + super(cameraProperties); + } + + /** + * Sets the camera boundaries that are required for the focus point feature to function. + * + * @param cameraBoundaries - The camera boundaries to set. + */ + public void setCameraBoundaries(@NonNull Size cameraBoundaries) { + this.cameraBoundaries = cameraBoundaries; + this.buildFocusRectangle(); + } + + @Override + public String getDebugName() { + return "FocusPointFeature"; + } + + @Override + public Point getValue() { + return focusPoint; + } + + @Override + public void setValue(Point value) { + this.focusPoint = value == null || value.x == null || value.y == null ? null : value; + this.buildFocusRectangle(); + } + + // Whether or not this camera can set the focus point. + @Override + public boolean checkIsSupported() { + Integer supportedRegions = cameraProperties.getControlMaxRegionsAutoFocus(); + return supportedRegions != null && supportedRegions > 0; + } + + @Override + public void updateBuilder(CaptureRequest.Builder requestBuilder) { + if (!checkIsSupported()) { + return; + } + requestBuilder.set( + CaptureRequest.CONTROL_AF_REGIONS, + focusRectangle == null ? null : new MeteringRectangle[] {focusRectangle}); + } + + private void buildFocusRectangle() { + if (this.cameraBoundaries == null) { + throw new AssertionError( + "The cameraBoundaries should be set (using `FocusPointFeature.setCameraBoundaries(Size)`) before updating the focus point."); + } + if (this.focusPoint == null) { + this.focusRectangle = null; + } else { + this.focusRectangle = + CameraRegionUtils.convertPointToMeteringRectangle( + this.cameraBoundaries, this.focusPoint.x, this.focusPoint.y); + } + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/CameraRegions.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/CameraRegions.java deleted file mode 100644 index b86241e78d29..000000000000 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/types/CameraRegions.java +++ /dev/null @@ -1,199 +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.types; - -import android.annotation.TargetApi; -import android.hardware.camera2.CaptureRequest; -import android.hardware.camera2.params.MeteringRectangle; -import android.os.Build; -import android.util.Size; -import androidx.annotation.NonNull; -import io.flutter.plugins.camera.CameraProperties; -import java.util.Arrays; - -/** - * Utility class that contains information regarding the camera's regions. - * - *

The regions information is used to calculate focus and exposure settings. - */ -public final class CameraRegions { - - /** Factory class that assists in creating a {@link CameraRegions} instance. */ - public static class Factory { - /** - * Creates a new instance of the {@link CameraRegions} class. - * - *

The {@link CameraProperties} and {@link CaptureRequest.Builder} classed are used to - * determine if the device's camera supports distortion correction mode and calculate the - * correct boundaries based on the outcome. - * - * @param cameraProperties Collection of the characteristics for the current camera device. - * @param requestBuilder CaptureRequest builder containing current target and surface settings. - * @return new instance of the {@link CameraRegions} class. - */ - public static CameraRegions create( - @NonNull CameraProperties cameraProperties, - @NonNull CaptureRequest.Builder requestBuilder) { - Size boundaries; - - // No distortion correction support - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P - && supportsDistortionCorrection(cameraProperties)) { - // Get the current distortion correction mode - Integer distortionCorrectionMode = - requestBuilder.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 = cameraProperties.getSensorInfoPreCorrectionActiveArraySize(); - } else { - rect = cameraProperties.getSensorInfoActiveArraySize(); - } - - // Set new region size - boundaries = rect == null ? null : new Size(rect.width(), rect.height()); - } else { - boundaries = cameraProperties.getSensorInfoPixelArraySize(); - } - - // Create new camera regions using new size - return new CameraRegions(boundaries); - } - - @TargetApi(Build.VERSION_CODES.P) - private static boolean supportsDistortionCorrection(CameraProperties cameraProperties) { - int[] availableDistortionCorrectionModes = - cameraProperties.getDistortionCorrectionAvailableModes(); - if (availableDistortionCorrectionModes == null) { - availableDistortionCorrectionModes = new int[0]; - } - long nonOffModesSupported = - Arrays.stream(availableDistortionCorrectionModes) - .filter((value) -> value != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) - .count(); - return nonOffModesSupported > 0; - } - } - - private final Size boundaries; - - private MeteringRectangle aeMeteringRectangle; - private MeteringRectangle afMeteringRectangle; - - /** - * Creates a new instance of the {@link CameraRegions} class. - * - * @param boundaries The area of the image sensor. - */ - CameraRegions(Size boundaries) { - assert (boundaries == null || boundaries.getWidth() > 0); - assert (boundaries == null || boundaries.getHeight() > 0); - - this.boundaries = boundaries; - } - - /** - * Gets the {@link MeteringRectangle} on which the auto exposure will be applied. - * - * @return The {@link MeteringRectangle} on which the auto exposure will be applied. - */ - public MeteringRectangle getAEMeteringRectangle() { - return aeMeteringRectangle; - } - - /** - * Gets the {@link MeteringRectangle} on which the auto focus will be applied. - * - * @return The {@link MeteringRectangle} on which the auto focus will be applied. - */ - public MeteringRectangle getAFMeteringRectangle() { - return afMeteringRectangle; - } - - /** - * Gets the area of the image sensor. - * - *

If distortion correction is supported the size corresponds to the active pixels after any - * geometric distortion correction has been applied. If distortion correction is not supported the - * dimensions include the full pixel array, possibly including black calibration pixels. - * - * @return The area of the image sensor. - */ - public Size getBoundaries() { - return this.boundaries; - } - - /** Resets the {@link MeteringRectangle} on which the auto exposure will be applied. */ - public void resetAutoExposureMeteringRectangle() { - this.aeMeteringRectangle = null; - } - - /** - * Sets the coordinates which will form the centre of the exposure rectangle. - * - * @param x x – coordinate >= 0 - * @param y y – coordinate >= 0 - */ - public void setAutoExposureMeteringRectangleFromPoint(double x, double y) { - this.aeMeteringRectangle = convertPointToMeteringRectangle(x, y); - } - - /** Resets the {@link MeteringRectangle} on which the auto focus will be applied. */ - public void resetAutoFocusMeteringRectangle() { - this.afMeteringRectangle = null; - } - - /** - * Sets the coordinates which will form the centre of the focus rectangle. - * - * @param x x – coordinate >= 0 - * @param y y – coordinate >= 0 - */ - public void setAutoFocusMeteringRectangleFromPoint(double x, double y) { - this.afMeteringRectangle = convertPointToMeteringRectangle(x, y); - } - - /** - * Converts a point into a {@link MeteringRectangle} with the supplied coordinates as the centre - * point. - * - *

Since the Camera API (due to cross-platform constraints) only accepts a point when - * configuring a specific focus or exposure area and Android requires a rectangle to configure - * these settings there is a need to convert the point into a rectangle. This method will create - * the required rectangle with an arbitrarily size that is a 10th of the current viewport and the - * coordinates as the centre point. - * - * @param x x - coordinate >= 0 - * @param y y - coordinate >= 0 - * @return The dimensions of the metering rectangle based on the supplied coordinates. - */ - MeteringRectangle convertPointToMeteringRectangle(double x, double y) { - assert (x >= 0 && x <= 1); - assert (y >= 0 && y <= 1); - - // Interpolate the target coordinate - int targetX = (int) Math.round(x * ((double) (boundaries.getWidth() - 1))); - int targetY = (int) Math.round(y * ((double) (boundaries.getHeight() - 1))); - // Since the Camera API only allows Determine the dimensions of the metering rectangle (10th of - // the viewport) - int targetWidth = (int) Math.round(((double) boundaries.getWidth()) / 10d); - int targetHeight = (int) Math.round(((double) boundaries.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 = boundaries.getWidth() - 1 - targetWidth; - int maxTargetY = boundaries.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/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java new file mode 100644 index 000000000000..2d65c4e0fc05 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraRegionUtilsTest.java @@ -0,0 +1,353 @@ +// 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.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.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +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 { + + Size mockCameraBoundaries; + + @Before + public void setUp() { + this.mockCameraBoundaries = mock(Size.class); + when(this.mockCameraBoundaries.getWidth()).thenReturn(100); + when(this.mockCameraBoundaries.getHeight()).thenReturn(100); + } + + @Test + public void + getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_running_pre_android_p() { + updateSdkVersion(Build.VERSION_CODES.O_MR1); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockCameraBoundaries); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(mockCameraBoundaries, result); + verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); + verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); + } finally { + updateSdkVersion(0); + } + } + + @Test + public void + getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_distortion_correction_is_null() { + updateSdkVersion(Build.VERSION_CODES.P); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + + when(mockCameraProperties.getDistortionCorrectionAvailableModes()).thenReturn(null); + when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockCameraBoundaries); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(mockCameraBoundaries, result); + verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); + verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); + } finally { + updateSdkVersion(0); + } + } + + @Test + public void + getCameraBoundaries_should_return_sensor_info_pixel_array_size_when_distortion_correction_is_off() { + updateSdkVersion(Build.VERSION_CODES.P); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + + when(mockCameraProperties.getDistortionCorrectionAvailableModes()) + .thenReturn(new int[] {CaptureRequest.DISTORTION_CORRECTION_MODE_OFF}); + when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockCameraBoundaries); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(mockCameraBoundaries, result); + verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); + verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); + } finally { + updateSdkVersion(0); + } + } + + @Test + public void + getCameraBoundaries_should_return_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_to_null() { + updateSdkVersion(Build.VERSION_CODES.P); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + Rect mockSensorInfoPreCorrectionActiveArraySize = mock(Rect.class); + when(mockSensorInfoPreCorrectionActiveArraySize.width()).thenReturn(100); + when(mockSensorInfoPreCorrectionActiveArraySize.height()).thenReturn(100); + + when(mockCameraProperties.getDistortionCorrectionAvailableModes()) + .thenReturn( + new int[] { + CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, + CaptureRequest.DISTORTION_CORRECTION_MODE_FAST + }); + when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)).thenReturn(null); + when(mockCameraProperties.getSensorInfoPreCorrectionActiveArraySize()) + .thenReturn(mockSensorInfoPreCorrectionActiveArraySize); + + try (MockedStatic mockedSizeFactory = + mockStatic(CameraRegionUtils.SizeFactory.class)) { + mockedSizeFactory + .when(() -> CameraRegionUtils.SizeFactory.create(anyInt(), anyInt())) + .thenAnswer( + (Answer) + invocation -> { + Size mockSize = mock(Size.class); + when(mockSize.getWidth()).thenReturn(invocation.getArgument(0)); + when(mockSize.getHeight()).thenReturn(invocation.getArgument(1)); + return mockSize; + }); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(100, result.getWidth()); + assertEquals(100, result.getHeight()); + verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); + verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); + } + } finally { + updateSdkVersion(0); + } + } + + @Test + public void + getCameraBoundaries_should_return_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_to_off() { + updateSdkVersion(Build.VERSION_CODES.P); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + Rect mockSensorInfoPreCorrectionActiveArraySize = mock(Rect.class); + when(mockSensorInfoPreCorrectionActiveArraySize.width()).thenReturn(100); + when(mockSensorInfoPreCorrectionActiveArraySize.height()).thenReturn(100); + + when(mockCameraProperties.getDistortionCorrectionAvailableModes()) + .thenReturn( + new int[] { + CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, + CaptureRequest.DISTORTION_CORRECTION_MODE_FAST + }); + + when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)) + .thenReturn(CaptureRequest.DISTORTION_CORRECTION_MODE_OFF); + when(mockCameraProperties.getSensorInfoPreCorrectionActiveArraySize()) + .thenReturn(mockSensorInfoPreCorrectionActiveArraySize); + + try (MockedStatic mockedSizeFactory = + mockStatic(CameraRegionUtils.SizeFactory.class)) { + mockedSizeFactory + .when(() -> CameraRegionUtils.SizeFactory.create(anyInt(), anyInt())) + .thenAnswer( + (Answer) + invocation -> { + Size mockSize = mock(Size.class); + when(mockSize.getWidth()).thenReturn(invocation.getArgument(0)); + when(mockSize.getHeight()).thenReturn(invocation.getArgument(1)); + return mockSize; + }); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(100, result.getWidth()); + assertEquals(100, result.getHeight()); + verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); + verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); + } + } finally { + updateSdkVersion(0); + } + } + + @Test + public void + getCameraBoundaries_should_return_sensor_info_active_array_size_when_distortion_correction_mode_is_set() { + updateSdkVersion(Build.VERSION_CODES.P); + + try { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + Rect mockSensorInfoActiveArraySize = mock(Rect.class); + when(mockSensorInfoActiveArraySize.width()).thenReturn(100); + when(mockSensorInfoActiveArraySize.height()).thenReturn(100); + + when(mockCameraProperties.getDistortionCorrectionAvailableModes()) + .thenReturn( + new int[] { + CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, + CaptureRequest.DISTORTION_CORRECTION_MODE_FAST + }); + + when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)) + .thenReturn(CaptureRequest.DISTORTION_CORRECTION_MODE_FAST); + when(mockCameraProperties.getSensorInfoActiveArraySize()) + .thenReturn(mockSensorInfoActiveArraySize); + + try (MockedStatic mockedSizeFactory = + mockStatic(CameraRegionUtils.SizeFactory.class)) { + mockedSizeFactory + .when(() -> CameraRegionUtils.SizeFactory.create(anyInt(), anyInt())) + .thenAnswer( + (Answer) + invocation -> { + Size mockSize = mock(Size.class); + when(mockSize.getWidth()).thenReturn(invocation.getArgument(0)); + when(mockSize.getHeight()).thenReturn(invocation.getArgument(1)); + return mockSize; + }); + + Size result = CameraRegionUtils.getCameraBoundaries(mockCameraProperties, mockBuilder); + + assertEquals(100, result.getWidth()); + assertEquals(100, result.getHeight()); + verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); + verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); + } + } finally { + updateSdkVersion(0); + } + } + + @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 mockedMeteringRectangleFactory = + mockStatic(CameraRegionUtils.MeteringRectangleFactory.class)) { + + mockedMeteringRectangleFactory + .when( + () -> + CameraRegionUtils.MeteringRectangleFactory.create( + anyInt(), anyInt(), anyInt(), anyInt(), anyInt())) + .thenAnswer( + new Answer() { + @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() { + @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/features/exposurepoint/ExposurePointFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/exposurepoint/ExposurePointFeatureTest.java index 0aedc59ef635..4a515c6fd0ec 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 @@ -6,9 +6,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -17,41 +18,48 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.MeteringRectangle; +import android.util.Size; import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.CameraRegionUtils; import io.flutter.plugins.camera.features.Point; -import io.flutter.plugins.camera.types.CameraRegions; +import org.junit.Before; import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; public class ExposurePointFeatureTest { + + Size mockCameraBoundaries; + + @Before + public void setUp() { + this.mockCameraBoundaries = mock(Size.class); + when(this.mockCameraBoundaries.getWidth()).thenReturn(100); + when(this.mockCameraBoundaries.getHeight()).thenReturn(100); + } + @Test public void getDebugName_should_return_the_name_of_the_feature() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + CameraRegionUtils mockCameraRegions = mock(CameraRegionUtils.class); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); assertEquals("ExposurePointFeature", exposurePointFeature.getDebugName()); } @Test - public void getValue_should_return_default_point_if_not_set() { + public void getValue_should_return_null_if_not_set() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); - Point expectedPoint = new Point(0.0, 0.0); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); Point actualPoint = exposurePointFeature.getValue(); - - assertEquals(expectedPoint.x, actualPoint.x); - assertEquals(expectedPoint.y, actualPoint.y); + assertNull(exposurePointFeature.getValue()); } @Test public void getValue_should_echo_the_set_value() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); Point expectedPoint = new Point(0.0, 0.0); exposurePointFeature.setValue(expectedPoint); @@ -63,45 +71,114 @@ public void getValue_should_echo_the_set_value() { @Test public void setValue_should_reset_point_when_x_coord_is_null() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); exposurePointFeature.setValue(new Point(null, 0.0)); - verify(mockCameraRegions, times(1)).resetAutoExposureMeteringRectangle(); + assertNull(exposurePointFeature.getValue()); } @Test public void setValue_should_reset_point_when_y_coord_is_null() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); exposurePointFeature.setValue(new Point(0.0, null)); - verify(mockCameraRegions, times(1)).resetAutoExposureMeteringRectangle(); + assertNull(exposurePointFeature.getValue()); } @Test - public void setValue_should_reset_point_when_valid_coords_are_supplied() { + public void setValue_should_set_point_when_valid_coords_are_supplied() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); Point point = new Point(0.0, 0.0); exposurePointFeature.setValue(point); - verify(mockCameraRegions, times(1)).setAutoExposureMeteringRectangleFromPoint(point.x, point.y); + assertEquals(point, exposurePointFeature.getValue()); + } + + @Test + public void + setValue_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + exposurePointFeature.setValue(new Point(0.5, 0.5)); + + mockedCameraRegionUtils.verify( + () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5), + times(1)); + } + } + + @Test(expected = AssertionError.class) + public void setValue_should_throw_assertion_error_when_no_valid_boundaries_are_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + exposurePointFeature.setValue(new Point(0.5, 0.5)); + } + } + + @Test + public void setValue_should_not_determine_metering_rectangle_when_null_coords_are_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + exposurePointFeature.setValue(null); + exposurePointFeature.setValue(new Point(null, 0.5)); + exposurePointFeature.setValue(new Point(0.5, null)); + + mockedCameraRegionUtils.verifyNoInteractions(); + } + } + + @Test + public void + setCameraBoundaries_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); + exposurePointFeature.setValue(new Point(0.5, 0.5)); + Size mockedCameraBoundaries = mock(Size.class); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries); + + mockedCameraRegionUtils.verify( + () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5), + times(1)); + } } @Test public void checkIsSupported_should_return_false_when_max_regions_is_null() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, null); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(new Size(100, 100)); when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(null); @@ -111,8 +188,8 @@ public void checkIsSupported_should_return_false_when_max_regions_is_null() { @Test public void checkIsSupported_should_return_false_when_max_regions_is_zero() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, null); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(new Size(100, 100)); when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(0); @@ -122,8 +199,8 @@ public void checkIsSupported_should_return_false_when_max_regions_is_zero() { @Test public void checkIsSupported_should_return_true_when_max_regions_is_bigger_then_zero() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, null); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(new Size(100, 100)); when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); @@ -133,64 +210,72 @@ public void checkIsSupported_should_return_true_when_max_regions_is_bigger_then_ @Test public void updateBuilder_should_return_when_checkIsSupported_is_false() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(0); - exposurePointFeature.updateBuilder(null); + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); - verify(mockCameraRegions, never()).getAEMeteringRectangle(); + verify(mockCaptureRequestBuilder, never()).set(any(), any()); } @Test - public void updateBuilder_should_set_ae_regions_to_null_when_ae_metering_rectangle_is_null() { + public void + updateBuilder_should_set_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); - when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); - when(mockCameraRegions.getAEMeteringRectangle()).thenReturn(null); - - exposurePointFeature.updateBuilder(mockBuilder); - - verify(mockBuilder, times(1)).set(CaptureRequest.CONTROL_AE_REGIONS, null); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + mockedCameraRegionUtils + .when( + () -> + CameraRegionUtils.convertPointToMeteringRectangle( + mockedCameraBoundaries, 0.5, 0.5)) + .thenReturn(mockedMeteringRectangle); + exposurePointFeature.setCameraBoundaries(mockedCameraBoundaries); + exposurePointFeature.setValue(new Point(0.5, 0.5)); + + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); + } + + verify(mockCaptureRequestBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[] {mockedMeteringRectangle}); } @Test - public void updateBuilder_should_set_ae_regions_with_metering_rectangle() { + public void + updateBuilder_should_not_set_metering_rectangle_when_no_valid_boundaries_are_supplied() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); - MeteringRectangle meteringRectangle = new MeteringRectangle(0, 0, 0, 0, 0); - when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); - when(mockCameraRegions.getAEMeteringRectangle()).thenReturn(meteringRectangle); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class); - exposurePointFeature.updateBuilder(mockBuilder); + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); - verify(mockBuilder, times(1)) - .set(eq(CaptureRequest.CONTROL_AE_REGIONS), any(MeteringRectangle[].class)); + verify(mockCaptureRequestBuilder, times(1)).set(any(), isNull()); } @Test - public void updateBuilder_should_silently_fail_when_exception_occurs() { + public void updateBuilder_should_not_set_metering_rectangle_when_no_valid_coords_are_supplied() { CameraProperties mockCameraProperties = mock(CameraProperties.class); - CameraRegions mockCameraRegions = mock(CameraRegions.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - ExposurePointFeature exposurePointFeature = - new ExposurePointFeature(mockCameraProperties, mockCameraRegions); - when(mockCameraProperties.getControlMaxRegionsAutoExposure()).thenReturn(1); - when(mockCameraRegions.getAEMeteringRectangle()).thenThrow(new IllegalArgumentException()); - - exposurePointFeature.updateBuilder(mockBuilder); - - verify(mockBuilder, times(1)).set(CaptureRequest.CONTROL_AE_REGIONS, null); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + ExposurePointFeature exposurePointFeature = new ExposurePointFeature(mockCameraProperties); + exposurePointFeature.setCameraBoundaries(this.mockCameraBoundaries); + + exposurePointFeature.setValue(null); + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); + exposurePointFeature.setValue(new Point(0d, null)); + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); + exposurePointFeature.setValue(new Point(null, 0d)); + exposurePointFeature.updateBuilder(mockCaptureRequestBuilder); + verify(mockCaptureRequestBuilder, times(3)).set(any(), isNull()); } } 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 new file mode 100644 index 000000000000..d158336ef235 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/focuspoint/FocusPointFeatureTest.java @@ -0,0 +1,281 @@ +// 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.features.focuspoint; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.isNull; +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.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.MeteringRectangle; +import android.util.Size; +import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.CameraRegionUtils; +import io.flutter.plugins.camera.features.Point; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public class FocusPointFeatureTest { + + Size mockCameraBoundaries; + + @Before + public void setUp() { + this.mockCameraBoundaries = mock(Size.class); + when(this.mockCameraBoundaries.getWidth()).thenReturn(100); + when(this.mockCameraBoundaries.getHeight()).thenReturn(100); + } + + @Test + public void getDebugName_should_return_the_name_of_the_feature() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CameraRegionUtils mockCameraRegions = mock(CameraRegionUtils.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + + assertEquals("FocusPointFeature", focusPointFeature.getDebugName()); + } + + @Test + public void getValue_should_return_null_if_not_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + Point actualPoint = focusPointFeature.getValue(); + assertNull(focusPointFeature.getValue()); + } + + @Test + public void getValue_should_echo_the_set_value() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + Point expectedPoint = new Point(0.0, 0.0); + + focusPointFeature.setValue(expectedPoint); + Point actualPoint = focusPointFeature.getValue(); + + assertEquals(expectedPoint, actualPoint); + } + + @Test + public void setValue_should_reset_point_when_x_coord_is_null() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + + focusPointFeature.setValue(new Point(null, 0.0)); + + assertNull(focusPointFeature.getValue()); + } + + @Test + public void setValue_should_reset_point_when_y_coord_is_null() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + + focusPointFeature.setValue(new Point(0.0, null)); + + assertNull(focusPointFeature.getValue()); + } + + @Test + public void setValue_should_set_point_when_valid_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + Point point = new Point(0.0, 0.0); + + focusPointFeature.setValue(point); + + assertEquals(point, focusPointFeature.getValue()); + } + + @Test + public void + setValue_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + focusPointFeature.setCameraBoundaries(mockedCameraBoundaries); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + focusPointFeature.setValue(new Point(0.5, 0.5)); + + mockedCameraRegionUtils.verify( + () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5), + times(1)); + } + } + + @Test(expected = AssertionError.class) + public void setValue_should_throw_assertion_error_when_no_valid_boundaries_are_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + focusPointFeature.setValue(new Point(0.5, 0.5)); + } + } + + @Test + public void setValue_should_not_determine_metering_rectangle_when_null_coords_are_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + focusPointFeature.setCameraBoundaries(mockedCameraBoundaries); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + focusPointFeature.setValue(null); + focusPointFeature.setValue(new Point(null, 0.5)); + focusPointFeature.setValue(new Point(0.5, null)); + + mockedCameraRegionUtils.verifyNoInteractions(); + } + } + + @Test + public void + setCameraBoundaries_should_determine_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + focusPointFeature.setValue(new Point(0.5, 0.5)); + Size mockedCameraBoundaries = mock(Size.class); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + + focusPointFeature.setCameraBoundaries(mockedCameraBoundaries); + + mockedCameraRegionUtils.verify( + () -> CameraRegionUtils.convertPointToMeteringRectangle(mockedCameraBoundaries, 0.5, 0.5), + times(1)); + } + } + + @Test + public void checkIsSupported_should_return_false_when_max_regions_is_null() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(new Size(100, 100)); + + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(null); + + assertFalse(focusPointFeature.checkIsSupported()); + } + + @Test + public void checkIsSupported_should_return_false_when_max_regions_is_zero() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(new Size(100, 100)); + + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(0); + + assertFalse(focusPointFeature.checkIsSupported()); + } + + @Test + public void checkIsSupported_should_return_true_when_max_regions_is_bigger_then_zero() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(new Size(100, 100)); + + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + + assertTrue(focusPointFeature.checkIsSupported()); + } + + @Test + public void updateBuilder_should_return_when_checkIsSupported_is_false() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(0); + + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + + verify(mockCaptureRequestBuilder, never()).set(any(), any()); + } + + @Test + public void + updateBuilder_should_set_metering_rectangle_when_valid_boundaries_and_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + Size mockedCameraBoundaries = mock(Size.class); + MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class); + + try (MockedStatic mockedCameraRegionUtils = + Mockito.mockStatic(CameraRegionUtils.class)) { + mockedCameraRegionUtils + .when( + () -> + CameraRegionUtils.convertPointToMeteringRectangle( + mockedCameraBoundaries, 0.5, 0.5)) + .thenReturn(mockedMeteringRectangle); + focusPointFeature.setCameraBoundaries(mockedCameraBoundaries); + focusPointFeature.setValue(new Point(0.5, 0.5)); + + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + } + + verify(mockCaptureRequestBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[] {mockedMeteringRectangle}); + } + + @Test + public void + updateBuilder_should_not_set_metering_rectangle_when_no_valid_boundaries_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + MeteringRectangle mockedMeteringRectangle = mock(MeteringRectangle.class); + + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + + verify(mockCaptureRequestBuilder, times(1)).set(any(), isNull()); + } + + @Test + public void updateBuilder_should_not_set_metering_rectangle_when_no_valid_coords_are_supplied() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + when(mockCameraProperties.getControlMaxRegionsAutoFocus()).thenReturn(1); + CaptureRequest.Builder mockCaptureRequestBuilder = mock(CaptureRequest.Builder.class); + FocusPointFeature focusPointFeature = new FocusPointFeature(mockCameraProperties); + focusPointFeature.setCameraBoundaries(this.mockCameraBoundaries); + + focusPointFeature.setValue(null); + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + focusPointFeature.setValue(new Point(0d, null)); + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + focusPointFeature.setValue(new Point(null, 0d)); + focusPointFeature.updateBuilder(mockCaptureRequestBuilder); + verify(mockCaptureRequestBuilder, times(3)).set(any(), isNull()); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsFactoryTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsFactoryTest.java deleted file mode 100644 index 5fa0c2c4a2a4..000000000000 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsFactoryTest.java +++ /dev/null @@ -1,201 +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.types; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.hardware.camera2.CaptureRequest; -import android.os.Build.VERSION; -import android.os.Build.VERSION_CODES; -import android.util.Size; -import io.flutter.plugins.camera.CameraProperties; -import io.flutter.plugins.camera.utils.TestUtils; -import org.junit.Before; -import org.junit.Test; - -public class CameraRegionsFactoryTest { - private Size mockSize; - - @Before - public void before() { - mockSize = mock(Size.class); - - when(mockSize.getHeight()).thenReturn(640); - when(mockSize.getWidth()).thenReturn(480); - } - - @Test - public void - create_should_initialize_with_sensor_info_pixel_array_size_when_running_pre_android_p() { - updateSdkVersion(VERSION_CODES.O_MR1); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockSize); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertEquals(mockSize, cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); - verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void - create_should_initialize_with_sensor_info_pixel_array_size_when_distortion_correction_is_null() { - updateSdkVersion(VERSION_CODES.P); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getDistortionCorrectionAvailableModes()).thenReturn(null); - when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockSize); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertEquals(mockSize, cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); - verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void - create_should_initialize_with_sensor_info_pixel_array_size_when_distortion_correction_is_off() { - updateSdkVersion(VERSION_CODES.P); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getDistortionCorrectionAvailableModes()) - .thenReturn(new int[] {CaptureRequest.DISTORTION_CORRECTION_MODE_OFF}); - when(mockCameraProperties.getSensorInfoPixelArraySize()).thenReturn(mockSize); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertEquals(mockSize, cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); - verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void - create_should_initialize_with_sensor_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_to_null() { - updateSdkVersion(VERSION_CODES.P); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getDistortionCorrectionAvailableModes()) - .thenReturn( - new int[] { - CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, - CaptureRequest.DISTORTION_CORRECTION_MODE_FAST - }); - - when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)).thenReturn(null); - when(mockCameraProperties.getSensorInfoPreCorrectionActiveArraySize()).thenReturn(null); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertNull(cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); - verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void - create_should_initialize_with_sensor_info_pre_correction_active_array_size_when_distortion_correction_mode_is_set_off() { - updateSdkVersion(VERSION_CODES.P); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getDistortionCorrectionAvailableModes()) - .thenReturn( - new int[] { - CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, - CaptureRequest.DISTORTION_CORRECTION_MODE_FAST - }); - - when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)) - .thenReturn(CaptureRequest.DISTORTION_CORRECTION_MODE_OFF); - when(mockCameraProperties.getSensorInfoPreCorrectionActiveArraySize()).thenReturn(null); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertNull(cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); - verify(mockCameraProperties, never()).getSensorInfoActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void - ctor_should_initialize_with_sensor_info_active_array_size_when_distortion_correction_mode_is_set() { - updateSdkVersion(VERSION_CODES.P); - - try { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - - when(mockCameraProperties.getDistortionCorrectionAvailableModes()) - .thenReturn( - new int[] { - CaptureRequest.DISTORTION_CORRECTION_MODE_OFF, - CaptureRequest.DISTORTION_CORRECTION_MODE_FAST - }); - - when(mockBuilder.get(CaptureRequest.DISTORTION_CORRECTION_MODE)) - .thenReturn(CaptureRequest.DISTORTION_CORRECTION_MODE_FAST); - when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(null); - - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertNull(cameraRegions.getBoundaries()); - verify(mockCameraProperties, never()).getSensorInfoPixelArraySize(); - verify(mockCameraProperties, never()).getSensorInfoPreCorrectionActiveArraySize(); - } finally { - updateSdkVersion(0); - } - } - - @Test - public void getBoundaries_should_return_null_if_not_set() { - CameraProperties mockCameraProperties = mock(CameraProperties.class); - CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - CameraRegions cameraRegions = CameraRegions.Factory.create(mockCameraProperties, mockBuilder); - - assertNull(cameraRegions.getBoundaries()); - } - - private static void updateSdkVersion(int version) { - TestUtils.setFinalStatic(VERSION.class, "SDK_INT", version); - } -} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsTest.java deleted file mode 100644 index b760e1e9ca29..000000000000 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/types/CameraRegionsTest.java +++ /dev/null @@ -1,114 +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.types; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import android.hardware.camera2.params.MeteringRectangle; -import android.util.Size; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class CameraRegionsTest { - io.flutter.plugins.camera.types.CameraRegions cameraRegions; - - @Before - public void setUp() { - this.cameraRegions = new io.flutter.plugins.camera.types.CameraRegions(new Size(100, 100)); - } - - @Test(expected = AssertionError.class) - public void getMeteringRectangleForPoint_should_throw_for_x_upper_bound() { - cameraRegions.convertPointToMeteringRectangle(1.5, 0); - } - - @Test(expected = AssertionError.class) - public void getMeteringRectangleForPoint_should_throw_for_x_lower_bound() { - cameraRegions.convertPointToMeteringRectangle(-0.5, 0); - } - - @Test(expected = AssertionError.class) - public void getMeteringRectangleForPoint_should_throw_for_y_upper_bound() { - cameraRegions.convertPointToMeteringRectangle(0, 1.5); - } - - @Test(expected = AssertionError.class) - public void getMeteringRectangleForPoint_should_throw_for_y_lower_bound() { - cameraRegions.convertPointToMeteringRectangle(0, -0.5); - } - - @Test - public void getMeteringRectangleForPoint_should_return_valid_MeteringRectangle() { - MeteringRectangle r; - // Center - r = cameraRegions.convertPointToMeteringRectangle(0.5, 0.5); - assertEquals(new MeteringRectangle(45, 45, 10, 10, 1), r); - - // Top left - r = cameraRegions.convertPointToMeteringRectangle(0.0, 0.0); - assertEquals(new MeteringRectangle(0, 0, 10, 10, 1), r); - - // Bottom right - r = cameraRegions.convertPointToMeteringRectangle(1.0, 1.0); - assertEquals(new MeteringRectangle(89, 89, 10, 10, 1), r); - - // Top left - r = cameraRegions.convertPointToMeteringRectangle(0.0, 1.0); - assertEquals(new MeteringRectangle(0, 89, 10, 10, 1), r); - - // Top right - r = cameraRegions.convertPointToMeteringRectangle(1.0, 0.0); - assertEquals(new MeteringRectangle(89, 0, 10, 10, 1), r); - } - - @Test(expected = AssertionError.class) - public void constructor_should_throw_for_0_width_boundary() { - new io.flutter.plugins.camera.CameraRegions(new Size(0, 50)); - } - - @Test(expected = AssertionError.class) - public void constructor_should_throw_for_0_height_boundary() { - new io.flutter.plugins.camera.CameraRegions(new Size(100, 0)); - } - - @Test - public void setAutoExposureMeteringRectangleFromPoint_should_set_aeMeteringRectangle_for_point() { - cameraRegions.setAutoExposureMeteringRectangleFromPoint(0, 0); - assertEquals(new MeteringRectangle(0, 0, 10, 10, 1), cameraRegions.getAEMeteringRectangle()); - } - - @Test - public void resetAutoExposureMeteringRectangle_should_reset_aeMeteringRectangle() { - io.flutter.plugins.camera.types.CameraRegions cr = - new io.flutter.plugins.camera.types.CameraRegions(new Size(100, 50)); - cr.setAutoExposureMeteringRectangleFromPoint(0, 0); - assertNotNull(cr.getAEMeteringRectangle()); - cr.resetAutoExposureMeteringRectangle(); - assertNull(cr.getAEMeteringRectangle()); - } - - @Test - public void setAutoFocusMeteringRectangleFromPoint_should_set_afMeteringRectangle_for_point() { - io.flutter.plugins.camera.types.CameraRegions cr = - new io.flutter.plugins.camera.types.CameraRegions(new Size(100, 50)); - cr.setAutoFocusMeteringRectangleFromPoint(0, 0); - assertEquals(new MeteringRectangle(0, 0, 10, 5, 1), cr.getAFMeteringRectangle()); - } - - @Test - public void resetAutoFocusMeteringRectangle_should_reset_afMeteringRectangle() { - io.flutter.plugins.camera.types.CameraRegions cr = - new io.flutter.plugins.camera.types.CameraRegions(new Size(100, 50)); - cr.setAutoFocusMeteringRectangleFromPoint(0, 0); - assertNotNull(cr.getAFMeteringRectangle()); - cr.resetAutoFocusMeteringRectangle(); - assertNull(cr.getAFMeteringRectangle()); - } -}