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