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