From 2b7aa9b12c5cbd57b8225f38670e3ec81f11c671 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 8 Apr 2021 13:11:03 +0200 Subject: [PATCH 1/3] Base classes to support Android camera features Co-authored-by: Andrew Coutts --- .../plugins/camera/CameraProperties.java | 168 ++++++++++++ .../camera/features/CameraFeature.java | 56 ++++ .../camera/CameraPropertiesImplTest.java | 254 ++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java new file mode 100644 index 000000000000..1a8bb742d811 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java @@ -0,0 +1,168 @@ +// 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.graphics.Rect; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.os.Build.VERSION_CODES; +import android.util.Range; +import android.util.Rational; +import android.util.Size; +import androidx.annotation.RequiresApi; + +/** + * An interface allowing access to the different characteristics of the device's camera. + */ +public interface CameraProperties { + String getCameraName(); + + Range[] getControlAutoExposureAvailableTargetFpsRanges(); + + Range getControlAutoExposureCompensationRange(); + + double getControlAutoExposureCompensationStep(); + + int[] getControlAutoFocusAvailableModes(); + + Integer getControlMaxRegionsAutoExposure(); + + Integer getControlMaxRegionsAutoFocus(); + + int[] getDistortionCorrectionAvailableModes(); + + Boolean getFlashInfoAvailable(); + + int getLensFacing(); + + Float getLensInfoMinimumFocusDistance(); + + Float getScalerAvailableMaxDigitalZoom(); + + Rect getSensorInfoActiveArraySize(); + + Size getSensorInfoPixelArraySize(); + + Rect getSensorInfoPreCorrectionActiveArraySize(); + + int getSensorOrientation(); + + int getHardwareLevel(); + + 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); + } +} \ No newline at end of file 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..618c637f7589 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/CameraFeature.java @@ -0,0 +1,56 @@ +// 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(); + + /** + * Get the current value of this feature's setting. + * + * @return + */ + public abstract T getValue(); + + /** + * Set a new value for this feature's setting. + * + * @param value + */ + public abstract void setValue(T value); + + /** + * Returns whether or not this feature is supported. + * + * @return + */ + public abstract boolean checkIsSupported(); + + /** + * Update the setting in a provided request builder. + * + * @param requestBuilder + */ + public abstract void updateBuilder(CaptureRequest.Builder requestBuilder); +} \ No newline at end of file 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..189bb2cd61fb --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java @@ -0,0 +1,254 @@ +// 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.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; + +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; + +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); + } +} From f7807420ba1963eb937104a05d7cca1519774dea Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 8 Apr 2021 13:51:58 +0200 Subject: [PATCH 2/3] Fixed formatting --- .../plugins/camera/CameraProperties.java | 256 +++++----- .../camera/features/CameraFeature.java | 74 +-- .../camera/CameraPropertiesImplTest.java | 482 +++++++++--------- 3 files changed, 418 insertions(+), 394 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java index 1a8bb742d811..6ed550bc233e 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java @@ -14,155 +14,153 @@ import android.util.Size; import androidx.annotation.RequiresApi; -/** - * An interface allowing access to the different characteristics of the device's camera. - */ +/** An interface allowing access to the different characteristics of the device's camera. */ public interface CameraProperties { - String getCameraName(); + String getCameraName(); - Range[] getControlAutoExposureAvailableTargetFpsRanges(); + Range[] getControlAutoExposureAvailableTargetFpsRanges(); - Range getControlAutoExposureCompensationRange(); + Range getControlAutoExposureCompensationRange(); - double getControlAutoExposureCompensationStep(); + double getControlAutoExposureCompensationStep(); - int[] getControlAutoFocusAvailableModes(); + int[] getControlAutoFocusAvailableModes(); - Integer getControlMaxRegionsAutoExposure(); + Integer getControlMaxRegionsAutoExposure(); - Integer getControlMaxRegionsAutoFocus(); + Integer getControlMaxRegionsAutoFocus(); - int[] getDistortionCorrectionAvailableModes(); + int[] getDistortionCorrectionAvailableModes(); - Boolean getFlashInfoAvailable(); + Boolean getFlashInfoAvailable(); - int getLensFacing(); + int getLensFacing(); - Float getLensInfoMinimumFocusDistance(); + Float getLensInfoMinimumFocusDistance(); - Float getScalerAvailableMaxDigitalZoom(); + Float getScalerAvailableMaxDigitalZoom(); - Rect getSensorInfoActiveArraySize(); + Rect getSensorInfoActiveArraySize(); - Size getSensorInfoPixelArraySize(); + Size getSensorInfoPixelArraySize(); - Rect getSensorInfoPreCorrectionActiveArraySize(); + Rect getSensorInfoPreCorrectionActiveArraySize(); - int getSensorOrientation(); + int getSensorOrientation(); - int getHardwareLevel(); + int getHardwareLevel(); - int[] getAvailableNoiseReductionModes(); + int[] getAvailableNoiseReductionModes(); } /** - * Implementation of the @see CameraProperties interface using the @see android.hardware.camera2.CameraCharacteristics - * class to access the different characteristics. + * 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); - } -} \ No newline at end of file + 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 index 618c637f7589..39ecc8f92a39 100644 --- 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 @@ -17,40 +17,40 @@ * @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(); - - /** - * Get the current value of this feature's setting. - * - * @return - */ - public abstract T getValue(); - - /** - * Set a new value for this feature's setting. - * - * @param value - */ - public abstract void setValue(T value); - - /** - * Returns whether or not this feature is supported. - * - * @return - */ - public abstract boolean checkIsSupported(); - - /** - * Update the setting in a provided request builder. - * - * @param requestBuilder - */ - public abstract void updateBuilder(CaptureRequest.Builder requestBuilder); -} \ No newline at end of file + protected final CameraProperties cameraProperties; + + protected CameraFeature(@NonNull CameraProperties cameraProperties) { + this.cameraProperties = cameraProperties; + } + + /** Debug name for this feature. */ + public abstract String getDebugName(); + + /** + * Get the current value of this feature's setting. + * + * @return + */ + public abstract T getValue(); + + /** + * Set a new value for this feature's setting. + * + * @param value + */ + public abstract void setValue(T value); + + /** + * Returns whether or not this feature is supported. + * + * @return + */ + public abstract boolean checkIsSupported(); + + /** + * Update the setting in a provided request builder. + * + * @param requestBuilder + */ + 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 index 189bb2cd61fb..2c0381744191 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/CameraPropertiesImplTest.java @@ -4,6 +4,15 @@ 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; @@ -11,244 +20,261 @@ import android.util.Range; import android.util.Rational; import android.util.Size; - import org.junit.Before; import org.junit.Test; -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; - 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); + 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 getSensorInfoPreCorrectionActiveArraySize() { - Rect expectedArraySize = mock(Rect.class); - when(mockCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE)).thenReturn(expectedArraySize); - - Rect actualArraySize = cameraProperties.getSensorInfoPreCorrectionActiveArraySize(); + @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); - 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); + 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); + } - int actualOrientation = cameraProperties.getSensorOrientation(); + @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.SENSOR_ORIENTATION); - assertEquals(actualOrientation, expectedOrientation); - } + verify(mockCharacteristics, times(1)).get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + assertEquals(actualAvailability, expectedAvailability); + } - @Test - public void getHardwareLevelTest() { - int expectedLevel = 42; - when(mockCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)).thenReturn(expectedLevel); + @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(); - int actualLevel = cameraProperties.getHardwareLevel(); + 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); - 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); - } + 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); + } } From 76bc5bd2febb87319c678aa4c96cbcfe69ca32ed Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 20 Apr 2021 13:21:38 +0200 Subject: [PATCH 3/3] Applied feedback from PR --- .../plugins/camera/CameraProperties.java | 184 ++++++++++++++++++ .../camera/features/CameraFeature.java | 17 +- 2 files changed, 194 insertions(+), 7 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java index 6ed550bc233e..a69ddd0410d4 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/CameraProperties.java @@ -16,40 +16,224 @@ /** An interface allowing access to the different characteristics of the device's camera. */ public interface CameraProperties { + + /** + * Returns the name (or identifier) of the camera device. + * + * @return String The name of the camera device. + */ String getCameraName(); + /** + * Returns the list of frame rate ranges for @see android.control.aeTargetFpsRange supported by + * this camera device. + * + *

By default maps to the @see + * android.hardware.camera2.CameraCharacteristics#CONTROL_AE_TARGET_FPS_RANGE key. + * + * @return android.util.Range[] List of frame rate ranges supported by this camera + * device. + */ Range[] getControlAutoExposureAvailableTargetFpsRanges(); + /** + * Returns the maximum and minimum exposure compensation values for @see + * android.control.aeExposureCompensation, in counts of @see android.control.aeCompensationStep, + * that are supported by this camera device. + * + *

By default maps to the @see + * android.hardware.camera2.CameraCharacteristics#CONTROL_AE_COMPENSATION_RANGE key. + * + * @return android.util.Range Maximum and minimum exposure compensation supported by this + * camera device. + */ Range 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(); } 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 index 39ecc8f92a39..ad800f5e1163 100644 --- 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 @@ -27,30 +27,33 @@ protected CameraFeature(@NonNull CameraProperties cameraProperties) { public abstract String getDebugName(); /** - * Get the current value of this feature's setting. + * Gets the current value of this feature's setting. * - * @return + * @return Current value of this feature's setting. */ public abstract T getValue(); /** - * Set a new value for this feature's setting. + * Sets a new value for this feature's setting. * - * @param value + * @param value New value for this feature's setting. */ public abstract void setValue(T value); /** * Returns whether or not this feature is supported. * - * @return + *

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(); /** - * Update the setting in a provided request builder. + * Updates the setting in a provided {@see android.hardware.camera2.CaptureRequest.Builder}. * - * @param requestBuilder + * @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); }