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.List;
     46 
     47 import static com.android.internal.util.Preconditions.*;
     48 import static android.hardware.camera2.CameraCharacteristics.*;
     49 import 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")
     56 public 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