LegacyMetadataMapper.java revision 733341bf0db89c93ee1341ddfca9b0c49731c836
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.ImageFormat;
20import android.graphics.Rect;
21import android.hardware.Camera;
22import android.hardware.Camera.CameraInfo;
23import android.hardware.Camera.Parameters;
24import android.hardware.camera2.CameraCharacteristics;
25import android.hardware.camera2.CameraDevice;
26import android.hardware.camera2.CameraMetadata;
27import android.hardware.camera2.CaptureRequest;
28import android.hardware.camera2.CaptureResult;
29import android.hardware.camera2.impl.CameraMetadataNative;
30import android.hardware.camera2.params.MeteringRectangle;
31import android.hardware.camera2.params.StreamConfiguration;
32import android.hardware.camera2.params.StreamConfigurationDuration;
33import android.hardware.camera2.utils.ArrayUtils;
34import android.hardware.camera2.utils.ListUtils;
35import android.hardware.camera2.utils.ParamsUtils;
36import android.util.Log;
37import android.util.Range;
38import android.util.Size;
39
40import java.util.ArrayList;
41import java.util.Arrays;
42import java.util.List;
43
44import static com.android.internal.util.Preconditions.*;
45import static android.hardware.camera2.CameraCharacteristics.*;
46import static android.hardware.camera2.legacy.ParameterUtils.*;
47
48/**
49 * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
50 * camera characteristics.
51 */
52@SuppressWarnings("deprecation")
53public class LegacyMetadataMapper {
54    private static final String TAG = "LegacyMetadataMapper";
55    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
56
57    private static final long NS_PER_MS = 1000000;
58
59    // from graphics.h
60    private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
61    private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
62
63    // for metadata
64    private static final float LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS = 0.0f;
65
66    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW = 0; // no raw support
67    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC = 3; // preview, video, cb
68    private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL = 1; // 1 jpeg only
69    private static final int REQUEST_MAX_NUM_INPUT_STREAMS_COUNT = 0; // no reprocessing
70
71    /** Assume 3 HAL1 stages: Exposure, Read-out, Post-Processing */
72    private static final int REQUEST_PIPELINE_MAX_DEPTH_HAL1 = 3;
73    /** Assume 3 shim stages: Preview input, Split output, Format conversion for output */
74    private static final int REQUEST_PIPELINE_MAX_DEPTH_OURS = 3;
75    /* TODO: Update above maxDepth values once we do more performance measurements */
76
77    // For approximating JPEG stall durations
78    private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // 200 milliseconds
79    private static final long APPROXIMATE_SENSOR_AREA_PX = (1 << 23); // 8 megapixels
80    private static final long APPROXIMATE_JPEG_ENCODE_TIME_MS = 600; // 600 milliseconds
81
82    static final int UNKNOWN_MODE = -1;
83
84    /*
85     * Development hijinks: Lie about not supporting certain capabilities
86     *
87     * - Unblock some CTS tests from running whose main intent is not the metadata itself
88     *
89     * TODO: Remove these constants and strip out any code that previously relied on them
90     * being set to true.
91     */
92    static final boolean LIE_ABOUT_AE_STATE = false;
93    static final boolean LIE_ABOUT_AE_MAX_REGIONS = false;
94    static final boolean LIE_ABOUT_AF = false;
95    static final boolean LIE_ABOUT_AF_MAX_REGIONS = false;
96    static final boolean LIE_ABOUT_AWB_STATE = false;
97    static final boolean LIE_ABOUT_AWB = false;
98
99    /**
100     * Create characteristics for a legacy device by mapping the {@code parameters}
101     * and {@code info}
102     *
103     * @param parameters A non-{@code null} parameters set
104     * @param info Camera info with camera facing direction and angle of orientation
105     *
106     * @return static camera characteristics for a camera device
107     *
108     * @throws NullPointerException if any of the args were {@code null}
109     */
110    public static CameraCharacteristics createCharacteristics(Camera.Parameters parameters,
111            CameraInfo info) {
112        checkNotNull(parameters, "parameters must not be null");
113        checkNotNull(info, "info must not be null");
114
115        String paramStr = parameters.flatten();
116        android.hardware.CameraInfo outerInfo = new android.hardware.CameraInfo();
117        outerInfo.info = info;
118
119        return createCharacteristics(paramStr, outerInfo);
120    }
121
122    /**
123     * Create characteristics for a legacy device by mapping the {@code parameters}
124     * and {@code info}
125     *
126     * @param parameters A string parseable by {@link Camera.Parameters#unflatten}
127     * @param info Camera info with camera facing direction and angle of orientation
128     * @return static camera characteristics for a camera device
129     *
130     * @throws NullPointerException if any of the args were {@code null}
131     */
132    public static CameraCharacteristics createCharacteristics(String parameters,
133            android.hardware.CameraInfo info) {
134        checkNotNull(parameters, "parameters must not be null");
135        checkNotNull(info, "info must not be null");
136        checkNotNull(info.info, "info.info must not be null");
137
138        CameraMetadataNative m = new CameraMetadataNative();
139
140        mapCharacteristicsFromInfo(m, info.info);
141
142        Camera.Parameters params = Camera.getEmptyParameters();
143        params.unflatten(parameters);
144        mapCharacteristicsFromParameters(m, params);
145
146        if (VERBOSE) {
147            Log.v(TAG, "createCharacteristics metadata:");
148            Log.v(TAG, "--------------------------------------------------- (start)");
149            m.dumpToLog();
150            Log.v(TAG, "--------------------------------------------------- (end)");
151        }
152
153        return new CameraCharacteristics(m);
154    }
155
156    private static void mapCharacteristicsFromInfo(CameraMetadataNative m, CameraInfo i) {
157        m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ?
158                LENS_FACING_BACK : LENS_FACING_FRONT);
159        m.set(SENSOR_ORIENTATION, i.orientation);
160    }
161
162    private static void mapCharacteristicsFromParameters(CameraMetadataNative m,
163            Camera.Parameters p) {
164        /*
165         * control.ae*
166         */
167        mapControlAe(m, p);
168        /*
169         * control.af*
170         */
171        mapControlAf(m, p);
172        /*
173         * control.awb*
174         */
175        mapControlAwb(m, p);
176        /*
177         * control.*
178         * - Anything that doesn't have a set of related fields
179         */
180        mapControlOther(m, p);
181        /*
182         * lens.*
183         */
184        mapLens(m, p);
185        /*
186         * flash.*
187         */
188        mapFlash(m, p);
189
190        /*
191         * request.*
192         */
193        mapRequest(m, p);
194        // TODO: map other fields
195
196        /*
197         * scaler.*
198         */
199        mapScaler(m, p);
200
201        /*
202         * sensor.*
203         */
204        mapSensor(m, p);
205
206        /*
207         * sync.*
208         */
209        mapSync(m, p);
210
211        /*
212         * info.supportedHardwareLevel
213         */
214        m.set(INFO_SUPPORTED_HARDWARE_LEVEL, INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
215
216        /*
217         * scaler.availableStream*, scaler.available*Durations, sensor.info.maxFrameDuration
218         */
219        mapScalerStreamConfigs(m, p);
220
221    }
222
223    private static void mapScalerStreamConfigs(CameraMetadataNative m, Camera.Parameters p) {
224
225        ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>();
226        /*
227         * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes
228         * YUV_420_888 cpu callbacks -> use camera1 preview sizes
229         * Other preview callbacks (CPU) -> use camera1 preview sizes
230         * JPEG still capture -> use camera1 still capture sizes
231         *
232         * Use platform-internal format constants here, since StreamConfigurationMap does the
233         * remapping to public format constants.
234         */
235        List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
236        appendStreamConfig(availableStreamConfigs,
237                HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes);
238        appendStreamConfig(availableStreamConfigs,
239                ImageFormat.YUV_420_888, previewSizes);
240        for (int format : p.getSupportedPreviewFormats()) {
241            if (ImageFormat.isPublicFormat(format)) {
242                appendStreamConfig(availableStreamConfigs, format, previewSizes);
243            } else {
244                /*
245                 *  Do not add any formats unknown to us
246                 * (since it would fail runtime checks in StreamConfigurationMap)
247                 */
248                Log.w(TAG,
249                        String.format("mapStreamConfigs - Skipping non-public format %x", format));
250            }
251        }
252
253        List<Camera.Size> jpegSizes = p.getSupportedPictureSizes();
254        appendStreamConfig(availableStreamConfigs,
255                HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes());
256        /*
257         * scaler.availableStreamConfigurations
258         */
259        m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
260                availableStreamConfigs.toArray(new StreamConfiguration[0]));
261
262        /*
263         * scaler.availableMinFrameDurations
264         */
265        // No frame durations available
266        m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[0]);
267
268        StreamConfigurationDuration[] jpegStalls =
269                new StreamConfigurationDuration[jpegSizes.size()];
270        int i = 0;
271        long longestStallDuration = -1;
272        for (Camera.Size s : jpegSizes) {
273            long stallDuration =  calculateJpegStallDuration(s);
274            jpegStalls[i++] = new StreamConfigurationDuration(HAL_PIXEL_FORMAT_BLOB, s.width,
275                    s.height, stallDuration);
276            if (longestStallDuration < stallDuration) {
277                longestStallDuration = stallDuration;
278            }
279        }
280        /*
281         * scaler.availableStallDurations
282         */
283        // Set stall durations for jpeg, other formats use default stall duration
284        m.set(SCALER_AVAILABLE_STALL_DURATIONS, jpegStalls);
285
286        /*
287         * sensor.info.maxFrameDuration
288         */
289        m.set(SENSOR_INFO_MAX_FRAME_DURATION, longestStallDuration);
290    }
291
292    @SuppressWarnings({"unchecked"})
293    private static void mapControlAe(CameraMetadataNative m, Camera.Parameters p) {
294        /*
295         * control.aeAvailableAntiBandingModes
296         */
297        List<String> antiBandingModes = p.getSupportedAntibanding();
298        if (antiBandingModes != null && antiBandingModes.size() > 0) { // antibanding is optional
299            int[] modes = new int[antiBandingModes.size()];
300            int j = 0;
301            for (String mode : antiBandingModes) {
302                int convertedMode = convertAntiBandingMode(mode);
303                if (convertedMode == -1) {
304                    Log.w(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
305                            " not supported, skipping...");
306                } else {
307                    modes[j++] = convertedMode;
308                }
309            }
310            m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, Arrays.copyOf(modes, j));
311        } else {
312            m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, new int[0]);
313        }
314
315        /*
316         * control.aeAvailableTargetFpsRanges
317         */
318        {
319            List<int[]> fpsRanges = p.getSupportedPreviewFpsRange();
320            if (fpsRanges == null) {
321                throw new AssertionError("Supported FPS ranges cannot be null.");
322            }
323            int rangesSize = fpsRanges.size();
324            if (rangesSize <= 0) {
325                throw new AssertionError("At least one FPS range must be supported.");
326            }
327            Range<Integer>[] ranges = new Range[rangesSize];
328            int i = 0;
329            for (int[] r : fpsRanges) {
330                ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
331                        r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
332            }
333            m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges);
334        }
335
336        /*
337         * control.aeAvailableModes
338         */
339        {
340            List<String> flashModes = p.getSupportedFlashModes();
341
342            String[] flashModeStrings = new String[] {
343                    Camera.Parameters.FLASH_MODE_OFF,
344                    Camera.Parameters.FLASH_MODE_AUTO,
345                    Camera.Parameters.FLASH_MODE_ON,
346                    Camera.Parameters.FLASH_MODE_RED_EYE,
347                    // Map these manually
348                    Camera.Parameters.FLASH_MODE_TORCH,
349            };
350            int[] flashModeInts = new int[] {
351                    CONTROL_AE_MODE_ON,
352                    CONTROL_AE_MODE_ON_AUTO_FLASH,
353                    CONTROL_AE_MODE_ON_ALWAYS_FLASH,
354                    CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
355            };
356            int[] aeAvail = ArrayUtils.convertStringListToIntArray(
357                    flashModes, flashModeStrings, flashModeInts);
358
359            // No flash control -> AE is always on
360            if (aeAvail == null || aeAvail.length == 0) {
361                aeAvail = new int[] {
362                        CONTROL_AE_MODE_ON
363                };
364            }
365
366            // Note that AE_MODE_OFF is never available.
367            m.set(CONTROL_AE_AVAILABLE_MODES, aeAvail);
368        }
369
370        /*
371         * control.aeCompensationRanges
372         */
373        {
374            int min = p.getMinExposureCompensation();
375            int max = p.getMaxExposureCompensation();
376
377            m.set(CONTROL_AE_COMPENSATION_RANGE, Range.create(min, max));
378        }
379
380        /*
381         * control.aeCompensationStep
382         */
383        {
384            float step = p.getExposureCompensationStep();
385
386            m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step));
387        }
388    }
389
390
391    @SuppressWarnings({"unchecked"})
392    private static void mapControlAf(CameraMetadataNative m, Camera.Parameters p) {
393        /*
394         * control.afAvailableModes
395         */
396        {
397            List<String> focusModes = p.getSupportedFocusModes();
398
399            String[] focusModeStrings = new String[] {
400                    Camera.Parameters.FOCUS_MODE_AUTO,
401                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
402                    Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
403                    Camera.Parameters.FOCUS_MODE_EDOF,
404                    Camera.Parameters.FOCUS_MODE_INFINITY,
405                    Camera.Parameters.FOCUS_MODE_MACRO,
406                    Camera.Parameters.FOCUS_MODE_FIXED,
407            };
408
409            int[] focusModeInts = new int[] {
410                    CONTROL_AF_MODE_AUTO,
411                    CONTROL_AF_MODE_CONTINUOUS_PICTURE,
412                    CONTROL_AF_MODE_CONTINUOUS_VIDEO,
413                    CONTROL_AF_MODE_EDOF,
414                    CONTROL_AF_MODE_OFF,
415                    CONTROL_AF_MODE_MACRO,
416                    CONTROL_AF_MODE_OFF
417            };
418
419            List<Integer> afAvail = ArrayUtils.convertStringListToIntList(
420                    focusModes, focusModeStrings, focusModeInts);
421
422            // No AF modes supported? That's unpossible!
423            if (afAvail == null || afAvail.size() == 0) {
424                Log.w(TAG, "No AF modes supported (HAL bug); defaulting to AF_MODE_OFF only");
425                afAvail = new ArrayList<Integer>(/*capacity*/1);
426                afAvail.add(CONTROL_AF_MODE_OFF);
427            }
428
429            m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail));
430
431            if (VERBOSE) {
432                Log.v(TAG, "mapControlAf - control.afAvailableModes set to " +
433                        ListUtils.listToString(afAvail));
434            }
435        }
436    }
437
438    private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) {
439        /*
440         * control.awbAvailableModes
441         */
442
443        {
444            List<String> wbModes = p.getSupportedWhiteBalance();
445
446            String[] wbModeStrings = new String[] {
447                    Camera.Parameters.WHITE_BALANCE_AUTO                    ,
448                    Camera.Parameters.WHITE_BALANCE_INCANDESCENT            ,
449                    Camera.Parameters.WHITE_BALANCE_FLUORESCENT             ,
450                    Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT        ,
451                    Camera.Parameters.WHITE_BALANCE_DAYLIGHT                ,
452                    Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT         ,
453                    Camera.Parameters.WHITE_BALANCE_TWILIGHT                ,
454                    Camera.Parameters.WHITE_BALANCE_SHADE                   ,
455            };
456
457            int[] wbModeInts = new int[] {
458                    CONTROL_AWB_MODE_AUTO,
459                    CONTROL_AWB_MODE_INCANDESCENT            ,
460                    CONTROL_AWB_MODE_FLUORESCENT             ,
461                    CONTROL_AWB_MODE_WARM_FLUORESCENT        ,
462                    CONTROL_AWB_MODE_DAYLIGHT                ,
463                    CONTROL_AWB_MODE_CLOUDY_DAYLIGHT         ,
464                    CONTROL_AWB_MODE_TWILIGHT                ,
465                    CONTROL_AWB_MODE_SHADE                   ,
466                    // Note that CONTROL_AWB_MODE_OFF is unsupported
467            };
468
469            List<Integer> awbAvail = ArrayUtils.convertStringListToIntList(
470                        wbModes, wbModeStrings, wbModeInts);
471
472            // No AWB modes supported? That's unpossible!
473            if (awbAvail == null || awbAvail.size() == 0) {
474                Log.w(TAG, "No AWB modes supported (HAL bug); defaulting to AWB_MODE_AUTO only");
475                awbAvail = new ArrayList<Integer>(/*capacity*/1);
476                awbAvail.add(CONTROL_AWB_MODE_AUTO);
477            }
478
479            m.set(CONTROL_AWB_AVAILABLE_MODES, ArrayUtils.toIntArray(awbAvail));
480
481            if (VERBOSE) {
482                Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " +
483                        ListUtils.listToString(awbAvail));
484            }
485        }
486    }
487
488    private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
489        /*
490         * android.control.maxRegions
491         */
492        final int AE = 0, AWB = 1, AF = 2;
493
494        int[] maxRegions = new int[3];
495        maxRegions[AE] = p.getMaxNumMeteringAreas();
496        maxRegions[AWB] = 0; // AWB regions not supported in API1
497        maxRegions[AF] = p.getMaxNumFocusAreas();
498
499        if (LIE_ABOUT_AE_MAX_REGIONS) {
500            maxRegions[AE] = 0;
501        }
502        if (LIE_ABOUT_AF_MAX_REGIONS) {
503            maxRegions[AF] = 0;
504        }
505
506        m.set(CONTROL_MAX_REGIONS, maxRegions);
507
508        /*
509         * android.control.availableEffects
510         */
511        List<String> effectModes = p.getSupportedColorEffects();
512        int[] supportedEffectModes = (effectModes == null) ? new int[0] :
513                ArrayUtils.convertStringListToIntArray(effectModes, sLegacyEffectMode,
514                        sEffectModes);
515        m.set(CONTROL_AVAILABLE_EFFECTS, supportedEffectModes);
516
517        /*
518         * android.control.availableSceneModes
519         */
520        List<String> sceneModes = p.getSupportedSceneModes();
521        int[] supportedSceneModes = (sceneModes == null) ? new int[0] :
522                ArrayUtils.convertStringListToIntArray(sceneModes, sLegacySceneModes, sSceneModes);
523        m.set(CONTROL_AVAILABLE_SCENE_MODES, supportedSceneModes);
524    }
525
526    private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
527        /*
528         *  We can tell if the lens is fixed focus;
529         *  but if it's not, we can't tell the minimum focus distance, so leave it null then.
530         */
531        if (p.getFocusMode() == Camera.Parameters.FOCUS_MODE_FIXED) {
532            /*
533             * lens.info.minimumFocusDistance
534             */
535            m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS);
536        }
537
538        float[] focalLengths = new float[] { p.getFocalLength() };
539        m.set(LENS_INFO_AVAILABLE_FOCAL_LENGTHS, focalLengths);
540    }
541
542    private static void mapFlash(CameraMetadataNative m, Camera.Parameters p) {
543        boolean flashAvailable = false;
544        List<String> supportedFlashModes = p.getSupportedFlashModes();
545
546        if (supportedFlashModes != null) {
547            // If only 'OFF' is available, we don't really have flash support
548            flashAvailable = !ListUtils.listElementsEqualTo(
549                    supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
550        }
551
552        /*
553         * flash.info.available
554         */
555        m.set(FLASH_INFO_AVAILABLE, flashAvailable);
556    }
557
558    private static void mapRequest(CameraMetadataNative m, Parameters p) {
559        /*
560         * request.availableCapabilities
561         */
562        int[] capabilities = { REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE };
563        m.set(REQUEST_AVAILABLE_CAPABILITIES, capabilities);
564
565        /*
566         * request.availableCharacteristicsKeys
567         */
568        {
569            // TODO: check if the underlying key is supported before listing a key as available
570
571            // Note: We only list public keys. Native HALs should list ALL keys regardless of visibility.
572
573            Key<?> availableKeys[] = new Key<?>[] {
574                    CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          ,
575                    CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      ,
576                    CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          ,
577                    CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   ,
578                    CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    ,
579                    CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      ,
580                    CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       ,
581                    CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   ,
582                    CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     ,
583                    CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     ,
584                    CameraCharacteristics.CONTROL_MAX_REGIONS                             ,
585                    CameraCharacteristics.FLASH_INFO_AVAILABLE                            ,
586                    CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   ,
587                    CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  ,
588                    CameraCharacteristics.LENS_FACING                                     ,
589                    CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               ,
590                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  ,
591                    CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS                  ,
592                    CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    ,
593                    CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      ,
594                    CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               ,
595//                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 ,
596                    CameraCharacteristics.SCALER_CROPPING_TYPE                            ,
597                    CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             ,
598                    CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   ,
599                    CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       ,
600                    CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    ,
601                    CameraCharacteristics.SENSOR_ORIENTATION                              ,
602                    CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     ,
603                    CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  ,
604                    CameraCharacteristics.SYNC_MAX_LATENCY                                ,
605            };
606            m.set(REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, getTagsForKeys(availableKeys));
607        }
608
609        /*
610         * request.availableRequestKeys
611         */
612        {
613            CaptureRequest.Key<?> availableKeys[] = new CaptureRequest.Key<?>[] {
614                    CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
615                    CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
616                    CaptureRequest.CONTROL_AE_LOCK,
617                    CaptureRequest.CONTROL_AE_MODE,
618                    CaptureRequest.CONTROL_AE_REGIONS,
619                    CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
620                    CaptureRequest.CONTROL_AF_MODE,
621                    CaptureRequest.CONTROL_AF_REGIONS,
622                    CaptureRequest.CONTROL_AF_TRIGGER,
623                    CaptureRequest.CONTROL_AWB_LOCK,
624                    CaptureRequest.CONTROL_AWB_MODE,
625                    CaptureRequest.CONTROL_CAPTURE_INTENT,
626                    CaptureRequest.CONTROL_EFFECT_MODE,
627                    CaptureRequest.CONTROL_MODE,
628                    CaptureRequest.CONTROL_SCENE_MODE,
629                    CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
630                    CaptureRequest.FLASH_MODE,
631                    CaptureRequest.JPEG_GPS_COORDINATES,
632                    CaptureRequest.JPEG_GPS_PROCESSING_METHOD,
633                    CaptureRequest.JPEG_GPS_TIMESTAMP,
634                    CaptureRequest.JPEG_ORIENTATION,
635                    CaptureRequest.JPEG_QUALITY,
636                    CaptureRequest.JPEG_THUMBNAIL_QUALITY,
637                    CaptureRequest.JPEG_THUMBNAIL_SIZE,
638                    CaptureRequest.LENS_FOCAL_LENGTH,
639                    CaptureRequest.SCALER_CROP_REGION,
640                    CaptureRequest.STATISTICS_FACE_DETECT_MODE,
641            };
642            m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableKeys));
643        }
644
645        /*
646         * request.availableResultKeys
647         */
648        {
649            CaptureResult.Key<?> availableKeys[] = new CaptureResult.Key<?>[] {
650                    CaptureResult.CONTROL_AE_ANTIBANDING_MODE                      ,
651                    CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION                 ,
652                    CaptureResult.CONTROL_AE_LOCK                                  ,
653                    CaptureResult.CONTROL_AE_MODE                                  ,
654                    CaptureResult.CONTROL_AE_REGIONS                               ,
655                    CaptureResult.CONTROL_AF_MODE                                  ,
656                    CaptureResult.CONTROL_AF_REGIONS                               ,
657                    CaptureResult.CONTROL_AF_STATE                                 ,
658                    CaptureResult.CONTROL_AWB_MODE                                 ,
659                    CaptureResult.CONTROL_AWB_LOCK                                 ,
660                    CaptureResult.CONTROL_MODE                                     ,
661                    CaptureResult.FLASH_MODE                                       ,
662                    CaptureResult.JPEG_GPS_COORDINATES                             ,
663                    CaptureResult.JPEG_GPS_PROCESSING_METHOD                       ,
664                    CaptureResult.JPEG_GPS_TIMESTAMP                               ,
665                    CaptureResult.JPEG_ORIENTATION                                 ,
666                    CaptureResult.JPEG_QUALITY                                     ,
667                    CaptureResult.JPEG_THUMBNAIL_QUALITY                           ,
668                    CaptureResult.LENS_FOCAL_LENGTH                                ,
669                    CaptureResult.REQUEST_PIPELINE_DEPTH                           ,
670                    CaptureResult.SCALER_CROP_REGION                               ,
671                    CaptureResult.SENSOR_TIMESTAMP                                 ,
672                    CaptureResult.STATISTICS_FACE_DETECT_MODE                      ,
673//                    CaptureResult.STATISTICS_FACES                                 ,
674            };
675            m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableKeys));
676        }
677
678        /*
679         * request.maxNumOutputStreams
680         */
681        int[] outputStreams = {
682                /* RAW */
683                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW,
684                /* Processed & Not-Stalling */
685                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC,
686                /* Processed & Stalling */
687                REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL,
688        };
689        m.set(REQUEST_MAX_NUM_OUTPUT_STREAMS, outputStreams);
690
691        /*
692         * request.maxNumInputStreams
693         */
694        m.set(REQUEST_MAX_NUM_INPUT_STREAMS, REQUEST_MAX_NUM_INPUT_STREAMS_COUNT);
695
696        /*
697         * request.partialResultCount
698         */
699        m.set(REQUEST_PARTIAL_RESULT_COUNT, 1); // No partial results supported
700
701        /*
702         * request.pipelineMaxDepth
703         */
704        m.set(REQUEST_PIPELINE_MAX_DEPTH,
705                (byte)(REQUEST_PIPELINE_MAX_DEPTH_HAL1 + REQUEST_PIPELINE_MAX_DEPTH_OURS));
706    }
707
708    private static void mapScaler(CameraMetadataNative m, Parameters p) {
709        /*
710         * scaler.availableMaxDigitalZoom
711         */
712        m.set(SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, ParameterUtils.getMaxZoomRatio(p));
713
714        /*
715         * scaler.croppingType = CENTER_ONLY
716         */
717        m.set(SCALER_CROPPING_TYPE, SCALER_CROPPING_TYPE_CENTER_ONLY);
718    }
719
720    private static void mapSensor(CameraMetadataNative m, Parameters p) {
721        // Use the largest jpeg size (by area) for both active array and pixel array
722        Size largestJpegSize = getLargestSupportedJpegSizeByArea(p);
723        /*
724         * sensor.info.activeArraySize
725         */
726        {
727            Rect activeArrayRect = ParamsUtils.createRect(largestJpegSize);
728            m.set(SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArrayRect);
729        }
730
731        /*
732         * sensor.availableTestPatternModes
733         */
734        {
735            // Only "OFF" test pattern mode is available
736            m.set(SENSOR_AVAILABLE_TEST_PATTERN_MODES, new int[] { SENSOR_TEST_PATTERN_MODE_OFF });
737        }
738
739        /*
740         * sensor.info.pixelArraySize
741         */
742        m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize);
743    }
744
745    private static void mapSync(CameraMetadataNative m, Parameters p) {
746        /*
747         * sync.maxLatency
748         */
749        m.set(SYNC_MAX_LATENCY, SYNC_MAX_LATENCY_UNKNOWN);
750    }
751
752    private static void appendStreamConfig(
753            ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
754        for (Camera.Size size : sizes) {
755            StreamConfiguration config =
756                    new StreamConfiguration(format, size.width, size.height, /*input*/false);
757            configs.add(config);
758        }
759    }
760
761    private final static String[] sLegacySceneModes = {
762        Parameters.SCENE_MODE_AUTO,
763        Parameters.SCENE_MODE_ACTION,
764        Parameters.SCENE_MODE_PORTRAIT,
765        Parameters.SCENE_MODE_LANDSCAPE,
766        Parameters.SCENE_MODE_NIGHT,
767        Parameters.SCENE_MODE_NIGHT_PORTRAIT,
768        Parameters.SCENE_MODE_THEATRE,
769        Parameters.SCENE_MODE_BEACH,
770        Parameters.SCENE_MODE_SNOW,
771        Parameters.SCENE_MODE_SUNSET,
772        Parameters.SCENE_MODE_STEADYPHOTO,
773        Parameters.SCENE_MODE_FIREWORKS,
774        Parameters.SCENE_MODE_SPORTS,
775        Parameters.SCENE_MODE_PARTY,
776        Parameters.SCENE_MODE_CANDLELIGHT,
777        Parameters.SCENE_MODE_BARCODE,
778    };
779
780    private final static int[] sSceneModes = {
781        CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED,
782        CameraCharacteristics.CONTROL_SCENE_MODE_ACTION,
783        CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT,
784        CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE,
785        CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT,
786        CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
787        CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE,
788        CameraCharacteristics.CONTROL_SCENE_MODE_BEACH,
789        CameraCharacteristics.CONTROL_SCENE_MODE_SNOW,
790        CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET,
791        CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO,
792        CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS,
793        CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS,
794        CameraCharacteristics.CONTROL_SCENE_MODE_PARTY,
795        CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT,
796        CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE,
797    };
798
799    static int convertSceneModeFromLegacy(String mode) {
800        if (mode == null) {
801            return CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED;
802        }
803        int index = ArrayUtils.getArrayIndex(sLegacySceneModes, mode);
804        if (index < 0) {
805            return UNKNOWN_MODE;
806        }
807        return sSceneModes[index];
808    }
809
810    static String convertSceneModeToLegacy(int mode) {
811        int index = ArrayUtils.getArrayIndex(sSceneModes, mode);
812        if (index < 0) {
813            return null;
814        }
815        return sLegacySceneModes[index];
816    }
817
818    private final static String[] sLegacyEffectMode = {
819        Parameters.EFFECT_NONE,
820        Parameters.EFFECT_MONO,
821        Parameters.EFFECT_NEGATIVE,
822        Parameters.EFFECT_SOLARIZE,
823        Parameters.EFFECT_SEPIA,
824        Parameters.EFFECT_POSTERIZE,
825        Parameters.EFFECT_WHITEBOARD,
826        Parameters.EFFECT_BLACKBOARD,
827        Parameters.EFFECT_AQUA,
828    };
829
830    private final static int[] sEffectModes = {
831        CameraCharacteristics.CONTROL_EFFECT_MODE_OFF,
832        CameraCharacteristics.CONTROL_EFFECT_MODE_MONO,
833        CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE,
834        CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE,
835        CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA,
836        CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE,
837        CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD,
838        CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD,
839        CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA,
840    };
841
842    static int convertEffectModeFromLegacy(String mode) {
843        if (mode == null) {
844            return CameraCharacteristics.CONTROL_EFFECT_MODE_OFF;
845        }
846        int index = ArrayUtils.getArrayIndex(sLegacyEffectMode, mode);
847        if (index < 0) {
848            return UNKNOWN_MODE;
849        }
850        return sEffectModes[index];
851    }
852
853    static String convertEffectModeToLegacy(int mode) {
854        int index = ArrayUtils.getArrayIndex(sEffectModes, mode);
855        if (index < 0) {
856            return null;
857        }
858        return sLegacyEffectMode[index];
859    }
860
861    /**
862     * Convert the ae antibanding mode from api1 into api2.
863     *
864     * @param mode the api1 mode, {@code null} is allowed and will return {@code -1}.
865     *
866     * @return The api2 value, or {@code -1} by default if conversion failed
867     */
868    private static int convertAntiBandingMode(String mode) {
869        if (mode == null) {
870            return -1;
871        }
872
873        switch (mode) {
874            case Camera.Parameters.ANTIBANDING_OFF: {
875                return CONTROL_AE_ANTIBANDING_MODE_OFF;
876            }
877            case Camera.Parameters.ANTIBANDING_50HZ: {
878                return CONTROL_AE_ANTIBANDING_MODE_50HZ;
879            }
880            case Camera.Parameters.ANTIBANDING_60HZ: {
881                return CONTROL_AE_ANTIBANDING_MODE_60HZ;
882            }
883            case Camera.Parameters.ANTIBANDING_AUTO: {
884                return CONTROL_AE_ANTIBANDING_MODE_AUTO;
885            }
886            default: {
887                Log.w(TAG, "convertAntiBandingMode - Unknown antibanding mode " + mode);
888                return -1;
889            }
890        }
891    }
892
893    /**
894     * Convert the ae antibanding mode from api1 into api2.
895     *
896     * @param mode the api1 mode, {@code null} is allowed and will return {@code MODE_OFF}.
897     *
898     * @return The api2 value, or {@code MODE_OFF} by default if conversion failed
899     */
900    static int convertAntiBandingModeOrDefault(String mode) {
901        int antiBandingMode = convertAntiBandingMode(mode);
902        if (antiBandingMode == -1) {
903            return CONTROL_AE_ANTIBANDING_MODE_OFF;
904        }
905
906        return antiBandingMode;
907    }
908
909    private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
910        int[] legacyFps = new int[2];
911        legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
912        legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
913        return legacyFps;
914    }
915
916    /**
917     * Return the stall duration for a given output jpeg size in nanoseconds.
918     *
919     * <p>An 8mp image is chosen to have a stall duration of 0.8 seconds.</p>
920     */
921    private static long calculateJpegStallDuration(Camera.Size size) {
922        long baseDuration = APPROXIMATE_CAPTURE_DELAY_MS * NS_PER_MS; // 200ms for capture
923        long area = size.width * (long) size.height;
924        long stallPerArea = APPROXIMATE_JPEG_ENCODE_TIME_MS * NS_PER_MS /
925                APPROXIMATE_SENSOR_AREA_PX; // 600ms stall for 8mp
926        return baseDuration + area * stallPerArea;
927    }
928
929    /**
930     * Set the legacy parameters using the {@link LegacyRequest legacy request}.
931     *
932     * <p>The legacy request's parameters are changed as a side effect of calling this
933     * method.</p>
934     *
935     * @param request a non-{@code null} legacy request
936     */
937    public static void convertRequestMetadata(LegacyRequest request) {
938        LegacyRequestMapper.convertRequestMetadata(request);
939    }
940
941    private static final int[] sAllowedTemplates = {
942            CameraDevice.TEMPLATE_PREVIEW,
943            CameraDevice.TEMPLATE_STILL_CAPTURE,
944            CameraDevice.TEMPLATE_RECORD,
945            // Disallowed templates in legacy mode:
946            // CameraDevice.TEMPLATE_VIDEO_SNAPSHOT,
947            // CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
948            // CameraDevice.TEMPLATE_MANUAL
949    };
950
951    /**
952     * Create a request template
953     *
954     * @param c a non-{@code null} camera characteristics for this camera
955     * @param templateId a non-negative template ID
956     *
957     * @return a non-{@code null} request template
958     *
959     * @throws IllegalArgumentException if {@code templateId} was invalid
960     *
961     * @see android.hardware.camera2.CameraDevice#TEMPLATE_MANUAL
962     */
963    public static CameraMetadataNative createRequestTemplate(
964            CameraCharacteristics c, int templateId) {
965        if (!ArrayUtils.contains(sAllowedTemplates, templateId)) {
966            throw new IllegalArgumentException("templateId out of range");
967        }
968
969        CameraMetadataNative m = new CameraMetadataNative();
970
971        /*
972         * NOTE: If adding new code here and it needs to query the static info,
973         * query the camera characteristics, so we can reuse this for api2 code later
974         * to create our own templates in the framework
975         */
976
977        /*
978         * control.*
979         */
980
981        // control.awbMode
982        m.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);
983        // AWB is always unconditionally available in API1 devices
984
985        // control.aeAntibandingMode
986        m.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, CONTROL_AE_ANTIBANDING_MODE_AUTO);
987
988        // control.aeExposureCompensation
989        m.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
990
991        // control.aeLock
992        m.set(CaptureRequest.CONTROL_AE_LOCK, false);
993
994        // control.aePrecaptureTrigger
995        m.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
996
997        // control.afTrigger
998        m.set(CaptureRequest.CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
999
1000        // control.awbMode
1001        m.set(CaptureRequest.CONTROL_AWB_MODE, CONTROL_AWB_MODE_AUTO);
1002
1003        // control.awbLock
1004        m.set(CaptureRequest.CONTROL_AWB_LOCK, false);
1005
1006        // control.aeRegions, control.awbRegions, control.afRegions
1007        {
1008            Rect activeArray = c.get(SENSOR_INFO_ACTIVE_ARRAY_SIZE);
1009            MeteringRectangle[] activeRegions =  new MeteringRectangle[] {
1010                    new MeteringRectangle(/*x*/0, /*y*/0, /*width*/activeArray.width() - 1,
1011                    /*height*/activeArray.height() - 1,/*weight*/1)};
1012            m.set(CaptureRequest.CONTROL_AE_REGIONS, activeRegions);
1013            m.set(CaptureRequest.CONTROL_AWB_REGIONS, activeRegions);
1014            m.set(CaptureRequest.CONTROL_AF_REGIONS, activeRegions);
1015        }
1016
1017        // control.captureIntent
1018        m.set(CaptureRequest.CONTROL_CAPTURE_INTENT, templateId);
1019
1020        // control.aeMode
1021        m.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
1022        // AE is always unconditionally available in API1 devices
1023
1024        // control.mode
1025        m.set(CaptureRequest.CONTROL_MODE, CONTROL_MODE_AUTO);
1026
1027        // control.afMode
1028        {
1029            Float minimumFocusDistance = c.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE);
1030
1031            int afMode;
1032            if (minimumFocusDistance != null &&
1033                    minimumFocusDistance == LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS) {
1034                // Cannot control auto-focus with fixed-focus cameras
1035                afMode = CameraMetadata.CONTROL_AF_MODE_OFF;
1036            } else {
1037                // If a minimum focus distance is reported; the camera must have AF
1038                afMode = CameraMetadata.CONTROL_AF_MODE_AUTO;
1039
1040                if (templateId == CameraDevice.TEMPLATE_RECORD ||
1041                        templateId == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
1042                    if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
1043                            CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
1044                        afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
1045                    }
1046                } else if (templateId == CameraDevice.TEMPLATE_PREVIEW ||
1047                        templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) {
1048                    if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
1049                            CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {
1050                        afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
1051                    }
1052                }
1053            }
1054
1055            m.set(CaptureRequest.CONTROL_AF_MODE, afMode);
1056        }
1057
1058        {
1059            // control.aeTargetFpsRange
1060            Range<Integer>[] availableFpsRange = c.
1061                    get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
1062
1063            // Pick FPS range with highest max value, tiebreak on higher min value
1064            Range<Integer> bestRange = availableFpsRange[0];
1065            for (Range<Integer> r : availableFpsRange) {
1066                if (bestRange.getUpper() < r.getUpper()) {
1067                    bestRange = r;
1068                } else if (bestRange.getUpper() == r.getUpper() &&
1069                        bestRange.getLower() < r.getLower()) {
1070                    bestRange = r;
1071                }
1072            }
1073            m.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange);
1074        }
1075
1076        /*
1077         * statistics.*
1078         */
1079
1080        // statistics.faceDetectMode
1081        m.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF);
1082
1083        /*
1084         * flash.*
1085         */
1086
1087        // flash.mode
1088        m.set(CaptureRequest.FLASH_MODE, FLASH_MODE_OFF);
1089
1090        /*
1091         * lens.*
1092         */
1093
1094        // lens.focalLength
1095        m.set(CaptureRequest.LENS_FOCAL_LENGTH,
1096                c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0]);
1097
1098        // TODO: map other request template values
1099        return m;
1100    }
1101
1102    private static int[] getTagsForKeys(Key<?>[] keys) {
1103        int[] tags = new int[keys.length];
1104
1105        for (int i = 0; i < keys.length; ++i) {
1106            tags[i] = keys[i].getNativeKey().getTag();
1107        }
1108
1109        return tags;
1110    }
1111
1112    private static int[] getTagsForKeys(CaptureRequest.Key<?>[] keys) {
1113        int[] tags = new int[keys.length];
1114
1115        for (int i = 0; i < keys.length; ++i) {
1116            tags[i] = keys[i].getNativeKey().getTag();
1117        }
1118
1119        return tags;
1120    }
1121
1122    private static int[] getTagsForKeys(CaptureResult.Key<?>[] keys) {
1123        int[] tags = new int[keys.length];
1124
1125        for (int i = 0; i < keys.length; ++i) {
1126            tags[i] = keys[i].getNativeKey().getTag();
1127        }
1128
1129        return tags;
1130    }
1131
1132    /**
1133     * Convert the requested AF mode into its equivalent supported parameter.
1134     *
1135     * @param mode {@code CONTROL_AF_MODE}
1136     * @param supportedFocusModes list of camera1's supported focus modes
1137     * @return the stringified af mode, or {@code null} if its not supported
1138     */
1139    static String convertAfModeToLegacy(int mode, List<String> supportedFocusModes) {
1140        if (supportedFocusModes == null || supportedFocusModes.isEmpty()) {
1141            Log.w(TAG, "No focus modes supported; API1 bug");
1142            return null;
1143        }
1144
1145        String param = null;
1146        switch (mode) {
1147            case CONTROL_AF_MODE_AUTO:
1148                param = Parameters.FOCUS_MODE_AUTO;
1149                break;
1150            case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
1151                param = Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
1152                break;
1153            case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
1154                param = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
1155                break;
1156            case CONTROL_AF_MODE_EDOF:
1157                param = Parameters.FOCUS_MODE_EDOF;
1158                break;
1159            case CONTROL_AF_MODE_MACRO:
1160                param = Parameters.FOCUS_MODE_MACRO;
1161                break;
1162            case CONTROL_AF_MODE_OFF:
1163                if (supportedFocusModes.contains(Parameters.FOCUS_MODE_FIXED)) {
1164                    param = Parameters.FOCUS_MODE_FIXED;
1165                } else {
1166                    param = Parameters.FOCUS_MODE_INFINITY;
1167                }
1168        }
1169
1170        if (!supportedFocusModes.contains(param)) {
1171            // Weed out bad user input by setting to the first arbitrary focus mode
1172            String defaultMode = supportedFocusModes.get(0);
1173            Log.w(TAG,
1174                    String.format(
1175                            "convertAfModeToLegacy - ignoring unsupported mode %d, " +
1176                            "defaulting to %s", mode, defaultMode));
1177            param = defaultMode;
1178        }
1179
1180        return param;
1181    }
1182}
1183