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