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