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 static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 20 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContains; 21 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContainsAnyOf; 22 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertCollectionContainsAnyOf; 23 import static android.hardware.cts.helpers.CameraUtils.matchParametersToCharacteristics; 24 25 import static junit.framework.Assert.assertEquals; 26 import static junit.framework.Assert.assertFalse; 27 import static junit.framework.Assert.assertNotNull; 28 import static junit.framework.Assert.assertTrue; 29 import static junit.framework.Assert.fail; 30 31 import static org.junit.Assume.assumeFalse; 32 import static org.junit.Assume.assumeTrue; 33 import static org.mockito.Mockito.any; 34 import static org.mockito.Mockito.mock; 35 import static org.mockito.Mockito.never; 36 import static org.mockito.Mockito.reset; 37 import static org.mockito.Mockito.timeout; 38 import static org.mockito.Mockito.verify; 39 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.pm.PackageManager; 43 import android.graphics.ColorSpace; 44 import android.graphics.ImageFormat; 45 import android.graphics.Rect; 46 import android.graphics.SurfaceTexture; 47 import android.hardware.Camera; 48 import android.hardware.DataSpace; 49 import android.hardware.HardwareBuffer; 50 import android.hardware.camera2.CameraCaptureSession; 51 import android.hardware.camera2.CameraCharacteristics; 52 import android.hardware.camera2.CameraCharacteristics.Key; 53 import android.hardware.camera2.CameraDevice; 54 import android.hardware.camera2.CameraExtensionCharacteristics; 55 import android.hardware.camera2.CameraMetadata; 56 import android.hardware.camera2.CaptureFailure; 57 import android.hardware.camera2.CaptureRequest; 58 import android.hardware.camera2.CaptureResult; 59 import android.hardware.camera2.TotalCaptureResult; 60 import android.hardware.camera2.cts.helpers.StaticMetadata; 61 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 62 import android.hardware.camera2.params.BlackLevelPattern; 63 import android.hardware.camera2.params.ColorSpaceProfiles; 64 import android.hardware.camera2.params.ColorSpaceTransform; 65 import android.hardware.camera2.params.DeviceStateSensorOrientationMap; 66 import android.hardware.camera2.params.DynamicRangeProfiles; 67 import android.hardware.camera2.params.OutputConfiguration; 68 import android.hardware.camera2.params.RecommendedStreamConfigurationMap; 69 import android.hardware.camera2.params.SessionConfiguration; 70 import android.hardware.camera2.params.StreamConfigurationMap; 71 import android.hardware.cts.helpers.CameraUtils; 72 import android.media.CamcorderProfile; 73 import android.media.Image; 74 import android.media.ImageReader; 75 import android.mediapc.cts.common.PerformanceClassEvaluator; 76 import android.mediapc.cts.common.Requirements; 77 import android.mediapc.cts.common.Requirements.CameraConcurrentRearFrontStreamingRequirement; 78 import android.mediapc.cts.common.Requirements.CameraDynamicRange10BitRequirement; 79 import android.mediapc.cts.common.Requirements.CameraFaceDetectionRequirement; 80 import android.mediapc.cts.common.Requirements.CameraHardwareLevelRequirement; 81 import android.mediapc.cts.common.Requirements.CameraJPEGRRequirement; 82 import android.mediapc.cts.common.Requirements.CameraLogicalMultiCameraRequirement; 83 import android.mediapc.cts.common.Requirements.CameraNightModeExtensionRequirement; 84 import android.mediapc.cts.common.Requirements.CameraPreviewStabilizationRequirement; 85 import android.mediapc.cts.common.Requirements.CameraRAWCapabilityRequirement; 86 import android.mediapc.cts.common.Requirements.CameraSlowMotionRequirement; 87 import android.mediapc.cts.common.Requirements.CameraStreamUseCaseRequirement; 88 import android.mediapc.cts.common.Requirements.CameraUltrawideZoomRatioRequirement; 89 import android.mediapc.cts.common.Requirements.PrimaryFrontCameraResolutionAndFrameRateRequirement; 90 import android.mediapc.cts.common.Requirements.PrimaryRearCameraResolutionAndFrameRateRequirement; 91 import android.mediapc.cts.common.Requirements.TimestampSourceRealtimeRequirement; 92 import android.os.Build; 93 import android.platform.test.annotations.AppModeFull; 94 import android.platform.test.annotations.RequiresFlagsEnabled; 95 import android.platform.test.flag.junit.CheckFlagsRule; 96 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 97 import android.util.ArraySet; 98 import android.util.Log; 99 import android.util.Pair; 100 import android.util.Patterns; 101 import android.util.Range; 102 import android.util.Rational; 103 import android.util.Size; 104 import android.util.SizeF; 105 import android.view.Display; 106 import android.view.Surface; 107 import android.view.WindowManager; 108 import android.view.WindowMetrics; 109 110 import androidx.camera.core.CameraSelector; 111 import androidx.camera.extensions.ExtensionMode; 112 import androidx.camera.extensions.ExtensionsManager; 113 import androidx.camera.lifecycle.ProcessCameraProvider; 114 import androidx.test.rule.ActivityTestRule; 115 116 import com.android.compatibility.common.util.ApiTest; 117 import com.android.compatibility.common.util.CddTest; 118 import com.android.internal.camera.flags.Flags; 119 120 import com.google.common.util.concurrent.ListenableFuture; 121 122 import org.junit.Rule; 123 import org.junit.Test; 124 import org.junit.rules.TestName; 125 import org.junit.runner.RunWith; 126 import org.junit.runners.Parameterized; 127 128 import java.util.ArrayList; 129 import java.util.Arrays; 130 import java.util.HashSet; 131 import java.util.List; 132 import java.util.Map; 133 import java.util.Objects; 134 import java.util.Set; 135 import java.util.concurrent.ExecutionException; 136 import java.util.concurrent.TimeUnit; 137 import java.util.concurrent.TimeoutException; 138 import java.util.regex.Matcher; 139 import java.util.regex.Pattern; 140 141 142 /** 143 * Extended tests for static camera characteristics. 144 */ 145 @RunWith(Parameterized.class) 146 public class ExtendedCameraCharacteristicsTest extends Camera2AndroidTestCase { 147 private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw 148 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 149 150 private static final String PREFIX_ANDROID = "android"; 151 152 /* 153 * Constants for static RAW metadata. 154 */ 155 private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5 156 157 @Rule 158 public final TestName mTestName = new TestName(); 159 160 private List<CameraCharacteristics> mCharacteristics; 161 162 private static final Size FULLHD = new Size(1920, 1080); 163 private static final Size FULLHD_ALT = new Size(1920, 1088); 164 private static final Size HD = new Size(1280, 720); 165 private static final Size VGA = new Size(640, 480); 166 private static final Size QVGA = new Size(320, 240); 167 private static final Size UHD = new Size(3840, 2160); 168 private static final Size DC4K = new Size(4096, 2160); 169 170 private static final long MIN_BACK_SENSOR_RESOLUTION = 2000000; 171 private static final long MIN_FRONT_SENSOR_RESOLUTION = VGA.getHeight() * VGA.getWidth(); 172 private static final long LOW_LATENCY_THRESHOLD_MS = 200; 173 private static final float LATENCY_TOLERANCE_FACTOR = 1.1f; // 10% tolerance 174 private static final int MAX_NUM_IMAGES = 5; 175 private static final long PREVIEW_RUN_MS = 500; 176 private static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30; 177 private static final long WAIT_TIMEOUT_IN_MS = 10_000; 178 private static final int CONFIGURE_TIMEOUT = 5000; // ms 179 private static final int CAPTURE_TIMEOUT = 1500; // ms 180 181 private static final long MIN_UHR_SENSOR_RESOLUTION = 24000000; 182 /* 183 * HW Levels short hand 184 */ 185 private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 186 private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 187 private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 188 private static final int LEVEL_3 = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3; 189 private static final int EXTERNAL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL; 190 private static final int OPT = Integer.MAX_VALUE; // For keys that are optional on all hardware levels. 191 192 /* 193 * Capabilities short hand 194 */ 195 private static final int NONE = -1; 196 private static final int BC = 197 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE; 198 private static final int MANUAL_SENSOR = 199 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR; 200 private static final int MANUAL_POSTPROC = 201 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING; 202 private static final int RAW = 203 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW; 204 private static final int YUV_REPROCESS = 205 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING; 206 private static final int OPAQUE_REPROCESS = 207 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING; 208 private static final int CONSTRAINED_HIGH_SPEED = 209 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO; 210 private static final int DYNAMIC_RANGE_TEN_BIT = 211 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT; 212 private static final int FACE_DETECTION_MODE_SIMPLE = 213 CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE; 214 private static final int FACE_DETECTION_MODE_FULL = 215 CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL; 216 private static final int MONOCHROME = 217 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME; 218 private static final int HIGH_SPEED_FPS_LOWER_MIN = 30; 219 private static final int HIGH_SPEED_FPS_UPPER_MIN = 120; 220 221 @Rule 222 public final ActivityTestRule<EmptyActivity> mActivityRule = new ActivityTestRule<>( 223 EmptyActivity.class, false, false); 224 225 @Rule 226 public final CheckFlagsRule mCheckFlagsRule = 227 DeviceFlagsValueProvider.createCheckFlagsRule(); 228 229 @Override setUp()230 public void setUp() throws Exception { 231 super.setUp(); 232 mCharacteristics = new ArrayList<>(); 233 String[] allCameraIds = getAllCameraIds(); 234 for (int i = 0; i < allCameraIds.length; i++) { 235 mCharacteristics.add(mAllStaticInfo.get(allCameraIds[i]).getCharacteristics()); 236 } 237 } 238 239 @Override tearDown()240 public void tearDown() throws Exception { 241 super.tearDown(); 242 mCharacteristics = null; 243 } 244 245 /** 246 * Test that the available stream configurations contain a few required formats and sizes. 247 */ 248 @CddTest(requirement="7.5.1/C-1-2") 249 @Test testAvailableStreamConfigs()250 public void testAvailableStreamConfigs() throws Exception { 251 boolean firstBackFacingCamera = true; 252 String[] allCameraIds = getAllCameraIds(); 253 for (int i = 0; i < allCameraIds.length; i++) { 254 CameraCharacteristics c = mCharacteristics.get(i); 255 StreamConfigurationMap config = 256 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 257 assertNotNull(String.format("No stream configuration map found for: ID %s", 258 allCameraIds[i]), config); 259 int[] outputFormats = config.getOutputFormats(); 260 261 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 262 assertNotNull("android.request.availableCapabilities must never be null", 263 actualCapabilities); 264 265 // Check required formats exist (JPEG, and YUV_420_888). 266 if (!arrayContains(actualCapabilities, BC)) { 267 Log.i(TAG, "Camera " + allCameraIds[i] + 268 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 269 continue; 270 } 271 272 boolean isMonochromeWithY8 = arrayContains(actualCapabilities, MONOCHROME) 273 && arrayContains(outputFormats, ImageFormat.Y8); 274 boolean isHiddenPhysicalCamera = !arrayContains(getCameraIdsUnderTest(), allCameraIds[i]); 275 boolean supportHeic = arrayContains(outputFormats, ImageFormat.HEIC); 276 277 assertArrayContains( 278 String.format("No valid YUV_420_888 preview formats found for: ID %s", 279 allCameraIds[i]), outputFormats, ImageFormat.YUV_420_888); 280 if (isMonochromeWithY8) { 281 assertArrayContains( 282 String.format("No valid Y8 preview formats found for: ID %s", 283 allCameraIds[i]), outputFormats, ImageFormat.Y8); 284 } 285 assertArrayContains(String.format("No JPEG image format for: ID %s", 286 allCameraIds[i]), outputFormats, ImageFormat.JPEG); 287 288 Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888); 289 Size[] y8Sizes = config.getOutputSizes(ImageFormat.Y8); 290 Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG); 291 Size[] heicSizes = config.getOutputSizes(ImageFormat.HEIC); 292 Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE); 293 294 CameraTestUtils.assertArrayNotEmpty(yuvSizes, 295 String.format("No sizes for preview format %x for: ID %s", 296 ImageFormat.YUV_420_888, allCameraIds[i])); 297 if (isMonochromeWithY8) { 298 CameraTestUtils.assertArrayNotEmpty(y8Sizes, 299 String.format("No sizes for preview format %x for: ID %s", 300 ImageFormat.Y8, allCameraIds[i])); 301 } 302 303 Rect activeRect = CameraTestUtils.getValueNotNull( 304 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 305 Size pixelArraySize = CameraTestUtils.getValueNotNull( 306 c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 307 308 int activeArrayHeight = activeRect.height(); 309 int activeArrayWidth = activeRect.width(); 310 long sensorResolution = pixelArraySize.getHeight() * pixelArraySize.getWidth() ; 311 Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); 312 assertNotNull("Can't get lens facing info for camera id: " + allCameraIds[i], 313 lensFacing); 314 315 // Check that the sensor sizes are atleast what the CDD specifies 316 switch(lensFacing) { 317 case CameraCharacteristics.LENS_FACING_FRONT: 318 assertTrue("Front Sensor resolution should be at least " + 319 MIN_FRONT_SENSOR_RESOLUTION + " pixels, is "+ sensorResolution, 320 sensorResolution >= MIN_FRONT_SENSOR_RESOLUTION); 321 break; 322 case CameraCharacteristics.LENS_FACING_BACK: 323 if (firstBackFacingCamera) { 324 assertTrue("Back Sensor resolution should be at least " 325 + MIN_BACK_SENSOR_RESOLUTION + 326 " pixels, is "+ sensorResolution, 327 sensorResolution >= MIN_BACK_SENSOR_RESOLUTION); 328 firstBackFacingCamera = false; 329 } 330 break; 331 default: 332 break; 333 } 334 335 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 336 337 if (activeArrayWidth >= FULLHD.getWidth() && 338 activeArrayHeight >= FULLHD.getHeight()) { 339 assertArrayContainsAnyOf(String.format( 340 "Required FULLHD size not found for format %x for: ID %s", 341 ImageFormat.JPEG, allCameraIds[i]), jpegSizes, 342 new Size[] {FULLHD, FULLHD_ALT}); 343 if (supportHeic) { 344 assertArrayContainsAnyOf(String.format( 345 "Required FULLHD size not found for format %x for: ID %s", 346 ImageFormat.HEIC, allCameraIds[i]), heicSizes, 347 new Size[] {FULLHD, FULLHD_ALT}); 348 } 349 } 350 351 boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera( 352 mCameraManager, allCameraIds[i]); 353 boolean isPrimaryFront = CameraTestUtils.isPrimaryFrontFacingCamera( 354 mCameraManager, allCameraIds[i]); 355 boolean isPrimaryCamera = isPrimaryFront || isPrimaryRear; 356 // Skip check for < 1080p JPEG sizes for media performance class level >= 31 357 // since SDK 31 requires a minimum size of 1080p for JPEG 358 if (Build.VERSION.MEDIA_PERFORMANCE_CLASS < Build.VERSION_CODES.S 359 || !isPrimaryCamera) { 360 if (activeArrayWidth >= HD.getWidth() 361 && activeArrayHeight >= HD.getHeight()) { 362 assertArrayContains(String.format( 363 "Required HD size not found for format %x for: ID %s", 364 ImageFormat.JPEG, allCameraIds[i]), jpegSizes, HD); 365 if (supportHeic) { 366 assertArrayContains(String.format( 367 "Required HD size not found for format %x for: ID %s", 368 ImageFormat.HEIC, allCameraIds[i]), heicSizes, HD); 369 } 370 } 371 372 if (activeArrayWidth >= VGA.getWidth() 373 && activeArrayHeight >= VGA.getHeight()) { 374 assertArrayContains(String.format( 375 "Required VGA size not found for format %x for: ID %s", 376 ImageFormat.JPEG, allCameraIds[i]), jpegSizes, VGA); 377 if (supportHeic) { 378 assertArrayContains(String.format( 379 "Required VGA size not found for format %x for: ID %s", 380 ImageFormat.HEIC, allCameraIds[i]), heicSizes, VGA); 381 } 382 } 383 384 if (activeArrayWidth >= QVGA.getWidth() 385 && activeArrayHeight >= QVGA.getHeight()) { 386 assertArrayContains(String.format( 387 "Required QVGA size not found for format %x for: ID %s", 388 ImageFormat.JPEG, allCameraIds[i]), jpegSizes, QVGA); 389 if (supportHeic) { 390 assertArrayContains(String.format( 391 "Required QVGA size not found for format %x for: ID %s", 392 ImageFormat.HEIC, allCameraIds[i]), heicSizes, QVGA); 393 } 394 } 395 } 396 397 ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes)); 398 ArrayList<Size> yuvSizesList = new ArrayList<>(Arrays.asList(yuvSizes)); 399 ArrayList<Size> privateSizesList = new ArrayList<>(Arrays.asList(privateSizes)); 400 boolean isExternalCamera = (hwLevel == 401 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 402 Size maxVideoSize = null; 403 if (isExternalCamera || isHiddenPhysicalCamera) { 404 // TODO: for now, use FULLHD 30 as largest possible video size for external camera. 405 // For hidden physical camera, since we don't require CamcorderProfile to be 406 // available, use FULLHD 30 as maximum video size as well. 407 List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes( 408 allCameraIds[i], mCameraManager, FULLHD); 409 for (Size sz : videoSizes) { 410 long minFrameDuration = config.getOutputMinFrameDuration( 411 android.media.MediaRecorder.class, sz); 412 // Give some margin for rounding error 413 if (minFrameDuration < (1e9 / 29.9)) { 414 maxVideoSize = sz; 415 break; 416 } 417 } 418 } else { 419 int cameraId = Integer.valueOf(allCameraIds[i]); 420 CamcorderProfile maxVideoProfile = CamcorderProfile.get( 421 cameraId, CamcorderProfile.QUALITY_HIGH); 422 maxVideoSize = new Size( 423 maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight); 424 } 425 if (maxVideoSize == null) { 426 fail("Camera " + allCameraIds[i] + " does not support any 30fps video output"); 427 } 428 429 // Handle FullHD special case first 430 if (jpegSizesList.contains(FULLHD)) { 431 if (compareHardwareLevel(hwLevel, LEVEL_3) >= 0 || hwLevel == FULL || 432 (hwLevel == LIMITED && 433 maxVideoSize.getWidth() >= FULLHD.getWidth() && 434 maxVideoSize.getHeight() >= FULLHD.getHeight())) { 435 boolean yuvSupportFullHD = yuvSizesList.contains(FULLHD) || 436 yuvSizesList.contains(FULLHD_ALT); 437 boolean privateSupportFullHD = privateSizesList.contains(FULLHD) || 438 privateSizesList.contains(FULLHD_ALT); 439 assertTrue("Full device FullHD YUV size not found", yuvSupportFullHD); 440 assertTrue("Full device FullHD PRIVATE size not found", privateSupportFullHD); 441 442 if (isMonochromeWithY8) { 443 ArrayList<Size> y8SizesList = new ArrayList<>(Arrays.asList(y8Sizes)); 444 boolean y8SupportFullHD = y8SizesList.contains(FULLHD) || 445 y8SizesList.contains(FULLHD_ALT); 446 assertTrue("Full device FullHD Y8 size not found", y8SupportFullHD); 447 } 448 } 449 // remove all FullHD or FullHD_Alt sizes for the remaining of the test 450 jpegSizesList.remove(FULLHD); 451 jpegSizesList.remove(FULLHD_ALT); 452 } 453 454 // Check all sizes other than FullHD 455 if (hwLevel == LIMITED) { 456 // Remove all jpeg sizes larger than max video size 457 ArrayList<Size> toBeRemoved = new ArrayList<>(); 458 for (Size size : jpegSizesList) { 459 if (size.getWidth() >= maxVideoSize.getWidth() && 460 size.getHeight() >= maxVideoSize.getHeight()) { 461 toBeRemoved.add(size); 462 } 463 } 464 jpegSizesList.removeAll(toBeRemoved); 465 } 466 467 if (compareHardwareLevel(hwLevel, LEVEL_3) >= 0 || hwLevel == FULL || 468 hwLevel == LIMITED) { 469 if (!yuvSizesList.containsAll(jpegSizesList)) { 470 for (Size s : jpegSizesList) { 471 if (!yuvSizesList.contains(s)) { 472 fail("Size " + s + " not found in YUV format"); 473 } 474 } 475 } 476 477 if (isMonochromeWithY8) { 478 ArrayList<Size> y8SizesList = new ArrayList<>(Arrays.asList(y8Sizes)); 479 if (!y8SizesList.containsAll(jpegSizesList)) { 480 for (Size s : jpegSizesList) { 481 if (!y8SizesList.contains(s)) { 482 fail("Size " + s + " not found in Y8 format"); 483 } 484 } 485 } 486 } 487 } 488 489 if (!privateSizesList.containsAll(yuvSizesList)) { 490 for (Size s : yuvSizesList) { 491 if (!privateSizesList.contains(s)) { 492 fail("Size " + s + " not found in PRIVATE format"); 493 } 494 } 495 } 496 } 497 } 498 499 /** 500 * Check JPEG size overrides for devices claiming S Performance class requirement via 501 * Version.MEDIA_PERFORMANCE_CLASS 502 */ 503 @Test testSPerfClassJpegSizes()504 public void testSPerfClassJpegSizes() throws Exception { 505 final boolean isAtLeastSPerfClass = 506 (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S); 507 if (!isAtLeastSPerfClass) { 508 return; 509 } 510 511 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 512 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 513 testSPerfClassJpegSizesByCamera(cameraIdsUnderTest[i]); 514 } 515 } 516 517 // Verify primary camera devices's supported JPEG sizes are at least 1080p. testSPerfClassJpegSizesByCamera(String cameraId)518 private void testSPerfClassJpegSizesByCamera(String cameraId) throws Exception { 519 boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera( 520 mCameraManager, cameraId); 521 boolean isPrimaryFront = CameraTestUtils.isPrimaryFrontFacingCamera( 522 mCameraManager, cameraId); 523 if (!isPrimaryRear && !isPrimaryFront) { 524 return; 525 } 526 527 CameraCharacteristics c = mCameraManager.getCameraCharacteristics(cameraId); 528 StaticMetadata staticInfo = 529 new StaticMetadata(c, StaticMetadata.CheckLevel.ASSERT, mCollector); 530 531 Size[] jpegSizes = staticInfo.getJpegOutputSizesChecked(); 532 assertTrue("Primary cameras must support JPEG formats", 533 jpegSizes != null && jpegSizes.length > 0); 534 int minEuclidDistSquare = Integer.MAX_VALUE; 535 Size closestJpegSizeToVga = VGA; 536 for (Size jpegSize : jpegSizes) { 537 mCollector.expectTrue( 538 "Primary camera's JPEG size must be at least 1080p, but is " 539 + jpegSize, jpegSize.getWidth() * jpegSize.getHeight() 540 >= FULLHD.getWidth() * FULLHD.getHeight()); 541 int widthDist = jpegSize.getWidth() - VGA.getWidth(); 542 int heightDist = jpegSize.getHeight() - VGA.getHeight(); 543 int euclidDistSquare = widthDist * widthDist + heightDist * heightDist; 544 if (euclidDistSquare < minEuclidDistSquare) { 545 closestJpegSizeToVga = jpegSize; 546 minEuclidDistSquare = euclidDistSquare; 547 } 548 } 549 550 CameraDevice camera = null; 551 ImageReader jpegTarget = null; 552 Image image = null; 553 try { 554 camera = CameraTestUtils.openCamera(mCameraManager, cameraId, 555 /*listener*/null, mHandler); 556 557 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 558 CameraTestUtils.SimpleImageReaderListener imageListener = 559 new CameraTestUtils.SimpleImageReaderListener(); 560 jpegTarget = CameraTestUtils.makeImageReader(VGA, 561 ImageFormat.JPEG, 1 /*maxNumImages*/, imageListener, mHandler); 562 Surface jpegSurface = jpegTarget.getSurface(); 563 outputConfigs.add(new OutputConfiguration(jpegSurface)); 564 565 // isSessionConfigurationSupported will return true for JPEG sizes smaller 566 // than 1080P, due to framework rouding up to closest supported size. 567 CameraTestUtils.SessionConfigSupport sessionConfigSupport = 568 CameraTestUtils.isSessionConfigSupported( 569 camera, mHandler, outputConfigs, /*inputConfig*/ null, 570 SessionConfiguration.SESSION_REGULAR, 571 mCameraManager, true/*defaultSupport*/); 572 mCollector.expectTrue("isSessionConfiguration fails with error", 573 !sessionConfigSupport.error); 574 mCollector.expectTrue("isSessionConfiguration returns false for JPEG < 1080p", 575 sessionConfigSupport.configSupported); 576 577 // Session creation for JPEG sizes smaller than 1080p will succeed, and the 578 // result JPEG image dimension is rounded up to closest supported size. 579 CaptureRequest.Builder request = 580 camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 581 request.addTarget(jpegSurface); 582 583 CameraCaptureSession.StateCallback sessionListener = 584 mock(CameraCaptureSession.StateCallback.class); 585 CameraCaptureSession session = CameraTestUtils.configureCameraSessionWithConfig( 586 camera, outputConfigs, sessionListener, mHandler); 587 588 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()) 589 .onConfigured(any(CameraCaptureSession.class)); 590 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()) 591 .onReady(any(CameraCaptureSession.class)); 592 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class)); 593 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class)); 594 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class)); 595 596 CameraCaptureSession.CaptureCallback captureListener = 597 mock(CameraCaptureSession.CaptureCallback.class); 598 session.capture(request.build(), captureListener, mHandler); 599 600 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()) 601 .onCaptureCompleted(any(CameraCaptureSession.class), 602 any(CaptureRequest.class), any(TotalCaptureResult.class)); 603 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class), 604 any(CaptureRequest.class), any(CaptureFailure.class)); 605 606 image = imageListener.getImage(CAPTURE_TIMEOUT); 607 assertNotNull("Image must be valid", image); 608 assertEquals("Image format isn't JPEG", image.getFormat(), ImageFormat.JPEG); 609 610 byte[] data = CameraTestUtils.getDataFromImage(image); 611 assertTrue("Invalid image data", data != null && data.length > 0); 612 613 CameraTestUtils.validateJpegData(data, closestJpegSizeToVga.getWidth(), 614 closestJpegSizeToVga.getHeight(), null /*filePath*/); 615 } finally { 616 if (camera != null) { 617 camera.close(); 618 } 619 if (jpegTarget != null) { 620 jpegTarget.close(); 621 } 622 if (image != null) { 623 image.close(); 624 } 625 } 626 } 627 verifyCommonRecommendedConfiguration(String id, CameraCharacteristics c, RecommendedStreamConfigurationMap config, boolean checkNoInput, boolean checkNoHighRes, boolean checkNoHighSpeed, boolean checkNoPrivate, boolean checkNoDepth)628 private void verifyCommonRecommendedConfiguration(String id, CameraCharacteristics c, 629 RecommendedStreamConfigurationMap config, boolean checkNoInput, 630 boolean checkNoHighRes, boolean checkNoHighSpeed, boolean checkNoPrivate, 631 boolean checkNoDepth) { 632 StreamConfigurationMap fullConfig = c.get( 633 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 634 assertNotNull(String.format("No stream configuration map found for ID: %s!", id), 635 fullConfig); 636 637 Set<Integer> recommendedOutputFormats = config.getOutputFormats(); 638 639 if (checkNoInput) { 640 Set<Integer> inputFormats = config.getInputFormats(); 641 assertTrue(String.format("Recommended configuration must not include any input " + 642 "streams for ID: %s", id), 643 ((inputFormats == null) || (inputFormats.size() == 0))); 644 } 645 646 if (checkNoHighRes) { 647 for (int format : recommendedOutputFormats) { 648 Set<Size> highResSizes = config.getHighResolutionOutputSizes(format); 649 assertTrue(String.format("Recommended configuration should not include any " + 650 "high resolution sizes, which cannot operate at full " + 651 "BURST_CAPTURE rate for ID: %s", id), 652 ((highResSizes == null) || (highResSizes.size() == 0))); 653 } 654 } 655 656 if (checkNoHighSpeed) { 657 Set<Size> highSpeedSizes = config.getHighSpeedVideoSizes(); 658 assertTrue(String.format("Recommended configuration must not include any high " + 659 "speed configurations for ID: %s", id), 660 ((highSpeedSizes == null) || (highSpeedSizes.size() == 0))); 661 } 662 663 int[] exhaustiveOutputFormats = fullConfig.getOutputFormats(); 664 for (Integer formatInteger : recommendedOutputFormats) { 665 int format = formatInteger.intValue(); 666 assertArrayContains(String.format("Unsupported recommended output format: %d for " + 667 "ID: %s ", format, id), exhaustiveOutputFormats, format); 668 Set<Size> recommendedSizes = config.getOutputSizes(format); 669 670 switch (format) { 671 case ImageFormat.PRIVATE: 672 if (checkNoPrivate) { 673 fail(String.format("Recommended configuration must not include " + 674 "PRIVATE format entries for ID: %s", id)); 675 } 676 677 Set<Size> classOutputSizes = config.getOutputSizes(ImageReader.class); 678 assertCollectionContainsAnyOf(String.format("Recommended output sizes for " + 679 "ImageReader class don't match the output sizes for the " + 680 "corresponding format for ID: %s", id), classOutputSizes, 681 recommendedSizes); 682 break; 683 case ImageFormat.DEPTH16: 684 case ImageFormat.DEPTH_POINT_CLOUD: 685 if (checkNoDepth) { 686 fail(String.format("Recommended configuration must not include any DEPTH " + 687 "formats for ID: %s", id)); 688 } 689 break; 690 default: 691 } 692 Size [] exhaustiveSizes = fullConfig.getOutputSizes(format); 693 for (Size sz : recommendedSizes) { 694 assertArrayContains(String.format("Unsupported recommended size %s for " + 695 "format: %d for ID: %s", sz.toString(), format, id), 696 exhaustiveSizes, sz); 697 698 long recommendedMinDuration = config.getOutputMinFrameDuration(format, sz); 699 long availableMinDuration = fullConfig.getOutputMinFrameDuration(format, sz); 700 assertTrue(String.format("Recommended minimum frame duration %d for size " + 701 "%s format: %d doesn't match with currently available minimum" + 702 " frame duration of %d for ID: %s", recommendedMinDuration, 703 sz.toString(), format, availableMinDuration, id), 704 (recommendedMinDuration == availableMinDuration)); 705 long recommendedStallDuration = config.getOutputStallDuration(format, sz); 706 long availableStallDuration = fullConfig.getOutputStallDuration(format, sz); 707 assertTrue(String.format("Recommended stall duration %d for size %s" + 708 " format: %d doesn't match with currently available stall " + 709 "duration of %d for ID: %s", recommendedStallDuration, 710 sz.toString(), format, availableStallDuration, id), 711 (recommendedStallDuration == availableStallDuration)); 712 713 ImageReader reader = ImageReader.newInstance(sz.getWidth(), sz.getHeight(), format, 714 /*maxImages*/1); 715 Surface readerSurface = reader.getSurface(); 716 assertTrue(String.format("ImageReader surface using format %d and size %s is not" + 717 " supported for ID: %s", format, sz.toString(), id), 718 config.isOutputSupportedFor(readerSurface)); 719 if (format == ImageFormat.PRIVATE) { 720 long classMinDuration = config.getOutputMinFrameDuration(ImageReader.class, sz); 721 assertTrue(String.format("Recommended minimum frame duration %d for size " + 722 "%s format: %d doesn't match with the duration %d for " + 723 "ImageReader class of the same size", recommendedMinDuration, 724 sz.toString(), format, classMinDuration), 725 classMinDuration == recommendedMinDuration); 726 long classStallDuration = config.getOutputStallDuration(ImageReader.class, sz); 727 assertTrue(String.format("Recommended stall duration %d for size " + 728 "%s format: %d doesn't match with the stall duration %d for " + 729 "ImageReader class of the same size", recommendedStallDuration, 730 sz.toString(), format, classStallDuration), 731 classStallDuration == recommendedStallDuration); 732 } 733 } 734 } 735 } 736 verifyRecommendedPreviewConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap previewConfig)737 private void verifyRecommendedPreviewConfiguration(String cameraId, CameraCharacteristics c, 738 RecommendedStreamConfigurationMap previewConfig) { 739 verifyCommonRecommendedConfiguration(cameraId, c, previewConfig, /*checkNoInput*/ true, 740 /*checkNoHighRes*/ true, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 741 /*checkNoDepth*/ true); 742 743 Set<Integer> outputFormats = previewConfig.getOutputFormats(); 744 assertTrue(String.format("No valid YUV_420_888 and PRIVATE preview " + 745 "formats found in recommended preview configuration for ID: %s", cameraId), 746 outputFormats.containsAll(Arrays.asList(new Integer(ImageFormat.YUV_420_888), 747 new Integer(ImageFormat.PRIVATE)))); 748 } 749 verifyRecommendedVideoConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap videoConfig)750 private void verifyRecommendedVideoConfiguration(String cameraId, CameraCharacteristics c, 751 RecommendedStreamConfigurationMap videoConfig) { 752 verifyCommonRecommendedConfiguration(cameraId, c, videoConfig, /*checkNoInput*/ true, 753 /*checkNoHighRes*/ true, /*checkNoHighSpeed*/ false, /*checkNoPrivate*/false, 754 /*checkNoDepth*/ true); 755 756 Set<Size> highSpeedSizes = videoConfig.getHighSpeedVideoSizes(); 757 StreamConfigurationMap fullConfig = c.get( 758 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 759 assertNotNull("No stream configuration map found!", fullConfig); 760 Size [] availableHighSpeedSizes = fullConfig.getHighSpeedVideoSizes(); 761 if ((highSpeedSizes != null) && (highSpeedSizes.size() > 0)) { 762 for (Size sz : highSpeedSizes) { 763 assertArrayContains(String.format("Recommended video configuration includes " + 764 "unsupported high speed configuration with size %s for ID: %s", 765 sz.toString(), cameraId), availableHighSpeedSizes, sz); 766 Set<Range<Integer>> highSpeedFpsRanges = 767 videoConfig.getHighSpeedVideoFpsRangesFor(sz); 768 Range<Integer> [] availableHighSpeedFpsRanges = 769 fullConfig.getHighSpeedVideoFpsRangesFor(sz); 770 for (Range<Integer> fpsRange : highSpeedFpsRanges) { 771 assertArrayContains(String.format("Recommended video configuration includes " + 772 "unsupported high speed fps range [%d %d] for ID: %s", 773 fpsRange.getLower().intValue(), fpsRange.getUpper().intValue(), 774 cameraId), availableHighSpeedFpsRanges, fpsRange); 775 } 776 } 777 } 778 779 final int[] profileList = { 780 CamcorderProfile.QUALITY_2160P, 781 CamcorderProfile.QUALITY_1080P, 782 CamcorderProfile.QUALITY_480P, 783 CamcorderProfile.QUALITY_720P, 784 CamcorderProfile.QUALITY_CIF, 785 CamcorderProfile.QUALITY_HIGH, 786 CamcorderProfile.QUALITY_LOW, 787 CamcorderProfile.QUALITY_QCIF, 788 CamcorderProfile.QUALITY_QVGA, 789 }; 790 Set<Size> privateSizeSet = videoConfig.getOutputSizes(ImageFormat.PRIVATE); 791 for (int profile : profileList) { 792 int idx = Integer.valueOf(cameraId); 793 if (CamcorderProfile.hasProfile(idx, profile)) { 794 CamcorderProfile videoProfile = CamcorderProfile.get(idx, profile); 795 Size profileSize = new Size(videoProfile.videoFrameWidth, 796 videoProfile.videoFrameHeight); 797 assertCollectionContainsAnyOf(String.format("Recommended video configuration " + 798 "doesn't include supported video profile size %s with Private format " + 799 "for ID: %s", profileSize.toString(), cameraId), privateSizeSet, 800 Arrays.asList(profileSize)); 801 } 802 } 803 } 804 isSizeWithinSensorMargin(Size sz, Size sensorSize)805 private Pair<Boolean, Size> isSizeWithinSensorMargin(Size sz, Size sensorSize) { 806 final float SIZE_ERROR_MARGIN = 0.03f; 807 float croppedWidth = (float)sensorSize.getWidth(); 808 float croppedHeight = (float)sensorSize.getHeight(); 809 float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight(); 810 float maxAspectRatio = (float)sz.getWidth() / (float)sz.getHeight(); 811 if (sensorAspectRatio < maxAspectRatio) { 812 croppedHeight = (float)sensorSize.getWidth() / maxAspectRatio; 813 } else if (sensorAspectRatio > maxAspectRatio) { 814 croppedWidth = (float)sensorSize.getHeight() * maxAspectRatio; 815 } 816 Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight); 817 818 Boolean match = new Boolean( 819 (sz.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) && 820 sz.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) && 821 sz.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) && 822 sz.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN))); 823 824 return Pair.create(match, croppedSensorSize); 825 } 826 verifyRecommendedSnapshotConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap snapshotConfig)827 private void verifyRecommendedSnapshotConfiguration(String cameraId, CameraCharacteristics c, 828 RecommendedStreamConfigurationMap snapshotConfig) { 829 verifyCommonRecommendedConfiguration(cameraId, c, snapshotConfig, /*checkNoInput*/ true, 830 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/false, 831 /*checkNoDepth*/ false); 832 Rect activeRect = CameraTestUtils.getValueNotNull( 833 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 834 Size arraySize = new Size(activeRect.width(), activeRect.height()); 835 836 837 ArraySet<Size> snapshotSizeSet = new ArraySet<>(snapshotConfig.getOutputSizes( 838 ImageFormat.JPEG)); 839 Set<Size> highResSnapshotSizeSet = snapshotConfig.getHighResolutionOutputSizes( 840 ImageFormat.JPEG); 841 if (highResSnapshotSizeSet != null) { 842 snapshotSizeSet.addAll(highResSnapshotSizeSet); 843 } 844 Size[] snapshotSizes = new Size[snapshotSizeSet.size()]; 845 snapshotSizes = snapshotSizeSet.toArray(snapshotSizes); 846 Size maxJpegSize = CameraTestUtils.getMaxSize(snapshotSizes); 847 assertTrue(String.format("Maximum recommended Jpeg size %s should be within 3 percent " + 848 "of the area of the advertised array size %s for ID: %s", 849 maxJpegSize.toString(), arraySize.toString(), cameraId), 850 isSizeWithinSensorMargin(maxJpegSize, arraySize).first.booleanValue()); 851 } 852 verifyRecommendedVideoSnapshotConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap videoSnapshotConfig, RecommendedStreamConfigurationMap videoConfig)853 private void verifyRecommendedVideoSnapshotConfiguration(String cameraId, 854 CameraCharacteristics c, 855 RecommendedStreamConfigurationMap videoSnapshotConfig, 856 RecommendedStreamConfigurationMap videoConfig) { 857 verifyCommonRecommendedConfiguration(cameraId, c, videoSnapshotConfig, 858 /*checkNoInput*/ true, /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, 859 /*checkNoPrivate*/ true, /*checkNoDepth*/ true); 860 861 Set<Integer> outputFormats = videoSnapshotConfig.getOutputFormats(); 862 assertCollectionContainsAnyOf(String.format("No valid JPEG format found " + 863 "in recommended video snapshot configuration for ID: %s", cameraId), 864 outputFormats, Arrays.asList(new Integer(ImageFormat.JPEG))); 865 assertTrue(String.format("Recommended video snapshot configuration must only advertise " + 866 "JPEG format for ID: %s", cameraId), outputFormats.size() == 1); 867 868 Set<Size> privateVideoSizeSet = videoConfig.getOutputSizes(ImageFormat.PRIVATE); 869 Size[] privateVideoSizes = new Size[privateVideoSizeSet.size()]; 870 privateVideoSizes = privateVideoSizeSet.toArray(privateVideoSizes); 871 Size maxVideoSize = CameraTestUtils.getMaxSize(privateVideoSizes); 872 Set<Size> outputSizes = videoSnapshotConfig.getOutputSizes(ImageFormat.JPEG); 873 assertCollectionContainsAnyOf(String.format("The maximum recommended video size %s " + 874 "should be present in the recommended video snapshot configurations for ID: %s", 875 maxVideoSize.toString(), cameraId), outputSizes, Arrays.asList(maxVideoSize)); 876 } 877 verifyRecommendedRawConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap rawConfig)878 private void verifyRecommendedRawConfiguration(String cameraId, 879 CameraCharacteristics c, RecommendedStreamConfigurationMap rawConfig) { 880 verifyCommonRecommendedConfiguration(cameraId, c, rawConfig, /*checkNoInput*/ true, 881 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ true, 882 /*checkNoDepth*/ true); 883 884 Set<Integer> outputFormats = rawConfig.getOutputFormats(); 885 for (Integer outputFormatInteger : outputFormats) { 886 int outputFormat = outputFormatInteger.intValue(); 887 switch (outputFormat) { 888 case ImageFormat.RAW10: 889 case ImageFormat.RAW12: 890 case ImageFormat.RAW_PRIVATE: 891 case ImageFormat.RAW_SENSOR: 892 break; 893 default: 894 fail(String.format("Recommended raw configuration map must not contain " + 895 " non-RAW formats like: %d for ID: %s", outputFormat, cameraId)); 896 897 } 898 } 899 } 900 verifyRecommendedZSLConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap zslConfig)901 private void verifyRecommendedZSLConfiguration(String cameraId, CameraCharacteristics c, 902 RecommendedStreamConfigurationMap zslConfig) { 903 verifyCommonRecommendedConfiguration(cameraId, c, zslConfig, /*checkNoInput*/ false, 904 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 905 /*checkNoDepth*/ false); 906 907 StreamConfigurationMap fullConfig = 908 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 909 assertNotNull(String.format("No stream configuration map found for ID: %s!", cameraId), 910 fullConfig); 911 Set<Integer> inputFormats = zslConfig.getInputFormats(); 912 int [] availableInputFormats = fullConfig.getInputFormats(); 913 for (Integer inputFormatInteger : inputFormats) { 914 int inputFormat = inputFormatInteger.intValue(); 915 assertArrayContains(String.format("Recommended ZSL configuration includes " + 916 "unsupported input format %d for ID: %s", inputFormat, cameraId), 917 availableInputFormats, inputFormat); 918 919 Set<Size> inputSizes = zslConfig.getInputSizes(inputFormat); 920 Size [] availableInputSizes = fullConfig.getInputSizes(inputFormat); 921 assertTrue(String.format("Recommended ZSL configuration input format %d includes " + 922 "invalid input sizes for ID: %s", inputFormat, cameraId), 923 ((inputSizes != null) && (inputSizes.size() > 0))); 924 for (Size inputSize : inputSizes) { 925 assertArrayContains(String.format("Recommended ZSL configuration includes " + 926 "unsupported input format %d with size %s ID: %s", inputFormat, 927 inputSize.toString(), cameraId), availableInputSizes, inputSize); 928 } 929 Set<Integer> validOutputFormats = zslConfig.getValidOutputFormatsForInput(inputFormat); 930 int [] availableValidOutputFormats = fullConfig.getValidOutputFormatsForInput( 931 inputFormat); 932 for (Integer outputFormatInteger : validOutputFormats) { 933 int outputFormat = outputFormatInteger.intValue(); 934 assertArrayContains(String.format("Recommended ZSL configuration includes " + 935 "unsupported output format %d for input %s ID: %s", outputFormat, 936 inputFormat, cameraId), availableValidOutputFormats, outputFormat); 937 } 938 } 939 } 940 checkFormatLatency(int format, long latencyThresholdMs, RecommendedStreamConfigurationMap configMap)941 private void checkFormatLatency(int format, long latencyThresholdMs, 942 RecommendedStreamConfigurationMap configMap) throws Exception { 943 Set<Size> availableSizes = configMap.getOutputSizes(format); 944 assertNotNull(String.format("No available sizes for output format: %d", format), 945 availableSizes); 946 947 ImageReader previewReader = null; 948 long threshold = (long) (latencyThresholdMs * LATENCY_TOLERANCE_FACTOR); 949 // for each resolution, check that the end-to-end latency doesn't exceed the given threshold 950 for (Size sz : availableSizes) { 951 try { 952 // Create ImageReaders, capture session and requests 953 final ImageReader.OnImageAvailableListener mockListener = mock( 954 ImageReader.OnImageAvailableListener.class); 955 createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mockListener); 956 Size previewSize = mOrderedPreviewSizes.get(0); 957 previewReader = createImageReader(previewSize, ImageFormat.YUV_420_888, 958 MAX_NUM_IMAGES, new CameraTestUtils.ImageDropperListener()); 959 Surface previewSurface = previewReader.getSurface(); 960 List<Surface> surfaces = new ArrayList<Surface>(); 961 surfaces.add(previewSurface); 962 surfaces.add(mReaderSurface); 963 createSession(surfaces); 964 CaptureRequest.Builder captureBuilder = 965 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 966 captureBuilder.addTarget(previewSurface); 967 CaptureRequest request = captureBuilder.build(); 968 969 // Let preview run for a while 970 startCapture(request, /*repeating*/ true, new SimpleCaptureCallback(), mHandler); 971 Thread.sleep(PREVIEW_RUN_MS); 972 973 // Start capture. 974 captureBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 975 captureBuilder.addTarget(mReaderSurface); 976 request = captureBuilder.build(); 977 978 for (int i = 0; i < MAX_NUM_IMAGES; i++) { 979 startCapture(request, /*repeating*/ false, new SimpleCaptureCallback(), 980 mHandler); 981 verify(mockListener, timeout(threshold).times(1)).onImageAvailable( 982 any(ImageReader.class)); 983 reset(mockListener); 984 } 985 986 // stop capture. 987 stopCapture(/*fast*/ false); 988 } finally { 989 closeDefaultImageReader(); 990 991 if (previewReader != null) { 992 previewReader.close(); 993 previewReader = null; 994 } 995 } 996 997 } 998 } 999 verifyRecommendedLowLatencyConfiguration(String cameraId, CameraCharacteristics c, RecommendedStreamConfigurationMap lowLatencyConfig)1000 private void verifyRecommendedLowLatencyConfiguration(String cameraId, CameraCharacteristics c, 1001 RecommendedStreamConfigurationMap lowLatencyConfig) throws Exception { 1002 verifyCommonRecommendedConfiguration(cameraId, c, lowLatencyConfig, /*checkNoInput*/ true, 1003 /*checkNoHighRes*/ false, /*checkNoHighSpeed*/ true, /*checkNoPrivate*/ false, 1004 /*checkNoDepth*/ true); 1005 1006 try { 1007 openDevice(cameraId); 1008 1009 Set<Integer> formats = lowLatencyConfig.getOutputFormats(); 1010 for (Integer format : formats) { 1011 checkFormatLatency(format.intValue(), LOW_LATENCY_THRESHOLD_MS, lowLatencyConfig); 1012 } 1013 } finally { 1014 closeDevice(cameraId); 1015 } 1016 1017 } 1018 1019 @Test testRecommendedStreamConfigurations()1020 public void testRecommendedStreamConfigurations() throws Exception { 1021 String[] allCameraIds = getAllCameraIds(); 1022 for (int i = 0; i < allCameraIds.length; i++) { 1023 CameraCharacteristics c = mCharacteristics.get(i); 1024 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1025 assertNotNull("android.request.availableCapabilities must never be null", 1026 actualCapabilities); 1027 1028 if (!arrayContains(actualCapabilities, BC)) { 1029 Log.i(TAG, "Camera " + allCameraIds[i] + 1030 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 1031 continue; 1032 } 1033 1034 try { 1035 RecommendedStreamConfigurationMap map = c.getRecommendedStreamConfigurationMap( 1036 RecommendedStreamConfigurationMap.USECASE_PREVIEW - 1); 1037 fail("Recommended configuration map shouldn't be available for invalid " + 1038 "use case!"); 1039 } catch (IllegalArgumentException e) { 1040 //Expected continue 1041 } 1042 1043 try { 1044 RecommendedStreamConfigurationMap map = c.getRecommendedStreamConfigurationMap( 1045 RecommendedStreamConfigurationMap.USECASE_10BIT_OUTPUT + 1); 1046 fail("Recommended configuration map shouldn't be available for invalid " + 1047 "use case!"); 1048 } catch (IllegalArgumentException e) { 1049 //Expected continue 1050 } 1051 1052 RecommendedStreamConfigurationMap previewConfig = 1053 c.getRecommendedStreamConfigurationMap( 1054 RecommendedStreamConfigurationMap.USECASE_PREVIEW); 1055 RecommendedStreamConfigurationMap videoRecordingConfig = 1056 c.getRecommendedStreamConfigurationMap( 1057 RecommendedStreamConfigurationMap.USECASE_RECORD); 1058 RecommendedStreamConfigurationMap videoSnapshotConfig = 1059 c.getRecommendedStreamConfigurationMap( 1060 RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT); 1061 RecommendedStreamConfigurationMap snapshotConfig = 1062 c.getRecommendedStreamConfigurationMap( 1063 RecommendedStreamConfigurationMap.USECASE_SNAPSHOT); 1064 RecommendedStreamConfigurationMap rawConfig = 1065 c.getRecommendedStreamConfigurationMap( 1066 RecommendedStreamConfigurationMap.USECASE_RAW); 1067 RecommendedStreamConfigurationMap zslConfig = 1068 c.getRecommendedStreamConfigurationMap( 1069 RecommendedStreamConfigurationMap.USECASE_ZSL); 1070 RecommendedStreamConfigurationMap lowLatencyConfig = 1071 c.getRecommendedStreamConfigurationMap( 1072 RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT); 1073 RecommendedStreamConfigurationMap dynamic10BitOutputConfig = 1074 c.getRecommendedStreamConfigurationMap( 1075 RecommendedStreamConfigurationMap.USECASE_10BIT_OUTPUT); 1076 if ((previewConfig == null) && (videoRecordingConfig == null) && 1077 (videoSnapshotConfig == null) && (snapshotConfig == null) && 1078 (rawConfig == null) && (zslConfig == null) && (lowLatencyConfig == null)) { 1079 Log.i(TAG, "Camera " + allCameraIds[i] + 1080 " doesn't support recommended configurations, skipping test"); 1081 continue; 1082 } 1083 1084 assertNotNull(String.format("Mandatory recommended preview configuration map not " + 1085 "found for: ID %s", allCameraIds[i]), previewConfig); 1086 verifyRecommendedPreviewConfiguration(allCameraIds[i], c, previewConfig); 1087 1088 assertNotNull(String.format("Mandatory recommended video recording configuration map " + 1089 "not found for: ID %s", allCameraIds[i]), videoRecordingConfig); 1090 verifyRecommendedVideoConfiguration(allCameraIds[i], c, videoRecordingConfig); 1091 1092 assertNotNull(String.format("Mandatory recommended video snapshot configuration map " + 1093 "not found for: ID %s", allCameraIds[i]), videoSnapshotConfig); 1094 verifyRecommendedVideoSnapshotConfiguration(allCameraIds[i], c, videoSnapshotConfig, 1095 videoRecordingConfig); 1096 1097 assertNotNull(String.format("Mandatory recommended snapshot configuration map not " + 1098 "found for: ID %s", allCameraIds[i]), snapshotConfig); 1099 verifyRecommendedSnapshotConfiguration(allCameraIds[i], c, snapshotConfig); 1100 1101 if (arrayContains(actualCapabilities, RAW)) { 1102 assertNotNull(String.format("Mandatory recommended raw configuration map not " + 1103 "found for: ID %s", allCameraIds[i]), rawConfig); 1104 verifyRecommendedRawConfiguration(allCameraIds[i], c, rawConfig); 1105 } 1106 1107 if (arrayContains(actualCapabilities, OPAQUE_REPROCESS) || 1108 arrayContains(actualCapabilities, YUV_REPROCESS)) { 1109 assertNotNull(String.format("Mandatory recommended ZSL configuration map not " + 1110 "found for: ID %s", allCameraIds[i]), zslConfig); 1111 verifyRecommendedZSLConfiguration(allCameraIds[i], c, zslConfig); 1112 } 1113 1114 if (lowLatencyConfig != null) { 1115 verifyRecommendedLowLatencyConfiguration(allCameraIds[i], c, lowLatencyConfig); 1116 } 1117 1118 if (dynamic10BitOutputConfig != null) { 1119 verifyCommonRecommendedConfiguration(allCameraIds[i], c, dynamic10BitOutputConfig, 1120 /*checkNoInput*/ true, /*checkNoHighRes*/ false, 1121 /*checkNoHighSpeed*/ false, /*checkNoPrivate*/ false, 1122 /*checkNoDepth*/ true); 1123 } 1124 } 1125 } 1126 1127 /** 1128 * Test {@link CameraCharacteristics#getKeys} 1129 */ 1130 @Test testKeys()1131 public void testKeys() throws Exception { 1132 String[] allCameraIds = getAllCameraIds(); 1133 for (int i = 0; i < allCameraIds.length; i++) { 1134 CameraCharacteristics c = mCharacteristics.get(i); 1135 mCollector.setCameraId(allCameraIds[i]); 1136 1137 if (VERBOSE) { 1138 Log.v(TAG, "testKeys - testing characteristics for camera " + allCameraIds[i]); 1139 } 1140 1141 List<CameraCharacteristics.Key<?>> allKeys = c.getKeys(); 1142 assertNotNull("Camera characteristics keys must not be null", allKeys); 1143 assertFalse("Camera characteristics keys must have at least 1 key", 1144 allKeys.isEmpty()); 1145 1146 for (CameraCharacteristics.Key<?> key : allKeys) { 1147 assertKeyPrefixValid(key.getName()); 1148 1149 // All characteristics keys listed must never be null 1150 mCollector.expectKeyValueNotNull(c, key); 1151 1152 // TODO: add a check that key must not be @hide 1153 } 1154 1155 /* 1156 * List of keys that must be present in camera characteristics (not null). 1157 * 1158 * Keys for LIMITED, FULL devices might be available despite lacking either 1159 * the hardware level or the capability. This is *OK*. This only lists the 1160 * *minimal* requirements for a key to be listed. 1161 * 1162 * LEGACY devices are a bit special since they map to api1 devices, so we know 1163 * for a fact most keys are going to be illegal there so they should never be 1164 * available. 1165 * 1166 * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to 1167 * do the actual checking. 1168 */ 1169 { 1170 // (Key Name) (HW Level) (Capabilities <Var-Arg>) 1171 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES , OPT , BC ); 1172 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES , OPT , BC ); 1173 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES , OPT , BC ); 1174 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES , OPT , BC ); 1175 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , OPT , BC ); 1176 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , OPT , BC ); 1177 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , OPT , BC ); 1178 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE , OPT , BC ); 1179 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , OPT , BC ); 1180 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AUTOFRAMING_AVAILABLE , LIMITED , NONE ); 1181 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , OPT , BC ); 1182 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , OPT , BC ); 1183 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , OPT , BC ); 1184 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , OPT , BC ); 1185 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE , OPT , BC ); 1186 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE , OPT , BC ); 1187 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF , OPT , BC ); 1188 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB , OPT , BC ); 1189 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES , FULL , NONE ); 1190 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE , OPT , BC ); 1191 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES , OPT , RAW ); 1192 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , OPT , BC ); 1193 expectKeyAvailable(c, CameraCharacteristics.INFO_VERSION , OPT , NONE ); 1194 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES , OPT , BC ); 1195 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING , OPT , BC ); 1196 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES , FULL , MANUAL_SENSOR ); 1197 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES , FULL , MANUAL_SENSOR ); 1198 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION , LIMITED , BC ); 1199 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION , LIMITED , MANUAL_SENSOR ); 1200 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE , LIMITED , BC ); 1201 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE , LIMITED , BC ); 1202 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT , BC ); 1203 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES , OPT , BC ); 1204 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS , OPT , YUV_REPROCESS, OPAQUE_REPROCESS); 1205 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , CONSTRAINED_HIGH_SPEED); 1206 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC , OPT , BC ); 1207 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING , OPT , BC ); 1208 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW , OPT , BC ); 1209 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT , OPT , BC ); 1210 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH , OPT , BC ); 1211 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM , OPT , BC ); 1212 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , BC ); 1213 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE , OPT , BC ); 1214 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN , FULL , RAW ); 1215 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE , OPT , BC, RAW ); 1216 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT , FULL , RAW ); 1217 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE , FULL , MANUAL_SENSOR ); 1218 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION , FULL , MANUAL_SENSOR ); 1219 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE , OPT , BC ); 1220 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE , FULL , MANUAL_SENSOR ); 1221 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL , OPT , RAW ); 1222 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE , OPT , BC ); 1223 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY , FULL , MANUAL_SENSOR ); 1224 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION , OPT , BC ); 1225 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES , LIMITED , MANUAL_POSTPROC, RAW ); 1226 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES , OPT , BC ); 1227 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES , OPT , RAW ); 1228 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED , RAW ); 1229 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT , OPT , BC ); 1230 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY , OPT , BC ); 1231 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES , FULL , MANUAL_POSTPROC ); 1232 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS , FULL , MANUAL_POSTPROC ); 1233 1234 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line 1235 1236 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list 1237 } 1238 1239 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1240 assertNotNull("android.request.availableCapabilities must never be null", 1241 actualCapabilities); 1242 boolean isMonochrome = arrayContains(actualCapabilities, 1243 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME); 1244 if (!isMonochrome) { 1245 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1 , OPT , RAW ); 1246 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1 , OPT , RAW ); 1247 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1 , OPT , RAW ); 1248 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1 , OPT , RAW ); 1249 1250 1251 // Only check for these if the second reference illuminant is included 1252 if (allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)) { 1253 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2 , OPT , RAW ); 1254 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2 , OPT , RAW ); 1255 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2 , OPT , RAW ); 1256 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2 , OPT , RAW ); 1257 } 1258 } 1259 1260 // Required key if any of RAW format output is supported 1261 StreamConfigurationMap config = 1262 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1263 assertNotNull(String.format("No stream configuration map found for: ID %s", 1264 allCameraIds[i]), config); 1265 if (config.isOutputSupportedFor(ImageFormat.RAW_SENSOR) || 1266 config.isOutputSupportedFor(ImageFormat.RAW10) || 1267 config.isOutputSupportedFor(ImageFormat.RAW12) || 1268 config.isOutputSupportedFor(ImageFormat.RAW_PRIVATE)) { 1269 expectKeyAvailable(c, 1270 CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, OPT, BC); 1271 } 1272 1273 // External Camera exceptional keys 1274 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1275 boolean isExternalCamera = (hwLevel == 1276 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 1277 if (!isExternalCamera) { 1278 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS , OPT , BC ); 1279 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES , OPT , BC ); 1280 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE , OPT , BC ); 1281 } 1282 1283 1284 // Verify version is a short text string. 1285 if (allKeys.contains(CameraCharacteristics.INFO_VERSION)) { 1286 final String TEXT_REGEX = "[\\p{Alnum}\\p{Punct}\\p{Space}]*"; 1287 final int MAX_VERSION_LENGTH = 256; 1288 1289 String version = c.get(CameraCharacteristics.INFO_VERSION); 1290 mCollector.expectTrue("Version contains non-text characters: " + version, 1291 version.matches(TEXT_REGEX)); 1292 mCollector.expectLessOrEqual("Version too long: " + version, MAX_VERSION_LENGTH, 1293 version.length()); 1294 } 1295 1296 // Verify COLOR_CORRECTION_AVAILABLE_MODES is populated if color correction 1297 // mode is supported 1298 if (Flags.colorTemperature()) { 1299 List<CaptureRequest.Key<?>> availableRequestKeys = 1300 c.getAvailableCaptureRequestKeys(); 1301 if (availableRequestKeys.contains(CaptureRequest.COLOR_CORRECTION_MODE)) { 1302 mCollector.expectNotNull("COLOR_CORRECTION_AVAILABLE_MODES must be advertised" 1303 + " if COLOR_CORRECTION_MODE is supported", 1304 c.get(CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_MODES)); 1305 } 1306 } 1307 } 1308 } 1309 1310 /** 1311 * Test values for static metadata used by the RAW capability. 1312 */ 1313 @Test testStaticRawCharacteristics()1314 public void testStaticRawCharacteristics() throws Exception { 1315 String[] allCameraIds = getAllCameraIds(); 1316 for (int i = 0; i < allCameraIds.length; i++) { 1317 CameraCharacteristics c = mCharacteristics.get(i); 1318 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1319 assertNotNull("android.request.availableCapabilities must never be null", 1320 actualCapabilities); 1321 if (!arrayContains(actualCapabilities, 1322 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1323 Log.i(TAG, "RAW capability is not supported in camera " + allCameraIds[i] + 1324 ". Skip the test."); 1325 continue; 1326 } 1327 1328 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1329 if (actualHwLevel != null && actualHwLevel == FULL) { 1330 mCollector.expectKeyValueContains(c, 1331 CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, 1332 CameraCharacteristics.HOT_PIXEL_MODE_FAST); 1333 } 1334 mCollector.expectKeyValueContains(c, 1335 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false); 1336 mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL, 1337 MIN_ALLOWABLE_WHITELEVEL); 1338 1339 1340 boolean isMonochrome = arrayContains(actualCapabilities, 1341 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME); 1342 if (!isMonochrome) { 1343 mCollector.expectKeyValueIsIn(c, 1344 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 1345 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, 1346 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, 1347 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, 1348 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR); 1349 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 1350 1351 mCollector.expectKeyValueInRange(c, 1352 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1, 1353 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 1354 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 1355 // Only check the range if the second reference illuminant is avaliable 1356 if (c.get(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2) != null) { 1357 mCollector.expectKeyValueInRange(c, 1358 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 1359 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 1360 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 1361 } 1362 1363 Rational[] zeroes = new Rational[9]; 1364 Arrays.fill(zeroes, Rational.ZERO); 1365 1366 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 1367 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 1368 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 1369 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 1370 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 1371 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 1372 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 1373 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 1374 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 1375 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 1376 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 1377 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 1378 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 1379 } else { 1380 mCollector.expectKeyValueIsIn(c, 1381 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 1382 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO, 1383 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR); 1384 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 1385 } 1386 1387 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 1388 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 1389 if (blackLevel != null) { 1390 String blackLevelPatternString = blackLevel.toString(); 1391 if (VERBOSE) { 1392 Log.v(TAG, "Black level pattern: " + blackLevelPatternString); 1393 } 1394 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 1395 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 1396 if (isMonochrome) { 1397 for (int index = 1; index < BlackLevelPattern.COUNT; index++) { 1398 mCollector.expectEquals( 1399 "Monochrome camera 2x2 channels blacklevel value must be the same.", 1400 blackLevelPattern[index], blackLevelPattern[0]); 1401 } 1402 } 1403 1404 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 1405 if (whitelevel != null) { 1406 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 1407 whitelevel); 1408 } else { 1409 mCollector.addMessage( 1410 "No WhiteLevel available, cannot check BlackLevelPattern range."); 1411 } 1412 } 1413 1414 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 1415 } 1416 } 1417 1418 /** 1419 * Test values for the available session keys. 1420 */ 1421 @Test testStaticSessionKeys()1422 public void testStaticSessionKeys() throws Exception { 1423 for (CameraCharacteristics c : mCharacteristics) { 1424 List<CaptureRequest.Key<?>> availableSessionKeys = c.getAvailableSessionKeys(); 1425 if (availableSessionKeys == null) { 1426 continue; 1427 } 1428 List<CaptureRequest.Key<?>> availableRequestKeys = c.getAvailableCaptureRequestKeys(); 1429 1430 //Every session key should be part of the available request keys 1431 for (CaptureRequest.Key<?> key : availableSessionKeys) { 1432 assertTrue("Session key:" + key.getName() + " not present in the available capture " 1433 + "request keys!", availableRequestKeys.contains(key)); 1434 } 1435 } 1436 } 1437 1438 /** 1439 * Test values for static metadata used by the BURST capability. 1440 */ 1441 @Test testStaticBurstCharacteristics()1442 public void testStaticBurstCharacteristics() throws Exception { 1443 String[] allCameraIds = getAllCameraIds(); 1444 for (int i = 0; i < allCameraIds.length; i++) { 1445 CameraCharacteristics c = mCharacteristics.get(i); 1446 int[] actualCapabilities = CameraTestUtils.getValueNotNull( 1447 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1448 1449 // Check if the burst capability is defined 1450 boolean haveBurstCapability = arrayContains(actualCapabilities, 1451 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 1452 boolean haveBC = arrayContains(actualCapabilities, 1453 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 1454 1455 if(haveBurstCapability && !haveBC) { 1456 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined"); 1457 } 1458 1459 if (!haveBC) continue; 1460 1461 StreamConfigurationMap config = 1462 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1463 assertNotNull(String.format("No stream configuration map found for: ID %s", 1464 allCameraIds[i]), config); 1465 Rect activeRect = CameraTestUtils.getValueNotNull( 1466 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 1467 Size sensorSize = new Size(activeRect.width(), activeRect.height()); 1468 1469 // Ensure that max YUV size matches max JPEG size 1470 Size maxYuvSize = CameraTestUtils.getMaxSize( 1471 config.getOutputSizes(ImageFormat.YUV_420_888)); 1472 Size maxFastYuvSize = maxYuvSize; 1473 1474 Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888); 1475 Size maxSlowYuvSizeLessThan24M = null; 1476 if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) { 1477 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes); 1478 final int SIZE_24MP_BOUND = 24000000; 1479 maxSlowYuvSizeLessThan24M = 1480 CameraTestUtils.getMaxSizeWithBound(slowYuvSizes, SIZE_24MP_BOUND); 1481 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize}); 1482 } 1483 1484 Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat( 1485 ImageFormat.JPEG, allCameraIds[i], mCameraManager)); 1486 1487 boolean haveMaxYuv = maxYuvSize != null ? 1488 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 1489 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 1490 1491 Pair<Boolean, Size> maxYuvMatchSensorPair = isSizeWithinSensorMargin(maxYuvSize, 1492 sensorSize); 1493 1494 // No need to do null check since framework will generate the key if HAL don't supply 1495 boolean haveAeLock = CameraTestUtils.getValueNotNull( 1496 c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 1497 boolean haveAwbLock = CameraTestUtils.getValueNotNull( 1498 c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 1499 1500 // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps 1501 1502 long maxFastYuvRate = 1503 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize); 1504 final long MIN_8MP_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps 1505 boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS; 1506 1507 final int SIZE_8MP_BOUND = 8000000; 1508 boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) > 1509 SIZE_8MP_BOUND; 1510 1511 // Ensure that max YUV output smaller than 24MP is fast enough 1512 // - needs to be at least 10 fps 1513 final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps 1514 long maxYuvRate = maxFastYuvRate; 1515 if (maxSlowYuvSizeLessThan24M != null) { 1516 maxYuvRate = config.getOutputMinFrameDuration( 1517 ImageFormat.YUV_420_888, maxSlowYuvSizeLessThan24M); 1518 } 1519 boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS; 1520 1521 // Ensure that there's an FPS range that's fast enough to capture at above 1522 // minFrameDuration, for full-auto bursts at the fast resolutions 1523 Range[] fpsRanges = CameraTestUtils.getValueNotNull( 1524 c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 1525 float minYuvFps = 1.f / maxFastYuvRate; 1526 1527 boolean haveFastAeTargetFps = false; 1528 for (Range<Integer> r : fpsRanges) { 1529 if (r.getLower() >= minYuvFps) { 1530 haveFastAeTargetFps = true; 1531 break; 1532 } 1533 } 1534 1535 // Ensure that maximum sync latency is small enough for fast setting changes, even if 1536 // it's not quite per-frame 1537 1538 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 1539 assertNotNull(String.format("No sync latency declared for ID %s", allCameraIds[i]), 1540 maxSyncLatencyValue); 1541 1542 int maxSyncLatency = maxSyncLatencyValue; 1543 final long MAX_LATENCY_BOUND = 4; 1544 boolean haveFastSyncLatency = 1545 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 1546 1547 if (haveBurstCapability) { 1548 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!", 1549 slowYuvSizes != null); 1550 assertTrue( 1551 String.format("BURST-capable camera device %s does not have maximum YUV " + 1552 "size that is at least max JPEG size", 1553 allCameraIds[i]), 1554 haveMaxYuv); 1555 assertTrue( 1556 String.format("BURST-capable camera device %s max-resolution " + 1557 "YUV frame rate is too slow" + 1558 "(%d ns min frame duration reported, less than %d ns expected)", 1559 allCameraIds[i], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS), 1560 haveMaxYuvRate); 1561 assertTrue( 1562 String.format("BURST-capable camera device %s >= 8MP YUV output " + 1563 "frame rate is too slow" + 1564 "(%d ns min frame duration reported, less than %d ns expected)", 1565 allCameraIds[i], maxYuvRate, MIN_8MP_DURATION_BOUND_NS), 1566 haveFastYuvRate); 1567 assertTrue( 1568 String.format("BURST-capable camera device %s does not list an AE target " + 1569 " FPS range with min FPS >= %f, for full-AUTO bursts", 1570 allCameraIds[i], minYuvFps), 1571 haveFastAeTargetFps); 1572 assertTrue( 1573 String.format("BURST-capable camera device %s YUV sync latency is too long" + 1574 "(%d frames reported, [0, %d] frames expected)", 1575 allCameraIds[i], maxSyncLatency, MAX_LATENCY_BOUND), 1576 haveFastSyncLatency); 1577 assertTrue( 1578 String.format("BURST-capable camera device %s max YUV size %s should be" + 1579 "close to active array size %s or cropped active array size %s", 1580 allCameraIds[i], maxYuvSize.toString(), sensorSize.toString(), 1581 maxYuvMatchSensorPair.second.toString()), 1582 maxYuvMatchSensorPair.first.booleanValue()); 1583 assertTrue( 1584 String.format("BURST-capable camera device %s does not support AE lock", 1585 allCameraIds[i]), 1586 haveAeLock); 1587 assertTrue( 1588 String.format("BURST-capable camera device %s does not support AWB lock", 1589 allCameraIds[i]), 1590 haveAwbLock); 1591 } else { 1592 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!", 1593 slowYuvSizes == null); 1594 assertTrue( 1595 String.format("Camera device %s has all the requirements for BURST" + 1596 " capability but does not report it!", allCameraIds[i]), 1597 !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps && 1598 haveFastSyncLatency && maxYuvMatchSensorPair.first.booleanValue() && 1599 haveAeLock && haveAwbLock)); 1600 } 1601 } 1602 } 1603 1604 /** 1605 * Check reprocessing capabilities. 1606 */ 1607 @Test testReprocessingCharacteristics()1608 public void testReprocessingCharacteristics() throws Exception { 1609 String[] allCameraIds = getAllCameraIds(); 1610 for (int i = 0; i < allCameraIds.length; i++) { 1611 Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + allCameraIds[i]); 1612 1613 CameraCharacteristics c = mCharacteristics.get(i); 1614 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1615 assertNotNull("android.request.availableCapabilities must never be null", 1616 capabilities); 1617 boolean supportYUV = arrayContains(capabilities, 1618 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 1619 boolean supportOpaque = arrayContains(capabilities, 1620 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 1621 StreamConfigurationMap configs = 1622 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1623 Integer maxNumInputStreams = 1624 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 1625 int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES); 1626 int[] availableNoiseReductionModes = c.get( 1627 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES); 1628 1629 int[] inputFormats = configs.getInputFormats(); 1630 int[] outputFormats = configs.getOutputFormats(); 1631 boolean isMonochromeWithY8 = arrayContains(capabilities, MONOCHROME) 1632 && arrayContains(outputFormats, ImageFormat.Y8); 1633 1634 boolean supportZslEdgeMode = false; 1635 boolean supportZslNoiseReductionMode = false; 1636 boolean supportHiQNoiseReductionMode = false; 1637 boolean supportHiQEdgeMode = false; 1638 1639 if (availableEdgeModes != null) { 1640 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 1641 contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 1642 supportHiQEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 1643 contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY); 1644 } 1645 1646 if (availableNoiseReductionModes != null) { 1647 supportZslNoiseReductionMode = Arrays.asList( 1648 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 1649 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 1650 supportHiQNoiseReductionMode = Arrays.asList( 1651 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 1652 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 1653 } 1654 1655 if (supportYUV || supportOpaque) { 1656 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 1657 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 1658 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " + 1659 "not supported", supportZslEdgeMode); 1660 mCollector.expectTrue("Support reprocessing but " + 1661 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported", 1662 supportZslNoiseReductionMode); 1663 1664 // For reprocessing, if we only require OFF and ZSL mode, it will be just like jpeg 1665 // encoding. We implicitly require FAST to make reprocessing meaningful, which means 1666 // that we also require HIGH_QUALITY. 1667 mCollector.expectTrue("Support reprocessing but EDGE_MODE_HIGH_QUALITY is " + 1668 "not supported", supportHiQEdgeMode); 1669 mCollector.expectTrue("Support reprocessing but " + 1670 "NOISE_REDUCTION_MODE_HIGH_QUALITY is not supported", 1671 supportHiQNoiseReductionMode); 1672 1673 // Verify mandatory input formats are supported 1674 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing", 1675 !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888)); 1676 mCollector.expectTrue("Y8 input must be supported for YUV reprocessing on " + 1677 "MONOCHROME devices with Y8 support", !supportYUV || !isMonochromeWithY8 1678 || arrayContains(inputFormats, ImageFormat.Y8)); 1679 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing", 1680 !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE)); 1681 1682 // max capture stall must be reported if one of the reprocessing is supported. 1683 final int MAX_ALLOWED_STALL_FRAMES = 4; 1684 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 1685 mCollector.expectTrue("max capture stall must be non-null and no larger than " 1686 + MAX_ALLOWED_STALL_FRAMES, 1687 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 1688 1689 for (int input : inputFormats) { 1690 // Verify mandatory output formats are supported 1691 int[] outputFormatsForInput = configs.getValidOutputFormatsForInput(input); 1692 mCollector.expectTrue( 1693 "YUV_420_888 output must be supported for reprocessing", 1694 input == ImageFormat.Y8 1695 || arrayContains(outputFormatsForInput, ImageFormat.YUV_420_888)); 1696 mCollector.expectTrue( 1697 "Y8 output must be supported for reprocessing on MONOCHROME devices with" 1698 + " Y8 support", !isMonochromeWithY8 || input == ImageFormat.YUV_420_888 1699 || arrayContains(outputFormatsForInput, ImageFormat.Y8)); 1700 mCollector.expectTrue("JPEG output must be supported for reprocessing", 1701 arrayContains(outputFormatsForInput, ImageFormat.JPEG)); 1702 1703 // Verify camera can output the reprocess input formats and sizes. 1704 Size[] inputSizes = configs.getInputSizes(input); 1705 Size[] outputSizes = configs.getOutputSizes(input); 1706 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 1707 mCollector.expectTrue("no input size supported for format " + input, 1708 inputSizes.length > 0); 1709 mCollector.expectTrue("no output size supported for format " + input, 1710 outputSizes.length > 0); 1711 1712 for (Size inputSize : inputSizes) { 1713 mCollector.expectTrue("Camera must be able to output the supported " + 1714 "reprocessing input size", 1715 arrayContains(outputSizes, inputSize) || 1716 arrayContains(highResOutputSizes, inputSize)); 1717 } 1718 } 1719 } else { 1720 mCollector.expectTrue("Doesn't support reprocessing but report input format: " + 1721 Arrays.toString(inputFormats), inputFormats.length == 0); 1722 mCollector.expectTrue("Doesn't support reprocessing but max number of input " + 1723 "stream is " + maxNumInputStreams, 1724 maxNumInputStreams == null || maxNumInputStreams == 0); 1725 mCollector.expectTrue("Doesn't support reprocessing but " + 1726 "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode); 1727 mCollector.expectTrue("Doesn't support reprocessing but " + 1728 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported", 1729 !supportZslNoiseReductionMode); 1730 } 1731 } 1732 } 1733 1734 /** 1735 * Check ultra high resolution sensor characteristics. 1736 */ 1737 @Test testUltraHighResolutionSensorCharacteristics()1738 public void testUltraHighResolutionSensorCharacteristics() throws Exception { 1739 String[] allCameraIds = getAllCameraIds(); 1740 for (int i = 0; i < allCameraIds.length; i++) { 1741 CameraCharacteristics c = mCharacteristics.get(i); 1742 String cameraId = allCameraIds[i]; 1743 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1744 assertNotNull("android.request.availableCapabilities must never be null", 1745 capabilities); 1746 boolean isUltraHighResolutionSensor = arrayContains(capabilities, 1747 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR); 1748 1749 boolean supportsRemosaic = arrayContains(capabilities, 1750 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING); 1751 1752 List<CaptureRequest.Key<?>> requestKeys = c.getAvailableCaptureRequestKeys(); 1753 boolean doesSupportSensorPixelMode = 1754 requestKeys.contains(CaptureRequest.SENSOR_PIXEL_MODE); 1755 1756 if (!isUltraHighResolutionSensor && !doesSupportSensorPixelMode) { 1757 Log.i(TAG, "Camera id " + cameraId + " not ultra high resolution / doesn't" + 1758 " support sensor pixel mode. Skipping " + 1759 "testUltraHighResolutionSensorCharacteristics"); 1760 continue; 1761 } 1762 1763 // Test conditions applicable to both ULTRA_HIGH_RESOLUTION_SENSOR devices and those 1764 // which support SENSOR_PIXEL_MODE. 1765 StreamConfigurationMap configs = 1766 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 1767 assertNotNull("Maximum resolution stream configuration map must not be null for ultra" + 1768 " high resolution sensor camera " + cameraId, configs); 1769 1770 int[] outputFormats = configs.getOutputFormats(); 1771 boolean supportsRawOutput = 1772 arrayContains(outputFormats, ImageFormat.RAW_SENSOR) || 1773 arrayContains(outputFormats, ImageFormat.RAW10) || 1774 arrayContains(outputFormats, ImageFormat.RAW_PRIVATE) || 1775 arrayContains(outputFormats, ImageFormat.RAW12); 1776 1777 if (supportsRawOutput) { 1778 Size binningFactor = c.get(CameraCharacteristics.SENSOR_INFO_BINNING_FACTOR); 1779 assertTrue("SENSOR_INFO_BINNING_FACTOR must be advertised by a sensor that " + 1780 " supports ULTRA_HIGH_RESOLUTION_SENSOR / SENSOR_PIXEL_MODE with " 1781 + " RAW outputs - camera id: " + 1782 cameraId, binningFactor != null); 1783 } 1784 1785 if (!isUltraHighResolutionSensor) { 1786 continue; 1787 } 1788 1789 // These conditions apply to ULTRA_HIGH_RESOLUTION_SENSOR devices. 1790 assertArrayContains( 1791 String.format("Ultra high resolution sensor, camera id %s" + 1792 " must also have the RAW capability", cameraId), capabilities, 1793 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW); 1794 1795 Size uhrPixelArraySize = CameraTestUtils.getValueNotNull( 1796 c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION); 1797 long uhrSensorSize = uhrPixelArraySize.getHeight() * uhrPixelArraySize.getWidth(); 1798 1799 assertTrue("ULTRA_HIGH_RESOLUTION_SENSOR pixel array size should be at least " + 1800 MIN_UHR_SENSOR_RESOLUTION + " pixels, is " + uhrSensorSize + ", for camera id " 1801 + cameraId, uhrSensorSize >= MIN_UHR_SENSOR_RESOLUTION); 1802 1803 assertArrayContains(String.format("No max res JPEG image format for ultra high" + 1804 " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.JPEG); 1805 assertArrayContains(String.format("No max res YUV_420_88 image format for ultra high" + 1806 " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.YUV_420_888); 1807 assertArrayContains(String.format("No max res RAW_SENSOR image format for ultra high" + 1808 " resolution sensor: ID %s", cameraId), outputFormats, ImageFormat.RAW_SENSOR); 1809 1810 if (supportsRemosaic) { 1811 testRemosaicReprocessingCharacteristics(cameraId, c); 1812 } 1813 } 1814 1815 } 1816 /** 1817 * Check remosaic reprocessing capabilities. Check that ImageFormat.RAW_SENSOR is supported as 1818 * input and output. 1819 */ testRemosaicReprocessingCharacteristics(String cameraId, CameraCharacteristics c)1820 private void testRemosaicReprocessingCharacteristics(String cameraId, CameraCharacteristics c) { 1821 StreamConfigurationMap configs = 1822 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 1823 Integer maxNumInputStreams = 1824 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 1825 int[] inputFormats = configs.getInputFormats(); 1826 int[] outputFormats = configs.getOutputFormats(); 1827 1828 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 1829 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 1830 1831 // Verify mandatory input formats are supported 1832 mCollector.expectTrue("RAW_SENSOR input support needed for REMOSAIC reprocessing", 1833 arrayContains(inputFormats, ImageFormat.RAW_SENSOR)); 1834 // max capture stall must be reported if one of the reprocessing is supported. 1835 final int MAX_ALLOWED_STALL_FRAMES = 4; 1836 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 1837 mCollector.expectTrue("max capture stall must be non-null and no larger than " 1838 + MAX_ALLOWED_STALL_FRAMES, 1839 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 1840 1841 for (int input : inputFormats) { 1842 // Verify mandatory output formats are supported 1843 int[] outputFormatsForInput = configs.getValidOutputFormatsForInput(input); 1844 1845 // Verify camera can output the reprocess input formats and sizes. 1846 Size[] inputSizes = configs.getInputSizes(input); 1847 Size[] outputSizes = configs.getOutputSizes(input); 1848 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 1849 mCollector.expectTrue("no input size supported for format " + input, 1850 inputSizes.length > 0); 1851 mCollector.expectTrue("no output size supported for format " + input, 1852 outputSizes.length > 0); 1853 1854 for (Size inputSize : inputSizes) { 1855 mCollector.expectTrue("Camera must be able to output the supported " + 1856 "reprocessing input size", 1857 arrayContains(outputSizes, inputSize) || 1858 arrayContains(highResOutputSizes, inputSize)); 1859 } 1860 } 1861 } 1862 1863 1864 /** 1865 * Check depth output capability 1866 */ 1867 @Test testDepthOutputCharacteristics()1868 public void testDepthOutputCharacteristics() throws Exception { 1869 String[] allCameraIds = getAllCameraIds(); 1870 for (int i = 0; i < allCameraIds.length; i++) { 1871 Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + allCameraIds[i]); 1872 1873 CameraCharacteristics c = mCharacteristics.get(i); 1874 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1875 assertNotNull("android.request.availableCapabilities must never be null", 1876 capabilities); 1877 boolean supportDepth = arrayContains(capabilities, 1878 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 1879 StreamConfigurationMap configs = 1880 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1881 1882 int[] outputFormats = configs.getOutputFormats(); 1883 boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16); 1884 1885 Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE); 1886 1887 float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 1888 float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 1889 Integer poseReference = c.get(CameraCharacteristics.LENS_POSE_REFERENCE); 1890 float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 1891 float[] distortion = getLensDistortion(c); 1892 Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 1893 Rect precorrectionArray = c.get( 1894 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 1895 Rect activeArray = c.get( 1896 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 1897 Integer facing = c.get(CameraCharacteristics.LENS_FACING); 1898 float jpegAspectRatioThreshold = .01f; 1899 boolean jpegSizeMatch = false; 1900 1901 // Verify pre-correction array encloses active array 1902 mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " + 1903 precorrectionArray.top + ", " + precorrectionArray.right + ", " + 1904 precorrectionArray.bottom + "] does not enclose activeArray[" + 1905 activeArray.left + ", " + activeArray.top + ", " + activeArray.right + 1906 ", " + activeArray.bottom, 1907 precorrectionArray.contains(activeArray.left, activeArray.top) && 1908 precorrectionArray.contains(activeArray.right-1, activeArray.bottom-1)); 1909 1910 // Verify pixel array encloses pre-correction array 1911 mCollector.expectTrue("preCorrectionArray [" + precorrectionArray.left + ", " + 1912 precorrectionArray.top + ", " + precorrectionArray.right + ", " + 1913 precorrectionArray.bottom + "] isn't enclosed by pixelArray[" + 1914 pixelArraySize.getWidth() + ", " + pixelArraySize.getHeight() + "]", 1915 precorrectionArray.left >= 0 && 1916 precorrectionArray.left < pixelArraySize.getWidth() && 1917 precorrectionArray.right > 0 && 1918 precorrectionArray.right <= pixelArraySize.getWidth() && 1919 precorrectionArray.top >= 0 && 1920 precorrectionArray.top < pixelArraySize.getHeight() && 1921 precorrectionArray.bottom > 0 && 1922 precorrectionArray.bottom <= pixelArraySize.getHeight()); 1923 1924 if (supportDepth) { 1925 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16", 1926 hasDepth16); 1927 if (hasDepth16) { 1928 Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16); 1929 Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG); 1930 mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!", 1931 depthSizes != null && depthSizes.length > 0); 1932 if (depthSizes != null) { 1933 for (Size depthSize : depthSizes) { 1934 mCollector.expectTrue("All depth16 sizes must be positive", 1935 depthSize.getWidth() > 0 && depthSize.getHeight() > 0); 1936 long minFrameDuration = configs.getOutputMinFrameDuration( 1937 ImageFormat.DEPTH16, depthSize); 1938 mCollector.expectTrue("Non-negative min frame duration for depth size " 1939 + depthSize + " expected, got " + minFrameDuration, 1940 minFrameDuration >= 0); 1941 long stallDuration = configs.getOutputStallDuration( 1942 ImageFormat.DEPTH16, depthSize); 1943 mCollector.expectTrue("Non-negative stall duration for depth size " 1944 + depthSize + " expected, got " + stallDuration, 1945 stallDuration >= 0); 1946 if ((jpegSizes != null) && (!jpegSizeMatch)) { 1947 for (Size jpegSize : jpegSizes) { 1948 if (jpegSize.equals(depthSize)) { 1949 jpegSizeMatch = true; 1950 break; 1951 } else { 1952 float depthAR = (float) depthSize.getWidth() / 1953 (float) depthSize.getHeight(); 1954 float jpegAR = (float) jpegSize.getWidth() / 1955 (float) jpegSize.getHeight(); 1956 if (Math.abs(depthAR - jpegAR) <= 1957 jpegAspectRatioThreshold) { 1958 jpegSizeMatch = true; 1959 break; 1960 } 1961 } 1962 } 1963 } 1964 } 1965 } 1966 } 1967 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) { 1968 Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD); 1969 mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " + 1970 "but no sizes for DEPTH_POINT_CLOUD supported!", 1971 depthCloudSizes != null && depthCloudSizes.length > 0); 1972 if (depthCloudSizes != null) { 1973 for (Size depthCloudSize : depthCloudSizes) { 1974 mCollector.expectTrue("All depth point cloud sizes must be nonzero", 1975 depthCloudSize.getWidth() > 0); 1976 mCollector.expectTrue("All depth point cloud sizes must be N x 1", 1977 depthCloudSize.getHeight() == 1); 1978 long minFrameDuration = configs.getOutputMinFrameDuration( 1979 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 1980 mCollector.expectTrue("Non-negative min frame duration for depth size " 1981 + depthCloudSize + " expected, got " + minFrameDuration, 1982 minFrameDuration >= 0); 1983 long stallDuration = configs.getOutputStallDuration( 1984 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 1985 mCollector.expectTrue("Non-negative stall duration for depth size " 1986 + depthCloudSize + " expected, got " + stallDuration, 1987 stallDuration >= 0); 1988 } 1989 } 1990 } 1991 if (arrayContains(outputFormats, ImageFormat.DEPTH_JPEG)) { 1992 mCollector.expectTrue("Supports DEPTH_JPEG but has no DEPTH16 support!", 1993 hasDepth16); 1994 mCollector.expectTrue("Supports DEPTH_JPEG but DEPTH_IS_EXCLUSIVE is not " + 1995 "defined", depthIsExclusive != null); 1996 mCollector.expectTrue("Supports DEPTH_JPEG but DEPTH_IS_EXCLUSIVE is true", 1997 !depthIsExclusive.booleanValue()); 1998 Size[] depthJpegSizes = configs.getOutputSizes(ImageFormat.DEPTH_JPEG); 1999 mCollector.expectTrue("Supports DEPTH_JPEG " + 2000 "but no sizes for DEPTH_JPEG supported!", 2001 depthJpegSizes != null && depthJpegSizes.length > 0); 2002 mCollector.expectTrue("Supports DEPTH_JPEG but there are no JPEG sizes with" + 2003 " matching DEPTH16 aspect ratio", jpegSizeMatch); 2004 if (depthJpegSizes != null) { 2005 for (Size depthJpegSize : depthJpegSizes) { 2006 mCollector.expectTrue("All depth jpeg sizes must be nonzero", 2007 depthJpegSize.getWidth() > 0 && depthJpegSize.getHeight() > 0); 2008 long minFrameDuration = configs.getOutputMinFrameDuration( 2009 ImageFormat.DEPTH_JPEG, depthJpegSize); 2010 mCollector.expectTrue("Non-negative min frame duration for depth jpeg" + 2011 " size " + depthJpegSize + " expected, got " + minFrameDuration, 2012 minFrameDuration >= 0); 2013 long stallDuration = configs.getOutputStallDuration( 2014 ImageFormat.DEPTH_JPEG, depthJpegSize); 2015 mCollector.expectTrue("Non-negative stall duration for depth jpeg size " 2016 + depthJpegSize + " expected, got " + stallDuration, 2017 stallDuration >= 0); 2018 } 2019 } 2020 } else { 2021 boolean canSupportDynamicDepth = jpegSizeMatch && !depthIsExclusive; 2022 mCollector.expectTrue("Device must support DEPTH_JPEG, please check whether " + 2023 "library libdepthphoto.so is part of the device PRODUCT_PACKAGES", 2024 !canSupportDynamicDepth); 2025 } 2026 2027 2028 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined", 2029 depthIsExclusive != null); 2030 2031 verifyLensCalibration(poseRotation, poseTranslation, poseReference, 2032 cameraIntrinsics, distortion, precorrectionArray, facing); 2033 2034 } else { 2035 boolean hasFields = 2036 hasDepth16 && (poseTranslation != null) && 2037 (poseRotation != null) && (cameraIntrinsics != null) && 2038 (distortion != null) && (depthIsExclusive != null); 2039 2040 mCollector.expectTrue( 2041 "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed", 2042 !hasFields); 2043 2044 boolean reportCalibration = poseTranslation != null || 2045 poseRotation != null || cameraIntrinsics !=null; 2046 // Verify calibration keys are co-existing 2047 if (reportCalibration) { 2048 mCollector.expectTrue( 2049 "Calibration keys must be co-existing", 2050 poseTranslation != null && poseRotation != null && 2051 cameraIntrinsics !=null); 2052 } 2053 2054 boolean reportDistortion = distortion != null; 2055 if (reportDistortion) { 2056 mCollector.expectTrue( 2057 "Calibration keys must present where distortion is reported", 2058 reportCalibration); 2059 } 2060 } 2061 } 2062 } 2063 2064 /** 2065 * Check 10-Bit output capability 2066 */ 2067 @CddTest(requirement="7.5/C-2-1") 2068 @Test test10BitOutputCharacteristics()2069 public void test10BitOutputCharacteristics() throws Exception { 2070 String[] allCameraIds = getAllCameraIds(); 2071 for (int i = 0; i < allCameraIds.length; i++) { 2072 Log.i(TAG, "test10BitOutputCharacteristics: Testing camera ID " + allCameraIds[i]); 2073 2074 CameraCharacteristics c = mCharacteristics.get(i); 2075 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2076 assertNotNull("android.request.availableCapabilities must never be null", 2077 capabilities); 2078 boolean supports10BitOutput = arrayContains(capabilities, 2079 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); 2080 if (!supports10BitOutput) { 2081 continue; 2082 } 2083 2084 DynamicRangeProfiles dynamicProfiles = c.get( 2085 CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES); 2086 mCollector.expectNotNull("Dynamic range profile must always be present in case " + 2087 "of 10-bit capable devices!", dynamicProfiles); 2088 Set<Long> supportedProfiles = dynamicProfiles.getSupportedProfiles(); 2089 mCollector.expectTrue("Dynamic range profiles not present!", 2090 !supportedProfiles.isEmpty()); 2091 // STANDARD and HLG10 must always be present in the supported profiles 2092 mCollector.expectContains(supportedProfiles.toArray(), DynamicRangeProfiles.STANDARD); 2093 mCollector.expectContains(supportedProfiles.toArray(), DynamicRangeProfiles.HLG10); 2094 2095 Long recommendedProfile = c.get( 2096 CameraCharacteristics.REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE); 2097 assertNotNull(recommendedProfile); 2098 mCollector.expectContains(supportedProfiles.toArray(), recommendedProfile); 2099 mCollector.expectTrue("The recommended 10-bit dynamic range profile must " + 2100 "not be the same as standard", 2101 recommendedProfile != DynamicRangeProfiles.STANDARD); 2102 mCollector.expectTrue("HLG10 profile must not have extra latency!", 2103 !dynamicProfiles.isExtraLatencyPresent(DynamicRangeProfiles.HLG10)); 2104 mCollector.expectTrue("STANDARD profile must not have extra latency!", 2105 !dynamicProfiles.isExtraLatencyPresent(DynamicRangeProfiles.STANDARD)); 2106 2107 // Verify constraints validity. For example if HLG10 advertises support for HDR10, then 2108 // there shouldn't be any HDR10 constraints related to HLG10. 2109 for (Long profile : supportedProfiles) { 2110 Set<Long> currentConstraints = 2111 dynamicProfiles.getProfileCaptureRequestConstraints(profile); 2112 boolean isSameProfilePresent = false; 2113 for (Long concurrentProfile : currentConstraints) { 2114 if (Objects.equals(concurrentProfile, profile)) { 2115 isSameProfilePresent = true; 2116 continue; 2117 } 2118 String msg = String.format("Dynamic profile %d supports profile %d " + 2119 "in the same capture request, however profile %d is not" + 2120 "advertised as supported!", profile, concurrentProfile, 2121 concurrentProfile); 2122 mCollector.expectTrue(msg, supportedProfiles.contains(concurrentProfile)); 2123 2124 Set<Long> supportedConstraints = 2125 dynamicProfiles.getProfileCaptureRequestConstraints(concurrentProfile); 2126 msg = String.format("Dynamic range profile %d advertises support " + 2127 "for profile %d, however the opposite is not true!", 2128 profile, concurrentProfile); 2129 mCollector.expectTrue(msg, supportedConstraints.isEmpty() || 2130 supportedConstraints.contains(profile)); 2131 } 2132 2133 String msg = String.format("Dynamic profile %d not present in its advertised " + 2134 "capture request constraints!", profile); 2135 mCollector.expectTrue(msg, isSameProfilePresent || currentConstraints.isEmpty()); 2136 } 2137 } 2138 } 2139 2140 /** 2141 * If device implementations support HDR 10-bit output capability, then they 2142 * MUST support 10-bit output for either the primary rear-facing or the primary front-facing 2143 * camera. 2144 */ 2145 @CddTest(requirement="7.5/C-2-2") 2146 @Test test10BitDeviceSupport()2147 public void test10BitDeviceSupport() throws Exception { 2148 boolean rearFacing10bitSupport = false; 2149 boolean frontFacing10bitSupport = false; 2150 boolean device10bitSupport = false; 2151 2152 String[] allCameraIds = getAllCameraIds(); 2153 for (int i = 0; i < allCameraIds.length; i++) { 2154 Log.i(TAG, "test10BitDeviceSupport: Testing camera ID " + allCameraIds[i]); 2155 2156 CameraCharacteristics c = mCharacteristics.get(i); 2157 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2158 assertNotNull("android.request.availableCapabilities must never be null", 2159 capabilities); 2160 boolean supports10BitOutput = arrayContains(capabilities, 2161 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); 2162 if (!supports10BitOutput) { 2163 continue; 2164 } else { 2165 device10bitSupport = true; 2166 } 2167 2168 if (CameraTestUtils.isPrimaryRearFacingCamera(mCameraManager, allCameraIds[i])) { 2169 rearFacing10bitSupport = true; 2170 } else if (CameraTestUtils.isPrimaryFrontFacingCamera(mCameraManager, 2171 allCameraIds[i])) { 2172 frontFacing10bitSupport = true; 2173 } 2174 } 2175 2176 if (device10bitSupport) { 2177 assertTrue("10-bit output support must be enabled on either front or rear " + 2178 " camera", rearFacing10bitSupport || frontFacing10bitSupport); 2179 } 2180 } 2181 2182 /** 2183 * The same HDR profiles must be supported for all BACKWARD_COMPATIBLE-capable physical 2184 * sub-cameras of a logical camera, and the logical camera itself. 2185 */ 2186 @CddTest(requirement="7.5/C-2-3") 2187 @Test test10BitLogicalDeviceSupport()2188 public void test10BitLogicalDeviceSupport() throws Exception { 2189 String[] allCameraIds = getAllCameraIds(); 2190 for (int i = 0; i < allCameraIds.length; i++) { 2191 Log.i(TAG, "test10BitLogicalDeviceSupport: Testing camera ID " + allCameraIds[i]); 2192 2193 CameraCharacteristics c = mCharacteristics.get(i); 2194 StaticMetadata staticMetadata = mAllStaticInfo.get(allCameraIds[i]); 2195 boolean supports10BitOutput = staticMetadata.isCapabilitySupported( 2196 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); 2197 if (!supports10BitOutput) { 2198 continue; 2199 } 2200 2201 if (!staticMetadata.isColorOutputSupported()) { 2202 continue; 2203 } 2204 2205 if (staticMetadata.isLogicalMultiCamera()) { 2206 Set<Long> logicalProfiles = 2207 staticMetadata.getAvailableDynamicRangeProfilesChecked(); 2208 Set<String> physicalCameraIds = c.getPhysicalCameraIds(); 2209 for (String physicalId : physicalCameraIds) { 2210 StaticMetadata physicalMeta = mAllStaticInfo.get(physicalId); 2211 if (physicalMeta.isColorOutputSupported()) { 2212 boolean physical10bitOutput = 2213 physicalMeta.isCapabilitySupported(CameraCharacteristics. 2214 REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); 2215 assertTrue("The logical camera: " + allCameraIds[i] + 2216 " 10-bit support must match with all publicly accessible color " + 2217 "capable physical devices: " + physicalId + " !", 2218 physical10bitOutput); 2219 2220 Set<Long> physicalProfiles = 2221 physicalMeta.getAvailableDynamicRangeProfilesChecked(); 2222 assertTrue("The logical camera: " + allCameraIds[i] + 2223 " dynamic range profiles must match with all publicly accessible " + 2224 "and color capable physical devices: " + physicalId + " !", 2225 physicalProfiles.equals(logicalProfiles)); 2226 } 2227 } 2228 } 2229 } 2230 } 2231 2232 @Test 2233 @ApiTest(apis = {"android.hardware.camera2.params.ColorSpaceProfiles#getProfileMap"}) testColorSpaceProfileMap()2234 public void testColorSpaceProfileMap() throws Exception { 2235 String[] allCameraIds = getAllCameraIds(); 2236 for (int i = 0; i < allCameraIds.length; i++) { 2237 Log.i(TAG, "testColorSpaceProfileMap Testing camera ID " + allCameraIds[i]); 2238 2239 CameraCharacteristics c = mCharacteristics.get(i); 2240 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2241 assertNotNull("android.request.availableCapabilities must never be null", 2242 capabilities); 2243 boolean supportsColorSpaceProfiles = arrayContains(capabilities, 2244 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES); 2245 if (!supportsColorSpaceProfiles) { 2246 continue; 2247 } 2248 2249 ColorSpaceProfiles colorSpaceProfiles = c.get( 2250 CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES); 2251 mCollector.expectNotNull("Color space profiles must always be present if the " 2252 + "capability is reported!", colorSpaceProfiles); 2253 2254 Map<ColorSpace.Named, Map<Integer, Set<Long>>> profileMap = 2255 colorSpaceProfiles.getProfileMap(); 2256 2257 Set<ColorSpace.Named> colorSpaces = profileMap.keySet(); 2258 mCollector.expectNotNull("profileMap.keySet() is null!", colorSpaces); 2259 mCollector.expectTrue("profileMap.keySet() is empty!", !colorSpaces.isEmpty()); 2260 for (ColorSpace.Named colorSpace : colorSpaces) { 2261 Set<Integer> imageFormats = profileMap.get(colorSpace).keySet(); 2262 mCollector.expectNotNull("profileMap.get(" + colorSpace + ").keySet() is null!", 2263 imageFormats); 2264 mCollector.expectTrue("profileMap.get(" + colorSpace + ").keySet() is empty!", 2265 !imageFormats.isEmpty()); 2266 for (int imageFormat : imageFormats) { 2267 Set<Long> dynamicRangeProfiles = profileMap.get(colorSpace).get(imageFormat); 2268 mCollector.expectNotNull("profileMap.get(" + colorSpace + ").get(" 2269 + imageFormat + ") is null!", dynamicRangeProfiles); 2270 } 2271 } 2272 } 2273 } 2274 2275 @Test 2276 @ApiTest(apis = { 2277 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpaces", 2278 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpacesForDynamicRange", 2279 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedImageFormatsForColorSpace", 2280 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedDynamicRangeProfiles"}) test8BitColorSpaceOutputCharacteristics()2281 public void test8BitColorSpaceOutputCharacteristics() throws Exception { 2282 final Set<ColorSpace.Named> sdrColorSpaces = new ArraySet<>(); 2283 sdrColorSpaces.add(ColorSpace.Named.SRGB); 2284 sdrColorSpaces.add(ColorSpace.Named.DISPLAY_P3); 2285 2286 String[] allCameraIds = getAllCameraIds(); 2287 for (int i = 0; i < allCameraIds.length; i++) { 2288 Log.i(TAG, "test8BitColorSpaceOutputCharacteristics: Testing camera ID " 2289 + allCameraIds[i]); 2290 2291 CameraCharacteristics c = mCharacteristics.get(i); 2292 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2293 assertNotNull("android.request.availableCapabilities must never be null", 2294 capabilities); 2295 boolean supportsColorSpaceProfiles = arrayContains(capabilities, 2296 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES); 2297 if (!supportsColorSpaceProfiles) { 2298 continue; 2299 } 2300 2301 ColorSpaceProfiles colorSpaceProfiles = c.get( 2302 CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES); 2303 mCollector.expectNotNull("Color space profiles must always be present if the " 2304 + "capability is reported!", colorSpaceProfiles); 2305 2306 Set<ColorSpace.Named> supportedColorSpacesStandard = 2307 colorSpaceProfiles.getSupportedColorSpacesForDynamicRange( 2308 ImageFormat.UNKNOWN, DynamicRangeProfiles.STANDARD); 2309 mCollector.expectTrue("8-bit color spaces not present!", 2310 !supportedColorSpacesStandard.isEmpty()); 2311 2312 for (ColorSpace.Named colorSpace : supportedColorSpacesStandard) { 2313 mCollector.expectTrue("ColorSpace " + colorSpace.ordinal() + " is not in the set" 2314 + " of supported color spaces", sdrColorSpaces.contains(colorSpace)); 2315 } 2316 2317 Set<ColorSpace.Named> supportedColorSpaces = colorSpaceProfiles.getSupportedColorSpaces( 2318 ImageFormat.UNKNOWN); 2319 for (ColorSpace.Named colorSpace : supportedColorSpacesStandard) { 2320 mCollector.expectTrue("Standard color space " + colorSpace + " not present in " 2321 + "getSupportedColorSpaces!", supportedColorSpaces.contains(colorSpace)); 2322 } 2323 2324 for (ColorSpace.Named colorSpace : supportedColorSpaces) { 2325 Set<Integer> imageFormats = 2326 colorSpaceProfiles.getSupportedImageFormatsForColorSpace(colorSpace); 2327 mCollector.expectTrue("getSupportedImageFormatsForColorSpace returns an empty set " 2328 + "for a supported color space!", !imageFormats.isEmpty()); 2329 2330 for (int imageFormat : imageFormats) { 2331 Set<Long> dynamicRangeProfiles = 2332 colorSpaceProfiles.getSupportedDynamicRangeProfiles( 2333 colorSpace, imageFormat); 2334 mCollector.expectTrue("getSupportedDynamicRangeProfiles returns an empty set " 2335 + "for a supported color space and image format!", 2336 !dynamicRangeProfiles.isEmpty()); 2337 } 2338 } 2339 2340 for (ColorSpace.Named colorSpace : supportedColorSpacesStandard) { 2341 Set<Integer> imageFormats = 2342 colorSpaceProfiles.getSupportedImageFormatsForColorSpace(colorSpace); 2343 mCollector.expectTrue("getSupportedImageFormatsForColorSpace returns an empty set " 2344 + "for a supported color space!", !imageFormats.isEmpty()); 2345 2346 for (int imageFormat : imageFormats) { 2347 Set<Long> dynamicRangeProfiles = 2348 colorSpaceProfiles.getSupportedDynamicRangeProfiles( 2349 colorSpace, imageFormat); 2350 mCollector.expectTrue("getSupportedDynamicRangeProfiles returns an empty set " 2351 + "for a supported color space and image format!", 2352 !dynamicRangeProfiles.isEmpty()); 2353 mCollector.expectTrue("getSupportedDynamicRangeProfiles missing STANDARD for " 2354 + "color space " + colorSpace + " and image format " + imageFormat, 2355 dynamicRangeProfiles.contains(DynamicRangeProfiles.STANDARD)); 2356 } 2357 } 2358 } 2359 } 2360 2361 @Test 2362 @ApiTest(apis = { 2363 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpaces", 2364 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpacesForDynamicRange", 2365 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedImageFormatsForColorSpace", 2366 "android.hardware.camera2.params.ColorSpaceProfiles#getSupportedDynamicRangeProfiles"}) test10BitColorSpaceOutputCharacteristics()2367 public void test10BitColorSpaceOutputCharacteristics() throws Exception { 2368 final Set<ColorSpace.Named> sdrColorSpaces = new ArraySet<>(); 2369 sdrColorSpaces.add(ColorSpace.Named.SRGB); 2370 sdrColorSpaces.add(ColorSpace.Named.DISPLAY_P3); 2371 2372 final Set<ColorSpace.Named> hdrColorSpaces = new ArraySet<>(); 2373 hdrColorSpaces.add(ColorSpace.Named.SRGB); 2374 hdrColorSpaces.add(ColorSpace.Named.DISPLAY_P3); 2375 hdrColorSpaces.add(ColorSpace.Named.BT2020_HLG); 2376 2377 String[] allCameraIds = getAllCameraIds(); 2378 for (int i = 0; i < allCameraIds.length; i++) { 2379 Log.i(TAG, "test10BitColorSpaceOutputCharacteristics: Testing camera ID " 2380 + allCameraIds[i]); 2381 2382 CameraCharacteristics c = mCharacteristics.get(i); 2383 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2384 assertNotNull("android.request.availableCapabilities must never be null", 2385 capabilities); 2386 boolean supportsColorSpaceProfiles = arrayContains(capabilities, 2387 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES); 2388 if (!supportsColorSpaceProfiles) { 2389 Log.i(TAG, "Camera " + allCameraIds[i] 2390 + " does not support color space profiles."); 2391 continue; 2392 } 2393 2394 ColorSpaceProfiles colorSpaceProfiles = c.get( 2395 CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES); 2396 mCollector.expectNotNull("Color space profiles must always be present if the " 2397 + "capability is reported!", colorSpaceProfiles); 2398 2399 boolean supports10BitOutput = arrayContains(capabilities, 2400 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); 2401 Set<ColorSpace.Named> supportedColorSpaces = null; 2402 int[] imageFormats = { ImageFormat.YCBCR_P010, ImageFormat.UNKNOWN }; 2403 if (!supports10BitOutput) { 2404 Log.i(TAG, "Camera " + allCameraIds[i] 2405 + " does not support dynamic range profiles."); 2406 for (int imageFormat : imageFormats) { 2407 supportedColorSpaces = colorSpaceProfiles.getSupportedColorSpaces(imageFormat); 2408 for (ColorSpace.Named colorSpace : supportedColorSpaces) { 2409 Set<Long> compatibleDynamicRangeProfiles = 2410 colorSpaceProfiles.getSupportedDynamicRangeProfiles(colorSpace, 2411 imageFormat); 2412 if (!compatibleDynamicRangeProfiles.isEmpty()) { 2413 Long[] arrDynamicRangeProfiles = 2414 compatibleDynamicRangeProfiles.toArray(new Long[0]); 2415 mCollector.expectTrue("getSupportedDynamicRangeProfiles should return a" 2416 + " set containing only STANDARD!", 2417 arrDynamicRangeProfiles.length == 1); 2418 mCollector.expectTrue("getSupportedDynamicRangeProfiles should return a" 2419 + " set containing only STANDARD!", 2420 arrDynamicRangeProfiles[0] == DynamicRangeProfiles.STANDARD); 2421 } 2422 2423 for (Long dynamicRangeProfile = DynamicRangeProfiles.STANDARD; 2424 dynamicRangeProfile < DynamicRangeProfiles.PUBLIC_MAX; 2425 dynamicRangeProfile <<= 1) { 2426 Set<ColorSpace.Named> compatibleColorSpaces = 2427 colorSpaceProfiles.getSupportedColorSpacesForDynamicRange( 2428 imageFormat, dynamicRangeProfile); 2429 if (dynamicRangeProfile == DynamicRangeProfiles.STANDARD) { 2430 mCollector.expectTrue("getSupportedColorSpacesForDynamicRange " 2431 + "should return a set containing STANDARD for a supported" 2432 + "color space and image format!", 2433 compatibleColorSpaces.contains(colorSpace)); 2434 mCollector.expectTrue("ColorSpace " + colorSpace.ordinal() + " is " 2435 + "not in the set of supported color spaces for STANDARD", 2436 sdrColorSpaces.contains(colorSpace)); 2437 } else { 2438 mCollector.expectTrue("getSupportedColorSpacesForDynamicRange " 2439 + "should return an empty set for HDR!", 2440 compatibleColorSpaces.isEmpty()); 2441 mCollector.expectTrue("ColorSpace " + colorSpace.ordinal() + " is " 2442 + "not in the set of supported color spaces for HDR", 2443 hdrColorSpaces.contains(colorSpace)); 2444 } 2445 } 2446 } 2447 } 2448 } else { 2449 for (int imageFormat : imageFormats) { 2450 supportedColorSpaces = colorSpaceProfiles.getSupportedColorSpaces( 2451 imageFormat); 2452 DynamicRangeProfiles dynamicRangeProfiles = c.get( 2453 CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES); 2454 mCollector.expectNotNull("Dynamic range profile must always be present in case " 2455 + "of 10-bit capable devices!", dynamicRangeProfiles); 2456 Set<Long> supportedDynamicRangeProfiles = 2457 dynamicRangeProfiles.getSupportedProfiles(); 2458 mCollector.expectTrue("Dynamic range profiles not present!", 2459 !supportedDynamicRangeProfiles.isEmpty()); 2460 2461 for (ColorSpace.Named colorSpace : supportedColorSpaces) { 2462 Set<Long> compatibleDynamicRangeProfiles = 2463 colorSpaceProfiles.getSupportedDynamicRangeProfiles(colorSpace, 2464 imageFormat); 2465 2466 for (Long dynamicRangeProfile : compatibleDynamicRangeProfiles) { 2467 mCollector.expectTrue("Compatible dynamic range profile not reported in" 2468 + " DynamicRangeProfiles!", 2469 supportedDynamicRangeProfiles.contains(dynamicRangeProfile)); 2470 2471 if (dynamicRangeProfile == DynamicRangeProfiles.STANDARD) { 2472 mCollector.expectTrue("ColorSpace " + colorSpace.ordinal() + " is " 2473 + "not in the set of supported color spaces for STANDARD", 2474 sdrColorSpaces.contains(colorSpace)); 2475 } else { 2476 mCollector.expectTrue("ColorSpace " + colorSpace.ordinal() + " is " 2477 + "not in the set of supported color spaces for HDR", 2478 hdrColorSpaces.contains(colorSpace)); 2479 } 2480 } 2481 } 2482 } 2483 } 2484 } 2485 } 2486 verifyLensCalibration(float[] poseRotation, float[] poseTranslation, Integer poseReference, float[] cameraIntrinsics, float[] distortion, Rect precorrectionArray, Integer facing)2487 private void verifyLensCalibration(float[] poseRotation, float[] poseTranslation, 2488 Integer poseReference, float[] cameraIntrinsics, float[] distortion, 2489 Rect precorrectionArray, Integer facing) { 2490 2491 mCollector.expectTrue( 2492 "LENS_POSE_ROTATION not right size", 2493 poseRotation != null && poseRotation.length == 4); 2494 mCollector.expectTrue( 2495 "LENS_POSE_TRANSLATION not right size", 2496 poseTranslation != null && poseTranslation.length == 3); 2497 mCollector.expectTrue( 2498 "LENS_POSE_REFERENCE is not defined", 2499 poseReference != null); 2500 mCollector.expectTrue( 2501 "LENS_INTRINSIC_CALIBRATION not right size", 2502 cameraIntrinsics != null && cameraIntrinsics.length == 5); 2503 mCollector.expectTrue( 2504 "LENS_DISTORTION not right size", 2505 distortion != null && distortion.length == 6); 2506 2507 if (poseRotation != null && poseRotation.length == 4) { 2508 float normSq = 2509 poseRotation[0] * poseRotation[0] + 2510 poseRotation[1] * poseRotation[1] + 2511 poseRotation[2] * poseRotation[2] + 2512 poseRotation[3] * poseRotation[3]; 2513 mCollector.expectTrue( 2514 "LENS_POSE_ROTATION quarternion must be unit-length", 2515 0.9999f < normSq && normSq < 1.0001f); 2516 2517 if (facing.intValue() == CameraMetadata.LENS_FACING_FRONT || 2518 facing.intValue() == CameraMetadata.LENS_FACING_BACK) { 2519 // Use the screen's natural facing to test pose rotation 2520 int[] facingSensor = new int[]{0, 0, 1}; 2521 float[][] r = new float[][] { 2522 { 1.0f - 2 * poseRotation[1] * poseRotation[1] 2523 - 2 * poseRotation[2] * poseRotation[2], 2524 2 * poseRotation[0] * poseRotation[1] 2525 - 2 * poseRotation[2] * poseRotation[3], 2526 2 * poseRotation[0] * poseRotation[2] 2527 + 2 * poseRotation[1] * poseRotation[3] }, 2528 { 2 * poseRotation[0] * poseRotation[1] 2529 + 2 * poseRotation[2] * poseRotation[3], 2530 1.0f - 2 * poseRotation[0] * poseRotation[0] 2531 - 2 * poseRotation[2] * poseRotation[2], 2532 2 * poseRotation[1] * poseRotation[2] 2533 - 2 * poseRotation[0] * poseRotation[3] }, 2534 { 2 * poseRotation[0] * poseRotation[2] 2535 - 2 * poseRotation[1] * poseRotation[3], 2536 2 * poseRotation[1] * poseRotation[2] 2537 + 2 * poseRotation[0] * poseRotation[3], 2538 1.0f - 2 * poseRotation[0] * poseRotation[0] 2539 - 2 * poseRotation[1] * poseRotation[1] } 2540 }; 2541 // The screen natural facing in camera's coordinate system 2542 float facingCameraX = r[0][0] * facingSensor[0] + r[0][1] * facingSensor[1] + 2543 r[0][2] * facingSensor[2]; 2544 float facingCameraY = r[1][0] * facingSensor[0] + r[1][1] * facingSensor[1] + 2545 r[1][2] * facingSensor[2]; 2546 float facingCameraZ = r[2][0] * facingSensor[0] + r[2][1] * facingSensor[1] + 2547 r[2][2] * facingSensor[2]; 2548 2549 mCollector.expectTrue("LENS_POSE_ROTATION must be consistent with lens facing", 2550 (facingCameraZ > 0) ^ 2551 (facing.intValue() == CameraMetadata.LENS_FACING_BACK)); 2552 2553 if (poseReference == CameraCharacteristics.LENS_POSE_REFERENCE_UNDEFINED) { 2554 mCollector.expectTrue( 2555 "LENS_POSE_ROTATION quarternion must be consistent with camera's " + 2556 "default facing", 2557 Math.abs(facingCameraX) < 0.00001f && 2558 Math.abs(facingCameraY) < 0.00001f && 2559 Math.abs(facingCameraZ) > 0.99999f && 2560 Math.abs(facingCameraZ) < 1.00001f); 2561 } 2562 } 2563 2564 // TODO: Cross-validate orientation and poseRotation 2565 } 2566 2567 if (poseTranslation != null && poseTranslation.length == 3) { 2568 float normSq = 2569 poseTranslation[0] * poseTranslation[0] + 2570 poseTranslation[1] * poseTranslation[1] + 2571 poseTranslation[2] * poseTranslation[2]; 2572 mCollector.expectTrue("Pose translation is larger than 1 m", 2573 normSq < 1.f); 2574 2575 // Pose translation should be all 0s for UNDEFINED pose reference. 2576 if (poseReference != null && poseReference == 2577 CameraCharacteristics.LENS_POSE_REFERENCE_UNDEFINED) { 2578 mCollector.expectTrue("Pose translation aren't all 0s ", 2579 normSq < 0.00001f); 2580 } 2581 } 2582 2583 if (poseReference != null) { 2584 int ref = poseReference; 2585 boolean validReference = false; 2586 switch (ref) { 2587 case CameraCharacteristics.LENS_POSE_REFERENCE_PRIMARY_CAMERA: 2588 case CameraCharacteristics.LENS_POSE_REFERENCE_GYROSCOPE: 2589 case CameraCharacteristics.LENS_POSE_REFERENCE_UNDEFINED: 2590 // Allowed values 2591 validReference = true; 2592 break; 2593 default: 2594 } 2595 mCollector.expectTrue("POSE_REFERENCE has unknown value", validReference); 2596 } 2597 2598 mCollector.expectTrue("Does not have precorrection active array defined", 2599 precorrectionArray != null); 2600 2601 if (cameraIntrinsics != null && precorrectionArray != null) { 2602 float fx = cameraIntrinsics[0]; 2603 float fy = cameraIntrinsics[1]; 2604 float cx = cameraIntrinsics[2]; 2605 float cy = cameraIntrinsics[3]; 2606 float s = cameraIntrinsics[4]; 2607 mCollector.expectTrue("Optical center expected to be within precorrection array", 2608 0 <= cx && cx < precorrectionArray.width() && 2609 0 <= cy && cy < precorrectionArray.height()); 2610 2611 // TODO: Verify focal lengths and skew are reasonable 2612 } 2613 2614 if (distortion != null) { 2615 // TODO: Verify radial distortion 2616 } 2617 2618 } 2619 2620 /** 2621 * Cross-check StreamConfigurationMap output 2622 */ 2623 @Test testStreamConfigurationMap()2624 public void testStreamConfigurationMap() throws Exception { 2625 String[] allCameraIds = getAllCameraIds(); 2626 for (int i = 0; i < allCameraIds.length; i++) { 2627 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + allCameraIds[i]); 2628 CameraCharacteristics c = mCharacteristics.get(i); 2629 StreamConfigurationMap config = 2630 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 2631 assertNotNull(String.format("No stream configuration map found for: ID %s", 2632 allCameraIds[i]), config); 2633 2634 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2635 assertNotNull("android.request.availableCapabilities must never be null", 2636 actualCapabilities); 2637 2638 if (arrayContains(actualCapabilities, BC)) { 2639 assertTrue("ImageReader must be supported", 2640 config.isOutputSupportedFor(android.media.ImageReader.class)); 2641 assertTrue("MediaRecorder must be supported", 2642 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 2643 assertTrue("MediaCodec must be supported", 2644 config.isOutputSupportedFor(android.media.MediaCodec.class)); 2645 assertTrue("SurfaceHolder must be supported", 2646 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 2647 assertTrue("SurfaceTexture must be supported", 2648 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 2649 2650 assertTrue("YUV_420_888 must be supported", 2651 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 2652 assertTrue("JPEG must be supported", 2653 config.isOutputSupportedFor(ImageFormat.JPEG)); 2654 } else { 2655 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed", 2656 !config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 2657 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed", 2658 !config.isOutputSupportedFor(ImageFormat.JPEG)); 2659 } 2660 2661 // Check RAW 2662 2663 if (arrayContains(actualCapabilities, 2664 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2665 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 2666 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 2667 } 2668 2669 // Cross check public formats and sizes 2670 2671 int[] supportedFormats = config.getOutputFormats(); 2672 for (int format : supportedFormats) { 2673 assertTrue("Format " + format + " fails cross check", 2674 config.isOutputSupportedFor(format)); 2675 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes( 2676 Arrays.asList(config.getOutputSizes(format)), /*ascending*/true); 2677 if (arrayContains(actualCapabilities, 2678 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 2679 supportedSizes.addAll( 2680 Arrays.asList(config.getHighResolutionOutputSizes(format))); 2681 supportedSizes = CameraTestUtils.getAscendingOrderSizes( 2682 supportedSizes, /*ascending*/true); 2683 } 2684 assertTrue("Supported format " + format + " has no sizes listed", 2685 supportedSizes.size() > 0); 2686 for (int j = 0; j < supportedSizes.size(); j++) { 2687 Size size = supportedSizes.get(j); 2688 if (VERBOSE) { 2689 Log.v(TAG, 2690 String.format("Testing camera %s, format %d, size %s", 2691 allCameraIds[i], format, size.toString())); 2692 } 2693 2694 long stallDuration = config.getOutputStallDuration(format, size); 2695 switch(format) { 2696 case ImageFormat.YUV_420_888: 2697 assertTrue("YUV_420_888 may not have a non-zero stall duration", 2698 stallDuration == 0); 2699 break; 2700 case ImageFormat.JPEG: 2701 case ImageFormat.RAW_SENSOR: 2702 final float TOLERANCE_FACTOR = 2.0f; 2703 long prevDuration = 0; 2704 if (j > 0) { 2705 prevDuration = config.getOutputStallDuration( 2706 format, supportedSizes.get(j - 1)); 2707 } 2708 long nextDuration = Long.MAX_VALUE; 2709 if (j < (supportedSizes.size() - 1)) { 2710 nextDuration = config.getOutputStallDuration( 2711 format, supportedSizes.get(j + 1)); 2712 } 2713 long curStallDuration = config.getOutputStallDuration(format, size); 2714 // Stall duration should be in a reasonable range: larger size should 2715 // normally have larger stall duration. 2716 mCollector.expectInRange("Stall duration (format " + format + 2717 " and size " + size + ") is not in the right range", 2718 curStallDuration, 2719 (long) (prevDuration / TOLERANCE_FACTOR), 2720 (long) (nextDuration * TOLERANCE_FACTOR)); 2721 break; 2722 default: 2723 assertTrue("Negative stall duration for format " + format, 2724 stallDuration >= 0); 2725 break; 2726 } 2727 long minDuration = config.getOutputMinFrameDuration(format, size); 2728 if (arrayContains(actualCapabilities, 2729 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 2730 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 2731 + "format " + format + " for size " + size + " minDuration " + 2732 minDuration, 2733 minDuration > 0); 2734 } else { 2735 assertTrue("Need non-negative min frame duration for format " + format, 2736 minDuration >= 0); 2737 } 2738 2739 if (Flags.cameraHeifGainmap() && (format == ImageFormat.HEIC_ULTRAHDR)) { 2740 // Currently ImageReader cannot map HEIC_ULTRAHDR without explicit 2741 // hardware buffer and dataspace configuration. 2742 // TODO: b/364911926 Remove this check once DataSpace.DATASPACE_HEIF_ULTRAHDR 2743 // is available end to end. 2744 ImageReader.Builder testReaderBuilder = new ImageReader.Builder( 2745 size.getWidth(), 2746 size.getHeight()); 2747 2748 testReaderBuilder.setImageFormat(HardwareBuffer.BLOB); 2749 testReaderBuilder.setDefaultHardwareBufferFormat(HardwareBuffer.BLOB); 2750 testReaderBuilder.setDefaultDataSpace(DataSpace.DATASPACE_HEIF_ULTRAHDR); 2751 testReaderBuilder.setMaxImages(1); 2752 ImageReader testReader = testReaderBuilder.build(); 2753 Surface testSurface = testReader.getSurface(); 2754 2755 assertTrue( 2756 String.format("isOutputSupportedFor fails for config %s, format %d", 2757 size.toString(), format), 2758 config.isOutputSupportedFor(testSurface)); 2759 2760 testReader.close(); 2761 } else if (format != ImageFormat.PRIVATE) { 2762 // todo: test opaque image reader when it's supported. 2763 ImageReader testReader = ImageReader.newInstance( 2764 size.getWidth(), 2765 size.getHeight(), 2766 format, 2767 1); 2768 Surface testSurface = testReader.getSurface(); 2769 2770 assertTrue( 2771 String.format("isOutputSupportedFor fails for config %s, format %d", 2772 size.toString(), format), 2773 config.isOutputSupportedFor(testSurface)); 2774 2775 testReader.close(); 2776 } 2777 } // sizes 2778 2779 // Try an invalid size in this format, should round 2780 Size invalidSize = findInvalidSize(supportedSizes); 2781 int MAX_ROUNDING_WIDTH = 1920; 2782 if (Flags.cameraHeifGainmap() && (format == ImageFormat.HEIC_ULTRAHDR)) { 2783 // Currently ImageReader cannot map HEIC_ULTRAHDR without explicit 2784 // hardware buffer and dataspace configuration. 2785 // TODO: b/364911926 Remove this check once DataSpace.DATASPACE_HEIF_ULTRAHDR 2786 // is available end to end. 2787 ImageReader.Builder testReaderBuilder = new ImageReader.Builder( 2788 invalidSize.getWidth(), 2789 invalidSize.getHeight()); 2790 2791 testReaderBuilder.setImageFormat(HardwareBuffer.BLOB); 2792 testReaderBuilder.setDefaultHardwareBufferFormat(HardwareBuffer.BLOB); 2793 testReaderBuilder.setDefaultDataSpace(DataSpace.DATASPACE_HEIF_ULTRAHDR); 2794 testReaderBuilder.setMaxImages(1); 2795 ImageReader testReader = testReaderBuilder.build(); 2796 Surface testSurface = testReader.getSurface(); 2797 2798 assertTrue( 2799 String.format("isOutputSupportedFor fails for config %s, format %d", 2800 invalidSize.toString(), format), 2801 config.isOutputSupportedFor(testSurface)); 2802 2803 testReader.close(); 2804 } else if (format != ImageFormat.PRIVATE && 2805 invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 2806 // todo: test opaque image reader when it's supported. 2807 ImageReader testReader = ImageReader.newInstance( 2808 invalidSize.getWidth(), 2809 invalidSize.getHeight(), 2810 format, 2811 1); 2812 Surface testSurface = testReader.getSurface(); 2813 2814 assertTrue( 2815 String.format("isOutputSupportedFor fails for config %s, %d", 2816 invalidSize.toString(), format), 2817 config.isOutputSupportedFor(testSurface)); 2818 2819 testReader.close(); 2820 } 2821 } // formats 2822 2823 // Cross-check opaque format and sizes 2824 if (arrayContains(actualCapabilities, BC)) { 2825 SurfaceTexture st = new SurfaceTexture(1); 2826 Surface surf = new Surface(st); 2827 2828 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class, 2829 allCameraIds[i], mCameraManager); 2830 assertTrue("Opaque format has no sizes listed", 2831 opaqueSizes.length > 0); 2832 for (Size size : opaqueSizes) { 2833 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 2834 assertTrue("Opaque output may not have a non-zero stall duration", 2835 stallDuration == 0); 2836 2837 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 2838 if (arrayContains(actualCapabilities, 2839 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 2840 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 2841 + "opaque format", 2842 minDuration > 0); 2843 } else { 2844 assertTrue("Need non-negative min frame duration for opaque format ", 2845 minDuration >= 0); 2846 } 2847 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 2848 2849 assertTrue( 2850 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 2851 size.toString()), 2852 config.isOutputSupportedFor(surf)); 2853 2854 } // opaque sizes 2855 2856 // Try invalid opaque size, should get rounded 2857 Size invalidSize = findInvalidSize(opaqueSizes); 2858 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 2859 assertTrue( 2860 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 2861 invalidSize.toString()), 2862 config.isOutputSupportedFor(surf)); 2863 2864 } 2865 } // mCharacteristics 2866 } 2867 2868 /** 2869 * Test high speed capability and cross-check the high speed sizes and fps ranges from 2870 * the StreamConfigurationMap. 2871 */ 2872 @Test testConstrainedHighSpeedCapability()2873 public void testConstrainedHighSpeedCapability() throws Exception { 2874 String[] allCameraIds = getAllCameraIds(); 2875 for (int i = 0; i < allCameraIds.length; i++) { 2876 CameraCharacteristics c = mCharacteristics.get(i); 2877 int[] capabilities = CameraTestUtils.getValueNotNull( 2878 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 2879 boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED); 2880 if (supportHighSpeed) { 2881 StreamConfigurationMap config = 2882 CameraTestUtils.getValueNotNull( 2883 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 2884 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 2885 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0); 2886 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE, 2887 allCameraIds[i], mCameraManager); 2888 assertTrue("Normal size for PRIVATE format shouldn't be null or empty", 2889 allSizes != null && allSizes.length > 0); 2890 for (Size size: highSpeedSizes) { 2891 // The sizes must be a subset of the normal sizes 2892 assertTrue("High speed size " + size + 2893 " must be part of normal sizes " + Arrays.toString(allSizes), 2894 Arrays.asList(allSizes).contains(size)); 2895 2896 // Sanitize the high speed FPS ranges for each size 2897 List<Range<Integer>> ranges = 2898 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size)); 2899 int previewFps = Integer.MAX_VALUE; 2900 for (Range<Integer> range : ranges) { 2901 int rangeMin = range.getLower(); 2902 if (previewFps > rangeMin) { 2903 previewFps = rangeMin; 2904 } 2905 } 2906 Log.v(TAG, "Advertised preview fps is: " + previewFps); 2907 // We only support preview of 30fps or 60fps. 2908 assertTrue("Preview fps " + previewFps + " is not valid.", 2909 (previewFps == 30 || previewFps == 60)); 2910 for (Range<Integer> range : ranges) { 2911 assertTrue("The range " + range + " doesn't satisfy the" 2912 + " min/max boundary requirements.", 2913 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN && 2914 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN); 2915 assertTrue("The range " + range + " should be multiple of 30fps", 2916 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0); 2917 // If the range is fixed high speed range, it should contain the 2918 // [previewFps, fps_max] in the high speed range list; if it's variable FPS 2919 // range, the corresponding fixed FPS Range must be included in the range 2920 // list. 2921 if (Objects.equals(range.getLower(), range.getUpper())) { 2922 Range<Integer> variableRange = new Range<Integer>(previewFps, 2923 range.getUpper()); 2924 assertTrue("The variable FPS range " + variableRange + 2925 " shoould be included in the high speed ranges for size " + 2926 size, ranges.contains(variableRange)); 2927 } else { 2928 Range<Integer> fixedRange = 2929 new Range<Integer>(range.getUpper(), range.getUpper()); 2930 assertTrue("The fixed FPS range " + fixedRange + 2931 " shoould be included in the high speed ranges for size " + 2932 size, ranges.contains(fixedRange)); 2933 } 2934 } 2935 } 2936 // If the device advertise some high speed profiles, the sizes and FPS ranges 2937 // should be advertise by the camera. 2938 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P; 2939 quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) { 2940 int cameraId = Integer.valueOf(allCameraIds[i]); 2941 if (CamcorderProfile.hasProfile(cameraId, quality)) { 2942 CamcorderProfile profile = CamcorderProfile.get(cameraId, quality); 2943 Size camcorderProfileSize = 2944 new Size(profile.videoFrameWidth, profile.videoFrameHeight); 2945 assertTrue("CamcorderPrfile size " + camcorderProfileSize + 2946 " must be included in the high speed sizes " + 2947 Arrays.toString(highSpeedSizes.toArray()), 2948 highSpeedSizes.contains(camcorderProfileSize)); 2949 Range<Integer> camcorderFpsRange = 2950 new Range<Integer>(profile.videoFrameRate, profile.videoFrameRate); 2951 List<Range<Integer>> allRanges = 2952 Arrays.asList(config.getHighSpeedVideoFpsRangesFor( 2953 camcorderProfileSize)); 2954 assertTrue("Camcorder fps range " + camcorderFpsRange + 2955 " should be included by high speed fps ranges " + 2956 Arrays.toString(allRanges.toArray()), 2957 allRanges.contains(camcorderFpsRange)); 2958 } 2959 } 2960 } 2961 } 2962 } 2963 2964 /** 2965 * Correctness check of optical black regions. 2966 */ 2967 @Test testOpticalBlackRegions()2968 public void testOpticalBlackRegions() throws Exception { 2969 String[] allCameraIds = getAllCameraIds(); 2970 for (int i = 0; i < allCameraIds.length; i++) { 2971 CameraCharacteristics c = mCharacteristics.get(i); 2972 List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys(); 2973 boolean hasDynamicBlackLevel = 2974 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 2975 boolean hasDynamicWhiteLevel = 2976 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL); 2977 boolean hasFixedBlackLevel = 2978 c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 2979 boolean hasFixedWhiteLevel = 2980 c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 2981 // The black and white levels should be either all supported or none of them is 2982 // supported. 2983 mCollector.expectTrue("Dynamic black and white level should be all or none of them" 2984 + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel); 2985 mCollector.expectTrue("Fixed black and white level should be all or none of them" 2986 + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel); 2987 mCollector.expectTrue("Fixed black level should be supported if dynamic black" 2988 + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel); 2989 2990 if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) { 2991 // Regions shouldn't be null or empty. 2992 Rect[] regions = CameraTestUtils.getValueNotNull(c, 2993 CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS); 2994 CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not" 2995 + " be empty"); 2996 2997 // Dynamic black level should be supported if the optical black region is 2998 // advertised. 2999 mCollector.expectTrue("Dynamic black and white level keys should be advertised in " 3000 + "available capture result key list", hasDynamicWhiteLevel); 3001 3002 // Range check. 3003 for (Rect region : regions) { 3004 mCollector.expectTrue("Camera " + allCameraIds[i] + ": optical black region" + 3005 " shouldn't be empty!", !region.isEmpty()); 3006 mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/, 3007 region.left/*actual*/); 3008 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 3009 region.top/*actual*/); 3010 mCollector.expectTrue("Optical black region left/right/width/height must be" 3011 + " even number, otherwise, the bayer CFA pattern in this region will" 3012 + " be messed up", 3013 region.left % 2 == 0 && region.top % 2 == 0 && 3014 region.width() % 2 == 0 && region.height() % 2 == 0); 3015 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 3016 region.top/*actual*/); 3017 Size size = CameraTestUtils.getValueNotNull(c, 3018 CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 3019 mCollector.expectLessOrEqual("Optical black region width", 3020 size.getWidth()/*expected*/, region.width()); 3021 mCollector.expectLessOrEqual("Optical black region height", 3022 size.getHeight()/*expected*/, region.height()); 3023 Rect activeArray = CameraTestUtils.getValueNotNull(c, 3024 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 3025 mCollector.expectTrue("Optical black region" + region + " should be outside of" 3026 + " active array " + activeArray, 3027 !region.intersect(activeArray)); 3028 // Region need to be disjoint: 3029 for (Rect region2 : regions) { 3030 mCollector.expectTrue("Optical black region" + region + " should have no " 3031 + "overlap with " + region2, 3032 region == region2 || !region.intersect(region2)); 3033 } 3034 } 3035 } else { 3036 Log.i(TAG, "Camera " + allCameraIds[i] + " doesn't support optical black regions," 3037 + " skip the region test"); 3038 } 3039 } 3040 } 3041 3042 /** 3043 * Check Logical camera capability 3044 */ 3045 @Test testLogicalCameraCharacteristics()3046 public void testLogicalCameraCharacteristics() throws Exception { 3047 String[] allCameraIds = getAllCameraIds(); 3048 for (int i = 0; i < allCameraIds.length; i++) { 3049 CameraCharacteristics c = mCharacteristics.get(i); 3050 int[] capabilities = CameraTestUtils.getValueNotNull( 3051 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 3052 boolean supportLogicalCamera = arrayContains(capabilities, 3053 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA); 3054 if (supportLogicalCamera) { 3055 Set<String> physicalCameraIds = c.getPhysicalCameraIds(); 3056 assertNotNull("android.logicalCam.physicalCameraIds shouldn't be null", 3057 physicalCameraIds); 3058 assertTrue("Logical camera must contain at least 2 physical camera ids", 3059 physicalCameraIds.size() >= 2); 3060 3061 mCollector.expectKeyValueInRange(c, 3062 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE, 3063 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE, 3064 CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED); 3065 3066 Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); 3067 for (String physicalCameraId : physicalCameraIds) { 3068 assertNotNull("Physical camera id shouldn't be null", physicalCameraId); 3069 assertTrue( 3070 String.format("Physical camera id %s shouldn't be the same as logical" 3071 + " camera id %s", physicalCameraId, allCameraIds[i]), 3072 physicalCameraId != allCameraIds[i]); 3073 3074 //validation for depth static metadata of physical cameras 3075 CameraCharacteristics pc = 3076 mCameraManager.getCameraCharacteristics(physicalCameraId); 3077 3078 float[] poseRotation = pc.get(CameraCharacteristics.LENS_POSE_ROTATION); 3079 float[] poseTranslation = pc.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 3080 Integer poseReference = pc.get(CameraCharacteristics.LENS_POSE_REFERENCE); 3081 float[] cameraIntrinsics = pc.get( 3082 CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 3083 float[] distortion = getLensDistortion(pc); 3084 Integer facing = pc.get(CameraCharacteristics.LENS_FACING); 3085 Rect precorrectionArray = pc.get( 3086 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 3087 3088 verifyLensCalibration(poseRotation, poseTranslation, poseReference, 3089 cameraIntrinsics, distortion, precorrectionArray, facing); 3090 3091 Integer timestampSourcePhysical = 3092 pc.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); 3093 mCollector.expectEquals("Logical camera and physical cameras must have same " + 3094 "timestamp source", timestampSource, timestampSourcePhysical); 3095 } 3096 } 3097 3098 // Verify that if multiple focal lengths or apertures are supported, they are in 3099 // ascending order. 3100 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 3101 boolean isExternalCamera = (hwLevel == 3102 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL); 3103 if (!isExternalCamera) { 3104 float[] focalLengths = c.get( 3105 CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); 3106 for (int j = 0; j < focalLengths.length-1; j++) { 3107 mCollector.expectTrue("Camera's available focal lengths must be ascending!", 3108 focalLengths[j] < focalLengths[j+1]); 3109 } 3110 float[] apertures = c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES); 3111 for (int j = 0; j < apertures.length-1; j++) { 3112 mCollector.expectTrue("Camera's available apertures must be ascending!", 3113 apertures[j] < apertures[j+1]); 3114 } 3115 } 3116 } 3117 } 3118 3119 /** 3120 * Check manual flash control capability 3121 */ 3122 @Test testManualFlashStrengthControlCharacteristics()3123 public void testManualFlashStrengthControlCharacteristics() throws Exception { 3124 String[] allCameraIds = getAllCameraIds(); 3125 for (int i = 0; i < allCameraIds.length; i++) { 3126 Log.i(TAG, "testManualFlashStrengthControlCharacteristics: Testing camera ID " 3127 + allCameraIds[i]); 3128 CameraCharacteristics c = mCharacteristics.get(i); 3129 if (!arrayContains(getCameraIdsUnderTest(), allCameraIds[i])) { 3130 // Skip hidden physical cameras 3131 continue; 3132 } 3133 int singleDefaultLevel = 3134 c.get(CameraCharacteristics.FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL); 3135 assertTrue("singleDefaultLevel must be >=1", singleDefaultLevel >= 1); 3136 int singleMaxLevel = c.get(CameraCharacteristics.FLASH_SINGLE_STRENGTH_MAX_LEVEL); 3137 assertTrue("singleMaxLevel must be >=1", singleMaxLevel >= 1); 3138 int torchDefaultLevel = c.get(CameraCharacteristics.FLASH_TORCH_STRENGTH_DEFAULT_LEVEL); 3139 assertTrue("torchDefaultLevel must be >=1", torchDefaultLevel >= 1); 3140 int torchMaxLevel = c.get(CameraCharacteristics.FLASH_TORCH_STRENGTH_MAX_LEVEL); 3141 assertTrue("torchMaxLevel must be >=1", torchMaxLevel >= 1); 3142 // Verify that the default level is not greater than the max level. 3143 assertTrue("singleDefaultLevel cannot be greater than singleMaxLevel", 3144 singleDefaultLevel <= singleMaxLevel); 3145 assertTrue("torchDefaultLevel cannot be greater than torchMaxLevel", 3146 torchDefaultLevel <= torchMaxLevel); 3147 } 3148 } 3149 3150 /** 3151 * Check monochrome camera capability 3152 */ 3153 @Test testMonochromeCharacteristics()3154 public void testMonochromeCharacteristics() throws Exception { 3155 String[] allCameraIds = getAllCameraIds(); 3156 for (int i = 0; i < allCameraIds.length; i++) { 3157 Log.i(TAG, "testMonochromeCharacteristics: Testing camera ID " + allCameraIds[i]); 3158 3159 CameraCharacteristics c = mCharacteristics.get(i); 3160 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 3161 assertNotNull("android.request.availableCapabilities must never be null", 3162 capabilities); 3163 boolean supportMonochrome = arrayContains(capabilities, MONOCHROME); 3164 3165 if (!supportMonochrome) { 3166 continue; 3167 } 3168 3169 List<Key<?>> allKeys = c.getKeys(); 3170 List<CaptureRequest.Key<?>> requestKeys = c.getAvailableCaptureRequestKeys(); 3171 List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys(); 3172 3173 assertTrue("Monochrome camera must have BACKWARD_COMPATIBLE capability", 3174 arrayContains(capabilities, BC)); 3175 int colorFilterArrangement = c.get( 3176 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 3177 assertTrue("Monochrome camera must have either MONO or NIR color filter pattern", 3178 colorFilterArrangement == 3179 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO 3180 || colorFilterArrangement == 3181 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR); 3182 3183 assertFalse("Monochrome camera must not contain SENSOR_CALIBRATION_TRANSFORM1 key", 3184 allKeys.contains(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 3185 assertFalse("Monochrome camera must not contain SENSOR_COLOR_TRANSFORM1 key", 3186 allKeys.contains(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 3187 assertFalse("Monochrome camera must not contain SENSOR_FORWARD_MATRIX1 key", 3188 allKeys.contains(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 3189 assertFalse("Monochrome camera must not contain SENSOR_REFERENCE_ILLUMINANT1 key", 3190 allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1)); 3191 assertFalse("Monochrome camera must not contain SENSOR_CALIBRATION_TRANSFORM2 key", 3192 allKeys.contains(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 3193 assertFalse("Monochrome camera must not contain SENSOR_COLOR_TRANSFORM2 key", 3194 allKeys.contains(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 3195 assertFalse("Monochrome camera must not contain SENSOR_FORWARD_MATRIX2 key", 3196 allKeys.contains(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 3197 assertFalse("Monochrome camera must not contain SENSOR_REFERENCE_ILLUMINANT2 key", 3198 allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)); 3199 3200 assertFalse( 3201 "Monochrome capture result must not contain SENSOR_NEUTRAL_COLOR_POINT key", 3202 resultKeys.contains(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT)); 3203 assertFalse("Monochrome capture result must not contain SENSOR_GREEN_SPLIT key", 3204 resultKeys.contains(CaptureResult.SENSOR_GREEN_SPLIT)); 3205 3206 // Check that color correction tags are not available for monochrome cameras 3207 assertTrue("Monochrome camera must not have MANUAL_POST_PROCESSING capability", 3208 !arrayContains(capabilities, MANUAL_POSTPROC)); 3209 assertTrue("Monochrome camera must not have COLOR_CORRECTION_MODE in request keys", 3210 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_MODE)); 3211 assertTrue("Monochrome camera must not have COLOR_CORRECTION_MODE in result keys", 3212 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_MODE)); 3213 assertTrue("Monochrome camera must not have COLOR_CORRECTION_TRANSFORM in request keys", 3214 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_TRANSFORM)); 3215 assertTrue("Monochrome camera must not have COLOR_CORRECTION_TRANSFORM in result keys", 3216 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_TRANSFORM)); 3217 assertTrue("Monochrome camera must not have COLOR_CORRECTION_GAINS in request keys", 3218 !requestKeys.contains(CaptureRequest.COLOR_CORRECTION_GAINS)); 3219 assertTrue("Monochrome camera must not have COLOR_CORRECTION_GAINS in result keys", 3220 !resultKeys.contains(CaptureResult.COLOR_CORRECTION_GAINS)); 3221 3222 // Check that awbSupportedModes only contains AUTO 3223 int[] awbAvailableModes = c.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES); 3224 assertTrue("availableAwbModes must not be null", awbAvailableModes != null); 3225 assertTrue("availableAwbModes must contain only AUTO", awbAvailableModes.length == 1 && 3226 awbAvailableModes[0] == CaptureRequest.CONTROL_AWB_MODE_AUTO); 3227 } 3228 } 3229 3230 /** 3231 * Check rotate-and-crop camera reporting. 3232 * Every device must report NONE; if actually supporting feature, must report NONE, 90, AUTO at 3233 * least. 3234 */ 3235 @Test testRotateAndCropCharacteristics()3236 public void testRotateAndCropCharacteristics() throws Exception { 3237 String[] allCameraIds = getAllCameraIds(); 3238 for (int i = 0; i < allCameraIds.length; i++) { 3239 Log.i(TAG, "testRotateAndCropCharacteristics: Testing camera ID " + allCameraIds[i]); 3240 3241 CameraCharacteristics c = mCharacteristics.get(i); 3242 3243 if (!arrayContains(getCameraIdsUnderTest(), allCameraIds[i])) { 3244 // Skip hidden physical cameras 3245 continue; 3246 } 3247 3248 int[] availableRotateAndCropModes = c.get( 3249 CameraCharacteristics.SCALER_AVAILABLE_ROTATE_AND_CROP_MODES); 3250 assertTrue("availableRotateAndCropModes must not be null", 3251 availableRotateAndCropModes != null); 3252 boolean foundAuto = false; 3253 boolean foundNone = false; 3254 boolean found90 = false; 3255 for (int mode : availableRotateAndCropModes) { 3256 switch(mode) { 3257 case CameraCharacteristics.SCALER_ROTATE_AND_CROP_NONE: 3258 foundNone = true; 3259 break; 3260 case CameraCharacteristics.SCALER_ROTATE_AND_CROP_90: 3261 found90 = true; 3262 break; 3263 case CameraCharacteristics.SCALER_ROTATE_AND_CROP_AUTO: 3264 foundAuto = true; 3265 break; 3266 } 3267 } 3268 if (availableRotateAndCropModes.length > 1) { 3269 assertTrue("To support SCALER_ROTATE_AND_CROP: NONE, 90, and AUTO must be included", 3270 foundNone && found90 && foundAuto); 3271 } else { 3272 assertTrue("If only one SCALER_ROTATE_AND_CROP value is supported, it must be NONE", 3273 foundNone); 3274 } 3275 } 3276 } 3277 3278 /** 3279 * Check DeviceStateSensorOrientationMap camera reporting. 3280 * If present, the map should only be part of logical camera characteristics. 3281 * Verify that all device state modes return valid orientations. 3282 */ 3283 @Test testDeviceStateSensorOrientationMapCharacteristics()3284 public void testDeviceStateSensorOrientationMapCharacteristics() throws Exception { 3285 String[] allCameraIds = getAllCameraIds(); 3286 for (int i = 0; i < allCameraIds.length; i++) { 3287 Log.i(TAG, "testDeviceStateOrientationMapCharacteristics: Testing camera ID " + 3288 allCameraIds[i]); 3289 3290 CameraCharacteristics c = mCharacteristics.get(i); 3291 DeviceStateSensorOrientationMap orientationMap = c.get( 3292 CameraCharacteristics.INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP); 3293 if (orientationMap == null) { 3294 continue; 3295 } 3296 // DeviceStateOrientationMaps must only be present within logical camera 3297 // characteristics. 3298 assertTrue("Camera id: " + i + " All devices advertising a " + 3299 "DeviceStateSensorOrientationMap must also be logical cameras!", 3300 CameraTestUtils.hasCapability(c, 3301 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)); 3302 List<Long> supportedStates = new ArrayList<>(Arrays.asList( 3303 DeviceStateSensorOrientationMap.NORMAL, DeviceStateSensorOrientationMap.FOLDED)); 3304 for (long deviceState : supportedStates) { 3305 int orientation = orientationMap.getSensorOrientation(deviceState); 3306 assertTrue("CameraId: " + i + " Unexpected orientation: " + orientation, 3307 (orientation >= 0) && (orientation <= 270) && 3308 ((orientation % 90) == 0)); 3309 } 3310 } 3311 } 3312 3313 /** 3314 * Check that all devices available through the legacy API are also 3315 * accessible via Camera2. 3316 */ 3317 @CddTest(requirement="7.5.4/C-0-11") 3318 @Test testLegacyCameraDeviceParity()3319 public void testLegacyCameraDeviceParity() { 3320 if (mAdoptShellPerm) { 3321 // There is no current way to determine in camera1 api if a device is a system camera 3322 // Skip test, http://b/141496896 3323 return; 3324 } 3325 if (mOverrideCameraId != null) { 3326 // A single camera is being tested. Skip test. 3327 return; 3328 } 3329 int legacyDeviceCount = Camera.getNumberOfCameras(); 3330 assertTrue("More legacy devices: " + legacyDeviceCount + " compared to Camera2 devices: " + 3331 mCharacteristics.size(), legacyDeviceCount <= mCharacteristics.size()); 3332 3333 ArrayList<CameraCharacteristics> chars = new ArrayList<> (mCharacteristics); 3334 for (int i = 0; i < legacyDeviceCount; i++) { 3335 Camera camera = null; 3336 Camera.Parameters legacyParams = null; 3337 Camera.CameraInfo legacyInfo = new Camera.CameraInfo(); 3338 try { 3339 Camera.getCameraInfo(i, legacyInfo); 3340 camera = Camera.open(i); 3341 legacyParams = camera.getParameters(); 3342 3343 assertNotNull("Camera parameters for device: " + i + " must not be null", 3344 legacyParams); 3345 } finally { 3346 if (camera != null) { 3347 camera.release(); 3348 } 3349 } 3350 3351 // Camera Ids between legacy devices and Camera2 device could be 3352 // different try to match devices by using other common traits. 3353 CameraCharacteristics found = null; 3354 for (CameraCharacteristics ch : chars) { 3355 if (matchParametersToCharacteristics(legacyParams, legacyInfo, ch)) { 3356 found = ch; 3357 break; 3358 } 3359 } 3360 assertNotNull("No matching Camera2 device for legacy device id: " + i, found); 3361 3362 chars.remove(found); 3363 } 3364 } 3365 3366 /** 3367 * Check camera orientation against device orientation 3368 */ 3369 @AppModeFull(reason = "DeviceStateManager is not accessible to instant apps") 3370 @CddTest(requirement = "7.5.5/C-1-1") 3371 @Test testCameraOrientationAlignedWithDevice()3372 public void testCameraOrientationAlignedWithDevice() throws Exception { 3373 assumeFalse("Skip test: CDD 7.5.5/C-1-1 does not apply to automotive", 3374 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)); 3375 if (CameraUtils.isDeviceFoldable(mContext)) { 3376 // CDD 7.5.5/C-1-1 does not apply to devices with folding displays as the display aspect 3377 // ratios might change with the device's folding state. 3378 // Skip this test in foldables until the CDD is updated to include foldables. 3379 Log.i(TAG, "CDD 7.5.5/C-1-1 does not apply to foldables, skipping" 3380 + " testCameraOrientationAlignedWithDevice"); 3381 return; 3382 } 3383 3384 // Start the empty activty to check the display we're testing. 3385 mActivityRule.launchActivity(new Intent()); 3386 Context foregroundActivity = mActivityRule.getActivity(); 3387 3388 WindowManager windowManager = foregroundActivity.getSystemService(WindowManager.class); 3389 assertNotNull("Could not get window manager for test activity.", windowManager); 3390 3391 WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); 3392 Rect displayBounds = metrics.getBounds(); 3393 int widthPixels = displayBounds.width(); 3394 int heightPixels = displayBounds.height(); 3395 3396 // For square screen, test is guaranteed to pass 3397 if (widthPixels == heightPixels) { 3398 return; 3399 } 3400 3401 // Handle display rotation 3402 Display display = foregroundActivity.getDisplay(); 3403 int displayRotation = display.getRotation(); 3404 if (displayRotation == Surface.ROTATION_90 || displayRotation == Surface.ROTATION_270) { 3405 int tmp = widthPixels; 3406 widthPixels = heightPixels; 3407 heightPixels = tmp; 3408 } 3409 boolean isDevicePortrait = widthPixels < heightPixels; 3410 3411 String[] allCameraIds = getAllCameraIds(); 3412 for (int i = 0; i < allCameraIds.length; i++) { 3413 CameraCharacteristics c = mCharacteristics.get(i); 3414 // Camera size 3415 Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 3416 // Camera orientation 3417 int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 3418 3419 // For square sensor, test is guaranteed to pass 3420 if (pixelArraySize.getWidth() == pixelArraySize.getHeight()) { 3421 continue; 3422 } 3423 3424 Integer facing = c.get(CameraCharacteristics.LENS_FACING); 3425 if (facing == CameraCharacteristics.LENS_FACING_EXTERNAL) { 3426 // CDD "7.5.5/C-1-1" only applies to front and back cameras 3427 continue; 3428 } 3429 // Camera size adjusted for device native orientation. 3430 Size adjustedSensorSize; 3431 if (sensorOrientation == 90 || sensorOrientation == 270) { 3432 adjustedSensorSize = new Size( 3433 pixelArraySize.getHeight(), pixelArraySize.getWidth()); 3434 } else { 3435 adjustedSensorSize = pixelArraySize; 3436 } 3437 3438 boolean isCameraPortrait = 3439 adjustedSensorSize.getWidth() < adjustedSensorSize.getHeight(); 3440 3441 // device and camera orientation should either be both portrait, or both landscape 3442 assertEquals("Camera " + allCameraIds[i] + "'s long dimension must " 3443 + "align with screen's long dimension", isDevicePortrait, isCameraPortrait); 3444 } 3445 } 3446 3447 /** 3448 * Check the CameraX Night extension requirement 3449 */ 3450 private ExtensionsManager getCameraXExtensionManager() throws Exception { 3451 // Obtain an instance of a process camera provider 3452 final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = 3453 ProcessCameraProvider.getInstance(mContext); 3454 ProcessCameraProvider cameraProvider = null; 3455 try { 3456 cameraProvider = cameraProviderFuture.get(WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS); 3457 } catch (InterruptedException | ExecutionException | TimeoutException e) { 3458 throw new AssertionError("Provider future failed to complete", e); 3459 } 3460 assertNotNull("CameraProviderManager isn't available", cameraProvider); 3461 3462 // Obtain an instance of the extension manager 3463 final ListenableFuture<ExtensionsManager> extensionsManagerFuture = 3464 ExtensionsManager.getInstanceAsync(mContext, cameraProvider); 3465 ExtensionsManager extensionsManager = null; 3466 try { 3467 extensionsManager = extensionsManagerFuture.get( 3468 WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS); 3469 } catch (InterruptedException | ExecutionException | TimeoutException e) { 3470 throw new AssertionError("ExtensionManager future failed to complete", e); 3471 } 3472 assertNotNull("ExtensionManager isn't available", extensionsManager); 3473 3474 return extensionsManager; 3475 } 3476 3477 /** 3478 * Check camera characteristics for Performance class requirements as specified 3479 * in CDD camera section 7.5 3480 */ 3481 @Test 3482 @AppModeFull(reason = "DeviceStateManager is not accessible to instant apps") 3483 @CddTest(requirements = { 3484 "2.2.7.2/7.5/H-1-1", 3485 "2.2.7.2/7.5/H-1-2", 3486 "2.2.7.2/7.5/H-1-3", 3487 "2.2.7.2/7.5/H-1-4", 3488 "2.2.7.2/7.5/H-1-8", 3489 "2.2.7.2/7.5/H-1-9", 3490 "2.2.7.2/7.5/H-1-10", 3491 "2.2.7.2/7.5/H-1-11", 3492 "2.2.7.2/7.5/H-1-12", 3493 "2.2.7.2/7.5/H-1-13", 3494 "2.2.7.2/7.5/H-1-14"}) 3495 public void testCameraPerfClassCharacteristics() throws Exception { 3496 assumeFalse("Media performance class tests not applicable if shell permission is adopted", 3497 mAdoptShellPerm); 3498 assumeTrue("Media performance class tests not applicable when test is restricted " 3499 + "to single camera by specifying camera id override.", mOverrideCameraId == null); 3500 3501 PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName); 3502 PrimaryRearCameraResolutionAndFrameRateRequirement primaryRearReq = 3503 Requirements.addR7_5__H_1_1().to(pce); 3504 PrimaryFrontCameraResolutionAndFrameRateRequirement primaryFrontReq = 3505 Requirements.addR7_5__H_1_2().to(pce); 3506 CameraHardwareLevelRequirement hwLevelReq = 3507 Requirements.addR7_5__H_1_3().to(pce); 3508 TimestampSourceRealtimeRequirement timestampSourceReq = 3509 Requirements.addR7_5__H_1_4().to(pce); 3510 CameraRAWCapabilityRequirement rearRawReq = 3511 Requirements.addR7_5__H_1_8().to(pce); 3512 CameraSlowMotionRequirement hfrReq = 3513 Requirements.addR7_5__H_1_9().to(pce); 3514 CameraUltrawideZoomRatioRequirement ultrawideZoomRatioReq = 3515 Requirements.addR7_5__H_1_10().to(pce); 3516 CameraConcurrentRearFrontStreamingRequirement concurrentRearFrontReq = 3517 Requirements.addR7_5__H_1_11().to(pce); 3518 CameraPreviewStabilizationRequirement previewStabilizationReq = 3519 Requirements.addR7_5__H_1_12().to(pce); 3520 CameraLogicalMultiCameraRequirement logicalMultiCameraReq = 3521 Requirements.addR7_5__H_1_13().to(pce); 3522 CameraStreamUseCaseRequirement streamUseCaseReq = 3523 Requirements.addR7_5__H_1_14().to(pce); 3524 3525 String primaryRearId = null; 3526 String primaryFrontId = null; 3527 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 3528 for (int i = 0; i < cameraIdsUnderTest.length; i++) { 3529 String cameraId = cameraIdsUnderTest[i]; 3530 boolean isPrimaryRear = CameraTestUtils.isPrimaryRearFacingCamera( 3531 mCameraManager, cameraId); 3532 boolean isPrimaryFront = CameraTestUtils.isPrimaryFrontFacingCamera( 3533 mCameraManager, cameraId); 3534 if (!isPrimaryRear && !isPrimaryFront) { 3535 continue; 3536 } 3537 3538 CameraCharacteristics c = mCharacteristics.get(i); 3539 StaticMetadata staticInfo = mAllStaticInfo.get(cameraId); 3540 3541 // H-1-1, H-1-2 3542 Size pixelArraySize = CameraTestUtils.getValueNotNull( 3543 c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 3544 long sensorResolution = pixelArraySize.getHeight() * pixelArraySize.getWidth(); 3545 StreamConfigurationMap config = staticInfo.getValueFromKeyNonNull( 3546 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 3547 assertNotNull("No stream configuration map found for ID " + cameraId, config); 3548 List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(cameraId, 3549 mCameraManager, null /*bound*/); 3550 3551 Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE); 3552 if (isPrimaryRear) { 3553 primaryRearId = cameraId; 3554 primaryRearReq.setPrimaryCameraAvailable(true); 3555 primaryRearReq.setPrimaryCameraResolution(sensorResolution); 3556 hwLevelReq.setRearPrimaryCameraHwlLevel(staticInfo.getHardwareLevelChecked()); 3557 timestampSourceReq.setRearPrimaryCameraTimestampSource(timestampSource); 3558 3559 // 4K @ 30fps 3560 boolean supportUHD = videoSizes.contains(UHD); 3561 boolean supportDC4K = videoSizes.contains(DC4K); 3562 boolean support4K = (supportUHD || supportDC4K); 3563 boolean supportFullHD = videoSizes.contains(FULLHD); 3564 boolean support720p = videoSizes.contains(HD); 3565 primaryRearReq.setPrimaryCameraVideoSizeReqSatisfied(support4K); 3566 primaryRearReq.setPrimaryCamera720PVideoSizeReqSatisfied(support720p); 3567 primaryRearReq.setPrimaryCamera1080PVideoSizeReqSatisfied(supportFullHD); 3568 if (support4K) { 3569 long minFrameDuration = config.getOutputMinFrameDuration( 3570 android.media.MediaRecorder.class, supportDC4K ? DC4K : UHD); 3571 primaryRearReq.setPrimaryCameraVideoFps(1e9 / minFrameDuration); 3572 } else { 3573 primaryRearReq.setPrimaryCameraVideoFps(-1); 3574 } 3575 if (supportFullHD) { 3576 long minFrameDuration = config.getOutputMinFrameDuration( 3577 android.media.MediaRecorder.class, FULLHD); 3578 primaryRearReq.setPrimaryCamera1080PVideoFps(1e9 / minFrameDuration); 3579 } else { 3580 primaryRearReq.setPrimaryCamera1080PVideoFps(-1); 3581 } 3582 if (support720p) { 3583 long minFrameDuration = config.getOutputMinFrameDuration( 3584 android.media.MediaRecorder.class, HD); 3585 primaryRearReq.setPrimaryCamera720PVideoFps(1e9 / minFrameDuration); 3586 } else { 3587 primaryRearReq.setPrimaryCamera720PVideoFps(-1); 3588 } 3589 // H-1-9 3590 boolean supportHighSpeed = staticInfo.isCapabilitySupported(CONSTRAINED_HIGH_SPEED); 3591 boolean support240Fps = false; 3592 if (supportHighSpeed) { 3593 Size[] availableHighSpeedSizes = config.getHighSpeedVideoSizes(); 3594 for (Size size : availableHighSpeedSizes) { 3595 if (!size.equals(HD) && !size.equals(FULLHD)) { 3596 continue; 3597 } 3598 Range<Integer>[] availableFpsRanges = 3599 config.getHighSpeedVideoFpsRangesFor(size); 3600 for (Range<Integer> fpsRange : availableFpsRanges) { 3601 if (fpsRange.getUpper() == 240) { 3602 support240Fps = true; 3603 break; 3604 } 3605 } 3606 if (support240Fps) { 3607 break; 3608 } 3609 } 3610 } 3611 hfrReq.setRearCamera240FpsSupported(support240Fps); 3612 } else { 3613 primaryFrontId = cameraId; 3614 primaryFrontReq.setPrimaryCameraAvailable(true); 3615 primaryFrontReq.setPrimaryCameraResolution(sensorResolution); 3616 hwLevelReq.setFrontPrimaryCameraHwlLevel(staticInfo.getHardwareLevelChecked()); 3617 timestampSourceReq.setFrontPrimaryCameraTimestampSource(timestampSource); 3618 3619 // 1080P @ 30fps 3620 boolean supportFULLHD = videoSizes.contains(FULLHD); 3621 primaryFrontReq.setPrimaryCameraVideoSizeReqSatisfied(supportFULLHD); 3622 if (supportFULLHD) { 3623 long minFrameDuration = config.getOutputMinFrameDuration( 3624 android.media.MediaRecorder.class, FULLHD); 3625 primaryFrontReq.setPrimaryCameraVideoFps(1e9 / minFrameDuration); 3626 } else { 3627 primaryFrontReq.setPrimaryCameraVideoFps(-1); 3628 } 3629 } 3630 3631 // H-1-8 3632 if (isPrimaryRear) { 3633 boolean supportRaw = staticInfo.isCapabilitySupported(RAW); 3634 rearRawReq.setRearCameraRawSupported(supportRaw); 3635 } 3636 3637 // H-1-10 3638 final double FOV_THRESHOLD = 0.001f; 3639 double primaryToMaxFovRatio = getPrimaryToMaxFovRatio(cameraId, staticInfo); 3640 Range<Float> zoomRatioRange = staticInfo.getZoomRatioRangeChecked(); 3641 boolean meetH110 = (CameraUtils.isDeviceFoldable(mContext) 3642 && hasUndefinedPoseReferenceWithSameFacing(cameraId, staticInfo)) 3643 || (primaryToMaxFovRatio >= 1.0f - FOV_THRESHOLD) 3644 || (zoomRatioRange.getLower() < 1.0f - FOV_THRESHOLD); 3645 if (isPrimaryRear) { 3646 ultrawideZoomRatioReq.setRearCameraUltrawideZoomReqMet(meetH110); 3647 } else { 3648 ultrawideZoomRatioReq.setFrontCameraUltrawideZoomReqMet(meetH110); 3649 } 3650 3651 // H-1-12 3652 if (isPrimaryRear) { 3653 boolean previewStab = staticInfo.isPreviewStabilizationSupported(); 3654 previewStabilizationReq.setRearCameraPreviewStabilizationSupported(previewStab); 3655 } 3656 3657 // H-1-13 3658 if (isPrimaryRear) { 3659 int facing = staticInfo.getLensFacingChecked(); 3660 int numOfPhysicalRgbCameras = getNumberOfRgbPhysicalCameras(facing); 3661 boolean logicalMultiCameraReqMet = 3662 (numOfPhysicalRgbCameras <= 1) || staticInfo.isLogicalMultiCamera(); 3663 logicalMultiCameraReq.setRearCameraLogicalMultiCameraReqMet( 3664 logicalMultiCameraReqMet); 3665 } 3666 3667 // H-1-14 3668 boolean streamUseCaseSupported = staticInfo.isStreamUseCaseSupported(); 3669 if (isPrimaryRear) { 3670 streamUseCaseReq.setRearCameraStreamUsecaseSupported(streamUseCaseSupported); 3671 } else { 3672 streamUseCaseReq.setFrontCameraStreamUsecaseSupported(streamUseCaseSupported); 3673 } 3674 } 3675 3676 if (primaryRearId == null) { 3677 primaryRearReq.setPrimaryCameraAvailable(false); 3678 primaryRearReq.setPrimaryCameraResolution(-1); 3679 primaryRearReq.setPrimaryCameraVideoSizeReqSatisfied(false); 3680 primaryRearReq.setPrimaryCameraVideoFps(-1); 3681 primaryRearReq.setPrimaryCamera1080PVideoFps(-1); 3682 primaryRearReq.setPrimaryCamera720PVideoFps(-1); 3683 primaryRearReq.setPrimaryCamera720PVideoSizeReqSatisfied(false); 3684 primaryRearReq.setPrimaryCamera1080PVideoSizeReqSatisfied(false); 3685 hwLevelReq.setRearPrimaryCameraHwlLevel(-1); 3686 timestampSourceReq.setRearPrimaryCameraTimestampSource( 3687 CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN); 3688 rearRawReq.setRearCameraRawSupported(false); 3689 hfrReq.setRearCamera240FpsSupported(false); 3690 ultrawideZoomRatioReq.setRearCameraUltrawideZoomReqMet(false); 3691 previewStabilizationReq.setRearCameraPreviewStabilizationSupported(false); 3692 logicalMultiCameraReq.setRearCameraLogicalMultiCameraReqMet(false); 3693 streamUseCaseReq.setRearCameraStreamUsecaseSupported(false); 3694 } 3695 if (primaryFrontId == null) { 3696 primaryFrontReq.setPrimaryCameraAvailable(false); 3697 primaryFrontReq.setPrimaryCameraResolution(-1); 3698 primaryFrontReq.setPrimaryCameraVideoSizeReqSatisfied(false); 3699 primaryFrontReq.setPrimaryCameraVideoFps(-1); 3700 hwLevelReq.setFrontPrimaryCameraHwlLevel(-1); 3701 timestampSourceReq.setFrontPrimaryCameraTimestampSource( 3702 CameraMetadata.SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN); 3703 ultrawideZoomRatioReq.setFrontCameraUltrawideZoomReqMet(false); 3704 streamUseCaseReq.setFrontCameraStreamUsecaseSupported(false); 3705 } 3706 3707 // H-1-11 3708 Set<Set<String>> concurrentCameraIds = mCameraManager.getConcurrentCameraIds(); 3709 Set<String> primaryCameras = new HashSet<>(Arrays.asList(primaryRearId, primaryFrontId)); 3710 boolean supportPrimaryFrontBack = concurrentCameraIds.contains(primaryCameras); 3711 concurrentRearFrontReq.setRearFrontConcurrentCamera(supportPrimaryFrontBack); 3712 3713 pce.submitAndCheck(); 3714 } 3715 3716 /** 3717 * Get the number of physical RGB camera devices facing the same direction as the 3718 * primary camera id 3719 */ 3720 private int getNumberOfRgbPhysicalCameras(int facing) throws Exception { 3721 int numOfRgbPhysicalCameras = 0; 3722 for (String id : getAllCameraIds()) { 3723 StaticMetadata staticInfo = mAllStaticInfo.get(id); 3724 if (staticInfo.getLensFacingChecked() != facing) { 3725 continue; 3726 } 3727 if (staticInfo.isLogicalMultiCamera()) { 3728 continue; 3729 } 3730 if (!staticInfo.isColorOutputSupported()) { 3731 continue; 3732 } 3733 if (staticInfo.isMonochromeCamera()) { 3734 continue; 3735 } 3736 numOfRgbPhysicalCameras++; 3737 } 3738 return numOfRgbPhysicalCameras; 3739 } 3740 3741 /** 3742 * Get the ratio of FOV between the primary camera and the maximium FOV of all color cameras 3743 * of the same facing. 3744 */ 3745 private double getPrimaryToMaxFovRatio(String primaryCameraId, StaticMetadata staticInfo) 3746 throws Exception { 3747 int facing = staticInfo.getLensFacingChecked(); 3748 double fovForPrimaryCamera = getCameraFov(staticInfo); 3749 3750 double largestFov = fovForPrimaryCamera; 3751 for (String id : getAllCameraIds()) { 3752 if (primaryCameraId.equals(id)) { 3753 continue; 3754 } 3755 3756 StaticMetadata staticInfoForId = mAllStaticInfo.get(id); 3757 if (staticInfoForId.getLensFacingChecked() != facing) { 3758 continue; 3759 } 3760 if (!staticInfoForId.isColorOutputSupported()) { 3761 continue; 3762 } 3763 3764 largestFov = Math.max(largestFov, getCameraFov(staticInfoForId)); 3765 } 3766 3767 Log.v(TAG, "Primary camera " + primaryCameraId + " FOV is " + fovForPrimaryCamera 3768 + ", largest camera FOV for the same facing is " + largestFov); 3769 return fovForPrimaryCamera / largestFov; 3770 } 3771 3772 private double getCameraFov(StaticMetadata staticInfo) { 3773 SizeF physicalSize = staticInfo.getCharacteristics().get( 3774 CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE); 3775 double physicalDiag = Math.sqrt(Math.pow(physicalSize.getWidth(), 2) 3776 + Math.pow(physicalSize.getHeight(), 2)); 3777 float[] availableFocalLengths = staticInfo.getAvailableFocalLengthsChecked(); 3778 3779 return 2 * Math.toDegrees(Math.atan2(physicalDiag / 2, availableFocalLengths[0])); 3780 } 3781 3782 /** 3783 * Whether there is a camera with UNDEFINED lens pose reference with the same facing. 3784 */ 3785 private boolean hasUndefinedPoseReferenceWithSameFacing(String cameraId, 3786 StaticMetadata staticInfo) throws Exception { 3787 int facing = staticInfo.getLensFacingChecked(); 3788 for (String id : getAllCameraIds()) { 3789 if (cameraId.equals(id)) { 3790 continue; 3791 } 3792 StaticMetadata staticInfoForId = mAllStaticInfo.get(id); 3793 if (staticInfoForId.getLensFacingChecked() != facing) { 3794 continue; 3795 } 3796 if (!staticInfoForId.isColorOutputSupported()) { 3797 continue; 3798 } 3799 if (staticInfoForId.isPoseReferenceUndefined()) { 3800 return true; 3801 } 3802 } 3803 return false; 3804 } 3805 3806 /** 3807 * Check camera characteristics for Android 14 Performance class requirements 3808 * as specified in CDD camera section 7.5 3809 */ 3810 @Test 3811 @AppModeFull(reason = "Media Performance class test not applicable to instant apps") 3812 @CddTest(requirements = { 3813 "2.2.7.2/7.5/H-1-16", 3814 "2.2.7.2/7.5/H-1-17"}) 3815 public void testCameraUPerfClassCharacteristics() throws Exception { 3816 assumeFalse("Media performance class tests not applicable if shell permission is adopted", 3817 mAdoptShellPerm); 3818 assumeTrue("Media performance class tests not applicable when test is restricted " 3819 + "to single camera by specifying camera id override.", mOverrideCameraId == null); 3820 3821 PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName); 3822 CameraDynamicRange10BitRequirement dynamicRangeTenBitsReq = 3823 Requirements.addR7_5__H_1_16().to(pce); 3824 CameraFaceDetectionRequirement faceDetectionReq = 3825 Requirements.addR7_5__H_1_17().to(pce); 3826 3827 String primaryRearId = CameraTestUtils.getPrimaryRearCamera(mCameraManager, 3828 getCameraIdsUnderTest()); 3829 String primaryFrontId = CameraTestUtils.getPrimaryFrontCamera(mCameraManager, 3830 getCameraIdsUnderTest()); 3831 3832 // H-1-16 3833 verifyDynamicRangeTenBits(primaryRearId, true /* isRear */, dynamicRangeTenBitsReq); 3834 verifyDynamicRangeTenBits(primaryFrontId, false /* isRear */, dynamicRangeTenBitsReq); 3835 3836 // H-1-17 3837 verifyFaceDetection(primaryRearId, true /* isRear */, faceDetectionReq); 3838 verifyFaceDetection(primaryFrontId, false /* isRear */, faceDetectionReq); 3839 3840 pce.submitAndCheck(); 3841 } 3842 3843 @Test 3844 @AppModeFull(reason = "Media Performance class test not applicable to instant apps") 3845 @CddTest(requirements = {"2.2.7.2/7.5/H-1-18"}) 3846 public void testCameraVPerfClassCharacteristics() throws Exception { 3847 assumeFalse("Media performance class tests not applicable if shell permission is adopted", 3848 mAdoptShellPerm); 3849 assumeTrue("Media performance class tests not applicable when test is restricted " 3850 + "to single camera by specifying camera id override.", mOverrideCameraId == null); 3851 3852 PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName); 3853 CameraJPEGRRequirement jpegRReq = Requirements.addR7_5__H_1_18().to(pce); 3854 3855 String primaryRearId = CameraTestUtils.getPrimaryRearCamera(mCameraManager, 3856 getCameraIdsUnderTest()); 3857 String primaryFrontId = CameraTestUtils.getPrimaryFrontCamera(mCameraManager, 3858 getCameraIdsUnderTest()); 3859 3860 // H-1-18 3861 verifyJpegRRequirement(primaryRearId, true /* isRear */, jpegRReq); 3862 verifyJpegRRequirement(primaryFrontId, false /* isRear */, jpegRReq); 3863 3864 pce.submitAndCheck(); 3865 } 3866 3867 /** 3868 * Check camera extension characteristics for Android 14 Performance class requirements 3869 * as specified in CDD camera section 7.5 3870 */ 3871 @Test 3872 @AppModeFull(reason = "Media Performance class test not applicable to instant apps") 3873 @CddTest(requirements = { 3874 "2.2.7.2/7.5/H-1-15"}) 3875 public void testCameraUPerfClassExtensionCharacteristics() throws Exception { 3876 assumeFalse("Media performance class tests not applicable if shell permission is adopted", 3877 mAdoptShellPerm); 3878 assumeTrue("Media performance class tests not applicable when test is restricted " 3879 + "to single camera by specifying camera id override.", mOverrideCameraId == null); 3880 3881 PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName); 3882 CameraNightModeExtensionRequirement cameraExtensionReq = 3883 Requirements.addR7_5__H_1_15().to(pce); 3884 3885 String primaryRearId = CameraTestUtils.getPrimaryRearCamera(mCameraManager, 3886 getCameraIdsUnderTest()); 3887 String primaryFrontId = CameraTestUtils.getPrimaryFrontCamera(mCameraManager, 3888 getCameraIdsUnderTest()); 3889 3890 verifyExtensionForCamera(primaryRearId, true /* isRear */, cameraExtensionReq); 3891 verifyExtensionForCamera(primaryFrontId, false /* isRear */, cameraExtensionReq); 3892 3893 pce.submitAndCheck(); 3894 } 3895 3896 /** 3897 * Verify camera2 and CameraX extension requirements for a camera id 3898 */ 3899 private void verifyExtensionForCamera(String cameraId, boolean isRear, 3900 CameraNightModeExtensionRequirement req) throws Exception { 3901 if (cameraId == null) { 3902 if (isRear) { 3903 req.setRearCamera2ExtensionNightSupported(false); 3904 req.setRearCameraxExtensionNightSupported(false); 3905 } else { 3906 req.setFrontCamera2ExtensionNightSupported(false); 3907 req.setFrontCameraxExtensionNightSupported(false); 3908 } 3909 return; 3910 } 3911 3912 ExtensionsManager extensionsManager = getCameraXExtensionManager(); 3913 CameraExtensionCharacteristics extensionChars = 3914 mCameraManager.getCameraExtensionCharacteristics(cameraId); 3915 StaticMetadata staticInfo = mAllStaticInfo.get(cameraId); 3916 3917 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 3918 boolean nightExtensionSupported = 3919 supportedExtensions.contains(CameraExtensionCharacteristics.EXTENSION_NIGHT); 3920 if (isRear) { 3921 req.setRearCamera2ExtensionNightSupported(nightExtensionSupported); 3922 } else { 3923 req.setFrontCamera2ExtensionNightSupported(nightExtensionSupported); 3924 } 3925 3926 CameraSelector selector = isRear 3927 ? CameraSelector.DEFAULT_BACK_CAMERA 3928 : CameraSelector.DEFAULT_FRONT_CAMERA; 3929 nightExtensionSupported = 3930 extensionsManager.isExtensionAvailable(selector, ExtensionMode.NIGHT); 3931 if (isRear) { 3932 req.setRearCameraxExtensionNightSupported(nightExtensionSupported); 3933 } else { 3934 req.setFrontCameraxExtensionNightSupported(nightExtensionSupported); 3935 } 3936 } 3937 3938 /** 3939 * Verify JPEG_R requirement for a camera id 3940 */ 3941 private void verifyJpegRRequirement(String cameraId, boolean isRear, CameraJPEGRRequirement req) 3942 throws Exception { 3943 if (cameraId == null) { 3944 if (isRear) { 3945 req.setPrimaryRearCameraJpegRSupported(false); 3946 } else { 3947 req.setPrimaryFrontCameraJpegRSupported(false); 3948 } 3949 return; 3950 } 3951 3952 StaticMetadata staticInfo = mAllStaticInfo.get(cameraId); 3953 3954 if (isRear) { 3955 req.setPrimaryRearCameraJpegRSupported(staticInfo.isJpegRSupported()); 3956 } else { 3957 req.setPrimaryFrontCameraJpegRSupported(staticInfo.isJpegRSupported()); 3958 } 3959 } 3960 3961 /** 3962 * Verify dynamic range ten bits requirement for a camera id 3963 */ 3964 private void verifyDynamicRangeTenBits(String cameraId, boolean isRear, 3965 CameraDynamicRange10BitRequirement req) throws Exception { 3966 if (cameraId == null) { 3967 if (isRear) { 3968 req.setRearCameraDynamicTenbitsSupported(false); 3969 } else { 3970 req.setFrontCameraDynamicTenbitsSupported(false); 3971 } 3972 return; 3973 } 3974 3975 StaticMetadata staticInfo = mAllStaticInfo.get(cameraId); 3976 boolean dynamicRangeTenBitsSupported = 3977 staticInfo.isCapabilitySupported(DYNAMIC_RANGE_TEN_BIT); 3978 3979 if (isRear) { 3980 req.setRearCameraDynamicTenbitsSupported(dynamicRangeTenBitsSupported); 3981 } else { 3982 req.setFrontCameraDynamicTenbitsSupported(dynamicRangeTenBitsSupported); 3983 } 3984 } 3985 3986 /** 3987 * Verify face detection requirements for a camera id 3988 */ 3989 private void verifyFaceDetection(String cameraId, boolean isRear, 3990 CameraFaceDetectionRequirement req) { 3991 if (cameraId == null) { 3992 if (isRear) { 3993 req.setRearCameraFaceDetectionSupported(false); 3994 } else { 3995 req.setFrontCameraFaceDetectionSupported(false); 3996 } 3997 return; 3998 } 3999 4000 StaticMetadata staticInfo = mAllStaticInfo.get(cameraId); 4001 int[] availableFaceDetectionModes = staticInfo.getAvailableFaceDetectModesChecked(); 4002 assertNotNull(availableFaceDetectionModes); 4003 int[] supportedFaceDetectionModes = {FACE_DETECTION_MODE_SIMPLE, FACE_DETECTION_MODE_FULL}; 4004 boolean faceDetectionSupported = arrayContainsAnyOf(availableFaceDetectionModes, 4005 supportedFaceDetectionModes); 4006 4007 if (isRear) { 4008 req.setRearCameraFaceDetectionSupported(faceDetectionSupported); 4009 } else { 4010 req.setFrontCameraFaceDetectionSupported(faceDetectionSupported); 4011 } 4012 } 4013 4014 /** 4015 * Get lens distortion coefficients, as a list of 6 floats; returns null if no valid 4016 * distortion field is available 4017 */ 4018 private float[] getLensDistortion(CameraCharacteristics c) { 4019 float[] distortion = null; 4020 float[] newDistortion = c.get(CameraCharacteristics.LENS_DISTORTION); 4021 if (Build.VERSION.DEVICE_INITIAL_SDK_INT > Build.VERSION_CODES.O_MR1 || newDistortion != null) { 4022 // New devices need to use fixed radial distortion definition; old devices can 4023 // opt-in to it 4024 if (newDistortion != null && newDistortion.length == 5) { 4025 distortion = new float[6]; 4026 distortion[0] = 1.0f; 4027 for (int i = 1; i < 6; i++) { 4028 distortion[i] = newDistortion[i-1]; 4029 } 4030 } 4031 } else { 4032 // Select old field only if on older first SDK and new definition not available 4033 distortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION); 4034 } 4035 return distortion; 4036 } 4037 4038 /** 4039 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 4040 */ 4041 private Size findInvalidSize(Size[] goodSizes) { 4042 return findInvalidSize(Arrays.asList(goodSizes)); 4043 } 4044 4045 /** 4046 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 4047 */ 4048 private Size findInvalidSize(List<Size> goodSizes) { 4049 Size invalidSize = new Size(goodSizes.get(0).getWidth() + 1, goodSizes.get(0).getHeight()); 4050 while(goodSizes.contains(invalidSize)) { 4051 invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight()); 4052 } 4053 return invalidSize; 4054 } 4055 4056 /** 4057 * Validate {@link CameraCharacteristics#LENS_POSE_TRANSLATION} and @{link 4058 * CameraCharacteristics#LENS_POSE_ROTATION} of camera that list below characteristics in their 4059 * static metadata. 4060 * - CameraCharacteristics.AUTOMOTIVE_LOCATION_INTERIOR_OTHER 4061 * - CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER 4062 * - CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER 4063 */ 4064 @Test 4065 public void testAutomotiveCameraCharacteristics() throws Exception { 4066 String[] allCameraIds = getAllCameraIds(); 4067 for (int i = 0; i < allCameraIds.length; i++) { 4068 CameraCharacteristics c = mCharacteristics.get(i); 4069 4070 Integer location = c.get(CameraCharacteristics.AUTOMOTIVE_LOCATION); 4071 int[] lensFacing = c.get(CameraCharacteristics.AUTOMOTIVE_LENS_FACING); 4072 if (location == null || lensFacing == null) { 4073 // CameraManagerTest#testCameraManagerAutomotiveCameras() guarantees 4074 // CameraCharacteristics.AUTOMOTIVE_LOCATION and 4075 // CameraCharacteristics.AUTOMOTIVE_LENS_FACING are listed in a static metadata of 4076 // cameras on the automotive device implementations. 4077 continue; 4078 } 4079 4080 float[] translation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 4081 float[] rotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 4082 assertTrue("android.lens.poseTranslation and android.lens.poseRotation must exist " + 4083 "together or not at all", 4084 (translation != null) == (rotation != null)); 4085 if (translation == null && rotation == null) { 4086 // Cameras without android.lens.poseTranslation and anroid.lens.poseRotation are 4087 // exempt from this test case. 4088 continue; 4089 } 4090 4091 // android.lens.poseTranslation describes the lens optical center of the camera device 4092 // as a three dimensional vector (x, y, z) and in the unit of meters. On the automotive 4093 // sensor coordinate system, we expect the following: 4094 // - The width of the vehicle body frame would not exceed 6 meters, which is a width of 4095 // the vehicle lane approximately. 4096 // - The length of the vehicle body frame would not exceed 10 meters, which is an 4097 // average length of the city bus. We apply approximately 20% tolerance to this value 4098 // because of a relatively higher variance of the vehicle's length. 4099 // - The height of the vehicle body frame would not exceed 5 meters, which is an average 4100 // height of the double decker bus. 4101 assertTrue("Lens pose translation vector is invalid", 4102 (translation[0] >= -3 && translation[0] <= 3) 4103 && (translation[1] >= -2 && translation[1] <= 10) 4104 && (translation[2] >= 0 && translation[2] <= 5)); 4105 4106 // Convert a given quaternion to axis-angle representation 4107 double theta = 2.0 * Math.acos(rotation[3]); 4108 double a_x = rotation[0] / Math.sin(theta / 2.0); 4109 double a_y = rotation[1] / Math.sin(theta / 2.0); 4110 double a_z = rotation[2] / Math.sin(theta / 2.0); 4111 4112 // Calculate an angle between a translation vector and a rotation axis 4113 double dot = (translation[0] * a_x) + (translation[1] * a_y) + (translation[2] * a_z); 4114 double mag_a = Math.sqrt(Math.pow(translation[0], 2) + Math.pow(translation[1], 2) 4115 + Math.pow(translation[2], 2)); 4116 double mag_b = 4117 Math.sqrt(Math.pow(a_x, 2) + Math.pow(a_y, 2) + Math.pow(a_z, 2)); 4118 double angle = Math.acos(dot / (mag_a * mag_b)); 4119 4120 if (location == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER 4121 || location == CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER) { 4122 // If android.automotive.location is 4123 // CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTERIOR_OTHER or 4124 // CameraCharacteristics.AUTOMOTIVE_LOCATION_EXTRA_OTHER, its 4125 // android.lens.poseRotation should not describe a direction toward the inside of 4126 // the vehicle cabin. 4127 assertTrue("Lens pose rotation should not describe a direction toward the cabin", 4128 angle >= Math.PI / 4); 4129 } else if (location == CameraCharacteristics.AUTOMOTIVE_LOCATION_INTERIOR) { 4130 // Likewise, if android.automotive.lens.facing is 4131 // CameraCharacteristics.AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER, its 4132 // android.lens.poseRotation should not describe a direction toward the outside 4133 // of the vehicle cabin. 4134 for (int value : lensFacing) { 4135 if (value != CameraCharacteristics.AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER) { 4136 continue; 4137 } 4138 4139 assertTrue("Lens pose rotation should not describe a direction toward " + 4140 "the outside of the cabin", 4141 angle <= Math.PI * 3 / 4); 4142 4143 // No need to examine remaining lens facing values. 4144 break; 4145 } 4146 } 4147 } 4148 } 4149 4150 private void testLandscapeToPortraitSensorOrientation(String cameraId) throws Exception { 4151 CameraCharacteristics characteristics = 4152 mCameraManager.getCameraCharacteristics(cameraId, false); 4153 CameraCharacteristics characteristicsOverride = 4154 mCameraManager.getCameraCharacteristics(cameraId, true); 4155 int sensorOrientation = characteristics.get( 4156 CameraCharacteristics.SENSOR_ORIENTATION); 4157 int sensorOrientationOverride = characteristicsOverride.get( 4158 CameraCharacteristics.SENSOR_ORIENTATION); 4159 4160 if (sensorOrientation == 0 || sensorOrientation == 180) { 4161 int facing = characteristics.get(CameraCharacteristics.LENS_FACING); 4162 if (facing == CameraMetadata.LENS_FACING_FRONT) { 4163 assertEquals("SENSOR_ORIENTATION should be rotated 90 degrees" 4164 + " counter-clockwise for front-facing cameras.", 4165 (360 + sensorOrientation - 90) % 360, sensorOrientationOverride); 4166 } else if (facing == CameraMetadata.LENS_FACING_BACK) { 4167 assertEquals("SENSOR_ORIENTATION should be rotated 90 degrees clockwise" 4168 + " for back-facing cameras.", 4169 (360 + sensorOrientation + 90) % 360, sensorOrientationOverride); 4170 } else { 4171 assertEquals("SENSOR_ORIENTATION should be unchanged for external cameras.", 4172 sensorOrientation, sensorOrientationOverride); 4173 } 4174 } else { 4175 assertEquals("SENSOR_ORIENTATION should be unchanged for non-landscape " 4176 + "sensors.", sensorOrientation, sensorOrientationOverride); 4177 } 4178 } 4179 4180 /** 4181 * Test that the landscape to portrait override modifies SENSOR_ORIENTATION as expected. 4182 * All cameras with SENSOR_ORIENTATION 0 or 180 should have SENSOR_ORIENTATION 90 or 270 4183 * when the override is turned on. Cameras not accessible via openCamera ("constituent 4184 * cameras") should not update their SENSOR_ORIENTATION values. 4185 */ 4186 @Test 4187 public void testLandscapeToPortraitOverride() throws Exception { 4188 String[] cameraIdArr = mCameraManager.getCameraIdListNoLazy(); 4189 ArrayList<String> cameraIdList = new ArrayList<>(Arrays.asList(cameraIdArr)); 4190 for (String cameraId : getCameraIdsUnderTest()) { 4191 Log.i(TAG, "testLandscapeToPortraitOverride: Testing camera ID " + cameraId); 4192 StaticMetadata staticMetadata = mAllStaticInfo.get(cameraId); 4193 4194 testLandscapeToPortraitSensorOrientation(cameraId); 4195 4196 if (staticMetadata.isLogicalMultiCamera()) { 4197 Log.i(TAG, "Camera " + cameraId + " is a logical multi-camera."); 4198 4199 CameraCharacteristics characteristics = 4200 mCameraManager.getCameraCharacteristics(cameraId, false); 4201 4202 Set<String> physicalCameraIds = characteristics.getPhysicalCameraIds(); 4203 for (String physicalId : physicalCameraIds) { 4204 if (!cameraIdList.contains(physicalId)) { 4205 Log.i(TAG, "Testing constituent camera id: " + physicalId); 4206 4207 CameraCharacteristics physicalCharacteristics = 4208 mCameraManager.getCameraCharacteristics(physicalId, false); 4209 CameraCharacteristics physicalCharacteristicsOverride = 4210 mCameraManager.getCameraCharacteristics(physicalId, true); 4211 int physicalSensorOrientation = physicalCharacteristics.get( 4212 CameraCharacteristics.SENSOR_ORIENTATION); 4213 int physicalSensorOrientationOverride = physicalCharacteristicsOverride.get( 4214 CameraCharacteristics.SENSOR_ORIENTATION); 4215 4216 // Check that physical camera orientations have NOT been overridden. 4217 assertEquals("SENSOR_ORIENTATION should be unchanged for constituent " 4218 + "physical cameras.", physicalSensorOrientation, 4219 physicalSensorOrientationOverride); 4220 } 4221 } 4222 } 4223 } 4224 } 4225 4226 /** 4227 * Validate that the rear/world facing cameras in automotive devices are oriented so that the 4228 * long dimension of the camera aligns with the X-Y plane of Android automotive sensor axes. 4229 */ 4230 @CddTest(requirements = "7.5/A-1-1") 4231 @Test 4232 public void testAutomotiveCameraOrientation() throws Exception { 4233 assumeTrue(mContext.getPackageManager().hasSystemFeature( 4234 PackageManager.FEATURE_AUTOMOTIVE)); 4235 String[] allCameraIds = getAllCameraIds(); 4236 for (int i = 0; i < allCameraIds.length; i++) { 4237 CameraCharacteristics c = mCharacteristics.get(i); 4238 int facing = c.get(CameraCharacteristics.LENS_FACING); 4239 if (facing == CameraMetadata.LENS_FACING_BACK) { 4240 // Camera size 4241 Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 4242 // Camera orientation 4243 int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 4244 // For square sensor, test is guaranteed to pass. 4245 if (pixelArraySize.getWidth() == pixelArraySize.getHeight()) { 4246 continue; 4247 } 4248 // Camera size adjusted for device native orientation. 4249 Size adjustedSensorSize; 4250 if (sensorOrientation == 90 || sensorOrientation == 270) { 4251 adjustedSensorSize = new Size( 4252 pixelArraySize.getHeight(), pixelArraySize.getWidth()); 4253 } else { 4254 adjustedSensorSize = pixelArraySize; 4255 } 4256 boolean isCameraLandscape = 4257 adjustedSensorSize.getWidth() > adjustedSensorSize.getHeight(); 4258 // Automotive camera orientation should be landscape for rear/world facing camera. 4259 assertTrue("Automotive camera " + allCameraIds[i] + " which is rear/world facing" 4260 + " must align with the X-Y plane of Android automotive sensor axes", 4261 isCameraLandscape); 4262 } 4263 } 4264 } 4265 4266 /** 4267 * Validate the operating luminance range for low light boost. If the luminance range is 4268 * defined then the AE mode CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY must also 4269 * be present in the list of available AE modes. 4270 */ 4271 @Test 4272 @RequiresFlagsEnabled(Flags.FLAG_CAMERA_AE_MODE_LOW_LIGHT_BOOST) 4273 public void testLowLightBoostLuminanceRange() throws Exception { 4274 String[] allCameraIds = getAllCameraIds(); 4275 for (int i = 0; i < allCameraIds.length; i++) { 4276 Log.i(TAG, "testLowLightBoostLuminanceRange: Testing camera ID " + allCameraIds[i]); 4277 CameraCharacteristics c = mCharacteristics.get(i); 4278 4279 // Check for the presence of AE mode low light boost 4280 int[] availableAeModes = c.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES); 4281 if (availableAeModes == null) { 4282 Log.i(TAG, "Camera id " + allCameraIds[i] + " does not have AE modes. " 4283 + "Skipping testLowLightBoostLuminanceRange"); 4284 continue; 4285 } 4286 4287 assertNotNull("CONTROL_AE_AVAILABLE_MODES must be present", availableAeModes); 4288 boolean containsAeModeLowLightBoost = false; 4289 for (int aeMode : availableAeModes) { 4290 if (aeMode 4291 == CameraMetadata.CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY) { 4292 containsAeModeLowLightBoost = true; 4293 break; 4294 } 4295 } 4296 4297 Range<Float> lowLightBoostLuminanceRange = 4298 c.get(CameraCharacteristics.CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE); 4299 4300 // The AE mode low light boost can only be available if the luminance range is also 4301 // defined 4302 if (lowLightBoostLuminanceRange == null) { 4303 assertFalse("AE mode ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY can only be present " 4304 + "if LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE is also defined", 4305 containsAeModeLowLightBoost); 4306 continue; 4307 } 4308 assertTrue("AE mode ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY must be present if " 4309 + "LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE is also defined", 4310 containsAeModeLowLightBoost); 4311 4312 float luminanceRangeLower = lowLightBoostLuminanceRange.getLower(); 4313 assertTrue("Luminance range lower bound is in the range [0.1, 8.0]", 4314 luminanceRangeLower >= 0.1f && luminanceRangeLower <= 8.0f); 4315 } 4316 } 4317 4318 /** 4319 * Check key is present in characteristics if the hardware level is at least {@code hwLevel}; 4320 * check that the key is present if the actual capabilities are one of {@code capabilities}. 4321 * 4322 * @return value of the {@code key} from {@code c} 4323 */ 4324 private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, 4325 int hwLevel, int... capabilities) { 4326 4327 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 4328 assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel); 4329 4330 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 4331 assertNotNull("android.request.availableCapabilities must never be null", 4332 actualCapabilities); 4333 4334 List<Key<?>> allKeys = c.getKeys(); 4335 4336 T value = c.get(key); 4337 4338 // For LIMITED-level targeted keys, rely on capability check, not level 4339 if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) { 4340 mCollector.expectTrue( 4341 String.format("Key (%s) must be in characteristics for this hardware level " + 4342 "(required minimal HW level %s, actual HW level %s)", 4343 key.getName(), toStringHardwareLevel(hwLevel), 4344 toStringHardwareLevel(actualHwLevel)), 4345 value != null); 4346 mCollector.expectTrue( 4347 String.format("Key (%s) must be in characteristics list of keys for this " + 4348 "hardware level (required minimal HW level %s, actual HW level %s)", 4349 key.getName(), toStringHardwareLevel(hwLevel), 4350 toStringHardwareLevel(actualHwLevel)), 4351 allKeys.contains(key)); 4352 } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) { 4353 if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) { 4354 // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined 4355 mCollector.expectTrue( 4356 String.format("Key (%s) must be in characteristics for these capabilities " + 4357 "(required capabilities %s, actual capabilities %s)", 4358 key.getName(), Arrays.toString(capabilities), 4359 Arrays.toString(actualCapabilities)), 4360 value != null); 4361 mCollector.expectTrue( 4362 String.format("Key (%s) must be in characteristics list of keys for " + 4363 "these capabilities (required capabilities %s, actual capabilities %s)", 4364 key.getName(), Arrays.toString(capabilities), 4365 Arrays.toString(actualCapabilities)), 4366 allKeys.contains(key)); 4367 } 4368 } else { 4369 if (actualHwLevel == LEGACY && hwLevel != OPT) { 4370 if (value != null || allKeys.contains(key)) { 4371 Log.w(TAG, String.format( 4372 "Key (%s) is not required for LEGACY devices but still appears", 4373 key.getName())); 4374 } 4375 } 4376 // OK: Key may or may not be present. 4377 } 4378 return value; 4379 } 4380 4381 private static boolean arrayContains(int[] arr, int needle) { 4382 if (arr == null) { 4383 return false; 4384 } 4385 4386 for (int elem : arr) { 4387 if (elem == needle) { 4388 return true; 4389 } 4390 } 4391 4392 return false; 4393 } 4394 4395 private static <T> boolean arrayContains(T[] arr, T needle) { 4396 if (arr == null) { 4397 return false; 4398 } 4399 4400 for (T elem : arr) { 4401 if (elem.equals(needle)) { 4402 return true; 4403 } 4404 } 4405 4406 return false; 4407 } 4408 4409 private static boolean arrayContainsAnyOf(int[] arr, int[] needles) { 4410 for (int needle : needles) { 4411 if (arrayContains(arr, needle)) { 4412 return true; 4413 } 4414 } 4415 return false; 4416 } 4417 4418 /** 4419 * The key name has a prefix of either "android." or a valid TLD; other prefixes are not valid. 4420 */ 4421 private static void assertKeyPrefixValid(String keyName) { 4422 assertStartsWithAndroidOrTLD( 4423 "All metadata keys must start with 'android.' (built-in keys) " + 4424 "or valid TLD (vendor-extended keys)", keyName); 4425 } 4426 4427 private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, 4428 boolean actual) { 4429 assertTrue(msg + " (key = '" + key.getName() + "')", actual); 4430 } 4431 4432 private static <T> void assertOneOf(String msg, T[] expected, T actual) { 4433 for (int i = 0; i < expected.length; ++i) { 4434 if (Objects.equals(expected[i], actual)) { 4435 return; 4436 } 4437 } 4438 4439 fail(String.format("%s: (expected one of %s, actual %s)", 4440 msg, Arrays.toString(expected), actual)); 4441 } 4442 4443 private static <T> void assertStartsWithAndroidOrTLD(String msg, String keyName) { 4444 String delimiter = "."; 4445 if (keyName.startsWith(PREFIX_ANDROID + delimiter)) { 4446 return; 4447 } 4448 Pattern tldPattern = Pattern.compile(Patterns.TOP_LEVEL_DOMAIN_STR); 4449 Matcher match = tldPattern.matcher(keyName); 4450 if (match.find(0) && (0 == match.start()) && (!match.hitEnd())) { 4451 if (keyName.regionMatches(match.end(), delimiter, 0, delimiter.length())) { 4452 return; 4453 } 4454 } 4455 4456 fail(String.format("%s: (expected to start with %s or valid TLD, but value was %s)", 4457 msg, PREFIX_ANDROID + delimiter, keyName)); 4458 } 4459 4460 /** Return a positive int if left > right, 0 if left==right, negative int if left < right */ 4461 private static int compareHardwareLevel(int left, int right) { 4462 return remapHardwareLevel(left) - remapHardwareLevel(right); 4463 } 4464 4465 /** Remap HW levels worst<->best, 0 = LEGACY, 1 = LIMITED, 2 = FULL, ..., N = LEVEL_N */ 4466 private static int remapHardwareLevel(int level) { 4467 switch (level) { 4468 case OPT: 4469 return Integer.MAX_VALUE; 4470 case LEGACY: 4471 return 0; // lowest 4472 case EXTERNAL: 4473 return 1; // second lowest 4474 case LIMITED: 4475 return 2; 4476 case FULL: 4477 return 3; // good 4478 case LEVEL_3: 4479 return 4; 4480 default: 4481 fail("Unknown HW level: " + level); 4482 } 4483 return -1; 4484 } 4485 4486 private static String toStringHardwareLevel(int level) { 4487 switch (level) { 4488 case LEGACY: 4489 return "LEGACY"; 4490 case LIMITED: 4491 return "LIMITED"; 4492 case FULL: 4493 return "FULL"; 4494 case EXTERNAL: 4495 return "EXTERNAL"; 4496 default: 4497 if (level >= LEVEL_3) { 4498 return String.format("LEVEL_%d", level); 4499 } 4500 } 4501 4502 // unknown 4503 Log.w(TAG, "Unknown hardware level " + level); 4504 return Integer.toString(level); 4505 } 4506 } 4507