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