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