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