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