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/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..054c81f5183b --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/flash/FlashFeature.java @@ -0,0 +1,75 @@ +// 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; + +/** 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); + } + + @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/ZoomLevelFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java new file mode 100644 index 000000000000..736fad4d92dc --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeature.java @@ -0,0 +1,94 @@ +// 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; + +/** 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; + 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); + + 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 + public String getDebugName() { + return "ZoomLevelFeature"; + } + + @Override + public Float getValue() { + return currentSetting; + } + + @Override + public void setValue(Float value) { + currentSetting = value; + } + + @Override + public boolean checkIsSupported() { + return hasSupport; + } + + @Override + public void updateBuilder(CaptureRequest.Builder requestBuilder) { + if (!checkIsSupported()) { + return; + } + + final Rect computedZoom = + ZoomUtils.computeZoom( + currentSetting, sensorArraySize, MINIMUM_ZOOM_LEVEL, maximumZoomLevel); + requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, computedZoom); + } + + /** + * Gets the minimum supported zoom level. + * + * @return The minimum zoom level. + */ + public float getMinimumZoomLevel() { + return MINIMUM_ZOOM_LEVEL; + } + + /** + * Gets the maximum supported zoom level. + * + * @return The maximum 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/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/ZoomLevelFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java new file mode 100644 index 000000000000..c76708a3769e --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/zoomlevel/ZoomLevelFeatureTest.java @@ -0,0 +1,166 @@ +// 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.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; + +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 ZoomUtils mockCameraZoom; + private Rect mockZoomArea; + private Rect mockSensorArray; + + @Before + public void before() { + mockedStaticCameraZoom = mockStatic(ZoomUtils.class); + mockCameraProperties = mock(CameraProperties.class); + mockCameraZoom = mock(ZoomUtils.class); + mockZoomArea = mock(Rect.class); + mockSensorArray = mock(Rect.class); + + mockedStaticCameraZoom + .when(() -> ZoomUtils.computeZoom(anyFloat(), any(), anyFloat(), anyFloat())) + .thenReturn(mockZoomArea); + } + + @After + public void after() { + mockedStaticCameraZoom.close(); + } + + @Test + 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(); + 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 + 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_false_by_default() { + ZoomLevelFeature zoomLevelFeature = new ZoomLevelFeature(mockCameraProperties); + + 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); + + zoomLevelFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, times(1)).set(CaptureRequest.SCALER_CROP_REGION, mockZoomArea); + } + + @Test + 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(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); + } +}