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