From 2b7aa9b12c5cbd57b8225f38670e3ec81f11c671 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 8 Apr 2021 13:11:03 +0200 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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); } From 547f58ae8104705291e216b1c32ac93755bc4379 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Thu, 8 Apr 2021 15:31:56 +0200 Subject: [PATCH 04/10] Added Android Flash and Zoom features Co-authored-by: Andrew Coutts --- .../camera/features/flash/FlashFeature.java | 69 ++++++++ .../camera/features/flash/FlashMode.java | 31 ++++ .../camera/features/zoomlevel/CameraZoom.java | 56 +++++++ .../features/zoomlevel/ZoomLevelFeature.java | 59 +++++++ .../features/flash/FlashFeatureTest.java | 156 ++++++++++++++++++ .../features/zoomlevel/CameraZoomTest.java | 125 ++++++++++++++ .../zoomlevel/ZoomLevelFeatureTest.java | 101 ++++++++++++ 7 files changed, 597 insertions(+) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashMode.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java new file mode 100644 index 000000000000..8703ff45c098 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java @@ -0,0 +1,69 @@ +// 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.flash; + +import android.hardware.camera2.CaptureRequest; +import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.features.CameraFeature; + +public class FlashFeature extends CameraFeature { + private FlashMode currentSetting = FlashMode.auto; + + public FlashFeature(CameraProperties cameraProperties) { + super(cameraProperties); + } + + @Override + public String getDebugName() { + return "FlashFeature"; + } + + @Override + public FlashMode getValue() { + return currentSetting; + } + + @Override + public void setValue(FlashMode value) { + this.currentSetting = value; + } + + @Override + public boolean checkIsSupported() { + Boolean available = cameraProperties.getFlashInfoAvailable(); + return available != null && available; + } + + @Override + public void updateBuilder(CaptureRequest.Builder requestBuilder) { + if (!checkIsSupported()) { + return; + } + + switch (currentSetting) { + case off: + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + + case always: + requestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); + requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + + case torch: + requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + break; + + case auto: + requestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + break; + } + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashMode.java new file mode 100644 index 000000000000..d4a5ee0ab12f --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashMode.java @@ -0,0 +1,31 @@ +// 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.flash; + +// Mirrors flash_mode.dart +public enum FlashMode { + off("off"), + auto("auto"), + always("always"), + torch("torch"); + + private final String strValue; + + FlashMode(String strValue) { + this.strValue = strValue; + } + + public static FlashMode getValueForString(String modeStr) { + for (FlashMode value : values()) { + if (value.strValue.equals(modeStr)) return value; + } + return null; + } + + @Override + public String toString() { + return strValue; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java new file mode 100644 index 000000000000..b03b84f1534b --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.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.zoomlevel; + +import android.graphics.Rect; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.math.MathUtils; + +public final class CameraZoom { + public static final float DEFAULT_ZOOM_FACTOR = 1.0f; + + @NonNull private final Rect cropRegion = new Rect(); + @Nullable private final Rect sensorSize; + + public final float maxZoom; + public final boolean hasSupport; + + public static CameraZoom create(@Nullable final Rect sensorArraySize, final Float maxZoom) { + return new CameraZoom(sensorArraySize, maxZoom); + } + + private CameraZoom(@Nullable final Rect sensorArraySize, final Float maxZoom) { + this.sensorSize = sensorArraySize; + + if (this.sensorSize == null) { + this.maxZoom = DEFAULT_ZOOM_FACTOR; + this.hasSupport = false; + return; + } + + this.maxZoom = + ((maxZoom == null) || (maxZoom < DEFAULT_ZOOM_FACTOR)) ? DEFAULT_ZOOM_FACTOR : maxZoom; + + this.hasSupport = (Float.compare(this.maxZoom, DEFAULT_ZOOM_FACTOR) > 0); + } + + public Rect computeZoom(final float zoom) { + if (sensorSize == null || !this.hasSupport) { + return null; + } + + final float newZoom = MathUtils.clamp(zoom, DEFAULT_ZOOM_FACTOR, this.maxZoom); + + final int centerX = this.sensorSize.width() / 2; + final int centerY = this.sensorSize.height() / 2; + final int deltaX = (int) ((0.5f * this.sensorSize.width()) / newZoom); + final int deltaY = (int) ((0.5f * this.sensorSize.height()) / newZoom); + + this.cropRegion.set(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY); + + return cropRegion; + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java new file mode 100644 index 000000000000..ff6087d85e28 --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.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.zoomlevel; + +import android.graphics.Rect; +import android.hardware.camera2.CaptureRequest; +import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.features.CameraFeature; + +/** Exposure offset makes the image brighter or darker. */ +public class ZoomLevelFeature extends CameraFeature { + private final CameraZoom cameraZoom; + private Float currentSetting = CameraZoom.DEFAULT_ZOOM_FACTOR; + + public ZoomLevelFeature(CameraProperties cameraProperties) { + super(cameraProperties); + this.cameraZoom = + CameraZoom.create( + cameraProperties.getSensorInfoActiveArraySize(), + cameraProperties.getScalerAvailableMaxDigitalZoom()); + } + + @Override + public String getDebugName() { + return "ZoomLevelFeature"; + } + + @Override + public Float getValue() { + return currentSetting; + } + + @Override + public void setValue(Float value) { + this.currentSetting = value; + } + + // Available on all devices. + @Override + public boolean checkIsSupported() { + return true; + } + + @Override + public void updateBuilder(CaptureRequest.Builder requestBuilder) { + if (!checkIsSupported()) { + return; + } + + final Rect computedZoom = cameraZoom.computeZoom(currentSetting); + requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); + } + + public CameraZoom getCameraZoom() { + return this.cameraZoom; + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java new file mode 100644 index 000000000000..eccfb07993c1 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/flash/FlashFeatureTest.java @@ -0,0 +1,156 @@ +// 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.flash; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.hardware.camera2.CaptureRequest; +import io.flutter.plugins.camera.CameraProperties; +import org.junit.Test; + +public class FlashFeatureTest { + @Test + public void getDebugName_should_return_the_name_of_the_feature() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + assertEquals("FlashFeature", flashFeature.getDebugName()); + } + + @Test + public void getValue_should_return_auto_if_not_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + assertEquals(FlashMode.auto, flashFeature.getValue()); + } + + @Test + public void getValue_should_echo_the_set_value() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + FlashMode expectedValue = FlashMode.torch; + + flashFeature.setValue(expectedValue); + FlashMode actualValue = flashFeature.getValue(); + + assertEquals(expectedValue, actualValue); + } + + @Test + public void checkIsSupported_should_return_false_when_flash_info_available_is_null() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(null); + + assertFalse(flashFeature.checkIsSupported()); + } + + @Test + public void checkIsSupported_should_return_false_when_flash_info_available_is_false() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(false); + + assertFalse(flashFeature.checkIsSupported()); + } + + @Test + public void checkIsSupported_should_return_true_when_flash_info_available_is_true() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(true); + + assertTrue(flashFeature.checkIsSupported()); + } + + @Test + public void updateBuilder_should_return_when_checkIsSupported_is_false() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(false); + + flashFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, never()).set(any(), any()); + } + + @Test + public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_off() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(true); + + flashFeature.setValue(FlashMode.off); + flashFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + verify(mockBuilder, times(1)).set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + } + + @Test + public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_always() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(true); + + flashFeature.setValue(FlashMode.always); + flashFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH); + verify(mockBuilder, times(1)).set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + } + + @Test + public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_torch() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(true); + + flashFeature.setValue(FlashMode.torch); + flashFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON); + verify(mockBuilder, times(1)).set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH); + } + + @Test + public void updateBuilder_should_set_ae_mode_and_flash_mode_when_flash_mode_is_auto() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + FlashFeature flashFeature = new FlashFeature(mockCameraProperties); + + when(mockCameraProperties.getFlashInfoAvailable()).thenReturn(true); + + flashFeature.setValue(FlashMode.auto); + flashFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)) + .set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + verify(mockBuilder, times(1)).set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java new file mode 100644 index 000000000000..22f5beea4fd2 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java @@ -0,0 +1,125 @@ +// 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.zoomlevel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.graphics.Rect; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class CameraZoomTest { + + @Test + public void ctor_when_parameters_are_valid() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = 4.0f; + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertTrue(cameraZoom.hasSupport); + assertEquals(4.0f, cameraZoom.maxZoom, 0); + assertEquals(1.0f, CameraZoom.DEFAULT_ZOOM_FACTOR, 0); + } + + @Test + public void ctor_when_sensor_size_is_null() { + final Rect sensorSize = null; + final Float maxZoom = 4.0f; + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_null() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = null; + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Float maxZoom = 0.5f; + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); + + assertNotNull(cameraZoom); + assertFalse(cameraZoom.hasSupport); + assertEquals(cameraZoom.maxZoom, 1.0f, 0); + } + + @Test + public void setZoom_when_no_support_should_not_set_scaler_crop_region() { + final CameraZoom cameraZoom = CameraZoom.create(null, null); + final Rect computedZoom = cameraZoom.computeZoom(2f); + + assertNull(computedZoom); + } + + @Test + public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 20f); + final Rect computedZoom = cameraZoom.computeZoom(18f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 0); + assertEquals(computedZoom.bottom, 0); + } + + @Test + public void setZoom_when_sensor_size_is_valid_should_return_crop_region() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 20f); + final Rect computedZoom = cameraZoom.computeZoom(18f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 48); + assertEquals(computedZoom.top, 48); + assertEquals(computedZoom.right, 52); + assertEquals(computedZoom.bottom, 52); + } + + @Test + public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 10f); + final Rect computedZoom = cameraZoom.computeZoom(25f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 45); + assertEquals(computedZoom.top, 45); + assertEquals(computedZoom.right, 55); + assertEquals(computedZoom.bottom, 55); + } + + @Test + public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 10f); + final Rect computedZoom = cameraZoom.computeZoom(0.5f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 100); + assertEquals(computedZoom.bottom, 100); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java new file mode 100644 index 000000000000..52602cbe1261 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java @@ -0,0 +1,101 @@ +// 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.zoomlevel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +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.CaptureRequest; +import io.flutter.plugins.camera.CameraProperties; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockedStatic; + +public class ZoomLevelFeatureTest { + private MockedStatic mockedStaticCameraZoom; + private CameraProperties mockCameraProperties; + private CameraZoom mockCameraZoom; + + @Before + public void before() { + mockedStaticCameraZoom = mockStatic(CameraZoom.class); + mockCameraProperties = mock(CameraProperties.class); + mockCameraZoom = mock(CameraZoom.class); + + mockedStaticCameraZoom.when(() -> CameraZoom.create(any(), any())).thenReturn(mockCameraZoom); + } + + @After + public void after() { + mockedStaticCameraZoom.close(); + } + + @Test + public void ctor_should_initiaze_camera_zoom_instance() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + verify(mockCameraProperties, times(1)).getSensorInfoActiveArraySize(); + verify(mockCameraProperties, times(1)).getScalerAvailableMaxDigitalZoom(); + assertEquals(mockCameraZoom, zoomLevelFeature.getCameraZoom()); + } + + @Test + public void getDebugName_should_return_the_name_of_the_feature() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + assertEquals("ZoomLevelFeature", zoomLevelFeature.getDebugName()); + } + + @Test + public void getValue_should_return_null_if_not_set() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + assertEquals(1.0, (float) zoomLevelFeature.getValue(), 0); + } + + @Test + public void getValue_should_echo_setValue() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + zoomLevelFeature.setValue(2.3f); + + assertEquals(2.3f, (float) zoomLevelFeature.getValue(), 0); + } + + @Test + public void checkIsSupport_returns_true() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + assertTrue(zoomLevelFeature.checkIsSupported()); + } + + @Test + public void updateBuilder_should_set_scalar_crop_region_when_checkIsSupport_is_true() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + Rect mockRect = mock(Rect.class); + + when(mockCameraZoom.computeZoom(1.0f)).thenReturn(mockRect); + + zoomLevelFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)).set(CaptureRequest.SCALER_CROP_REGION, mockRect); + } + + @Test + public void getCameraZoom_should_return_camera_zoom_instance_initialized_in_ctor() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + assertEquals(mockCameraZoom, zoomLevelFeature.getCameraZoom()); + } +} From 215fe533b95dc9274c7815414593dffec3f757a2 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 9 Apr 2021 13:41:26 +0200 Subject: [PATCH 05/10] Use mockito-inline --- packages/camera/camera/android/build.gradle | 2 +- .../main/java/io/flutter/plugins/camera/DartMessenger.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/android/build.gradle b/packages/camera/camera/android/build.gradle index 0b88fd10fb71..fa981d738015 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-core:3.5.13' + testImplementation 'org.mockito:mockito-inline:3.5.13' 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/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index aaac1361eb3d..d8ec25d6730d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -6,15 +6,18 @@ import android.os.Handler; import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FocusMode; -import java.util.HashMap; -import java.util.Map; class DartMessenger { @NonNull private final Handler handler; From 3402d9595390e3e43f03997a20bae7b24e67c318 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Fri, 9 Apr 2021 13:58:52 +0200 Subject: [PATCH 06/10] Fix formatting issue --- .../main/java/io/flutter/plugins/camera/DartMessenger.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java index d8ec25d6730d..aaac1361eb3d 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/DartMessenger.java @@ -6,18 +6,15 @@ import android.os.Handler; import android.text.TextUtils; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.Map; - import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.camera.types.ExposureMode; import io.flutter.plugins.camera.types.FocusMode; +import java.util.HashMap; +import java.util.Map; class DartMessenger { @NonNull private final Handler handler; From fab71a5936490020a1a6408b4605bdbdb7360937 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 19 May 2021 15:39:12 +0200 Subject: [PATCH 07/10] Processed feedback on pull request. --- .../camera/features/flash/FlashFeature.java | 8 ++ .../camera/features/zoomlevel/CameraZoom.java | 56 -------- .../features/zoomlevel/ZoomLevelFeature.java | 63 +++++++-- .../camera/features/zoomlevel/ZoomUtils.java | 40 ++++++ .../features/zoomlevel/CameraZoomTest.java | 125 ------------------ .../zoomlevel/ZoomLevelFeatureTest.java | 97 +++++++++++--- .../features/zoomlevel/ZoomUtilsTest.java | 64 +++++++++ 7 files changed, 242 insertions(+), 211 deletions(-) delete mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java delete mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java index 8703ff45c098..65f8bcfdd0b8 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java @@ -8,9 +8,17 @@ import io.flutter.plugins.camera.CameraProperties; import io.flutter.plugins.camera.features.CameraFeature; +/** + * Controls the flash configuration on the {@link android.hardware.camera2} API. + */ public class FlashFeature extends CameraFeature { private FlashMode currentSetting = FlashMode.auto; + /** + * Creates a new instance of the {@link FlashFeature}. + * + * @param cameraProperties Collection of characteristics for the current camera device. + */ public FlashFeature(CameraProperties cameraProperties) { super(cameraProperties); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java deleted file mode 100644 index b03b84f1534b..000000000000 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoom.java +++ /dev/null @@ -1,56 +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.features.zoomlevel; - -import android.graphics.Rect; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.math.MathUtils; - -public final class CameraZoom { - public static final float DEFAULT_ZOOM_FACTOR = 1.0f; - - @NonNull private final Rect cropRegion = new Rect(); - @Nullable private final Rect sensorSize; - - public final float maxZoom; - public final boolean hasSupport; - - public static CameraZoom create(@Nullable final Rect sensorArraySize, final Float maxZoom) { - return new CameraZoom(sensorArraySize, maxZoom); - } - - private CameraZoom(@Nullable final Rect sensorArraySize, final Float maxZoom) { - this.sensorSize = sensorArraySize; - - if (this.sensorSize == null) { - this.maxZoom = DEFAULT_ZOOM_FACTOR; - this.hasSupport = false; - return; - } - - this.maxZoom = - ((maxZoom == null) || (maxZoom < DEFAULT_ZOOM_FACTOR)) ? DEFAULT_ZOOM_FACTOR : maxZoom; - - this.hasSupport = (Float.compare(this.maxZoom, DEFAULT_ZOOM_FACTOR) > 0); - } - - public Rect computeZoom(final float zoom) { - if (sensorSize == null || !this.hasSupport) { - return null; - } - - final float newZoom = MathUtils.clamp(zoom, DEFAULT_ZOOM_FACTOR, this.maxZoom); - - final int centerX = this.sensorSize.width() / 2; - final int centerY = this.sensorSize.height() / 2; - final int deltaX = (int) ((0.5f * this.sensorSize.width()) / newZoom); - final int deltaY = (int) ((0.5f * this.sensorSize.height()) / newZoom); - - this.cropRegion.set(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY); - - return cropRegion; - } -} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java index ff6087d85e28..d373df2c63ba 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java @@ -9,17 +9,39 @@ import io.flutter.plugins.camera.CameraProperties; import io.flutter.plugins.camera.features.CameraFeature; -/** Exposure offset makes the image brighter or darker. */ +/** + * Controls the zoom configuration on the {@link android.hardware.camera2} API. + */ public class ZoomLevelFeature extends CameraFeature { - private final CameraZoom cameraZoom; - private Float currentSetting = CameraZoom.DEFAULT_ZOOM_FACTOR; + private static final float MINIMUM_ZOOM_LEVEL = 1.0f; + private final boolean hasSupport; + private final Rect sensorArraySize; + private Float currentSetting = MINIMUM_ZOOM_LEVEL; + private Float maximumZoomLevel = MINIMUM_ZOOM_LEVEL; + /** + * Creates a new instance of the {@link ZoomLevelFeature}. + * + * @param cameraProperties Collection of characteristics for the current camera device. + */ public ZoomLevelFeature(CameraProperties cameraProperties) { super(cameraProperties); - this.cameraZoom = - CameraZoom.create( - cameraProperties.getSensorInfoActiveArraySize(), - cameraProperties.getScalerAvailableMaxDigitalZoom()); + + sensorArraySize = cameraProperties.getSensorInfoActiveArraySize(); + + if (sensorArraySize == null) { + maximumZoomLevel = MINIMUM_ZOOM_LEVEL; + hasSupport = false; + return; + } + + Float maxDigitalZoom = cameraProperties.getScalerAvailableMaxDigitalZoom(); + maximumZoomLevel = + ((maxDigitalZoom == null) || (maxDigitalZoom < MINIMUM_ZOOM_LEVEL)) + ? MINIMUM_ZOOM_LEVEL + : maxDigitalZoom; + + hasSupport = (Float.compare(maximumZoomLevel, MINIMUM_ZOOM_LEVEL) > 0); } @Override @@ -34,13 +56,12 @@ public Float getValue() { @Override public void setValue(Float value) { - this.currentSetting = value; + currentSetting = value; } - // Available on all devices. @Override public boolean checkIsSupported() { - return true; + return hasSupport; } @Override @@ -49,11 +70,27 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) { return; } - final Rect computedZoom = cameraZoom.computeZoom(currentSetting); + final Rect computedZoom = + ZoomUtils.computeZoom( + currentSetting, sensorArraySize, MINIMUM_ZOOM_LEVEL, maximumZoomLevel); requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); } - public CameraZoom getCameraZoom() { - return this.cameraZoom; + /** + * Gets the maximum supported zoom level. + * + * @return The maximum zoom level. + */ + public float getMinimumZoomLevel() { + return MINIMUM_ZOOM_LEVEL; + } + + /** + * Gets the minimum supported zoom level. + * + * @return The minimum zoom level. + */ + public float getMaximumZoomLevel() { + return maximumZoomLevel; } } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java new file mode 100644 index 000000000000..a4890b952cff --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtils.java @@ -0,0 +1,40 @@ +// 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.zoomlevel; + +import android.graphics.Rect; +import androidx.annotation.NonNull; +import androidx.core.math.MathUtils; + +/** + * Utility class containing methods that assist with zoom features in the {@link + * android.hardware.camera2} API. + */ +final class ZoomUtils { + + /** + * Computes an image sensor area based on the supplied zoom settings. + * + *

The returned image sensor area can be applied to the {@link android.hardware.camera2} API in + * order to control zoom levels. + * + * @param zoom The desired zoom level. + * @param sensorArraySize The current area of the image sensor. + * @param minimumZoomLevel The minimum supported zoom level. + * @param maximumZoomLevel The maximim supported zoom level. + * @return An image sensor area based on the supplied zoom settings + */ + static Rect computeZoom( + float zoom, @NonNull Rect sensorArraySize, float minimumZoomLevel, float maximumZoomLevel) { + final float newZoom = MathUtils.clamp(zoom, minimumZoomLevel, maximumZoomLevel); + + final int centerX = sensorArraySize.width() / 2; + final int centerY = sensorArraySize.height() / 2; + final int deltaX = (int) ((0.5f * sensorArraySize.width()) / newZoom); + final int deltaY = (int) ((0.5f * sensorArraySize.height()) / newZoom); + + return new Rect(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY); + } +} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java deleted file mode 100644 index 22f5beea4fd2..000000000000 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/CameraZoomTest.java +++ /dev/null @@ -1,125 +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.features.zoomlevel; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import android.graphics.Rect; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class CameraZoomTest { - - @Test - public void ctor_when_parameters_are_valid() { - final Rect sensorSize = new Rect(0, 0, 0, 0); - final Float maxZoom = 4.0f; - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); - - assertNotNull(cameraZoom); - assertTrue(cameraZoom.hasSupport); - assertEquals(4.0f, cameraZoom.maxZoom, 0); - assertEquals(1.0f, CameraZoom.DEFAULT_ZOOM_FACTOR, 0); - } - - @Test - public void ctor_when_sensor_size_is_null() { - final Rect sensorSize = null; - final Float maxZoom = 4.0f; - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); - - assertNotNull(cameraZoom); - assertFalse(cameraZoom.hasSupport); - assertEquals(cameraZoom.maxZoom, 1.0f, 0); - } - - @Test - public void ctor_when_max_zoom_is_null() { - final Rect sensorSize = new Rect(0, 0, 0, 0); - final Float maxZoom = null; - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); - - assertNotNull(cameraZoom); - assertFalse(cameraZoom.hasSupport); - assertEquals(cameraZoom.maxZoom, 1.0f, 0); - } - - @Test - public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() { - final Rect sensorSize = new Rect(0, 0, 0, 0); - final Float maxZoom = 0.5f; - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, maxZoom); - - assertNotNull(cameraZoom); - assertFalse(cameraZoom.hasSupport); - assertEquals(cameraZoom.maxZoom, 1.0f, 0); - } - - @Test - public void setZoom_when_no_support_should_not_set_scaler_crop_region() { - final CameraZoom cameraZoom = CameraZoom.create(null, null); - final Rect computedZoom = cameraZoom.computeZoom(2f); - - assertNull(computedZoom); - } - - @Test - public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() { - final Rect sensorSize = new Rect(0, 0, 0, 0); - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 20f); - final Rect computedZoom = cameraZoom.computeZoom(18f); - - assertNotNull(computedZoom); - assertEquals(computedZoom.left, 0); - assertEquals(computedZoom.top, 0); - assertEquals(computedZoom.right, 0); - assertEquals(computedZoom.bottom, 0); - } - - @Test - public void setZoom_when_sensor_size_is_valid_should_return_crop_region() { - final Rect sensorSize = new Rect(0, 0, 100, 100); - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 20f); - final Rect computedZoom = cameraZoom.computeZoom(18f); - - assertNotNull(computedZoom); - assertEquals(computedZoom.left, 48); - assertEquals(computedZoom.top, 48); - assertEquals(computedZoom.right, 52); - assertEquals(computedZoom.bottom, 52); - } - - @Test - public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() { - final Rect sensorSize = new Rect(0, 0, 100, 100); - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 10f); - final Rect computedZoom = cameraZoom.computeZoom(25f); - - assertNotNull(computedZoom); - assertEquals(computedZoom.left, 45); - assertEquals(computedZoom.top, 45); - assertEquals(computedZoom.right, 55); - assertEquals(computedZoom.bottom, 55); - } - - @Test - public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() { - final Rect sensorSize = new Rect(0, 0, 100, 100); - final CameraZoom cameraZoom = CameraZoom.create(sensorSize, 10f); - final Rect computedZoom = cameraZoom.computeZoom(0.5f); - - assertNotNull(computedZoom); - assertEquals(computedZoom.left, 0); - assertEquals(computedZoom.top, 0); - assertEquals(computedZoom.right, 100); - assertEquals(computedZoom.bottom, 100); - } -} diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java index 52602cbe1261..361fb5587612 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java @@ -5,10 +5,13 @@ package io.flutter.plugins.camera.features.zoomlevel; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -22,17 +25,21 @@ import org.mockito.MockedStatic; public class ZoomLevelFeatureTest { - private MockedStatic mockedStaticCameraZoom; + private MockedStatic mockedStaticCameraZoom; private CameraProperties mockCameraProperties; - private CameraZoom mockCameraZoom; + private ZoomUtils mockCameraZoom; + private Rect mockZoomArea; + private Rect mockSensorArray; @Before public void before() { - mockedStaticCameraZoom = mockStatic(CameraZoom.class); + mockedStaticCameraZoom = mockStatic(ZoomUtils.class); mockCameraProperties = mock(CameraProperties.class); - mockCameraZoom = mock(CameraZoom.class); + mockCameraZoom = mock(ZoomUtils.class); + mockZoomArea = mock(Rect.class); + mockSensorArray = mock(Rect.class); - mockedStaticCameraZoom.when(() -> CameraZoom.create(any(), any())).thenReturn(mockCameraZoom); + mockedStaticCameraZoom.when(() -> ZoomUtils.computeZoom(anyFloat(), any(), anyFloat(), anyFloat())).thenReturn(mockZoomArea); } @After @@ -41,12 +48,58 @@ public void after() { } @Test - public void ctor_should_initiaze_camera_zoom_instance() { - ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + public void ctor_when_parameters_are_valid() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f); + + final ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + verify(mockCameraProperties, times(1)).getSensorInfoActiveArraySize(); + verify(mockCameraProperties, times(1)).getScalerAvailableMaxDigitalZoom(); + assertNotNull(zoomLevelFeature); + assertEquals(42f, zoomLevelFeature.getMaximumZoomLevel(), 0); + } + + @Test + public void ctor_when_sensor_size_is_null() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(null); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f); + + final ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + verify(mockCameraProperties, times(1)).getSensorInfoActiveArraySize(); + verify(mockCameraProperties, never()).getScalerAvailableMaxDigitalZoom(); + assertNotNull(zoomLevelFeature); + assertFalse(zoomLevelFeature.checkIsSupported()); + assertEquals(zoomLevelFeature.getMaximumZoomLevel(), 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_null() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(null); + + final ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); verify(mockCameraProperties, times(1)).getSensorInfoActiveArraySize(); verify(mockCameraProperties, times(1)).getScalerAvailableMaxDigitalZoom(); - assertEquals(mockCameraZoom, zoomLevelFeature.getCameraZoom()); + assertNotNull(zoomLevelFeature); + assertFalse(zoomLevelFeature.checkIsSupported()); + assertEquals(zoomLevelFeature.getMaximumZoomLevel(), 1.0f, 0); + } + + @Test + public void ctor_when_max_zoom_is_smaller_then_default_zoom_factor() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(0.5f); + + final ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + verify(mockCameraProperties, times(1)).getSensorInfoActiveArraySize(); + verify(mockCameraProperties, times(1)).getScalerAvailableMaxDigitalZoom(); + assertNotNull(zoomLevelFeature); + assertFalse(zoomLevelFeature.checkIsSupported()); + assertEquals(zoomLevelFeature.getMaximumZoomLevel(), 1.0f, 0); } @Test @@ -73,29 +126,39 @@ public void getValue_should_echo_setValue() { } @Test - public void checkIsSupport_returns_true() { + public void checkIsSupport_returns_false_by_default() { ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); - assertTrue(zoomLevelFeature.checkIsSupported()); + assertFalse(zoomLevelFeature.checkIsSupported()); } @Test public void updateBuilder_should_set_scalar_crop_region_when_checkIsSupport_is_true() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f); + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); - Rect mockRect = mock(Rect.class); - - when(mockCameraZoom.computeZoom(1.0f)).thenReturn(mockRect); zoomLevelFeature.updateBuilder(mockBuilder); - verify(mockBuilder, times(1)).set(CaptureRequest.SCALER_CROP_REGION, mockRect); + verify(mockBuilder, times(1)).set(CaptureRequest.SCALER_CROP_REGION, mockZoomArea); } @Test - public void getCameraZoom_should_return_camera_zoom_instance_initialized_in_ctor() { + public void getMinimumZoomLevel() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + assertEquals(1.0f, zoomLevelFeature.getMinimumZoomLevel(), 0); + } + + @Test + public void getMaximumZoomLevel() { + when(mockCameraProperties.getSensorInfoActiveArraySize()).thenReturn(mockSensorArray); + when(mockCameraProperties.getScalerAvailableMaxDigitalZoom()).thenReturn(42f); + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); - assertEquals(mockCameraZoom, zoomLevelFeature.getCameraZoom()); + assertEquals(42f, zoomLevelFeature.getMaximumZoomLevel(), 0); } } diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java new file mode 100644 index 000000000000..f83e5fb11e08 --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomUtilsTest.java @@ -0,0 +1,64 @@ +// 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.zoomlevel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.graphics.Rect; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class ZoomUtilsTest { + @Test + public void setZoom_when_sensor_size_equals_zero_should_return_crop_region_of_zero() { + final Rect sensorSize = new Rect(0, 0, 0, 0); + final Rect computedZoom = ZoomUtils.computeZoom(18f, sensorSize, 1f, 20f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 0); + assertEquals(computedZoom.bottom, 0); + } + + @Test + public void setZoom_when_sensor_size_is_valid_should_return_crop_region() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final Rect computedZoom = ZoomUtils.computeZoom(18f, sensorSize, 1f, 20f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 48); + assertEquals(computedZoom.top, 48); + assertEquals(computedZoom.right, 52); + assertEquals(computedZoom.bottom, 52); + } + + @Test + public void setZoom_when_zoom_is_greater_then_max_zoom_clamp_to_max_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final Rect computedZoom = ZoomUtils.computeZoom(25f, sensorSize, 1f, 10f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 45); + assertEquals(computedZoom.top, 45); + assertEquals(computedZoom.right, 55); + assertEquals(computedZoom.bottom, 55); + } + + @Test + public void setZoom_when_zoom_is_smaller_then_min_zoom_clamp_to_min_zoom() { + final Rect sensorSize = new Rect(0, 0, 100, 100); + final Rect computedZoom = ZoomUtils.computeZoom(0.5f, sensorSize, 1f, 10f); + + assertNotNull(computedZoom); + assertEquals(computedZoom.left, 0); + assertEquals(computedZoom.top, 0); + assertEquals(computedZoom.right, 100); + assertEquals(computedZoom.bottom, 100); + } +} From 788bbf9649e7d93c1ba9df0e7cf9a06e89fde5cb Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 19 May 2021 15:39:58 +0200 Subject: [PATCH 08/10] Fixed formatting --- .../plugins/camera/features/zoomlevel/ZoomLevelFeature.java | 4 +--- .../camera/features/zoomlevel/ZoomLevelFeatureTest.java | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java index d373df2c63ba..82e1eb8c7dc1 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java @@ -9,9 +9,7 @@ import io.flutter.plugins.camera.CameraProperties; import io.flutter.plugins.camera.features.CameraFeature; -/** - * Controls the zoom configuration on the {@link android.hardware.camera2} API. - */ +/** Controls the zoom configuration on the {@link android.hardware.camera2} API. */ public class ZoomLevelFeature extends CameraFeature { private static final float MINIMUM_ZOOM_LEVEL = 1.0f; private final boolean hasSupport; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java index 361fb5587612..c76708a3769e 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java @@ -39,7 +39,9 @@ public void before() { mockZoomArea = mock(Rect.class); mockSensorArray = mock(Rect.class); - mockedStaticCameraZoom.when(() -> ZoomUtils.computeZoom(anyFloat(), any(), anyFloat(), anyFloat())).thenReturn(mockZoomArea); + mockedStaticCameraZoom + .when(() -> ZoomUtils.computeZoom(anyFloat(), any(), anyFloat(), anyFloat())) + .thenReturn(mockZoomArea); } @After From a87045aad1293bc812200a4d3fd585838416ad41 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Wed, 19 May 2021 16:15:43 +0200 Subject: [PATCH 09/10] Fixed formatting --- .../flutter/plugins/camera/features/flash/FlashFeature.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java index 65f8bcfdd0b8..054c81f5183b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java @@ -8,9 +8,7 @@ import io.flutter.plugins.camera.CameraProperties; import io.flutter.plugins.camera.features.CameraFeature; -/** - * Controls the flash configuration on the {@link android.hardware.camera2} API. - */ +/** Controls the flash configuration on the {@link android.hardware.camera2} API. */ public class FlashFeature extends CameraFeature { private FlashMode currentSetting = FlashMode.auto; From 64e2e98fc8dd845a8c1ebfbc2a32c7216bcdc661 Mon Sep 17 00:00:00 2001 From: Maurits van Beusekom Date: Tue, 25 May 2021 20:16:05 +0200 Subject: [PATCH 10/10] Swap docs to match correct methods --- .../camera/features/zoomlevel/ZoomLevelFeature.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java index 82e1eb8c7dc1..736fad4d92dc 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java @@ -75,18 +75,18 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) { } /** - * Gets the maximum supported zoom level. + * Gets the minimum supported zoom level. * - * @return The maximum zoom level. + * @return The minimum zoom level. */ public float getMinimumZoomLevel() { return MINIMUM_ZOOM_LEVEL; } /** - * Gets the minimum supported zoom level. + * Gets the maximum supported zoom level. * - * @return The minimum zoom level. + * @return The maximum zoom level. */ public float getMaximumZoomLevel() { return maximumZoomLevel;