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