From 94fed0898430c439a6a45bbb22078b14c97023ce Mon Sep 17 00:00:00 2001 From: BeMacized Date: Mon, 14 Jun 2021 08:43:16 +0200 Subject: [PATCH 1/2] Added noise reduction feature --- .../noisereduction/NoiseReductionFeature.java | 89 +++++++++++ .../noisereduction/NoiseReductionMode.java | 32 ++++ .../NoiseReductionFeatureTest.java | 151 ++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java create mode 100644 packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java create mode 100644 packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java new file mode 100644 index 000000000000..b24fda4bdd8d --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java @@ -0,0 +1,89 @@ +// Copyright 2019 The Chromium 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.noisereduction; + +import android.hardware.camera2.CaptureRequest; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; +import android.util.Log; +import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.features.CameraFeature; +import java.util.HashMap; + +/** + * This can either be enabled or disabled. Only full capability devices can set this to off. Legacy + * and full support the fast mode. + * https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES + */ +public class NoiseReductionFeature extends CameraFeature { + private NoiseReductionMode currentSetting = NoiseReductionMode.fast; + + private static final HashMap NOISE_REDUCTION_MODES = new HashMap<>(); + + static { + NOISE_REDUCTION_MODES.put(NoiseReductionMode.off, CaptureRequest.NOISE_REDUCTION_MODE_OFF); + NOISE_REDUCTION_MODES.put(NoiseReductionMode.fast, CaptureRequest.NOISE_REDUCTION_MODE_FAST); + NOISE_REDUCTION_MODES.put( + NoiseReductionMode.highQuality, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); + if (VERSION.SDK_INT >= VERSION_CODES.M) { + NOISE_REDUCTION_MODES.put( + NoiseReductionMode.minimal, CaptureRequest.NOISE_REDUCTION_MODE_MINIMAL); + NOISE_REDUCTION_MODES.put( + NoiseReductionMode.zeroShutterLag, CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); + } + } + + public NoiseReductionFeature(CameraProperties cameraProperties) { + super(cameraProperties); + } + + @Override + public String getDebugName() { + return "NoiseReductionFeature"; + } + + @Override + public NoiseReductionMode getValue() { + return currentSetting; + } + + @Override + public void setValue(NoiseReductionMode value) { + this.currentSetting = value; + } + + @Override + public boolean checkIsSupported() { + /* + * Available settings: public static final int NOISE_REDUCTION_MODE_FAST = 1; public static + * final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2; public static final int + * NOISE_REDUCTION_MODE_MINIMAL = 3; public static final int NOISE_REDUCTION_MODE_OFF = 0; + * public static final int NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4; + * + *

Full-capability camera devices will always support OFF and FAST. Camera devices that + * support YUV_REPROCESSING or PRIVATE_REPROCESSING will support ZERO_SHUTTER_LAG. + * Legacy-capability camera devices will only support FAST mode. + */ + + // Can be null on some devices. + int[] modes = cameraProperties.getAvailableNoiseReductionModes(); + + /// If there's at least one mode available then we are supported. + return modes != null && modes.length > 0; + } + + @Override + public void updateBuilder(CaptureRequest.Builder requestBuilder) { + if (!checkIsSupported()) { + return; + } + + Log.i("Camera", "updateNoiseReduction | currentSetting: " + currentSetting); + + // Always use fast mode. + requestBuilder.set( + CaptureRequest.NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODES.get(currentSetting)); + } +} diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java new file mode 100644 index 000000000000..5219fd4c046e --- /dev/null +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java @@ -0,0 +1,32 @@ +// Copyright 2019 The Chromium 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.noisereduction; + +/** Only supports fast mode for now. */ +public enum NoiseReductionMode { + off("off"), + fast("fast"), + highQuality("highQuality"), + minimal("minimal"), + zeroShutterLag("zeroShutterLag"); + + private final String strValue; + + NoiseReductionMode(String strValue) { + this.strValue = strValue; + } + + public static NoiseReductionMode getValueForString(String modeStr) { + for (NoiseReductionMode 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/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java new file mode 100644 index 000000000000..4905c68bce8a --- /dev/null +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java @@ -0,0 +1,151 @@ +// Copyright 2019 The Chromium 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.noisereduction; + +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 android.os.Build.VERSION; +import io.flutter.plugins.camera.CameraProperties; +import io.flutter.plugins.camera.utils.TestUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class NoiseReductionFeatureTest { + @Before + public void before() { + // Make sure the VERSION.SDK_INT field returns 23, to allow using all available + // noise reduction modes in tests. + TestUtils.setFinalStatic(VERSION.class, "SDK_INT", 23); + } + + @After + public void after() { + // Make sure we reset the VERSION.SDK_INT field to it's original value. + TestUtils.setFinalStatic(VERSION.class, "SDK_INT", 0); + } + + @Test + public void getDebugName_should_return_the_name_of_the_feature() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + assertEquals("NoiseReductionFeature", noiseReductionFeature.getDebugName()); + } + + @Test + public void getValue_should_return_fast_if_not_set() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + assertEquals(NoiseReductionMode.fast, noiseReductionFeature.getValue()); + } + + @Test + public void getValue_should_echo_the_set_value() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + NoiseReductionMode expectedValue = NoiseReductionMode.fast; + + noiseReductionFeature.setValue(expectedValue); + NoiseReductionMode actualValue = noiseReductionFeature.getValue(); + + assertEquals(expectedValue, actualValue); + } + + @Test + public void checkIsSupported_should_return_false_when_available_noise_reduction_modes_is_null() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + when(mockCameraProperties.getAvailableNoiseReductionModes()).thenReturn(null); + + assertFalse(noiseReductionFeature.checkIsSupported()); + } + + @Test + public void + checkIsSupported_should_return_false_when_available_noise_reduction_modes_returns_an_empty_array() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + when(mockCameraProperties.getAvailableNoiseReductionModes()).thenReturn(new int[] {}); + + assertFalse(noiseReductionFeature.checkIsSupported()); + } + + @Test + public void + checkIsSupported_should_return_true_when_available_noise_reduction_modes_returns_at_least_one_item() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + when(mockCameraProperties.getAvailableNoiseReductionModes()).thenReturn(new int[] {1}); + + assertTrue(noiseReductionFeature.checkIsSupported()); + } + + @Test + public void updateBuilder_should_return_when_checkIsSupported_is_false() { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + when(mockCameraProperties.getAvailableNoiseReductionModes()).thenReturn(new int[] {}); + + noiseReductionFeature.updateBuilder(mockBuilder); + + verify(mockBuilder, never()).set(any(), any()); + } + + @Test + public void updateBuilder_should_set_noise_reduction_mode_off_when_off() { + testUpdateBuilderWith(NoiseReductionMode.off, CaptureRequest.NOISE_REDUCTION_MODE_OFF); + } + + @Test + public void updateBuilder_should_set_noise_reduction_mode_fast_when_fast() { + testUpdateBuilderWith(NoiseReductionMode.fast, CaptureRequest.NOISE_REDUCTION_MODE_FAST); + } + + @Test + public void updateBuilder_should_set_noise_reduction_mode_high_quality_when_high_quality() { + testUpdateBuilderWith( + NoiseReductionMode.highQuality, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); + } + + @Test + public void updateBuilder_should_set_noise_reduction_mode_minimal_when_minimal() { + testUpdateBuilderWith(NoiseReductionMode.minimal, CaptureRequest.NOISE_REDUCTION_MODE_MINIMAL); + } + + @Test + public void + updateBuilder_should_set_noise_reduction_mode_zero_shutter_lag_when_zero_shutter_lag() { + testUpdateBuilderWith( + NoiseReductionMode.zeroShutterLag, CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); + } + + private static void testUpdateBuilderWith(NoiseReductionMode mode, int expectedResult) { + CameraProperties mockCameraProperties = mock(CameraProperties.class); + CaptureRequest.Builder mockBuilder = mock(CaptureRequest.Builder.class); + NoiseReductionFeature noiseReductionFeature = new NoiseReductionFeature(mockCameraProperties); + + when(mockCameraProperties.getAvailableNoiseReductionModes()).thenReturn(new int[] {1}); + + noiseReductionFeature.setValue(mode); + noiseReductionFeature.updateBuilder(mockBuilder); + verify(mockBuilder, times(1)).set(CaptureRequest.NOISE_REDUCTION_MODE, expectedResult); + } +} From 3a68294765e326a85af3930694e26eebd986fd95 Mon Sep 17 00:00:00 2001 From: BeMacized Date: Tue, 15 Jun 2021 14:06:11 +0200 Subject: [PATCH 2/2] Implemented PR feedback --- .../plugins/camera/features/flash/FlashMode.java | 9 +++++++++ .../noisereduction/NoiseReductionFeature.java | 7 ++++++- .../features/noisereduction/NoiseReductionMode.java | 11 ++++++++++- .../noisereduction/NoiseReductionFeatureTest.java | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) 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 index d4a5ee0ab12f..788c768e0b3c 100644 --- 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 @@ -17,6 +17,15 @@ public enum FlashMode { this.strValue = strValue; } + /** + * Tries to convert the supplied string into a {@see FlashMode} enum value. + * + *

When the supplied string doesn't match a valid {@see FlashMode} enum value, null is + * returned. + * + * @param modeStr String value to convert into an {@see FlashMode} enum value. + * @return Matching {@see FlashMode} enum value, or null if no match is found. + */ public static FlashMode getValueForString(String modeStr) { for (FlashMode value : values()) { if (value.strValue.equals(modeStr)) return value; diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java index b24fda4bdd8d..847a817641ab 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeature.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. @@ -35,6 +35,11 @@ public class NoiseReductionFeature extends CameraFeature { } } + /** + * Creates a new instance of the {@link NoiseReductionFeature}. + * + * @param cameraProperties Collection of the characteristics for the current camera device. + */ public NoiseReductionFeature(CameraProperties cameraProperties) { super(cameraProperties); } diff --git a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java index 5219fd4c046e..425a458e2a2b 100644 --- a/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java +++ b/packages/camera/camera/android/src/main/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionMode.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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. @@ -18,6 +18,15 @@ public enum NoiseReductionMode { this.strValue = strValue; } + /** + * Tries to convert the supplied string into a {@see NoiseReductionMode} enum value. + * + *

When the supplied string doesn't match a valid {@see NoiseReductionMode} enum value, null is + * returned. + * + * @param modeStr String value to convert into an {@see NoiseReductionMode} enum value. + * @return Matching {@see NoiseReductionMode} enum value, or null if no match is found. + */ public static NoiseReductionMode getValueForString(String modeStr) { for (NoiseReductionMode value : values()) { if (value.strValue.equals(modeStr)) return value; diff --git a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java index 4905c68bce8a..eb1a639a2ac3 100644 --- a/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java +++ b/packages/camera/camera/android/src/test/java/io/flutter/plugins/camera/features/noisereduction/NoiseReductionFeatureTest.java @@ -1,4 +1,4 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. +// 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.