1 /* 2 * Copyright 2016 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 com.android.mediaframeworktest.helpers; 18 19 import static com.android.mediaframeworktest.helpers.AssertHelpers.assertArrayContainsAnyOf; 20 21 import android.graphics.ImageFormat; 22 import android.graphics.Rect; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraCharacteristics.Key; 25 import android.hardware.camera2.CameraMetadata; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.params.StreamConfigurationMap; 29 import android.util.Log; 30 import android.util.Range; 31 import android.util.Rational; 32 import android.util.Size; 33 34 import junit.framework.Assert; 35 36 import java.lang.reflect.Array; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collection; 40 import java.util.HashMap; 41 import java.util.HashSet; 42 import java.util.List; 43 import java.util.Set; 44 45 /** 46 * Helpers to get common static info out of the camera. 47 * 48 * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p> 49 * 50 * <p>Attempt to be durable against the camera device having bad or missing metadata 51 * by providing reasonable defaults and logging warnings when that happens.</p> 52 */ 53 /** 54 * (non-Javadoc) 55 * @see android.hardware.camera2.cts.helpers.StaticMetadata 56 */ 57 public class StaticMetadata { 58 59 private static final String TAG = "StaticMetadata"; 60 private static final int IGNORE_SIZE_CHECK = -1; 61 62 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us 63 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms 64 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100; 65 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800; 66 private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4; 67 private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64; 68 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2; 69 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2; 70 private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2); 71 private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8; 72 private static final int MAX_REPROCESS_MAX_CAPTURE_STALL = 4; 73 74 // TODO: Consider making this work across any metadata object, not just camera characteristics 75 private final CameraCharacteristics mCharacteristics; 76 private final CheckLevel mLevel; 77 private final CameraErrorCollector mCollector; 78 79 // Index with android.control.aeMode 80 public static final String[] AE_MODE_NAMES = new String[] { 81 "AE_MODE_OFF", 82 "AE_MODE_ON", 83 "AE_MODE_ON_AUTO_FLASH", 84 "AE_MODE_ON_ALWAYS_FLASH", 85 "AE_MODE_ON_AUTO_FLASH_REDEYE" 86 }; 87 88 // Index with android.control.afMode 89 public static final String[] AF_MODE_NAMES = new String[] { 90 "AF_MODE_OFF", 91 "AF_MODE_AUTO", 92 "AF_MODE_MACRO", 93 "AF_MODE_CONTINUOUS_VIDEO", 94 "AF_MODE_CONTINUOUS_PICTURE", 95 "AF_MODE_EDOF" 96 }; 97 98 // Index with android.control.aeState 99 public static final String[] AE_STATE_NAMES = new String[] { 100 "AE_STATE_INACTIVE", 101 "AE_STATE_SEARCHING", 102 "AE_STATE_CONVERGED", 103 "AE_STATE_LOCKED", 104 "AE_STATE_FLASH_REQUIRED", 105 "AE_STATE_PRECAPTURE" 106 }; 107 108 // Index with android.control.afState 109 public static final String[] AF_STATE_NAMES = new String[] { 110 "AF_STATE_INACTIVE", 111 "AF_STATE_PASSIVE_SCAN", 112 "AF_STATE_PASSIVE_FOCUSED", 113 "AF_STATE_ACTIVE_SCAN", 114 "AF_STATE_FOCUSED_LOCKED", 115 "AF_STATE_NOT_FOCUSED_LOCKED", 116 "AF_STATE_PASSIVE_UNFOCUSED" 117 }; 118 119 public enum CheckLevel { 120 /** Only log warnings for metadata check failures. Execution continues. */ 121 WARN, 122 /** 123 * Use ErrorCollector to collect the metadata check failures, Execution 124 * continues. 125 */ 126 COLLECT, 127 /** Assert the metadata check failures. Execution aborts. */ 128 ASSERT 129 } 130 131 /** 132 * Construct a new StaticMetadata object. 133 * 134 *<p> Default constructor, only log warnings for the static metadata check failures</p> 135 * 136 * @param characteristics static info for a camera 137 * @throws IllegalArgumentException if characteristics was null 138 */ StaticMetadata(CameraCharacteristics characteristics)139 public StaticMetadata(CameraCharacteristics characteristics) { 140 this(characteristics, CheckLevel.WARN, /*collector*/null); 141 } 142 143 /** 144 * Construct a new StaticMetadata object with {@link CameraErrorCollector}. 145 * <p> 146 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 147 * ignored, otherwise, it will be used to log the check failures. 148 * </p> 149 * 150 * @param characteristics static info for a camera 151 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 152 * @throws IllegalArgumentException if characteristics or collector was null. 153 */ StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector)154 public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) { 155 this(characteristics, CheckLevel.COLLECT, collector); 156 } 157 158 /** 159 * Construct a new StaticMetadata object with {@link CheckLevel} and 160 * {@link CameraErrorCollector}. 161 * <p> 162 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be 163 * ignored, otherwise, it will be used to log the check failures. 164 * </p> 165 * 166 * @param characteristics static info for a camera 167 * @param level The {@link CheckLevel} of this StaticMetadata 168 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata 169 * @throws IllegalArgumentException if characteristics was null or level was 170 * {@link CheckLevel.COLLECT} but collector was null. 171 */ StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, CameraErrorCollector collector)172 public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level, 173 CameraErrorCollector collector) { 174 if (characteristics == null) { 175 throw new IllegalArgumentException("characteristics was null"); 176 } 177 if (level == CheckLevel.COLLECT && collector == null) { 178 throw new IllegalArgumentException("collector must valid when COLLECT level is set"); 179 } 180 181 mCharacteristics = characteristics; 182 mLevel = level; 183 mCollector = collector; 184 } 185 186 /** 187 * Get the CameraCharacteristics associated with this StaticMetadata. 188 * 189 * @return A non-null CameraCharacteristics object 190 */ getCharacteristics()191 public CameraCharacteristics getCharacteristics() { 192 return mCharacteristics; 193 } 194 195 /** 196 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 197 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}. 198 * 199 * <p>If the camera device is not reporting the hardwareLevel, this 200 * will cause the test to fail.</p> 201 * 202 * @return {@code true} if the device is {@code FULL}, {@code false} otherwise. 203 */ isHardwareLevelFull()204 public boolean isHardwareLevelFull() { 205 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 206 } 207 208 /** 209 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 210 * Return the supported hardware level of the device, or fail if no value is reported. 211 * 212 * @return the supported hardware level as a constant defined for 213 * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}. 214 */ getHardwareLevelChecked()215 public int getHardwareLevelChecked() { 216 Integer hwLevel = getValueFromKeyNonNull( 217 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 218 if (hwLevel == null) { 219 Assert.fail("No supported hardware level reported."); 220 } 221 return hwLevel; 222 } 223 224 /** 225 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 226 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}. 227 * 228 * <p>If the camera device is not reporting the hardwareLevel, this 229 * will cause the test to fail.</p> 230 * 231 * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise. 232 */ isHardwareLevelLegacy()233 public boolean isHardwareLevelLegacy() { 234 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 235 } 236 237 /** 238 * Whether or not the per frame control is supported by the camera device. 239 * 240 * @return {@code true} if per frame control is supported, {@code false} otherwise. 241 */ isPerFrameControlSupported()242 public boolean isPerFrameControlSupported() { 243 return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL; 244 } 245 246 /** 247 * Get the maximum number of frames to wait for a request settings being applied 248 * 249 * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency 250 * CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control 251 * a positive int otherwise 252 */ getSyncMaxLatency()253 public int getSyncMaxLatency() { 254 Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY); 255 if (value == null) { 256 return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN; 257 } 258 return value; 259 } 260 261 /** 262 * Whether or not the hardware level reported by android.info.supportedHardwareLevel 263 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 264 * 265 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 266 * will always return {@code true}.</p> 267 * 268 * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise. 269 */ isHardwareLevelLimited()270 public boolean isHardwareLevelLimited() { 271 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 272 } 273 274 /** 275 * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel} 276 * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}. 277 * 278 * <p>If the camera device is incorrectly reporting the hardwareLevel, this 279 * will always return {@code false}.</p> 280 * 281 * @return 282 * {@code true} if the device is {@code LIMITED} or {@code FULL}, 283 * {@code false} otherwise (i.e. LEGACY). 284 */ isHardwareLevelLimitedOrBetter()285 public boolean isHardwareLevelLimitedOrBetter() { 286 Integer hwLevel = getValueFromKeyNonNull( 287 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 288 289 if (hwLevel == null) { 290 return false; 291 } 292 293 // Normal. Device could be limited. 294 int hwLevelInt = hwLevel; 295 return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL || 296 hwLevelInt == 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 (isHardwareLevelFull() || 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 validation 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 validation 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 validation 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 validation 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 validation 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 validation 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 (isHardwareLevelFull()) { 632 checkTrueForKey(key, "Full-capability camera devices must support FAST mode", 633 modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST)); 634 } 635 636 if (isHardwareLevelLimitedOrBetter()) { 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 (isHardwareLevelLimitedOrBetter()) { 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 (isHardwareLevelFull()) { 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 validation 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 validation 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 validation 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 // Skip vendor-added modes 1143 if (mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) { 1144 modeList.add(mode); 1145 } 1146 } 1147 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty()); 1148 modes = new int[modeList.size()]; 1149 for (int i = 0; i < modeList.size(); i++) { 1150 modes[i] = modeList.get(i); 1151 } 1152 1153 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty()); 1154 1155 // All camera device must support ON 1156 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode", 1157 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON)); 1158 1159 // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH 1160 Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE; 1161 Boolean hasFlash = getValueFromKeyNonNull(flashKey); 1162 if (hasFlash == null) { 1163 hasFlash = false; 1164 } 1165 if (hasFlash) { 1166 boolean flashModeConsistentWithFlash = 1167 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) && 1168 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); 1169 checkTrueForKey(modesKey, 1170 "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and when flash is" + 1171 "available", flashModeConsistentWithFlash); 1172 } else { 1173 boolean flashModeConsistentWithoutFlash = 1174 !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) || 1175 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) || 1176 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE)); 1177 checkTrueForKey(modesKey, 1178 "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" + 1179 "ON_AUTO_FLASH_REDEYE when flash is unavailable", 1180 flashModeConsistentWithoutFlash); 1181 } 1182 1183 // FULL mode camera devices always support OFF mode. 1184 boolean condition = 1185 !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF); 1186 checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition); 1187 1188 // Boundary check. 1189 for (int mode : modes) { 1190 checkTrueForKey(modesKey, "Value " + mode + " is out of bound", 1191 mode >= CameraMetadata.CONTROL_AE_MODE_OFF 1192 && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE); 1193 } 1194 1195 return modes; 1196 } 1197 1198 /** 1199 * Get available AWB modes and do the validation check. 1200 * 1201 * @return array that contains available AWB modes, empty array if awbAvailableModes is 1202 * unavailable. 1203 */ getAwbAvailableModesChecked()1204 public int[] getAwbAvailableModesChecked() { 1205 Key<int[]> key = 1206 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES; 1207 int[] awbModes = getValueFromKeyNonNull(key); 1208 1209 if (awbModes == null) { 1210 return new int[0]; 1211 } 1212 1213 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes)); 1214 checkTrueForKey(key, " All camera devices must support AUTO mode", 1215 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO)); 1216 if (isHardwareLevelFull()) { 1217 checkTrueForKey(key, " Full capability camera devices must support OFF mode", 1218 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF)); 1219 } 1220 1221 return awbModes; 1222 } 1223 1224 /** 1225 * Get available AF modes and do the validation check. 1226 * 1227 * @return array that contains available AF modes, empty array if afAvailableModes is 1228 * unavailable. 1229 */ getAfAvailableModesChecked()1230 public int[] getAfAvailableModesChecked() { 1231 Key<int[]> key = 1232 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES; 1233 int[] afModes = getValueFromKeyNonNull(key); 1234 1235 if (afModes == null) { 1236 return new int[0]; 1237 } 1238 1239 List<Integer> modesList = new ArrayList<Integer>(); 1240 for (int afMode : afModes) { 1241 // Skip vendor-added AF modes 1242 if (afMode > CameraCharacteristics.CONTROL_AF_MODE_EDOF) continue; 1243 modesList.add(afMode); 1244 } 1245 afModes = new int[modesList.size()]; 1246 for (int i = 0; i < modesList.size(); i++) { 1247 afModes[i] = modesList.get(i); 1248 } 1249 1250 if (isHardwareLevelLimitedOrBetter()) { 1251 // Some LEGACY mode devices do not support AF OFF 1252 checkTrueForKey(key, " All camera devices must support OFF mode", 1253 modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF)); 1254 } 1255 if (hasFocuser()) { 1256 checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode", 1257 modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO)); 1258 } 1259 1260 return afModes; 1261 } 1262 1263 /** 1264 * Get supported raw output sizes and do the check. 1265 * 1266 * @return Empty size array if raw output is not supported 1267 */ getRawOutputSizesChecked()1268 public Size[] getRawOutputSizesChecked() { 1269 return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 1270 StreamDirection.Output); 1271 } 1272 1273 /** 1274 * Get supported jpeg output sizes and do the check. 1275 * 1276 * @return Empty size array if jpeg output is not supported 1277 */ getJpegOutputSizesChecked()1278 public Size[] getJpegOutputSizesChecked() { 1279 return getAvailableSizesForFormatChecked(ImageFormat.JPEG, 1280 StreamDirection.Output); 1281 } 1282 1283 /** 1284 * Used to determine the stream direction for various helpers that look up 1285 * format or size information. 1286 */ 1287 public enum StreamDirection { 1288 /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */ 1289 Output, 1290 /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */ 1291 Input 1292 } 1293 1294 /** 1295 * Get available formats for a given direction. 1296 * 1297 * @param direction The stream direction, input or output. 1298 * @return The formats of the given direction, empty array if no available format is found. 1299 */ getAvailableFormats(StreamDirection direction)1300 public int[] getAvailableFormats(StreamDirection direction) { 1301 Key<StreamConfigurationMap> key = 1302 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1303 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1304 1305 if (config == null) { 1306 return new int[0]; 1307 } 1308 1309 switch (direction) { 1310 case Output: 1311 return config.getOutputFormats(); 1312 case Input: 1313 return config.getInputFormats(); 1314 default: 1315 throw new IllegalArgumentException("direction must be output or input"); 1316 } 1317 } 1318 1319 /** 1320 * Get valid output formats for a given input format. 1321 * 1322 * @param inputFormat The input format used to produce the output images. 1323 * @return The output formats for the given input format, empty array if 1324 * no available format is found. 1325 */ getValidOutputFormatsForInput(int inputFormat)1326 public int[] getValidOutputFormatsForInput(int inputFormat) { 1327 Key<StreamConfigurationMap> key = 1328 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1329 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1330 1331 if (config == null) { 1332 return new int[0]; 1333 } 1334 1335 return config.getValidOutputFormatsForInput(inputFormat); 1336 } 1337 1338 /** 1339 * Get available sizes for given format and direction. 1340 * 1341 * @param format The format for the requested size array. 1342 * @param direction The stream direction, input or output. 1343 * @return The sizes of the given format, empty array if no available size is found. 1344 */ getAvailableSizesForFormatChecked(int format, StreamDirection direction)1345 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) { 1346 return getAvailableSizesForFormatChecked(format, direction, 1347 /*fastSizes*/true, /*slowSizes*/true); 1348 } 1349 1350 /** 1351 * Get available sizes for given format and direction, and whether to limit to slow or fast 1352 * resolutions. 1353 * 1354 * @param format The format for the requested size array. 1355 * @param direction The stream direction, input or output. 1356 * @param fastSizes whether to include getOutputSizes() sizes (generally faster) 1357 * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower) 1358 * @return The sizes of the given format, empty array if no available size is found. 1359 */ getAvailableSizesForFormatChecked(int format, StreamDirection direction, boolean fastSizes, boolean slowSizes)1360 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction, 1361 boolean fastSizes, boolean slowSizes) { 1362 Key<StreamConfigurationMap> key = 1363 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1364 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1365 1366 if (config == null) { 1367 return new Size[0]; 1368 } 1369 1370 Size[] sizes = null; 1371 1372 switch (direction) { 1373 case Output: 1374 Size[] fastSizeList = null; 1375 Size[] slowSizeList = null; 1376 if (fastSizes) { 1377 fastSizeList = config.getOutputSizes(format); 1378 } 1379 if (slowSizes) { 1380 slowSizeList = config.getHighResolutionOutputSizes(format); 1381 } 1382 if (fastSizeList != null && slowSizeList != null) { 1383 sizes = new Size[slowSizeList.length + fastSizeList.length]; 1384 System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length); 1385 System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length); 1386 } else if (fastSizeList != null) { 1387 sizes = fastSizeList; 1388 } else if (slowSizeList != null) { 1389 sizes = slowSizeList; 1390 } 1391 break; 1392 case Input: 1393 sizes = config.getInputSizes(format); 1394 break; 1395 default: 1396 throw new IllegalArgumentException("direction must be output or input"); 1397 } 1398 1399 if (sizes == null) { 1400 sizes = new Size[0]; 1401 } 1402 1403 return sizes; 1404 } 1405 1406 /** 1407 * Get available AE target fps ranges. 1408 * 1409 * @return Empty int array if aeAvailableTargetFpsRanges is invalid. 1410 */ 1411 @SuppressWarnings("raw") getAeAvailableTargetFpsRangesChecked()1412 public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() { 1413 Key<Range<Integer>[]> key = 1414 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; 1415 Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key); 1416 1417 if (fpsRanges == null) { 1418 return new Range[0]; 1419 } 1420 1421 // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound 1422 // in case the above check fails. 1423 int fpsRangeLength = fpsRanges.length; 1424 int minFps, maxFps; 1425 long maxFrameDuration = getMaxFrameDurationChecked(); 1426 for (int i = 0; i < fpsRangeLength; i += 1) { 1427 minFps = fpsRanges[i].getLower(); 1428 maxFps = fpsRanges[i].getUpper(); 1429 checkTrueForKey(key, " min fps must be no larger than max fps!", 1430 minFps > 0 && maxFps >= minFps); 1431 long maxDuration = (long) (1e9 / minFps); 1432 checkTrueForKey(key, String.format( 1433 " the frame duration %d for min fps %d must smaller than maxFrameDuration %d", 1434 maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration); 1435 } 1436 return fpsRanges; 1437 } 1438 getAeModeName(int aeMode)1439 public static String getAeModeName(int aeMode) { 1440 return (aeMode >= AE_MODE_NAMES.length) ? String.format("VENDOR_AE_MODE_%d", aeMode) : 1441 AE_MODE_NAMES[aeMode]; 1442 } 1443 getAfModeName(int afMode)1444 public static String getAfModeName(int afMode) { 1445 return (afMode >= AF_MODE_NAMES.length) ? String.format("VENDOR_AF_MODE_%d", afMode) : 1446 AF_MODE_NAMES[afMode]; 1447 } 1448 1449 /** 1450 * Get the highest supported target FPS range. 1451 * Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS. 1452 */ getAeMaxTargetFpsRange()1453 public Range<Integer> getAeMaxTargetFpsRange() { 1454 Range<Integer>[] fpsRanges = getAeAvailableTargetFpsRangesChecked(); 1455 1456 Range<Integer> targetRange = fpsRanges[0]; 1457 // Assume unsorted list of target FPS ranges, so use two passes, first maximize min FPS 1458 for (Range<Integer> candidateRange : fpsRanges) { 1459 if (candidateRange.getLower() > targetRange.getLower()) { 1460 targetRange = candidateRange; 1461 } 1462 } 1463 // Then maximize max FPS while not lowering min FPS 1464 for (Range<Integer> candidateRange : fpsRanges) { 1465 if (candidateRange.getLower() >= targetRange.getLower() && 1466 candidateRange.getUpper() > targetRange.getUpper()) { 1467 targetRange = candidateRange; 1468 } 1469 } 1470 return targetRange; 1471 } 1472 1473 /** 1474 * Get max frame duration. 1475 * 1476 * @return 0 if maxFrameDuration is null 1477 */ getMaxFrameDurationChecked()1478 public long getMaxFrameDurationChecked() { 1479 Key<Long> key = 1480 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION; 1481 Long maxDuration = getValueFromKeyNonNull(key); 1482 1483 if (maxDuration == null) { 1484 return 0; 1485 } 1486 1487 return maxDuration; 1488 } 1489 1490 /** 1491 * Get available minimal frame durations for a given format. 1492 * 1493 * @param format One of the format from {@link ImageFormat}. 1494 * @return HashMap of minimal frame durations for different sizes, empty HashMap 1495 * if availableMinFrameDurations is null. 1496 */ getAvailableMinFrameDurationsForFormatChecked(int format)1497 public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) { 1498 1499 HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>(); 1500 1501 Key<StreamConfigurationMap> key = 1502 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP; 1503 StreamConfigurationMap config = getValueFromKeyNonNull(key); 1504 1505 if (config == null) { 1506 return minDurationMap; 1507 } 1508 1509 for (Size size : getAvailableSizesForFormatChecked(format, 1510 StreamDirection.Output)) { 1511 long minFrameDuration = config.getOutputMinFrameDuration(format, size); 1512 1513 if (minFrameDuration != 0) { 1514 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration); 1515 } 1516 } 1517 1518 return minDurationMap; 1519 } 1520 getAvailableEdgeModesChecked()1521 public int[] getAvailableEdgeModesChecked() { 1522 Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES; 1523 int[] edgeModes = getValueFromKeyNonNull(key); 1524 1525 if (edgeModes == null) { 1526 return new int[0]; 1527 } 1528 1529 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes)); 1530 // Full device should always include OFF and FAST 1531 if (isHardwareLevelFull()) { 1532 checkTrueForKey(key, "Full device must contain OFF and FAST edge modes", 1533 modeList.contains(CameraMetadata.EDGE_MODE_OFF) && 1534 modeList.contains(CameraMetadata.EDGE_MODE_FAST)); 1535 } 1536 1537 if (isHardwareLevelLimitedOrBetter()) { 1538 // FAST and HIGH_QUALITY mode must be both present or both not present 1539 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1540 CameraMetadata.EDGE_MODE_FAST, 1541 CameraMetadata.EDGE_MODE_HIGH_QUALITY 1542 }); 1543 checkTrueForKey( 1544 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1545 containsAllOrNone(modeList, coupledModes)); 1546 } 1547 1548 return edgeModes; 1549 } 1550 getAvailableNoiseReductionModesChecked()1551 public int[] getAvailableNoiseReductionModesChecked() { 1552 Key<int[]> key = 1553 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; 1554 int[] noiseReductionModes = getValueFromKeyNonNull(key); 1555 1556 if (noiseReductionModes == null) { 1557 return new int[0]; 1558 } 1559 1560 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes)); 1561 // Full device should always include OFF and FAST 1562 if (isHardwareLevelFull()) { 1563 1564 checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes", 1565 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) && 1566 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST)); 1567 } 1568 1569 if (isHardwareLevelLimitedOrBetter()) { 1570 // FAST and HIGH_QUALITY mode must be both present or both not present 1571 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1572 CameraMetadata.NOISE_REDUCTION_MODE_FAST, 1573 CameraMetadata.NOISE_REDUCTION_MODE_HIGH_QUALITY 1574 }); 1575 checkTrueForKey( 1576 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1577 containsAllOrNone(modeList, coupledModes)); 1578 } 1579 return noiseReductionModes; 1580 } 1581 1582 /** 1583 * Get value of key android.control.aeCompensationStep and do the validation check. 1584 * 1585 * @return default value if the value is null. 1586 */ getAeCompensationStepChecked()1587 public Rational getAeCompensationStepChecked() { 1588 Key<Rational> key = 1589 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP; 1590 Rational compensationStep = getValueFromKeyNonNull(key); 1591 1592 if (compensationStep == null) { 1593 // Return default step. 1594 return CONTROL_AE_COMPENSATION_STEP_DEFAULT; 1595 } 1596 1597 // Legacy devices don't have a minimum step requirement 1598 if (isHardwareLevelLimitedOrBetter()) { 1599 float compensationStepF = 1600 (float) compensationStep.getNumerator() / compensationStep.getDenominator(); 1601 checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f); 1602 } 1603 1604 return compensationStep; 1605 } 1606 1607 /** 1608 * Get value of key android.control.aeCompensationRange and do the validation check. 1609 * 1610 * @return default value if the value is null or malformed. 1611 */ getAeCompensationRangeChecked()1612 public Range<Integer> getAeCompensationRangeChecked() { 1613 Key<Range<Integer>> key = 1614 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE; 1615 Range<Integer> compensationRange = getValueFromKeyNonNull(key); 1616 Rational compensationStep = getAeCompensationStepChecked(); 1617 float compensationStepF = compensationStep.floatValue(); 1618 final Range<Integer> DEFAULT_RANGE = Range.create( 1619 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN / compensationStepF), 1620 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF)); 1621 final Range<Integer> ZERO_RANGE = Range.create(0, 0); 1622 if (compensationRange == null) { 1623 return ZERO_RANGE; 1624 } 1625 1626 // Legacy devices don't have a minimum range requirement 1627 if (isHardwareLevelLimitedOrBetter() && !compensationRange.equals(ZERO_RANGE)) { 1628 checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE 1629 + ", actual " + compensationRange + ", compensation step " + compensationStep, 1630 compensationRange.getLower() <= DEFAULT_RANGE.getLower() && 1631 compensationRange.getUpper() >= DEFAULT_RANGE.getUpper()); 1632 } 1633 1634 return compensationRange; 1635 } 1636 1637 /** 1638 * Get availableVideoStabilizationModes and do the validation check. 1639 * 1640 * @return available video stabilization modes, empty array if it is unavailable. 1641 */ getAvailableVideoStabilizationModesChecked()1642 public int[] getAvailableVideoStabilizationModesChecked() { 1643 Key<int[]> key = 1644 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; 1645 int[] modes = getValueFromKeyNonNull(key); 1646 1647 if (modes == null) { 1648 return new int[0]; 1649 } 1650 1651 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1652 checkTrueForKey(key, " All device should support OFF mode", 1653 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF)); 1654 checkArrayValuesInRange(key, modes, 1655 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF, 1656 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); 1657 1658 return modes; 1659 } 1660 isVideoStabilizationSupported()1661 public boolean isVideoStabilizationSupported() { 1662 Integer[] videoStabModes = 1663 CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked()); 1664 return Arrays.asList(videoStabModes).contains( 1665 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON); 1666 } 1667 1668 /** 1669 * Get availableOpticalStabilization and do the validation check. 1670 * 1671 * @return available optical stabilization modes, empty array if it is unavailable. 1672 */ getAvailableOpticalStabilizationChecked()1673 public int[] getAvailableOpticalStabilizationChecked() { 1674 Key<int[]> key = 1675 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; 1676 int[] modes = getValueFromKeyNonNull(key); 1677 1678 if (modes == null) { 1679 return new int[0]; 1680 } 1681 1682 checkArrayValuesInRange(key, modes, 1683 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF, 1684 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON); 1685 1686 return modes; 1687 } 1688 1689 /** 1690 * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array 1691 * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable 1692 */ getAvailableMaxDigitalZoomChecked()1693 public float getAvailableMaxDigitalZoomChecked() { 1694 Key<Float> key = 1695 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; 1696 1697 Float maxZoom = getValueFromKeyNonNull(key); 1698 if (maxZoom == null) { 1699 return 1.0f; 1700 } 1701 1702 checkTrueForKey(key, " max digital zoom should be no less than 1", 1703 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom)); 1704 1705 return maxZoom; 1706 } 1707 getAvailableSceneModesChecked()1708 public int[] getAvailableSceneModesChecked() { 1709 Key<int[]> key = 1710 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES; 1711 int[] modes = getValueFromKeyNonNull(key); 1712 1713 if (modes == null) { 1714 return new int[0]; 1715 } 1716 1717 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1718 // FACE_PRIORITY must be included if face detection is supported. 1719 if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) && 1720 getMaxFaceCountChecked() > 0) { 1721 checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported", 1722 modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY)); 1723 } 1724 1725 return modes; 1726 } 1727 getAvailableEffectModesChecked()1728 public int[] getAvailableEffectModesChecked() { 1729 Key<int[]> key = 1730 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS; 1731 int[] modes = getValueFromKeyNonNull(key); 1732 1733 if (modes == null) { 1734 return new int[0]; 1735 } 1736 1737 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1738 // OFF must be included. 1739 checkTrueForKey(key, " OFF must be included", 1740 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF)); 1741 1742 return modes; 1743 } 1744 1745 /** 1746 * Get and check the available color aberration modes 1747 * 1748 * @return the available color aberration modes 1749 */ getAvailableColorAberrationModesChecked()1750 public int[] getAvailableColorAberrationModesChecked() { 1751 Key<int[]> key = 1752 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; 1753 int[] modes = getValueFromKeyNonNull(key); 1754 1755 if (modes == null) { 1756 return new int[0]; 1757 } 1758 1759 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1760 checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode", 1761 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) || 1762 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST)); 1763 1764 if (isHardwareLevelLimitedOrBetter()) { 1765 // FAST and HIGH_QUALITY mode must be both present or both not present 1766 List<Integer> coupledModes = Arrays.asList(new Integer[] { 1767 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST, 1768 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY 1769 }); 1770 checkTrueForKey( 1771 key, " FAST and HIGH_QUALITY mode must both present or both not present", 1772 containsAllOrNone(modeList, coupledModes)); 1773 } 1774 checkElementDistinct(key, modeList); 1775 checkArrayValuesInRange(key, modes, 1776 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF, 1777 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY); 1778 1779 return modes; 1780 } 1781 1782 /** 1783 * Get max pipeline depth and do the validation check. 1784 * 1785 * @return max pipeline depth, default value if it is not available. 1786 */ getPipelineMaxDepthChecked()1787 public byte getPipelineMaxDepthChecked() { 1788 Key<Byte> key = 1789 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH; 1790 Byte maxDepth = getValueFromKeyNonNull(key); 1791 1792 if (maxDepth == null) { 1793 return REQUEST_PIPELINE_MAX_DEPTH_MAX; 1794 } 1795 1796 checkTrueForKey(key, " max pipeline depth should be no larger than " 1797 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX); 1798 1799 return maxDepth; 1800 } 1801 1802 /** 1803 * Get available lens shading modes. 1804 */ getAvailableLensShadingModesChecked()1805 public int[] getAvailableLensShadingModesChecked() { 1806 Key<int[]> key = 1807 CameraCharacteristics.SHADING_AVAILABLE_MODES; 1808 int[] modes = getValueFromKeyNonNull(key); 1809 if (modes == null) { 1810 return new int[0]; 1811 } 1812 1813 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1814 // FAST must be included. 1815 checkTrueForKey(key, " FAST must be included", 1816 modeList.contains(CameraMetadata.SHADING_MODE_FAST)); 1817 1818 if (isCapabilitySupported( 1819 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) { 1820 checkTrueForKey(key, " OFF must be included for MANUAL_POST_PROCESSING devices", 1821 modeList.contains(CameraMetadata.SHADING_MODE_OFF)); 1822 } 1823 return modes; 1824 } 1825 1826 /** 1827 * Get available lens shading map modes. 1828 */ getAvailableLensShadingMapModesChecked()1829 public int[] getAvailableLensShadingMapModesChecked() { 1830 Key<int[]> key = 1831 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES; 1832 int[] modes = getValueFromKeyNonNull(key); 1833 if (modes == null) { 1834 return new int[0]; 1835 } 1836 1837 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes)); 1838 1839 if (isCapabilitySupported( 1840 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 1841 checkTrueForKey(key, " ON must be included for RAW capability devices", 1842 modeList.contains(CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON)); 1843 } 1844 return modes; 1845 } 1846 1847 1848 /** 1849 * Get available capabilities and do the validation check. 1850 * 1851 * @return reported available capabilities list, empty list if the value is unavailable. 1852 */ getAvailableCapabilitiesChecked()1853 public List<Integer> getAvailableCapabilitiesChecked() { 1854 Key<int[]> key = 1855 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES; 1856 int[] availableCaps = getValueFromKeyNonNull(key); 1857 List<Integer> capList; 1858 1859 if (availableCaps == null) { 1860 return new ArrayList<Integer>(); 1861 } 1862 1863 capList = Arrays.asList(CameraTestUtils.toObject(availableCaps)); 1864 return capList; 1865 } 1866 1867 /** 1868 * Determine whether the current device supports a capability or not. 1869 * 1870 * @param capability (non-negative) 1871 * 1872 * @return {@code true} if the capability is supported, {@code false} otherwise. 1873 * 1874 * @throws IllegalArgumentException if {@code capability} was negative 1875 * 1876 * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES 1877 */ isCapabilitySupported(int capability)1878 public boolean isCapabilitySupported(int capability) { 1879 if (capability < 0) { 1880 throw new IllegalArgumentException("capability must be non-negative"); 1881 } 1882 1883 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 1884 1885 return availableCapabilities.contains(capability); 1886 } 1887 1888 /** 1889 * Determine whether or not all the {@code keys} are available characteristics keys 1890 * (as in {@link CameraCharacteristics#getKeys}. 1891 * 1892 * <p>If this returns {@code true}, then querying for this key from a characteristics 1893 * object will always return a non-{@code null} value.</p> 1894 * 1895 * @param keys collection of camera characteristics keys 1896 * @return whether or not all characteristics keys are available 1897 */ areCharacteristicsKeysAvailable( Collection<Key<?>> keys)1898 public final boolean areCharacteristicsKeysAvailable( 1899 Collection<Key<?>> keys) { 1900 return mCharacteristics.getKeys().containsAll(keys); 1901 } 1902 1903 /** 1904 * Determine whether or not all the {@code keys} are available result keys 1905 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 1906 * 1907 * <p>If this returns {@code true}, then querying for this key from a result 1908 * object will almost always return a non-{@code null} value.</p> 1909 * 1910 * <p>In some cases (e.g. lens shading map), the request must have additional settings 1911 * configured in order for the key to correspond to a value.</p> 1912 * 1913 * @param keys collection of capture result keys 1914 * @return whether or not all result keys are available 1915 */ areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys)1916 public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) { 1917 return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys); 1918 } 1919 1920 /** 1921 * Determine whether or not all the {@code keys} are available request keys 1922 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 1923 * 1924 * <p>If this returns {@code true}, then setting this key in the request builder 1925 * may have some effect (and if it's {@code false}, then the camera device will 1926 * definitely ignore it).</p> 1927 * 1928 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 1929 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 1930 * 1931 * @param keys collection of capture request keys 1932 * @return whether or not all result keys are available 1933 */ areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys)1934 public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) { 1935 return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys); 1936 } 1937 1938 /** 1939 * Determine whether or not all the {@code keys} are available characteristics keys 1940 * (as in {@link CameraCharacteristics#getKeys}. 1941 * 1942 * <p>If this returns {@code true}, then querying for this key from a characteristics 1943 * object will always return a non-{@code null} value.</p> 1944 * 1945 * @param keys one or more camera characteristic keys 1946 * @return whether or not all characteristics keys are available 1947 */ 1948 @SafeVarargs areKeysAvailable(Key<?>.... keys)1949 public final boolean areKeysAvailable(Key<?>... keys) { 1950 return areCharacteristicsKeysAvailable(Arrays.asList(keys)); 1951 } 1952 1953 /** 1954 * Determine whether or not all the {@code keys} are available result keys 1955 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}. 1956 * 1957 * <p>If this returns {@code true}, then querying for this key from a result 1958 * object will almost always return a non-{@code null} value.</p> 1959 * 1960 * <p>In some cases (e.g. lens shading map), the request must have additional settings 1961 * configured in order for the key to correspond to a value.</p> 1962 * 1963 * @param keys one or more capture result keys 1964 * @return whether or not all result keys are available 1965 */ 1966 @SafeVarargs areKeysAvailable(CaptureResult.Key<?>.... keys)1967 public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) { 1968 return areResultKeysAvailable(Arrays.asList(keys)); 1969 } 1970 1971 /** 1972 * Determine whether or not all the {@code keys} are available request keys 1973 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}. 1974 * 1975 * <p>If this returns {@code true}, then setting this key in the request builder 1976 * may have some effect (and if it's {@code false}, then the camera device will 1977 * definitely ignore it).</p> 1978 * 1979 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set 1980 * in order for a key to take effect (e.g. control.mode set to OFF).</p> 1981 * 1982 * @param keys one or more capture request keys 1983 * @return whether or not all result keys are available 1984 */ 1985 @SafeVarargs areKeysAvailable(CaptureRequest.Key<?>.... keys)1986 public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) { 1987 return areRequestKeysAvailable(Arrays.asList(keys)); 1988 } 1989 1990 /* 1991 * Determine if camera device support AE lock control 1992 * 1993 * @return {@code true} if AE lock control is supported 1994 */ isAeLockSupported()1995 public boolean isAeLockSupported() { 1996 return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 1997 } 1998 1999 /* 2000 * Determine if camera device support AWB lock control 2001 * 2002 * @return {@code true} if AWB lock control is supported 2003 */ isAwbLockSupported()2004 public boolean isAwbLockSupported() { 2005 return getValueFromKeyNonNull(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 2006 } 2007 2008 2009 /* 2010 * Determine if camera device support manual lens shading map control 2011 * 2012 * @return {@code true} if manual lens shading map control is supported 2013 */ isManualLensShadingMapSupported()2014 public boolean isManualLensShadingMapSupported() { 2015 return areKeysAvailable(CaptureRequest.SHADING_MODE); 2016 } 2017 2018 /** 2019 * Determine if camera device support manual color correction control 2020 * 2021 * @return {@code true} if manual color correction control is supported 2022 */ isColorCorrectionSupported()2023 public boolean isColorCorrectionSupported() { 2024 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE); 2025 } 2026 2027 /** 2028 * Determine if camera device support manual tone mapping control 2029 * 2030 * @return {@code true} if manual tone mapping control is supported 2031 */ isManualToneMapSupported()2032 public boolean isManualToneMapSupported() { 2033 return areKeysAvailable(CaptureRequest.TONEMAP_MODE); 2034 } 2035 2036 /** 2037 * Determine if camera device support manual color aberration control 2038 * 2039 * @return {@code true} if manual color aberration control is supported 2040 */ isManualColorAberrationControlSupported()2041 public boolean isManualColorAberrationControlSupported() { 2042 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE); 2043 } 2044 2045 /** 2046 * Determine if camera device support edge mode control 2047 * 2048 * @return {@code true} if edge mode control is supported 2049 */ isEdgeModeControlSupported()2050 public boolean isEdgeModeControlSupported() { 2051 return areKeysAvailable(CaptureRequest.EDGE_MODE); 2052 } 2053 2054 /** 2055 * Determine if camera device support hot pixel mode control 2056 * 2057 * @return {@code true} if hot pixel mode control is supported 2058 */ isHotPixelMapModeControlSupported()2059 public boolean isHotPixelMapModeControlSupported() { 2060 return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE); 2061 } 2062 2063 /** 2064 * Determine if camera device support noise reduction mode control 2065 * 2066 * @return {@code true} if noise reduction mode control is supported 2067 */ isNoiseReductionModeControlSupported()2068 public boolean isNoiseReductionModeControlSupported() { 2069 return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE); 2070 } 2071 2072 /** 2073 * Get max number of output raw streams and do the basic validation check. 2074 * 2075 * @return reported max number of raw output stream 2076 */ getMaxNumOutputStreamsRawChecked()2077 public int getMaxNumOutputStreamsRawChecked() { 2078 Integer maxNumStreams = 2079 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW); 2080 if (maxNumStreams == null) 2081 return 0; 2082 return maxNumStreams; 2083 } 2084 2085 /** 2086 * Get max number of output processed streams and do the basic validation check. 2087 * 2088 * @return reported max number of processed output stream 2089 */ getMaxNumOutputStreamsProcessedChecked()2090 public int getMaxNumOutputStreamsProcessedChecked() { 2091 Integer maxNumStreams = 2092 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC); 2093 if (maxNumStreams == null) 2094 return 0; 2095 return maxNumStreams; 2096 } 2097 2098 /** 2099 * Get max number of output stalling processed streams and do the basic validation check. 2100 * 2101 * @return reported max number of stalling processed output stream 2102 */ getMaxNumOutputStreamsProcessedStallChecked()2103 public int getMaxNumOutputStreamsProcessedStallChecked() { 2104 Integer maxNumStreams = 2105 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING); 2106 if (maxNumStreams == null) 2107 return 0; 2108 return maxNumStreams; 2109 } 2110 2111 /** 2112 * Get lens facing and do the validation check 2113 * @return lens facing, return default value (BACK) if value is unavailable. 2114 */ getLensFacingChecked()2115 public int getLensFacingChecked() { 2116 Key<Integer> key = 2117 CameraCharacteristics.LENS_FACING; 2118 Integer facing = getValueFromKeyNonNull(key); 2119 2120 if (facing == null) { 2121 return CameraCharacteristics.LENS_FACING_BACK; 2122 } 2123 2124 checkTrueForKey(key, " value is out of range ", 2125 facing >= CameraCharacteristics.LENS_FACING_FRONT && 2126 facing <= CameraCharacteristics.LENS_FACING_BACK); 2127 return facing; 2128 } 2129 2130 /** 2131 * Get maxCaptureStall frames or default value (if value doesn't exist) 2132 * @return maxCaptureStall frames or default value. 2133 */ getMaxCaptureStallOrDefault()2134 public int getMaxCaptureStallOrDefault() { 2135 Key<Integer> key = 2136 CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL; 2137 Integer value = getValueFromKeyNonNull(key); 2138 2139 if (value == null) { 2140 return MAX_REPROCESS_MAX_CAPTURE_STALL; 2141 } 2142 2143 checkTrueForKey(key, " value is out of range ", 2144 value >= 0 && 2145 value <= MAX_REPROCESS_MAX_CAPTURE_STALL); 2146 2147 return value; 2148 } 2149 2150 /** 2151 * Get the scaler's cropping type (center only or freeform) 2152 * @return cropping type, return default value (CENTER_ONLY) if value is unavailable 2153 */ getScalerCroppingTypeChecked()2154 public int getScalerCroppingTypeChecked() { 2155 Key<Integer> key = 2156 CameraCharacteristics.SCALER_CROPPING_TYPE; 2157 Integer value = getValueFromKeyNonNull(key); 2158 2159 if (value == null) { 2160 return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY; 2161 } 2162 2163 checkTrueForKey(key, " value is out of range ", 2164 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY && 2165 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM); 2166 2167 return value; 2168 } 2169 2170 /** 2171 * Check if the constrained high speed video is supported by the camera device. 2172 * The high speed FPS ranges and sizes are sanitized in 2173 * ExtendedCameraCharacteristicsTest#testConstrainedHighSpeedCapability. 2174 * 2175 * @return true if the constrained high speed video is supported, false otherwise. 2176 */ isConstrainedHighSpeedVideoSupported()2177 public boolean isConstrainedHighSpeedVideoSupported() { 2178 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked(); 2179 return (availableCapabilities.contains( 2180 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO)); 2181 } 2182 2183 /** 2184 * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is 2185 * supported, supported high speed fps ranges and sizes are valid). 2186 * 2187 * @return true if high speed video is supported. 2188 */ isHighSpeedVideoSupported()2189 public boolean isHighSpeedVideoSupported() { 2190 List<Integer> sceneModes = 2191 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked())); 2192 if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) { 2193 StreamConfigurationMap config = 2194 getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 2195 if (config == null) { 2196 return false; 2197 } 2198 Size[] availableSizes = config.getHighSpeedVideoSizes(); 2199 if (availableSizes.length == 0) { 2200 return false; 2201 } 2202 2203 for (Size size : availableSizes) { 2204 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size); 2205 if (availableFpsRanges.length == 0) { 2206 return false; 2207 } 2208 } 2209 2210 return true; 2211 } else { 2212 return false; 2213 } 2214 } 2215 2216 /** 2217 * Check if depth output is supported, based on the depth capability 2218 */ isDepthOutputSupported()2219 public boolean isDepthOutputSupported() { 2220 return isCapabilitySupported( 2221 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 2222 } 2223 2224 /** 2225 * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the 2226 * backwards-compatible capability 2227 */ isColorOutputSupported()2228 public boolean isColorOutputSupported() { 2229 return isCapabilitySupported( 2230 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 2231 } 2232 2233 /** 2234 * Check if optical black regions key is supported. 2235 */ isOpticalBlackRegionSupported()2236 public boolean isOpticalBlackRegionSupported() { 2237 return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS); 2238 } 2239 2240 /** 2241 * Check if the dynamic black level is supported. 2242 * 2243 * <p> 2244 * Note that: This also indicates if the white level is supported, as dynamic black and white 2245 * level must be all supported or none of them is supported. 2246 * </p> 2247 */ isDynamicBlackLevelSupported()2248 public boolean isDynamicBlackLevelSupported() { 2249 return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 2250 } 2251 2252 /** 2253 * Get the value in index for a fixed-size array from a given key. 2254 * 2255 * <p>If the camera device is incorrectly reporting values, log a warning and return 2256 * the default value instead.</p> 2257 * 2258 * @param key Key to fetch 2259 * @param defaultValue Default value to return if camera device uses invalid values 2260 * @param name Human-readable name for the array index (logging only) 2261 * @param index Array index of the subelement 2262 * @param size Expected fixed size of the array 2263 * 2264 * @return The value reported by the camera device, or the defaultValue otherwise. 2265 */ getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, int size)2266 private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index, 2267 int size) { 2268 T elementValue = getArrayElementCheckRangeNonNull( 2269 key, 2270 index, 2271 size); 2272 2273 if (elementValue == null) { 2274 failKeyCheck(key, 2275 "had no valid " + name + " value; using default of " + defaultValue); 2276 elementValue = defaultValue; 2277 } 2278 2279 return elementValue; 2280 } 2281 2282 /** 2283 * Fetch an array sub-element from an array value given by a key. 2284 * 2285 * <p> 2286 * Prints a warning if the sub-element was null. 2287 * </p> 2288 * 2289 * <p>Use for variable-size arrays since this does not check the array size.</p> 2290 * 2291 * @param key Metadata key to look up 2292 * @param element A non-negative index value. 2293 * @return The array sub-element, or null if the checking failed. 2294 */ getArrayElementNonNull(Key<?> key, int element)2295 private <T> T getArrayElementNonNull(Key<?> key, int element) { 2296 return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK); 2297 } 2298 2299 /** 2300 * Fetch an array sub-element from an array value given by a key. 2301 * 2302 * <p> 2303 * Prints a warning if the array size does not match the size, or if the sub-element was null. 2304 * </p> 2305 * 2306 * @param key Metadata key to look up 2307 * @param element The index in [0,size) 2308 * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK} 2309 * @return The array sub-element, or null if the checking failed. 2310 */ getArrayElementCheckRangeNonNull(Key<?> key, int element, int size)2311 private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) { 2312 Object array = getValueFromKeyNonNull(key); 2313 2314 if (array == null) { 2315 // Warning already printed 2316 return null; 2317 } 2318 2319 if (size != IGNORE_SIZE_CHECK) { 2320 int actualLength = Array.getLength(array); 2321 if (actualLength != size) { 2322 failKeyCheck(key, 2323 String.format("had the wrong number of elements (%d), expected (%d)", 2324 actualLength, size)); 2325 return null; 2326 } 2327 } 2328 2329 @SuppressWarnings("unchecked") 2330 T val = (T) Array.get(array, element); 2331 2332 if (val == null) { 2333 failKeyCheck(key, "had a null element at index" + element); 2334 return null; 2335 } 2336 2337 return val; 2338 } 2339 2340 /** 2341 * Gets the key, logging warnings for null values. 2342 */ getValueFromKeyNonNull(Key<T> key)2343 public <T> T getValueFromKeyNonNull(Key<T> key) { 2344 if (key == null) { 2345 throw new IllegalArgumentException("key was null"); 2346 } 2347 2348 T value = mCharacteristics.get(key); 2349 2350 if (value == null) { 2351 failKeyCheck(key, "was null"); 2352 } 2353 2354 return value; 2355 } 2356 checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max)2357 private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) { 2358 for (int value : array) { 2359 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 2360 value <= max && value >= min); 2361 } 2362 } 2363 checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max)2364 private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) { 2365 for (byte value : array) { 2366 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max), 2367 value <= max && value >= min); 2368 } 2369 } 2370 2371 /** 2372 * Check the uniqueness of the values in a list. 2373 * 2374 * @param key The key to be checked 2375 * @param list The list contains the value of the key 2376 */ checkElementDistinct(Key<U> key, List<T> list)2377 private <U, T> void checkElementDistinct(Key<U> key, List<T> list) { 2378 // Each size must be distinct. 2379 Set<T> sizeSet = new HashSet<T>(list); 2380 checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size()); 2381 } 2382 checkTrueForKey(Key<T> key, String message, boolean condition)2383 private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) { 2384 if (!condition) { 2385 failKeyCheck(key, message); 2386 } 2387 } 2388 2389 /* Helper function to check if the coupled modes are either all present or all non-present */ containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes)2390 private <T> boolean containsAllOrNone(Collection<T> observedModes, Collection<T> coupledModes) { 2391 if (observedModes.containsAll(coupledModes)) { 2392 return true; 2393 } 2394 for (T mode : coupledModes) { 2395 if (observedModes.contains(mode)) { 2396 return false; 2397 } 2398 } 2399 return true; 2400 } 2401 failKeyCheck(Key<T> key, String message)2402 private <T> void failKeyCheck(Key<T> key, String message) { 2403 // TODO: Consider only warning once per key/message combination if it's too spammy. 2404 // TODO: Consider offering other options such as throwing an assertion exception 2405 String failureCause = String.format("The static info key '%s' %s", key.getName(), message); 2406 switch (mLevel) { 2407 case WARN: 2408 Log.w(TAG, failureCause); 2409 break; 2410 case COLLECT: 2411 mCollector.addMessage(failureCause); 2412 break; 2413 case ASSERT: 2414 Assert.fail(failureCause); 2415 default: 2416 throw new UnsupportedOperationException("Unhandled level " + mLevel); 2417 } 2418 } 2419 } 2420