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