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 
17 package android.hardware.camera2.legacy;
18 
19 import android.graphics.Rect;
20 import android.hardware.Camera;
21 import android.hardware.Camera.Parameters;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CaptureRequest;
24 import android.hardware.camera2.params.MeteringRectangle;
25 import android.hardware.camera2.utils.ListUtils;
26 import android.hardware.camera2.utils.ParamsUtils;
27 import android.location.Location;
28 import android.util.Log;
29 import android.util.Range;
30 import android.util.Size;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 import java.util.Objects;
36 
37 import static android.hardware.camera2.CaptureRequest.*;
38 
39 /**
40  * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
41  */
42 @SuppressWarnings("deprecation")
43 public 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      */
convertRequestMetadata(LegacyRequest legacyRequest)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 
checkForCompleteGpsData(Location location)458     private static boolean checkForCompleteGpsData(Location location) {
459         return location != null && location.getProvider() != null && location.getTime() != 0;
460     }
461 
filterSupportedCaptureIntent(int captureIntent)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 
convertMeteringRegionsToLegacy( Rect activeArray, ParameterUtils.ZoomData zoomData, MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName)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 
mapAeAndFlashMode(CaptureRequest r, Parameters p)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      */
convertAeAntiBandingModeToLegacy(int mode)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 
convertAeFpsRangeToLegacy(Range<Integer> fpsRange)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 
convertAwbModeToLegacy(int mode)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      */
getIfSupported( CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported, T allowedValue)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