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