Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[camera] android-rework part 7: Android noise reduction feature #4052

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ public enum FlashMode {
this.strValue = strValue;
}

/**
* Tries to convert the supplied string into a {@see FlashMode} enum value.
*
* <p>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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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.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<NoiseReductionMode> {
private NoiseReductionMode currentSetting = NoiseReductionMode.fast;

private static final HashMap<NoiseReductionMode, Integer> 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);
}
}

/**
* Creates a new instance of the {@link NoiseReductionFeature}.
*
* @param cameraProperties Collection of the characteristics for the current camera device.
*/
public NoiseReductionFeature(CameraProperties cameraProperties) {
BeMacized marked this conversation as resolved.
Show resolved Hide resolved
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;
*
* <p>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));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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.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;
}

/**
* Tries to convert the supplied string into a {@see NoiseReductionMode} enum value.
*
* <p>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) {
BeMacized marked this conversation as resolved.
Show resolved Hide resolved
for (NoiseReductionMode value : values()) {
if (value.strValue.equals(modeStr)) return value;
}
return null;
}

@Override
public String toString() {
return strValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// 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.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);
}
}