FileDocCategorySizeDatePackage
LegacyRequestMapper.javaAPI DocAndroid 5.1 API27632Thu Mar 12 22:22:10 GMT 2015android.hardware.camera2.legacy

LegacyRequestMapper

public class LegacyRequestMapper extends Object
Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.

Fields Summary
private static final String
TAG
private static final boolean
VERBOSE
private static final byte
DEFAULT_JPEG_QUALITY
Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality
Constructors Summary
Methods Summary
private static booleancheckForCompleteGpsData(android.location.Location location)

        return location != null && location.getProvider() != null && location.getTime() != 0;
    
private static java.lang.StringconvertAeAntiBandingModeToLegacy(int mode)
Returns null if the anti-banding mode enum is not supported.

        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(android.util.Range fpsRange)

        int[] legacyFps = new int[2];
        legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
        legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
        return legacyFps;
    
private static java.lang.StringconvertAwbModeToLegacy(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;
        }
    
private static java.util.ListconvertMeteringRegionsToLegacy(android.graphics.Rect activeArray, ParameterUtils.ZoomData zoomData, android.hardware.camera2.params.MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, java.lang.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 (VERBOSE) {
            Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = "
                    + ParameterUtils.stringFromAreaList(meteringAreaList));
        }

        return meteringAreaList;
    
public static voidconvertRequestMetadata(LegacyRequest legacyRequest)
Set the legacy parameters using the {@link LegacyRequest legacy request}.

The legacy request's parameters are changed as a side effect of calling this method.

param
legacyRequest a non-{@code null} legacy request


                                        
         
        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.convertScalerCropRegion(activeArray,
                    request.get(SCALER_CROP_REGION),
                    previewSize,
                    params);

            if (params.isZoomSupported()) {
                params.setZoom(zoomData.zoomIndex);
            } else if (VERBOSE) {
                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) {
                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);

            // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range?
            boolean supported = false;
            for(int[] range : params.getSupportedPreviewFpsRange()) {
                if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) {
                    supported = true;
                    break;
                }
            }
            if (supported) {
                params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
                        legacyFps[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 (VERBOSE) {
                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 (VERBOSE) {
                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 (VERBOSE) {
                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) {
                Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
                        "noiseReduction.mode = " + mode);
            }
        }
    
static intfilterSupportedCaptureIntent(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 TgetIfSupported(android.hardware.camera2.CaptureRequest r, CaptureRequest.Key key, T defaultValue, boolean isSupported, T allowedValue)
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).

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}.

Logs a warning to logcat if the key is not supported by api1 camera device.

        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;
    
private static voidmapAeAndFlashMode(android.hardware.camera2.CaptureRequest r, android.hardware.Camera.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 (VERBOSE) {
                Log.v(TAG,
                        "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting
                        + ", requested (api2) " + flashMode
                        + ", supported (api1) " + ListUtils.listToString(supportedFlashModes));
        }