blob: 3a46379477e9aa7f3a599b6d2f09b94ab7bf9b05 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.legacy;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.utils.ListUtils;
import android.hardware.camera2.utils.ParamsUtils;
import android.location.Location;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static android.hardware.camera2.CaptureRequest.*;
/**
* Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
*/
@SuppressWarnings("deprecation")
public class LegacyRequestMapper {
private static final String TAG = "LegacyRequestMapper";
private static final boolean DEBUG = false;
/** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */
private static final byte DEFAULT_JPEG_QUALITY = 85;
/**
* Set the legacy parameters using the {@link LegacyRequest legacy request}.
*
* <p>The legacy request's parameters are changed as a side effect of calling this
* method.</p>
*
* @param legacyRequest a non-{@code null} legacy request
*/
public static void convertRequestMetadata(LegacyRequest legacyRequest) {
CameraCharacteristics characteristics = legacyRequest.characteristics;
CaptureRequest request = legacyRequest.captureRequest;
Size previewSize = legacyRequest.previewSize;
Camera.Parameters params = legacyRequest.parameters;
Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
/*
* scaler.cropRegion
*/
ParameterUtils.ZoomData zoomData;
{
zoomData = ParameterUtils.convertToLegacyZoom(activeArray,
request.get(SCALER_CROP_REGION),
request.get(CONTROL_ZOOM_RATIO),
previewSize,
params);
if (params.isZoomSupported()) {
params.setZoom(zoomData.zoomIndex);
} else if (DEBUG) {
Log.v(TAG, "convertRequestToMetadata - zoom is not supported");
}
}
/*
* colorCorrection.*
*/
// colorCorrection.aberrationMode
{
int aberrationMode = ParamsUtils.getOrDefault(request,
COLOR_CORRECTION_ABERRATION_MODE,
/*defaultValue*/COLOR_CORRECTION_ABERRATION_MODE_FAST);
if (aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_FAST &&
aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) {
Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
"colorCorrection.aberrationMode = " + aberrationMode);
}
}
/*
* control.ae*
*/
// control.aeAntibandingMode
{
String legacyMode;
Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE);
if (antiBandingMode != null) {
legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode);
} else {
legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(),
new String[] {
Parameters.ANTIBANDING_AUTO,
Parameters.ANTIBANDING_OFF,
Parameters.ANTIBANDING_50HZ,
Parameters.ANTIBANDING_60HZ,
});
}
if (legacyMode != null) {
params.setAntibanding(legacyMode);
}
}
/*
* control.aeRegions, afRegions
*/
{
// aeRegions
{
// Use aeRegions if available, fall back to using awbRegions if present
MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
if (request.get(CONTROL_AWB_REGIONS) != null) {
Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " +
"supported, ignoring value");
}
int maxNumMeteringAreas = params.getMaxNumMeteringAreas();
List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy(
activeArray, zoomData, aeRegions, maxNumMeteringAreas,
/*regionName*/"AE");
// WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
if (maxNumMeteringAreas > 0) {
params.setMeteringAreas(meteringAreaList);
}
}
// afRegions
{
MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
int maxNumFocusAreas = params.getMaxNumFocusAreas();
List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy(
activeArray, zoomData, afRegions, maxNumFocusAreas,
/*regionName*/"AF");
// WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
if (maxNumFocusAreas > 0) {
params.setFocusAreas(focusAreaList);
}
}
}
// control.aeTargetFpsRange
Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE);
if (aeFpsRange != null) {
int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
int[] rangeToApply = null;
for(int[] range : params.getSupportedPreviewFpsRange()) {
// Round range up/down to integer FPS value
int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000;
int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000;
if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) {
rangeToApply = range;
break;
}
}
if (rangeToApply != null) {
params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
} else {
Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
}
}
/*
* control
*/
// control.aeExposureCompensation
{
Range<Integer> compensationRange =
characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
int compensation = ParamsUtils.getOrDefault(request,
CONTROL_AE_EXPOSURE_COMPENSATION,
/*defaultValue*/0);
if (!compensationRange.contains(compensation)) {
Log.w(TAG,
"convertRequestMetadata - control.aeExposureCompensation " +
"is out of range, ignoring value");
compensation = 0;
}
params.setExposureCompensation(compensation);
}
// control.aeLock
{
Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false,
params.isAutoExposureLockSupported(),
/*allowedValue*/false);
if (aeLock != null) {
params.setAutoExposureLock(aeLock);
}
if (DEBUG) {
Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock);
}
// TODO: Don't add control.aeLock to availableRequestKeys if it's not supported
}
// control.aeMode, flash.mode
mapAeAndFlashMode(request, /*out*/params);
// control.afMode
{
int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
/*defaultValue*/CONTROL_AF_MODE_OFF);
String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
params.getSupportedFocusModes());
if (focusMode != null) {
params.setFocusMode(focusMode);
}
if (DEBUG) {
Log.v(TAG, "convertRequestToMetadata - control.afMode "
+ afMode + " mapped to " + focusMode);
}
}
// control.awbMode
{
Integer awbMode = getIfSupported(request, CONTROL_AWB_MODE,
/*defaultValue*/CONTROL_AWB_MODE_AUTO,
params.getSupportedWhiteBalance() != null,
/*allowedValue*/CONTROL_AWB_MODE_AUTO);
String whiteBalanceMode = null;
if (awbMode != null) { // null iff AWB is not supported by camera1 api
whiteBalanceMode = convertAwbModeToLegacy(awbMode);
params.setWhiteBalance(whiteBalanceMode);
}
if (DEBUG) {
Log.v(TAG, "convertRequestToMetadata - control.awbMode "
+ awbMode + " mapped to " + whiteBalanceMode);
}
}
// control.awbLock
{
Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
params.isAutoWhiteBalanceLockSupported(),
/*allowedValue*/false);
if (awbLock != null) {
params.setAutoWhiteBalanceLock(awbLock);
}
// TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
}
// control.captureIntent
{
int captureIntent = ParamsUtils.getOrDefault(request,
CONTROL_CAPTURE_INTENT,
/*defaultValue*/CONTROL_CAPTURE_INTENT_PREVIEW);
captureIntent = filterSupportedCaptureIntent(captureIntent);
params.setRecordingHint(
captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_RECORD ||
captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
}
// control.videoStabilizationMode
{
Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
/*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
params.isVideoStabilizationSupported(),
/*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
if (stabMode != null) {
params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
}
}
// lens.focusDistance
{
boolean infinityFocusSupported =
ListUtils.listContains(params.getSupportedFocusModes(),
Parameters.FOCUS_MODE_INFINITY);
Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
/*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
if (focusDistance == null || focusDistance != 0f) {
Log.w(TAG,
"convertRequestToMetadata - Ignoring android.lens.focusDistance "
+ infinityFocusSupported + ", only 0.0f is supported");
}
}
// control.sceneMode, control.mode
{
// TODO: Map FACE_PRIORITY scene mode to face detection.
if (params.getSupportedSceneModes() != null) {
int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE,
/*defaultValue*/CONTROL_MODE_AUTO);
String modeToSet;
switch (controlMode) {
case CONTROL_MODE_USE_SCENE_MODE: {
int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE,
/*defaultValue*/CONTROL_SCENE_MODE_DISABLED);
String legacySceneMode = LegacyMetadataMapper.
convertSceneModeToLegacy(sceneMode);
if (legacySceneMode != null) {
modeToSet = legacySceneMode;
} else {
modeToSet = Parameters.SCENE_MODE_AUTO;
Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode);
}
break;
}
case CONTROL_MODE_AUTO: {
modeToSet = Parameters.SCENE_MODE_AUTO;
break;
}
default: {
Log.w(TAG, "Control mode " + controlMode +
" is unsupported, defaulting to AUTO");
modeToSet = Parameters.SCENE_MODE_AUTO;
}
}
params.setSceneMode(modeToSet);
}
}
// control.effectMode
{
if (params.getSupportedColorEffects() != null) {
int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE,
/*defaultValue*/CONTROL_EFFECT_MODE_OFF);
String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode);
if (legacyEffectMode != null) {
params.setColorEffect(legacyEffectMode);
} else {
params.setColorEffect(Parameters.EFFECT_NONE);
Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode);
}
}
}
/*
* sensor
*/
// sensor.testPattern
{
int testPatternMode = ParamsUtils.getOrDefault(request, SENSOR_TEST_PATTERN_MODE,
/*defaultValue*/SENSOR_TEST_PATTERN_MODE_OFF);
if (testPatternMode != SENSOR_TEST_PATTERN_MODE_OFF) {
Log.w(TAG, "convertRequestToMetadata - ignoring sensor.testPatternMode "
+ testPatternMode + "; only OFF is supported");
}
}
/*
* jpeg.*
*/
// jpeg.gpsLocation
{
Location location = request.get(JPEG_GPS_LOCATION);
if (location != null) {
if (checkForCompleteGpsData(location)) {
params.setGpsAltitude(location.getAltitude());
params.setGpsLatitude(location.getLatitude());
params.setGpsLongitude(location.getLongitude());
params.setGpsProcessingMethod(location.getProvider().toUpperCase());
params.setGpsTimestamp(location.getTime());
} else {
Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
}
} else {
params.removeGpsData();
}
}
// jpeg.orientation
{
Integer orientation = request.get(CaptureRequest.JPEG_ORIENTATION);
params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION,
(orientation == null) ? 0 : orientation));
}
// jpeg.quality
{
params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
DEFAULT_JPEG_QUALITY));
}
// jpeg.thumbnailQuality
{
params.setJpegThumbnailQuality(0xFF & ParamsUtils.getOrDefault(request,
JPEG_THUMBNAIL_QUALITY, DEFAULT_JPEG_QUALITY));
}
// jpeg.thumbnailSize
{
List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
if (sizes != null && sizes.size() > 0) {
Size s = request.get(JPEG_THUMBNAIL_SIZE);
boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
s.getWidth(), s.getHeight());
if (invalidSize) {
Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
}
if (s == null || invalidSize) {
// (0,0) = "no thumbnail" in Camera API 1
params.setJpegThumbnailSize(/*width*/0, /*height*/0);
} else {
params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
}
}
}
/*
* noiseReduction.*
*/
// noiseReduction.mode
{
int mode = ParamsUtils.getOrDefault(request,
NOISE_REDUCTION_MODE,
/*defaultValue*/NOISE_REDUCTION_MODE_FAST);
if (mode != NOISE_REDUCTION_MODE_FAST &&
mode != NOISE_REDUCTION_MODE_HIGH_QUALITY) {
Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
"noiseReduction.mode = " + mode);
}
}
}
private static boolean checkForCompleteGpsData(Location location) {
return location != null && location.getProvider() != null && location.getTime() != 0;
}
static int filterSupportedCaptureIntent(int captureIntent) {
switch (captureIntent) {
case CONTROL_CAPTURE_INTENT_CUSTOM:
case CONTROL_CAPTURE_INTENT_PREVIEW:
case CONTROL_CAPTURE_INTENT_STILL_CAPTURE:
case CONTROL_CAPTURE_INTENT_VIDEO_RECORD:
case CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT:
break;
case CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG:
case CONTROL_CAPTURE_INTENT_MANUAL:
captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
Log.w(TAG, "Unsupported control.captureIntent value " + captureIntent
+ "; default to PREVIEW");
default:
captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
Log.w(TAG, "Unknown control.captureIntent value " + captureIntent
+ "; default to PREVIEW");
}
return captureIntent;
}
private static List<Camera.Area> convertMeteringRegionsToLegacy(
Rect activeArray, ParameterUtils.ZoomData zoomData,
MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) {
if (meteringRegions == null || maxNumMeteringAreas <= 0) {
if (maxNumMeteringAreas > 0) {
return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
} else {
return null;
}
}
// Add all non-zero weight regions to the list
List<MeteringRectangle> meteringRectangleList = new ArrayList<>();
for (MeteringRectangle rect : meteringRegions) {
if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) {
meteringRectangleList.add(rect);
}
}
if (meteringRectangleList.size() == 0) {
Log.w(TAG, "Only received metering rectangles with weight 0.");
return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
}
// Ignore any regions beyond our maximum supported count
int countMeteringAreas =
Math.min(maxNumMeteringAreas, meteringRectangleList.size());
List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas);
for (int i = 0; i < countMeteringAreas; ++i) {
MeteringRectangle rect = meteringRectangleList.get(i);
ParameterUtils.MeteringData meteringData =
ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData);
meteringAreaList.add(meteringData.meteringArea);
}
if (maxNumMeteringAreas < meteringRectangleList.size()) {
Log.w(TAG,
"convertMeteringRegionsToLegacy - Too many requested " + regionName +
" regions, ignoring all beyond the first " + maxNumMeteringAreas);
}
if (DEBUG) {
Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = "
+ ParameterUtils.stringFromAreaList(meteringAreaList));
}
return meteringAreaList;
}
private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
List<String> supportedFlashModes = p.getSupportedFlashModes();
String flashModeSetting = null;
// Flash is OFF by default, on cameras that support flash
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) {
flashModeSetting = Parameters.FLASH_MODE_OFF;
}
/*
* Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it
*/
// Ignore flash.mode controls unless aeMode == ON
if (aeMode == CONTROL_AE_MODE_ON) {
if (flashMode == FLASH_MODE_TORCH) {
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) {
flashModeSetting = Parameters.FLASH_MODE_TORCH;
} else {
Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" +
"camera does not support it");
}
} else if (flashMode == FLASH_MODE_SINGLE) {
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
flashModeSetting = Parameters.FLASH_MODE_ON;
} else {
Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" +
"camera does not support it");
}
} else {
// Use the default FLASH_MODE_OFF
}
} else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) {
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
flashModeSetting = Parameters.FLASH_MODE_ON;
} else {
Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" +
"camera does not support it");
}
} else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) {
flashModeSetting = Parameters.FLASH_MODE_AUTO;
} else {
Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" +
"camera does not support it");
}
} else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) {
flashModeSetting = Parameters.FLASH_MODE_RED_EYE;
} else {
Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;"
+ "camera does not support it");
}
} else {
// Default to aeMode == ON, flash = OFF
}
if (flashModeSetting != null) {
p.setFlashMode(flashModeSetting);
}
if (DEBUG) {
Log.v(TAG,
"mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting
+ ", requested (api2) " + flashMode
+ ", supported (api1) " + ListUtils.listToString(supportedFlashModes));
}
}
/**
* Returns null if the anti-banding mode enum is not supported.
*/
private static String convertAeAntiBandingModeToLegacy(int mode) {
switch (mode) {
case CONTROL_AE_ANTIBANDING_MODE_OFF: {
return Parameters.ANTIBANDING_OFF;
}
case CONTROL_AE_ANTIBANDING_MODE_50HZ: {
return Parameters.ANTIBANDING_50HZ;
}
case CONTROL_AE_ANTIBANDING_MODE_60HZ: {
return Parameters.ANTIBANDING_60HZ;
}
case CONTROL_AE_ANTIBANDING_MODE_AUTO: {
return Parameters.ANTIBANDING_AUTO;
}
default: {
return null;
}
}
}
private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
int[] legacyFps = new int[2];
legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000;
legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000;
return legacyFps;
}
private static String convertAwbModeToLegacy(int mode) {
switch (mode) {
case CONTROL_AWB_MODE_AUTO:
return Camera.Parameters.WHITE_BALANCE_AUTO;
case CONTROL_AWB_MODE_INCANDESCENT:
return Camera.Parameters.WHITE_BALANCE_INCANDESCENT;
case CONTROL_AWB_MODE_FLUORESCENT:
return Camera.Parameters.WHITE_BALANCE_FLUORESCENT;
case CONTROL_AWB_MODE_WARM_FLUORESCENT:
return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT;
case CONTROL_AWB_MODE_DAYLIGHT:
return Camera.Parameters.WHITE_BALANCE_DAYLIGHT;
case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
case CONTROL_AWB_MODE_TWILIGHT:
return Camera.Parameters.WHITE_BALANCE_TWILIGHT;
case CONTROL_AWB_MODE_SHADE:
return Parameters.WHITE_BALANCE_SHADE;
default:
Log.w(TAG, "convertAwbModeToLegacy - unrecognized control.awbMode" + mode);
return Camera.Parameters.WHITE_BALANCE_AUTO;
}
}
/**
* Return {@code null} if the value is not supported, otherwise return the retrieved key's
* value from the request (or the default value if it wasn't set).
*
* <p>If the fetched value in the request is equivalent to {@code allowedValue},
* then omit the warning (e.g. turning off AF lock on a camera
* that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p>
*
* <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p.
*/
private static <T> T getIfSupported(
CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
T allowedValue) {
T val = ParamsUtils.getOrDefault(r, key, defaultValue);
if (!isSupported) {
if (!Objects.equals(val, allowedValue)) {
Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val);
}
return null;
}
return val;
}
}