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.util.Range; 29 import android.util.Size; 30 import android.util.Log; 31 import android.util.Rational; 32 33 import junit.framework.Assert; 34 35 import java.lang.reflect.Array; 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.Collection; 39 import java.util.HashMap; 40 import java.util.HashSet; 41 import java.util.List; 42 import java.util.Set; 43 44 /** 45 * Helpers to get common static info out of the camera. 46 * 47 * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p> 48 * 49 * <p>Attempt to be durable against the camera device having bad or missing metadata 50 * by providing reasonable defaults and logging warnings when that happens.</p> 51 */ 52 public class StaticMetadata { 53 54 private static final String TAG = "StaticMetadata"; 55 private static final int IGNORE_SIZE_CHECK = -1; 56 57 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us 58 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms 59 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100; 60 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800; 61 private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4; 62 private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64; 63 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2; 64 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2; 65 private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2); 66 private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8; 67 68 // TODO: Consider making this work across any metadata object, not just camera characteristics 69 private final CameraCharacteristics mCharacteristics; 70 private final CheckLevel mLevel; 71 private final CameraErrorCollector mCollector; 72 73 public enum CheckLevel { 74 /** Only log warnings for metadata check failures. Execution continues. */ 75 WARN, 76 /** 77 * Use ErrorCollector to collect the metadata check failures, Execution 78 * continues. 79 */ 80 COLLECT, 81 /** Assert the metadata check failures. Execution aborts. */ 82 ASSERT 83 } 84 85 /** 86 * Construct a new StaticMetadata object. 87 * 88 *<p> Default constructor, only log warnings for the static metadata check failures</p> 89 * 90 * @param characteristics static info for a camera 91 * @throws IllegalArgumentException if characteristics was null 92 */ 93 public StaticMetadata(CameraCharacteristics characteristics) { 94 this(characteristics, CheckLevel.WARN, /*collector*/null); 95 } 96 97 /** 98 * Construct a new StaticMetadata object with {@link CameraErrorCollector}. 99 * <p> 100 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 101 * ignored, otherwise, it will be used to log the check failures. 102 * </p> 103 * 104 * @param characteristics static info for a camera 105 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 106 * @throws IllegalArgumentException if characteristics or collector was null. 107 */ 108 public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) { 109 this(characteristics, CheckLevel.COLLECT, collector); 110 } 111 112 /** 113 * Construct a new StaticMetadata object with {@link CheckLevel} and 114 * {@link CameraErrorCollector}. 115 * <p> 116 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 117 * ignored, otherwise, it will be used to log the check failures. 118 * </p> 119 * 120 * @param characteristics static info for a camera 121 * @param level The {@link CheckLevel} of this StaticMetadata 122 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 123 * @throws IllegalArgumentException if characteristics was null or level was 124 * {@link CheckLevel.COLLECT} but collector was null. 125 */ 126 public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, 127 CameraErrorCollector collector) { 128 if (characteristics == null) { 129 throw new IllegalArgumentException("characteristics was null"); 130 } 131 if (level == CheckLevel.COLLECT && collector == null) { 132 throw new IllegalArgumentException("collector must valid when COLLECT level is set"); 133 } 134 135 mCharacteristics = characteristics; 136 mLevel = level; 137 mCollector = collector; 138 } 139 140 /** 141 * Get the CameraCharacteristics associated with this StaticMetadata. 142 * 143 * @return A non-null CameraCharacteristics object 144 */ 145 public CameraCharacteristics getCharacteristics() { 146 return mCharacteristics; 147 } 148 149 /** 150 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 151 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}. 152 * 153 * <p>If the camera device is not reporting the hardwareLevel, this 154 * will cause the test to fail.</p> 155 * 156 * @return {@code true} if the device is {@code FULL}, {@code false} otherwise. 157 */ 158 public boolean isHardwareLevelFull() { 159 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 160 } 161 162 /** 163 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 164 * Return the supported hardware level of the device, or fail if no value is reported. 165 * 166 * @return the supported hardware level as a constant defined for 167 * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}. 168 */ 169 public int getHardwareLevelChecked() { 170 Integer hwLevel = getValueFromKeyNonNull( 171 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 172 if (hwLevel == null) { 173 Assert.fail("No supported hardware level reported."); 174 } 175 return hwLevel; 176 } 177 178 /** 179 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 180 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}. 181 * 182 * <p>If the camera device is not reporting the hardwareLevel, this 183 * will cause the test to fail.</p> 184 * 185 * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise. 186 */ 187 public boolean isHardwareLevelLegacy() { 188 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 189 } 190 191 /** 192 * Whether or not the per frame control is supported by the camera device. 193 * 194 * @return {@code true} if per frame control is supported, {@code false} otherwise. 195 */ 196 public boolean isPerFrameControlSupported() { 197 return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL; 198 } 199 200 /** 201 * Get the maximum number of frames to wait for a request settings being applied 202 * 203 * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency 204 * CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control 205 * a positive int otherwise 206 */ 207 public int getSyncMaxLatency() { 208 Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY); 209 if (value == null) { 210 return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN; 211 } 212 return value; 213 } 214 215 /** 216 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 217 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 218 * 219 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 220 * will always return {@code true}.</p> 221 * 222 * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise. 223 */ 224 public boolean isHardwareLevelLimited() { 225 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 226 } 227 228 /** 229 * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel} 230 * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 231 * 232 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 233 * will always return {@code false}.</p> 234 * 235 * @return 236 * {@code true} if the device is {@code LIMITED} or {@code FULL}, 237 * {@code false} otherwise (i.e. LEGACY). 238 */ 239 public boolean isHardwareLevelLimitedOrBetter() { 240 Integer hwLevel = getValueFromKeyNonNull( 241 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 242 243 if (hwLevel == null) { 244 return false; 245 } 246 247 // Normal. Device could be limited. 248 int hwLevelInt = hwLevel; 249 return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL || 250 hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 251 } 252 253 /** 254 * Get the maximum number of partial result a request can expect 255 * 256 * @return 1 if partial result is not supported. 257 * a integer value larger than 1 if partial result is supported. 258 */ 259 public int getPartialResultCount() { 260 Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT); 261 if (value == null) { 262 // Optional key. Default value is 1 if key is missing. 263 return 1; 264 } 265 return value; 266 } 267 268 /** 269 * Get the exposure time value and clamp to the range if needed. 270 * 271 * @param exposure Input exposure time value to check. 272 * @return Exposure value in the legal range. 273 */ 274 public long getExposureClampToRange(long exposure) { 275 long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE); 276 long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE); 277 if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) { 278 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 279 String.format( 280 "Min value %d is too large, set to maximal legal value %d", 281 minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST)); 282 minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST; 283 } 284 if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) { 285 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 286 String.format( 287 "Max value %d is too small, set to minimal legal value %d", 288 maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST)); 289 maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST; 290 } 291 292 return Math.max(minExposure, Math.min(maxExposure, exposure)); 293 } 294 295 /** 296 * Check if the camera device support focuser. 297 * 298 * @return true if camera device support focuser, false otherwise. 299 */ 300 public boolean hasFocuser() { 301 if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) { 302 // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query 303 return (getMinimumFocusDistanceChecked() > 0); 304 } else { 305 // Check available AF modes 306 int[] availableAfModes = mCharacteristics.get( 307 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES); 308 309 if (availableAfModes == null) { 310 return false; 311 } 312 313 // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser 314 boolean hasFocuser = false; 315 loop: for (int mode : availableAfModes) { 316 switch (mode) { 317 case CameraMetadata.CONTROL_AF_MODE_AUTO: 318 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 319 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 320 case CameraMetadata.CONTROL_AF_MODE_MACRO: 321 hasFocuser = true; 322 break loop; 323 } 324 } 325 326 return hasFocuser; 327 } 328 } 329 330 /** 331 * Check if the camera device has flash unit. 332 * @return true if flash unit is available, false otherwise. 333 */ 334 public boolean hasFlash() { 335 return getFlashInfoChecked(); 336 } 337 338 /** 339 * Get minimum focus distance. 340 * 341 * @return minimum focus distance, 0 if minimum focus distance is invalid. 342 */ 343 public float getMinimumFocusDistanceChecked() { 344 Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE; 345 Float minFocusDistance; 346 347 /** 348 * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable 349 * devices; optional for all other devices. 350 */ 351 if (isHardwareLevelFull() || isCapabilitySupported( 352 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 353 minFocusDistance = getValueFromKeyNonNull(key); 354 } else { 355 minFocusDistance = mCharacteristics.get(key); 356 } 357 358 if (minFocusDistance == null) { 359 return 0.0f; 360 } 361 362 checkTrueForKey(key, " minFocusDistance value shouldn't be negative", 363 minFocusDistance >= 0); 364 if (minFocusDistance < 0) { 365 minFocusDistance = 0.0f; 366 } 367 368 return minFocusDistance; 369 } 370 371 /** 372 * Get focusDistanceCalibration. 373 * 374 * @return focusDistanceCalibration, UNCALIBRATED if value is invalid. 375 */ 376 public int getFocusDistanceCalibrationChecked() { 377 Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION; 378 Integer calibration = getValueFromKeyNonNull(key); 379 380 if (calibration == null) { 381 return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED; 382 } 383 384 checkTrueForKey(key, " value is out of range" , 385 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED && 386 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED); 387 388 return calibration; 389 } 390 391 /** 392 * Get max AE regions and do sanity check. 393 * 394 * @return AE max regions supported by the camera device 395 */ 396 public int getAeMaxRegionsChecked() { 397 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AE); 398 if (regionCount == null) { 399 return 0; 400 } 401 return regionCount; 402 } 403 404 /** 405 * Get max AWB regions and do sanity check. 406 * 407 * @return AWB max regions supported by the camera device 408 */ 409 public int getAwbMaxRegionsChecked() { 410 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB); 411 if (regionCount == null) { 412 return 0; 413 } 414 return regionCount; 415 } 416 417 /** 418 * Get max AF regions and do sanity check. 419 * 420 * @return AF max regions supported by the camera device 421 */ 422 public int getAfMaxRegionsChecked() { 423 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AF); 424 if (regionCount == null) { 425 return 0; 426 } 427 return regionCount; 428 } 429 /** 430 * Get the available anti-banding modes. 431 * 432 * @return The array contains available anti-banding modes. 433 */ 434 public int[] getAeAvailableAntiBandingModesChecked() { 435 Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; 436 int[] modes = getValueFromKeyNonNull(key); 437 438 boolean foundAuto = false; 439 boolean found50Hz = false; 440 boolean found60Hz = false; 441 for (int mode : modes) { 442 checkTrueForKey(key, "mode value " + mode + " is out if range", 443 mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF || 444 mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO); 445 if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) { 446 foundAuto = true; 447 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ) { 448 found50Hz = true; 449 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ) { 450 found60Hz = true; 451 } 452 } 453 // Must contain AUTO mode or one of 50/60Hz mode. 454 checkTrueForKey(key, "Either AUTO mode or both 50HZ/60HZ mode should present", 455 foundAuto || (found50Hz && found60Hz)); 456 457 return modes; 458 } 459 460 /** 461 * Check if the antibanding OFF mode is supported. 462 * 463 * @return true if antibanding OFF mode is supported, false otherwise. 464 */ 465 public boolean isAntiBandingOffModeSupported() { 466 List<Integer> antiBandingModes = 467 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked())); 468 469 return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF); 470 } 471 472 public Boolean getFlashInfoChecked() { 473 Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE; 474 Boolean hasFlash = getValueFromKeyNonNull(key); 475 476 // In case the failOnKey only gives warning. 477 if (hasFlash == null) { 478 return false; 479 } 480 481 return hasFlash; 482 } 483 484 public int[] getAvailableTestPatternModesChecked() { 485 Key<int[]> key = 486 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES; 487 int[] modes = getValueFromKeyNonNull(key); 488 489 if (modes == null) { 490 return new int[0]; 491 } 492 493 int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF; 494 Integer[] boxedModes = CameraTestUtils.toObject(modes); 495 checkTrueForKey(key, " value must contain OFF mode", 496 Arrays.asList(boxedModes).contains(expectValue)); 497 498 return modes; 499 } 500 501 /** 502 * Get available thumbnail sizes and do the sanity check. 503 * 504 * @return The array of available thumbnail sizes 505 */ 506 public Size[] getAvailableThumbnailSizesChecked() { 507 Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES; 508 Size[] sizes = getValueFromKeyNonNull(key); 509 final List<Size> sizeList = Arrays.asList(sizes); 510 511 // Size must contain (0, 0). 512 checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0))); 513 514 // Each size must be distinct. 515 checkElementDistinct(key, sizeList); 516 517 // Must be sorted in ascending order by area, by width if areas are same. 518 List<Size> orderedSizes = 519 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true); 520 checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString() 521 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList)); 522 523 // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations 524 // implementation see b/12958122. 525 526 return sizes; 527 } 528 529 /** 530 * Get available focal lengths and do the sanity check. 531 * 532 * @return The array of available focal lengths 533 */ 534 public float[] getAvailableFocalLengthsChecked() { 535 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS; 536 float[] focalLengths = getValueFromKeyNonNull(key); 537 538 checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1); 539 540 for (int i = 0; i < focalLengths.length; i++) { 541 checkTrueForKey(key, 542 String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]), 543 focalLengths[i] > 0); 544 } 545 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths))); 546 547 return focalLengths; 548 } 549 550 /** 551 * Get available apertures and do the sanity check. 552 * 553 * @return The non-null array of available apertures 554 */ 555 public float[] getAvailableAperturesChecked() { 556 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES; 557 float[] apertures = getValueFromKeyNonNull(key); 558 559 checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1); 560 561 for (int i = 0; i < apertures.length; i++) { 562 checkTrueForKey(key, 563 String.format("apertures[%d] %f should be positive.", i, apertures[i]), 564 apertures[i] > 0); 565 } 566 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures))); 567 568 return apertures; 569 } 570 571 /** 572 * Get and check the available hot pixel map modes. 573 * 574 * @return the available hot pixel map modes 575 */ 576 public int[] getAvailableHotPixelModesChecked() { 577 Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; 578 int[] modes = getValueFromKeyNonNull(key); 579 580 if (modes == null) { 581 return new int[0]; 582 } 583 584 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 585 if (isHardwareLevelFull()) { 586 checkTrueForKey(key, "Full-capability camera devices must support FAST mode", 587 modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST)); 588 } 589 checkElementDistinct(key, modeList); 590 checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF, 591 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY); 592 593 return modes; 594 } 595 596 /** 597 * Get and check available face detection modes. 598 * 599 * @return The non-null array of available face detection modes 600 */ 601 public int[] getAvailableFaceDetectModesChecked() { 602 Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; 603 int[] modes = getValueFromKeyNonNull(key); 604 605 if (modes == null) { 606 return new int[0]; 607 } 608 609 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 610 checkTrueForKey(key, "Array should contain OFF mode", 611 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF)); 612 checkElementDistinct(key, modeList); 613 checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF, 614 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL); 615 616 return modes; 617 } 618 619 /** 620 * Get and check max face detected count. 621 * 622 * @return max number of faces that can be detected 623 */ 624 public int getMaxFaceCountChecked() { 625 Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT; 626 Integer count = getValueFromKeyNonNull(key); 627 628 if (count == null) { 629 return 0; 630 } 631 632 List<Integer> faceDetectModes = 633 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked())); 634 if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) && 635 faceDetectModes.size() == 1) { 636 checkTrueForKey(key, " value must be 0 if only OFF mode is supported in " 637 + "availableFaceDetectionModes", count == 0); 638 } else { 639 int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST; 640 641 // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces. 642 if (isHardwareLevelLegacy()) { 643 maxFaceCountAtLeast = 1; 644 } 645 checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE" 646 + "or FULL is also supported in availableFaceDetectionModes", 647 count >= maxFaceCountAtLeast); 648 } 649 650 return count; 651 } 652 653 /** 654 * Get and check the available tone map modes. 655 * 656 * @return the available tone map modes 657 */ 658 public int[] getAvailableToneMapModesChecked() { 659 Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES; 660 int[] modes = getValueFromKeyNonNull(key); 661 662 if (modes == null) { 663 return new int[0]; 664 } 665 666 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 667 checkTrueForKey(key, " Camera devices must always support FAST mode", 668 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST)); 669 if (isCapabilitySupported( 670 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) { 671 checkTrueForKey(key, "MANUAL_POST_PROCESSING supported camera devices must support" 672 + "CONTRAST_CURVE mode", 673 modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) && 674 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST)); 675 } 676 checkElementDistinct(key, modeList); 677 checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE, 678 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY); 679 680 return modes; 681 } 682 683 /** 684 * Get and check max tonemap curve point. 685 * 686 * @return Max tonemap curve points. 687 */ 688 public int getMaxTonemapCurvePointChecked() { 689 Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS; 690 Integer count = getValueFromKeyNonNull(key); 691 692 if (count == null) { 693 return 0; 694 } 695 696 List<Integer> modeList = 697 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked())); 698 if (modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE)) { 699 checkTrueForKey(key, "Full-capability camera device must support maxCurvePoints " 700 + ">= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST, 701 count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST); 702 } 703 704 return count; 705 } 706 707 /** 708 * Get and check pixel array size. 709 */ 710 public Size getPixelArraySizeChecked() { 711 Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE; 712 Size pixelArray = getValueFromKeyNonNull(key); 713 if (pixelArray == null) { 714 return new Size(0, 0); 715 } 716 717 return pixelArray; 718 } 719 720 /** 721 * Get and check active array size. 722 */ 723 public Rect getActiveArraySizeChecked() { 724 Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE; 725 Rect activeArray = getValueFromKeyNonNull(key); 726 727 if (activeArray == null) { 728 return new Rect(0, 0, 0, 0); 729 } 730 731 Size pixelArraySize = getPixelArraySizeChecked(); 732 checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0); 733 checkTrueForKey(key, "values width/height are invalid", 734 activeArray.width() <= pixelArraySize.getWidth() && 735 activeArray.height() <= pixelArraySize.getHeight()); 736 737 return activeArray; 738 } 739 740 /** 741 * Get the sensitivity value and clamp to the range if needed. 742 * 743 * @param sensitivity Input sensitivity value to check. 744 * @return Sensitivity value in legal range. 745 */ 746 public int getSensitivityClampToRange(int sensitivity) { 747 int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE); 748 int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE); 749 if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) { 750 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 751 String.format( 752 "Min value %d is too large, set to maximal legal value %d", 753 minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST)); 754 minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST; 755 } 756 if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) { 757 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 758 String.format( 759 "Max value %d is too small, set to minimal legal value %d", 760 maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST)); 761 maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST; 762 } 763 764 return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity)); 765 } 766 767 /** 768 * Get maxAnalogSensitivity for a camera device. 769 * <p> 770 * This is only available for FULL capability device, return 0 if it is unavailable. 771 * </p> 772 * 773 * @return maxAnalogSensitivity, 0 if it is not available. 774 */ 775 public int getMaxAnalogSensitivityChecked() { 776 777 Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY; 778 Integer maxAnalogsensitivity = mCharacteristics.get(key); 779 if (maxAnalogsensitivity == null) { 780 if (isHardwareLevelFull()) { 781 Assert.fail("Full device should report max analog sensitivity"); 782 } 783 return 0; 784 } 785 786 int minSensitivity = getSensitivityMinimumOrDefault(); 787 int maxSensitivity = getSensitivityMaximumOrDefault(); 788 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity 789 + " should be no larger than max sensitivity " + maxSensitivity, 790 maxAnalogsensitivity <= maxSensitivity); 791 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity 792 + " should be larger than min sensitivity " + maxSensitivity, 793 maxAnalogsensitivity > minSensitivity); 794 795 return maxAnalogsensitivity; 796 } 797 798 /** 799 * Get hyperfocalDistance and do the sanity check. 800 * <p> 801 * Note that, this tag is optional, will return -1 if this tag is not 802 * available. 803 * </p> 804 * 805 * @return hyperfocalDistance of this device, -1 if this tag is not available. 806 */ 807 public float getHyperfocalDistanceChecked() { 808 Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE; 809 Float hyperfocalDistance = getValueFromKeyNonNull(key); 810 if (hyperfocalDistance == null) { 811 return -1; 812 } 813 814 if (hasFocuser()) { 815 float minFocusDistance = getMinimumFocusDistanceChecked(); 816 checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of" 817 + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f, 818 minFocusDistance), 819 hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance); 820 } 821 822 return hyperfocalDistance; 823 } 824 825 /** 826 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange. 827 * 828 * <p>If the camera is incorrectly reporting values, log a warning and return 829 * the default value instead, which is the largest minimum value required to be supported 830 * by all camera devices.</p> 831 * 832 * @return The value reported by the camera device or the defaultValue otherwise. 833 */ 834 public int getSensitivityMinimumOrDefault() { 835 return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST); 836 } 837 838 /** 839 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange. 840 * 841 * <p>If the camera is incorrectly reporting values, log a warning and return 842 * the default value instead.</p> 843 * 844 * @param defaultValue Value to return if no legal value is available 845 * @return The value reported by the camera device or the defaultValue otherwise. 846 */ 847 public int getSensitivityMinimumOrDefault(int defaultValue) { 848 Range<Integer> range = getValueFromKeyNonNull( 849 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); 850 if (range == null) { 851 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 852 "had no valid minimum value; using default of " + defaultValue); 853 return defaultValue; 854 } 855 return range.getLower(); 856 } 857 858 /** 859 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange. 860 * 861 * <p>If the camera is incorrectly reporting values, log a warning and return 862 * the default value instead, which is the smallest maximum value required to be supported 863 * by all camera devices.</p> 864 * 865 * @return The value reported by the camera device or the defaultValue otherwise. 866 */ 867 public int getSensitivityMaximumOrDefault() { 868 return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST); 869 } 870 871 /** 872 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange. 873 * 874 * <p>If the camera is incorrectly reporting values, log a warning and return 875 * the default value instead.</p> 876 * 877 * @param defaultValue Value to return if no legal value is available 878 * @return The value reported by the camera device or the defaultValue otherwise. 879 */ 880 public int getSensitivityMaximumOrDefault(int defaultValue) { 881 Range<Integer> range = getValueFromKeyNonNull( 882 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE); 883 if (range == null) { 884 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE, 885 "had no valid maximum value; using default of " + defaultValue); 886 return defaultValue; 887 } 888 return range.getUpper(); 889 } 890 891 /** 892 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange. 893 * 894 * <p>If the camera is incorrectly reporting values, log a warning and return 895 * the default value instead.</p> 896 * 897 * @param defaultValue Value to return if no legal value is available 898 * @return The value reported by the camera device or the defaultValue otherwise. 899 */ 900 public long getExposureMinimumOrDefault(long defaultValue) { 901 Range<Long> range = getValueFromKeyNonNull( 902 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 903 if (range == null) { 904 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 905 "had no valid minimum value; using default of " + defaultValue); 906 return defaultValue; 907 } 908 return range.getLower(); 909 } 910 911 /** 912 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange. 913 * 914 * <p>If the camera is incorrectly reporting values, log a warning and return 915 * the default value instead, which is the largest minimum value required to be supported 916 * by all camera devices.</p> 917 * 918 * @return The value reported by the camera device or the defaultValue otherwise. 919 */ 920 public long getExposureMinimumOrDefault() { 921 return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST); 922 } 923 924 /** 925 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange. 926 * 927 * <p>If the camera is incorrectly reporting values, log a warning and return 928 * the default value instead.</p> 929 * 930 * @param defaultValue Value to return if no legal value is available 931 * @return The value reported by the camera device or the defaultValue otherwise. 932 */ 933 public long getExposureMaximumOrDefault(long defaultValue) { 934 Range<Long> range = getValueFromKeyNonNull( 935 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE); 936 if (range == null) { 937 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE, 938 "had no valid maximum value; using default of " + defaultValue); 939 return defaultValue; 940 } 941 return range.getUpper(); 942 } 943 944 /** 945 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange. 946 * 947 * <p>If the camera is incorrectly reporting values, log a warning and return 948 * the default value instead, which is the smallest maximum value required to be supported 949 * by all camera devices.</p> 950 * 951 * @return The value reported by the camera device or the defaultValue otherwise. 952 */ 953 public long getExposureMaximumOrDefault() { 954 return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST); 955 } 956 957 /** 958 * Get aeAvailableModes and do the sanity check. 959 * 960 * <p>Depending on the check level this class has, for WAR or COLLECT levels, 961 * If the aeMode list is invalid, return an empty mode array. The the caller doesn't 962 * have to abort the execution even the aeMode list is invalid.</p> 963 * @return AE available modes 964 */ 965 public int[] getAeAvailableModesChecked() { 966 Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES; 967 int[] modes = getValueFromKeyNonNull(modesKey); 968 if (modes == null) { 969 modes = new int[0]; 970 } 971 List<Integer> modeList = new ArrayList<Integer>(); 972 for (int mode : modes) { 973 modeList.add(mode); 974 } 975 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty()); 976 977 // All camera device must support ON 978 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode", 979 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON)); 980 981 // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH 982 Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE; 983 Boolean hasFlash = getValueFromKeyNonNull(flashKey); 984 if (hasFlash == null) { 985 hasFlash = false; 986 } 987 if (hasFlash) { 988 boolean flashModeConsistentWithFlash = 989 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) && 990 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); 991 checkTrueForKey(modesKey, 992 "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and when flash is" + 993 "available", flashModeConsistentWithFlash); 994 } else { 995 boolean flashModeConsistentWithoutFlash = 996 !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) || 997 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) || 998 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)); 999 checkTrueForKey(modesKey, 1000 "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" + 1001 "ON_AUTO_FLASH_REDEYE when flash is unavailable", 1002 flashModeConsistentWithoutFlash); 1003 } 1004 1005 // FULL mode camera devices always support OFF mode. 1006 boolean condition = 1007 !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF); 1008 checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition); 1009 1010 // Boundary check. 1011 for (int mode : modes) { 1012 checkTrueForKey(modesKey, "Value " + mode + " is out of bound", 1013 mode >= CameraMetadata.CONTROL_AE_MODE_OFF 1014 && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE); 1015 } 1016 1017 return modes; 1018 } 1019 1020 /** 1021 * Get available AWB modes and do the sanity check. 1022 * 1023 * @return array that contains available AWB modes, empty array if awbAvailableModes is 1024 * unavailable. 1025 */ 1026 public int[] getAwbAvailableModesChecked() { 1027 Key<int[]> key = 1028 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES; 1029 int[] awbModes = getValueFromKeyNonNull(key); 1030 1031 if (awbModes == null) { 1032 return new int[0]; 1033 } 1034 1035 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes)); 1036 checkTrueForKey(key, " All camera devices must support AUTO mode", 1037 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO)); 1038 if (isHardwareLevelFull()) { 1039 checkTrueForKey(key, " Full capability camera devices must support OFF mode", 1040 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF)); 1041 } 1042 1043 return awbModes; 1044 } 1045 1046 /** 1047 * Get available AF modes and do the sanity check. 1048 * 1049 * @return array that contains available AF modes, empty array if afAvailableModes is 1050 * unavailable. 1051 */ 1052 public int[] getAfAvailableModesChecked() { 1053 Key<int[]> key = 1054 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES; 1055 int[] afModes = getValueFromKeyNonNull(key); 1056 1057 if (afModes == null) { 1058 return new int[0]; 1059 } 1060 1061 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes)); 1062 if (isHardwareLevelLimitedOrBetter()) { 1063 // Some LEGACY mode devices do not support AF OFF 1064 checkTrueForKey(key, " All camera devices must support OFF mode", 1065 modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF)); 1066 } 1067 if (hasFocuser()) { 1068 checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode", 1069 modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO)); 1070 } 1071 1072 return afModes; 1073 } 1074 1075 /** 1076 * Get supported raw output sizes and do the check. 1077 * 1078 * @return Empty size array if raw output is not supported 1079 */ 1080 public Size[] getRawOutputSizesChecked() { 1081 return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 1082 StreamDirection.Output); 1083 } 1084 1085 /** 1086 * Get supported jpeg output sizes and do the check. 1087 * 1088 * @return Empty size array if jpeg output is not supported 1089 */ 1090 public Size[] getJpegOutputSizeChecked() { 1091 return getAvailableSizesForFormatChecked(ImageFormat.JPEG, 1092 StreamDirection.Output); 1093 } 1094 1095 /** 1096 * Used to determine the stream direction for various helpers that look up 1097 * format or size information. 1098 */ 1099 public enum StreamDirection { 1100 /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */ 1101 Output, 1102 /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */ 1103 Input 1104 } 1105 1106 /** 1107 * Get available sizes for given user-defined format. 1108 * 1109 * <p><strong>Does not</strong> work with implementation-defined format.</p> 1110 * 1111 * @param format The format for the requested size array. 1112 * @param direction The stream direction, input or output. 1113 * @return The sizes of the given format, empty array if no available size is found. 1114 */ 1115 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) { 1116 Key<StreamConfigurationMap> key = 1117 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1118 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1119 1120 if (config == null) { 1121 return new Size[0]; 1122 } 1123 1124 android.util.Size[] utilSizes; 1125 1126 switch (direction) { 1127 case Output: 1128 utilSizes = config.getOutputSizes(format); 1129 break; 1130 case Input: 1131 utilSizes = null; 1132 break; 1133 default: 1134 throw new IllegalArgumentException("direction must be output or input"); 1135 } 1136 1137 // TODO: Get rid of android.util.Size 1138 if (utilSizes == null) { 1139 Log.i(TAG, "This camera doesn't support format " + format + " for " + direction); 1140 return new Size[0]; 1141 } 1142 1143 Size[] sizes = new Size[utilSizes.length]; 1144 for (int i = 0; i < utilSizes.length; ++i) { 1145 sizes[i] = new Size(utilSizes[i].getWidth(), utilSizes[i].getHeight()); 1146 } 1147 1148 return sizes; 1149 } 1150 1151 /** 1152 * Get available AE target fps ranges. 1153 * 1154 * @return Empty int array if aeAvailableTargetFpsRanges is invalid. 1155 */ 1156 @SuppressWarnings("raw") 1157 public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() { 1158 Key<Range<Integer>[]> key = 1159 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; 1160 Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key); 1161 1162 if (fpsRanges == null) { 1163 return new Range[0]; 1164 } 1165 1166 // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound 1167 // in case the above check fails. 1168 int fpsRangeLength = fpsRanges.length; 1169 int minFps, maxFps; 1170 long maxFrameDuration = getMaxFrameDurationChecked(); 1171 for (int i = 0; i < fpsRangeLength; i += 1) { 1172 minFps = fpsRanges[i].getLower(); 1173 maxFps = fpsRanges[i].getUpper(); 1174 checkTrueForKey(key, " min fps must be no larger than max fps!", 1175 minFps > 0 && maxFps >= minFps); 1176 long maxDuration = (long) (1e9 / minFps); 1177 checkTrueForKey(key, String.format( 1178 " the frame duration %d for min fps %d must smaller than maxFrameDuration %d", 1179 maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration); 1180 } 1181 1182 return fpsRanges; 1183 } 1184 1185 /** 1186 * Get max frame duration. 1187 * 1188 * @return 0 if maxFrameDuration is null 1189 */ 1190 public long getMaxFrameDurationChecked() { 1191 Key<Long> key = 1192 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION; 1193 Long maxDuration = getValueFromKeyNonNull(key); 1194 1195 if (maxDuration == null) { 1196 return 0; 1197 } 1198 1199 return maxDuration; 1200 } 1201 1202 /** 1203 * Get available minimal frame durations for a given user-defined format. 1204 * 1205 * <p><strong>Does not</strong> work with implementation-defined format.</p> 1206 * 1207 * @param format One of the format from {@link ImageFormat}. 1208 * @return HashMap of minimal frame durations for different sizes, empty HashMap 1209 * if availableMinFrameDurations is null. 1210 */ 1211 public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) { 1212 1213 HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>(); 1214 1215 Key<StreamConfigurationMap> key = 1216 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1217 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1218 1219 if (config == null) { 1220 return minDurationMap; 1221 } 1222 1223 for (android.util.Size size : config.getOutputSizes(format)) { 1224 long minFrameDuration = config.getOutputMinFrameDuration(format, size); 1225 1226 if (minFrameDuration != 0) { 1227 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration); 1228 } 1229 } 1230 1231 return minDurationMap; 1232 } 1233 1234 public int[] getAvailableEdgeModesChecked() { 1235 Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES; 1236 int[] edgeModes = getValueFromKeyNonNull(key); 1237 1238 if (edgeModes == null) { 1239 return new int[0]; 1240 } 1241 1242 // Full device should always include OFF and FAST 1243 if (isHardwareLevelFull()) { 1244 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes)); 1245 checkTrueForKey(key, "Full device must contain OFF and FAST edge modes", 1246 modeList.contains(CameraMetadata.EDGE_MODE_OFF) && 1247 modeList.contains(CameraMetadata.EDGE_MODE_FAST)); 1248 } 1249 1250 return edgeModes; 1251 } 1252 1253 public int[] getAvailableNoiseReductionModesChecked() { 1254 Key<int[]> key = 1255 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; 1256 int[] noiseReductionModes = getValueFromKeyNonNull(key); 1257 1258 if (noiseReductionModes == null) { 1259 return new int[0]; 1260 } 1261 1262 // Full device should always include OFF and FAST 1263 if (isHardwareLevelFull()) { 1264 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes)); 1265 checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes", 1266 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) && 1267 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST)); 1268 } 1269 1270 return noiseReductionModes; 1271 } 1272 1273 /** 1274 * Get value of key android.control.aeCompensationStep and do the sanity check. 1275 * 1276 * @return default value if the value is null. 1277 */ 1278 public Rational getAeCompensationStepChecked() { 1279 Key<Rational> key = 1280 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP; 1281 Rational compensationStep = getValueFromKeyNonNull(key); 1282 1283 if (compensationStep == null) { 1284 // Return default step. 1285 return CONTROL_AE_COMPENSATION_STEP_DEFAULT; 1286 } 1287 1288 // Legacy devices don't have a minimum step requirement 1289 if (isHardwareLevelLimitedOrBetter()) { 1290 float compensationStepF = 1291 (float) compensationStep.getNumerator() / compensationStep.getDenominator(); 1292 checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f); 1293 } 1294 1295 return compensationStep; 1296 } 1297 1298 /** 1299 * Get value of key android.control.aeCompensationRange and do the sanity check. 1300 * 1301 * @return default value if the value is null or malformed. 1302 */ 1303 public Range<Integer> getAeCompensationRangeChecked() { 1304 Key<Range<Integer>> key = 1305 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE; 1306 Range<Integer> compensationRange = getValueFromKeyNonNull(key); 1307 Rational compensationStep = getAeCompensationStepChecked(); 1308 float compensationStepF = compensationStep.floatValue(); 1309 final Range<Integer> DEFAULT_RANGE = Range.create( 1310 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF), 1311 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF)); 1312 final Range<Integer> ZERO_RANGE = Range.create(0, 0); 1313 if (compensationRange == null) { 1314 return ZERO_RANGE; 1315 } 1316 1317 // Legacy devices don't have a minimum range requirement 1318 if (isHardwareLevelLimitedOrBetter() && !compensationRange.equals(ZERO_RANGE)) { 1319 checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE 1320 + ", actual " + compensationRange + ", compensation step " + compensationStep, 1321 compensationRange.getLower() <= DEFAULT_RANGE.getLower() && 1322 compensationRange.getUpper() >= DEFAULT_RANGE.getUpper()); 1323 } 1324 1325 return compensationRange; 1326 } 1327 1328 /** 1329 * Get availableVideoStabilizationModes and do the sanity check. 1330 * 1331 * @return available video stabilization modes, empty array if it is unavailable. 1332 */ 1333 public int[] getAvailableVideoStabilizationModesChecked() { 1334 Key<int[]> key = 1335 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; 1336 int[] modes = getValueFromKeyNonNull(key); 1337 1338 if (modes == null) { 1339 return new int[0]; 1340 } 1341 1342 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1343 checkTrueForKey(key, " All device should support OFF mode", 1344 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF)); 1345 checkArrayValuesInRange(key, modes, 1346 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF, 1347 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); 1348 1349 return modes; 1350 } 1351 1352 /** 1353 * Get availableOpticalStabilization and do the sanity check. 1354 * 1355 * @return available optical stabilization modes, empty array if it is unavailable. 1356 */ 1357 public int[] getAvailableOpticalStabilizationChecked() { 1358 Key<int[]> key = 1359 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; 1360 int[] modes = getValueFromKeyNonNull(key); 1361 1362 if (modes == null) { 1363 return new int[0]; 1364 } 1365 1366 checkArrayValuesInRange(key, modes, 1367 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF, 1368 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON); 1369 1370 return modes; 1371 } 1372 1373 /** 1374 * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array 1375 * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable 1376 */ 1377 public float getAvailableMaxDigitalZoomChecked() { 1378 Key<Float> key = 1379 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; 1380 1381 Float maxZoom = getValueFromKeyNonNull(key); 1382 if (maxZoom == null) { 1383 return 1.0f; 1384 } 1385 1386 checkTrueForKey(key, " max digital zoom should be no less than 1", 1387 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom)); 1388 1389 return maxZoom; 1390 } 1391 1392 public int[] getAvailableSceneModesChecked() { 1393 Key<int[]> key = 1394 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES; 1395 int[] modes = getValueFromKeyNonNull(key); 1396 1397 if (modes == null) { 1398 return new int[0]; 1399 } 1400 1401 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1402 // FACE_PRIORITY must be included if face detection is supported. 1403 if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) && 1404 getMaxFaceCountChecked() > 0) { 1405 checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported", 1406 modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY)); 1407 } 1408 1409 return modes; 1410 } 1411 1412 public int[] getAvailableEffectModesChecked() { 1413 Key<int[]> key = 1414 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS; 1415 int[] modes = getValueFromKeyNonNull(key); 1416 1417 if (modes == null) { 1418 return new int[0]; 1419 } 1420 1421 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1422 // OFF must be included. 1423 checkTrueForKey(key, " OFF must be included", 1424 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF)); 1425 1426 return modes; 1427 } 1428 1429 /** 1430 * Get and check the available color aberration modes 1431 * 1432 * @return the available color aberration modes 1433 */ 1434 public int[] getAvailableColorAberrationModesChecked() { 1435 Key<int[]> key = 1436 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; 1437 int[] modes = getValueFromKeyNonNull(key); 1438 1439 if (modes == null) { 1440 return new int[0]; 1441 } 1442 1443 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1444 checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode", 1445 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) || 1446 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST)); 1447 checkElementDistinct(key, modeList); 1448 checkArrayValuesInRange(key, modes, 1449 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF, 1450 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); 1451 1452 return modes; 1453 } 1454 1455 /** 1456 * Get max pipeline depth and do the sanity check. 1457 * 1458 * @return max pipeline depth, default value if it is not available. 1459 */ 1460 public byte getPipelineMaxDepthChecked() { 1461 Key<Byte> key = 1462 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH; 1463 Byte maxDepth = getValueFromKeyNonNull(key); 1464 1465 if (maxDepth == null) { 1466 return REQUEST_PIPELINE_MAX_DEPTH_MAX; 1467 } 1468 1469 checkTrueForKey(key, " max pipeline depth should be no larger than " 1470 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX); 1471 1472 return maxDepth; 1473 } 1474 1475 /** 1476 * Get available capabilities and do the sanity check. 1477 * 1478 * @return reported available capabilities list, empty list if the value is unavailable. 1479 */ 1480 public List<Integer> getAvailableCapabilitiesChecked() { 1481 Key<int[]> key = 1482 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES; 1483 int[] availableCaps = getValueFromKeyNonNull(key); 1484 List<Integer> capList; 1485 1486 if (availableCaps == null) { 1487 return new ArrayList<Integer>(); 1488 } 1489 1490 checkArrayValuesInRange(key, availableCaps, 1491 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, 1492 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 1493 capList = Arrays.asList(CameraTestUtils.toObject(availableCaps)); 1494 return capList; 1495 } 1496 1497 /** 1498 * Determine whether the current device supports a capability or not. 1499 * 1500 * @param capability (non-negative) 1501 * 1502 * @return {@code true} if the capability is supported, {@code false} otherwise. 1503 * 1504 * @throws IllegalArgumentException if {@code capability} was negative 1505 * 1506 * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 1507 */ 1508 public boolean isCapabilitySupported(int capability) { 1509 if (capability < 0) { 1510 throw new IllegalArgumentException("capability must be non-negative"); 1511 } 1512 1513 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 1514 1515 return availableCapabilities.contains(capability); 1516 } 1517 1518 /** 1519 * Determine whether or not all the {@code keys} are available characteristics keys 1520 * (as in {@link CameraCharacteristics#getKeys}. 1521 * 1522 * <p>If this returns {@code true}, then querying for this key from a characteristics 1523 * object will always return a non-{@code null} value.</p> 1524 * 1525 * @param keys collection of camera characteristics keys 1526 * @return whether or not all characteristics keys are available 1527 */ 1528 public final boolean areCharacteristicsKeysAvailable( 1529 Collection<CameraCharacteristics.Key<?>> keys) { 1530 return mCharacteristics.getKeys().containsAll(keys); 1531 } 1532 1533 /** 1534 * Determine whether or not all the {@code keys} are available result keys 1535 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 1536 * 1537 * <p>If this returns {@code true}, then querying for this key from a result 1538 * object will almost always return a non-{@code null} value.</p> 1539 * 1540 * <p>In some cases (e.g. lens shading map), the request must have additional settings 1541 * configured in order for the key to correspond to a value.</p> 1542 * 1543 * @param keys collection of capture result keys 1544 * @return whether or not all result keys are available 1545 */ 1546 public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) { 1547 return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys); 1548 } 1549 1550 /** 1551 * Determine whether or not all the {@code keys} are available request keys 1552 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 1553 * 1554 * <p>If this returns {@code true}, then setting this key in the request builder 1555 * may have some effect (and if it's {@code false}, then the camera device will 1556 * definitely ignore it).</p> 1557 * 1558 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 1559 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 1560 * 1561 * @param keys collection of capture request keys 1562 * @return whether or not all result keys are available 1563 */ 1564 public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) { 1565 return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys); 1566 } 1567 1568 /** 1569 * Determine whether or not all the {@code keys} are available characteristics keys 1570 * (as in {@link CameraCharacteristics#getKeys}. 1571 * 1572 * <p>If this returns {@code true}, then querying for this key from a characteristics 1573 * object will always return a non-{@code null} value.</p> 1574 * 1575 * @param keys one or more camera characteristic keys 1576 * @return whether or not all characteristics keys are available 1577 */ 1578 @SafeVarargs 1579 public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) { 1580 return areCharacteristicsKeysAvailable(Arrays.asList(keys)); 1581 } 1582 1583 /** 1584 * Determine whether or not all the {@code keys} are available result keys 1585 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 1586 * 1587 * <p>If this returns {@code true}, then querying for this key from a result 1588 * object will almost always return a non-{@code null} value.</p> 1589 * 1590 * <p>In some cases (e.g. lens shading map), the request must have additional settings 1591 * configured in order for the key to correspond to a value.</p> 1592 * 1593 * @param keys one or more capture result keys 1594 * @return whether or not all result keys are available 1595 */ 1596 @SafeVarargs 1597 public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) { 1598 return areResultKeysAvailable(Arrays.asList(keys)); 1599 } 1600 1601 /** 1602 * Determine whether or not all the {@code keys} are available request keys 1603 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 1604 * 1605 * <p>If this returns {@code true}, then setting this key in the request builder 1606 * may have some effect (and if it's {@code false}, then the camera device will 1607 * definitely ignore it).</p> 1608 * 1609 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 1610 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 1611 * 1612 * @param keys one or more capture request keys 1613 * @return whether or not all result keys are available 1614 */ 1615 @SafeVarargs 1616 public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) { 1617 return areRequestKeysAvailable(Arrays.asList(keys)); 1618 } 1619 1620 /* 1621 * Determine if camera device support manual lens shading map control 1622 * 1623 * @return {@code true} if manual lens shading map control is supported 1624 */ 1625 public boolean isManualLensShadingMapSupported() { 1626 return areKeysAvailable(CaptureRequest.SHADING_MODE); 1627 } 1628 1629 /** 1630 * Determine if camera device support manual color correction control 1631 * 1632 * @return {@code true} if manual color correction control is supported 1633 */ 1634 public boolean isManualColorCorrectionSupported() { 1635 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE); 1636 } 1637 1638 /** 1639 * Determine if camera device support manual tone mapping control 1640 * 1641 * @return {@code true} if manual tone mapping control is supported 1642 */ 1643 public boolean isManualToneMapSupported() { 1644 return areKeysAvailable(CaptureRequest.TONEMAP_MODE); 1645 } 1646 1647 /** 1648 * Determine if camera device support manual color aberration control 1649 * 1650 * @return {@code true} if manual color aberration control is supported 1651 */ 1652 public boolean isManualColorAberrationControlSupported() { 1653 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE); 1654 } 1655 1656 /** 1657 * Determine if camera device support edge mode control 1658 * 1659 * @return {@code true} if edge mode control is supported 1660 */ 1661 public boolean isEdgeModeControlSupported() { 1662 return areKeysAvailable(CaptureRequest.EDGE_MODE); 1663 } 1664 1665 /** 1666 * Determine if camera device support hot pixel mode control 1667 * 1668 * @return {@code true} if hot pixel mode control is supported 1669 */ 1670 public boolean isHotPixelMapModeControlSupported() { 1671 return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE); 1672 } 1673 1674 /** 1675 * Determine if camera device support noise reduction mode control 1676 * 1677 * @return {@code true} if noise reduction mode control is supported 1678 */ 1679 public boolean isNoiseReductionModeControlSupported() { 1680 return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE); 1681 } 1682 1683 /** 1684 * Get max number of output raw streams and do the basic sanity check. 1685 * 1686 * @return reported max number of raw output stream 1687 */ 1688 public int getMaxNumOutputStreamsRawChecked() { 1689 Integer maxNumStreams = 1690 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW); 1691 if (maxNumStreams == null) 1692 return 0; 1693 return maxNumStreams; 1694 } 1695 1696 /** 1697 * Get max number of output processed streams and do the basic sanity check. 1698 * 1699 * @return reported max number of processed output stream 1700 */ 1701 public int getMaxNumOutputStreamsProcessedChecked() { 1702 Integer maxNumStreams = 1703 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC); 1704 if (maxNumStreams == null) 1705 return 0; 1706 return maxNumStreams; 1707 } 1708 1709 /** 1710 * Get max number of output stalling processed streams and do the basic sanity check. 1711 * 1712 * @return reported max number of stalling processed output stream 1713 */ 1714 public int getMaxNumOutputStreamsProcessedStallChecked() { 1715 Integer maxNumStreams = 1716 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING); 1717 if (maxNumStreams == null) 1718 return 0; 1719 return maxNumStreams; 1720 } 1721 1722 /** 1723 * Get lens facing and do the sanity check 1724 * @return lens facing, return default value (BACK) if value is unavailable. 1725 */ 1726 public int getLensFacingChecked() { 1727 Key<Integer> key = 1728 CameraCharacteristics.LENS_FACING; 1729 Integer facing = getValueFromKeyNonNull(key); 1730 1731 if (facing == null) { 1732 return CameraCharacteristics.LENS_FACING_BACK; 1733 } 1734 1735 checkTrueForKey(key, " value is out of range ", 1736 facing >= CameraCharacteristics.LENS_FACING_FRONT && 1737 facing <= CameraCharacteristics.LENS_FACING_BACK); 1738 return facing; 1739 } 1740 1741 /** 1742 * Get the scaler's cropping type (center only or freeform) 1743 * @return cropping type, return default value (CENTER_ONLY) if value is unavailable 1744 */ 1745 public int getScalerCroppingTypeChecked() { 1746 Key<Integer> key = 1747 CameraCharacteristics.SCALER_CROPPING_TYPE; 1748 Integer value = getValueFromKeyNonNull(key); 1749 1750 if (value == null) { 1751 return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY; 1752 } 1753 1754 checkTrueForKey(key, " value is out of range ", 1755 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY && 1756 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM); 1757 1758 return value; 1759 } 1760 1761 /** 1762 * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is 1763 * supported, supported high speed fps ranges and sizes are valid). 1764 * 1765 * @return true if high speed video is supported. 1766 */ 1767 public boolean isHighSpeedVideoSupported() { 1768 List<Integer> sceneModes = 1769 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked())); 1770 if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) { 1771 StreamConfigurationMap config = 1772 getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1773 if (config == null) { 1774 return false; 1775 } 1776 Size[] availableSizes = config.getHighSpeedVideoSizes(); 1777 if (availableSizes.length == 0) { 1778 return false; 1779 } 1780 1781 for (Size size : availableSizes) { 1782 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size); 1783 if (availableFpsRanges.length == 0) { 1784 return false; 1785 } 1786 } 1787 1788 return true; 1789 } else { 1790 return false; 1791 } 1792 } 1793 1794 /** 1795 * Get the value in index for a fixed-size array from a given key. 1796 * 1797 * <p>If the camera device is incorrectly reporting values, log a warning and return 1798 * the default value instead.</p> 1799 * 1800 * @param key Key to fetch 1801 * @param defaultValue Default value to return if camera device uses invalid values 1802 * @param name Human-readable name for the array index (logging only) 1803 * @param index Array index of the subelement 1804 * @param size Expected fixed size of the array 1805 * 1806 * @return The value reported by the camera device, or the defaultValue otherwise. 1807 */ 1808 private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, 1809 int size) { 1810 T elementValue = getArrayElementCheckRangeNonNull( 1811 key, 1812 index, 1813 size); 1814 1815 if (elementValue == null) { 1816 failKeyCheck(key, 1817 "had no valid " + name + " value; using default of " + defaultValue); 1818 elementValue = defaultValue; 1819 } 1820 1821 return elementValue; 1822 } 1823 1824 /** 1825 * Fetch an array sub-element from an array value given by a key. 1826 * 1827 * <p> 1828 * Prints a warning if the sub-element was null. 1829 * </p> 1830 * 1831 * <p>Use for variable-size arrays since this does not check the array size.</p> 1832 * 1833 * @param key Metadata key to look up 1834 * @param element A non-negative index value. 1835 * @return The array sub-element, or null if the checking failed. 1836 */ 1837 private <T> T getArrayElementNonNull(Key<?> key, int element) { 1838 return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK); 1839 } 1840 1841 /** 1842 * Fetch an array sub-element from an array value given by a key. 1843 * 1844 * <p> 1845 * Prints a warning if the array size does not match the size, or if the sub-element was null. 1846 * </p> 1847 * 1848 * @param key Metadata key to look up 1849 * @param element The index in [0,size) 1850 * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK} 1851 * @return The array sub-element, or null if the checking failed. 1852 */ 1853 private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) { 1854 Object array = getValueFromKeyNonNull(key); 1855 1856 if (array == null) { 1857 // Warning already printed 1858 return null; 1859 } 1860 1861 if (size != IGNORE_SIZE_CHECK) { 1862 int actualLength = Array.getLength(array); 1863 if (actualLength != size) { 1864 failKeyCheck(key, 1865 String.format("had the wrong number of elements (%d), expected (%d)", 1866 actualLength, size)); 1867 return null; 1868 } 1869 } 1870 1871 @SuppressWarnings("unchecked") 1872 T val = (T) Array.get(array, element); 1873 1874 if (val == null) { 1875 failKeyCheck(key, "had a null element at index" + element); 1876 return null; 1877 } 1878 1879 return val; 1880 } 1881 1882 /** 1883 * Gets the key, logging warnings for null values. 1884 */ 1885 public <T> T getValueFromKeyNonNull(Key<T> key) { 1886 if (key == null) { 1887 throw new IllegalArgumentException("key was null"); 1888 } 1889 1890 T value = mCharacteristics.get(key); 1891 1892 if (value == null) { 1893 failKeyCheck(key, "was null"); 1894 } 1895 1896 return value; 1897 } 1898 1899 private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) { 1900 for (int value : array) { 1901 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 1902 value <= max && value >= min); 1903 } 1904 } 1905 1906 private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) { 1907 for (byte value : array) { 1908 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 1909 value <= max && value >= min); 1910 } 1911 } 1912 1913 /** 1914 * Check the uniqueness of the values in a list. 1915 * 1916 * @param key The key to be checked 1917 * @param list The list contains the value of the key 1918 */ 1919 private <U, T> void checkElementDistinct(Key<U> key, List<T> list) { 1920 // Each size must be distinct. 1921 Set<T> sizeSet = new HashSet<T>(list); 1922 checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size()); 1923 } 1924 1925 private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) { 1926 if (!condition) { 1927 failKeyCheck(key, message); 1928 } 1929 } 1930 1931 private <T> void failKeyCheck(Key<T> key, String message) { 1932 // TODO: Consider only warning once per key/message combination if it's too spammy. 1933 // TODO: Consider offering other options such as throwing an assertion exception 1934 String failureCause = String.format("The static info key '%s' %s", key.getName(), message); 1935 switch (mLevel) { 1936 case WARN: 1937 Log.w(TAG, failureCause); 1938 break; 1939 case COLLECT: 1940 mCollector.addMessage(failureCause); 1941 break; 1942 case ASSERT: 1943 Assert.fail(failureCause); 1944 default: 1945 throw new UnsupportedOperationException("Unhandled level " + mLevel); 1946 } 1947 } 1948 } 1949