LegacyRequestMapper.java revision 08c7116ab9cd04ad6dd3c04aa1017237e7f409ac
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.camera2.legacy;
18
19import android.graphics.Rect;
20import android.hardware.Camera;
21import android.hardware.Camera.Parameters;
22import android.hardware.camera2.CameraCharacteristics;
23import android.hardware.camera2.CaptureRequest;
24import android.hardware.camera2.params.MeteringRectangle;
25import android.hardware.camera2.utils.ListUtils;
26import android.hardware.camera2.utils.ParamsUtils;
27import android.location.Location;
28import android.util.Log;
29import android.util.Range;
30import android.util.Size;
31
32import java.util.ArrayList;
33import java.util.Arrays;
34import java.util.List;
35import java.util.Objects;
36
37import static android.hardware.camera2.CaptureRequest.*;
38
39/**
40 * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
41 */
42@SuppressWarnings("deprecation")
43public class LegacyRequestMapper {
44    private static final String TAG = "LegacyRequestMapper";
45    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
46
47    /** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */
48    private static final byte DEFAULT_JPEG_QUALITY = 85;
49
50    /**
51     * Set the legacy parameters using the {@link LegacyRequest legacy request}.
52     *
53     * <p>The legacy request's parameters are changed as a side effect of calling this
54     * method.</p>
55     *
56     * @param legacyRequest a non-{@code null} legacy request
57     */
58    public static void convertRequestMetadata(LegacyRequest legacyRequest) {
59        CameraCharacteristics characteristics = legacyRequest.characteristics;
60        CaptureRequest request = legacyRequest.captureRequest;
61        Size previewSize = legacyRequest.previewSize;
62        Camera.Parameters params = legacyRequest.parameters;
63
64        Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
65
66        /*
67         * scaler.cropRegion
68         */
69        ParameterUtils.ZoomData zoomData;
70        {
71            zoomData = ParameterUtils.convertScalerCropRegion(activeArray,
72                    request.get(SCALER_CROP_REGION),
73                    previewSize,
74                    params);
75
76            if (params.isZoomSupported()) {
77                params.setZoom(zoomData.zoomIndex);
78            } else if (VERBOSE) {
79                Log.v(TAG, "convertRequestToMetadata - zoom is not supported");
80            }
81        }
82
83        /*
84         * colorCorrection.*
85         */
86        // colorCorrection.aberrationMode
87        {
88            int aberrationMode = ParamsUtils.getOrDefault(request,
89                    COLOR_CORRECTION_ABERRATION_MODE,
90                    /*defaultValue*/COLOR_CORRECTION_ABERRATION_MODE_FAST);
91
92            if (aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_FAST) {
93                Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
94                        "colorCorrection.aberrationMode = " + aberrationMode);
95            }
96        }
97
98        /*
99         * control.ae*
100         */
101        // control.aeAntibandingMode
102        {
103        String legacyMode;
104            Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE);
105            if (antiBandingMode != null) {
106                legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode);
107            } else {
108                legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(),
109                        new String[] {
110                            Parameters.ANTIBANDING_AUTO,
111                            Parameters.ANTIBANDING_OFF,
112                            Parameters.ANTIBANDING_50HZ,
113                            Parameters.ANTIBANDING_60HZ,
114                        });
115            }
116
117            if (legacyMode != null) {
118                params.setAntibanding(legacyMode);
119            }
120        }
121
122        /*
123         * control.aeRegions, afRegions
124         */
125        {
126            // aeRegions
127            {
128                // Use aeRegions if available, fall back to using awbRegions if present
129                MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
130                if (request.get(CONTROL_AWB_REGIONS) != null) {
131                    Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " +
132                            "supported, ignoring value");
133                }
134                int maxNumMeteringAreas = params.getMaxNumMeteringAreas();
135                List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy(
136                        activeArray, zoomData, aeRegions, maxNumMeteringAreas,
137                        /*regionName*/"AE");
138
139                // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
140                if (maxNumMeteringAreas > 0) {
141                    params.setMeteringAreas(meteringAreaList);
142                }
143            }
144
145            // afRegions
146            {
147                MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
148                int maxNumFocusAreas = params.getMaxNumFocusAreas();
149                List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy(
150                        activeArray, zoomData, afRegions, maxNumFocusAreas,
151                        /*regionName*/"AF");
152
153                // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
154                if (maxNumFocusAreas > 0) {
155                    params.setFocusAreas(focusAreaList);
156                }
157            }
158        }
159
160        // control.aeTargetFpsRange
161        Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE);
162        if (aeFpsRange != null) {
163            int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
164
165            // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range?
166            boolean supported = false;
167            for(int[] range : params.getSupportedPreviewFpsRange()) {
168                if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) {
169                    supported = true;
170                    break;
171                }
172            }
173            if (supported) {
174                params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
175                        legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
176            } else {
177                Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
178            }
179        }
180
181        /*
182         * control
183         */
184
185        // control.aeExposureCompensation
186        {
187            Range<Integer> compensationRange =
188                    characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
189            int compensation = ParamsUtils.getOrDefault(request,
190                    CONTROL_AE_EXPOSURE_COMPENSATION,
191                    /*defaultValue*/0);
192
193            if (!compensationRange.contains(compensation)) {
194                Log.w(TAG,
195                        "convertRequestMetadata - control.aeExposureCompensation " +
196                        "is out of range, ignoring value");
197                compensation = 0;
198            }
199
200            params.setExposureCompensation(compensation);
201        }
202
203        // control.aeLock
204        {
205            Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false,
206                    params.isAutoExposureLockSupported(),
207                    /*allowedValue*/false);
208
209            if (aeLock != null) {
210                params.setAutoExposureLock(aeLock);
211            }
212
213            if (VERBOSE) {
214                Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock);
215            }
216
217            // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported
218        }
219
220        // control.aeMode, flash.mode
221        mapAeAndFlashMode(request, /*out*/params);
222
223        // control.afMode
224        {
225            int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
226                    /*defaultValue*/CONTROL_AF_MODE_OFF);
227            String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
228                    params.getSupportedFocusModes());
229
230            if (focusMode != null) {
231                params.setFocusMode(focusMode);
232            }
233
234            if (VERBOSE) {
235                Log.v(TAG, "convertRequestToMetadata - control.afMode "
236                        + afMode + " mapped to " + focusMode);
237            }
238        }
239
240        // control.awbMode
241        {
242            Integer awbMode = getIfSupported(request, CONTROL_AWB_MODE,
243                    /*defaultValue*/CONTROL_AWB_MODE_AUTO,
244                    params.getSupportedWhiteBalance() != null,
245                    /*allowedValue*/CONTROL_AWB_MODE_AUTO);
246
247            String whiteBalanceMode = null;
248            if (awbMode != null) { // null iff AWB is not supported by camera1 api
249                whiteBalanceMode = convertAwbModeToLegacy(awbMode);
250                params.setWhiteBalance(whiteBalanceMode);
251            }
252
253            if (VERBOSE) {
254                Log.v(TAG, "convertRequestToMetadata - control.awbMode "
255                        + awbMode + " mapped to " + whiteBalanceMode);
256            }
257        }
258
259        // control.awbLock
260        {
261            Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
262                    params.isAutoWhiteBalanceLockSupported(),
263                    /*allowedValue*/false);
264
265            if (awbLock != null) {
266                params.setAutoWhiteBalanceLock(awbLock);
267            }
268
269         // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
270        }
271
272        // control.captureIntent
273        {
274            int captureIntent = ParamsUtils.getOrDefault(request,
275                    CONTROL_CAPTURE_INTENT,
276                    /*defaultValue*/CONTROL_CAPTURE_INTENT_PREVIEW);
277
278            captureIntent = filterSupportedCaptureIntent(captureIntent);
279
280            params.setRecordingHint(
281                    captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_RECORD ||
282                    captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
283        }
284
285        // control.videoStabilizationMode
286        {
287            Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
288                    /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
289                    params.isVideoStabilizationSupported(),
290                    /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
291
292            if (stabMode != null) {
293                params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
294            }
295        }
296
297        // lens.focusDistance
298        {
299            boolean infinityFocusSupported =
300                    ListUtils.listContains(params.getSupportedFocusModes(),
301                            Parameters.FOCUS_MODE_INFINITY);
302            Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
303                    /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
304
305            if (focusDistance == null || focusDistance != 0f) {
306                Log.w(TAG,
307                        "convertRequestToMetadata - Ignoring android.lens.focusDistance "
308                                + infinityFocusSupported + ", only 0.0f is supported");
309            }
310        }
311
312        // control.sceneMode, control.mode
313        {
314            // TODO: Map FACE_PRIORITY scene mode to face detection.
315
316            if (params.getSupportedSceneModes() != null) {
317                int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE,
318                    /*defaultValue*/CONTROL_MODE_AUTO);
319                String modeToSet;
320                switch (controlMode) {
321                    case CONTROL_MODE_USE_SCENE_MODE: {
322                        int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE,
323                                /*defaultValue*/CONTROL_SCENE_MODE_DISABLED);
324                        String legacySceneMode = LegacyMetadataMapper.
325                                convertSceneModeToLegacy(sceneMode);
326                        if (legacySceneMode != null) {
327                            modeToSet = legacySceneMode;
328                        } else {
329                            modeToSet = Parameters.SCENE_MODE_AUTO;
330                            Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode);
331                        }
332                        break;
333                    }
334                    case CONTROL_MODE_AUTO: {
335                        modeToSet = Parameters.SCENE_MODE_AUTO;
336                        break;
337                    }
338                    default: {
339                        Log.w(TAG, "Control mode " + controlMode +
340                                " is unsupported, defaulting to AUTO");
341                        modeToSet = Parameters.SCENE_MODE_AUTO;
342                    }
343                }
344                params.setSceneMode(modeToSet);
345            }
346        }
347
348        // control.effectMode
349        {
350            if (params.getSupportedColorEffects() != null) {
351                int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE,
352                    /*defaultValue*/CONTROL_EFFECT_MODE_OFF);
353                String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode);
354                if (legacyEffectMode != null) {
355                    params.setColorEffect(legacyEffectMode);
356                } else {
357                    params.setColorEffect(Parameters.EFFECT_NONE);
358                    Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode);
359                }
360            }
361        }
362
363        /*
364         * sensor
365         */
366
367        // sensor.testPattern
368        {
369            int testPatternMode = ParamsUtils.getOrDefault(request, SENSOR_TEST_PATTERN_MODE,
370                    /*defaultValue*/SENSOR_TEST_PATTERN_MODE_OFF);
371            if (testPatternMode != SENSOR_TEST_PATTERN_MODE_OFF) {
372                Log.w(TAG, "convertRequestToMetadata - ignoring sensor.testPatternMode "
373                        + testPatternMode + "; only OFF is supported");
374            }
375        }
376
377        /*
378         * jpeg.*
379         */
380
381        // jpeg.gpsLocation
382        {
383            Location location = request.get(JPEG_GPS_LOCATION);
384            if (location != null) {
385                if (checkForCompleteGpsData(location)) {
386                    params.setGpsAltitude(location.getAltitude());
387                    params.setGpsLatitude(location.getLatitude());
388                    params.setGpsLongitude(location.getLongitude());
389                    params.setGpsProcessingMethod(location.getProvider().toUpperCase());
390                    params.setGpsTimestamp(location.getTime());
391                } else {
392                    Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
393                }
394            } else {
395                params.removeGpsData();
396            }
397        }
398
399        // jpeg.orientation
400        {
401            Integer orientation = request.get(CaptureRequest.JPEG_ORIENTATION);
402            params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION,
403                    (orientation == null) ? 0 : orientation));
404        }
405
406        // jpeg.quality
407        {
408            params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
409                    DEFAULT_JPEG_QUALITY));
410        }
411
412        // jpeg.thumbnailQuality
413        {
414            params.setJpegThumbnailQuality(0xFF & ParamsUtils.getOrDefault(request,
415                    JPEG_THUMBNAIL_QUALITY, DEFAULT_JPEG_QUALITY));
416        }
417
418        // jpeg.thumbnailSize
419        {
420            List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
421
422            if (sizes != null && sizes.size() > 0) {
423                Size s = request.get(JPEG_THUMBNAIL_SIZE);
424                boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
425                        s.getWidth(), s.getHeight());
426                if (invalidSize) {
427                    Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
428                }
429                if (s == null || invalidSize) {
430                    // (0,0) = "no thumbnail" in Camera API 1
431                    params.setJpegThumbnailSize(/*width*/0, /*height*/0);
432                } else {
433                    params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
434                }
435            }
436        }
437
438        /*
439         * noiseReduction.*
440         */
441        // noiseReduction.mode
442        {
443            int mode = ParamsUtils.getOrDefault(request,
444                    NOISE_REDUCTION_MODE,
445                    /*defaultValue*/NOISE_REDUCTION_MODE_FAST);
446
447            if (mode != NOISE_REDUCTION_MODE_FAST) {
448                Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
449                        "noiseReduction.mode = " + mode);
450            }
451        }
452    }
453
454    private static boolean checkForCompleteGpsData(Location location) {
455        return location != null && location.getProvider() != null && location.getTime() != 0;
456    }
457
458    static int filterSupportedCaptureIntent(int captureIntent) {
459        switch (captureIntent) {
460            case CONTROL_CAPTURE_INTENT_CUSTOM:
461            case CONTROL_CAPTURE_INTENT_PREVIEW:
462            case CONTROL_CAPTURE_INTENT_STILL_CAPTURE:
463            case CONTROL_CAPTURE_INTENT_VIDEO_RECORD:
464            case CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT:
465                break;
466            case CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG:
467            case CONTROL_CAPTURE_INTENT_MANUAL:
468                captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
469                Log.w(TAG, "Unsupported control.captureIntent value " + captureIntent
470                        + "; default to PREVIEW");
471            default:
472                captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
473                Log.w(TAG, "Unknown control.captureIntent value " + captureIntent
474                        + "; default to PREVIEW");
475        }
476
477        return captureIntent;
478    }
479
480    private static List<Camera.Area> convertMeteringRegionsToLegacy(
481            Rect activeArray, ParameterUtils.ZoomData zoomData,
482            MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) {
483        if (meteringRegions == null || maxNumMeteringAreas <= 0) {
484            if (maxNumMeteringAreas > 0) {
485                return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
486            } else {
487                return null;
488            }
489        }
490
491        // Add all non-zero weight regions to the list
492        List<MeteringRectangle> meteringRectangleList = new ArrayList<>();
493        for (MeteringRectangle rect : meteringRegions) {
494            if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) {
495                meteringRectangleList.add(rect);
496            }
497        }
498
499        if (meteringRectangleList.size() == 0) {
500            Log.w(TAG, "Only received metering rectangles with weight 0.");
501            return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
502        }
503
504        // Ignore any regions beyond our maximum supported count
505        int countMeteringAreas =
506                Math.min(maxNumMeteringAreas, meteringRectangleList.size());
507        List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas);
508
509        for (int i = 0; i < countMeteringAreas; ++i) {
510            MeteringRectangle rect = meteringRectangleList.get(i);
511
512            ParameterUtils.MeteringData meteringData =
513                    ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData);
514            meteringAreaList.add(meteringData.meteringArea);
515        }
516
517        if (maxNumMeteringAreas < meteringRectangleList.size()) {
518            Log.w(TAG,
519                    "convertMeteringRegionsToLegacy - Too many requested " + regionName +
520                            " regions, ignoring all beyond the first " + maxNumMeteringAreas);
521        }
522
523        if (VERBOSE) {
524            Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = "
525                    + ParameterUtils.stringFromAreaList(meteringAreaList));
526        }
527
528        return meteringAreaList;
529    }
530
531    private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
532        int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
533        int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
534
535        List<String> supportedFlashModes = p.getSupportedFlashModes();
536
537        String flashModeSetting = null;
538
539        // Flash is OFF by default, on cameras that support flash
540        if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) {
541            flashModeSetting = Parameters.FLASH_MODE_OFF;
542        }
543
544        /*
545         * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it
546         */
547
548        // Ignore flash.mode controls unless aeMode == ON
549        if (aeMode == CONTROL_AE_MODE_ON) {
550            if (flashMode == FLASH_MODE_TORCH) {
551                    if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) {
552                        flashModeSetting = Parameters.FLASH_MODE_TORCH;
553                    } else {
554                        Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" +
555                                "camera does not support it");
556                    }
557            } else if (flashMode == FLASH_MODE_SINGLE) {
558                if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
559                    flashModeSetting = Parameters.FLASH_MODE_ON;
560                } else {
561                    Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" +
562                            "camera does not support it");
563                }
564            } else {
565                // Use the default FLASH_MODE_OFF
566            }
567        } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) {
568                if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
569                    flashModeSetting = Parameters.FLASH_MODE_ON;
570                } else {
571                    Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" +
572                            "camera does not support it");
573                }
574        } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {
575            if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) {
576                flashModeSetting = Parameters.FLASH_MODE_AUTO;
577            } else {
578                Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" +
579                        "camera does not support it");
580            }
581        } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
582                if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) {
583                    flashModeSetting = Parameters.FLASH_MODE_RED_EYE;
584                } else {
585                    Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;"
586                            + "camera does not support it");
587                }
588        } else {
589            // Default to aeMode == ON, flash = OFF
590        }
591
592        if (flashModeSetting != null) {
593            p.setFlashMode(flashModeSetting);
594        }
595
596        if (VERBOSE) {
597                Log.v(TAG,
598                        "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting
599                        + ", requested (api2) " + flashMode
600                        + ", supported (api1) " + ListUtils.listToString(supportedFlashModes));
601        }
602    }
603
604    /**
605     * Returns null if the anti-banding mode enum is not supported.
606     */
607    private static String convertAeAntiBandingModeToLegacy(int mode) {
608        switch (mode) {
609            case CONTROL_AE_ANTIBANDING_MODE_OFF: {
610                return Parameters.ANTIBANDING_OFF;
611            }
612            case CONTROL_AE_ANTIBANDING_MODE_50HZ: {
613                return Parameters.ANTIBANDING_50HZ;
614            }
615            case CONTROL_AE_ANTIBANDING_MODE_60HZ: {
616                return Parameters.ANTIBANDING_60HZ;
617            }
618            case CONTROL_AE_ANTIBANDING_MODE_AUTO: {
619                return Parameters.ANTIBANDING_AUTO;
620            }
621            default: {
622                return null;
623            }
624        }
625    }
626
627    private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
628        int[] legacyFps = new int[2];
629        legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
630        legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
631        return legacyFps;
632    }
633
634    private static String convertAwbModeToLegacy(int mode) {
635        switch (mode) {
636            case CONTROL_AWB_MODE_AUTO:
637                return Camera.Parameters.WHITE_BALANCE_AUTO;
638            case CONTROL_AWB_MODE_INCANDESCENT:
639                return Camera.Parameters.WHITE_BALANCE_INCANDESCENT;
640            case CONTROL_AWB_MODE_FLUORESCENT:
641                return Camera.Parameters.WHITE_BALANCE_FLUORESCENT;
642            case CONTROL_AWB_MODE_WARM_FLUORESCENT:
643                return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT;
644            case CONTROL_AWB_MODE_DAYLIGHT:
645                return Camera.Parameters.WHITE_BALANCE_DAYLIGHT;
646            case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
647                return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
648            case CONTROL_AWB_MODE_TWILIGHT:
649                return Camera.Parameters.WHITE_BALANCE_TWILIGHT;
650            case CONTROL_AWB_MODE_SHADE:
651                return Parameters.WHITE_BALANCE_SHADE;
652            default:
653                Log.w(TAG, "convertAwbModeToLegacy - unrecognized control.awbMode" + mode);
654                return Camera.Parameters.WHITE_BALANCE_AUTO;
655        }
656    }
657
658
659    /**
660     * Return {@code null} if the value is not supported, otherwise return the retrieved key's
661     * value from the request (or the default value if it wasn't set).
662     *
663     * <p>If the fetched value in the request is equivalent to {@code allowedValue},
664     * then omit the warning (e.g. turning off AF lock on a camera
665     * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p>
666     *
667     * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p.
668     */
669    private static <T> T getIfSupported(
670            CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
671            T allowedValue) {
672        T val = ParamsUtils.getOrDefault(r, key, defaultValue);
673
674        if (!isSupported) {
675            if (!Objects.equals(val, allowedValue)) {
676                Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val);
677            }
678            return null;
679        }
680
681        return val;
682    }
683}
684