Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright 2013 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.cts;
     18 
     19 import android.content.Context;
     20 import android.graphics.ImageFormat;
     21 import android.hardware.camera2.CameraCaptureSession;
     22 import android.hardware.camera2.CameraCharacteristics;
     23 import android.hardware.camera2.CameraDevice;
     24 import android.hardware.camera2.CaptureRequest;
     25 import android.hardware.camera2.CaptureResult;
     26 import android.hardware.camera2.TotalCaptureResult;
     27 import android.media.Image;
     28 import android.media.ImageReader;
     29 import android.os.SystemClock;
     30 import android.platform.test.annotations.AppModeFull;
     31 import android.util.Pair;
     32 import android.util.Size;
     33 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
     34 import android.hardware.camera2.cts.helpers.StaticMetadata;
     35 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
     36 
     37 import static android.hardware.camera2.cts.CameraTestUtils.*;
     38 import static android.hardware.camera2.cts.helpers.CameraSessionUtils.*;
     39 
     40 import android.util.Log;
     41 import android.view.Surface;
     42 
     43 import java.util.ArrayList;
     44 import java.util.Arrays;
     45 import java.util.HashMap;
     46 import java.util.HashSet;
     47 import java.util.List;
     48 import java.util.Map;
     49 import java.util.Set;
     50 import java.util.concurrent.LinkedBlockingQueue;
     51 import java.util.concurrent.TimeUnit;
     52 
     53 @AppModeFull
     54 public class CaptureResultTest extends Camera2AndroidTestCase {
     55     private static final String TAG = "CaptureResultTest";
     56     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     57     private static final int MAX_NUM_IMAGES = MAX_READER_IMAGES;
     58     private static final int NUM_FRAMES_VERIFIED = 30;
     59     private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
     60 
     61 
     62     // List tracking the failed test keys.
     63 
     64     @Override
     65     public void setContext(Context context) {
     66         super.setContext(context);
     67 
     68         /**
     69          * Workaround for mockito and JB-MR2 incompatibility
     70          *
     71          * Avoid java.lang.IllegalArgumentException: dexcache == null
     72          * https://code.google.com/p/dexmaker/issues/detail?id=2
     73          */
     74         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
     75     }
     76 
     77     @Override
     78     protected void setUp() throws Exception {
     79         super.setUp();
     80     }
     81 
     82     @Override
     83     protected void tearDown() throws Exception {
     84         super.tearDown();
     85     }
     86 
     87     /**
     88      * <p>
     89      * Basic non-null check test for multiple capture results.
     90      * </p>
     91      * <p>
     92      * When capturing many frames, some camera devices may return some results that have null keys
     93      * randomly, which is an API violation and could cause application crash randomly. This test
     94      * runs a typical flexible yuv capture many times, and checks if there is any null entries in
     95      * a capture result.
     96      * </p>
     97      */
     98     public void testCameraCaptureResultAllKeys() throws Exception {
     99         for (String id : mCameraIds) {
    100             try {
    101                 openDevice(id);
    102                 if (mStaticInfo.isColorOutputSupported()) {
    103                     // Create image reader and surface.
    104                     Size size = mOrderedPreviewSizes.get(0);
    105                     createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
    106                             new ImageDropperListener());
    107                 } else {
    108                     Size size = getMaxDepthSize(id, mCameraManager);
    109                     createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES,
    110                             new ImageDropperListener());
    111                 }
    112 
    113                 // Configure output streams.
    114                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
    115                 outputSurfaces.add(mReaderSurface);
    116                 createSession(outputSurfaces);
    117 
    118                 CaptureRequest.Builder requestBuilder =
    119                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    120                 assertNotNull("Failed to create capture request", requestBuilder);
    121                 requestBuilder.addTarget(mReaderSurface);
    122 
    123                 // Start capture
    124                 SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
    125                 startCapture(requestBuilder.build(), /*repeating*/true, captureListener, mHandler);
    126 
    127                 // Verify results
    128                 validateCaptureResult(mCollector, captureListener, mStaticInfo, mAllStaticInfo,
    129                         null/*requestedPhysicalIds*/, requestBuilder, NUM_FRAMES_VERIFIED);
    130 
    131                 stopCapture(/*fast*/false);
    132             } finally {
    133                 closeDevice(id);
    134                 closeDefaultImageReader();
    135             }
    136         }
    137     }
    138 
    139     /**
    140      * Check partial results conform to its specification.
    141      * <p>
    142      * The test is skipped if partial result is not supported on device. </p>
    143      * <p>Test summary:<ul>
    144      * <li>1. Number of partial results is less than or equal to
    145      * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}.
    146      * <li>2. Each key appeared in partial results must be unique across all partial results.
    147      * <li>3. All keys appeared in partial results must be present in TotalCaptureResult
    148      * <li>4. Also test onCaptureComplete callback always happen after onCaptureStart or
    149      * onCaptureProgressed callbacks.
    150      * </ul></p>
    151      */
    152     public void testPartialResult() throws Exception {
    153         final int NUM_FRAMES_TESTED = 30;
    154         final int WAIT_FOR_RESULT_TIMOUT_MS = 2000;
    155         for (String id : mCameraIds) {
    156             try {
    157                 openDevice(id);
    158 
    159                 // Skip the test if partial result is not supported
    160                 int partialResultCount = mStaticInfo.getPartialResultCount();
    161                 if (partialResultCount == 1) {
    162                     continue;
    163                 }
    164 
    165                 // Create image reader and surface.
    166                 if (mStaticInfo.isColorOutputSupported()) {
    167                     Size size = mOrderedPreviewSizes.get(0);
    168                     createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
    169                             new ImageDropperListener());
    170                 } else {
    171                     Size size = getMaxDepthSize(id, mCameraManager);
    172                     createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES,
    173                             new ImageDropperListener());
    174                 }
    175 
    176                 // Configure output streams.
    177                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
    178                 outputSurfaces.add(mReaderSurface);
    179                 createSession(outputSurfaces);
    180 
    181                 CaptureRequest.Builder requestBuilder =
    182                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    183                 assertNotNull("Failed to create capture request", requestBuilder);
    184                 requestBuilder.addTarget(mReaderSurface);
    185                 TotalAndPartialResultListener listener =
    186                         new TotalAndPartialResultListener();
    187 
    188                 // Start capture
    189                 for (Integer frame = 0; frame < NUM_FRAMES_TESTED; frame++) {
    190                     // Set a different tag for each request so the listener can group
    191                     // partial results by each request
    192                     requestBuilder.setTag(frame);
    193                     startCapture(
    194                             requestBuilder.build(), /*repeating*/false,
    195                             listener, mHandler);
    196                 }
    197 
    198                 // Verify capture results
    199                 for (int frame = 0; frame < NUM_FRAMES_TESTED; frame++) {
    200                     Pair<TotalCaptureResult, List<CaptureResult>> resultPair =
    201                             listener.getCaptureResultPairs(WAIT_FOR_RESULT_TIMOUT_MS);
    202 
    203                     List<CaptureResult> partialResults = resultPair.second;
    204 
    205                     if (partialResults == null) {
    206                         // HAL only sends total result is legal
    207                         partialResults = new ArrayList<>();
    208                     }
    209 
    210                     TotalCaptureResult totalResult = resultPair.first;
    211 
    212                     mCollector.expectLessOrEqual("Too many partial results",
    213                             partialResultCount, partialResults.size());
    214                     Set<CaptureResult.Key<?>> appearedPartialKeys =
    215                             new HashSet<CaptureResult.Key<?>>();
    216                     for (CaptureResult partialResult : partialResults) {
    217                         List<CaptureResult.Key<?>> partialKeys = partialResult.getKeys();
    218                         mCollector.expectValuesUnique("Partial result keys: ", partialKeys);
    219                         for (CaptureResult.Key<?> key : partialKeys) {
    220                             mCollector.expectTrue(
    221                                     String.format("Key %s appears in multiple partial results",
    222                                             key.getName()),
    223                                     !appearedPartialKeys.contains(key));
    224                         }
    225                         appearedPartialKeys.addAll(partialKeys);
    226                     }
    227 
    228                     // Test total result against the partial results
    229                     List<CaptureResult.Key<?>> totalResultKeys = totalResult.getKeys();
    230                     mCollector.expectTrue(
    231                             "TotalCaptureResult must be a super set of partial capture results",
    232                             totalResultKeys.containsAll(appearedPartialKeys));
    233 
    234                     List<CaptureResult> totalResultPartials = totalResult.getPartialResults();
    235                     mCollector.expectEquals("TotalCaptureResult's partial results must match " +
    236                             "the ones observed by #onCaptureProgressed",
    237                             partialResults, totalResultPartials);
    238 
    239                     if (VERBOSE) {
    240                         Log.v(TAG, "testPartialResult - Observed " +
    241                                 partialResults.size() + "; queried for " +
    242                                 totalResultPartials.size());
    243                     }
    244                 }
    245 
    246                 int errorCode = listener.getErrorCode();
    247                 if ((errorCode & TotalAndPartialResultListener.ERROR_DUPLICATED_REQUEST) != 0) {
    248                     mCollector.addMessage("Listener received multiple onCaptureComplete" +
    249                             " callback for the same request");
    250                 }
    251                 if ((errorCode & TotalAndPartialResultListener.ERROR_WRONG_CALLBACK_ORDER) != 0) {
    252                     mCollector.addMessage("Listener received onCaptureStart or" +
    253                             " onCaptureProgressed after onCaptureComplete");
    254                 }
    255 
    256                 stopCapture(/*fast*/false);
    257             } finally {
    258                 closeDevice(id);
    259                 closeDefaultImageReader();
    260             }
    261         }
    262     }
    263 
    264     /**
    265      * Check that the timestamps passed in the results, buffers, and capture callbacks match for
    266      * a single request, and increase monotonically
    267      */
    268     public void testResultTimestamps() throws Exception {
    269         for (String id : mCameraIds) {
    270             ImageReader previewReader = null;
    271             ImageReader jpegReader = null;
    272 
    273             SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
    274             SimpleImageReaderListener prevListener = new SimpleImageReaderListener();
    275             try {
    276                 openDevice(id);
    277                 if (!mStaticInfo.isColorOutputSupported()) {
    278                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
    279                     continue;
    280                 }
    281 
    282                 CaptureRequest.Builder previewBuilder =
    283                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    284                 CaptureRequest.Builder multiBuilder =
    285                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
    286 
    287                 // Create image reader and surface.
    288                 Size previewSize = mOrderedPreviewSizes.get(0);
    289                 Size jpegSize = mOrderedStillSizes.get(0);
    290 
    291                 // Create ImageReaders.
    292                 previewReader = makeImageReader(previewSize, ImageFormat.YUV_420_888,
    293                         MAX_NUM_IMAGES, prevListener, mHandler);
    294                 jpegReader = makeImageReader(jpegSize, ImageFormat.JPEG,
    295                         MAX_NUM_IMAGES, jpegListener, mHandler);
    296 
    297                 // Configure output streams with preview and jpeg streams.
    298                 List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(
    299                         previewReader.getSurface(), jpegReader.getSurface()));
    300 
    301                 SessionListener mockSessionListener = getMockSessionListener();
    302 
    303                 CameraCaptureSession session = configureAndVerifySession(mockSessionListener,
    304                         mCamera, outputSurfaces, mHandler);
    305 
    306                 // Configure the requests.
    307                 previewBuilder.addTarget(previewReader.getSurface());
    308                 multiBuilder.addTarget(previewReader.getSurface());
    309                 multiBuilder.addTarget(jpegReader.getSurface());
    310 
    311                 if (mStaticInfo.isEnableZslSupported()) {
    312                     // Turn off ZSL to ensure timestamps are increasing
    313                     previewBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
    314                     multiBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false);
    315                 }
    316 
    317                 CaptureCallback mockCaptureCallback = getMockCaptureListener();
    318 
    319                 // Capture targeting only preview
    320                 Pair<TotalCaptureResult, Long> result = captureAndVerifyResult(mockCaptureCallback,
    321                         session, previewBuilder.build(), mHandler);
    322 
    323                 // Check if all timestamps are the same
    324                 Image prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
    325                 validateTimestamps("Result 1", result.first,
    326                         prevImage, result.second);
    327                 prevImage.close();
    328 
    329                 // Capture targeting both jpeg and preview
    330                 Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback,
    331                         session, multiBuilder.build(), mHandler);
    332 
    333                 // Check if all timestamps are the same
    334                 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
    335                 Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
    336                 validateTimestamps("Result 2 Preview", result2.first,
    337                         prevImage, result2.second);
    338                 validateTimestamps("Result 2 Jpeg", result2.first,
    339                         jpegImage, result2.second);
    340                 prevImage.close();
    341                 jpegImage.close();
    342 
    343                 // Check if timestamps are increasing
    344                 mCollector.expectGreater("Timestamps must be increasing.", result.second,
    345                         result2.second);
    346 
    347                 // Capture two preview frames
    348                 long startTime = SystemClock.elapsedRealtimeNanos();
    349                 Pair<TotalCaptureResult, Long> result3 = captureAndVerifyResult(mockCaptureCallback,
    350                         session, previewBuilder.build(), mHandler);
    351                 Pair<TotalCaptureResult, Long> result4 = captureAndVerifyResult(mockCaptureCallback,
    352                         session, previewBuilder.build(), mHandler);
    353                 long clockDiff = SystemClock.elapsedRealtimeNanos() - startTime;
    354                 long resultDiff = result4.second - result3.second;
    355 
    356                 // Check if all timestamps are the same
    357                 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
    358                 validateTimestamps("Result 3", result3.first,
    359                         prevImage, result3.second);
    360                 prevImage.close();
    361                 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
    362                 validateTimestamps("Result 4", result4.first,
    363                         prevImage, result4.second);
    364                 prevImage.close();
    365 
    366                 // Check that the timestamps monotonically increase at a reasonable rate
    367                 mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.",
    368                         resultDiff, clockDiff);
    369                 mCollector.expectGreater("Timestamps must be increasing.", result3.second,
    370                         result4.second);
    371             } finally {
    372                 closeDevice(id);
    373                 closeImageReader(previewReader);
    374                 closeImageReader(jpegReader);
    375             }
    376         }
    377     }
    378 
    379     private void validateTimestamps(String msg, TotalCaptureResult result, Image resultImage,
    380                                     long captureTime) {
    381         mCollector.expectKeyValueEquals(result, CaptureResult.SENSOR_TIMESTAMP, captureTime);
    382         mCollector.expectEquals(msg + ": Capture timestamp must be same as resultImage timestamp",
    383                 resultImage.getTimestamp(), captureTime);
    384     }
    385 
    386     public static void validateCaptureResult(CameraErrorCollector errorCollector,
    387             SimpleCaptureCallback captureListener, StaticMetadata staticInfo,
    388             Map<String, StaticMetadata> allStaticInfo, List<String> requestedPhysicalIds,
    389             CaptureRequest.Builder requestBuilder, int numFramesVerified) throws Exception {
    390         // List that includes all public keys from CaptureResult
    391         List<CaptureResult.Key<?>> allKeys = getAllCaptureResultKeys();
    392         // Get the waived keys for current camera device
    393         List<CaptureResult.Key<?>> waiverKeys = getWaiverKeysForCamera(staticInfo);
    394         if (requestedPhysicalIds == null) {
    395             requestedPhysicalIds = new ArrayList<String>();
    396         }
    397 
    398         HashMap<String, List<CaptureResult.Key<?>>> physicalWaiverKeys = new HashMap<>();
    399         for (String physicalId : requestedPhysicalIds) {
    400             StaticMetadata physicalStaticInfo = allStaticInfo.get(physicalId);
    401             physicalWaiverKeys.put(physicalId, getWaiverKeysForCamera(physicalStaticInfo));
    402         }
    403 
    404         TotalCaptureResult result = null;
    405         for (int i = 0; i < numFramesVerified; i++) {
    406             result = captureListener.getTotalCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
    407             Map<String, CaptureResult> physicalCaptureResults = result.getPhysicalCameraResults();
    408             errorCollector.expectEquals("Number of physical result metadata doesn't match " +
    409                     physicalCaptureResults.size() + " vs " + requestedPhysicalIds.size(),
    410                     physicalCaptureResults.size(), requestedPhysicalIds.size());
    411 
    412             validateOneCaptureResult(errorCollector, waiverKeys, allKeys, requestBuilder, result,
    413                     null/*cameraId*/, i);
    414             for (String physicalId : requestedPhysicalIds) {
    415                 validateOneCaptureResult(errorCollector, physicalWaiverKeys.get(physicalId),
    416                         allKeys, null/*requestBuilder*/, physicalCaptureResults.get(physicalId),
    417                         physicalId, i);
    418             }
    419         }
    420     }
    421 
    422     private static void validateOneCaptureResult(CameraErrorCollector errorCollector,
    423             List<CaptureResult.Key<?>> skippedKeys, List<CaptureResult.Key<?>> allKeys,
    424             CaptureRequest.Builder requestBuilder, CaptureResult result, String cameraId,
    425             int resultCount) throws Exception {
    426         String failMsg = "Failed capture result " + resultCount + " test";
    427         String cameraIdString = " ";
    428         if (cameraId != null) {
    429             cameraIdString += "for physical camera " + cameraId;
    430         }
    431         boolean verifyMatchRequest = (requestBuilder != null);
    432         for (CaptureResult.Key<?> key : allKeys) {
    433             if (!skippedKeys.contains(key)) {
    434                 /**
    435                  * Check the critical tags here.
    436                  * TODO: Can use the same key for request and result when request/result
    437                  * becomes symmetric (b/14059883). Then below check can be wrapped into
    438                  * a generic function.
    439                  */
    440                 String msg = failMsg + cameraIdString + "for key " + key.getName();
    441                 if (verifyMatchRequest) {
    442                     if (key.equals(CaptureResult.CONTROL_AE_MODE)) {
    443                         errorCollector.expectEquals(msg,
    444                                 requestBuilder.get(CaptureRequest.CONTROL_AE_MODE),
    445                                 result.get(CaptureResult.CONTROL_AE_MODE));
    446                     } else if (key.equals(CaptureResult.CONTROL_AF_MODE)) {
    447                         errorCollector.expectEquals(msg,
    448                                 requestBuilder.get(CaptureRequest.CONTROL_AF_MODE),
    449                                 result.get(CaptureResult.CONTROL_AF_MODE));
    450                     } else if (key.equals(CaptureResult.CONTROL_AWB_MODE)) {
    451                         errorCollector.expectEquals(msg,
    452                                 requestBuilder.get(CaptureRequest.CONTROL_AWB_MODE),
    453                                 result.get(CaptureResult.CONTROL_AWB_MODE));
    454                     } else if (key.equals(CaptureResult.CONTROL_MODE)) {
    455                         errorCollector.expectEquals(msg,
    456                                 requestBuilder.get(CaptureRequest.CONTROL_MODE),
    457                                 result.get(CaptureResult.CONTROL_MODE));
    458                     } else if (key.equals(CaptureResult.STATISTICS_FACE_DETECT_MODE)) {
    459                         errorCollector.expectEquals(msg,
    460                                 requestBuilder.get(CaptureRequest.STATISTICS_FACE_DETECT_MODE),
    461                                 result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE));
    462                     } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
    463                         errorCollector.expectEquals(msg,
    464                                 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
    465                                 result.get(CaptureResult.NOISE_REDUCTION_MODE));
    466                     } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
    467                         errorCollector.expectEquals(msg,
    468                                 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
    469                                 result.get(CaptureResult.NOISE_REDUCTION_MODE));
    470                     } else if (key.equals(CaptureResult.REQUEST_PIPELINE_DEPTH)) {
    471 
    472                     } else if (key.equals(CaptureResult.STATISTICS_OIS_DATA_MODE)) {
    473                         errorCollector.expectEquals(msg,
    474                                 requestBuilder.get(CaptureRequest.STATISTICS_OIS_DATA_MODE),
    475                                 result.get(CaptureResult.STATISTICS_OIS_DATA_MODE));
    476                     } else {
    477                         // Only do non-null check for the rest of keys.
    478                         errorCollector.expectKeyValueNotNull(failMsg, result, key);
    479                     }
    480                 } else {
    481                     // Only do non-null check for the rest of keys.
    482                     errorCollector.expectKeyValueNotNull(failMsg, result, key);
    483                 }
    484             } else {
    485                 // These keys should always be null
    486                 if (key.equals(CaptureResult.CONTROL_AE_REGIONS)) {
    487                     errorCollector.expectNull(
    488                             "Capture result contains AE regions but aeMaxRegions is 0"
    489                             + cameraIdString,
    490                             result.get(CaptureResult.CONTROL_AE_REGIONS));
    491                 } else if (key.equals(CaptureResult.CONTROL_AWB_REGIONS)) {
    492                     errorCollector.expectNull(
    493                             "Capture result contains AWB regions but awbMaxRegions is 0"
    494                             + cameraIdString,
    495                             result.get(CaptureResult.CONTROL_AWB_REGIONS));
    496                 } else if (key.equals(CaptureResult.CONTROL_AF_REGIONS)) {
    497                     errorCollector.expectNull(
    498                             "Capture result contains AF regions but afMaxRegions is 0"
    499                             + cameraIdString,
    500                             result.get(CaptureResult.CONTROL_AF_REGIONS));
    501                 }
    502             }
    503         }
    504     }
    505 
    506     /*
    507      * Add waiver keys per camera device hardware level and capability.
    508      *
    509      * Must be called after camera device is opened.
    510      */
    511     private static List<CaptureResult.Key<?>> getWaiverKeysForCamera(StaticMetadata staticInfo) {
    512         List<CaptureResult.Key<?>> waiverKeys = new ArrayList<>();
    513 
    514         // Global waiver keys
    515         waiverKeys.add(CaptureResult.JPEG_GPS_LOCATION);
    516         waiverKeys.add(CaptureResult.JPEG_ORIENTATION);
    517         waiverKeys.add(CaptureResult.JPEG_QUALITY);
    518         waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
    519         waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
    520 
    521         // Keys only present when corresponding control is on are being
    522         // verified in its own functional test
    523         // Only present in certain tonemap mode. Test in CaptureRequestTest.
    524         waiverKeys.add(CaptureResult.TONEMAP_CURVE);
    525         waiverKeys.add(CaptureResult.TONEMAP_GAMMA);
    526         waiverKeys.add(CaptureResult.TONEMAP_PRESET_CURVE);
    527         // Only present when test pattern mode is SOLID_COLOR.
    528         // TODO: verify this key in test pattern test later
    529         waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
    530         // Only present when STATISTICS_LENS_SHADING_MAP_MODE is ON
    531         waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
    532         // Only present when STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES is ON
    533         waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
    534         // Only present when face detection is on
    535         waiverKeys.add(CaptureResult.STATISTICS_FACES);
    536         // Only present in reprocessing capture result.
    537         waiverKeys.add(CaptureResult.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR);
    538 
    539         //Keys not required if RAW is not supported
    540         if (!staticInfo.isCapabilitySupported(
    541                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
    542             waiverKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
    543             waiverKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
    544             waiverKeys.add(CaptureResult.SENSOR_NOISE_PROFILE);
    545         }
    546 
    547         //Keys for depth output capability
    548         if (!staticInfo.isCapabilitySupported(
    549                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT)) {
    550             waiverKeys.add(CaptureResult.LENS_POSE_ROTATION);
    551             waiverKeys.add(CaptureResult.LENS_POSE_TRANSLATION);
    552         }
    553 
    554         //Keys for lens distortion correction
    555         boolean distortionCorrectionSupported = false;
    556         int[] distortionModes = staticInfo.getCharacteristics().get(
    557                 CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES);
    558         if (distortionModes == null) {
    559             waiverKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE);
    560         } else {
    561             boolean gotNonOff = false;
    562             for (int mode : distortionModes) {
    563                 if (mode != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) {
    564                     gotNonOff = true;
    565                     distortionCorrectionSupported = true;
    566                     break;
    567                 }
    568             }
    569             if (!gotNonOff) {
    570                 waiverKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE);
    571             }
    572         }
    573 
    574         // These keys must present on either DEPTH or distortion correction devices
    575         if (!staticInfo.isCapabilitySupported(
    576                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) &&
    577                 !distortionCorrectionSupported) {
    578             waiverKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION);
    579             waiverKeys.add(CaptureResult.LENS_RADIAL_DISTORTION);
    580             waiverKeys.add(CaptureResult.LENS_DISTORTION);
    581         }
    582 
    583 
    584         // Waived if RAW output is not supported
    585         int[] outputFormats = staticInfo.getAvailableFormats(
    586                 StaticMetadata.StreamDirection.Output);
    587         boolean supportRaw = false;
    588         for (int format : outputFormats) {
    589             if (format == ImageFormat.RAW_SENSOR || format == ImageFormat.RAW10 ||
    590                     format == ImageFormat.RAW12 || format == ImageFormat.RAW_PRIVATE) {
    591                 supportRaw = true;
    592                 break;
    593             }
    594         }
    595         if (!supportRaw) {
    596             waiverKeys.add(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
    597         }
    598 
    599         // Waived if MONOCHROME capability
    600         if (!staticInfo.isCapabilitySupported(
    601                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME)) {
    602             waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
    603             waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
    604             waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
    605         }
    606 
    607         if (staticInfo.getAeMaxRegionsChecked() == 0) {
    608             waiverKeys.add(CaptureResult.CONTROL_AE_REGIONS);
    609         }
    610         if (staticInfo.getAwbMaxRegionsChecked() == 0) {
    611             waiverKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
    612         }
    613         if (staticInfo.getAfMaxRegionsChecked() == 0) {
    614             waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS);
    615         }
    616 
    617         // Keys for dynamic black/white levels
    618         if (!staticInfo.isOpticalBlackRegionSupported()) {
    619             waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
    620             waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
    621         }
    622 
    623         if (!staticInfo.isEnableZslSupported()) {
    624             waiverKeys.add(CaptureResult.CONTROL_ENABLE_ZSL);
    625         }
    626 
    627         if (!staticInfo.isAfSceneChangeSupported()) {
    628             waiverKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE);
    629         }
    630 
    631         if (!staticInfo.isOisDataModeSupported()) {
    632             waiverKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE);
    633             waiverKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES);
    634         }
    635 
    636         if (staticInfo.isHardwareLevelAtLeastFull()) {
    637             return waiverKeys;
    638         }
    639 
    640         /*
    641          * Hardware Level = LIMITED or LEGACY
    642          */
    643         // Key not present if certain control is not supported
    644         if (!staticInfo.isColorCorrectionSupported()) {
    645             waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
    646             waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
    647             waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
    648         }
    649 
    650         if (!staticInfo.isManualColorAberrationControlSupported()) {
    651             waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
    652         }
    653 
    654         if (!staticInfo.isManualToneMapSupported()) {
    655             waiverKeys.add(CaptureResult.TONEMAP_MODE);
    656         }
    657 
    658         if (!staticInfo.isEdgeModeControlSupported()) {
    659             waiverKeys.add(CaptureResult.EDGE_MODE);
    660         }
    661 
    662         if (!staticInfo.isHotPixelMapModeControlSupported()) {
    663             waiverKeys.add(CaptureResult.HOT_PIXEL_MODE);
    664         }
    665 
    666         if (!staticInfo.isNoiseReductionModeControlSupported()) {
    667             waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
    668         }
    669 
    670         if (!staticInfo.isManualLensShadingMapSupported()) {
    671             waiverKeys.add(CaptureResult.SHADING_MODE);
    672         }
    673 
    674         //Keys not required if neither MANUAL_SENSOR nor READ_SENSOR_SETTINGS is supported
    675         if (!staticInfo.isCapabilitySupported(
    676                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) &&
    677             !staticInfo.isCapabilitySupported(
    678                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
    679             waiverKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
    680             waiverKeys.add(CaptureResult.SENSOR_SENSITIVITY);
    681             waiverKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
    682             waiverKeys.add(CaptureResult.LENS_APERTURE);
    683         }
    684 
    685         if (!staticInfo.isCapabilitySupported(
    686                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
    687             waiverKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
    688             waiverKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
    689             waiverKeys.add(CaptureResult.LENS_FOCUS_RANGE);
    690             waiverKeys.add(CaptureResult.LENS_STATE);
    691             waiverKeys.add(CaptureResult.LENS_FILTER_DENSITY);
    692         }
    693 
    694         if (staticInfo.isHardwareLevelLimited() && staticInfo.isColorOutputSupported()) {
    695             return waiverKeys;
    696         }
    697 
    698         /*
    699          * Hardware Level = EXTERNAL
    700          */
    701         if (staticInfo.isExternalCamera()) {
    702             waiverKeys.add(CaptureResult.LENS_FOCAL_LENGTH);
    703             waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
    704             waiverKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
    705         }
    706 
    707         if (staticInfo.isExternalCamera() && staticInfo.isColorOutputSupported()) {
    708             return waiverKeys;
    709         }
    710 
    711         /*
    712          * Hardware Level = LEGACY or no regular output is supported
    713          */
    714         waiverKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
    715         waiverKeys.add(CaptureResult.CONTROL_AE_STATE);
    716         waiverKeys.add(CaptureResult.CONTROL_AWB_STATE);
    717         waiverKeys.add(CaptureResult.FLASH_STATE);
    718         waiverKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
    719         waiverKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
    720         waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE);
    721         waiverKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
    722         waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
    723         waiverKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
    724         waiverKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
    725 
    726         if (staticInfo.isHardwareLevelLegacy()) {
    727             return waiverKeys;
    728         }
    729 
    730         /*
    731          * Regular output not supported, only depth, waive color-output-related keys
    732          */
    733         waiverKeys.add(CaptureResult.CONTROL_SCENE_MODE);
    734         waiverKeys.add(CaptureResult.CONTROL_EFFECT_MODE);
    735         waiverKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE);
    736         waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
    737         waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
    738         waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
    739         waiverKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE);
    740         waiverKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION);
    741         waiverKeys.add(CaptureResult.CONTROL_AE_LOCK);
    742         waiverKeys.add(CaptureResult.CONTROL_AE_MODE);
    743         waiverKeys.add(CaptureResult.CONTROL_AF_MODE);
    744         waiverKeys.add(CaptureResult.CONTROL_AWB_MODE);
    745         waiverKeys.add(CaptureResult.CONTROL_AWB_LOCK);
    746         waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
    747         waiverKeys.add(CaptureResult.FLASH_MODE);
    748         waiverKeys.add(CaptureResult.SCALER_CROP_REGION);
    749 
    750         return waiverKeys;
    751     }
    752 
    753     /**
    754      * A capture listener implementation for collecting both partial and total results.
    755      *
    756      * <p> This is not a full-blown class and has some implicit assumptions. The class groups
    757      * capture results by capture request, so the user must guarantee each request this listener
    758      * is listening is unique. This class is not thread safe, so don't attach an instance object
    759      * with multiple handlers.</p>
    760      * */
    761     private static class TotalAndPartialResultListener
    762             extends CameraCaptureSession.CaptureCallback {
    763         static final int ERROR_DUPLICATED_REQUEST = 1 << 0;
    764         static final int ERROR_WRONG_CALLBACK_ORDER = 1 << 1;
    765 
    766         private final LinkedBlockingQueue<Pair<TotalCaptureResult, List<CaptureResult>> > mQueue =
    767                 new LinkedBlockingQueue<>();
    768         private final HashMap<CaptureRequest, List<CaptureResult>> mPartialResultsMap =
    769                 new HashMap<CaptureRequest, List<CaptureResult>>();
    770         private final HashSet<CaptureRequest> completedRequests = new HashSet<>();
    771         private int errorCode = 0;
    772 
    773         @Override
    774         public void onCaptureStarted(
    775             CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber)
    776         {
    777             checkCallbackOrder(request);
    778             createMapEntryIfNecessary(request);
    779         }
    780 
    781         @Override
    782         public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
    783                 TotalCaptureResult result) {
    784             try {
    785                 List<CaptureResult> partialResultsList = mPartialResultsMap.get(request);
    786                 if (partialResultsList == null) {
    787                     Log.w(TAG, "onCaptureCompleted: unknown request");
    788                 }
    789                 mQueue.put(new Pair<TotalCaptureResult, List<CaptureResult>>(
    790                         result, partialResultsList));
    791                 mPartialResultsMap.remove(request);
    792                 boolean newEntryAdded = completedRequests.add(request);
    793                 if (!newEntryAdded) {
    794                     Integer frame = (Integer) request.getTag();
    795                     Log.e(TAG, "Frame " + frame + "ERROR_DUPLICATED_REQUEST");
    796                     errorCode |= ERROR_DUPLICATED_REQUEST;
    797                 }
    798             } catch (InterruptedException e) {
    799                 throw new UnsupportedOperationException(
    800                         "Can't handle InterruptedException in onCaptureCompleted");
    801             }
    802         }
    803 
    804         @Override
    805         public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
    806                 CaptureResult partialResult) {
    807             createMapEntryIfNecessary(request);
    808             List<CaptureResult> partialResultsList = mPartialResultsMap.get(request);
    809             partialResultsList.add(partialResult);
    810         }
    811 
    812         private void createMapEntryIfNecessary(CaptureRequest request) {
    813             if (!mPartialResultsMap.containsKey(request)) {
    814                 // create a new entry in the map
    815                 mPartialResultsMap.put(request, new ArrayList<CaptureResult>());
    816             }
    817         }
    818 
    819         private void checkCallbackOrder(CaptureRequest request) {
    820             if (completedRequests.contains(request)) {
    821                 Integer frame = (Integer) request.getTag();
    822                 Log.e(TAG, "Frame " + frame + "ERROR_WRONG_CALLBACK_ORDER");
    823                 errorCode |= ERROR_WRONG_CALLBACK_ORDER;
    824             }
    825         }
    826 
    827         public Pair<TotalCaptureResult, List<CaptureResult>> getCaptureResultPairs(long timeout) {
    828             try {
    829                 Pair<TotalCaptureResult, List<CaptureResult>> result =
    830                         mQueue.poll(timeout, TimeUnit.MILLISECONDS);
    831                 assertNotNull("Wait for a capture result timed out in " + timeout + "ms", result);
    832                 return result;
    833             } catch (InterruptedException e) {
    834                 throw new UnsupportedOperationException("Unhandled interrupted exception", e);
    835             }
    836         }
    837 
    838         public int getErrorCode() {
    839             return errorCode;
    840         }
    841     }
    842 
    843     /**
    844      * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out
    845      * @hide keys.
    846      *
    847      */
    848 
    849     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
    850      * The key entries below this point are generated from metadata
    851      * definitions in /system/media/camera/docs. Do not modify by hand or
    852      * modify the comment blocks at the start or end.
    853      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
    854 
    855     private static List<CaptureResult.Key<?>> getAllCaptureResultKeys() {
    856         ArrayList<CaptureResult.Key<?>> resultKeys = new ArrayList<CaptureResult.Key<?>>();
    857         resultKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
    858         resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
    859         resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
    860         resultKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
    861         resultKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE);
    862         resultKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION);
    863         resultKeys.add(CaptureResult.CONTROL_AE_LOCK);
    864         resultKeys.add(CaptureResult.CONTROL_AE_MODE);
    865         resultKeys.add(CaptureResult.CONTROL_AE_REGIONS);
    866         resultKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
    867         resultKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
    868         resultKeys.add(CaptureResult.CONTROL_AF_MODE);
    869         resultKeys.add(CaptureResult.CONTROL_AF_REGIONS);
    870         resultKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
    871         resultKeys.add(CaptureResult.CONTROL_AWB_LOCK);
    872         resultKeys.add(CaptureResult.CONTROL_AWB_MODE);
    873         resultKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
    874         resultKeys.add(CaptureResult.CONTROL_CAPTURE_INTENT);
    875         resultKeys.add(CaptureResult.CONTROL_EFFECT_MODE);
    876         resultKeys.add(CaptureResult.CONTROL_MODE);
    877         resultKeys.add(CaptureResult.CONTROL_SCENE_MODE);
    878         resultKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE);
    879         resultKeys.add(CaptureResult.CONTROL_AE_STATE);
    880         resultKeys.add(CaptureResult.CONTROL_AF_STATE);
    881         resultKeys.add(CaptureResult.CONTROL_AWB_STATE);
    882         resultKeys.add(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
    883         resultKeys.add(CaptureResult.CONTROL_ENABLE_ZSL);
    884         resultKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE);
    885         resultKeys.add(CaptureResult.EDGE_MODE);
    886         resultKeys.add(CaptureResult.FLASH_MODE);
    887         resultKeys.add(CaptureResult.FLASH_STATE);
    888         resultKeys.add(CaptureResult.HOT_PIXEL_MODE);
    889         resultKeys.add(CaptureResult.JPEG_GPS_LOCATION);
    890         resultKeys.add(CaptureResult.JPEG_ORIENTATION);
    891         resultKeys.add(CaptureResult.JPEG_QUALITY);
    892         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
    893         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
    894         resultKeys.add(CaptureResult.LENS_APERTURE);
    895         resultKeys.add(CaptureResult.LENS_FILTER_DENSITY);
    896         resultKeys.add(CaptureResult.LENS_FOCAL_LENGTH);
    897         resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
    898         resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
    899         resultKeys.add(CaptureResult.LENS_POSE_ROTATION);
    900         resultKeys.add(CaptureResult.LENS_POSE_TRANSLATION);
    901         resultKeys.add(CaptureResult.LENS_FOCUS_RANGE);
    902         resultKeys.add(CaptureResult.LENS_STATE);
    903         resultKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION);
    904         resultKeys.add(CaptureResult.LENS_RADIAL_DISTORTION);
    905         resultKeys.add(CaptureResult.LENS_DISTORTION);
    906         resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
    907         resultKeys.add(CaptureResult.REQUEST_PIPELINE_DEPTH);
    908         resultKeys.add(CaptureResult.SCALER_CROP_REGION);
    909         resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
    910         resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
    911         resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
    912         resultKeys.add(CaptureResult.SENSOR_TIMESTAMP);
    913         resultKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
    914         resultKeys.add(CaptureResult.SENSOR_NOISE_PROFILE);
    915         resultKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
    916         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
    917         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
    918         resultKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
    919         resultKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
    920         resultKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
    921         resultKeys.add(CaptureResult.SHADING_MODE);
    922         resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
    923         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
    924         resultKeys.add(CaptureResult.STATISTICS_FACES);
    925         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
    926         resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
    927         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
    928         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE);
    929         resultKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE);
    930         resultKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES);
    931         resultKeys.add(CaptureResult.TONEMAP_CURVE);
    932         resultKeys.add(CaptureResult.TONEMAP_MODE);
    933         resultKeys.add(CaptureResult.TONEMAP_GAMMA);
    934         resultKeys.add(CaptureResult.TONEMAP_PRESET_CURVE);
    935         resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
    936         resultKeys.add(CaptureResult.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR);
    937         resultKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE);
    938 
    939         return resultKeys;
    940     }
    941 
    942     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
    943      * End generated code
    944      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
    945 }
    946