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