1 /* 2 * Copyright 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.helpers; 18 19 import android.graphics.Rect; 20 import android.graphics.ImageFormat; 21 import android.hardware.camera2.CameraCharacteristics; 22 import android.hardware.camera2.CameraCharacteristics.Key; 23 import android.hardware.camera2.CameraMetadata; 24 import android.hardware.camera2.CaptureRequest; 25 import android.hardware.camera2.CaptureResult; 26 import android.hardware.camera2.cts.CameraTestUtils; 27 import android.hardware.camera2.params.StreamConfigurationMap; 28 import android.hardware.camera2.params.Capability; 29 import android.util.Range; 30 import android.util.Size; 31 import android.util.Log; 32 import android.util.Rational; 33 34 import junit.framework.Assert; 35 36 import java.lang.reflect.Array; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collection; 40 import java.util.HashMap; 41 import java.util.HashSet; 42 import java.util.List; 43 import java.util.Set; 44 45 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 46 47 /** 48 * Helpers to get common static info out of the camera. 49 * 50 * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p> 51 * 52 * <p>Attempt to be durable against the camera device having bad or missing metadata 53 * by providing reasonable defaults and logging warnings when that happens.</p> 54 */ 55 public class StaticMetadata { 56 57 private static final String TAG = "StaticMetadata"; 58 private static final int IGNORE_SIZE_CHECK = -1; 59 60 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us 61 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms 62 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100; 63 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800; 64 private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4; 65 private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64; 66 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2; 67 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2; 68 private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2); 69 private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8; 70 private static final int MAX_REPROCESS_MAX_CAPTURE_STALL = 4; 71 72 // TODO: Consider making this work across any metadata object, not just camera characteristics 73 private final CameraCharacteristics mCharacteristics; 74 private final CheckLevel mLevel; 75 private final CameraErrorCollector mCollector; 76 77 // Last defined capability enum, for iterating over all of them 78 public static final int LAST_CAPABILITY_ENUM = 79 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING; 80 81 // Access via getAeModeName() to account for vendor extensions 82 public static final String[] AE_MODE_NAMES = new String[] { 83 "AE_MODE_OFF", 84 "AE_MODE_ON", 85 "AE_MODE_ON_AUTO_FLASH", 86 "AE_MODE_ON_ALWAYS_FLASH", 87 "AE_MODE_ON_AUTO_FLASH_REDEYE" 88 }; 89 90 // Access via getAfModeName() to account for vendor extensions 91 public static final String[] AF_MODE_NAMES = new String[] { 92 "AF_MODE_OFF", 93 "AF_MODE_AUTO", 94 "AF_MODE_MACRO", 95 "AF_MODE_CONTINUOUS_VIDEO", 96 "AF_MODE_CONTINUOUS_PICTURE", 97 "AF_MODE_EDOF" 98 }; 99 100 // Index with android.control.aeState 101 public static final String[] AE_STATE_NAMES = new String[] { 102 "AE_STATE_INACTIVE", 103 "AE_STATE_SEARCHING", 104 "AE_STATE_CONVERGED", 105 "AE_STATE_LOCKED", 106 "AE_STATE_FLASH_REQUIRED", 107 "AE_STATE_PRECAPTURE" 108 }; 109 110 // Index with android.control.afState 111 public static final String[] AF_STATE_NAMES = new String[] { 112 "AF_STATE_INACTIVE", 113 "AF_STATE_PASSIVE_SCAN", 114 "AF_STATE_PASSIVE_FOCUSED", 115 "AF_STATE_ACTIVE_SCAN", 116 "AF_STATE_FOCUSED_LOCKED", 117 "AF_STATE_NOT_FOCUSED_LOCKED", 118 "AF_STATE_PASSIVE_UNFOCUSED" 119 }; 120 121 // Index with android.control.aePrecaptureTrigger 122 public static final String[] AE_TRIGGER_NAMES = new String[] { 123 "AE_TRIGGER_IDLE", 124 "AE_TRIGGER_START", 125 "AE_TRIGGER_CANCEL" 126 }; 127 128 // Index with android.control.afTrigger 129 public static final String[] AF_TRIGGER_NAMES = new String[] { 130 "AF_TRIGGER_IDLE", 131 "AF_TRIGGER_START", 132 "AF_TRIGGER_CANCEL" 133 }; 134 135 public enum CheckLevel { 136 /** Only log warnings for metadata check failures. Execution continues. */ 137 WARN, 138 /** 139 * Use ErrorCollector to collect the metadata check failures, Execution 140 * continues. 141 */ 142 COLLECT, 143 /** Assert the metadata check failures. Execution aborts. */ 144 ASSERT 145 } 146 147 /** 148 * Construct a new StaticMetadata object. 149 * 150 *<p> Default constructor, only log warnings for the static metadata check failures</p> 151 * 152 * @param characteristics static info for a camera 153 * @throws IllegalArgumentException if characteristics was null 154 */ StaticMetadata(CameraCharacteristics characteristics)155 public StaticMetadata(CameraCharacteristics characteristics) { 156 this(characteristics, CheckLevel.WARN, /*collector*/null); 157 } 158 159 /** 160 * Construct a new StaticMetadata object with {@link CameraErrorCollector}. 161 * <p> 162 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 163 * ignored, otherwise, it will be used to log the check failures. 164 * </p> 165 * 166 * @param characteristics static info for a camera 167 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 168 * @throws IllegalArgumentException if characteristics or collector was null. 169 */ StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector)170 public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) { 171 this(characteristics, CheckLevel.COLLECT, collector); 172 } 173 174 /** 175 * Construct a new StaticMetadata object with {@link CheckLevel} and 176 * {@link CameraErrorCollector}. 177 * <p> 178 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 179 * ignored, otherwise, it will be used to log the check failures. 180 * </p> 181 * 182 * @param characteristics static info for a camera 183 * @param level The {@link CheckLevel} of this StaticMetadata 184 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 185 * @throws IllegalArgumentException if characteristics was null or level was 186 * {@link CheckLevel.COLLECT} but collector was null. 187 */ StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, CameraErrorCollector collector)188 public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, 189 CameraErrorCollector collector) { 190 if (characteristics == null) { 191 throw new IllegalArgumentException("characteristics was null"); 192 } 193 if (level == CheckLevel.COLLECT && collector == null) { 194 throw new IllegalArgumentException("collector must valid when COLLECT level is set"); 195 } 196 197 mCharacteristics = characteristics; 198 mLevel = level; 199 mCollector = collector; 200 } 201 202 /** 203 * Get the CameraCharacteristics associated with this StaticMetadata. 204 * 205 * @return A non-null CameraCharacteristics object 206 */ getCharacteristics()207 public CameraCharacteristics getCharacteristics() { 208 return mCharacteristics; 209 } 210 211 /** 212 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 213 * is at least {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}. 214 * 215 * <p>If the camera device is not reporting the hardwareLevel, this 216 * will cause the test to fail.</p> 217 * 218 * @return {@code true} if the device is {@code FULL}, {@code false} otherwise. 219 */ isHardwareLevelAtLeastFull()220 public boolean isHardwareLevelAtLeastFull() { 221 return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL); 222 } 223 224 /** 225 * Whether or not the hardware level reported by android.info.supportedHardwareLevel is 226 * at least the desired one (but could be higher) 227 */ isHardwareLevelAtLeast(int level)228 public boolean isHardwareLevelAtLeast(int level) { 229 final int[] sortedHwLevels = { 230 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, 231 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL, 232 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED, 233 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, 234 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 235 }; 236 int deviceLevel = getHardwareLevelChecked(); 237 if (level == deviceLevel) { 238 return true; 239 } 240 241 for (int sortedlevel : sortedHwLevels) { 242 if (sortedlevel == level) { 243 return true; 244 } else if (sortedlevel == deviceLevel) { 245 return false; 246 } 247 } 248 Assert.fail("Unknown hardwareLevel " + level + " and device hardware level " + deviceLevel); 249 return false; 250 } 251 252 /** 253 * Whether or not the camera is an external camera. If so the hardware level 254 * reported by android.info.supportedHardwareLevel is 255 * {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL}. 256 * 257 * <p>If the camera device is not reporting the hardwareLevel, this 258 * will cause the test to fail.</p> 259 * 260 * @return {@code true} if the device is external, {@code false} otherwise. 261 */ isExternalCamera()262 public boolean isExternalCamera() { 263 int deviceLevel = getHardwareLevelChecked(); 264 return deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL; 265 } 266 267 /** 268 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 269 * Return the supported hardware level of the device, or fail if no value is reported. 270 * 271 * @return the supported hardware level as a constant defined for 272 * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}. 273 */ getHardwareLevelChecked()274 public int getHardwareLevelChecked() { 275 Integer hwLevel = getValueFromKeyNonNull( 276 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 277 if (hwLevel == null) { 278 Assert.fail("No supported hardware level reported."); 279 } 280 return hwLevel; 281 } 282 283 /** 284 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 285 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}. 286 * 287 * <p>If the camera device is not reporting the hardwareLevel, this 288 * will cause the test to fail.</p> 289 * 290 * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise. 291 */ isHardwareLevelLegacy()292 public boolean isHardwareLevelLegacy() { 293 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 294 } 295 296 /** 297 * Whether or not the per frame control is supported by the camera device. 298 * 299 * @return {@code true} if per frame control is supported, {@code false} otherwise. 300 */ isPerFrameControlSupported()301 public boolean isPerFrameControlSupported() { 302 return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL; 303 } 304 305 /** 306 * Get the maximum number of frames to wait for a request settings being applied 307 * 308 * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency 309 * CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control 310 * a positive int otherwise 311 */ getSyncMaxLatency()312 public int getSyncMaxLatency() { 313 Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY); 314 if (value == null) { 315 return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN; 316 } 317 return value; 318 } 319 320 /** 321 * Get the color filter arrangement for this camera device. 322 * 323 * @return Color Filter arrangement of this camera device 324 */ getCFAChecked()325 public int getCFAChecked() { 326 Integer cfa = getValueFromKeyNonNull( 327 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 328 if (cfa == null) { 329 Assert.fail("No color filter array (CFA) reported."); 330 } 331 return cfa; 332 } 333 isNIRColorFilter()334 public boolean isNIRColorFilter() { 335 Integer cfa = mCharacteristics.get( 336 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 337 if (cfa == null) { 338 return false; 339 } 340 return cfa == CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR; 341 } 342 343 /** 344 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 345 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 346 * 347 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 348 * will always return {@code true}.</p> 349 * 350 * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise. 351 */ isHardwareLevelLimited()352 public boolean isHardwareLevelLimited() { 353 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 354 } 355 356 /** 357 * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel} 358 * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 359 * 360 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 361 * will always return {@code false}.</p> 362 * 363 * @return 364 * {@code true} if the device is {@code LIMITED} or {@code FULL}, 365 * {@code false} otherwise (i.e. LEGACY). 366 */ isHardwareLevelAtLeastLimited()367 public boolean isHardwareLevelAtLeastLimited() { 368 return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED); 369 } 370 371 /** 372 * Get the maximum number of partial result a request can expect 373 * 374 * @return 1 if partial result is not supported. 375 * a integer value larger than 1 if partial result is supported. 376 */ getPartialResultCount()377 public int getPartialResultCount() { 378 Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT); 379 if (value == null) { 380 // Optional key. Default value is 1 if key is missing. 381 return 1; 382 } 383 return value; 384 } 385 386 /** 387 * Get the exposure time value and clamp to the range if needed. 388 * 389 * @param exposure Input exposure time value to check. 390 * @return Exposure value in the legal range. 391 */ getExposureClampToRange(long exposure)392 public long getExposureClampToRange(long exposure) { 393 long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE); 394 long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE); 395 if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) { 396 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 397 String.format( 398 "Min value %d is too large, set to maximal legal value %d", 399 minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST)); 400 minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST; 401 } 402 if (isHardwareLevelAtLeastFull() && 403 maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) { 404 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 405 String.format( 406 "Max value %d is too small, set to minimal legal value %d", 407 maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST)); 408 maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST; 409 } 410 411 return Math.max(minExposure, Math.min(maxExposure, exposure)); 412 } 413 414 /** 415 * Check if the camera device support focuser. 416 * 417 * @return true if camera device support focuser, false otherwise. 418 */ hasFocuser()419 public boolean hasFocuser() { 420 if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) { 421 // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query 422 return (getMinimumFocusDistanceChecked() > 0); 423 } else { 424 // Check available AF modes 425 int[] availableAfModes = mCharacteristics.get( 426 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); 427 428 if (availableAfModes == null) { 429 return false; 430 } 431 432 // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser 433 boolean hasFocuser = false; 434 loop: for (int mode : availableAfModes) { 435 switch (mode) { 436 case CameraMetadata.CONTROL_AF_MODE_AUTO: 437 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 438 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 439 case CameraMetadata.CONTROL_AF_MODE_MACRO: 440 hasFocuser = true; 441 break loop; 442 } 443 } 444 445 return hasFocuser; 446 } 447 } 448 449 /** 450 * Check if the camera device has flash unit. 451 * @return true if flash unit is available, false otherwise. 452 */ hasFlash()453 public boolean hasFlash() { 454 return getFlashInfoChecked(); 455 } 456 457 /** 458 * Get minimum focus distance. 459 * 460 * @return minimum focus distance, 0 if minimum focus distance is invalid. 461 */ getMinimumFocusDistanceChecked()462 public float getMinimumFocusDistanceChecked() { 463 Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE; 464 Float minFocusDistance; 465 466 /** 467 * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable 468 * devices; optional for all other devices. 469 */ 470 if (isHardwareLevelAtLeastFull() || isCapabilitySupported( 471 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 472 minFocusDistance = getValueFromKeyNonNull(key); 473 } else { 474 minFocusDistance = mCharacteristics.get(key); 475 } 476 477 if (minFocusDistance == null) { 478 return 0.0f; 479 } 480 481 checkTrueForKey(key, " minFocusDistance value shouldn't be negative", 482 minFocusDistance >= 0); 483 if (minFocusDistance < 0) { 484 minFocusDistance = 0.0f; 485 } 486 487 return minFocusDistance; 488 } 489 490 /** 491 * Get focusDistanceCalibration. 492 * 493 * @return focusDistanceCalibration, UNCALIBRATED if value is invalid. 494 */ getFocusDistanceCalibrationChecked()495 public int getFocusDistanceCalibrationChecked() { 496 Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION; 497 Integer calibration = getValueFromKeyNonNull(key); 498 499 if (calibration == null) { 500 return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED; 501 } 502 503 checkTrueForKey(key, " value is out of range" , 504 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED && 505 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED); 506 507 return calibration; 508 } 509 getAeModeName(int aeMode)510 public static String getAeModeName(int aeMode) { 511 return (aeMode >= AE_MODE_NAMES.length) ? String.format("VENDOR_AE_MODE_%d", aeMode) : 512 AE_MODE_NAMES[aeMode]; 513 } 514 getAfModeName(int afMode)515 public static String getAfModeName(int afMode) { 516 return (afMode >= AF_MODE_NAMES.length) ? String.format("VENDOR_AF_MODE_%d", afMode) : 517 AF_MODE_NAMES[afMode]; 518 } 519 520 /** 521 * Get max AE regions and do validity check. 522 * 523 * @return AE max regions supported by the camera device 524 */ getAeMaxRegionsChecked()525 public int getAeMaxRegionsChecked() { 526 Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 527 if (regionCount == null) { 528 return 0; 529 } 530 return regionCount; 531 } 532 533 /** 534 * Get max AWB regions and do validity check. 535 * 536 * @return AWB max regions supported by the camera device 537 */ getAwbMaxRegionsChecked()538 public int getAwbMaxRegionsChecked() { 539 Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 540 if (regionCount == null) { 541 return 0; 542 } 543 return regionCount; 544 } 545 546 /** 547 * Get max AF regions and do validity check. 548 * 549 * @return AF max regions supported by the camera device 550 */ getAfMaxRegionsChecked()551 public int getAfMaxRegionsChecked() { 552 Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 553 if (regionCount == null) { 554 return 0; 555 } 556 return regionCount; 557 } 558 /** 559 * Get the available anti-banding modes. 560 * 561 * @return The array contains available anti-banding modes. 562 */ getAeAvailableAntiBandingModesChecked()563 public int[] getAeAvailableAntiBandingModesChecked() { 564 Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; 565 int[] modes = getValueFromKeyNonNull(key); 566 567 boolean foundAuto = false; 568 boolean found50Hz = false; 569 boolean found60Hz = false; 570 for (int mode : modes) { 571 checkTrueForKey(key, "mode value " + mode + " is out if range", 572 mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF || 573 mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO); 574 if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) { 575 foundAuto = true; 576 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ) { 577 found50Hz = true; 578 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ) { 579 found60Hz = true; 580 } 581 } 582 // Must contain AUTO mode or one of 50/60Hz mode. 583 checkTrueForKey(key, "Either AUTO mode or both 50HZ/60HZ mode should present", 584 foundAuto || (found50Hz && found60Hz)); 585 586 return modes; 587 } 588 589 /** 590 * Check if the antibanding OFF mode is supported. 591 * 592 * @return true if antibanding OFF mode is supported, false otherwise. 593 */ isAntiBandingOffModeSupported()594 public boolean isAntiBandingOffModeSupported() { 595 List<Integer> antiBandingModes = 596 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked())); 597 598 return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF); 599 } 600 getFlashInfoChecked()601 public Boolean getFlashInfoChecked() { 602 Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE; 603 Boolean hasFlash = getValueFromKeyNonNull(key); 604 605 // In case the failOnKey only gives warning. 606 if (hasFlash == null) { 607 return false; 608 } 609 610 return hasFlash; 611 } 612 getAvailableTestPatternModesChecked()613 public int[] getAvailableTestPatternModesChecked() { 614 Key<int[]> key = 615 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES; 616 int[] modes = getValueFromKeyNonNull(key); 617 618 if (modes == null) { 619 return new int[0]; 620 } 621 622 int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF; 623 Integer[] boxedModes = CameraTestUtils.toObject(modes); 624 checkTrueForKey(key, " value must contain OFF mode", 625 Arrays.asList(boxedModes).contains(expectValue)); 626 627 return modes; 628 } 629 630 /** 631 * Get available thumbnail sizes and do the validity check. 632 * 633 * @return The array of available thumbnail sizes 634 */ getAvailableThumbnailSizesChecked()635 public Size[] getAvailableThumbnailSizesChecked() { 636 Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES; 637 Size[] sizes = getValueFromKeyNonNull(key); 638 final List<Size> sizeList = Arrays.asList(sizes); 639 640 // Size must contain (0, 0). 641 checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0))); 642 643 // Each size must be distinct. 644 checkElementDistinct(key, sizeList); 645 646 // Must be sorted in ascending order by area, by width if areas are same. 647 List<Size> orderedSizes = 648 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true); 649 checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString() 650 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList)); 651 652 // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations 653 // implementation see b/12958122. 654 655 return sizes; 656 } 657 658 /** 659 * Get available focal lengths and do the validity check. 660 * 661 * @return The array of available focal lengths 662 */ getAvailableFocalLengthsChecked()663 public float[] getAvailableFocalLengthsChecked() { 664 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS; 665 float[] focalLengths = getValueFromKeyNonNull(key); 666 667 checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1); 668 669 for (int i = 0; i < focalLengths.length; i++) { 670 checkTrueForKey(key, 671 String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]), 672 focalLengths[i] > 0); 673 } 674 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths))); 675 676 return focalLengths; 677 } 678 679 /** 680 * Get available apertures and do the validity check. 681 * 682 * @return The non-null array of available apertures 683 */ getAvailableAperturesChecked()684 public float[] getAvailableAperturesChecked() { 685 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES; 686 float[] apertures = getValueFromKeyNonNull(key); 687 688 checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1); 689 690 for (int i = 0; i < apertures.length; i++) { 691 checkTrueForKey(key, 692 String.format("apertures[%d] %f should be positive.", i, apertures[i]), 693 apertures[i] > 0); 694 } 695 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures))); 696 697 return apertures; 698 } 699 700 /** 701 * Get and check the available hot pixel map modes. 702 * 703 * @return the available hot pixel map modes 704 */ getAvailableHotPixelModesChecked()705 public int[] getAvailableHotPixelModesChecked() { 706 Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; 707 int[] modes = getValueFromKeyNonNull(key); 708 709 if (modes == null) { 710 return new int[0]; 711 } 712 713 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 714 if (isHardwareLevelAtLeastFull()) { 715 checkTrueForKey(key, "Full-capability camera devices must support FAST mode", 716 modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST)); 717 } 718 719 if (isHardwareLevelAtLeastLimited()) { 720 // FAST and HIGH_QUALITY mode must be both present or both not present 721 List<Integer> coupledModes = Arrays.asList(new Integer[] { 722 CameraMetadata.HOT_PIXEL_MODE_FAST, 723 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY 724 }); 725 checkTrueForKey( 726 key, " FAST and HIGH_QUALITY mode must both present or both not present", 727 containsAllOrNone(modeList, coupledModes)); 728 } 729 checkElementDistinct(key, modeList); 730 checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF, 731 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY); 732 733 return modes; 734 } 735 736 /** 737 * Get and check available face detection modes. 738 * 739 * @return The non-null array of available face detection modes 740 */ getAvailableFaceDetectModesChecked()741 public int[] getAvailableFaceDetectModesChecked() { 742 Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; 743 int[] modes = getValueFromKeyNonNull(key); 744 745 if (modes == null) { 746 return new int[0]; 747 } 748 749 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 750 checkTrueForKey(key, "Array should contain OFF mode", 751 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF)); 752 checkElementDistinct(key, modeList); 753 checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF, 754 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL); 755 756 return modes; 757 } 758 759 /** 760 * Get and check max face detected count. 761 * 762 * @return max number of faces that can be detected 763 */ getMaxFaceCountChecked()764 public int getMaxFaceCountChecked() { 765 Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT; 766 Integer count = getValueFromKeyNonNull(key); 767 768 if (count == null) { 769 return 0; 770 } 771 772 List<Integer> faceDetectModes = 773 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked())); 774 if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) && 775 faceDetectModes.size() == 1) { 776 checkTrueForKey(key, " value must be 0 if only OFF mode is supported in " 777 + "availableFaceDetectionModes", count == 0); 778 } else { 779 int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST; 780 781 // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces. 782 if (isHardwareLevelLegacy()) { 783 maxFaceCountAtLeast = 1; 784 } 785 checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE" 786 + "or FULL is also supported in availableFaceDetectionModes", 787 count >= maxFaceCountAtLeast); 788 } 789 790 return count; 791 } 792 793 /** 794 * Get and check the available tone map modes. 795 * 796 * @return the available tone map modes 797 */ getAvailableToneMapModesChecked()798 public int[] getAvailableToneMapModesChecked() { 799 Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES; 800 int[] modes = mCharacteristics.get(key); 801 802 if (modes == null) { 803 return new int[0]; 804 } 805 806 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 807 checkTrueForKey(key, " Camera devices must always support FAST mode", 808 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST)); 809 // Qualification check for MANUAL_POSTPROCESSING capability is in 810 // StaticMetadataTest#testCapabilities 811 812 if (isHardwareLevelAtLeastLimited()) { 813 // FAST and HIGH_QUALITY mode must be both present or both not present 814 List<Integer> coupledModes = Arrays.asList(new Integer[] { 815 CameraMetadata.TONEMAP_MODE_FAST, 816 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY 817 }); 818 checkTrueForKey( 819 key, " FAST and HIGH_QUALITY mode must both present or both not present", 820 containsAllOrNone(modeList, coupledModes)); 821 } 822 checkElementDistinct(key, modeList); 823 checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE, 824 CameraMetadata.TONEMAP_MODE_PRESET_CURVE); 825 826 return modes; 827 } 828 829 /** 830 * Get and check max tonemap curve point. 831 * 832 * @return Max tonemap curve points. 833 */ getMaxTonemapCurvePointChecked()834 public int getMaxTonemapCurvePointChecked() { 835 Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS; 836 Integer count = getValueFromKeyNonNull(key); 837 List<Integer> modeList = 838 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked())); 839 boolean tonemapCurveOutputSupported = 840 modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) || 841 modeList.contains(CameraMetadata.TONEMAP_MODE_GAMMA_VALUE) || 842 modeList.contains(CameraMetadata.TONEMAP_MODE_PRESET_CURVE); 843 844 if (count == null) { 845 if (tonemapCurveOutputSupported) { 846 Assert.fail("Tonemap curve output is supported but MAX_CURVE_POINTS is null"); 847 } 848 return 0; 849 } 850 851 if (tonemapCurveOutputSupported) { 852 checkTrueForKey(key, "Tonemap curve output supported camera device must support " 853 + "maxCurvePoints >= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST, 854 count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST); 855 } 856 857 return count; 858 } 859 860 /** 861 * Get and check pixel array size. 862 */ getPixelArraySizeChecked()863 public Size getPixelArraySizeChecked() { 864 Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE; 865 Size pixelArray = getValueFromKeyNonNull(key); 866 if (pixelArray == null) { 867 return new Size(0, 0); 868 } 869 870 return pixelArray; 871 } 872 873 /** 874 * Get and check pre-correction active array size. 875 */ getPreCorrectedActiveArraySizeChecked()876 public Rect getPreCorrectedActiveArraySizeChecked() { 877 Key<Rect> key = CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE; 878 Rect activeArray = getValueFromKeyNonNull(key); 879 880 if (activeArray == null) { 881 return new Rect(0, 0, 0, 0); 882 } 883 884 Size pixelArraySize = getPixelArraySizeChecked(); 885 checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0); 886 checkTrueForKey(key, "values width/height are invalid", 887 activeArray.width() <= pixelArraySize.getWidth() && 888 activeArray.height() <= pixelArraySize.getHeight()); 889 890 return activeArray; 891 } 892 893 /** 894 * Get and check active array size. 895 */ getActiveArraySizeChecked()896 public Rect getActiveArraySizeChecked() { 897 Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE; 898 Rect activeArray = getValueFromKeyNonNull(key); 899 900 if (activeArray == null) { 901 return new Rect(0, 0, 0, 0); 902 } 903 904 Size pixelArraySize = getPixelArraySizeChecked(); 905 checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0); 906 checkTrueForKey(key, "values width/height are invalid", 907 activeArray.width() <= pixelArraySize.getWidth() && 908 activeArray.height() <= pixelArraySize.getHeight()); 909 910 return activeArray; 911 } 912 913 /** 914 * Get the dimensions to use for RAW16 buffers. 915 */ getRawDimensChecked()916 public Size getRawDimensChecked() throws Exception { 917 Size[] targetCaptureSizes = getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 918 StaticMetadata.StreamDirection.Output); 919 Assert.assertTrue("No capture sizes available for RAW format!", 920 targetCaptureSizes.length != 0); 921 Rect activeArray = getPreCorrectedActiveArraySizeChecked(); 922 Size preCorrectionActiveArraySize = 923 new Size(activeArray.width(), activeArray.height()); 924 Size pixelArraySize = getPixelArraySizeChecked(); 925 Assert.assertTrue("Missing pre-correction active array size", activeArray.width() > 0 && 926 activeArray.height() > 0); 927 Assert.assertTrue("Missing pixel array size", pixelArraySize.getWidth() > 0 && 928 pixelArraySize.getHeight() > 0); 929 Size[] allowedArraySizes = new Size[] { preCorrectionActiveArraySize, 930 pixelArraySize }; 931 return assertArrayContainsAnyOf("Available sizes for RAW format" + 932 " must include either the pre-corrected active array size, or the full " + 933 "pixel array size", targetCaptureSizes, allowedArraySizes); 934 } 935 936 /** 937 * Get the sensitivity value and clamp to the range if needed. 938 * 939 * @param sensitivity Input sensitivity value to check. 940 * @return Sensitivity value in legal range. 941 */ getSensitivityClampToRange(int sensitivity)942 public int getSensitivityClampToRange(int sensitivity) { 943 int minSensitivity = getSensitivityMinimumOrDefault(); 944 int maxSensitivity = getSensitivityMaximumOrDefault(); 945 if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) { 946 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 947 String.format( 948 "Min value %d is too large, set to maximal legal value %d", 949 minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST)); 950 minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST; 951 } 952 if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) { 953 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 954 String.format( 955 "Max value %d is too small, set to minimal legal value %d", 956 maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST)); 957 maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST; 958 } 959 960 return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity)); 961 } 962 963 /** 964 * Get maxAnalogSensitivity for a camera device. 965 * <p> 966 * This is only available for FULL capability device, return 0 if it is unavailable. 967 * </p> 968 * 969 * @return maxAnalogSensitivity, 0 if it is not available. 970 */ getMaxAnalogSensitivityChecked()971 public int getMaxAnalogSensitivityChecked() { 972 973 Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY; 974 Integer maxAnalogsensitivity = mCharacteristics.get(key); 975 if (maxAnalogsensitivity == null) { 976 if (isHardwareLevelAtLeastFull()) { 977 Assert.fail("Full device should report max analog sensitivity"); 978 } 979 return 0; 980 } 981 982 int minSensitivity = getSensitivityMinimumOrDefault(); 983 int maxSensitivity = getSensitivityMaximumOrDefault(); 984 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity 985 + " should be no larger than max sensitivity " + maxSensitivity, 986 maxAnalogsensitivity <= maxSensitivity); 987 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity 988 + " should be larger than min sensitivity " + maxSensitivity, 989 maxAnalogsensitivity > minSensitivity); 990 991 return maxAnalogsensitivity; 992 } 993 994 /** 995 * Get hyperfocalDistance and do the validity check. 996 * <p> 997 * Note that, this tag is optional, will return -1 if this tag is not 998 * available. 999 * </p> 1000 * 1001 * @return hyperfocalDistance of this device, -1 if this tag is not available. 1002 */ getHyperfocalDistanceChecked()1003 public float getHyperfocalDistanceChecked() { 1004 Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE; 1005 Float hyperfocalDistance = getValueFromKeyNonNull(key); 1006 if (hyperfocalDistance == null) { 1007 return -1; 1008 } 1009 1010 if (hasFocuser()) { 1011 float minFocusDistance = getMinimumFocusDistanceChecked(); 1012 checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of" 1013 + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f, 1014 minFocusDistance), 1015 hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance); 1016 } 1017 1018 return hyperfocalDistance; 1019 } 1020 1021 /** 1022 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange. 1023 * 1024 * <p>If the camera is incorrectly reporting values, log a warning and return 1025 * the default value instead, which is the largest minimum value required to be supported 1026 * by all camera devices.</p> 1027 * 1028 * @return The value reported by the camera device or the defaultValue otherwise. 1029 */ getSensitivityMinimumOrDefault()1030 public int getSensitivityMinimumOrDefault() { 1031 return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST); 1032 } 1033 1034 /** 1035 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange. 1036 * 1037 * <p>If the camera is incorrectly reporting values, log a warning and return 1038 * the default value instead.</p> 1039 * 1040 * @param defaultValue Value to return if no legal value is available 1041 * @return The value reported by the camera device or the defaultValue otherwise. 1042 */ getSensitivityMinimumOrDefault(int defaultValue)1043 public int getSensitivityMinimumOrDefault(int defaultValue) { 1044 Range<Integer> range = mCharacteristics.get( 1045 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); 1046 if (range == null) { 1047 if (isHardwareLevelAtLeastFull()) { 1048 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 1049 "had no valid minimum value; using default of " + defaultValue); 1050 } 1051 return defaultValue; 1052 } 1053 return range.getLower(); 1054 } 1055 1056 /** 1057 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange. 1058 * 1059 * <p>If the camera is incorrectly reporting values, log a warning and return 1060 * the default value instead, which is the smallest maximum value required to be supported 1061 * by all camera devices.</p> 1062 * 1063 * @return The value reported by the camera device or the defaultValue otherwise. 1064 */ getSensitivityMaximumOrDefault()1065 public int getSensitivityMaximumOrDefault() { 1066 return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST); 1067 } 1068 1069 /** 1070 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange. 1071 * 1072 * <p>If the camera is incorrectly reporting values, log a warning and return 1073 * the default value instead.</p> 1074 * 1075 * @param defaultValue Value to return if no legal value is available 1076 * @return The value reported by the camera device or the defaultValue otherwise. 1077 */ getSensitivityMaximumOrDefault(int defaultValue)1078 public int getSensitivityMaximumOrDefault(int defaultValue) { 1079 Range<Integer> range = mCharacteristics.get( 1080 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); 1081 if (range == null) { 1082 if (isHardwareLevelAtLeastFull()) { 1083 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 1084 "had no valid maximum value; using default of " + defaultValue); 1085 } 1086 return defaultValue; 1087 } 1088 return range.getUpper(); 1089 } 1090 1091 /** 1092 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange. 1093 * 1094 * <p>If the camera is incorrectly reporting values, log a warning and return 1095 * the default value instead.</p> 1096 * 1097 * @param defaultValue Value to return if no legal value is available 1098 * @return The value reported by the camera device or the defaultValue otherwise. 1099 */ getExposureMinimumOrDefault(long defaultValue)1100 public long getExposureMinimumOrDefault(long defaultValue) { 1101 Range<Long> range = getValueFromKeyNonNull( 1102 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 1103 if (range == null) { 1104 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 1105 "had no valid minimum value; using default of " + defaultValue); 1106 return defaultValue; 1107 } 1108 return range.getLower(); 1109 } 1110 1111 /** 1112 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange. 1113 * 1114 * <p>If the camera is incorrectly reporting values, log a warning and return 1115 * the default value instead, which is the largest minimum value required to be supported 1116 * by all camera devices.</p> 1117 * 1118 * @return The value reported by the camera device or the defaultValue otherwise. 1119 */ getExposureMinimumOrDefault()1120 public long getExposureMinimumOrDefault() { 1121 return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST); 1122 } 1123 1124 /** 1125 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange. 1126 * 1127 * <p>If the camera is incorrectly reporting values, log a warning and return 1128 * the default value instead.</p> 1129 * 1130 * @param defaultValue Value to return if no legal value is available 1131 * @return The value reported by the camera device or the defaultValue otherwise. 1132 */ getExposureMaximumOrDefault(long defaultValue)1133 public long getExposureMaximumOrDefault(long defaultValue) { 1134 Range<Long> range = getValueFromKeyNonNull( 1135 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 1136 if (range == null) { 1137 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 1138 "had no valid maximum value; using default of " + defaultValue); 1139 return defaultValue; 1140 } 1141 return range.getUpper(); 1142 } 1143 1144 /** 1145 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange. 1146 * 1147 * <p>If the camera is incorrectly reporting values, log a warning and return 1148 * the default value instead, which is the smallest maximum value required to be supported 1149 * by all camera devices.</p> 1150 * 1151 * @return The value reported by the camera device or the defaultValue otherwise. 1152 */ getExposureMaximumOrDefault()1153 public long getExposureMaximumOrDefault() { 1154 return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST); 1155 } 1156 1157 /** 1158 * get android.control.availableModes and do the validity check. 1159 * 1160 * @return available control modes. 1161 */ getAvailableControlModesChecked()1162 public int[] getAvailableControlModesChecked() { 1163 Key<int[]> modesKey = CameraCharacteristics.CONTROL_AVAILABLE_MODES; 1164 int[] modes = getValueFromKeyNonNull(modesKey); 1165 if (modes == null) { 1166 modes = new int[0]; 1167 } 1168 1169 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1170 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty()); 1171 1172 // All camera device must support AUTO 1173 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain AUTO mode", 1174 modeList.contains(CameraMetadata.CONTROL_MODE_AUTO)); 1175 1176 boolean isAeOffSupported = Arrays.asList( 1177 CameraTestUtils.toObject(getAeAvailableModesChecked())).contains( 1178 CameraMetadata.CONTROL_AE_MODE_OFF); 1179 boolean isAfOffSupported = Arrays.asList( 1180 CameraTestUtils.toObject(getAfAvailableModesChecked())).contains( 1181 CameraMetadata.CONTROL_AF_MODE_OFF); 1182 boolean isAwbOffSupported = Arrays.asList( 1183 CameraTestUtils.toObject(getAwbAvailableModesChecked())).contains( 1184 CameraMetadata.CONTROL_AWB_MODE_OFF); 1185 if (isAeOffSupported && isAfOffSupported && isAwbOffSupported) { 1186 // 3A OFF controls are supported, OFF mode must be supported here. 1187 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain OFF mode", 1188 modeList.contains(CameraMetadata.CONTROL_MODE_OFF)); 1189 } 1190 1191 if (isSceneModeSupported()) { 1192 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain" 1193 + " USE_SCENE_MODE", 1194 modeList.contains(CameraMetadata.CONTROL_MODE_USE_SCENE_MODE)); 1195 } 1196 1197 return modes; 1198 } 1199 isSceneModeSupported()1200 public boolean isSceneModeSupported() { 1201 List<Integer> availableSceneModes = Arrays.asList( 1202 CameraTestUtils.toObject(getAvailableSceneModesChecked())); 1203 1204 if (availableSceneModes.isEmpty()) { 1205 return false; 1206 } 1207 1208 // If sceneMode is not supported, camera device will contain single entry: DISABLED. 1209 return availableSceneModes.size() > 1 || 1210 !availableSceneModes.contains(CameraMetadata.CONTROL_SCENE_MODE_DISABLED); 1211 } 1212 1213 /** 1214 * Get aeAvailableModes and do the validity check. 1215 * 1216 * <p>Depending on the check level this class has, for WAR or COLLECT levels, 1217 * If the aeMode list is invalid, return an empty mode array. The the caller doesn't 1218 * have to abort the execution even the aeMode list is invalid.</p> 1219 * @return AE available modes 1220 */ getAeAvailableModesChecked()1221 public int[] getAeAvailableModesChecked() { 1222 Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES; 1223 int[] modes = getValueFromKeyNonNull(modesKey); 1224 if (modes == null) { 1225 modes = new int[0]; 1226 } 1227 List<Integer> modeList = new ArrayList<Integer>(); 1228 for (int mode : modes) { 1229 // Skip vendor-added modes 1230 if (mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) { 1231 modeList.add(mode); 1232 } 1233 } 1234 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty()); 1235 modes = new int[modeList.size()]; 1236 for (int i = 0; i < modeList.size(); i++) { 1237 modes[i] = modeList.get(i); 1238 } 1239 1240 // All camera device must support ON 1241 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode", 1242 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON)); 1243 1244 // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH 1245 Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE; 1246 Boolean hasFlash = getValueFromKeyNonNull(flashKey); 1247 if (hasFlash == null) { 1248 hasFlash = false; 1249 } 1250 if (hasFlash) { 1251 boolean flashModeConsistentWithFlash = 1252 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) && 1253 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); 1254 checkTrueForKey(modesKey, 1255 "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and when flash is" + 1256 "available", flashModeConsistentWithFlash); 1257 } else { 1258 boolean flashModeConsistentWithoutFlash = 1259 !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) || 1260 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) || 1261 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)); 1262 checkTrueForKey(modesKey, 1263 "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" + 1264 "ON_AUTO_FLASH_REDEYE when flash is unavailable", 1265 flashModeConsistentWithoutFlash); 1266 } 1267 1268 // FULL mode camera devices always support OFF mode. 1269 boolean condition = 1270 !isHardwareLevelAtLeastFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF); 1271 checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition); 1272 1273 // Boundary check. 1274 for (int mode : modes) { 1275 checkTrueForKey(modesKey, "Value " + mode + " is out of bound", 1276 mode >= CameraMetadata.CONTROL_AE_MODE_OFF 1277 && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE); 1278 } 1279 1280 return modes; 1281 } 1282 1283 /** 1284 * Get available AWB modes and do the validity check. 1285 * 1286 * @return array that contains available AWB modes, empty array if awbAvailableModes is 1287 * unavailable. 1288 */ getAwbAvailableModesChecked()1289 public int[] getAwbAvailableModesChecked() { 1290 Key<int[]> key = 1291 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES; 1292 int[] awbModes = getValueFromKeyNonNull(key); 1293 1294 if (awbModes == null) { 1295 return new int[0]; 1296 } 1297 1298 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes)); 1299 checkTrueForKey(key, " All camera devices must support AUTO mode", 1300 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO)); 1301 if (isHardwareLevelAtLeastFull()) { 1302 checkTrueForKey(key, " Full capability camera devices must support OFF mode", 1303 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF)); 1304 } 1305 1306 return awbModes; 1307 } 1308 1309 /** 1310 * Get available AF modes and do the validity check. 1311 * 1312 * @return array that contains available AF modes, empty array if afAvailableModes is 1313 * unavailable. 1314 */ getAfAvailableModesChecked()1315 public int[] getAfAvailableModesChecked() { 1316 Key<int[]> key = 1317 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES; 1318 int[] afModes = getValueFromKeyNonNull(key); 1319 1320 if (afModes == null) { 1321 return new int[0]; 1322 } 1323 1324 List<Integer> modesList = new ArrayList<Integer>(); 1325 for (int afMode : afModes) { 1326 // Skip vendor-added AF modes 1327 if (afMode > CameraCharacteristics.CONTROL_AF_MODE_EDOF) continue; 1328 modesList.add(afMode); 1329 } 1330 afModes = new int[modesList.size()]; 1331 for (int i = 0; i < modesList.size(); i++) { 1332 afModes[i] = modesList.get(i); 1333 } 1334 1335 if (isHardwareLevelAtLeastLimited()) { 1336 // Some LEGACY mode devices do not support AF OFF 1337 checkTrueForKey(key, " All camera devices must support OFF mode", 1338 modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF)); 1339 } 1340 if (hasFocuser()) { 1341 checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode", 1342 modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO)); 1343 } 1344 1345 return afModes; 1346 } 1347 1348 /** 1349 * Get supported raw output sizes and do the check. 1350 * 1351 * @return Empty size array if raw output is not supported 1352 */ getRawOutputSizesChecked()1353 public Size[] getRawOutputSizesChecked() { 1354 return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 1355 StreamDirection.Output); 1356 } 1357 1358 /** 1359 * Get supported jpeg output sizes and do the check. 1360 * 1361 * @return Empty size array if jpeg output is not supported 1362 */ getJpegOutputSizesChecked()1363 public Size[] getJpegOutputSizesChecked() { 1364 return getAvailableSizesForFormatChecked(ImageFormat.JPEG, 1365 StreamDirection.Output); 1366 } 1367 1368 /** 1369 * Get supported heic output sizes and do the check. 1370 * 1371 * @return Empty size array if heic output is not supported 1372 */ getHeicOutputSizesChecked()1373 public Size[] getHeicOutputSizesChecked() { 1374 return getAvailableSizesForFormatChecked(ImageFormat.HEIC, 1375 StreamDirection.Output); 1376 } 1377 1378 /** 1379 * Used to determine the stream direction for various helpers that look up 1380 * format or size information. 1381 */ 1382 public enum StreamDirection { 1383 /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */ 1384 Output, 1385 /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */ 1386 Input 1387 } 1388 1389 /** 1390 * Get available formats for a given direction. 1391 * 1392 * @param direction The stream direction, input or output. 1393 * @return The formats of the given direction, empty array if no available format is found. 1394 */ getAvailableFormats(StreamDirection direction)1395 public int[] getAvailableFormats(StreamDirection direction) { 1396 Key<StreamConfigurationMap> key = 1397 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1398 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1399 1400 if (config == null) { 1401 return new int[0]; 1402 } 1403 1404 switch (direction) { 1405 case Output: 1406 return config.getOutputFormats(); 1407 case Input: 1408 return config.getInputFormats(); 1409 default: 1410 throw new IllegalArgumentException("direction must be output or input"); 1411 } 1412 } 1413 1414 /** 1415 * Get valid output formats for a given input format. 1416 * 1417 * @param inputFormat The input format used to produce the output images. 1418 * @return The output formats for the given input format, empty array if 1419 * no available format is found. 1420 */ getValidOutputFormatsForInput(int inputFormat)1421 public int[] getValidOutputFormatsForInput(int inputFormat) { 1422 Key<StreamConfigurationMap> key = 1423 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1424 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1425 1426 if (config == null) { 1427 return new int[0]; 1428 } 1429 1430 return config.getValidOutputFormatsForInput(inputFormat); 1431 } 1432 1433 /** 1434 * Get available sizes for given format and direction. 1435 * 1436 * @param format The format for the requested size array. 1437 * @param direction The stream direction, input or output. 1438 * @return The sizes of the given format, empty array if no available size is found. 1439 */ getAvailableSizesForFormatChecked(int format, StreamDirection direction)1440 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) { 1441 return getAvailableSizesForFormatChecked(format, direction, 1442 /*fastSizes*/true, /*slowSizes*/true); 1443 } 1444 1445 /** 1446 * Get available sizes for given format and direction, and whether to limit to slow or fast 1447 * resolutions. 1448 * 1449 * @param format The format for the requested size array. 1450 * @param direction The stream direction, input or output. 1451 * @param fastSizes whether to include getOutputSizes() sizes (generally faster) 1452 * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower) 1453 * @return The sizes of the given format, empty array if no available size is found. 1454 */ getAvailableSizesForFormatChecked(int format, StreamDirection direction, boolean fastSizes, boolean slowSizes)1455 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction, 1456 boolean fastSizes, boolean slowSizes) { 1457 Key<StreamConfigurationMap> key = 1458 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1459 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1460 1461 if (config == null) { 1462 return new Size[0]; 1463 } 1464 1465 Size[] sizes = null; 1466 1467 switch (direction) { 1468 case Output: 1469 Size[] fastSizeList = null; 1470 Size[] slowSizeList = null; 1471 if (fastSizes) { 1472 fastSizeList = config.getOutputSizes(format); 1473 } 1474 if (slowSizes) { 1475 slowSizeList = config.getHighResolutionOutputSizes(format); 1476 } 1477 if (fastSizeList != null && slowSizeList != null) { 1478 sizes = new Size[slowSizeList.length + fastSizeList.length]; 1479 System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length); 1480 System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length); 1481 } else if (fastSizeList != null) { 1482 sizes = fastSizeList; 1483 } else if (slowSizeList != null) { 1484 sizes = slowSizeList; 1485 } 1486 break; 1487 case Input: 1488 sizes = config.getInputSizes(format); 1489 break; 1490 default: 1491 throw new IllegalArgumentException("direction must be output or input"); 1492 } 1493 1494 if (sizes == null) { 1495 sizes = new Size[0]; 1496 } 1497 1498 return sizes; 1499 } 1500 1501 /** 1502 * Get available AE target fps ranges. 1503 * 1504 * @return Empty int array if aeAvailableTargetFpsRanges is invalid. 1505 */ 1506 @SuppressWarnings("raw") getAeAvailableTargetFpsRangesChecked()1507 public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() { 1508 Key<Range<Integer>[]> key = 1509 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; 1510 Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key); 1511 1512 if (fpsRanges == null) { 1513 return new Range[0]; 1514 } 1515 1516 // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound 1517 // in case the above check fails. 1518 int fpsRangeLength = fpsRanges.length; 1519 int minFps, maxFps; 1520 long maxFrameDuration = getMaxFrameDurationChecked(); 1521 for (int i = 0; i < fpsRangeLength; i += 1) { 1522 minFps = fpsRanges[i].getLower(); 1523 maxFps = fpsRanges[i].getUpper(); 1524 checkTrueForKey(key, " min fps must be no larger than max fps!", 1525 minFps > 0 && maxFps >= minFps); 1526 long maxDuration = (long) (1e9 / minFps); 1527 checkTrueForKey(key, String.format( 1528 " the frame duration %d for min fps %d must smaller than maxFrameDuration %d", 1529 maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration); 1530 } 1531 return fpsRanges; 1532 } 1533 1534 /** 1535 * Get the highest supported target FPS range. 1536 * Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS. 1537 */ getAeMaxTargetFpsRange()1538 public Range<Integer> getAeMaxTargetFpsRange() { 1539 Range<Integer>[] fpsRanges = getAeAvailableTargetFpsRangesChecked(); 1540 1541 Range<Integer> targetRange = fpsRanges[0]; 1542 // Assume unsorted list of target FPS ranges, so use two passes, first maximize min FPS 1543 for (Range<Integer> candidateRange : fpsRanges) { 1544 if (candidateRange.getLower() > targetRange.getLower()) { 1545 targetRange = candidateRange; 1546 } 1547 } 1548 // Then maximize max FPS while not lowering min FPS 1549 for (Range<Integer> candidateRange : fpsRanges) { 1550 if (candidateRange.getLower() >= targetRange.getLower() && 1551 candidateRange.getUpper() > targetRange.getUpper()) { 1552 targetRange = candidateRange; 1553 } 1554 } 1555 return targetRange; 1556 } 1557 1558 /** 1559 * Get max frame duration. 1560 * 1561 * @return 0 if maxFrameDuration is null 1562 */ getMaxFrameDurationChecked()1563 public long getMaxFrameDurationChecked() { 1564 Key<Long> key = 1565 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION; 1566 Long maxDuration = getValueFromKeyNonNull(key); 1567 1568 if (maxDuration == null) { 1569 return 0; 1570 } 1571 1572 return maxDuration; 1573 } 1574 1575 /** 1576 * Get available minimal frame durations for a given format. 1577 * 1578 * @param format One of the format from {@link ImageFormat}. 1579 * @return HashMap of minimal frame durations for different sizes, empty HashMap 1580 * if availableMinFrameDurations is null. 1581 */ getAvailableMinFrameDurationsForFormatChecked(int format)1582 public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) { 1583 1584 HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>(); 1585 1586 Key<StreamConfigurationMap> key = 1587 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1588 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1589 1590 if (config == null) { 1591 return minDurationMap; 1592 } 1593 1594 for (android.util.Size size : getAvailableSizesForFormatChecked(format, 1595 StreamDirection.Output)) { 1596 long minFrameDuration = config.getOutputMinFrameDuration(format, size); 1597 1598 if (minFrameDuration != 0) { 1599 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration); 1600 } 1601 } 1602 1603 return minDurationMap; 1604 } 1605 getAvailableEdgeModesChecked()1606 public int[] getAvailableEdgeModesChecked() { 1607 Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES; 1608 int[] edgeModes = getValueFromKeyNonNull(key); 1609 1610 if (edgeModes == null) { 1611 return new int[0]; 1612 } 1613 1614 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes)); 1615 // Full device should always include OFF and FAST 1616 if (isHardwareLevelAtLeastFull()) { 1617 checkTrueForKey(key, "Full device must contain OFF and FAST edge modes", 1618 modeList.contains(CameraMetadata.EDGE_MODE_OFF) && 1619 modeList.contains(CameraMetadata.EDGE_MODE_FAST)); 1620 } 1621 1622 if (isHardwareLevelAtLeastLimited()) { 1623 // FAST and HIGH_QUALITY mode must be both present or both not present 1624 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1625 CameraMetadata.EDGE_MODE_FAST, 1626 CameraMetadata.EDGE_MODE_HIGH_QUALITY 1627 }); 1628 checkTrueForKey( 1629 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1630 containsAllOrNone(modeList, coupledModes)); 1631 } 1632 1633 return edgeModes; 1634 } 1635 getAvailableShadingModesChecked()1636 public int[] getAvailableShadingModesChecked() { 1637 Key<int[]> key = CameraCharacteristics.SHADING_AVAILABLE_MODES; 1638 int[] shadingModes = getValueFromKeyNonNull(key); 1639 1640 if (shadingModes == null) { 1641 return new int[0]; 1642 } 1643 1644 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(shadingModes)); 1645 // Full device should always include OFF and FAST 1646 if (isHardwareLevelAtLeastFull()) { 1647 checkTrueForKey(key, "Full device must contain OFF and FAST shading modes", 1648 modeList.contains(CameraMetadata.SHADING_MODE_OFF) && 1649 modeList.contains(CameraMetadata.SHADING_MODE_FAST)); 1650 } 1651 1652 if (isHardwareLevelAtLeastLimited()) { 1653 // FAST and HIGH_QUALITY mode must be both present or both not present 1654 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1655 CameraMetadata.SHADING_MODE_FAST, 1656 CameraMetadata.SHADING_MODE_HIGH_QUALITY 1657 }); 1658 checkTrueForKey( 1659 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1660 containsAllOrNone(modeList, coupledModes)); 1661 } 1662 1663 return shadingModes; 1664 } 1665 getAvailableNoiseReductionModesChecked()1666 public int[] getAvailableNoiseReductionModesChecked() { 1667 Key<int[]> key = 1668 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; 1669 int[] noiseReductionModes = getValueFromKeyNonNull(key); 1670 1671 if (noiseReductionModes == null) { 1672 return new int[0]; 1673 } 1674 1675 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes)); 1676 // Full device should always include OFF and FAST 1677 if (isHardwareLevelAtLeastFull()) { 1678 1679 checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes", 1680 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) && 1681 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST)); 1682 } 1683 1684 if (isHardwareLevelAtLeastLimited()) { 1685 // FAST and HIGH_QUALITY mode must be both present or both not present 1686 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1687 CameraMetadata.NOISE_REDUCTION_MODE_FAST, 1688 CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY 1689 }); 1690 checkTrueForKey( 1691 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1692 containsAllOrNone(modeList, coupledModes)); 1693 } 1694 return noiseReductionModes; 1695 } 1696 1697 /** 1698 * Get value of key android.control.aeCompensationStep and do the validity check. 1699 * 1700 * @return default value if the value is null. 1701 */ getAeCompensationStepChecked()1702 public Rational getAeCompensationStepChecked() { 1703 Key<Rational> key = 1704 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP; 1705 Rational compensationStep = getValueFromKeyNonNull(key); 1706 1707 if (compensationStep == null) { 1708 // Return default step. 1709 return CONTROL_AE_COMPENSATION_STEP_DEFAULT; 1710 } 1711 1712 // Legacy devices don't have a minimum step requirement 1713 if (isHardwareLevelAtLeastLimited()) { 1714 float compensationStepF = 1715 (float) compensationStep.getNumerator() / compensationStep.getDenominator(); 1716 checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f); 1717 } 1718 1719 return compensationStep; 1720 } 1721 1722 /** 1723 * Get value of key android.control.aeCompensationRange and do the validity check. 1724 * 1725 * @return default value if the value is null or malformed. 1726 */ getAeCompensationRangeChecked()1727 public Range<Integer> getAeCompensationRangeChecked() { 1728 Key<Range<Integer>> key = 1729 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE; 1730 Range<Integer> compensationRange = getValueFromKeyNonNull(key); 1731 Rational compensationStep = getAeCompensationStepChecked(); 1732 float compensationStepF = compensationStep.floatValue(); 1733 final Range<Integer> DEFAULT_RANGE = Range.create( 1734 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF), 1735 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF)); 1736 final Range<Integer> ZERO_RANGE = Range.create(0, 0); 1737 if (compensationRange == null) { 1738 return ZERO_RANGE; 1739 } 1740 1741 // Legacy devices don't have a minimum range requirement 1742 if (isHardwareLevelAtLeastLimited() && !compensationRange.equals(ZERO_RANGE)) { 1743 checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE 1744 + ", actual " + compensationRange + ", compensation step " + compensationStep, 1745 compensationRange.getLower() <= DEFAULT_RANGE.getLower() && 1746 compensationRange.getUpper() >= DEFAULT_RANGE.getUpper()); 1747 } 1748 1749 return compensationRange; 1750 } 1751 1752 /** 1753 * Get availableVideoStabilizationModes and do the validity check. 1754 * 1755 * @return available video stabilization modes, empty array if it is unavailable. 1756 */ getAvailableVideoStabilizationModesChecked()1757 public int[] getAvailableVideoStabilizationModesChecked() { 1758 Key<int[]> key = 1759 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; 1760 int[] modes = getValueFromKeyNonNull(key); 1761 1762 if (modes == null) { 1763 return new int[0]; 1764 } 1765 1766 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1767 checkTrueForKey(key, " All device should support OFF mode", 1768 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF)); 1769 checkArrayValuesInRange(key, modes, 1770 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF, 1771 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); 1772 1773 return modes; 1774 } 1775 isVideoStabilizationSupported()1776 public boolean isVideoStabilizationSupported() { 1777 Integer[] videoStabModes = 1778 CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked()); 1779 return Arrays.asList(videoStabModes).contains( 1780 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); 1781 } 1782 1783 /** 1784 * Get availableOpticalStabilization and do the validity check. 1785 * 1786 * @return available optical stabilization modes, empty array if it is unavailable. 1787 */ getAvailableOpticalStabilizationChecked()1788 public int[] getAvailableOpticalStabilizationChecked() { 1789 Key<int[]> key = 1790 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; 1791 int[] modes = getValueFromKeyNonNull(key); 1792 1793 if (modes == null) { 1794 return new int[0]; 1795 } 1796 1797 checkArrayValuesInRange(key, modes, 1798 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF, 1799 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON); 1800 1801 return modes; 1802 } 1803 1804 /** 1805 * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array 1806 * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable 1807 */ getAvailableMaxDigitalZoomChecked()1808 public float getAvailableMaxDigitalZoomChecked() { 1809 Key<Float> key = 1810 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; 1811 1812 Float maxZoom = getValueFromKeyNonNull(key); 1813 if (maxZoom == null) { 1814 return 1.0f; 1815 } 1816 1817 checkTrueForKey(key, " max digital zoom should be no less than 1", 1818 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom)); 1819 1820 return maxZoom; 1821 } 1822 getZoomRatioRangeChecked()1823 public Range<Float> getZoomRatioRangeChecked() { 1824 Key<Range<Float>> key = 1825 CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE; 1826 1827 Range<Float> zoomRatioRange = getValueFromKeyNonNull(key); 1828 if (zoomRatioRange == null) { 1829 return new Range<Float>(1.0f, 1.0f); 1830 } 1831 1832 checkTrueForKey(key, String.format(" min zoom ratio %f should be no more than 1", 1833 zoomRatioRange.getLower()), zoomRatioRange.getLower() <= 1.0); 1834 checkTrueForKey(key, String.format(" max zoom ratio %f should be no less than 1", 1835 zoomRatioRange.getUpper()), zoomRatioRange.getUpper() >= 1.0); 1836 final float ZOOM_MIN_RANGE = 0.01f; 1837 checkTrueForKey(key, " zoom ratio range should be reasonably large", 1838 zoomRatioRange.getUpper().equals(zoomRatioRange.getLower()) || 1839 zoomRatioRange.getUpper() - zoomRatioRange.getLower() > ZOOM_MIN_RANGE); 1840 return zoomRatioRange; 1841 } 1842 getAvailableSceneModesChecked()1843 public int[] getAvailableSceneModesChecked() { 1844 Key<int[]> key = 1845 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES; 1846 int[] modes = getValueFromKeyNonNull(key); 1847 1848 if (modes == null) { 1849 return new int[0]; 1850 } 1851 1852 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1853 // FACE_PRIORITY must be included if face detection is supported. 1854 if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) && 1855 getMaxFaceCountChecked() > 0) { 1856 checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported", 1857 modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY)); 1858 } 1859 1860 return modes; 1861 } 1862 getAvailableEffectModesChecked()1863 public int[] getAvailableEffectModesChecked() { 1864 Key<int[]> key = 1865 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS; 1866 int[] modes = getValueFromKeyNonNull(key); 1867 1868 if (modes == null) { 1869 return new int[0]; 1870 } 1871 1872 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1873 // OFF must be included. 1874 checkTrueForKey(key, " OFF must be included", 1875 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF)); 1876 1877 return modes; 1878 } 1879 getAvailableExtendedSceneModeCapsChecked()1880 public Capability[] getAvailableExtendedSceneModeCapsChecked() { 1881 final Size FULL_HD = new Size(1920, 1080); 1882 Rect activeRect = getValueFromKeyNonNull( 1883 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 1884 Key<Capability[]> key = 1885 CameraCharacteristics.CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_CAPABILITIES; 1886 Capability[] caps = mCharacteristics.get(key); 1887 if (caps == null) { 1888 return new Capability[0]; 1889 } 1890 1891 Size[] yuvSizes = getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888, 1892 StaticMetadata.StreamDirection.Output); 1893 List<Size> yuvSizesList = Arrays.asList(yuvSizes); 1894 for (Capability cap : caps) { 1895 int extendedSceneMode = cap.getMode(); 1896 Size maxStreamingSize = cap.getMaxStreamingSize(); 1897 boolean maxStreamingSizeIsZero = 1898 maxStreamingSize.getWidth() == 0 && maxStreamingSize.getHeight() == 0; 1899 switch (extendedSceneMode) { 1900 case CameraMetadata.CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE: 1901 // STILL_CAPTURE: Must either be (0, 0), or one of supported yuv/private sizes. 1902 // Because spec requires yuv and private sizes match, only check YUV sizes here. 1903 checkTrueForKey(key, 1904 String.format(" maxStreamingSize [%d, %d] for extended scene mode " + 1905 "%d must be a supported YCBCR_420_888 size, or (0, 0)", 1906 maxStreamingSize.getWidth(), maxStreamingSize.getHeight(), 1907 extendedSceneMode), 1908 yuvSizesList.contains(maxStreamingSize) || maxStreamingSizeIsZero); 1909 break; 1910 case CameraMetadata.CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS: 1911 // CONTINUOUS: Must be one of supported yuv/private stream sizes. 1912 checkTrueForKey(key, 1913 String.format(" maxStreamingSize [%d, %d] for extended scene mode " + 1914 "%d must be a supported YCBCR_420_888 size.", 1915 maxStreamingSize.getWidth(), maxStreamingSize.getHeight(), 1916 extendedSceneMode), yuvSizesList.contains(maxStreamingSize)); 1917 // Must be at least 1080p if sensor is at least 1080p. 1918 if (activeRect.width() >= FULL_HD.getWidth() && 1919 activeRect.height() >= FULL_HD.getHeight()) { 1920 checkTrueForKey(key, 1921 String.format(" maxStreamingSize [%d, %d] for extended scene " + 1922 "mode %d must be at least 1080p", maxStreamingSize.getWidth(), 1923 maxStreamingSize.getHeight(), extendedSceneMode), 1924 maxStreamingSize.getWidth() >= FULL_HD.getWidth() && 1925 maxStreamingSize.getHeight() >= FULL_HD.getHeight()); 1926 } 1927 break; 1928 default: 1929 break; 1930 } 1931 } 1932 1933 return caps; 1934 } 1935 1936 /** 1937 * Get and check the available color aberration modes 1938 * 1939 * @return the available color aberration modes 1940 */ getAvailableColorAberrationModesChecked()1941 public int[] getAvailableColorAberrationModesChecked() { 1942 Key<int[]> key = 1943 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; 1944 int[] modes = getValueFromKeyNonNull(key); 1945 1946 if (modes == null) { 1947 return new int[0]; 1948 } 1949 1950 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1951 checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode", 1952 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) || 1953 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST)); 1954 1955 if (isHardwareLevelAtLeastLimited()) { 1956 // FAST and HIGH_QUALITY mode must be both present or both not present 1957 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1958 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST, 1959 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY 1960 }); 1961 checkTrueForKey( 1962 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1963 containsAllOrNone(modeList, coupledModes)); 1964 } 1965 checkElementDistinct(key, modeList); 1966 checkArrayValuesInRange(key, modes, 1967 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF, 1968 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); 1969 1970 return modes; 1971 } 1972 1973 /** 1974 * Get max pipeline depth and do the validity check. 1975 * 1976 * @return max pipeline depth, default value if it is not available. 1977 */ getPipelineMaxDepthChecked()1978 public byte getPipelineMaxDepthChecked() { 1979 Key<Byte> key = 1980 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH; 1981 Byte maxDepth = getValueFromKeyNonNull(key); 1982 1983 if (maxDepth == null) { 1984 return REQUEST_PIPELINE_MAX_DEPTH_MAX; 1985 } 1986 1987 checkTrueForKey(key, " max pipeline depth should be no larger than " 1988 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX); 1989 1990 return maxDepth; 1991 } 1992 1993 /** 1994 * Get available lens shading modes. 1995 */ getAvailableLensShadingModesChecked()1996 public int[] getAvailableLensShadingModesChecked() { 1997 Key<int[]> key = 1998 CameraCharacteristics.SHADING_AVAILABLE_MODES; 1999 int[] modes = getValueFromKeyNonNull(key); 2000 if (modes == null) { 2001 return new int[0]; 2002 } 2003 2004 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 2005 // FAST must be included. 2006 checkTrueForKey(key, " FAST must be included", 2007 modeList.contains(CameraMetadata.SHADING_MODE_FAST)); 2008 2009 if (isCapabilitySupported( 2010 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) { 2011 checkTrueForKey(key, " OFF must be included for MANUAL_POST_PROCESSING devices", 2012 modeList.contains(CameraMetadata.SHADING_MODE_OFF)); 2013 } 2014 return modes; 2015 } 2016 2017 /** 2018 * Get available lens shading map modes. 2019 */ getAvailableLensShadingMapModesChecked()2020 public int[] getAvailableLensShadingMapModesChecked() { 2021 Key<int[]> key = 2022 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES; 2023 int[] modes = getValueFromKeyNonNull(key); 2024 if (modes == null) { 2025 return new int[0]; 2026 } 2027 2028 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 2029 2030 if (isCapabilitySupported( 2031 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2032 checkTrueForKey(key, " ON must be included for RAW capability devices", 2033 modeList.contains(CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON)); 2034 } 2035 return modes; 2036 } 2037 2038 2039 /** 2040 * Get available capabilities and do the validity check. 2041 * 2042 * @return reported available capabilities list, empty list if the value is unavailable. 2043 */ getAvailableCapabilitiesChecked()2044 public List<Integer> getAvailableCapabilitiesChecked() { 2045 Key<int[]> key = 2046 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES; 2047 int[] availableCaps = getValueFromKeyNonNull(key); 2048 List<Integer> capList; 2049 2050 if (availableCaps == null) { 2051 return new ArrayList<Integer>(); 2052 } 2053 2054 checkArrayValuesInRange(key, availableCaps, 2055 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, 2056 LAST_CAPABILITY_ENUM); 2057 capList = Arrays.asList(CameraTestUtils.toObject(availableCaps)); 2058 return capList; 2059 } 2060 2061 /** 2062 * Determine whether the current device supports a capability or not. 2063 * 2064 * @param capability (non-negative) 2065 * 2066 * @return {@code true} if the capability is supported, {@code false} otherwise. 2067 * 2068 * @throws IllegalArgumentException if {@code capability} was negative 2069 * 2070 * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 2071 */ isCapabilitySupported(int capability)2072 public boolean isCapabilitySupported(int capability) { 2073 if (capability < 0) { 2074 throw new IllegalArgumentException("capability must be non-negative"); 2075 } 2076 2077 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 2078 2079 return availableCapabilities.contains(capability); 2080 } 2081 2082 /** 2083 * Determine whether the current device supports a private reprocessing capability or not. 2084 * 2085 * @return {@code true} if the capability is supported, {@code false} otherwise. 2086 * 2087 * @throws IllegalArgumentException if {@code capability} was negative 2088 */ isPrivateReprocessingSupported()2089 public boolean isPrivateReprocessingSupported() { 2090 return isCapabilitySupported( 2091 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2092 } 2093 2094 /** 2095 * Get sorted (descending order) size list for given input format. Remove the sizes larger than 2096 * the bound. If the bound is null, don't do the size bound filtering. 2097 * 2098 * @param format input format 2099 * @param bound maximum allowed size bound 2100 * 2101 * @return Sorted input size list (descending order) 2102 */ getSortedSizesForInputFormat(int format, Size bound)2103 public List<Size> getSortedSizesForInputFormat(int format, Size bound) { 2104 Size[] availableSizes = getAvailableSizesForFormatChecked(format, StreamDirection.Input); 2105 if (bound == null) { 2106 return CameraTestUtils.getAscendingOrderSizes(Arrays.asList(availableSizes), 2107 /*ascending*/false); 2108 } 2109 2110 List<Size> sizes = new ArrayList<Size>(); 2111 for (Size sz: availableSizes) { 2112 if (sz.getWidth() <= bound.getWidth() && sz.getHeight() <= bound.getHeight()) { 2113 sizes.add(sz); 2114 } 2115 } 2116 2117 return CameraTestUtils.getAscendingOrderSizes(sizes, /*ascending*/false); 2118 } 2119 2120 2121 /** 2122 * Determine whether or not all the {@code keys} are available characteristics keys 2123 * (as in {@link CameraCharacteristics#getKeys}. 2124 * 2125 * <p>If this returns {@code true}, then querying for this key from a characteristics 2126 * object will always return a non-{@code null} value.</p> 2127 * 2128 * @param keys collection of camera characteristics keys 2129 * @return whether or not all characteristics keys are available 2130 */ areCharacteristicsKeysAvailable( Collection<CameraCharacteristics.Key<?>> keys)2131 public final boolean areCharacteristicsKeysAvailable( 2132 Collection<CameraCharacteristics.Key<?>> keys) { 2133 return mCharacteristics.getKeys().containsAll(keys); 2134 } 2135 2136 /** 2137 * Determine whether or not all the {@code keys} are available result keys 2138 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 2139 * 2140 * <p>If this returns {@code true}, then querying for this key from a result 2141 * object will almost always return a non-{@code null} value.</p> 2142 * 2143 * <p>In some cases (e.g. lens shading map), the request must have additional settings 2144 * configured in order for the key to correspond to a value.</p> 2145 * 2146 * @param keys collection of capture result keys 2147 * @return whether or not all result keys are available 2148 */ areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys)2149 public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) { 2150 return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys); 2151 } 2152 2153 /** 2154 * Determine whether or not all the {@code keys} are available request keys 2155 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 2156 * 2157 * <p>If this returns {@code true}, then setting this key in the request builder 2158 * may have some effect (and if it's {@code false}, then the camera device will 2159 * definitely ignore it).</p> 2160 * 2161 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 2162 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 2163 * 2164 * @param keys collection of capture request keys 2165 * @return whether or not all result keys are available 2166 */ areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys)2167 public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) { 2168 return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys); 2169 } 2170 2171 /** 2172 * Determine whether or not all the {@code keys} are available characteristics keys 2173 * (as in {@link CameraCharacteristics#getKeys}. 2174 * 2175 * <p>If this returns {@code true}, then querying for this key from a characteristics 2176 * object will always return a non-{@code null} value.</p> 2177 * 2178 * @param keys one or more camera characteristic keys 2179 * @return whether or not all characteristics keys are available 2180 */ 2181 @SafeVarargs areKeysAvailable(CameraCharacteristics.Key<?>.... keys)2182 public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) { 2183 return areCharacteristicsKeysAvailable(Arrays.asList(keys)); 2184 } 2185 2186 /** 2187 * Determine whether or not all the {@code keys} are available result keys 2188 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 2189 * 2190 * <p>If this returns {@code true}, then querying for this key from a result 2191 * object will almost always return a non-{@code null} value.</p> 2192 * 2193 * <p>In some cases (e.g. lens shading map), the request must have additional settings 2194 * configured in order for the key to correspond to a value.</p> 2195 * 2196 * @param keys one or more capture result keys 2197 * @return whether or not all result keys are available 2198 */ 2199 @SafeVarargs areKeysAvailable(CaptureResult.Key<?>.... keys)2200 public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) { 2201 return areResultKeysAvailable(Arrays.asList(keys)); 2202 } 2203 2204 /** 2205 * Determine whether or not all the {@code keys} are available request keys 2206 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 2207 * 2208 * <p>If this returns {@code true}, then setting this key in the request builder 2209 * may have some effect (and if it's {@code false}, then the camera device will 2210 * definitely ignore it).</p> 2211 * 2212 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 2213 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 2214 * 2215 * @param keys one or more capture request keys 2216 * @return whether or not all result keys are available 2217 */ 2218 @SafeVarargs areKeysAvailable(CaptureRequest.Key<?>.... keys)2219 public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) { 2220 return areRequestKeysAvailable(Arrays.asList(keys)); 2221 } 2222 2223 /* 2224 * Determine if camera device support AE lock control 2225 * 2226 * @return {@code true} if AE lock control is supported 2227 */ isAeLockSupported()2228 public boolean isAeLockSupported() { 2229 return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 2230 } 2231 2232 /* 2233 * Determine if camera device support AWB lock control 2234 * 2235 * @return {@code true} if AWB lock control is supported 2236 */ isAwbLockSupported()2237 public boolean isAwbLockSupported() { 2238 return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 2239 } 2240 2241 2242 /* 2243 * Determine if camera device support manual lens shading map control 2244 * 2245 * @return {@code true} if manual lens shading map control is supported 2246 */ isManualLensShadingMapSupported()2247 public boolean isManualLensShadingMapSupported() { 2248 return areKeysAvailable(CaptureRequest.SHADING_MODE); 2249 } 2250 2251 /** 2252 * Determine if camera device support manual color correction control 2253 * 2254 * @return {@code true} if manual color correction control is supported 2255 */ isColorCorrectionSupported()2256 public boolean isColorCorrectionSupported() { 2257 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE); 2258 } 2259 2260 /** 2261 * Determine if camera device support manual tone mapping control 2262 * 2263 * @return {@code true} if manual tone mapping control is supported 2264 */ isManualToneMapSupported()2265 public boolean isManualToneMapSupported() { 2266 return areKeysAvailable(CaptureRequest.TONEMAP_MODE); 2267 } 2268 2269 /** 2270 * Determine if camera device support manual color aberration control 2271 * 2272 * @return {@code true} if manual color aberration control is supported 2273 */ isManualColorAberrationControlSupported()2274 public boolean isManualColorAberrationControlSupported() { 2275 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE); 2276 } 2277 2278 /** 2279 * Determine if camera device support edge mode control 2280 * 2281 * @return {@code true} if edge mode control is supported 2282 */ isEdgeModeControlSupported()2283 public boolean isEdgeModeControlSupported() { 2284 return areKeysAvailable(CaptureRequest.EDGE_MODE); 2285 } 2286 2287 /** 2288 * Determine if camera device support hot pixel mode control 2289 * 2290 * @return {@code true} if hot pixel mode control is supported 2291 */ isHotPixelMapModeControlSupported()2292 public boolean isHotPixelMapModeControlSupported() { 2293 return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE); 2294 } 2295 2296 /** 2297 * Determine if camera device support noise reduction mode control 2298 * 2299 * @return {@code true} if noise reduction mode control is supported 2300 */ isNoiseReductionModeControlSupported()2301 public boolean isNoiseReductionModeControlSupported() { 2302 return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE); 2303 } 2304 2305 /** 2306 * Get max number of output raw streams and do the basic validity check. 2307 * 2308 * @return reported max number of raw output stream 2309 */ getMaxNumOutputStreamsRawChecked()2310 public int getMaxNumOutputStreamsRawChecked() { 2311 Integer maxNumStreams = 2312 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW); 2313 if (maxNumStreams == null) 2314 return 0; 2315 return maxNumStreams; 2316 } 2317 2318 /** 2319 * Get max number of output processed streams and do the basic validity check. 2320 * 2321 * @return reported max number of processed output stream 2322 */ getMaxNumOutputStreamsProcessedChecked()2323 public int getMaxNumOutputStreamsProcessedChecked() { 2324 Integer maxNumStreams = 2325 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC); 2326 if (maxNumStreams == null) 2327 return 0; 2328 return maxNumStreams; 2329 } 2330 2331 /** 2332 * Get max number of output stalling processed streams and do the basic validity check. 2333 * 2334 * @return reported max number of stalling processed output stream 2335 */ getMaxNumOutputStreamsProcessedStallChecked()2336 public int getMaxNumOutputStreamsProcessedStallChecked() { 2337 Integer maxNumStreams = 2338 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING); 2339 if (maxNumStreams == null) 2340 return 0; 2341 return maxNumStreams; 2342 } 2343 2344 /** 2345 * Get lens facing and do the validity check 2346 * @return lens facing, return default value (BACK) if value is unavailable. 2347 */ getLensFacingChecked()2348 public int getLensFacingChecked() { 2349 Key<Integer> key = 2350 CameraCharacteristics.LENS_FACING; 2351 Integer facing = getValueFromKeyNonNull(key); 2352 2353 if (facing == null) { 2354 return CameraCharacteristics.LENS_FACING_BACK; 2355 } 2356 2357 checkTrueForKey(key, " value is out of range ", 2358 facing >= CameraCharacteristics.LENS_FACING_FRONT && 2359 facing <= CameraCharacteristics.LENS_FACING_EXTERNAL); 2360 return facing; 2361 } 2362 2363 /** 2364 * Get maxCaptureStall frames or default value (if value doesn't exist) 2365 * @return maxCaptureStall frames or default value. 2366 */ getMaxCaptureStallOrDefault()2367 public int getMaxCaptureStallOrDefault() { 2368 Key<Integer> key = 2369 CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL; 2370 Integer value = getValueFromKeyNonNull(key); 2371 2372 if (value == null) { 2373 return MAX_REPROCESS_MAX_CAPTURE_STALL; 2374 } 2375 2376 checkTrueForKey(key, " value is out of range ", 2377 value >= 0 && 2378 value <= MAX_REPROCESS_MAX_CAPTURE_STALL); 2379 2380 return value; 2381 } 2382 2383 /** 2384 * Get the scaler's cropping type (center only or freeform) 2385 * @return cropping type, return default value (CENTER_ONLY) if value is unavailable 2386 */ getScalerCroppingTypeChecked()2387 public int getScalerCroppingTypeChecked() { 2388 Key<Integer> key = 2389 CameraCharacteristics.SCALER_CROPPING_TYPE; 2390 Integer value = getValueFromKeyNonNull(key); 2391 2392 if (value == null) { 2393 return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY; 2394 } 2395 2396 checkTrueForKey(key, " value is out of range ", 2397 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY && 2398 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM); 2399 2400 return value; 2401 } 2402 2403 /** 2404 * Check if the constrained high speed video is supported by the camera device. 2405 * The high speed FPS ranges and sizes are sanitized in 2406 * ExtendedCameraCharacteristicsTest#testConstrainedHighSpeedCapability. 2407 * 2408 * @return true if the constrained high speed video is supported, false otherwise. 2409 */ isConstrainedHighSpeedVideoSupported()2410 public boolean isConstrainedHighSpeedVideoSupported() { 2411 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 2412 return (availableCapabilities.contains( 2413 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)); 2414 } 2415 2416 /** 2417 * Check if this camera device is a logical multi-camera backed by multiple 2418 * physical cameras. 2419 * 2420 * @return true if this is a logical multi-camera. 2421 */ isLogicalMultiCamera()2422 public boolean isLogicalMultiCamera() { 2423 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 2424 return (availableCapabilities.contains( 2425 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)); 2426 } 2427 2428 /** 2429 * Check if this camera device is a monochrome camera with Y8 support. 2430 * 2431 * @return true if this is a monochrome camera with Y8 support. 2432 */ isMonochromeWithY8()2433 public boolean isMonochromeWithY8() { 2434 int[] supportedFormats = getAvailableFormats( 2435 StaticMetadata.StreamDirection.Output); 2436 return (isColorOutputSupported() 2437 && isCapabilitySupported( 2438 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) 2439 && CameraTestUtils.contains(supportedFormats, ImageFormat.Y8)); 2440 } 2441 2442 /** 2443 * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is 2444 * supported, supported high speed fps ranges and sizes are valid). 2445 * 2446 * @return true if high speed video is supported. 2447 */ isHighSpeedVideoSupported()2448 public boolean isHighSpeedVideoSupported() { 2449 List<Integer> sceneModes = 2450 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked())); 2451 if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) { 2452 StreamConfigurationMap config = 2453 getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 2454 if (config == null) { 2455 return false; 2456 } 2457 Size[] availableSizes = config.getHighSpeedVideoSizes(); 2458 if (availableSizes.length == 0) { 2459 return false; 2460 } 2461 2462 for (Size size : availableSizes) { 2463 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size); 2464 if (availableFpsRanges.length == 0) { 2465 return false; 2466 } 2467 } 2468 2469 return true; 2470 } else { 2471 return false; 2472 } 2473 } 2474 2475 /** 2476 * Check if depth output is supported, based on the depth capability 2477 */ isDepthOutputSupported()2478 public boolean isDepthOutputSupported() { 2479 return isCapabilitySupported( 2480 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 2481 } 2482 2483 /** 2484 * Check if offline processing is supported, based on the respective capability 2485 */ isOfflineProcessingSupported()2486 public boolean isOfflineProcessingSupported() { 2487 return isCapabilitySupported( 2488 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING); 2489 } 2490 2491 /** 2492 * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the 2493 * backwards-compatible capability 2494 */ isColorOutputSupported()2495 public boolean isColorOutputSupported() { 2496 return isCapabilitySupported( 2497 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 2498 } 2499 2500 /** 2501 * Check if this camera is a MONOCHROME camera. 2502 */ isMonochromeCamera()2503 public boolean isMonochromeCamera() { 2504 return isCapabilitySupported( 2505 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME); 2506 } 2507 2508 /** 2509 * Check if optical black regions key is supported. 2510 */ isOpticalBlackRegionSupported()2511 public boolean isOpticalBlackRegionSupported() { 2512 return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS); 2513 } 2514 2515 /** 2516 * Check if HEIC format is supported 2517 */ isHeicSupported()2518 public boolean isHeicSupported() { 2519 int[] formats = getAvailableFormats(StaticMetadata.StreamDirection.Output); 2520 return CameraTestUtils.contains(formats, ImageFormat.HEIC); 2521 } 2522 2523 /** 2524 * Check if Depth Jpeg format is supported 2525 */ isDepthJpegSupported()2526 public boolean isDepthJpegSupported() { 2527 int[] formats = getAvailableFormats(StaticMetadata.StreamDirection.Output); 2528 return CameraTestUtils.contains(formats, ImageFormat.DEPTH_JPEG); 2529 } 2530 2531 /** 2532 * Check if the dynamic black level is supported. 2533 * 2534 * <p> 2535 * Note that: This also indicates if the white level is supported, as dynamic black and white 2536 * level must be all supported or none of them is supported. 2537 * </p> 2538 */ isDynamicBlackLevelSupported()2539 public boolean isDynamicBlackLevelSupported() { 2540 return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 2541 } 2542 2543 /** 2544 * Check if the enable ZSL key is supported. 2545 */ isEnableZslSupported()2546 public boolean isEnableZslSupported() { 2547 return areKeysAvailable(CaptureRequest.CONTROL_ENABLE_ZSL); 2548 } 2549 2550 /** 2551 * Check if AF scene change key is supported. 2552 */ isAfSceneChangeSupported()2553 public boolean isAfSceneChangeSupported() { 2554 return areKeysAvailable(CaptureResult.CONTROL_AF_SCENE_CHANGE); 2555 } 2556 2557 /** 2558 * Check if OIS data mode is supported. 2559 */ isOisDataModeSupported()2560 public boolean isOisDataModeSupported() { 2561 int[] availableOisDataModes = mCharacteristics.get( 2562 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES); 2563 2564 if (availableOisDataModes == null) { 2565 return false; 2566 } 2567 2568 for (int mode : availableOisDataModes) { 2569 if (mode == CameraMetadata.STATISTICS_OIS_DATA_MODE_ON) { 2570 return true; 2571 } 2572 } 2573 2574 return false; 2575 } 2576 2577 /** 2578 * Check if distortion correction is supported. 2579 */ isDistortionCorrectionSupported()2580 public boolean isDistortionCorrectionSupported() { 2581 boolean distortionCorrectionSupported = false; 2582 int[] distortionModes = mCharacteristics.get( 2583 CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES); 2584 if (distortionModes == null) { 2585 return false; 2586 } 2587 2588 for (int mode : distortionModes) { 2589 if (mode != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) { 2590 return true; 2591 } 2592 } 2593 2594 return false; 2595 } 2596 2597 /** 2598 * Check if active physical camera Id metadata is supported. 2599 */ isActivePhysicalCameraIdSupported()2600 public boolean isActivePhysicalCameraIdSupported() { 2601 return areKeysAvailable(CaptureResult.LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID); 2602 } 2603 2604 /** 2605 * Get the value in index for a fixed-size array from a given key. 2606 * 2607 * <p>If the camera device is incorrectly reporting values, log a warning and return 2608 * the default value instead.</p> 2609 * 2610 * @param key Key to fetch 2611 * @param defaultValue Default value to return if camera device uses invalid values 2612 * @param name Human-readable name for the array index (logging only) 2613 * @param index Array index of the subelement 2614 * @param size Expected fixed size of the array 2615 * 2616 * @return The value reported by the camera device, or the defaultValue otherwise. 2617 */ getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, int size)2618 private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, 2619 int size) { 2620 T elementValue = getArrayElementCheckRangeNonNull( 2621 key, 2622 index, 2623 size); 2624 2625 if (elementValue == null) { 2626 failKeyCheck(key, 2627 "had no valid " + name + " value; using default of " + defaultValue); 2628 elementValue = defaultValue; 2629 } 2630 2631 return elementValue; 2632 } 2633 2634 /** 2635 * Fetch an array sub-element from an array value given by a key. 2636 * 2637 * <p> 2638 * Prints a warning if the sub-element was null. 2639 * </p> 2640 * 2641 * <p>Use for variable-size arrays since this does not check the array size.</p> 2642 * 2643 * @param key Metadata key to look up 2644 * @param element A non-negative index value. 2645 * @return The array sub-element, or null if the checking failed. 2646 */ getArrayElementNonNull(Key<?> key, int element)2647 private <T> T getArrayElementNonNull(Key<?> key, int element) { 2648 return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK); 2649 } 2650 2651 /** 2652 * Fetch an array sub-element from an array value given by a key. 2653 * 2654 * <p> 2655 * Prints a warning if the array size does not match the size, or if the sub-element was null. 2656 * </p> 2657 * 2658 * @param key Metadata key to look up 2659 * @param element The index in [0,size) 2660 * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK} 2661 * @return The array sub-element, or null if the checking failed. 2662 */ getArrayElementCheckRangeNonNull(Key<?> key, int element, int size)2663 private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) { 2664 Object array = getValueFromKeyNonNull(key); 2665 2666 if (array == null) { 2667 // Warning already printed 2668 return null; 2669 } 2670 2671 if (size != IGNORE_SIZE_CHECK) { 2672 int actualLength = Array.getLength(array); 2673 if (actualLength != size) { 2674 failKeyCheck(key, 2675 String.format("had the wrong number of elements (%d), expected (%d)", 2676 actualLength, size)); 2677 return null; 2678 } 2679 } 2680 2681 @SuppressWarnings("unchecked") 2682 T val = (T) Array.get(array, element); 2683 2684 if (val == null) { 2685 failKeyCheck(key, "had a null element at index" + element); 2686 return null; 2687 } 2688 2689 return val; 2690 } 2691 2692 /** 2693 * Gets the key, logging warnings for null values. 2694 */ getValueFromKeyNonNull(Key<T> key)2695 public <T> T getValueFromKeyNonNull(Key<T> key) { 2696 if (key == null) { 2697 throw new IllegalArgumentException("key was null"); 2698 } 2699 2700 T value = mCharacteristics.get(key); 2701 2702 if (value == null) { 2703 failKeyCheck(key, "was null"); 2704 } 2705 2706 return value; 2707 } 2708 checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max)2709 private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) { 2710 for (int value : array) { 2711 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 2712 value <= max && value >= min); 2713 } 2714 } 2715 checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max)2716 private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) { 2717 for (byte value : array) { 2718 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 2719 value <= max && value >= min); 2720 } 2721 } 2722 2723 /** 2724 * Check the uniqueness of the values in a list. 2725 * 2726 * @param key The key to be checked 2727 * @param list The list contains the value of the key 2728 */ checkElementDistinct(Key<U> key, List<T> list)2729 private <U, T> void checkElementDistinct(Key<U> key, List<T> list) { 2730 // Each size must be distinct. 2731 Set<T> sizeSet = new HashSet<T>(list); 2732 checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size()); 2733 } 2734 checkTrueForKey(Key<T> key, String message, boolean condition)2735 private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) { 2736 if (!condition) { 2737 failKeyCheck(key, message); 2738 } 2739 } 2740 2741 /* Helper function to check if the coupled modes are either all present or all non-present */ containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes)2742 private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) { 2743 if (observedModes.containsAll(coupledModes)) { 2744 return true; 2745 } 2746 for (T mode : coupledModes) { 2747 if (observedModes.contains(mode)) { 2748 return false; 2749 } 2750 } 2751 return true; 2752 } 2753 failKeyCheck(Key<T> key, String message)2754 private <T> void failKeyCheck(Key<T> key, String message) { 2755 // TODO: Consider only warning once per key/message combination if it's too spammy. 2756 // TODO: Consider offering other options such as throwing an assertion exception 2757 String failureCause = String.format("The static info key '%s' %s", key.getName(), message); 2758 switch (mLevel) { 2759 case WARN: 2760 Log.w(TAG, failureCause); 2761 break; 2762 case COLLECT: 2763 mCollector.addMessage(failureCause); 2764 break; 2765 case ASSERT: 2766 Assert.fail(failureCause); 2767 default: 2768 throw new UnsupportedOperationException("Unhandled level " + mLevel); 2769 } 2770 } 2771 } 2772