getControlAutoExposureCompensationRange();
+
+ /**
+ * Returns the smallest step by which the exposure compensation can be changed.
+ *
+ * By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#CONTROL_AE_COMPENSATION_STEP key.
+ *
+ * @return double Smallest step by which the exposure compensation can be changed.
+ */
+ double getControlAutoExposureCompensationStep();
+
+ /**
+ * Returns a list of auto-focus modes for @see android.control.afMode that are supported by this
+ * camera device.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES key.
+ *
+ * @return int[] List of auto-focus modes supported by this camera device.
+ */
+ int[] getControlAutoFocusAvailableModes();
+
+ /**
+ * Returns the maximum number of metering regions that can be used by the auto-exposure routine.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#CONTROL_MAX_REGIONS_AE key.
+ *
+ * @return Integer Maximum number of metering regions that can be used by the auto-exposure
+ * routine.
+ */
+ Integer getControlMaxRegionsAutoExposure();
+
+ /**
+ * Returns the maximum number of metering regions that can be used by the auto-focus routine.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#CONTROL_MAX_REGIONS_AF key.
+ *
+ * @return Integer Maximum number of metering regions that can be used by the auto-focus routine.
+ */
+ Integer getControlMaxRegionsAutoFocus();
+
+ /**
+ * Returns a list of distortion correction modes for @see android.distortionCorrection.mode that
+ * are supported by this camera device.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES key.
+ *
+ * @return int[] List of distortion correction modes supported by this camera device.
+ */
+ @RequiresApi(api = VERSION_CODES.P)
+ int[] getDistortionCorrectionAvailableModes();
+
+ /**
+ * Returns whether this camera device has a flash unit.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#FLASH_INFO_AVAILABLE key.
+ *
+ * @return Boolean Whether this camera device has a flash unit.
+ */
+ Boolean getFlashInfoAvailable();
+
+ /**
+ * Returns the direction the camera faces relative to device screen.
+ *
+ *
Possible values:
+ *
+ *
+ * - @see android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT
+ *
- @see android.hardware.camera2.CameraMetadata.LENS_FACING_BACK
+ *
- @see android.hardware.camera2.CameraMetadata.LENS_FACING_EXTERNAL
+ *
+ *
+ * By default maps to the @see android.hardware.camera2.CameraCharacteristics.LENS_FACING key.
+ *
+ * @return int Direction the camera faces relative to device screen.
+ */
+ int getLensFacing();
+
+ /**
+ * Returns the shortest distance from front most surface of the lens that can be brought into
+ * sharp focus.
+ *
+ * By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE key.
+ *
+ * @return Float Shortest distance from front most surface of the lens that can be brought into
+ * sharp focus.
+ */
+ Float getLensInfoMinimumFocusDistance();
+
+ /**
+ * Returns the maximum ratio between both active area width and crop region width, and active area
+ * height and crop region height, for @see android.scaler.cropRegion.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM key.
+ *
+ * @return Float Maximum ratio between both active area width and crop region width, and active
+ * area height and crop region height
+ */
+ Float getScalerAvailableMaxDigitalZoom();
+
+ /**
+ * Returns the area of the image sensor which corresponds to active pixels after any geometric
+ * distortion correction has been applied.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE key.
+ *
+ * @return android.graphics.Rect area of the image sensor which corresponds to active pixels after
+ * any geometric distortion correction has been applied.
+ */
+ Rect getSensorInfoActiveArraySize();
+
+ /**
+ * Returns the dimensions of the full pixel array, possibly including black calibration pixels.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE key.
+ *
+ * @return android.util.Size Dimensions of the full pixel array, possibly including black
+ * calibration pixels.
+ */
+ Size getSensorInfoPixelArraySize();
+
+ /**
+ * Returns the area of the image sensor which corresponds to active pixels prior to the
+ * application of any geometric distortion correction.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * key.
+ *
+ * @return android.graphics.Rect Area of the image sensor which corresponds to active pixels prior
+ * to the application of any geometric distortion correction.
+ */
+ @RequiresApi(api = VERSION_CODES.M)
+ Rect getSensorInfoPreCorrectionActiveArraySize();
+
+ /**
+ * Returns the clockwise angle through which the output image needs to be rotated to be upright on
+ * the device screen in its native orientation.
+ *
+ *
By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#SENSOR_ORIENTATION key.
+ *
+ * @return int Clockwise angle through which the output image needs to be rotated to be upright on
+ * the device screen in its native orientation.
+ */
+ int getSensorOrientation();
+
+ /**
+ * Returns a level which generally classifies the overall set of the camera device functionality.
+ *
+ *
Possible values:
+ *
+ *
+ * - @see android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+ *
- @see android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
+ *
- @see android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL
+ *
- @see android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEVEL_3
+ *
- @see android.hardware.camera2.CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
+ *
+ *
+ * By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL key.
+ *
+ * @return int Level which generally classifies the overall set of the camera device
+ * functionality.
+ */
+ int getHardwareLevel();
+
+ /**
+ * Returns a list of noise reduction modes for @see android.noiseReduction.mode that are supported
+ * by this camera device.
+ *
+ * By default maps to the @see
+ * android.hardware.camera2.CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
+ * key.
+ *
+ * @return int[] List of noise reduction modes that are supported by this camera device.
+ */
+ int[] getAvailableNoiseReductionModes();
+}
+
+/**
+ * Implementation of the @see CameraProperties interface using the @see
+ * android.hardware.camera2.CameraCharacteristics class to access the different characteristics.
+ */
+class CameraPropertiesImpl implements CameraProperties {
+ private final CameraCharacteristics cameraCharacteristics;
+ private final String cameraName;
+
+ public CameraPropertiesImpl(String cameraName, CameraManager cameraManager)
+ throws CameraAccessException {
+ this.cameraName = cameraName;
+ this.cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraName);
+ }
+
+ @Override
+ public String getCameraName() {
+ return cameraName;
+ }
+
+ @Override
+ public Range[] getControlAutoExposureAvailableTargetFpsRanges() {
+ return cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+ }
+
+ @Override
+ public Range getControlAutoExposureCompensationRange() {
+ return cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
+ }
+
+ @Override
+ public double getControlAutoExposureCompensationStep() {
+ Rational rational =
+ cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
+
+ return rational == null ? 0.0 : rational.doubleValue();
+ }
+
+ @Override
+ public int[] getControlAutoFocusAvailableModes() {
+ return cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+ }
+
+ @Override
+ public Integer getControlMaxRegionsAutoExposure() {
+ return cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+ }
+
+ @Override
+ public Integer getControlMaxRegionsAutoFocus() {
+ return cameraCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+ }
+
+ @RequiresApi(api = VERSION_CODES.P)
+ @Override
+ public int[] getDistortionCorrectionAvailableModes() {
+ return cameraCharacteristics.get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES);
+ }
+
+ @Override
+ public Boolean getFlashInfoAvailable() {
+ return cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ }
+
+ @Override
+ public int getLensFacing() {
+ return cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
+ }
+
+ @Override
+ public Float getLensInfoMinimumFocusDistance() {
+ return cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ }
+
+ @Override
+ public Float getScalerAvailableMaxDigitalZoom() {
+ return cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+ }
+
+ @Override
+ public Rect getSensorInfoActiveArraySize() {
+ return cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ }
+
+ @Override
+ public Size getSensorInfoPixelArraySize() {
+ return cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ }
+
+ @RequiresApi(api = VERSION_CODES.M)
+ @Override
+ public Rect getSensorInfoPreCorrectionActiveArraySize() {
+ return cameraCharacteristics.get(
+ CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ }
+
+ @Override
+ public int getSensorOrientation() {
+ return cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
+ }
+
+ @Override
+ public int getHardwareLevel() {
+ return cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ }
+
+ @Override
+ public int[] getAvailableNoiseReductionModes() {
+ return cameraCharacteristics.get(
+ CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES);
+ }
+}
diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java
new file mode 100644
index 000000000000..ad800f5e1163
--- /dev/null
+++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java
@@ -0,0 +1,59 @@
+// 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;
+
+import android.hardware.camera2.CaptureRequest;
+import androidx.annotation.NonNull;
+import io.flutter.plugins.camera.CameraProperties;
+
+/**
+ * An interface describing a feature in the camera. This holds a setting value of type T and must
+ * implement a means to check if this setting is supported by the current camera properties. It also
+ * must implement a builder update method which will update a given capture request builder for this
+ * feature's current setting value.
+ *
+ * @param
+ */
+public abstract class CameraFeature {
+ protected final CameraProperties cameraProperties;
+
+ protected CameraFeature(@NonNull CameraProperties cameraProperties) {
+ this.cameraProperties = cameraProperties;
+ }
+
+ /** Debug name for this feature. */
+ public abstract String getDebugName();
+
+ /**
+ * Gets the current value of this feature's setting.
+ *
+ * @return Current value of this feature's setting.
+ */
+ public abstract T getValue();
+
+ /**
+ * Sets a new value for this feature's setting.
+ *
+ * @param value New value for this feature's setting.
+ */
+ public abstract void setValue(T value);
+
+ /**
+ * Returns whether or not this feature is supported.
+ *
+ * When the feature is not supported any {@see #value} is simply ignored by the camera plugin.
+ *
+ * @return boolean Whether or not this feature is supported.
+ */
+ public abstract boolean checkIsSupported();
+
+ /**
+ * Updates the setting in a provided {@see android.hardware.camera2.CaptureRequest.Builder}.
+ *
+ * @param requestBuilder A {@see android.hardware.camera2.CaptureRequest.Builder} instance used to
+ * configure the settings and outputs needed to capture a single image from the camera device.
+ */
+ public abstract void updateBuilder(CaptureRequest.Builder requestBuilder);
+}
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
new file mode 100644
index 000000000000..2c0381744191
--- /dev/null
+++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java
@@ -0,0 +1,280 @@
+// 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.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.util.Range;
+import android.util.Rational;
+import android.util.Size;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CameraPropertiesImplTest {
+ private static final String CAMERA_NAME = "test_camera";
+ private final CameraCharacteristics mockCharacteristics = mock(CameraCharacteristics.class);
+ private final CameraManager mockCameraManager = mock(CameraManager.class);
+
+ private CameraPropertiesImpl cameraProperties;
+
+ @Before
+ public void before() {
+ try {
+ when(mockCameraManager.getCameraCharacteristics(CAMERA_NAME)).thenReturn(mockCharacteristics);
+ cameraProperties = new CameraPropertiesImpl(CAMERA_NAME, mockCameraManager);
+ } catch (CameraAccessException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void ctor_Should_return_valid_instance() throws CameraAccessException {
+ verify(mockCameraManager, times(1)).getCameraCharacteristics(CAMERA_NAME);
+ assertNotNull(cameraProperties);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void getControlAutoExposureAvailableTargetFpsRangesTest() {
+ Range mockRange = mock(Range.class);
+ Range[] mockRanges = new Range[] {mockRange};
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES))
+ .thenReturn(mockRanges);
+
+ Range[] actualRanges =
+ cameraProperties.getControlAutoExposureAvailableTargetFpsRanges();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+ assertArrayEquals(actualRanges, mockRanges);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void getControlAutoExposureCompensationRangeTest() {
+ Range mockRange = mock(Range.class);
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE))
+ .thenReturn(mockRange);
+
+ Range actualRange = cameraProperties.getControlAutoExposureCompensationRange();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
+ assertEquals(actualRange, mockRange);
+ }
+
+ @Test
+ public void
+ getControlAutoExposureCompensationStep_Should_return_double_When_rational_is_not_null() {
+ double expectedStep = 3.1415926535;
+ Rational mockRational = mock(Rational.class);
+
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP))
+ .thenReturn(mockRational);
+ when(mockRational.doubleValue()).thenReturn(expectedStep);
+
+ double actualSteps = cameraProperties.getControlAutoExposureCompensationStep();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
+ assertEquals(actualSteps, expectedStep, 0);
+ }
+
+ @Test
+ public void getControlAutoExposureCompensationStep_Should_return_zero_When_rational_is_null() {
+ double expectedStep = 0.0;
+
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP))
+ .thenReturn(null);
+
+ double actualSteps = cameraProperties.getControlAutoExposureCompensationStep();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP);
+ assertEquals(actualSteps, expectedStep, 0);
+ }
+
+ @Test
+ public void getControlAutoFocusAvailableModesTest() {
+ int[] expectedAutoFocusModes = new int[] {0, 1, 2};
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES))
+ .thenReturn(expectedAutoFocusModes);
+
+ int[] actualAutoFocusModes = cameraProperties.getControlAutoFocusAvailableModes();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
+ assertEquals(actualAutoFocusModes, expectedAutoFocusModes);
+ }
+
+ @Test
+ public void getControlMaxRegionsAutoExposureTest() {
+ int expectedRegions = 42;
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE))
+ .thenReturn(expectedRegions);
+
+ int actualRegions = cameraProperties.getControlMaxRegionsAutoExposure();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+ assertEquals(actualRegions, expectedRegions);
+ }
+
+ @Test
+ public void getControlMaxRegionsAutoFocusTest() {
+ int expectedRegions = 42;
+ when(mockCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF))
+ .thenReturn(expectedRegions);
+
+ int actualRegions = cameraProperties.getControlMaxRegionsAutoFocus();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+ assertEquals(actualRegions, expectedRegions);
+ }
+
+ @Test
+ public void getDistortionCorrectionAvailableModesTest() {
+ int[] expectedCorrectionModes = new int[] {0, 1, 2};
+ when(mockCharacteristics.get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES))
+ .thenReturn(expectedCorrectionModes);
+
+ int[] actualCorrectionModes = cameraProperties.getDistortionCorrectionAvailableModes();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES);
+ assertEquals(actualCorrectionModes, expectedCorrectionModes);
+ }
+
+ @Test
+ public void getFlashInfoAvailableTest() {
+ boolean expectedAvailability = true;
+ when(mockCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE))
+ .thenReturn(expectedAvailability);
+
+ boolean actualAvailability = cameraProperties.getFlashInfoAvailable();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ assertEquals(actualAvailability, expectedAvailability);
+ }
+
+ @Test
+ public void getLensFacingTest() {
+ int expectedFacing = 42;
+ when(mockCharacteristics.get(CameraCharacteristics.LENS_FACING)).thenReturn(expectedFacing);
+
+ int actualFacing = cameraProperties.getLensFacing();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.LENS_FACING);
+ assertEquals(actualFacing, expectedFacing);
+ }
+
+ @Test
+ public void getLensInfoMinimumFocusDistanceTest() {
+ Float expectedFocusDistance = new Float(3.14);
+ when(mockCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE))
+ .thenReturn(expectedFocusDistance);
+
+ Float actualFocusDistance = cameraProperties.getLensInfoMinimumFocusDistance();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ assertEquals(actualFocusDistance, expectedFocusDistance);
+ }
+
+ @Test
+ public void getScalerAvailableMaxDigitalZoomTest() {
+ Float expectedDigitalZoom = new Float(3.14);
+ when(mockCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM))
+ .thenReturn(expectedDigitalZoom);
+
+ Float actualDigitalZoom = cameraProperties.getScalerAvailableMaxDigitalZoom();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+ assertEquals(actualDigitalZoom, expectedDigitalZoom);
+ }
+
+ @Test
+ public void getSensorInfoActiveArraySizeTest() {
+ Rect expectedArraySize = mock(Rect.class);
+ when(mockCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE))
+ .thenReturn(expectedArraySize);
+
+ Rect actualArraySize = cameraProperties.getSensorInfoActiveArraySize();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ assertEquals(actualArraySize, expectedArraySize);
+ }
+
+ @Test
+ public void getSensorInfoPixelArraySizeTest() {
+ Size expectedArraySize = mock(Size.class);
+ when(mockCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE))
+ .thenReturn(expectedArraySize);
+
+ Size actualArraySize = cameraProperties.getSensorInfoPixelArraySize();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ assertEquals(actualArraySize, expectedArraySize);
+ }
+
+ @Test
+ public void getSensorInfoPreCorrectionActiveArraySize() {
+ Rect expectedArraySize = mock(Rect.class);
+ when(mockCharacteristics.get(
+ CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE))
+ .thenReturn(expectedArraySize);
+
+ Rect actualArraySize = cameraProperties.getSensorInfoPreCorrectionActiveArraySize();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ assertEquals(actualArraySize, expectedArraySize);
+ }
+
+ @Test
+ public void getSensorOrientationTest() {
+ int expectedOrientation = 42;
+ when(mockCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION))
+ .thenReturn(expectedOrientation);
+
+ int actualOrientation = cameraProperties.getSensorOrientation();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.SENSOR_ORIENTATION);
+ assertEquals(actualOrientation, expectedOrientation);
+ }
+
+ @Test
+ public void getHardwareLevelTest() {
+ int expectedLevel = 42;
+ when(mockCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL))
+ .thenReturn(expectedLevel);
+
+ int actualLevel = cameraProperties.getHardwareLevel();
+
+ verify(mockCharacteristics, times(1)).get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ assertEquals(actualLevel, expectedLevel);
+ }
+
+ @Test
+ public void getAvailableNoiseReductionModesTest() {
+ int[] expectedReductionModes = new int[] {0, 1, 2};
+ when(mockCharacteristics.get(
+ CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES))
+ .thenReturn(expectedReductionModes);
+
+ int[] actualReductionModes = cameraProperties.getAvailableNoiseReductionModes();
+
+ verify(mockCharacteristics, times(1))
+ .get(CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES);
+ assertEquals(actualReductionModes, expectedReductionModes);
+ }
+}