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