1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.cts; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.graphics.Rect; 22 import android.graphics.SurfaceTexture; 23 import android.hardware.Camera; 24 import android.hardware.camera2.CameraCharacteristics; 25 import android.hardware.camera2.CameraCharacteristics.Key; 26 import android.hardware.camera2.CameraDevice; 27 import android.hardware.camera2.CameraManager; 28 import android.hardware.camera2.CameraMetadata; 29 import android.hardware.camera2.CaptureRequest; 30 import android.hardware.camera2.CaptureResult; 31 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 32 import android.hardware.camera2.cts.helpers.StaticMetadata; 33 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 34 import android.hardware.camera2.params.BlackLevelPattern; 35 import android.hardware.camera2.params.ColorSpaceTransform; 36 import android.hardware.camera2.params.RecommendedStreamConfigurationMap; 37 import android.hardware.camera2.params.StreamConfigurationMap; 38 import android.media.CamcorderProfile; 39 import android.media.ImageReader; 40 import android.os.Build; 41 import android.util.DisplayMetrics; 42 import android.util.Log; 43 import android.util.Rational; 44 import android.util.Range; 45 import android.util.Size; 46 import android.util.Pair; 47 import android.util.Patterns; 48 import android.view.Display; 49 import android.view.Surface; 50 import android.view.WindowManager; 51 52 import com.android.compatibility.common.util.CddTest; 53 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.List; 57 import java.util.Objects; 58 import java.util.regex.Matcher; 59 import java.util.regex.Pattern; 60 import java.util.Set; 61 62 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 63 import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 64 65 import static org.mockito.Mockito.*; 66 67 /** 68 * Extended tests for static camera characteristics. 69 */ 70 public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { 71 private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw 72 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 73 74 private static final String PREFIX_ANDROID = "android"; 75 76 /* 77 * Constants for static RAW metadata. 78 */ 79 private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5 80 81 private List<CameraCharacteristics> mCharacteristics; 82 83 private static final Size FULLHD = new Size(1920, 1080); 84 private static final Size FULLHD_ALT = new Size(1920, 1088); 85 private static final Size HD = new Size(1280, 720); 86 private static final Size VGA = new Size(640, 480); 87 private static final Size QVGA = new Size(320, 240); 88 89 private static final long MIN_BACK_SENSOR_RESOLUTION = 2000000; 90 private static final long MIN_FRONT_SENSOR_RESOLUTION = VGA.getHeight() * VGA.getWidth(); 91 private static final long LOW_LATENCY_THRESHOLD_MS = 200; 92 private static final float LATENCY_TOLERANCE_FACTOR = 1.1f; // 10% tolerance 93 private static final float FOCAL_LENGTH_TOLERANCE = .01f; 94 private static final int MAX_NUM_IMAGES = 5; 95 private static final long PREVIEW_RUN_MS = 500; 96 private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30; 97 /* 98 * HW Levels short hand 99 */ 100 private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 101 private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 102 private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 103 private static final int LEVEL_3 = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3; 104 private static final int EXTERNAL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL; 105 private static final int OPT = Integer.MAX_VALUE; // For keys that are optional on all hardware levels. 106 107 /* 108 * Capabilities short hand 109 */ 110 private static final int NONE = -1; 111 private static final int BC = 112 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE; 113 private static final int MANUAL_SENSOR = 114 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR; 115 private static final int MANUAL_POSTPROC = 116 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING; 117 private static final int RAW = 118 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW; 119 private static final int YUV_REPROCESS = 120 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING; 121 private static final int OPAQUE_REPROCESS = 122 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING; 123 private static final int CONSTRAINED_HIGH_SPEED = 124 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO; 125 private static final int MONOCHROME = 126 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME; 127 private static final int HIGH_SPEED_FPS_LOWER_MIN = 30; 128 private static final int HIGH_SPEED_FPS_UPPER_MIN = 120; 129 130 @Override setUp()131 protected void setUp() throws Exception { 132 super.setUp(); 133 mCharacteristics = new ArrayList<>(); 134 for (int i = 0; i < mAllCameraIds.length; i++) { 135 mCharacteristics.add(mAllStaticInfo.get(mAllCameraIds[i]).getCharacteristics()); 136 } 137 } 138 139 @Override tearDown()140 protected void tearDown() throws Exception { 141 super.tearDown(); 142 mCharacteristics = null; 143 } 144 145 /** 146 * Test that the available stream configurations contain a few required formats and sizes. 147 */ 148 @CddTest(requirement="7.5.1/C-1-2") testAvailableStreamConfigs()149 public void testAvailableStreamConfigs() throws Exception { 150 boolean firstBackFacingCamera = true; 151 for (int i = 0; i < mAllCameraIds.length; i++) { 152 CameraCharacteristics c = mCharacteristics.get(i); 153 StreamConfigurationMap config = 154 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 155 assertNotNull(String.format("No stream configuration map found for: ID %s", 156 mAllCameraIds[i]), config); 157 int[] outputFormats = config.getOutputFormats(); 158 159 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 160 assertNotNull("android.request.availableCapabilities must never be null", 161 actualCapabilities); 162 163 // Check required formats exist (JPEG, and YUV_420_888). 164 if (!arrayContains(actualCapabilities, BC)) { 165 Log.i(TAG, "Camera " + mAllCameraIds[i] + 166 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 167 continue; 168 } 169 170 boolean isMonochromeWithY8 = arrayContains(actualCapabilities, MONOCHROME) 171 && arrayContains(outputFormats, ImageFormat.Y8); 172 boolean isHiddenPhysicalCamera = !arrayContains(mCameraIds, mAllCameraIds[i]); 173 boolean supportHeic = arrayContains(outputFormats, ImageFormat.HEIC); 174 175 assertArrayContains( 176 String.format("No valid YUV_420_888 preview formats found for: ID %s", 177 mAllCameraIds[i]), outputFormats, ImageFormat.YUV_420_888); 178 if (isMonochromeWithY8) { 179 assertArrayContains( 180 String.format("No valid Y8 preview formats found for: ID %s", 181 mAllCameraIds[i]), outputFormats, ImageFormat.Y8); 182 } 183 assertArrayContains(String.format("No JPEG image format for: ID %s", 184 mAllCameraIds[i]), outputFormats, ImageFormat.JPEG); 185 186 Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888); 187 Size[] y8Sizes = config.getOutputSizes(ImageFormat.Y8); 188 Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG); 189 Size[] heicSizes = config.getOutputSizes(ImageFormat.HEIC); 190 Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE); 191 192 CameraTestUtils.assertArrayNotEmpty(yuvSizes, 193 String.format("No sizes for preview format %x for: ID %s", 194 ImageFormat.YUV_420_888, mAllCameraIds[i])); 195 if (isMonochromeWithY8) { 196 CameraTestUtils.assertArrayNotEmpty(y8Sizes, 197 String.format("No sizes for preview format %x for: ID %s", 198 ImageFormat.Y8, mAllCameraIds[i])); 199 } 200 201 Rect activeRect = CameraTestUtils.getValueNotNull( 202 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 203 Size pixelArraySize = CameraTestUtils.getValueNotNull( 204 c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 205 206 int activeArrayHeight = activeRect.height(); 207 int activeArrayWidth = activeRect.width(); 208 long sensorResolution = pixelArraySize.getHeight() * pixelArraySize.getWidth() ; 209 Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); 210 assertNotNull("Can't get lens facing info for camera id: " + mAllCameraIds[i], 211 lensFacing); 212 213 // Check that the sensor sizes are atleast what the CDD specifies 214 switch(lensFacing) { 215 case CameraCharacteristics.LENS_FACING_FRONT: 216 assertTrue("Front Sensor resolution should be at least " + 217 MIN_FRONT_SENSOR_RESOLUTION + " pixels, is "+ sensorResolution, 218 sensorResolution >= MIN_FRONT_SENSOR_RESOLUTION); 219 break; 220 case CameraCharacteristics.LENS_FACING_BACK: 221 if (firstBackFacingCamera) { 222 assertTrue("Back Sensor resolution should be at least " 223 + MIN_BACK_SENSOR_RESOLUTION + 224 " pixels, is "+ sensorResolution, 225 sensorResolution >= MIN_BACK_SENSOR_RESOLUTION); 226 firstBackFacingCamera = false; 227 } 228 break; 229 default: 230 break; 231 } 232 233 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 234 235 if (activeArrayWidth >= FULLHD.getWidth() && 236 activeArrayHeight >= FULLHD.getHeight()) { 237 assertArrayContainsAnyOf(String.format( 238 "Required FULLHD size not found for format %x for: ID %s", 239 ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, 240 new Size[] {FULLHD, FULLHD_ALT}); 241 if (supportHeic) { 242 assertArrayContainsAnyOf(String.format( 243 "Required FULLHD size not found for format %x for: ID %s", 244 ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, 245 new Size[] {FULLHD, FULLHD_ALT}); 246 } 247 } 248 249 if (activeArrayWidth >= HD.getWidth() && 250 activeArrayHeight >= HD.getHeight()) { 251 assertArrayContains(String.format( 252 "Required HD size not found for format %x for: ID %s", 253 ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, HD); 254 if (supportHeic) { 255 assertArrayContains(String.format( 256 "Required HD size not found for format %x for: ID %s", 257 ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, HD); 258 } 259 } 260 261 if (activeArrayWidth >= VGA.getWidth() && 262 activeArrayHeight >= VGA.getHeight()) { 263 assertArrayContains(String.format( 264 "Required VGA size not found for format %x for: ID %s", 265 ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, VGA); 266 if (supportHeic) { 267 assertArrayContains(String.format( 268 "Required VGA size not found for format %x for: ID %s", 269 ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, VGA); 270 } 271 } 272 273 if (activeArrayWidth >= QVGA.getWidth() && 274 activeArrayHeight >= QVGA.getHeight()) { 275 assertArrayContains(String.format( 276 "Required QVGA size not found for format %x for: ID %s", 277 ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, QVGA); 278 if (supportHeic) { 279 assertArrayContains(String.format( 280 "Required QVGA size not found for format %x for: ID %s", 281 ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, QVGA); 282 } 283 284 } 285 286 ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes)); 287 ArrayList<Size> yuvSizesList = new ArrayList<>(Arrays.asList(yuvSizes)); 288 ArrayList<Size> privateSizesList = new ArrayList<>(Arrays.asList(privateSizes)); 289 boolean isExternalCamera = (hwLevel == 290 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 291 Size maxVideoSize = null; 292 if (isExternalCamera || isHiddenPhysicalCamera) { 293 // TODO: for now, use FULLHD 30 as largest possible video size for external camera. 294 // For hidden physical camera, since we don't require CamcorderProfile to be 295 // available, use FULLHD 30 as maximum video size as well. 296 List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes( 297 mAllCameraIds[i], mCameraManager, FULLHD); 298 for (Size sz : videoSizes) { 299 long minFrameDuration = config.getOutputMinFrameDuration( 300 android.media.MediaRecorder.class, sz); 301 // Give some margin for rounding error 302 if (minFrameDuration < (1e9 / 29.9)) { 303 maxVideoSize = sz; 304 break; 305 } 306 } 307 } else { 308 int cameraId = Integer.valueOf(mAllCameraIds[i]); 309 CamcorderProfile maxVideoProfile = CamcorderProfile.get( 310 cameraId, CamcorderProfile.QUALITY_HIGH); 311 maxVideoSize = new Size( 312 maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight); 313 } 314 if (maxVideoSize == null) { 315 fail("Camera " + mAllCameraIds[i] + " does not support any 30fps video output"); 316 } 317 318 // Handle FullHD special case first 319 if (jpegSizesList.contains(FULLHD)) { 320 if (compareHardwareLevel(hwLevel, LEVEL_3) >= 0 || hwLevel == FULL || 321 (hwLevel == LIMITED && 322 maxVideoSize.getWidth() >= FULLHD.getWidth() && 323 maxVideoSize.getHeight() >= FULLHD.getHeight())) { 324 boolean yuvSupportFullHD = yuvSizesList.contains(FULLHD) || 325 yuvSizesList.contains(FULLHD_ALT); 326 boolean privateSupportFullHD = privateSizesList.contains(FULLHD) || 327 privateSizesList.contains(FULLHD_ALT); 328 assertTrue("Full device FullHD YUV size not found", yuvSupportFullHD); 329 assertTrue("Full device FullHD PRIVATE size not found", privateSupportFullHD); 330 331 if (isMonochromeWithY8) { 332 ArrayList<Size> y8SizesList = new ArrayList<>(Arrays.asList(y8Sizes)); 333 boolean y8SupportFullHD = y8SizesList.contains(FULLHD) || 334 y8SizesList.contains(FULLHD_ALT); 335 assertTrue("Full device FullHD Y8 size not found", y8SupportFullHD); 336 } 337 } 338 // remove all FullHD or FullHD_Alt sizes for the remaining of the test 339 jpegSizesList.remove(FULLHD); 340 jpegSizesList.remove(FULLHD_ALT); 341 } 342 343 // Check all sizes other than FullHD 344 if (hwLevel == LIMITED) { 345 // Remove all jpeg sizes larger than max video size 346 ArrayList<Size> toBeRemoved = new ArrayList<>(); 347 for (Size size : jpegSizesList) { 348 if (size.getWidth() >= maxVideoSize.getWidth() && 349 size.getHeight() >= maxVideoSize.getHeight()) { 350 toBeRemoved.add(size); 351 } 352 } 353 jpegSizesList.removeAll(toBeRemoved); 354 } 355 356 if (compareHardwareLevel(hwLevel, LEVEL_3) >= 0 || hwLevel == FULL || 357 hwLevel == LIMITED) { 358 if (!yuvSizesList.containsAll(jpegSizesList)) { 359 for (Size s : jpegSizesList) { 360 if (!yuvSizesList.contains(s)) { 361 fail("Size " + s + " not found in YUV format"); 362 } 363 } 364 } 365 366 if (isMonochromeWithY8) { 367 ArrayList<Size> y8SizesList = new ArrayList<>(Arrays.asList(y8Sizes)); 368 if (!y8SizesList.containsAll(jpegSizesList)) { 369 for (Size s : jpegSizesList) { 370 if (!y8SizesList.contains(s)) { 371 fail("Size " + s + " not found in Y8 format"); 372 } 373 } 374 } 375 } 376 } 377 378 if (!privateSizesList.containsAll(yuvSizesList)) { 379 for (Size s : yuvSizesList) { 380 if (!privateSizesList.contains(s)) { 381 fail("Size " + s + " not found in PRIVATE format"); 382 } 383 } 384 } 385 } 386 } 387 verifyCommonRecommendedConfiguration(String id, CameraCharacteristics c, RecommendedStreamConfigurationMap config, boolean checkNoInput, boolean checkNoHighRes, boolean checkNoHighSpeed, boolean checkNoPrivate, boolean checkNoDepth)388 private void verifyCommonRecommendedConfiguration(String id, CameraCharacteristics c, 389 RecommendedStreamConfigurationMap config, boolean checkNoInput, 390 boolean checkNoHighRes, boolean checkNoHighSpeed, boolean checkNoPrivate, 391 boolean checkNoDepth) { 392 StreamConfigurationMap fullConfig = c.get( 393 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 394 assertNotNull(String.format("No stream configuration map found for ID: %s!", id), 395 fullConfig); 396 397 Set<Integer> recommendedOutputFormats = config.getOutputFormats(); 398 399 if (checkNoInput) { 400 Set<Integer> inputFormats = config.getInputFormats(); 401 assertTrue(String.format("Recommended configuration must not include any input " + 402 "streams for ID: %s", id), 403 ((inputFormats == null) || (inputFormats.size() == 0))); 404 } 405 406 if (checkNoHighRes) { 407 for (int format : recommendedOutputFormats) { 408 Set<Size> highResSizes = config.getHighResolutionOutputSizes(format); 409 assertTrue(String.format("Recommended configuration should not include any " + 410 "high resolution sizes, which cannot operate at full " + 411 "BURST_CAPTURE rate for ID: %s", id), 412 ((highResSizes == null) || (highResSizes.size() == 0))); 413 } 414 } 415 416 if (checkNoHighSpeed) { 417 Set<Size> highSpeedSizes = config.getHighSpeedVideoSizes(); 418 assertTrue(String.format("Recommended configuration must not include any high " + 419 "speed configurations for ID: %s", id), 420 ((highSpeedSizes == null) || (highSpeedSizes.size() == 0))); 421 } 422 423 int[] exhaustiveOutputFormats = fullConfig.getOutputFormats(); 424 for (Integer formatInteger : recommendedOutputFormats) { 425 int format = formatInteger.intValue(); 426 assertArrayContains(String.format("Unsupported recommended output format: %d for " + 427 "ID: %s ", format, id), exhaustiveOutputFormats, format); 428 Set<Size> recommendedSizes = config.getOutputSizes(format); 429 430 switch (format) { 431 case ImageFormat.PRIVATE: 432 if (checkNoPrivate) { 433 fail(String.format("Recommended configuration must not include " + 434 "PRIVATE format entries for ID: %s", id)); 435 } 436 437 Set<Size> classOutputSizes = config.getOutputSizes(ImageReader.class); 438 assertCollectionContainsAnyOf(String.format("Recommended output sizes for " + 439 "ImageReader class don't match the output sizes for the " + 440 "corresponding format for ID: %s", id), classOutputSizes, 441 recommendedSizes); 442 break; 443 case ImageFormat.DEPTH16: 444 case ImageFormat.DEPTH_POINT_CLOUD: 445 if (checkNoDepth) { 446 fail(String.format("Recommended configuration must not include any DEPTH " + 447 "formats for ID: %s", id)); 448 } 449 break; 450 default: 451 } 452 Size [] exhaustiveSizes = fullConfig.getOutputSizes(format); 453 for (Size sz : recommendedSizes) { 454 assertArrayContains(String.format("Unsupported recommended size %s for " + 455 "format: %d for ID: %s", sz.toString(), format, id), 456 exhaustiveSizes, sz); 457 458 long recommendedMinDuration = config.getOutputMinFrameDuration(format, sz); 459 long availableMinDuration = fullConfig.getOutputMinFrameDuration(format, sz); 460 assertTrue(String.format("Recommended minimum frame duration %d for size " + 461 "%s format: %d doesn't match with currently available minimum" + 462 " frame duration of %d for ID: %s", recommendedMinDuration, 463 sz.toString(), format, availableMinDuration, id), 464 (recommendedMinDuration == availableMinDuration)); 465 long recommendedStallDuration = config.getOutputStallDuration(format, sz); 466 long availableStallDuration = fullConfig.getOutputStallDuration(format, sz); 467 assertTrue(String.format("Recommended stall duration %d for size %s" + 468 " format: %d doesn't match with currently available stall " + 469 "duration of %d for ID: %s", recommendedStallDuration, 470 sz.toString(), format, availableStallDuration, id), 471 (recommendedStallDuration == availableStallDuration)); 472 473 ImageReader reader = ImageReader.newInstance(sz.getWidth(), sz.getHeight(), format, 474 /*maxImages*/1); 475 Surface readerSurface = reader.getSurface(); 476 assertTrue(String.format("ImageReader surface using format %d and size %s is not" + 477 " supported for ID: %s", format, sz.toString(), id), 478 config.isOutputSupportedFor(readerSurface)); 479 if (format == ImageFormat.PRIVATE) { 480 long classMinDuration = config.getOutputMinFrameDuration(ImageReader.class, sz); 481 assertTrue(String.format("Recommended minimum frame duration %d for size " + 482 "%s format: %d doesn't match with the duration %d for " + 483 "ImageReader class of the same size", recommendedMinDuration, 484 sz.toString(), format, classMinDuration), 485 classMinDuration == recommendedMinDuration); 486 long classStallDuration = config.getOutputStallDuration(ImageReader.class, sz); 487 assertTrue(String.format("Recommended stall duration %d for size " + 488 "%s format: %d doesn't match with the stall duration %d for " + 489 "ImageReader class of the same size", recommendedStallDuration, 490 sz.toString(), format, classStallDuration), 491 classStallDuration == recommendedStallDuration); 492 } 493 } 494 } 495 } 496 verifyRecommendedPreviewConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap previewConfig)497 private void verifyRecommendedPreviewConfiguration(String cameraId, CameraCharacteristics c, 498 RecommendedStreamConfigurationMap previewConfig) { 499 verifyCommonRecommendedConfiguration(cameraId, c, previewConfig, /*checkNoInput*/ true, 500 /*checkNoHighRes*/ true, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 501 /*checkNoDepth*/ true); 502 503 Set<Integer> outputFormats = previewConfig.getOutputFormats(); 504 assertTrue(String.format("No valid YUV_420_888 and PRIVATE preview " + 505 "formats found in recommended preview configuration for ID: %s", cameraId), 506 outputFormats.containsAll(Arrays.asList(new Integer(ImageFormat.YUV_420_888), 507 new Integer(ImageFormat.PRIVATE)))); 508 } 509 verifyRecommendedVideoConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap videoConfig)510 private void verifyRecommendedVideoConfiguration(String cameraId, CameraCharacteristics c, 511 RecommendedStreamConfigurationMap videoConfig) { 512 verifyCommonRecommendedConfiguration(cameraId, c, videoConfig, /*checkNoInput*/ true, 513 /*checkNoHighRes*/ true, /*checkNoHighSpeed*/ false, /*checkNoPrivate*/false, 514 /*checkNoDepth*/ true); 515 516 Set<Size> highSpeedSizes = videoConfig.getHighSpeedVideoSizes(); 517 StreamConfigurationMap fullConfig = c.get( 518 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 519 assertNotNull("No stream configuration map found!", fullConfig); 520 Size [] availableHighSpeedSizes = fullConfig.getHighSpeedVideoSizes(); 521 if ((highSpeedSizes != null) && (highSpeedSizes.size() > 0)) { 522 for (Size sz : highSpeedSizes) { 523 assertArrayContains(String.format("Recommended video configuration includes " + 524 "unsupported high speed configuration with size %s for ID: %s", 525 sz.toString(), cameraId), availableHighSpeedSizes, sz); 526 Set<Range<Integer>> highSpeedFpsRanges = 527 videoConfig.getHighSpeedVideoFpsRangesFor(sz); 528 Range<Integer> [] availableHighSpeedFpsRanges = 529 fullConfig.getHighSpeedVideoFpsRangesFor(sz); 530 for (Range<Integer> fpsRange : highSpeedFpsRanges) { 531 assertArrayContains(String.format("Recommended video configuration includes " + 532 "unsupported high speed fps range [%d %d] for ID: %s", 533 fpsRange.getLower().intValue(), fpsRange.getUpper().intValue(), 534 cameraId), availableHighSpeedFpsRanges, fpsRange); 535 } 536 } 537 } 538 539 final int[] profileList = { 540 CamcorderProfile.QUALITY_2160P, 541 CamcorderProfile.QUALITY_1080P, 542 CamcorderProfile.QUALITY_480P, 543 CamcorderProfile.QUALITY_720P, 544 CamcorderProfile.QUALITY_CIF, 545 CamcorderProfile.QUALITY_HIGH, 546 CamcorderProfile.QUALITY_LOW, 547 CamcorderProfile.QUALITY_QCIF, 548 CamcorderProfile.QUALITY_QVGA, 549 }; 550 Set<Size> privateSizeSet = videoConfig.getOutputSizes(ImageFormat.PRIVATE); 551 for (int profile : profileList) { 552 int idx = Integer.valueOf(cameraId); 553 if (CamcorderProfile.hasProfile(idx, profile)) { 554 CamcorderProfile videoProfile = CamcorderProfile.get(idx, profile); 555 Size profileSize = new Size(videoProfile.videoFrameWidth, 556 videoProfile.videoFrameHeight); 557 assertCollectionContainsAnyOf(String.format("Recommended video configuration " + 558 "doesn't include supported video profile size %s with Private format " + 559 "for ID: %s", profileSize.toString(), cameraId), privateSizeSet, 560 Arrays.asList(profileSize)); 561 } 562 } 563 } 564 isSizeWithinSensorMargin(Size sz, Size sensorSize)565 private Pair<Boolean, Size> isSizeWithinSensorMargin(Size sz, Size sensorSize) { 566 final float SIZE_ERROR_MARGIN = 0.03f; 567 float croppedWidth = (float)sensorSize.getWidth(); 568 float croppedHeight = (float)sensorSize.getHeight(); 569 float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight(); 570 float maxAspectRatio = (float)sz.getWidth() / (float)sz.getHeight(); 571 if (sensorAspectRatio < maxAspectRatio) { 572 croppedHeight = (float)sensorSize.getWidth() / maxAspectRatio; 573 } else if (sensorAspectRatio > maxAspectRatio) { 574 croppedWidth = (float)sensorSize.getHeight() * maxAspectRatio; 575 } 576 Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight); 577 578 Boolean match = new Boolean( 579 (sz.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) && 580 sz.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) && 581 sz.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) && 582 sz.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN))); 583 584 return Pair.create(match, croppedSensorSize); 585 } 586 verifyRecommendedSnapshotConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap snapshotConfig)587 private void verifyRecommendedSnapshotConfiguration(String cameraId, CameraCharacteristics c, 588 RecommendedStreamConfigurationMap snapshotConfig) { 589 verifyCommonRecommendedConfiguration(cameraId, c, snapshotConfig, /*checkNoInput*/ true, 590 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/false, 591 /*checkNoDepth*/ false); 592 Rect activeRect = CameraTestUtils.getValueNotNull( 593 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 594 Size arraySize = new Size(activeRect.width(), activeRect.height()); 595 596 Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes(ImageFormat.JPEG); 597 Size[] snapshotSizes = new Size[snapshotSizeSet.size()]; 598 snapshotSizes = snapshotSizeSet.toArray(snapshotSizes); 599 Size maxJpegSize = CameraTestUtils.getMaxSize(snapshotSizes); 600 assertTrue(String.format("Maximum recommended Jpeg size %s should be within 3 percent " + 601 "of the area of the advertised array size %s for ID: %s", 602 maxJpegSize.toString(), arraySize.toString(), cameraId), 603 isSizeWithinSensorMargin(maxJpegSize, arraySize).first.booleanValue()); 604 } 605 verifyRecommendedVideoSnapshotConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap videoSnapshotConfig, RecommendedStreamConfigurationMap videoConfig)606 private void verifyRecommendedVideoSnapshotConfiguration(String cameraId, 607 CameraCharacteristics c, 608 RecommendedStreamConfigurationMap videoSnapshotConfig, 609 RecommendedStreamConfigurationMap videoConfig) { 610 verifyCommonRecommendedConfiguration(cameraId, c, videoSnapshotConfig, 611 /*checkNoInput*/ true, /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, 612 /*checkNoPrivate*/ true, /*checkNoDepth*/ true); 613 614 Set<Integer> outputFormats = videoSnapshotConfig.getOutputFormats(); 615 assertCollectionContainsAnyOf(String.format("No valid JPEG format found " + 616 "in recommended video snapshot configuration for ID: %s", cameraId), 617 outputFormats, Arrays.asList(new Integer(ImageFormat.JPEG))); 618 assertTrue(String.format("Recommended video snapshot configuration must only advertise " + 619 "JPEG format for ID: %s", cameraId), outputFormats.size() == 1); 620 621 Set<Size> privateVideoSizeSet = videoConfig.getOutputSizes(ImageFormat.PRIVATE); 622 Size[] privateVideoSizes = new Size[privateVideoSizeSet.size()]; 623 privateVideoSizes = privateVideoSizeSet.toArray(privateVideoSizes); 624 Size maxVideoSize = CameraTestUtils.getMaxSize(privateVideoSizes); 625 Set<Size> outputSizes = videoSnapshotConfig.getOutputSizes(ImageFormat.JPEG); 626 assertCollectionContainsAnyOf(String.format("The maximum recommended video size %s " + 627 "should be present in the recommended video snapshot configurations for ID: %s", 628 maxVideoSize.toString(), cameraId), outputSizes, Arrays.asList(maxVideoSize)); 629 } 630 verifyRecommendedRawConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap rawConfig)631 private void verifyRecommendedRawConfiguration(String cameraId, 632 CameraCharacteristics c, RecommendedStreamConfigurationMap rawConfig) { 633 verifyCommonRecommendedConfiguration(cameraId, c, rawConfig, /*checkNoInput*/ true, 634 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ true, 635 /*checkNoDepth*/ true); 636 637 Set<Integer> outputFormats = rawConfig.getOutputFormats(); 638 for (Integer outputFormatInteger : outputFormats) { 639 int outputFormat = outputFormatInteger.intValue(); 640 switch (outputFormat) { 641 case ImageFormat.RAW10: 642 case ImageFormat.RAW12: 643 case ImageFormat.RAW_PRIVATE: 644 case ImageFormat.RAW_SENSOR: 645 break; 646 default: 647 fail(String.format("Recommended raw configuration map must not contain " + 648 " non-RAW formats like: %d for ID: %s", outputFormat, cameraId)); 649 650 } 651 } 652 } 653 verifyRecommendedZSLConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap zslConfig)654 private void verifyRecommendedZSLConfiguration(String cameraId, CameraCharacteristics c, 655 RecommendedStreamConfigurationMap zslConfig) { 656 verifyCommonRecommendedConfiguration(cameraId, c, zslConfig, /*checkNoInput*/ false, 657 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 658 /*checkNoDepth*/ false); 659 660 StreamConfigurationMap fullConfig = 661 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 662 assertNotNull(String.format("No stream configuration map found for ID: %s!", cameraId), 663 fullConfig); 664 Set<Integer> inputFormats = zslConfig.getInputFormats(); 665 int [] availableInputFormats = fullConfig.getInputFormats(); 666 for (Integer inputFormatInteger : inputFormats) { 667 int inputFormat = inputFormatInteger.intValue(); 668 assertArrayContains(String.format("Recommended ZSL configuration includes " + 669 "unsupported input format %d for ID: %s", inputFormat, cameraId), 670 availableInputFormats, inputFormat); 671 672 Set<Size> inputSizes = zslConfig.getInputSizes(inputFormat); 673 Size [] availableInputSizes = fullConfig.getInputSizes(inputFormat); 674 assertTrue(String.format("Recommended ZSL configuration input format %d includes " + 675 "invalid input sizes for ID: %s", inputFormat, cameraId), 676 ((inputSizes != null) && (inputSizes.size() > 0))); 677 for (Size inputSize : inputSizes) { 678 assertArrayContains(String.format("Recommended ZSL configuration includes " + 679 "unsupported input format %d with size %s ID: %s", inputFormat, 680 inputSize.toString(), cameraId), availableInputSizes, inputSize); 681 } 682 Set<Integer> validOutputFormats = zslConfig.getValidOutputFormatsForInput(inputFormat); 683 int [] availableValidOutputFormats = fullConfig.getValidOutputFormatsForInput( 684 inputFormat); 685 for (Integer outputFormatInteger : validOutputFormats) { 686 int outputFormat = outputFormatInteger.intValue(); 687 assertArrayContains(String.format("Recommended ZSL configuration includes " + 688 "unsupported output format %d for input %s ID: %s", outputFormat, 689 inputFormat, cameraId), availableValidOutputFormats, outputFormat); 690 } 691 } 692 } 693 checkFormatLatency(int format, long latencyThresholdMs, RecommendedStreamConfigurationMap configMap)694 private void checkFormatLatency(int format, long latencyThresholdMs, 695 RecommendedStreamConfigurationMap configMap) throws Exception { 696 Set<Size> availableSizes = configMap.getOutputSizes(format); 697 assertNotNull(String.format("No available sizes for output format: %d", format), 698 availableSizes); 699 700 ImageReader previewReader = null; 701 long threshold = (long) (latencyThresholdMs * LATENCY_TOLERANCE_FACTOR); 702 // for each resolution, check that the end-to-end latency doesn't exceed the given threshold 703 for (Size sz : availableSizes) { 704 try { 705 // Create ImageReaders, capture session and requests 706 final ImageReader.OnImageAvailableListener mockListener = mock( 707 ImageReader.OnImageAvailableListener.class); 708 createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mockListener); 709 Size previewSize = mOrderedPreviewSizes.get(0); 710 previewReader = createImageReader(previewSize, ImageFormat.YUV_420_888, 711 MAX_NUM_IMAGES, new CameraTestUtils.ImageDropperListener()); 712 Surface previewSurface = previewReader.getSurface(); 713 List<Surface> surfaces = new ArrayList<Surface>(); 714 surfaces.add(previewSurface); 715 surfaces.add(mReaderSurface); 716 createSession(surfaces); 717 CaptureRequest.Builder captureBuilder = 718 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 719 captureBuilder.addTarget(previewSurface); 720 CaptureRequest request = captureBuilder.build(); 721 722 // Let preview run for a while 723 startCapture(request, /*repeating*/ true, new SimpleCaptureCallback(), mHandler); 724 Thread.sleep(PREVIEW_RUN_MS); 725 726 // Start capture. 727 captureBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 728 captureBuilder.addTarget(mReaderSurface); 729 request = captureBuilder.build(); 730 731 for (int i = 0; i < MAX_NUM_IMAGES; i++) { 732 startCapture(request, /*repeating*/ false, new SimpleCaptureCallback(), 733 mHandler); 734 verify(mockListener, timeout(threshold).times(1)).onImageAvailable( 735 any(ImageReader.class)); 736 reset(mockListener); 737 } 738 739 // stop capture. 740 stopCapture(/*fast*/ false); 741 } finally { 742 closeDefaultImageReader(); 743 744 if (previewReader != null) { 745 previewReader.close(); 746 previewReader = null; 747 } 748 } 749 750 } 751 } 752 verifyRecommendedLowLatencyConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap lowLatencyConfig)753 private void verifyRecommendedLowLatencyConfiguration(String cameraId, CameraCharacteristics c, 754 RecommendedStreamConfigurationMap lowLatencyConfig) throws Exception { 755 verifyCommonRecommendedConfiguration(cameraId, c, lowLatencyConfig, /*checkNoInput*/ true, 756 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 757 /*checkNoDepth*/ true); 758 759 try { 760 openDevice(cameraId); 761 762 Set<Integer> formats = lowLatencyConfig.getOutputFormats(); 763 for (Integer format : formats) { 764 checkFormatLatency(format.intValue(), LOW_LATENCY_THRESHOLD_MS, lowLatencyConfig); 765 } 766 } finally { 767 closeDevice(cameraId); 768 } 769 770 } 771 testRecommendedStreamConfigurations()772 public void testRecommendedStreamConfigurations() throws Exception { 773 for (int i = 0; i < mAllCameraIds.length; i++) { 774 CameraCharacteristics c = mCharacteristics.get(i); 775 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 776 assertNotNull("android.request.availableCapabilities must never be null", 777 actualCapabilities); 778 779 if (!arrayContains(actualCapabilities, BC)) { 780 Log.i(TAG, "Camera " + mAllCameraIds[i] + 781 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 782 continue; 783 } 784 785 try { 786 RecommendedStreamConfigurationMap map = c.getRecommendedStreamConfigurationMap( 787 RecommendedStreamConfigurationMap.USECASE_PREVIEW - 1); 788 fail("Recommended configuration map shouldn't be available for invalid " + 789 "use case!"); 790 } catch (IllegalArgumentException e) { 791 //Expected continue 792 } 793 794 try { 795 RecommendedStreamConfigurationMap map = c.getRecommendedStreamConfigurationMap( 796 RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT + 1); 797 fail("Recommended configuration map shouldn't be available for invalid " + 798 "use case!"); 799 } catch (IllegalArgumentException e) { 800 //Expected continue 801 } 802 803 RecommendedStreamConfigurationMap previewConfig = 804 c.getRecommendedStreamConfigurationMap( 805 RecommendedStreamConfigurationMap.USECASE_PREVIEW); 806 RecommendedStreamConfigurationMap videoRecordingConfig = 807 c.getRecommendedStreamConfigurationMap( 808 RecommendedStreamConfigurationMap.USECASE_RECORD); 809 RecommendedStreamConfigurationMap videoSnapshotConfig = 810 c.getRecommendedStreamConfigurationMap( 811 RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT); 812 RecommendedStreamConfigurationMap snapshotConfig = 813 c.getRecommendedStreamConfigurationMap( 814 RecommendedStreamConfigurationMap.USECASE_SNAPSHOT); 815 RecommendedStreamConfigurationMap rawConfig = 816 c.getRecommendedStreamConfigurationMap( 817 RecommendedStreamConfigurationMap.USECASE_RAW); 818 RecommendedStreamConfigurationMap zslConfig = 819 c.getRecommendedStreamConfigurationMap( 820 RecommendedStreamConfigurationMap.USECASE_ZSL); 821 RecommendedStreamConfigurationMap lowLatencyConfig = 822 c.getRecommendedStreamConfigurationMap( 823 RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT); 824 if ((previewConfig == null) && (videoRecordingConfig == null) && 825 (videoSnapshotConfig == null) && (snapshotConfig == null) && 826 (rawConfig == null) && (zslConfig == null) && (lowLatencyConfig == null)) { 827 Log.i(TAG, "Camera " + mAllCameraIds[i] + 828 " doesn't support recommended configurations, skipping test"); 829 continue; 830 } 831 832 assertNotNull(String.format("Mandatory recommended preview configuration map not " + 833 "found for: ID %s", mAllCameraIds[i]), previewConfig); 834 verifyRecommendedPreviewConfiguration(mAllCameraIds[i], c, previewConfig); 835 836 assertNotNull(String.format("Mandatory recommended video recording configuration map " + 837 "not found for: ID %s", mAllCameraIds[i]), videoRecordingConfig); 838 verifyRecommendedVideoConfiguration(mAllCameraIds[i], c, videoRecordingConfig); 839 840 assertNotNull(String.format("Mandatory recommended video snapshot configuration map " + 841 "not found for: ID %s", mAllCameraIds[i]), videoSnapshotConfig); 842 verifyRecommendedVideoSnapshotConfiguration(mAllCameraIds[i], c, videoSnapshotConfig, 843 videoRecordingConfig); 844 845 assertNotNull(String.format("Mandatory recommended snapshot configuration map not " + 846 "found for: ID %s", mAllCameraIds[i]), snapshotConfig); 847 verifyRecommendedSnapshotConfiguration(mAllCameraIds[i], c, snapshotConfig); 848 849 if (arrayContains(actualCapabilities, RAW)) { 850 assertNotNull(String.format("Mandatory recommended raw configuration map not " + 851 "found for: ID %s", mAllCameraIds[i]), rawConfig); 852 verifyRecommendedRawConfiguration(mAllCameraIds[i], c, rawConfig); 853 } 854 855 if (arrayContains(actualCapabilities, OPAQUE_REPROCESS) || 856 arrayContains(actualCapabilities, YUV_REPROCESS)) { 857 assertNotNull(String.format("Mandatory recommended ZSL configuration map not " + 858 "found for: ID %s", mAllCameraIds[i]), zslConfig); 859 verifyRecommendedZSLConfiguration(mAllCameraIds[i], c, zslConfig); 860 } 861 862 if (lowLatencyConfig != null) { 863 verifyRecommendedLowLatencyConfiguration(mAllCameraIds[i], c, lowLatencyConfig); 864 } 865 } 866 } 867 868 /** 869 * Test {@link CameraCharacteristics#getKeys} 870 */ testKeys()871 public void testKeys() { 872 for (int i = 0; i < mAllCameraIds.length; i++) { 873 CameraCharacteristics c = mCharacteristics.get(i); 874 mCollector.setCameraId(mAllCameraIds[i]); 875 876 if (VERBOSE) { 877 Log.v(TAG, "testKeys - testing characteristics for camera " + mAllCameraIds[i]); 878 } 879 880 List<CameraCharacteristics.Key<?>> allKeys = c.getKeys(); 881 assertNotNull("Camera characteristics keys must not be null", allKeys); 882 assertFalse("Camera characteristics keys must have at least 1 key", 883 allKeys.isEmpty()); 884 885 for (CameraCharacteristics.Key<?> key : allKeys) { 886 assertKeyPrefixValid(key.getName()); 887 888 // All characteristics keys listed must never be null 889 mCollector.expectKeyValueNotNull(c, key); 890 891 // TODO: add a check that key must not be @hide 892 } 893 894 /* 895 * List of keys that must be present in camera characteristics (not null). 896 * 897 * Keys for LIMITED, FULL devices might be available despite lacking either 898 * the hardware level or the capability. This is *OK*. This only lists the 899 * *minimal* requirements for a key to be listed. 900 * 901 * LEGACY devices are a bit special since they map to api1 devices, so we know 902 * for a fact most keys are going to be illegal there so they should never be 903 * available. 904 * 905 * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to 906 * do the actual checking. 907 */ 908 { 909 // (Key Name) (HW Level) (Capabilities <Var-Arg>) 910 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES , OPT , BC ); 911 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES , OPT , BC ); 912 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES , OPT , BC ); 913 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES , OPT , BC ); 914 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , OPT , BC ); 915 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , OPT , BC ); 916 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , OPT , BC ); 917 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE , OPT , BC ); 918 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , OPT , BC ); 919 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , OPT , BC ); 920 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , OPT , BC ); 921 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , OPT , BC ); 922 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , OPT , BC ); 923 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE , OPT , BC ); 924 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE , OPT , BC ); 925 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF , OPT , BC ); 926 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB , OPT , BC ); 927 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES , FULL , NONE ); 928 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE , OPT , BC ); 929 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES , OPT , RAW ); 930 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , OPT , BC ); 931 expectKeyAvailable(c, CameraCharacteristics.INFO_VERSION , OPT , NONE ); 932 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES , OPT , BC ); 933 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING , OPT , BC ); 934 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES , FULL , MANUAL_SENSOR ); 935 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES , FULL , MANUAL_SENSOR ); 936 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION , LIMITED , BC ); 937 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION , LIMITED , MANUAL_SENSOR ); 938 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE , LIMITED , BC ); 939 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE , LIMITED , BC ); 940 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT , BC ); 941 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES , OPT , BC ); 942 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS , OPT , YUV_REPROCESS, OPAQUE_REPROCESS); 943 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , CONSTRAINED_HIGH_SPEED); 944 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC , OPT , BC ); 945 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING , OPT , BC ); 946 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW , OPT , BC ); 947 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT , OPT , BC ); 948 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH , OPT , BC ); 949 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM , OPT , BC ); 950 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , BC ); 951 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE , OPT , BC ); 952 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN , FULL , RAW ); 953 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE , OPT , BC, RAW ); 954 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT , FULL , RAW ); 955 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE , FULL , MANUAL_SENSOR ); 956 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION , FULL , MANUAL_SENSOR ); 957 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE , OPT , BC ); 958 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE , FULL , MANUAL_SENSOR ); 959 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL , OPT , RAW ); 960 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE , OPT , BC ); 961 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY , FULL , MANUAL_SENSOR ); 962 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION , OPT , BC ); 963 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES , LIMITED , MANUAL_POSTPROC, RAW ); 964 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES , OPT , BC ); 965 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES , OPT , RAW ); 966 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED , RAW ); 967 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT , OPT , BC ); 968 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY , OPT , BC ); 969 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES , FULL , MANUAL_POSTPROC ); 970 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS , FULL , MANUAL_POSTPROC ); 971 972 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line 973 974 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list 975 } 976 977 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 978 assertNotNull("android.request.availableCapabilities must never be null", 979 actualCapabilities); 980 boolean isMonochrome = arrayContains(actualCapabilities, 981 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME); 982 if (!isMonochrome) { 983 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1 , OPT , RAW ); 984 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1 , OPT , RAW ); 985 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1 , OPT , RAW ); 986 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1 , OPT , RAW ); 987 988 989 // Only check for these if the second reference illuminant is included 990 if (allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)) { 991 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2 , OPT , RAW ); 992 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2 , OPT , RAW ); 993 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2 , OPT , RAW ); 994 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2 , OPT , RAW ); 995 } 996 } 997 998 // Required key if any of RAW format output is supported 999 StreamConfigurationMap config = 1000 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1001 assertNotNull(String.format("No stream configuration map found for: ID %s", 1002 mAllCameraIds[i]), config); 1003 if (config.isOutputSupportedFor(ImageFormat.RAW_SENSOR) || 1004 config.isOutputSupportedFor(ImageFormat.RAW10) || 1005 config.isOutputSupportedFor(ImageFormat.RAW12) || 1006 config.isOutputSupportedFor(ImageFormat.RAW_PRIVATE)) { 1007 expectKeyAvailable(c, 1008 CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, OPT, BC); 1009 } 1010 1011 // External Camera exceptional keys 1012 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1013 boolean isExternalCamera = (hwLevel == 1014 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 1015 if (!isExternalCamera) { 1016 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS , OPT , BC ); 1017 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES , OPT , BC ); 1018 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE , OPT , BC ); 1019 } 1020 1021 1022 // Verify version is a short text string. 1023 if (allKeys.contains(CameraCharacteristics.INFO_VERSION)) { 1024 final String TEXT_REGEX = "[\\p{Alnum}\\p{Punct}\\p{Space}]*"; 1025 final int MAX_VERSION_LENGTH = 256; 1026 1027 String version = c.get(CameraCharacteristics.INFO_VERSION); 1028 mCollector.expectTrue("Version contains non-text characters: " + version, 1029 version.matches(TEXT_REGEX)); 1030 mCollector.expectLessOrEqual("Version too long: " + version, MAX_VERSION_LENGTH, 1031 version.length()); 1032 } 1033 } 1034 } 1035 1036 /** 1037 * Test values for static metadata used by the RAW capability. 1038 */ testStaticRawCharacteristics()1039 public void testStaticRawCharacteristics() { 1040 for (int i = 0; i < mAllCameraIds.length; i++) { 1041 CameraCharacteristics c = mCharacteristics.get(i); 1042 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1043 assertNotNull("android.request.availableCapabilities must never be null", 1044 actualCapabilities); 1045 if (!arrayContains(actualCapabilities, 1046 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1047 Log.i(TAG, "RAW capability is not supported in camera " + mAllCameraIds[i] + 1048 ". Skip the test."); 1049 continue; 1050 } 1051 1052 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1053 if (actualHwLevel != null && actualHwLevel == FULL) { 1054 mCollector.expectKeyValueContains(c, 1055 CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, 1056 CameraCharacteristics.HOT_PIXEL_MODE_FAST); 1057 } 1058 mCollector.expectKeyValueContains(c, 1059 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false); 1060 mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL, 1061 MIN_ALLOWABLE_WHITELEVEL); 1062 1063 1064 boolean isMonochrome = arrayContains(actualCapabilities, 1065 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME); 1066 if (!isMonochrome) { 1067 mCollector.expectKeyValueIsIn(c, 1068 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 1069 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, 1070 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, 1071 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, 1072 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR); 1073 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 1074 1075 mCollector.expectKeyValueInRange(c, 1076 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1, 1077 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 1078 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 1079 // Only check the range if the second reference illuminant is avaliable 1080 if (c.get(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2) != null) { 1081 mCollector.expectKeyValueInRange(c, 1082 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 1083 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 1084 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 1085 } 1086 1087 Rational[] zeroes = new Rational[9]; 1088 Arrays.fill(zeroes, Rational.ZERO); 1089 1090 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 1091 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 1092 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 1093 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 1094 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 1095 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 1096 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 1097 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 1098 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 1099 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 1100 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 1101 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 1102 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 1103 } else { 1104 mCollector.expectKeyValueIsIn(c, 1105 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 1106 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO, 1107 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR); 1108 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 1109 } 1110 1111 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 1112 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 1113 if (blackLevel != null) { 1114 String blackLevelPatternString = blackLevel.toString(); 1115 if (VERBOSE) { 1116 Log.v(TAG, "Black level pattern: " + blackLevelPatternString); 1117 } 1118 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 1119 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 1120 if (isMonochrome) { 1121 for (int index = 1; index < BlackLevelPattern.COUNT; index++) { 1122 mCollector.expectEquals( 1123 "Monochrome camera 2x2 channels blacklevel value must be the same.", 1124 blackLevelPattern[index], blackLevelPattern[0]); 1125 } 1126 } 1127 1128 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 1129 if (whitelevel != null) { 1130 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 1131 whitelevel); 1132 } else { 1133 mCollector.addMessage( 1134 "No WhiteLevel available, cannot check BlackLevelPattern range."); 1135 } 1136 } 1137 1138 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 1139 } 1140 } 1141 1142 /** 1143 * Test values for the available session keys. 1144 */ testStaticSessionKeys()1145 public void testStaticSessionKeys() throws Exception { 1146 for (CameraCharacteristics c : mCharacteristics) { 1147 List<CaptureRequest.Key<?>> availableSessionKeys = c.getAvailableSessionKeys(); 1148 if (availableSessionKeys == null) { 1149 continue; 1150 } 1151 List<CaptureRequest.Key<?>> availableRequestKeys = c.getAvailableCaptureRequestKeys(); 1152 1153 //Every session key should be part of the available request keys 1154 for (CaptureRequest.Key<?> key : availableSessionKeys) { 1155 assertTrue("Session key:" + key.getName() + " not present in the available capture " 1156 + "request keys!", availableRequestKeys.contains(key)); 1157 } 1158 } 1159 } 1160 1161 /** 1162 * Test values for static metadata used by the BURST capability. 1163 */ testStaticBurstCharacteristics()1164 public void testStaticBurstCharacteristics() throws Exception { 1165 for (int i = 0; i < mAllCameraIds.length; i++) { 1166 CameraCharacteristics c = mCharacteristics.get(i); 1167 int[] actualCapabilities = CameraTestUtils.getValueNotNull( 1168 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1169 1170 // Check if the burst capability is defined 1171 boolean haveBurstCapability = arrayContains(actualCapabilities, 1172 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 1173 boolean haveBC = arrayContains(actualCapabilities, 1174 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 1175 1176 if(haveBurstCapability && !haveBC) { 1177 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined"); 1178 } 1179 1180 if (!haveBC) continue; 1181 1182 StreamConfigurationMap config = 1183 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1184 assertNotNull(String.format("No stream configuration map found for: ID %s", 1185 mAllCameraIds[i]), config); 1186 Rect activeRect = CameraTestUtils.getValueNotNull( 1187 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 1188 Size sensorSize = new Size(activeRect.width(), activeRect.height()); 1189 1190 // Ensure that max YUV size matches max JPEG size 1191 Size maxYuvSize = CameraTestUtils.getMaxSize( 1192 config.getOutputSizes(ImageFormat.YUV_420_888)); 1193 Size maxFastYuvSize = maxYuvSize; 1194 1195 Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888); 1196 Size maxSlowYuvSizeLessThan24M = null; 1197 if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) { 1198 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes); 1199 final int SIZE_24MP_BOUND = 24000000; 1200 maxSlowYuvSizeLessThan24M = 1201 CameraTestUtils.getMaxSizeWithBound(slowYuvSizes, SIZE_24MP_BOUND); 1202 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize}); 1203 } 1204 1205 Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat( 1206 ImageFormat.JPEG, mAllCameraIds[i], mCameraManager)); 1207 1208 boolean haveMaxYuv = maxYuvSize != null ? 1209 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 1210 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 1211 1212 Pair<Boolean, Size> maxYuvMatchSensorPair = isSizeWithinSensorMargin(maxYuvSize, 1213 sensorSize); 1214 1215 // No need to do null check since framework will generate the key if HAL don't supply 1216 boolean haveAeLock = CameraTestUtils.getValueNotNull( 1217 c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 1218 boolean haveAwbLock = CameraTestUtils.getValueNotNull( 1219 c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 1220 1221 // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps 1222 1223 long maxFastYuvRate = 1224 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize); 1225 final long MIN_8MP_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps 1226 boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS; 1227 1228 final int SIZE_8MP_BOUND = 8000000; 1229 boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) > 1230 SIZE_8MP_BOUND; 1231 1232 // Ensure that max YUV output smaller than 24MP is fast enough 1233 // - needs to be at least 10 fps 1234 final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps 1235 long maxYuvRate = maxFastYuvRate; 1236 if (maxSlowYuvSizeLessThan24M != null) { 1237 maxYuvRate = config.getOutputMinFrameDuration( 1238 ImageFormat.YUV_420_888, maxSlowYuvSizeLessThan24M); 1239 } 1240 boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS; 1241 1242 // Ensure that there's an FPS range that's fast enough to capture at above 1243 // minFrameDuration, for full-auto bursts at the fast resolutions 1244 Range[] fpsRanges = CameraTestUtils.getValueNotNull( 1245 c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 1246 float minYuvFps = 1.f / maxFastYuvRate; 1247 1248 boolean haveFastAeTargetFps = false; 1249 for (Range<Integer> r : fpsRanges) { 1250 if (r.getLower() >= minYuvFps) { 1251 haveFastAeTargetFps = true; 1252 break; 1253 } 1254 } 1255 1256 // Ensure that maximum sync latency is small enough for fast setting changes, even if 1257 // it's not quite per-frame 1258 1259 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 1260 assertNotNull(String.format("No sync latency declared for ID %s", mAllCameraIds[i]), 1261 maxSyncLatencyValue); 1262 1263 int maxSyncLatency = maxSyncLatencyValue; 1264 final long MAX_LATENCY_BOUND = 4; 1265 boolean haveFastSyncLatency = 1266 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 1267 1268 if (haveBurstCapability) { 1269 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!", 1270 slowYuvSizes != null); 1271 assertTrue( 1272 String.format("BURST-capable camera device %s does not have maximum YUV " + 1273 "size that is at least max JPEG size", 1274 mAllCameraIds[i]), 1275 haveMaxYuv); 1276 assertTrue( 1277 String.format("BURST-capable camera device %s max-resolution " + 1278 "YUV frame rate is too slow" + 1279 "(%d ns min frame duration reported, less than %d ns expected)", 1280 mAllCameraIds[i], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS), 1281 haveMaxYuvRate); 1282 assertTrue( 1283 String.format("BURST-capable camera device %s >= 8MP YUV output " + 1284 "frame rate is too slow" + 1285 "(%d ns min frame duration reported, less than %d ns expected)", 1286 mAllCameraIds[i], maxYuvRate, MIN_8MP_DURATION_BOUND_NS), 1287 haveFastYuvRate); 1288 assertTrue( 1289 String.format("BURST-capable camera device %s does not list an AE target " + 1290 " FPS range with min FPS >= %f, for full-AUTO bursts", 1291 mAllCameraIds[i], minYuvFps), 1292 haveFastAeTargetFps); 1293 assertTrue( 1294 String.format("BURST-capable camera device %s YUV sync latency is too long" + 1295 "(%d frames reported, [0, %d] frames expected)", 1296 mAllCameraIds[i], maxSyncLatency, MAX_LATENCY_BOUND), 1297 haveFastSyncLatency); 1298 assertTrue( 1299 String.format("BURST-capable camera device %s max YUV size %s should be" + 1300 "close to active array size %s or cropped active array size %s", 1301 mAllCameraIds[i], maxYuvSize.toString(), sensorSize.toString(), 1302 maxYuvMatchSensorPair.second.toString()), 1303 maxYuvMatchSensorPair.first.booleanValue()); 1304 assertTrue( 1305 String.format("BURST-capable camera device %s does not support AE lock", 1306 mAllCameraIds[i]), 1307 haveAeLock); 1308 assertTrue( 1309 String.format("BURST-capable camera device %s does not support AWB lock", 1310 mAllCameraIds[i]), 1311 haveAwbLock); 1312 } else { 1313 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!", 1314 slowYuvSizes == null); 1315 assertTrue( 1316 String.format("Camera device %s has all the requirements for BURST" + 1317 " capability but does not report it!", mAllCameraIds[i]), 1318 !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps && 1319 haveFastSyncLatency && maxYuvMatchSensorPair.first.booleanValue() && 1320 haveAeLock && haveAwbLock)); 1321 } 1322 } 1323 } 1324 1325 /** 1326 * Check reprocessing capabilities. 1327 */ testReprocessingCharacteristics()1328 public void testReprocessingCharacteristics() { 1329 for (int i = 0; i < mAllCameraIds.length; i++) { 1330 Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mAllCameraIds[i]); 1331 1332 CameraCharacteristics c = mCharacteristics.get(i); 1333 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1334 assertNotNull("android.request.availableCapabilities must never be null", 1335 capabilities); 1336 boolean supportYUV = arrayContains(capabilities, 1337 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 1338 boolean supportOpaque = arrayContains(capabilities, 1339 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 1340 StreamConfigurationMap configs = 1341 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1342 Integer maxNumInputStreams = 1343 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 1344 int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES); 1345 int[] availableNoiseReductionModes = c.get( 1346 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES); 1347 1348 int[] inputFormats = configs.getInputFormats(); 1349 int[] outputFormats = configs.getOutputFormats(); 1350 boolean isMonochromeWithY8 = arrayContains(capabilities, MONOCHROME) 1351 && arrayContains(outputFormats, ImageFormat.Y8); 1352 1353 boolean supportZslEdgeMode = false; 1354 boolean supportZslNoiseReductionMode = false; 1355 boolean supportHiQNoiseReductionMode = false; 1356 boolean supportHiQEdgeMode = false; 1357 1358 if (availableEdgeModes != null) { 1359 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 1360 contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 1361 supportHiQEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 1362 contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY); 1363 } 1364 1365 if (availableNoiseReductionModes != null) { 1366 supportZslNoiseReductionMode = Arrays.asList( 1367 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 1368 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 1369 supportHiQNoiseReductionMode = Arrays.asList( 1370 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 1371 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 1372 } 1373 1374 if (supportYUV || supportOpaque) { 1375 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 1376 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 1377 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " + 1378 "not supported", supportZslEdgeMode); 1379 mCollector.expectTrue("Support reprocessing but " + 1380 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported", 1381 supportZslNoiseReductionMode); 1382 1383 // For reprocessing, if we only require OFF and ZSL mode, it will be just like jpeg 1384 // encoding. We implicitly require FAST to make reprocessing meaningful, which means 1385 // that we also require HIGH_QUALITY. 1386 mCollector.expectTrue("Support reprocessing but EDGE_MODE_HIGH_QUALITY is " + 1387 "not supported", supportHiQEdgeMode); 1388 mCollector.expectTrue("Support reprocessing but " + 1389 "NOISE_REDUCTION_MODE_HIGH_QUALITY is not supported", 1390 supportHiQNoiseReductionMode); 1391 1392 // Verify mandatory input formats are supported 1393 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing", 1394 !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888)); 1395 mCollector.expectTrue("Y8 input must be supported for YUV reprocessing on " + 1396 "MONOCHROME devices with Y8 support", !supportYUV || !isMonochromeWithY8 1397 || arrayContains(inputFormats, ImageFormat.Y8)); 1398 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing", 1399 !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE)); 1400 1401 // max capture stall must be reported if one of the reprocessing is supported. 1402 final int MAX_ALLOWED_STALL_FRAMES = 4; 1403 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 1404 mCollector.expectTrue("max capture stall must be non-null and no larger than " 1405 + MAX_ALLOWED_STALL_FRAMES, 1406 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 1407 1408 for (int input : inputFormats) { 1409 // Verify mandatory output formats are supported 1410 int[] outputFormatsForInput = configs.getValidOutputFormatsForInput(input); 1411 mCollector.expectTrue( 1412 "YUV_420_888 output must be supported for reprocessing", 1413 input == ImageFormat.Y8 1414 || arrayContains(outputFormatsForInput, ImageFormat.YUV_420_888)); 1415 mCollector.expectTrue( 1416 "Y8 output must be supported for reprocessing on MONOCHROME devices with" 1417 + " Y8 support", !isMonochromeWithY8 || input == ImageFormat.YUV_420_888 1418 || arrayContains(outputFormatsForInput, ImageFormat.Y8)); 1419 mCollector.expectTrue("JPEG output must be supported for reprocessing", 1420 arrayContains(outputFormatsForInput, ImageFormat.JPEG)); 1421 1422 // Verify camera can output the reprocess input formats and sizes. 1423 Size[] inputSizes = configs.getInputSizes(input); 1424 Size[] outputSizes = configs.getOutputSizes(input); 1425 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 1426 mCollector.expectTrue("no input size supported for format " + input, 1427 inputSizes.length > 0); 1428 mCollector.expectTrue("no output size supported for format " + input, 1429 outputSizes.length > 0); 1430 1431 for (Size inputSize : inputSizes) { 1432 mCollector.expectTrue("Camera must be able to output the supported " + 1433 "reprocessing input size", 1434 arrayContains(outputSizes, inputSize) || 1435 arrayContains(highResOutputSizes, inputSize)); 1436 } 1437 } 1438 } else { 1439 mCollector.expectTrue("Doesn't support reprocessing but report input format: " + 1440 Arrays.toString(inputFormats), inputFormats.length == 0); 1441 mCollector.expectTrue("Doesn't support reprocessing but max number of input " + 1442 "stream is " + maxNumInputStreams, 1443 maxNumInputStreams == null || maxNumInputStreams == 0); 1444 mCollector.expectTrue("Doesn't support reprocessing but " + 1445 "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode); 1446 mCollector.expectTrue("Doesn't support reprocessing but " + 1447 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported", 1448 !supportZslNoiseReductionMode); 1449 } 1450 } 1451 } 1452 1453 /** 1454 * Check depth output capability 1455 */ testDepthOutputCharacteristics()1456 public void testDepthOutputCharacteristics() { 1457 for (int i = 0; i < mAllCameraIds.length; i++) { 1458 Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mAllCameraIds[i]); 1459 1460 CameraCharacteristics c = mCharacteristics.get(i); 1461 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1462 assertNotNull("android.request.availableCapabilities must never be null", 1463 capabilities); 1464 boolean supportDepth = arrayContains(capabilities, 1465 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 1466 StreamConfigurationMap configs = 1467 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1468 1469 int[] outputFormats = configs.getOutputFormats(); 1470 boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16); 1471 1472 Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE); 1473 1474 float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 1475 float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 1476 Integer poseReference = c.get(CameraCharacteristics.LENS_POSE_REFERENCE); 1477 float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 1478 float[] distortion = getLensDistortion(c); 1479 Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 1480 Rect precorrectionArray = c.get( 1481 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 1482 Rect activeArray = c.get( 1483 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 1484 float jpegAspectRatioThreshold = .01f; 1485 boolean jpegSizeMatch = false; 1486 1487 // Verify pre-correction array encloses active array 1488 mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " + 1489 precorrectionArray.top + ", " + precorrectionArray.right + ", " + 1490 precorrectionArray.bottom + "] does not enclose activeArray[" + 1491 activeArray.left + ", " + activeArray.top + ", " + activeArray.right + 1492 ", " + activeArray.bottom, 1493 precorrectionArray.contains(activeArray.left, activeArray.top) && 1494 precorrectionArray.contains(activeArray.right-1, activeArray.bottom-1)); 1495 1496 // Verify pixel array encloses pre-correction array 1497 mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " + 1498 precorrectionArray.top + ", " + precorrectionArray.right + ", " + 1499 precorrectionArray.bottom + "] isn't enclosed by pixelArray[" + 1500 pixelArraySize.getWidth() + ", " + pixelArraySize.getHeight() + "]", 1501 precorrectionArray.left >= 0 && 1502 precorrectionArray.left < pixelArraySize.getWidth() && 1503 precorrectionArray.right > 0 && 1504 precorrectionArray.right <= pixelArraySize.getWidth() && 1505 precorrectionArray.top >= 0 && 1506 precorrectionArray.top < pixelArraySize.getHeight() && 1507 precorrectionArray.bottom > 0 && 1508 precorrectionArray.bottom <= pixelArraySize.getHeight()); 1509 1510 if (supportDepth) { 1511 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16", 1512 hasDepth16); 1513 if (hasDepth16) { 1514 Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16); 1515 Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG); 1516 mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!", 1517 depthSizes != null && depthSizes.length > 0); 1518 if (depthSizes != null) { 1519 for (Size depthSize : depthSizes) { 1520 mCollector.expectTrue("All depth16 sizes must be positive", 1521 depthSize.getWidth() > 0 && depthSize.getHeight() > 0); 1522 long minFrameDuration = configs.getOutputMinFrameDuration( 1523 ImageFormat.DEPTH16, depthSize); 1524 mCollector.expectTrue("Non-negative min frame duration for depth size " 1525 + depthSize + " expected, got " + minFrameDuration, 1526 minFrameDuration >= 0); 1527 long stallDuration = configs.getOutputStallDuration( 1528 ImageFormat.DEPTH16, depthSize); 1529 mCollector.expectTrue("Non-negative stall duration for depth size " 1530 + depthSize + " expected, got " + stallDuration, 1531 stallDuration >= 0); 1532 if ((jpegSizes != null) && (!jpegSizeMatch)) { 1533 for (Size jpegSize : jpegSizes) { 1534 if (jpegSize.equals(depthSize)) { 1535 jpegSizeMatch = true; 1536 break; 1537 } else { 1538 float depthAR = (float) depthSize.getWidth() / 1539 (float) depthSize.getHeight(); 1540 float jpegAR = (float) jpegSize.getWidth() / 1541 (float) jpegSize.getHeight(); 1542 if (Math.abs(depthAR - jpegAR) <= 1543 jpegAspectRatioThreshold) { 1544 jpegSizeMatch = true; 1545 break; 1546 } 1547 } 1548 } 1549 } 1550 } 1551 } 1552 } 1553 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) { 1554 Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD); 1555 mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " + 1556 "but no sizes for DEPTH_POINT_CLOUD supported!", 1557 depthCloudSizes != null && depthCloudSizes.length > 0); 1558 if (depthCloudSizes != null) { 1559 for (Size depthCloudSize : depthCloudSizes) { 1560 mCollector.expectTrue("All depth point cloud sizes must be nonzero", 1561 depthCloudSize.getWidth() > 0); 1562 mCollector.expectTrue("All depth point cloud sizes must be N x 1", 1563 depthCloudSize.getHeight() == 1); 1564 long minFrameDuration = configs.getOutputMinFrameDuration( 1565 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 1566 mCollector.expectTrue("Non-negative min frame duration for depth size " 1567 + depthCloudSize + " expected, got " + minFrameDuration, 1568 minFrameDuration >= 0); 1569 long stallDuration = configs.getOutputStallDuration( 1570 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 1571 mCollector.expectTrue("Non-negative stall duration for depth size " 1572 + depthCloudSize + " expected, got " + stallDuration, 1573 stallDuration >= 0); 1574 } 1575 } 1576 } 1577 if (arrayContains(outputFormats, ImageFormat.DEPTH_JPEG)) { 1578 mCollector.expectTrue("Supports DEPTH_JPEG but has no DEPTH16 support!", 1579 hasDepth16); 1580 mCollector.expectTrue("Supports DEPTH_JPEG but DEPTH_IS_EXCLUSIVE is not " + 1581 "defined", depthIsExclusive != null); 1582 mCollector.expectTrue("Supports DEPTH_JPEG but DEPTH_IS_EXCLUSIVE is true", 1583 !depthIsExclusive.booleanValue()); 1584 Size[] depthJpegSizes = configs.getOutputSizes(ImageFormat.DEPTH_JPEG); 1585 mCollector.expectTrue("Supports DEPTH_JPEG " + 1586 "but no sizes for DEPTH_JPEG supported!", 1587 depthJpegSizes != null && depthJpegSizes.length > 0); 1588 mCollector.expectTrue("Supports DEPTH_JPEG but there are no JPEG sizes with" + 1589 " matching DEPTH16 aspect ratio", jpegSizeMatch); 1590 if (depthJpegSizes != null) { 1591 for (Size depthJpegSize : depthJpegSizes) { 1592 mCollector.expectTrue("All depth jpeg sizes must be nonzero", 1593 depthJpegSize.getWidth() > 0 && depthJpegSize.getHeight() > 0); 1594 long minFrameDuration = configs.getOutputMinFrameDuration( 1595 ImageFormat.DEPTH_JPEG, depthJpegSize); 1596 mCollector.expectTrue("Non-negative min frame duration for depth jpeg" + 1597 " size " + depthJpegSize + " expected, got " + minFrameDuration, 1598 minFrameDuration >= 0); 1599 long stallDuration = configs.getOutputStallDuration( 1600 ImageFormat.DEPTH_JPEG, depthJpegSize); 1601 mCollector.expectTrue("Non-negative stall duration for depth jpeg size " 1602 + depthJpegSize + " expected, got " + stallDuration, 1603 stallDuration >= 0); 1604 } 1605 } 1606 } else { 1607 boolean canSupportDynamicDepth = jpegSizeMatch && !depthIsExclusive; 1608 mCollector.expectTrue("Device must support DEPTH_JPEG, please check whether " + 1609 "library libdepthphoto.so is part of the device PRODUCT_PACKAGES", 1610 !canSupportDynamicDepth); 1611 } 1612 1613 1614 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined", 1615 depthIsExclusive != null); 1616 1617 verifyLensCalibration(poseRotation, poseTranslation, poseReference, 1618 cameraIntrinsics, distortion, precorrectionArray); 1619 1620 } else { 1621 boolean hasFields = 1622 hasDepth16 && (poseTranslation != null) && 1623 (poseRotation != null) && (cameraIntrinsics != null) && 1624 (distortion != null) && (depthIsExclusive != null); 1625 1626 mCollector.expectTrue( 1627 "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed", 1628 !hasFields); 1629 1630 boolean reportCalibration = poseTranslation != null || 1631 poseRotation != null || cameraIntrinsics !=null; 1632 // Verify calibration keys are co-existing 1633 if (reportCalibration) { 1634 mCollector.expectTrue( 1635 "Calibration keys must be co-existing", 1636 poseTranslation != null && poseRotation != null && 1637 cameraIntrinsics !=null); 1638 } 1639 1640 boolean reportDistortion = distortion != null; 1641 if (reportDistortion) { 1642 mCollector.expectTrue( 1643 "Calibration keys must present where distortion is reported", 1644 reportCalibration); 1645 } 1646 } 1647 } 1648 } 1649 verifyLensCalibration(float[] poseRotation, float[] poseTranslation, Integer poseReference, float[] cameraIntrinsics, float[] distortion, Rect precorrectionArray)1650 private void verifyLensCalibration(float[] poseRotation, float[] poseTranslation, 1651 Integer poseReference, float[] cameraIntrinsics, float[] distortion, 1652 Rect precorrectionArray) { 1653 1654 mCollector.expectTrue( 1655 "LENS_POSE_ROTATION not right size", 1656 poseRotation != null && poseRotation.length == 4); 1657 mCollector.expectTrue( 1658 "LENS_POSE_TRANSLATION not right size", 1659 poseTranslation != null && poseTranslation.length == 3); 1660 mCollector.expectTrue( 1661 "LENS_POSE_REFERENCE is not defined", 1662 poseReference != null); 1663 mCollector.expectTrue( 1664 "LENS_INTRINSIC_CALIBRATION not right size", 1665 cameraIntrinsics != null && cameraIntrinsics.length == 5); 1666 mCollector.expectTrue( 1667 "LENS_DISTORTION not right size", 1668 distortion != null && distortion.length == 6); 1669 1670 if (poseRotation != null && poseRotation.length == 4) { 1671 float normSq = 1672 poseRotation[0] * poseRotation[0] + 1673 poseRotation[1] * poseRotation[1] + 1674 poseRotation[2] * poseRotation[2] + 1675 poseRotation[3] * poseRotation[3]; 1676 mCollector.expectTrue( 1677 "LENS_POSE_ROTATION quarternion must be unit-length", 1678 0.9999f < normSq && normSq < 1.0001f); 1679 1680 // TODO: Cross-validate orientation/facing and poseRotation 1681 } 1682 1683 if (poseTranslation != null && poseTranslation.length == 3) { 1684 float normSq = 1685 poseTranslation[0] * poseTranslation[0] + 1686 poseTranslation[1] * poseTranslation[1] + 1687 poseTranslation[2] * poseTranslation[2]; 1688 mCollector.expectTrue("Pose translation is larger than 1 m", 1689 normSq < 1.f); 1690 } 1691 1692 if (poseReference != null) { 1693 int ref = poseReference; 1694 boolean validReference = false; 1695 switch (ref) { 1696 case CameraCharacteristics.LENS_POSE_REFERENCE_PRIMARY_CAMERA: 1697 case CameraCharacteristics.LENS_POSE_REFERENCE_GYROSCOPE: 1698 // Allowed values 1699 validReference = true; 1700 break; 1701 default: 1702 } 1703 mCollector.expectTrue("POSE_REFERENCE has unknown value", validReference); 1704 } 1705 1706 mCollector.expectTrue("Does not have precorrection active array defined", 1707 precorrectionArray != null); 1708 1709 if (cameraIntrinsics != null && precorrectionArray != null) { 1710 float fx = cameraIntrinsics[0]; 1711 float fy = cameraIntrinsics[1]; 1712 float cx = cameraIntrinsics[2]; 1713 float cy = cameraIntrinsics[3]; 1714 float s = cameraIntrinsics[4]; 1715 mCollector.expectTrue("Optical center expected to be within precorrection array", 1716 0 <= cx && cx < precorrectionArray.width() && 1717 0 <= cy && cy < precorrectionArray.height()); 1718 1719 // TODO: Verify focal lengths and skew are reasonable 1720 } 1721 1722 if (distortion != null) { 1723 // TODO: Verify radial distortion 1724 } 1725 1726 } 1727 1728 /** 1729 * Cross-check StreamConfigurationMap output 1730 */ testStreamConfigurationMap()1731 public void testStreamConfigurationMap() throws Exception { 1732 for (int i = 0; i < mAllCameraIds.length; i++) { 1733 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mAllCameraIds[i]); 1734 CameraCharacteristics c = mCharacteristics.get(i); 1735 StreamConfigurationMap config = 1736 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1737 assertNotNull(String.format("No stream configuration map found for: ID %s", 1738 mAllCameraIds[i]), config); 1739 1740 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1741 assertNotNull("android.request.availableCapabilities must never be null", 1742 actualCapabilities); 1743 1744 if (arrayContains(actualCapabilities, BC)) { 1745 assertTrue("ImageReader must be supported", 1746 config.isOutputSupportedFor(android.media.ImageReader.class)); 1747 assertTrue("MediaRecorder must be supported", 1748 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 1749 assertTrue("MediaCodec must be supported", 1750 config.isOutputSupportedFor(android.media.MediaCodec.class)); 1751 assertTrue("Allocation must be supported", 1752 config.isOutputSupportedFor(android.renderscript.Allocation.class)); 1753 assertTrue("SurfaceHolder must be supported", 1754 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 1755 assertTrue("SurfaceTexture must be supported", 1756 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 1757 1758 assertTrue("YUV_420_888 must be supported", 1759 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 1760 assertTrue("JPEG must be supported", 1761 config.isOutputSupportedFor(ImageFormat.JPEG)); 1762 } else { 1763 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed", 1764 !config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 1765 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed", 1766 !config.isOutputSupportedFor(ImageFormat.JPEG)); 1767 } 1768 1769 // Check RAW 1770 1771 if (arrayContains(actualCapabilities, 1772 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1773 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 1774 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 1775 } 1776 1777 // Cross check public formats and sizes 1778 1779 int[] supportedFormats = config.getOutputFormats(); 1780 for (int format : supportedFormats) { 1781 assertTrue("Format " + format + " fails cross check", 1782 config.isOutputSupportedFor(format)); 1783 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes( 1784 Arrays.asList(config.getOutputSizes(format)), /*ascending*/true); 1785 if (arrayContains(actualCapabilities, 1786 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 1787 supportedSizes.addAll( 1788 Arrays.asList(config.getHighResolutionOutputSizes(format))); 1789 supportedSizes = CameraTestUtils.getAscendingOrderSizes( 1790 supportedSizes, /*ascending*/true); 1791 } 1792 assertTrue("Supported format " + format + " has no sizes listed", 1793 supportedSizes.size() > 0); 1794 for (int j = 0; j < supportedSizes.size(); j++) { 1795 Size size = supportedSizes.get(j); 1796 if (VERBOSE) { 1797 Log.v(TAG, 1798 String.format("Testing camera %s, format %d, size %s", 1799 mAllCameraIds[i], format, size.toString())); 1800 } 1801 1802 long stallDuration = config.getOutputStallDuration(format, size); 1803 switch(format) { 1804 case ImageFormat.YUV_420_888: 1805 assertTrue("YUV_420_888 may not have a non-zero stall duration", 1806 stallDuration == 0); 1807 break; 1808 case ImageFormat.JPEG: 1809 case ImageFormat.RAW_SENSOR: 1810 final float TOLERANCE_FACTOR = 2.0f; 1811 long prevDuration = 0; 1812 if (j > 0) { 1813 prevDuration = config.getOutputStallDuration( 1814 format, supportedSizes.get(j - 1)); 1815 } 1816 long nextDuration = Long.MAX_VALUE; 1817 if (j < (supportedSizes.size() - 1)) { 1818 nextDuration = config.getOutputStallDuration( 1819 format, supportedSizes.get(j + 1)); 1820 } 1821 long curStallDuration = config.getOutputStallDuration(format, size); 1822 // Stall duration should be in a reasonable range: larger size should 1823 // normally have larger stall duration. 1824 mCollector.expectInRange("Stall duration (format " + format + 1825 " and size " + size + ") is not in the right range", 1826 curStallDuration, 1827 (long) (prevDuration / TOLERANCE_FACTOR), 1828 (long) (nextDuration * TOLERANCE_FACTOR)); 1829 break; 1830 default: 1831 assertTrue("Negative stall duration for format " + format, 1832 stallDuration >= 0); 1833 break; 1834 } 1835 long minDuration = config.getOutputMinFrameDuration(format, size); 1836 if (arrayContains(actualCapabilities, 1837 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1838 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1839 + "format " + format + " for size " + size + " minDuration " + 1840 minDuration, 1841 minDuration > 0); 1842 } else { 1843 assertTrue("Need non-negative min frame duration for format " + format, 1844 minDuration >= 0); 1845 } 1846 1847 // todo: test opaque image reader when it's supported. 1848 if (format != ImageFormat.PRIVATE) { 1849 ImageReader testReader = ImageReader.newInstance( 1850 size.getWidth(), 1851 size.getHeight(), 1852 format, 1853 1); 1854 Surface testSurface = testReader.getSurface(); 1855 1856 assertTrue( 1857 String.format("isOutputSupportedFor fails for config %s, format %d", 1858 size.toString(), format), 1859 config.isOutputSupportedFor(testSurface)); 1860 1861 testReader.close(); 1862 } 1863 } // sizes 1864 1865 // Try an invalid size in this format, should round 1866 Size invalidSize = findInvalidSize(supportedSizes); 1867 int MAX_ROUNDING_WIDTH = 1920; 1868 // todo: test opaque image reader when it's supported. 1869 if (format != ImageFormat.PRIVATE && 1870 invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 1871 ImageReader testReader = ImageReader.newInstance( 1872 invalidSize.getWidth(), 1873 invalidSize.getHeight(), 1874 format, 1875 1); 1876 Surface testSurface = testReader.getSurface(); 1877 1878 assertTrue( 1879 String.format("isOutputSupportedFor fails for config %s, %d", 1880 invalidSize.toString(), format), 1881 config.isOutputSupportedFor(testSurface)); 1882 1883 testReader.close(); 1884 } 1885 } // formats 1886 1887 // Cross-check opaque format and sizes 1888 if (arrayContains(actualCapabilities, BC)) { 1889 SurfaceTexture st = new SurfaceTexture(1); 1890 Surface surf = new Surface(st); 1891 1892 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class, 1893 mAllCameraIds[i], mCameraManager); 1894 assertTrue("Opaque format has no sizes listed", 1895 opaqueSizes.length > 0); 1896 for (Size size : opaqueSizes) { 1897 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 1898 assertTrue("Opaque output may not have a non-zero stall duration", 1899 stallDuration == 0); 1900 1901 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 1902 if (arrayContains(actualCapabilities, 1903 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1904 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1905 + "opaque format", 1906 minDuration > 0); 1907 } else { 1908 assertTrue("Need non-negative min frame duration for opaque format ", 1909 minDuration >= 0); 1910 } 1911 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 1912 1913 assertTrue( 1914 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1915 size.toString()), 1916 config.isOutputSupportedFor(surf)); 1917 1918 } // opaque sizes 1919 1920 // Try invalid opaque size, should get rounded 1921 Size invalidSize = findInvalidSize(opaqueSizes); 1922 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 1923 assertTrue( 1924 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1925 invalidSize.toString()), 1926 config.isOutputSupportedFor(surf)); 1927 1928 } 1929 } // mCharacteristics 1930 } 1931 1932 /** 1933 * Test high speed capability and cross-check the high speed sizes and fps ranges from 1934 * the StreamConfigurationMap. 1935 */ testConstrainedHighSpeedCapability()1936 public void testConstrainedHighSpeedCapability() throws Exception { 1937 for (int i = 0; i < mAllCameraIds.length; i++) { 1938 CameraCharacteristics c = mCharacteristics.get(i); 1939 int[] capabilities = CameraTestUtils.getValueNotNull( 1940 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1941 boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED); 1942 if (supportHighSpeed) { 1943 StreamConfigurationMap config = 1944 CameraTestUtils.getValueNotNull( 1945 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1946 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 1947 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0); 1948 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE, 1949 mAllCameraIds[i], mCameraManager); 1950 assertTrue("Normal size for PRIVATE format shouldn't be null or empty", 1951 allSizes != null && allSizes.length > 0); 1952 for (Size size: highSpeedSizes) { 1953 // The sizes must be a subset of the normal sizes 1954 assertTrue("High speed size " + size + 1955 " must be part of normal sizes " + Arrays.toString(allSizes), 1956 Arrays.asList(allSizes).contains(size)); 1957 1958 // Sanitize the high speed FPS ranges for each size 1959 List<Range<Integer>> ranges = 1960 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size)); 1961 for (Range<Integer> range : ranges) { 1962 assertTrue("The range " + range + " doesn't satisfy the" 1963 + " min/max boundary requirements.", 1964 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN && 1965 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN); 1966 assertTrue("The range " + range + " should be multiple of 30fps", 1967 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0); 1968 // If the range is fixed high speed range, it should contain the 1969 // [30, fps_max] in the high speed range list; if it's variable FPS range, 1970 // the corresponding fixed FPS Range must be included in the range list. 1971 if (range.getLower() == range.getUpper()) { 1972 Range<Integer> variableRange = new Range<Integer>(30, range.getUpper()); 1973 assertTrue("The variable FPS range " + variableRange + 1974 " shoould be included in the high speed ranges for size " + 1975 size, ranges.contains(variableRange)); 1976 } else { 1977 Range<Integer> fixedRange = 1978 new Range<Integer>(range.getUpper(), range.getUpper()); 1979 assertTrue("The fixed FPS range " + fixedRange + 1980 " shoould be included in the high speed ranges for size " + 1981 size, ranges.contains(fixedRange)); 1982 } 1983 } 1984 } 1985 // If the device advertise some high speed profiles, the sizes and FPS ranges 1986 // should be advertise by the camera. 1987 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P; 1988 quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) { 1989 int cameraId = Integer.valueOf(mAllCameraIds[i]); 1990 if (CamcorderProfile.hasProfile(cameraId, quality)) { 1991 CamcorderProfile profile = CamcorderProfile.get(cameraId, quality); 1992 Size camcorderProfileSize = 1993 new Size(profile.videoFrameWidth, profile.videoFrameHeight); 1994 assertTrue("CamcorderPrfile size " + camcorderProfileSize + 1995 " must be included in the high speed sizes " + 1996 Arrays.toString(highSpeedSizes.toArray()), 1997 highSpeedSizes.contains(camcorderProfileSize)); 1998 Range<Integer> camcorderFpsRange = 1999 new Range<Integer>(profile.videoFrameRate, profile.videoFrameRate); 2000 List<Range<Integer>> allRanges = 2001 Arrays.asList(config.getHighSpeedVideoFpsRangesFor( 2002 camcorderProfileSize)); 2003 assertTrue("Camcorder fps range " + camcorderFpsRange + 2004 " should be included by high speed fps ranges " + 2005 Arrays.toString(allRanges.toArray()), 2006 allRanges.contains(camcorderFpsRange)); 2007 } 2008 } 2009 } 2010 } 2011 } 2012 2013 /** 2014 * Correctness check of optical black regions. 2015 */ testOpticalBlackRegions()2016 public void testOpticalBlackRegions() { 2017 for (int i = 0; i < mAllCameraIds.length; i++) { 2018 CameraCharacteristics c = mCharacteristics.get(i); 2019 List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys(); 2020 boolean hasDynamicBlackLevel = 2021 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 2022 boolean hasDynamicWhiteLevel = 2023 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL); 2024 boolean hasFixedBlackLevel = 2025 c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 2026 boolean hasFixedWhiteLevel = 2027 c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 2028 // The black and white levels should be either all supported or none of them is 2029 // supported. 2030 mCollector.expectTrue("Dynamic black and white level should be all or none of them" 2031 + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel); 2032 mCollector.expectTrue("Fixed black and white level should be all or none of them" 2033 + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel); 2034 mCollector.expectTrue("Fixed black level should be supported if dynamic black" 2035 + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel); 2036 2037 if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) { 2038 // Regions shouldn't be null or empty. 2039 Rect[] regions = CameraTestUtils.getValueNotNull(c, 2040 CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS); 2041 CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not" 2042 + " be empty"); 2043 2044 // Dynamic black level should be supported if the optical black region is 2045 // advertised. 2046 mCollector.expectTrue("Dynamic black and white level keys should be advertised in " 2047 + "available capture result key list", hasDynamicWhiteLevel); 2048 2049 // Range check. 2050 for (Rect region : regions) { 2051 mCollector.expectTrue("Camera " + mAllCameraIds[i] + ": optical black region" + 2052 " shouldn't be empty!", !region.isEmpty()); 2053 mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/, 2054 region.left/*actual*/); 2055 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 2056 region.top/*actual*/); 2057 mCollector.expectTrue("Optical black region left/right/width/height must be" 2058 + " even number, otherwise, the bayer CFA pattern in this region will" 2059 + " be messed up", 2060 region.left % 2 == 0 && region.top % 2 == 0 && 2061 region.width() % 2 == 0 && region.height() % 2 == 0); 2062 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 2063 region.top/*actual*/); 2064 Size size = CameraTestUtils.getValueNotNull(c, 2065 CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 2066 mCollector.expectLessOrEqual("Optical black region width", 2067 size.getWidth()/*expected*/, region.width()); 2068 mCollector.expectLessOrEqual("Optical black region height", 2069 size.getHeight()/*expected*/, region.height()); 2070 Rect activeArray = CameraTestUtils.getValueNotNull(c, 2071 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 2072 mCollector.expectTrue("Optical black region" + region + " should be outside of" 2073 + " active array " + activeArray, 2074 !region.intersect(activeArray)); 2075 // Region need to be disjoint: 2076 for (Rect region2 : regions) { 2077 mCollector.expectTrue("Optical black region" + region + " should have no " 2078 + "overlap with " + region2, 2079 region == region2 || !region.intersect(region2)); 2080 } 2081 } 2082 } else { 2083 Log.i(TAG, "Camera " + mAllCameraIds[i] + " doesn't support optical black regions," 2084 + " skip the region test"); 2085 } 2086 } 2087 } 2088 2089 /** 2090 * Check Logical camera capability 2091 */ testLogicalCameraCharacteristics()2092 public void testLogicalCameraCharacteristics() throws Exception { 2093 for (int i = 0; i < mAllCameraIds.length; i++) { 2094 CameraCharacteristics c = mCharacteristics.get(i); 2095 int[] capabilities = CameraTestUtils.getValueNotNull( 2096 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2097 boolean supportLogicalCamera = arrayContains(capabilities, 2098 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA); 2099 if (supportLogicalCamera) { 2100 Set<String> physicalCameraIds = c.getPhysicalCameraIds(); 2101 assertNotNull("android.logicalCam.physicalCameraIds shouldn't be null", 2102 physicalCameraIds); 2103 assertTrue("Logical camera must contain at least 2 physical camera ids", 2104 physicalCameraIds.size() >= 2); 2105 2106 mCollector.expectKeyValueInRange(c, 2107 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE, 2108 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE, 2109 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED); 2110 2111 Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); 2112 for (String physicalCameraId : physicalCameraIds) { 2113 assertNotNull("Physical camera id shouldn't be null", physicalCameraId); 2114 assertTrue( 2115 String.format("Physical camera id %s shouldn't be the same as logical" 2116 + " camera id %s", physicalCameraId, mAllCameraIds[i]), 2117 physicalCameraId != mAllCameraIds[i]); 2118 2119 //validation for depth static metadata of physical cameras 2120 CameraCharacteristics pc = 2121 mCameraManager.getCameraCharacteristics(physicalCameraId); 2122 2123 float[] poseRotation = pc.get(CameraCharacteristics.LENS_POSE_ROTATION); 2124 float[] poseTranslation = pc.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 2125 Integer poseReference = pc.get(CameraCharacteristics.LENS_POSE_REFERENCE); 2126 float[] cameraIntrinsics = pc.get( 2127 CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 2128 float[] distortion = getLensDistortion(pc); 2129 Rect precorrectionArray = pc.get( 2130 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 2131 2132 verifyLensCalibration(poseRotation, poseTranslation, poseReference, 2133 cameraIntrinsics, distortion, precorrectionArray); 2134 2135 Integer timestampSourcePhysical = 2136 pc.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); 2137 mCollector.expectEquals("Logical camera and physical cameras must have same " + 2138 "timestamp source", timestampSource, timestampSourcePhysical); 2139 } 2140 } 2141 2142 // Verify that if multiple focal lengths or apertures are supported, they are in 2143 // ascending order. 2144 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 2145 boolean isExternalCamera = (hwLevel == 2146 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 2147 if (!isExternalCamera) { 2148 float[] focalLengths = c.get( 2149 CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); 2150 for (int j = 0; j < focalLengths.length-1; j++) { 2151 mCollector.expectTrue("Camera's available focal lengths must be ascending!", 2152 focalLengths[j] < focalLengths[j+1]); 2153 } 2154 float[] apertures = c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES); 2155 for (int j = 0; j < apertures.length-1; j++) { 2156 mCollector.expectTrue("Camera's available apertures must be ascending!", 2157 apertures[j] < apertures[j+1]); 2158 } 2159 } 2160 } 2161 } 2162 2163 /** 2164 * Check monochrome camera capability 2165 */ testMonochromeCharacteristics()2166 public void testMonochromeCharacteristics() { 2167 for (int i = 0; i < mAllCameraIds.length; i++) { 2168 Log.i(TAG, "testMonochromeCharacteristics: Testing camera ID " + mAllCameraIds[i]); 2169 2170 CameraCharacteristics c = mCharacteristics.get(i); 2171 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2172 assertNotNull("android.request.availableCapabilities must never be null", 2173 capabilities); 2174 boolean supportMonochrome = arrayContains(capabilities, MONOCHROME); 2175 2176 if (!supportMonochrome) { 2177 continue; 2178 } 2179 2180 List<Key<?>> allKeys = c.getKeys(); 2181 List<CaptureRequest.Key<?>> requestKeys = c.getAvailableCaptureRequestKeys(); 2182 List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys(); 2183 2184 assertTrue("Monochrome camera must have BACKWARD_COMPATIBLE capability", 2185 arrayContains(capabilities, BC)); 2186 int colorFilterArrangement = c.get( 2187 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 2188 assertTrue("Monochrome camera must have either MONO or NIR color filter pattern", 2189 colorFilterArrangement == 2190 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO 2191 || colorFilterArrangement == 2192 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR); 2193 2194 assertFalse("Monochrome camera must not contain SENSOR_CALIBRATION_TRANSFORM1 key", 2195 allKeys.contains(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 2196 assertFalse("Monochrome camera must not contain SENSOR_COLOR_TRANSFORM1 key", 2197 allKeys.contains(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 2198 assertFalse("Monochrome camera must not contain SENSOR_FORWARD_MATRIX1 key", 2199 allKeys.contains(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 2200 assertFalse("Monochrome camera must not contain SENSOR_REFERENCE_ILLUMINANT1 key", 2201 allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1)); 2202 assertFalse("Monochrome camera must not contain SENSOR_CALIBRATION_TRANSFORM2 key", 2203 allKeys.contains(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 2204 assertFalse("Monochrome camera must not contain SENSOR_COLOR_TRANSFORM2 key", 2205 allKeys.contains(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 2206 assertFalse("Monochrome camera must not contain SENSOR_FORWARD_MATRIX2 key", 2207 allKeys.contains(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 2208 assertFalse("Monochrome camera must not contain SENSOR_REFERENCE_ILLUMINANT2 key", 2209 allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)); 2210 2211 assertFalse( 2212 "Monochrome capture result must not contain SENSOR_NEUTRAL_COLOR_POINT key", 2213 resultKeys.contains(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT)); 2214 assertFalse("Monochrome capture result must not contain SENSOR_GREEN_SPLIT key", 2215 resultKeys.contains(CaptureResult.SENSOR_GREEN_SPLIT)); 2216 2217 // Check that color correction tags are not available for monochrome cameras 2218 assertTrue("Monochrome camera must not have MANUAL_POST_PROCESSING capability", 2219 !arrayContains(capabilities, MANUAL_POSTPROC)); 2220 assertTrue("Monochrome camera must not have COLOR_CORRECTION_MODE in request keys", 2221 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_MODE)); 2222 assertTrue("Monochrome camera must not have COLOR_CORRECTION_MODE in result keys", 2223 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_MODE)); 2224 assertTrue("Monochrome camera must not have COLOR_CORRECTION_TRANSFORM in request keys", 2225 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_TRANSFORM)); 2226 assertTrue("Monochrome camera must not have COLOR_CORRECTION_TRANSFORM in result keys", 2227 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_TRANSFORM)); 2228 assertTrue("Monochrome camera must not have COLOR_CORRECTION_GAINS in request keys", 2229 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_GAINS)); 2230 assertTrue("Monochrome camera must not have COLOR_CORRECTION_GAINS in result keys", 2231 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_GAINS)); 2232 2233 // Check that awbSupportedModes only contains AUTO 2234 int[] awbAvailableModes = c.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES); 2235 assertTrue("availableAwbModes must not be null", awbAvailableModes != null); 2236 assertTrue("availableAwbModes must contain only AUTO", awbAvailableModes.length == 1 && 2237 awbAvailableModes[0] == CaptureRequest.CONTROL_AWB_MODE_AUTO); 2238 } 2239 } 2240 matchParametersToCharacteritics(Camera.Parameters params, Camera.CameraInfo info, CameraCharacteristics ch)2241 private boolean matchParametersToCharacteritics(Camera.Parameters params, 2242 Camera.CameraInfo info, CameraCharacteristics ch) { 2243 Integer facing = ch.get(CameraCharacteristics.LENS_FACING); 2244 switch (facing.intValue()) { 2245 case CameraMetadata.LENS_FACING_EXTERNAL: 2246 case CameraMetadata.LENS_FACING_FRONT: 2247 if (info.facing != Camera.CameraInfo.CAMERA_FACING_FRONT) { 2248 return false; 2249 } 2250 break; 2251 case CameraMetadata.LENS_FACING_BACK: 2252 if (info.facing != Camera.CameraInfo.CAMERA_FACING_BACK) { 2253 return false; 2254 } 2255 break; 2256 default: 2257 return false; 2258 } 2259 2260 Integer orientation = ch.get(CameraCharacteristics.SENSOR_ORIENTATION); 2261 if (orientation.intValue() != info.orientation) { 2262 return false; 2263 } 2264 2265 StaticMetadata staticMeta = new StaticMetadata(ch); 2266 boolean legacyHasFlash = params.getSupportedFlashModes() != null; 2267 if (staticMeta.hasFlash() != legacyHasFlash) { 2268 return false; 2269 } 2270 2271 List<String> legacyFocusModes = params.getSupportedFocusModes(); 2272 boolean legacyHasFocuser = !((legacyFocusModes.size() == 1) && 2273 (legacyFocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED))); 2274 if (staticMeta.hasFocuser() != legacyHasFocuser) { 2275 return false; 2276 } 2277 2278 if (staticMeta.isVideoStabilizationSupported() != params.isVideoStabilizationSupported()) { 2279 return false; 2280 } 2281 2282 float legacyFocalLength = params.getFocalLength(); 2283 float [] focalLengths = staticMeta.getAvailableFocalLengthsChecked(); 2284 boolean found = false; 2285 for (float focalLength : focalLengths) { 2286 if (Math.abs(focalLength - legacyFocalLength) <= FOCAL_LENGTH_TOLERANCE) { 2287 found = true; 2288 break; 2289 } 2290 } 2291 2292 return found; 2293 } 2294 2295 /** 2296 * Check that all devices available through the legacy API are also 2297 * accessible via Camera2. 2298 */ 2299 @CddTest(requirement="7.5.4/C-0-11") testLegacyCameraDeviceParity()2300 public void testLegacyCameraDeviceParity() { 2301 int legacyDeviceCount = Camera.getNumberOfCameras(); 2302 assertTrue("More legacy devices: " + legacyDeviceCount + " compared to Camera2 devices: " + 2303 mCharacteristics.size(), legacyDeviceCount <= mCharacteristics.size()); 2304 2305 ArrayList<CameraCharacteristics> chars = new ArrayList<> (mCharacteristics); 2306 for (int i = 0; i < legacyDeviceCount; i++) { 2307 Camera camera = null; 2308 Camera.Parameters legacyParams = null; 2309 Camera.CameraInfo legacyInfo = new Camera.CameraInfo(); 2310 try { 2311 Camera.getCameraInfo(i, legacyInfo); 2312 camera = Camera.open(i); 2313 legacyParams = camera.getParameters(); 2314 2315 assertNotNull("Camera parameters for device: " + i + " must not be null", 2316 legacyParams); 2317 } finally { 2318 if (camera != null) { 2319 camera.release(); 2320 } 2321 } 2322 2323 // Camera Ids between legacy devices and Camera2 device could be 2324 // different try to match devices by using other common traits. 2325 CameraCharacteristics found = null; 2326 for (CameraCharacteristics ch : chars) { 2327 if (matchParametersToCharacteritics(legacyParams, legacyInfo, ch)) { 2328 found = ch; 2329 break; 2330 } 2331 } 2332 assertNotNull("No matching Camera2 device for legacy device id: " + i, found); 2333 2334 chars.remove(found); 2335 } 2336 } 2337 2338 /** 2339 * Check camera orientation against device orientation 2340 */ 2341 @CddTest(requirement="7.5.5/C-1-1") testCameraOrientationAlignedWithDevice()2342 public void testCameraOrientationAlignedWithDevice() { 2343 WindowManager windowManager = 2344 (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 2345 Display display = windowManager.getDefaultDisplay(); 2346 DisplayMetrics metrics = new DisplayMetrics(); 2347 display.getMetrics(metrics); 2348 2349 // For square screen, test is guaranteed to pass 2350 if (metrics.widthPixels == metrics.heightPixels) { 2351 return; 2352 } 2353 2354 // Handle display rotation 2355 int displayRotation = display.getRotation(); 2356 if (displayRotation == Surface.ROTATION_90 || displayRotation == Surface.ROTATION_270) { 2357 int tmp = metrics.widthPixels; 2358 metrics.widthPixels = metrics.heightPixels; 2359 metrics.heightPixels = tmp; 2360 } 2361 boolean isDevicePortrait = metrics.widthPixels < metrics.heightPixels; 2362 2363 for (int i = 0; i < mAllCameraIds.length; i++) { 2364 CameraCharacteristics c = mCharacteristics.get(i); 2365 // Camera size 2366 Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 2367 // Camera orientation 2368 int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 2369 2370 // For square sensor, test is guaranteed to pass 2371 if (pixelArraySize.getWidth() == pixelArraySize.getHeight()) { 2372 continue; 2373 } 2374 2375 // Camera size adjusted for device native orientation. 2376 Size adjustedSensorSize; 2377 if (sensorOrientation == 90 || sensorOrientation == 270) { 2378 adjustedSensorSize = new Size( 2379 pixelArraySize.getHeight(), pixelArraySize.getWidth()); 2380 } else { 2381 adjustedSensorSize = pixelArraySize; 2382 } 2383 2384 boolean isCameraPortrait = 2385 adjustedSensorSize.getWidth() < adjustedSensorSize.getHeight(); 2386 assertFalse("Camera " + mAllCameraIds[i] + "'s long dimension must " 2387 + "align with screen's long dimension", isDevicePortrait^isCameraPortrait); 2388 } 2389 } 2390 2391 /** 2392 * Get lens distortion coefficients, as a list of 6 floats; returns null if no valid 2393 * distortion field is available 2394 */ 2395 private float[] getLensDistortion(CameraCharacteristics c) { 2396 float[] distortion = null; 2397 float[] newDistortion = c.get(CameraCharacteristics.LENS_DISTORTION); 2398 if (Build.VERSION.FIRST_SDK_INT > Build.VERSION_CODES.O_MR1 || newDistortion != null) { 2399 // New devices need to use fixed radial distortion definition; old devices can 2400 // opt-in to it 2401 if (newDistortion != null && newDistortion.length == 5) { 2402 distortion = new float[6]; 2403 distortion[0] = 1.0f; 2404 for (int i = 1; i < 6; i++) { 2405 distortion[i] = newDistortion[i-1]; 2406 } 2407 } 2408 } else { 2409 // Select old field only if on older first SDK and new definition not available 2410 distortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION); 2411 } 2412 return distortion; 2413 } 2414 2415 /** 2416 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 2417 */ 2418 private Size findInvalidSize(Size[] goodSizes) { 2419 return findInvalidSize(Arrays.asList(goodSizes)); 2420 } 2421 2422 /** 2423 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 2424 */ 2425 private Size findInvalidSize(List<Size> goodSizes) { 2426 Size invalidSize = new Size(goodSizes.get(0).getWidth() + 1, goodSizes.get(0).getHeight()); 2427 while(goodSizes.contains(invalidSize)) { 2428 invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight()); 2429 } 2430 return invalidSize; 2431 } 2432 2433 /** 2434 * Check key is present in characteristics if the hardware level is at least {@code hwLevel}; 2435 * check that the key is present if the actual capabilities are one of {@code capabilities}. 2436 * 2437 * @return value of the {@code key} from {@code c} 2438 */ 2439 private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, 2440 int hwLevel, int... capabilities) { 2441 2442 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 2443 assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel); 2444 2445 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2446 assertNotNull("android.request.availableCapabilities must never be null", 2447 actualCapabilities); 2448 2449 List<Key<?>> allKeys = c.getKeys(); 2450 2451 T value = c.get(key); 2452 2453 // For LIMITED-level targeted keys, rely on capability check, not level 2454 if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) { 2455 mCollector.expectTrue( 2456 String.format("Key (%s) must be in characteristics for this hardware level " + 2457 "(required minimal HW level %s, actual HW level %s)", 2458 key.getName(), toStringHardwareLevel(hwLevel), 2459 toStringHardwareLevel(actualHwLevel)), 2460 value != null); 2461 mCollector.expectTrue( 2462 String.format("Key (%s) must be in characteristics list of keys for this " + 2463 "hardware level (required minimal HW level %s, actual HW level %s)", 2464 key.getName(), toStringHardwareLevel(hwLevel), 2465 toStringHardwareLevel(actualHwLevel)), 2466 allKeys.contains(key)); 2467 } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) { 2468 if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) { 2469 // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined 2470 mCollector.expectTrue( 2471 String.format("Key (%s) must be in characteristics for these capabilities " + 2472 "(required capabilities %s, actual capabilities %s)", 2473 key.getName(), Arrays.toString(capabilities), 2474 Arrays.toString(actualCapabilities)), 2475 value != null); 2476 mCollector.expectTrue( 2477 String.format("Key (%s) must be in characteristics list of keys for " + 2478 "these capabilities (required capabilities %s, actual capabilities %s)", 2479 key.getName(), Arrays.toString(capabilities), 2480 Arrays.toString(actualCapabilities)), 2481 allKeys.contains(key)); 2482 } 2483 } else { 2484 if (actualHwLevel == LEGACY && hwLevel != OPT) { 2485 if (value != null || allKeys.contains(key)) { 2486 Log.w(TAG, String.format( 2487 "Key (%s) is not required for LEGACY devices but still appears", 2488 key.getName())); 2489 } 2490 } 2491 // OK: Key may or may not be present. 2492 } 2493 return value; 2494 } 2495 2496 private static boolean arrayContains(int[] arr, int needle) { 2497 if (arr == null) { 2498 return false; 2499 } 2500 2501 for (int elem : arr) { 2502 if (elem == needle) { 2503 return true; 2504 } 2505 } 2506 2507 return false; 2508 } 2509 2510 private static <T> boolean arrayContains(T[] arr, T needle) { 2511 if (arr == null) { 2512 return false; 2513 } 2514 2515 for (T elem : arr) { 2516 if (elem.equals(needle)) { 2517 return true; 2518 } 2519 } 2520 2521 return false; 2522 } 2523 2524 private static boolean arrayContainsAnyOf(int[] arr, int[] needles) { 2525 for (int needle : needles) { 2526 if (arrayContains(arr, needle)) { 2527 return true; 2528 } 2529 } 2530 return false; 2531 } 2532 2533 /** 2534 * The key name has a prefix of either "android." or a valid TLD; other prefixes are not valid. 2535 */ 2536 private static void assertKeyPrefixValid(String keyName) { 2537 assertStartsWithAndroidOrTLD( 2538 "All metadata keys must start with 'android.' (built-in keys) " + 2539 "or valid TLD (vendor-extended keys)", keyName); 2540 } 2541 2542 private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, 2543 boolean actual) { 2544 assertTrue(msg + " (key = '" + key.getName() + "')", actual); 2545 } 2546 2547 private static <T> void assertOneOf(String msg, T[] expected, T actual) { 2548 for (int i = 0; i < expected.length; ++i) { 2549 if (Objects.equals(expected[i], actual)) { 2550 return; 2551 } 2552 } 2553 2554 fail(String.format("%s: (expected one of %s, actual %s)", 2555 msg, Arrays.toString(expected), actual)); 2556 } 2557 2558 private static <T> void assertStartsWithAndroidOrTLD(String msg, String keyName) { 2559 String delimiter = "."; 2560 if (keyName.startsWith(PREFIX_ANDROID + delimiter)) { 2561 return; 2562 } 2563 Pattern tldPattern = Pattern.compile(Patterns.TOP_LEVEL_DOMAIN_STR); 2564 Matcher match = tldPattern.matcher(keyName); 2565 if (match.find(0) && (0 == match.start()) && (!match.hitEnd())) { 2566 if (keyName.regionMatches(match.end(), delimiter, 0, delimiter.length())) { 2567 return; 2568 } 2569 } 2570 2571 fail(String.format("%s: (expected to start with %s or valid TLD, but value was %s)", 2572 msg, PREFIX_ANDROID + delimiter, keyName)); 2573 } 2574 2575 /** Return a positive int if left > right, 0 if left==right, negative int if left < right */ 2576 private static int compareHardwareLevel(int left, int right) { 2577 return remapHardwareLevel(left) - remapHardwareLevel(right); 2578 } 2579 2580 /** Remap HW levels worst<->best, 0 = LEGACY, 1 = LIMITED, 2 = FULL, ..., N = LEVEL_N */ 2581 private static int remapHardwareLevel(int level) { 2582 switch (level) { 2583 case OPT: 2584 return Integer.MAX_VALUE; 2585 case LEGACY: 2586 return 0; // lowest 2587 case EXTERNAL: 2588 return 1; // second lowest 2589 case LIMITED: 2590 return 2; 2591 case FULL: 2592 return 3; // good 2593 case LEVEL_3: 2594 return 4; 2595 default: 2596 fail("Unknown HW level: " + level); 2597 } 2598 return -1; 2599 } 2600 2601 private static String toStringHardwareLevel(int level) { 2602 switch (level) { 2603 case LEGACY: 2604 return "LEGACY"; 2605 case LIMITED: 2606 return "LIMITED"; 2607 case FULL: 2608 return "FULL"; 2609 case EXTERNAL: 2610 return "EXTERNAL"; 2611 default: 2612 if (level >= LEVEL_3) { 2613 return String.format("LEVEL_%d", level); 2614 } 2615 } 2616 2617 // unknown 2618 Log.w(TAG, "Unknown hardware level " + level); 2619 return Integer.toString(level); 2620 } 2621 } 2622