1 /* 2 * Copyright (C) 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; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.graphics.Rect; 22 import android.graphics.SurfaceTexture; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraCharacteristics.Key; 25 import android.hardware.camera2.CameraManager; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 29 import android.hardware.camera2.params.BlackLevelPattern; 30 import android.hardware.camera2.params.ColorSpaceTransform; 31 import android.hardware.camera2.params.StreamConfigurationMap; 32 import android.media.CamcorderProfile; 33 import android.media.ImageReader; 34 import android.test.AndroidTestCase; 35 import android.util.Log; 36 import android.util.Rational; 37 import android.util.Range; 38 import android.util.Size; 39 import android.view.Surface; 40 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.List; 44 import java.util.Objects; 45 46 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 47 48 /** 49 * Extended tests for static camera characteristics. 50 */ 51 public class ExtendedCameraCharacteristicsTest extends AndroidTestCase { 52 private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw 53 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 54 55 private static final String PREFIX_ANDROID = "android"; 56 private static final String PREFIX_VENDOR = "com"; 57 58 /* 59 * Constants for static RAW metadata. 60 */ 61 private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5 62 63 private CameraManager mCameraManager; 64 private List<CameraCharacteristics> mCharacteristics; 65 private String[] mIds; 66 private CameraErrorCollector mCollector; 67 68 private static final Size FULLHD = new Size(1920, 1080); 69 private static final Size FULLHD_ALT = new Size(1920, 1088); 70 private static final Size HD = new Size(1280, 720); 71 private static final Size VGA = new Size(640, 480); 72 private static final Size QVGA = new Size(320, 240); 73 74 /* 75 * HW Levels short hand 76 */ 77 private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 78 private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; 79 private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL; 80 private static final int LEVEL_3 = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3; 81 private static final int OPT = Integer.MAX_VALUE; // For keys that are optional on all hardware levels. 82 83 /* 84 * Capabilities short hand 85 */ 86 private static final int NONE = -1; 87 private static final int BC = 88 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE; 89 private static final int MANUAL_SENSOR = 90 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR; 91 private static final int MANUAL_POSTPROC = 92 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING; 93 private static final int RAW = 94 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW; 95 private static final int YUV_REPROCESS = 96 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING; 97 private static final int OPAQUE_REPROCESS = 98 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING; 99 private static final int CONSTRAINED_HIGH_SPEED = 100 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO; 101 private static final int HIGH_SPEED_FPS_LOWER_MIN = 30; 102 private static final int HIGH_SPEED_FPS_UPPER_MIN = 120; 103 104 @Override setContext(Context context)105 public void setContext(Context context) { 106 super.setContext(context); 107 mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE); 108 assertNotNull("Can't connect to camera manager", mCameraManager); 109 } 110 111 @Override setUp()112 protected void setUp() throws Exception { 113 super.setUp(); 114 mIds = mCameraManager.getCameraIdList(); 115 mCharacteristics = new ArrayList<>(); 116 mCollector = new CameraErrorCollector(); 117 for (int i = 0; i < mIds.length; i++) { 118 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]); 119 assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]), 120 props); 121 mCharacteristics.add(props); 122 } 123 } 124 125 @Override tearDown()126 protected void tearDown() throws Exception { 127 mCharacteristics = null; 128 129 try { 130 mCollector.verify(); 131 } catch (Throwable e) { 132 // When new Exception(e) is used, exception info will be printed twice. 133 throw new Exception(e.getMessage()); 134 } finally { 135 super.tearDown(); 136 } 137 } 138 139 /** 140 * Test that the available stream configurations contain a few required formats and sizes. 141 */ testAvailableStreamConfigs()142 public void testAvailableStreamConfigs() { 143 int counter = 0; 144 for (CameraCharacteristics c : mCharacteristics) { 145 StreamConfigurationMap config = 146 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 147 assertNotNull(String.format("No stream configuration map found for: ID %s", 148 mIds[counter]), config); 149 int[] outputFormats = config.getOutputFormats(); 150 151 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 152 assertNotNull("android.request.availableCapabilities must never be null", 153 actualCapabilities); 154 155 // Check required formats exist (JPEG, and YUV_420_888). 156 if (!arrayContains(actualCapabilities, BC)) { 157 Log.i(TAG, "Camera " + mIds[counter] + 158 ": BACKWARD_COMPATIBLE capability not supported, skipping test"); 159 continue; 160 } 161 162 assertArrayContains( 163 String.format("No valid YUV_420_888 preview formats found for: ID %s", 164 mIds[counter]), outputFormats, ImageFormat.YUV_420_888); 165 assertArrayContains(String.format("No JPEG image format for: ID %s", 166 mIds[counter]), outputFormats, ImageFormat.JPEG); 167 168 Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888); 169 Size[] jpegSizes = config.getOutputSizes(ImageFormat.JPEG); 170 Size[] privateSizes = config.getOutputSizes(ImageFormat.PRIVATE); 171 172 CameraTestUtils.assertArrayNotEmpty(yuvSizes, 173 String.format("No sizes for preview format %x for: ID %s", 174 ImageFormat.YUV_420_888, mIds[counter])); 175 176 Rect activeRect = CameraTestUtils.getValueNotNull( 177 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 178 Size activeArraySize = new Size(activeRect.width(), activeRect.height()); 179 Integer hwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 180 181 if (activeArraySize.getWidth() >= FULLHD.getWidth() && 182 activeArraySize.getHeight() >= FULLHD.getHeight()) { 183 assertArrayContainsAnyOf(String.format( 184 "Required FULLHD size not found for format %x for: ID %s", 185 ImageFormat.JPEG, mIds[counter]), jpegSizes, 186 new Size[] {FULLHD, FULLHD_ALT}); 187 } 188 189 if (activeArraySize.getWidth() >= HD.getWidth() && 190 activeArraySize.getHeight() >= HD.getHeight()) { 191 assertArrayContains(String.format( 192 "Required HD size not found for format %x for: ID %s", 193 ImageFormat.JPEG, mIds[counter]), jpegSizes, HD); 194 } 195 196 if (activeArraySize.getWidth() >= VGA.getWidth() && 197 activeArraySize.getHeight() >= VGA.getHeight()) { 198 assertArrayContains(String.format( 199 "Required VGA size not found for format %x for: ID %s", 200 ImageFormat.JPEG, mIds[counter]), jpegSizes, VGA); 201 } 202 203 if (activeArraySize.getWidth() >= QVGA.getWidth() && 204 activeArraySize.getHeight() >= QVGA.getHeight()) { 205 assertArrayContains(String.format( 206 "Required QVGA size not found for format %x for: ID %s", 207 ImageFormat.JPEG, mIds[counter]), jpegSizes, QVGA); 208 } 209 210 ArrayList<Size> jpegSizesList = new ArrayList<>(Arrays.asList(jpegSizes)); 211 ArrayList<Size> yuvSizesList = new ArrayList<>(Arrays.asList(yuvSizes)); 212 ArrayList<Size> privateSizesList = new ArrayList<>(Arrays.asList(privateSizes)); 213 214 int cameraId = Integer.valueOf(mIds[counter]); 215 CamcorderProfile maxVideoProfile = CamcorderProfile.get( 216 cameraId, CamcorderProfile.QUALITY_HIGH); 217 Size maxVideoSize = new Size( 218 maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight); 219 220 // Handle FullHD special case first 221 if (jpegSizesList.contains(FULLHD)) { 222 if (hwLevel >= LEVEL_3 || hwLevel == FULL || (hwLevel == LIMITED && 223 maxVideoSize.getWidth() >= FULLHD.getWidth() && 224 maxVideoSize.getHeight() >= FULLHD.getHeight())) { 225 boolean yuvSupportFullHD = yuvSizesList.contains(FULLHD) || 226 yuvSizesList.contains(FULLHD_ALT); 227 boolean privateSupportFullHD = privateSizesList.contains(FULLHD) || 228 privateSizesList.contains(FULLHD_ALT); 229 assertTrue("Full device FullHD YUV size not found", yuvSupportFullHD); 230 assertTrue("Full device FullHD PRIVATE size not found", privateSupportFullHD); 231 } 232 // remove all FullHD or FullHD_Alt sizes for the remaining of the test 233 jpegSizesList.remove(FULLHD); 234 jpegSizesList.remove(FULLHD_ALT); 235 } 236 237 // Check all sizes other than FullHD 238 if (hwLevel == LIMITED) { 239 // Remove all jpeg sizes larger than max video size 240 ArrayList<Size> toBeRemoved = new ArrayList<>(); 241 for (Size size : jpegSizesList) { 242 if (size.getWidth() >= maxVideoSize.getWidth() && 243 size.getHeight() >= maxVideoSize.getHeight()) { 244 toBeRemoved.add(size); 245 } 246 } 247 jpegSizesList.removeAll(toBeRemoved); 248 } 249 250 if (hwLevel >= LEVEL_3 || hwLevel == FULL || hwLevel == LIMITED) { 251 if (!yuvSizesList.containsAll(jpegSizesList)) { 252 for (Size s : jpegSizesList) { 253 if (!yuvSizesList.contains(s)) { 254 fail("Size " + s + " not found in YUV format"); 255 } 256 } 257 } 258 } 259 260 if (!privateSizesList.containsAll(yuvSizesList)) { 261 for (Size s : yuvSizesList) { 262 if (!privateSizesList.contains(s)) { 263 fail("Size " + s + " not found in PRIVATE format"); 264 } 265 } 266 } 267 268 counter++; 269 } 270 } 271 272 /** 273 * Test {@link CameraCharacteristics#getKeys} 274 */ testKeys()275 public void testKeys() { 276 int counter = 0; 277 for (CameraCharacteristics c : mCharacteristics) { 278 mCollector.setCameraId(mIds[counter]); 279 280 if (VERBOSE) { 281 Log.v(TAG, "testKeys - testing characteristics for camera " + mIds[counter]); 282 } 283 284 List<CameraCharacteristics.Key<?>> allKeys = c.getKeys(); 285 assertNotNull("Camera characteristics keys must not be null", allKeys); 286 assertFalse("Camera characteristics keys must have at least 1 key", 287 allKeys.isEmpty()); 288 289 for (CameraCharacteristics.Key<?> key : allKeys) { 290 assertKeyPrefixValid(key.getName()); 291 292 // All characteristics keys listed must never be null 293 mCollector.expectKeyValueNotNull(c, key); 294 295 // TODO: add a check that key must not be @hide 296 } 297 298 /* 299 * List of keys that must be present in camera characteristics (not null). 300 * 301 * Keys for LIMITED, FULL devices might be available despite lacking either 302 * the hardware level or the capability. This is *OK*. This only lists the 303 * *minimal* requirements for a key to be listed. 304 * 305 * LEGACY devices are a bit special since they map to api1 devices, so we know 306 * for a fact most keys are going to be illegal there so they should never be 307 * available. 308 * 309 * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to 310 * do the actual checking. 311 */ 312 { 313 // (Key Name) (HW Level) (Capabilities <Var-Arg>) 314 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES , OPT , BC ); 315 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES , OPT , BC ); 316 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES , OPT , BC ); 317 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES , OPT , BC ); 318 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES , OPT , BC ); 319 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE , OPT , BC ); 320 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP , OPT , BC ); 321 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE , OPT , BC ); 322 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES , OPT , BC ); 323 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS , OPT , BC ); 324 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES , OPT , BC ); 325 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES , OPT , BC ); 326 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES , OPT , BC ); 327 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE , OPT , BC ); 328 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE , OPT , BC ); 329 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF , OPT , BC ); 330 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB , OPT , BC ); 331 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES , FULL , NONE ); 332 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE , OPT , BC ); 333 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES , OPT , RAW ); 334 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL , OPT , BC ); 335 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES , OPT , BC ); 336 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING , OPT , BC ); 337 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES , FULL , MANUAL_SENSOR ); 338 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES , FULL , MANUAL_SENSOR ); 339 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS , OPT , BC ); 340 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION , LIMITED , BC ); 341 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION , LIMITED , MANUAL_SENSOR ); 342 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE , LIMITED , BC ); 343 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE , LIMITED , BC ); 344 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT , BC ); 345 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES , OPT , BC ); 346 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS , OPT , YUV_REPROCESS, OPAQUE_REPROCESS); 347 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , CONSTRAINED_HIGH_SPEED); 348 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC , OPT , BC ); 349 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING , OPT , BC ); 350 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW , OPT , BC ); 351 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT , OPT , BC ); 352 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH , OPT , BC ); 353 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM , OPT , BC ); 354 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP , OPT , BC ); 355 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE , OPT , BC ); 356 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES , OPT , BC ); 357 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN , FULL , MANUAL_SENSOR, RAW ); 358 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1 , OPT , RAW ); 359 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1 , OPT , RAW ); 360 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1 , OPT , RAW ); 361 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE , OPT , BC, RAW ); 362 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT , FULL , RAW ); 363 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE , FULL , MANUAL_SENSOR ); 364 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION , FULL , MANUAL_SENSOR ); 365 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE , OPT , BC ); 366 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE , OPT , BC ); 367 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE , FULL , MANUAL_SENSOR ); 368 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL , OPT , RAW ); 369 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE , OPT , BC ); 370 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY , FULL , MANUAL_SENSOR ); 371 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION , OPT , BC ); 372 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1 , OPT , RAW ); 373 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES , LIMITED , MANUAL_POSTPROC, RAW ); 374 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES , OPT , BC ); 375 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES , OPT , RAW ); 376 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED , RAW ); 377 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT , OPT , BC ); 378 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY , OPT , BC ); 379 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES , FULL , MANUAL_POSTPROC ); 380 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS , FULL , MANUAL_POSTPROC ); 381 382 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line 383 384 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list 385 } 386 387 // Only check for these if the second reference illuminant is included 388 if (allKeys.contains(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2)) { 389 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2 , OPT , RAW ); 390 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2 , OPT , RAW ); 391 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2 , OPT , RAW ); 392 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2 , OPT , RAW ); 393 } 394 395 // Required key if any of RAW format output is supported 396 StreamConfigurationMap config = 397 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 398 assertNotNull(String.format("No stream configuration map found for: ID %s", 399 mIds[counter]), config); 400 if (config.isOutputSupportedFor(ImageFormat.RAW_SENSOR) || 401 config.isOutputSupportedFor(ImageFormat.RAW10) || 402 config.isOutputSupportedFor(ImageFormat.RAW12) || 403 config.isOutputSupportedFor(ImageFormat.RAW_PRIVATE)) { 404 expectKeyAvailable(c, 405 CameraCharacteristics.CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, OPT, BC); 406 } 407 counter++; 408 } 409 } 410 411 /** 412 * Test values for static metadata used by the RAW capability. 413 */ testStaticRawCharacteristics()414 public void testStaticRawCharacteristics() { 415 int counter = 0; 416 for (CameraCharacteristics c : mCharacteristics) { 417 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 418 assertNotNull("android.request.availableCapabilities must never be null", 419 actualCapabilities); 420 if (!arrayContains(actualCapabilities, 421 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 422 Log.i(TAG, "RAW capability is not supported in camera " + counter++ + 423 ". Skip the test."); 424 continue; 425 } 426 427 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 428 if (actualHwLevel != null && actualHwLevel == FULL) { 429 mCollector.expectKeyValueContains(c, 430 CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, 431 CameraCharacteristics.HOT_PIXEL_MODE_FAST); 432 } 433 mCollector.expectKeyValueContains(c, 434 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false); 435 mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL, 436 MIN_ALLOWABLE_WHITELEVEL); 437 438 mCollector.expectKeyValueIsIn(c, 439 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, 440 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB, 441 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG, 442 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG, 443 CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR); 444 // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet. 445 446 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1, 447 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 448 CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 449 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 450 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 451 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 452 453 Rational[] zeroes = new Rational[9]; 454 Arrays.fill(zeroes, Rational.ZERO); 455 456 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 457 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 458 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 459 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 460 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 461 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 462 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 463 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 464 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 465 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 466 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 467 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 468 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 469 470 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 471 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 472 if (blackLevel != null) { 473 String blackLevelPatternString = blackLevel.toString(); 474 if (VERBOSE) { 475 Log.v(TAG, "Black level pattern: " + blackLevelPatternString); 476 } 477 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 478 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 479 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 480 if (whitelevel != null) { 481 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 482 whitelevel); 483 } else { 484 mCollector.addMessage( 485 "No WhiteLevel available, cannot check BlackLevelPattern range."); 486 } 487 } 488 489 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 490 counter++; 491 } 492 } 493 494 /** 495 * Test values for static metadata used by the BURST capability. 496 */ testStaticBurstCharacteristics()497 public void testStaticBurstCharacteristics() throws Exception { 498 int counter = 0; 499 final float SIZE_ERROR_MARGIN = 0.03f; 500 for (CameraCharacteristics c : mCharacteristics) { 501 int[] actualCapabilities = CameraTestUtils.getValueNotNull( 502 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 503 504 // Check if the burst capability is defined 505 boolean haveBurstCapability = arrayContains(actualCapabilities, 506 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 507 boolean haveBC = arrayContains(actualCapabilities, 508 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 509 510 if(haveBurstCapability && !haveBC) { 511 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined"); 512 } 513 514 if (!haveBC) continue; 515 516 StreamConfigurationMap config = 517 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 518 assertNotNull(String.format("No stream configuration map found for: ID %s", 519 mIds[counter]), config); 520 Rect activeRect = CameraTestUtils.getValueNotNull( 521 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 522 Size sensorSize = new Size(activeRect.width(), activeRect.height()); 523 524 // Ensure that max YUV size matches max JPEG size 525 Size maxYuvSize = CameraTestUtils.getMaxSize( 526 config.getOutputSizes(ImageFormat.YUV_420_888)); 527 Size maxFastYuvSize = maxYuvSize; 528 529 Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888); 530 if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) { 531 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes); 532 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize}); 533 } 534 535 Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat( 536 ImageFormat.JPEG, mIds[counter], mCameraManager)); 537 538 boolean haveMaxYuv = maxYuvSize != null ? 539 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 540 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 541 542 float croppedWidth = (float)sensorSize.getWidth(); 543 float croppedHeight = (float)sensorSize.getHeight(); 544 float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight(); 545 float maxYuvAspectRatio = (float)maxYuvSize.getWidth() / (float)maxYuvSize.getHeight(); 546 if (sensorAspectRatio < maxYuvAspectRatio) { 547 croppedHeight = (float)sensorSize.getWidth() / maxYuvAspectRatio; 548 } else if (sensorAspectRatio > maxYuvAspectRatio) { 549 croppedWidth = (float)sensorSize.getHeight() * maxYuvAspectRatio; 550 } 551 Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight); 552 553 boolean maxYuvMatchSensor = 554 (maxYuvSize.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) && 555 maxYuvSize.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) && 556 maxYuvSize.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) && 557 maxYuvSize.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN)); 558 559 // No need to do null check since framework will generate the key if HAL don't supply 560 boolean haveAeLock = CameraTestUtils.getValueNotNull( 561 c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 562 boolean haveAwbLock = CameraTestUtils.getValueNotNull( 563 c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 564 565 // Ensure that max YUV output is fast enough - needs to be at least 10 fps 566 567 long maxYuvRate = 568 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize); 569 final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps 570 boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS; 571 572 // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps 573 574 long maxFastYuvRate = 575 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize); 576 final long MIN_8MP_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps 577 boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS; 578 579 final int SIZE_8MP_BOUND = 8000000; 580 boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) > 581 SIZE_8MP_BOUND; 582 583 // Ensure that there's an FPS range that's fast enough to capture at above 584 // minFrameDuration, for full-auto bursts at the fast resolutions 585 Range[] fpsRanges = CameraTestUtils.getValueNotNull( 586 c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 587 float minYuvFps = 1.f / maxFastYuvRate; 588 589 boolean haveFastAeTargetFps = false; 590 for (Range<Integer> r : fpsRanges) { 591 if (r.getLower() >= minYuvFps) { 592 haveFastAeTargetFps = true; 593 break; 594 } 595 } 596 597 // Ensure that maximum sync latency is small enough for fast setting changes, even if 598 // it's not quite per-frame 599 600 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 601 assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]), 602 maxSyncLatencyValue); 603 604 int maxSyncLatency = maxSyncLatencyValue; 605 final long MAX_LATENCY_BOUND = 4; 606 boolean haveFastSyncLatency = 607 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 608 609 if (haveBurstCapability) { 610 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!", 611 slowYuvSizes != null); 612 assertTrue( 613 String.format("BURST-capable camera device %s does not have maximum YUV " + 614 "size that is at least max JPEG size", 615 mIds[counter]), 616 haveMaxYuv); 617 assertTrue( 618 String.format("BURST-capable camera device %s max-resolution " + 619 "YUV frame rate is too slow" + 620 "(%d ns min frame duration reported, less than %d ns expected)", 621 mIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS), 622 haveMaxYuvRate); 623 assertTrue( 624 String.format("BURST-capable camera device %s >= 8MP YUV output " + 625 "frame rate is too slow" + 626 "(%d ns min frame duration reported, less than %d ns expected)", 627 mIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS), 628 haveFastYuvRate); 629 assertTrue( 630 String.format("BURST-capable camera device %s does not list an AE target " + 631 " FPS range with min FPS >= %f, for full-AUTO bursts", 632 mIds[counter], minYuvFps), 633 haveFastAeTargetFps); 634 assertTrue( 635 String.format("BURST-capable camera device %s YUV sync latency is too long" + 636 "(%d frames reported, [0, %d] frames expected)", 637 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND), 638 haveFastSyncLatency); 639 assertTrue( 640 String.format("BURST-capable camera device %s max YUV size %s should be" + 641 "close to active array size %s or cropped active array size %s", 642 mIds[counter], maxYuvSize.toString(), sensorSize.toString(), 643 croppedSensorSize.toString()), 644 maxYuvMatchSensor); 645 assertTrue( 646 String.format("BURST-capable camera device %s does not support AE lock", 647 mIds[counter]), 648 haveAeLock); 649 assertTrue( 650 String.format("BURST-capable camera device %s does not support AWB lock", 651 mIds[counter]), 652 haveAwbLock); 653 } else { 654 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!", 655 slowYuvSizes == null); 656 assertTrue( 657 String.format("Camera device %s has all the requirements for BURST" + 658 " capability but does not report it!", mIds[counter]), 659 !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps && 660 haveFastSyncLatency && maxYuvMatchSensor && 661 haveAeLock && haveAwbLock)); 662 } 663 664 counter++; 665 } 666 } 667 668 /** 669 * Check reprocessing capabilities. 670 */ testReprocessingCharacteristics()671 public void testReprocessingCharacteristics() { 672 int counter = 0; 673 674 for (CameraCharacteristics c : mCharacteristics) { 675 Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mIds[counter]); 676 677 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 678 assertNotNull("android.request.availableCapabilities must never be null", 679 capabilities); 680 boolean supportYUV = arrayContains(capabilities, 681 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 682 boolean supportOpaque = arrayContains(capabilities, 683 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 684 StreamConfigurationMap configs = 685 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 686 Integer maxNumInputStreams = 687 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 688 int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES); 689 int[] availableNoiseReductionModes = c.get( 690 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES); 691 692 int[] inputFormats = configs.getInputFormats(); 693 694 boolean supportZslEdgeMode = false; 695 boolean supportZslNoiseReductionMode = false; 696 boolean supportHiQNoiseReductionMode = false; 697 boolean supportHiQEdgeMode = false; 698 699 if (availableEdgeModes != null) { 700 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 701 contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 702 supportHiQEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 703 contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY); 704 } 705 706 if (availableNoiseReductionModes != null) { 707 supportZslNoiseReductionMode = Arrays.asList( 708 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 709 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 710 supportHiQNoiseReductionMode = Arrays.asList( 711 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 712 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 713 } 714 715 if (supportYUV || supportOpaque) { 716 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 717 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 718 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " + 719 "not supported", supportZslEdgeMode); 720 mCollector.expectTrue("Support reprocessing but " + 721 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported", 722 supportZslNoiseReductionMode); 723 724 // For reprocessing, if we only require OFF and ZSL mode, it will be just like jpeg 725 // encoding. We implicitly require FAST to make reprocessing meaningful, which means 726 // that we also require HIGH_QUALITY. 727 mCollector.expectTrue("Support reprocessing but EDGE_MODE_HIGH_QUALITY is " + 728 "not supported", supportHiQEdgeMode); 729 mCollector.expectTrue("Support reprocessing but " + 730 "NOISE_REDUCTION_MODE_HIGH_QUALITY is not supported", 731 supportHiQNoiseReductionMode); 732 733 // Verify mandatory input formats are supported 734 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing", 735 !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888)); 736 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing", 737 !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE)); 738 739 // max capture stall must be reported if one of the reprocessing is supported. 740 final int MAX_ALLOWED_STALL_FRAMES = 4; 741 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 742 mCollector.expectTrue("max capture stall must be non-null and no larger than " 743 + MAX_ALLOWED_STALL_FRAMES, 744 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 745 746 for (int input : inputFormats) { 747 // Verify mandatory output formats are supported 748 int[] outputFormats = configs.getValidOutputFormatsForInput(input); 749 mCollector.expectTrue("YUV_420_888 output must be supported for reprocessing", 750 arrayContains(outputFormats, ImageFormat.YUV_420_888)); 751 mCollector.expectTrue("JPEG output must be supported for reprocessing", 752 arrayContains(outputFormats, ImageFormat.JPEG)); 753 754 // Verify camera can output the reprocess input formats and sizes. 755 Size[] inputSizes = configs.getInputSizes(input); 756 Size[] outputSizes = configs.getOutputSizes(input); 757 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 758 mCollector.expectTrue("no input size supported for format " + input, 759 inputSizes.length > 0); 760 mCollector.expectTrue("no output size supported for format " + input, 761 outputSizes.length > 0); 762 763 for (Size inputSize : inputSizes) { 764 mCollector.expectTrue("Camera must be able to output the supported " + 765 "reprocessing input size", 766 arrayContains(outputSizes, inputSize) || 767 arrayContains(highResOutputSizes, inputSize)); 768 } 769 } 770 } else { 771 mCollector.expectTrue("Doesn't support reprocessing but report input format: " + 772 Arrays.toString(inputFormats), inputFormats.length == 0); 773 mCollector.expectTrue("Doesn't support reprocessing but max number of input " + 774 "stream is " + maxNumInputStreams, 775 maxNumInputStreams == null || maxNumInputStreams == 0); 776 mCollector.expectTrue("Doesn't support reprocessing but " + 777 "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode); 778 mCollector.expectTrue("Doesn't support reprocessing but " + 779 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported", 780 !supportZslNoiseReductionMode); 781 } 782 counter++; 783 } 784 } 785 786 /** 787 * Check depth output capability 788 */ testDepthOutputCharacteristics()789 public void testDepthOutputCharacteristics() { 790 int counter = 0; 791 792 for (CameraCharacteristics c : mCharacteristics) { 793 Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mIds[counter]); 794 795 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 796 assertNotNull("android.request.availableCapabilities must never be null", 797 capabilities); 798 boolean supportDepth = arrayContains(capabilities, 799 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 800 StreamConfigurationMap configs = 801 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 802 803 int[] outputFormats = configs.getOutputFormats(); 804 boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16); 805 806 Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE); 807 808 float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 809 float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 810 float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 811 float[] radialDistortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION); 812 813 if (supportDepth) { 814 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16", 815 hasDepth16); 816 if (hasDepth16) { 817 Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16); 818 mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!", 819 depthSizes != null && depthSizes.length > 0); 820 if (depthSizes != null) { 821 for (Size depthSize : depthSizes) { 822 mCollector.expectTrue("All depth16 sizes must be positive", 823 depthSize.getWidth() > 0 && depthSize.getHeight() > 0); 824 long minFrameDuration = configs.getOutputMinFrameDuration( 825 ImageFormat.DEPTH16, depthSize); 826 mCollector.expectTrue("Non-negative min frame duration for depth size " 827 + depthSize + " expected, got " + minFrameDuration, 828 minFrameDuration >= 0); 829 long stallDuration = configs.getOutputStallDuration( 830 ImageFormat.DEPTH16, depthSize); 831 mCollector.expectTrue("Non-negative stall duration for depth size " 832 + depthSize + " expected, got " + stallDuration, 833 stallDuration >= 0); 834 } 835 } 836 } 837 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) { 838 Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD); 839 mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " + 840 "but no sizes for DEPTH_POINT_CLOUD supported!", 841 depthCloudSizes != null && depthCloudSizes.length > 0); 842 if (depthCloudSizes != null) { 843 for (Size depthCloudSize : depthCloudSizes) { 844 mCollector.expectTrue("All depth point cloud sizes must be nonzero", 845 depthCloudSize.getWidth() > 0); 846 mCollector.expectTrue("All depth point cloud sizes must be N x 1", 847 depthCloudSize.getHeight() == 1); 848 long minFrameDuration = configs.getOutputMinFrameDuration( 849 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 850 mCollector.expectTrue("Non-negative min frame duration for depth size " 851 + depthCloudSize + " expected, got " + minFrameDuration, 852 minFrameDuration >= 0); 853 long stallDuration = configs.getOutputStallDuration( 854 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 855 mCollector.expectTrue("Non-negative stall duration for depth size " 856 + depthCloudSize + " expected, got " + stallDuration, 857 stallDuration >= 0); 858 } 859 } 860 } 861 862 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined", 863 depthIsExclusive != null); 864 865 mCollector.expectTrue( 866 "Supports DEPTH_OUTPUT but LENS_POSE_ROTATION not right size", 867 poseRotation != null && poseRotation.length == 4); 868 mCollector.expectTrue( 869 "Supports DEPTH_OUTPUT but LENS_POSE_TRANSLATION not right size", 870 poseTranslation != null && poseTranslation.length == 3); 871 mCollector.expectTrue( 872 "Supports DEPTH_OUTPUT but LENS_INTRINSIC_CALIBRATION not right size", 873 cameraIntrinsics != null && cameraIntrinsics.length == 5); 874 mCollector.expectTrue( 875 "Supports DEPTH_OUTPUT but LENS_RADIAL_DISTORTION not right size", 876 radialDistortion != null && radialDistortion.length == 6); 877 878 if (poseRotation != null && poseRotation.length == 4) { 879 float normSq = 880 poseRotation[0] * poseRotation[0] + 881 poseRotation[1] * poseRotation[1] + 882 poseRotation[2] * poseRotation[2] + 883 poseRotation[3] * poseRotation[3]; 884 mCollector.expectTrue( 885 "LENS_POSE_ROTATION quarternion must be unit-length", 886 0.9999f < normSq && normSq < 1.0001f); 887 888 // TODO: Cross-validate orientation/facing and poseRotation 889 Integer orientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 890 Integer facing = c.get(CameraCharacteristics.LENS_FACING); 891 } 892 893 if (poseTranslation != null && poseTranslation.length == 3) { 894 float normSq = 895 poseTranslation[0] * poseTranslation[0] + 896 poseTranslation[1] * poseTranslation[1] + 897 poseTranslation[2] * poseTranslation[2]; 898 mCollector.expectTrue("Pose translation is larger than 1 m", 899 normSq < 1.f); 900 } 901 902 Rect precorrectionArray = 903 c.get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 904 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not have " + 905 "precorrection active array defined", precorrectionArray != null); 906 907 if (cameraIntrinsics != null && precorrectionArray != null) { 908 float fx = cameraIntrinsics[0]; 909 float fy = cameraIntrinsics[1]; 910 float cx = cameraIntrinsics[2]; 911 float cy = cameraIntrinsics[3]; 912 float s = cameraIntrinsics[4]; 913 mCollector.expectTrue("Optical center expected to be within precorrection array", 914 0 <= cx && cx < precorrectionArray.width() && 915 0 <= cy && cy < precorrectionArray.height()); 916 917 // TODO: Verify focal lengths and skew are reasonable 918 } 919 920 if (radialDistortion != null) { 921 // TODO: Verify radial distortion 922 } 923 924 } else { 925 boolean hasFields = 926 hasDepth16 && (poseTranslation != null) && 927 (poseRotation != null) && (cameraIntrinsics != null) && 928 (radialDistortion != null) && (depthIsExclusive != null); 929 930 mCollector.expectTrue( 931 "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed", 932 !hasFields); 933 } 934 counter++; 935 } 936 } 937 938 /** 939 * Cross-check StreamConfigurationMap output 940 */ testStreamConfigurationMap()941 public void testStreamConfigurationMap() throws Exception { 942 int counter = 0; 943 for (CameraCharacteristics c : mCharacteristics) { 944 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]); 945 StreamConfigurationMap config = 946 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 947 assertNotNull(String.format("No stream configuration map found for: ID %s", 948 mIds[counter]), config); 949 950 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 951 assertNotNull("android.request.availableCapabilities must never be null", 952 actualCapabilities); 953 954 if (arrayContains(actualCapabilities, BC)) { 955 assertTrue("ImageReader must be supported", 956 config.isOutputSupportedFor(android.media.ImageReader.class)); 957 assertTrue("MediaRecorder must be supported", 958 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 959 assertTrue("MediaCodec must be supported", 960 config.isOutputSupportedFor(android.media.MediaCodec.class)); 961 assertTrue("Allocation must be supported", 962 config.isOutputSupportedFor(android.renderscript.Allocation.class)); 963 assertTrue("SurfaceHolder must be supported", 964 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 965 assertTrue("SurfaceTexture must be supported", 966 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 967 968 assertTrue("YUV_420_888 must be supported", 969 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 970 assertTrue("JPEG must be supported", 971 config.isOutputSupportedFor(ImageFormat.JPEG)); 972 } else { 973 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed", 974 !config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 975 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed", 976 !config.isOutputSupportedFor(ImageFormat.JPEG)); 977 } 978 979 // Legacy YUV formats should not be listed 980 assertTrue("NV21 must not be supported", 981 !config.isOutputSupportedFor(ImageFormat.NV21)); 982 983 // Check RAW 984 985 if (arrayContains(actualCapabilities, 986 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 987 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 988 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 989 } 990 991 // Cross check public formats and sizes 992 993 int[] supportedFormats = config.getOutputFormats(); 994 for (int format : supportedFormats) { 995 assertTrue("Format " + format + " fails cross check", 996 config.isOutputSupportedFor(format)); 997 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes( 998 Arrays.asList(config.getOutputSizes(format)), /*ascending*/true); 999 if (arrayContains(actualCapabilities, 1000 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 1001 supportedSizes.addAll( 1002 Arrays.asList(config.getHighResolutionOutputSizes(format))); 1003 supportedSizes = CameraTestUtils.getAscendingOrderSizes( 1004 supportedSizes, /*ascending*/true); 1005 } 1006 assertTrue("Supported format " + format + " has no sizes listed", 1007 supportedSizes.size() > 0); 1008 for (int i = 0; i < supportedSizes.size(); i++) { 1009 Size size = supportedSizes.get(i); 1010 if (VERBOSE) { 1011 Log.v(TAG, 1012 String.format("Testing camera %s, format %d, size %s", 1013 mIds[counter], format, size.toString())); 1014 } 1015 1016 long stallDuration = config.getOutputStallDuration(format, size); 1017 switch(format) { 1018 case ImageFormat.YUV_420_888: 1019 assertTrue("YUV_420_888 may not have a non-zero stall duration", 1020 stallDuration == 0); 1021 break; 1022 case ImageFormat.JPEG: 1023 case ImageFormat.RAW_SENSOR: 1024 final float TOLERANCE_FACTOR = 2.0f; 1025 long prevDuration = 0; 1026 if (i > 0) { 1027 prevDuration = config.getOutputStallDuration( 1028 format, supportedSizes.get(i - 1)); 1029 } 1030 long nextDuration = Long.MAX_VALUE; 1031 if (i < (supportedSizes.size() - 1)) { 1032 nextDuration = config.getOutputStallDuration( 1033 format, supportedSizes.get(i + 1)); 1034 } 1035 long curStallDuration = config.getOutputStallDuration(format, size); 1036 // Stall duration should be in a reasonable range: larger size should 1037 // normally have larger stall duration. 1038 mCollector.expectInRange("Stall duration (format " + format + 1039 " and size " + size + ") is not in the right range", 1040 curStallDuration, 1041 (long) (prevDuration / TOLERANCE_FACTOR), 1042 (long) (nextDuration * TOLERANCE_FACTOR)); 1043 break; 1044 default: 1045 assertTrue("Negative stall duration for format " + format, 1046 stallDuration >= 0); 1047 break; 1048 } 1049 long minDuration = config.getOutputMinFrameDuration(format, size); 1050 if (arrayContains(actualCapabilities, 1051 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1052 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1053 + "format " + format + " for size " + size + " minDuration " + 1054 minDuration, 1055 minDuration > 0); 1056 } else { 1057 assertTrue("Need non-negative min frame duration for format " + format, 1058 minDuration >= 0); 1059 } 1060 1061 // todo: test opaque image reader when it's supported. 1062 if (format != ImageFormat.PRIVATE) { 1063 ImageReader testReader = ImageReader.newInstance( 1064 size.getWidth(), 1065 size.getHeight(), 1066 format, 1067 1); 1068 Surface testSurface = testReader.getSurface(); 1069 1070 assertTrue( 1071 String.format("isOutputSupportedFor fails for config %s, format %d", 1072 size.toString(), format), 1073 config.isOutputSupportedFor(testSurface)); 1074 1075 testReader.close(); 1076 } 1077 } // sizes 1078 1079 // Try an invalid size in this format, should round 1080 Size invalidSize = findInvalidSize(supportedSizes); 1081 int MAX_ROUNDING_WIDTH = 1920; 1082 // todo: test opaque image reader when it's supported. 1083 if (format != ImageFormat.PRIVATE && 1084 invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 1085 ImageReader testReader = ImageReader.newInstance( 1086 invalidSize.getWidth(), 1087 invalidSize.getHeight(), 1088 format, 1089 1); 1090 Surface testSurface = testReader.getSurface(); 1091 1092 assertTrue( 1093 String.format("isOutputSupportedFor fails for config %s, %d", 1094 invalidSize.toString(), format), 1095 config.isOutputSupportedFor(testSurface)); 1096 1097 testReader.close(); 1098 } 1099 } // formats 1100 1101 // Cross-check opaque format and sizes 1102 if (arrayContains(actualCapabilities, BC)) { 1103 SurfaceTexture st = new SurfaceTexture(1); 1104 Surface surf = new Surface(st); 1105 1106 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class, 1107 mIds[counter], mCameraManager); 1108 assertTrue("Opaque format has no sizes listed", 1109 opaqueSizes.length > 0); 1110 for (Size size : opaqueSizes) { 1111 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 1112 assertTrue("Opaque output may not have a non-zero stall duration", 1113 stallDuration == 0); 1114 1115 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 1116 if (arrayContains(actualCapabilities, 1117 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1118 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1119 + "opaque format", 1120 minDuration > 0); 1121 } else { 1122 assertTrue("Need non-negative min frame duration for opaque format ", 1123 minDuration >= 0); 1124 } 1125 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 1126 1127 assertTrue( 1128 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1129 size.toString()), 1130 config.isOutputSupportedFor(surf)); 1131 1132 } // opaque sizes 1133 1134 // Try invalid opaque size, should get rounded 1135 Size invalidSize = findInvalidSize(opaqueSizes); 1136 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 1137 assertTrue( 1138 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1139 invalidSize.toString()), 1140 config.isOutputSupportedFor(surf)); 1141 1142 } 1143 counter++; 1144 } // mCharacteristics 1145 } 1146 1147 /** 1148 * Test high speed capability and cross-check the high speed sizes and fps ranges from 1149 * the StreamConfigurationMap. 1150 */ testConstrainedHighSpeedCapability()1151 public void testConstrainedHighSpeedCapability() throws Exception { 1152 int counter = 0; 1153 for (CameraCharacteristics c : mCharacteristics) { 1154 int[] capabilities = CameraTestUtils.getValueNotNull( 1155 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1156 boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED); 1157 if (supportHighSpeed) { 1158 StreamConfigurationMap config = 1159 CameraTestUtils.getValueNotNull( 1160 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1161 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 1162 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0); 1163 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE, 1164 mIds[counter], mCameraManager); 1165 assertTrue("Normal size for PRIVATE format shouldn't be null or empty", 1166 allSizes != null && allSizes.length > 0); 1167 for (Size size: highSpeedSizes) { 1168 // The sizes must be a subset of the normal sizes 1169 assertTrue("High speed size " + size + 1170 " must be part of normal sizes " + Arrays.toString(allSizes), 1171 Arrays.asList(allSizes).contains(size)); 1172 1173 // Sanitize the high speed FPS ranges for each size 1174 List<Range<Integer>> ranges = 1175 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size)); 1176 for (Range<Integer> range : ranges) { 1177 assertTrue("The range " + range + " doesn't satisfy the" 1178 + " min/max boundary requirements.", 1179 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN && 1180 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN); 1181 assertTrue("The range " + range + " should be multiple of 30fps", 1182 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0); 1183 // If the range is fixed high speed range, it should contain the 1184 // [30, fps_max] in the high speed range list; if it's variable FPS range, 1185 // the corresponding fixed FPS Range must be included in the range list. 1186 if (range.getLower() == range.getUpper()) { 1187 Range<Integer> variableRange = new Range<Integer>(30, range.getUpper()); 1188 assertTrue("The variable FPS range " + variableRange + 1189 " shoould be included in the high speed ranges for size " + 1190 size, ranges.contains(variableRange)); 1191 } else { 1192 Range<Integer> fixedRange = 1193 new Range<Integer>(range.getUpper(), range.getUpper()); 1194 assertTrue("The fixed FPS range " + fixedRange + 1195 " shoould be included in the high speed ranges for size " + 1196 size, ranges.contains(fixedRange)); 1197 } 1198 } 1199 } 1200 // If the device advertise some high speed profiles, the sizes and FPS ranges 1201 // should be advertise by the camera. 1202 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P; 1203 quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) { 1204 if (CamcorderProfile.hasProfile(quality)) { 1205 CamcorderProfile profile = CamcorderProfile.get(quality); 1206 Size camcorderProfileSize = 1207 new Size(profile.videoFrameWidth, profile.videoFrameHeight); 1208 assertTrue("CamcorderPrfile size " + camcorderProfileSize + 1209 " must be included in the high speed sizes " + 1210 Arrays.toString(highSpeedSizes.toArray()), 1211 highSpeedSizes.contains(camcorderProfileSize)); 1212 Range<Integer> camcorderFpsRange = 1213 new Range<Integer>(profile.videoFrameRate, profile.videoFrameRate); 1214 List<Range<Integer>> allRanges = 1215 Arrays.asList(config.getHighSpeedVideoFpsRangesFor( 1216 camcorderProfileSize)); 1217 assertTrue("Camcorder fps range " + camcorderFpsRange + 1218 " should be included by high speed fps ranges " + 1219 Arrays.toString(allRanges.toArray()), 1220 allRanges.contains(camcorderFpsRange)); 1221 } 1222 } 1223 } 1224 counter++; 1225 } 1226 } 1227 1228 /** 1229 * Sanity check of optical black regions. 1230 */ testOpticalBlackRegions()1231 public void testOpticalBlackRegions() { 1232 int counter = 0; 1233 for (CameraCharacteristics c : mCharacteristics) { 1234 List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys(); 1235 boolean hasDynamicBlackLevel = 1236 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 1237 boolean hasDynamicWhiteLevel = 1238 resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL); 1239 boolean hasFixedBlackLevel = 1240 c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 1241 boolean hasFixedWhiteLevel = 1242 c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 1243 // The black and white levels should be either all supported or none of them is 1244 // supported. 1245 mCollector.expectTrue("Dynamic black and white level should be all or none of them" 1246 + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel); 1247 mCollector.expectTrue("Fixed black and white level should be all or none of them" 1248 + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel); 1249 mCollector.expectTrue("Fixed black level should be supported if dynamic black" 1250 + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel); 1251 1252 if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) { 1253 // Regions shouldn't be null or empty. 1254 Rect[] regions = CameraTestUtils.getValueNotNull(c, 1255 CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS); 1256 CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not" 1257 + " be empty"); 1258 1259 // Dynamic black level should be supported if the optical black region is 1260 // advertised. 1261 mCollector.expectTrue("Dynamic black and white level keys should be advertised in " 1262 + "available capture result key list", hasDynamicWhiteLevel); 1263 1264 // Range check. 1265 for (Rect region : regions) { 1266 mCollector.expectTrue("Camera " + mIds[counter] + ": optical black region" + 1267 " shouldn't be empty!", !region.isEmpty()); 1268 mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/, 1269 region.left/*actual*/); 1270 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 1271 region.top/*actual*/); 1272 mCollector.expectTrue("Optical black region left/right/width/height must be" 1273 + " even number, otherwise, the bayer CFA pattern in this region will" 1274 + " be messed up", 1275 region.left % 2 == 0 && region.top % 2 == 0 && 1276 region.width() % 2 == 0 && region.height() % 2 == 0); 1277 mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/, 1278 region.top/*actual*/); 1279 Size size = CameraTestUtils.getValueNotNull(c, 1280 CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 1281 mCollector.expectLessOrEqual("Optical black region width", 1282 size.getWidth()/*expected*/, region.width()); 1283 mCollector.expectLessOrEqual("Optical black region height", 1284 size.getHeight()/*expected*/, region.height()); 1285 Rect activeArray = CameraTestUtils.getValueNotNull(c, 1286 CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 1287 mCollector.expectTrue("Optical black region" + region + " should be outside of" 1288 + " active array " + activeArray, 1289 !region.intersect(activeArray)); 1290 // Region need to be disjoint: 1291 for (Rect region2 : regions) { 1292 mCollector.expectTrue("Optical black region" + region + " should have no " 1293 + "overlap with " + region2, 1294 region == region2 || !region.intersect(region2)); 1295 } 1296 } 1297 } else { 1298 Log.i(TAG, "Camera " + mIds[counter] + " doesn't support optical black regions," 1299 + " skip the region test"); 1300 } 1301 counter++; 1302 } 1303 } 1304 /** 1305 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 1306 */ findInvalidSize(Size[] goodSizes)1307 private Size findInvalidSize(Size[] goodSizes) { 1308 return findInvalidSize(Arrays.asList(goodSizes)); 1309 } 1310 1311 /** 1312 * Create an invalid size that's close to one of the good sizes in the list, but not one of them 1313 */ findInvalidSize(List<Size> goodSizes)1314 private Size findInvalidSize(List<Size> goodSizes) { 1315 Size invalidSize = new Size(goodSizes.get(0).getWidth() + 1, goodSizes.get(0).getHeight()); 1316 while(goodSizes.contains(invalidSize)) { 1317 invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight()); 1318 } 1319 return invalidSize; 1320 } 1321 1322 /** 1323 * Check key is present in characteristics if the hardware level is at least {@code hwLevel}; 1324 * check that the key is present if the actual capabilities are one of {@code capabilities}. 1325 * 1326 * @return value of the {@code key} from {@code c} 1327 */ expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, int hwLevel, int... capabilities)1328 private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key, 1329 int hwLevel, int... capabilities) { 1330 1331 Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); 1332 assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel); 1333 1334 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1335 assertNotNull("android.request.availableCapabilities must never be null", 1336 actualCapabilities); 1337 1338 List<Key<?>> allKeys = c.getKeys(); 1339 1340 T value = c.get(key); 1341 1342 // For LIMITED-level targeted keys, rely on capability check, not level 1343 if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) { 1344 mCollector.expectTrue( 1345 String.format("Key (%s) must be in characteristics for this hardware level " + 1346 "(required minimal HW level %s, actual HW level %s)", 1347 key.getName(), toStringHardwareLevel(hwLevel), 1348 toStringHardwareLevel(actualHwLevel)), 1349 value != null); 1350 mCollector.expectTrue( 1351 String.format("Key (%s) must be in characteristics list of keys for this " + 1352 "hardware level (required minimal HW level %s, actual HW level %s)", 1353 key.getName(), toStringHardwareLevel(hwLevel), 1354 toStringHardwareLevel(actualHwLevel)), 1355 allKeys.contains(key)); 1356 } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) { 1357 if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) { 1358 // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined 1359 mCollector.expectTrue( 1360 String.format("Key (%s) must be in characteristics for these capabilities " + 1361 "(required capabilities %s, actual capabilities %s)", 1362 key.getName(), Arrays.toString(capabilities), 1363 Arrays.toString(actualCapabilities)), 1364 value != null); 1365 mCollector.expectTrue( 1366 String.format("Key (%s) must be in characteristics list of keys for " + 1367 "these capabilities (required capabilities %s, actual capabilities %s)", 1368 key.getName(), Arrays.toString(capabilities), 1369 Arrays.toString(actualCapabilities)), 1370 allKeys.contains(key)); 1371 } 1372 } else { 1373 if (actualHwLevel == LEGACY && hwLevel != OPT) { 1374 if (value != null || allKeys.contains(key)) { 1375 Log.w(TAG, String.format( 1376 "Key (%s) is not required for LEGACY devices but still appears", 1377 key.getName())); 1378 } 1379 } 1380 // OK: Key may or may not be present. 1381 } 1382 return value; 1383 } 1384 arrayContains(int[] arr, int needle)1385 private static boolean arrayContains(int[] arr, int needle) { 1386 if (arr == null) { 1387 return false; 1388 } 1389 1390 for (int elem : arr) { 1391 if (elem == needle) { 1392 return true; 1393 } 1394 } 1395 1396 return false; 1397 } 1398 arrayContains(T[] arr, T needle)1399 private static <T> boolean arrayContains(T[] arr, T needle) { 1400 if (arr == null) { 1401 return false; 1402 } 1403 1404 for (T elem : arr) { 1405 if (elem.equals(needle)) { 1406 return true; 1407 } 1408 } 1409 1410 return false; 1411 } 1412 arrayContainsAnyOf(int[] arr, int[] needles)1413 private static boolean arrayContainsAnyOf(int[] arr, int[] needles) { 1414 for (int needle : needles) { 1415 if (arrayContains(arr, needle)) { 1416 return true; 1417 } 1418 } 1419 return false; 1420 } 1421 1422 /** 1423 * The key name has a prefix of either "android." or "com."; other prefixes are not valid. 1424 */ assertKeyPrefixValid(String keyName)1425 private static void assertKeyPrefixValid(String keyName) { 1426 assertStartsWithAnyOf( 1427 "All metadata keys must start with 'android.' (built-in keys) " + 1428 "or 'com.' (vendor-extended keys)", new String[] { 1429 PREFIX_ANDROID + ".", 1430 PREFIX_VENDOR + ".", 1431 }, keyName); 1432 } 1433 assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, boolean actual)1434 private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key, 1435 boolean actual) { 1436 assertTrue(msg + " (key = '" + key.getName() + "')", actual); 1437 } 1438 assertOneOf(String msg, T[] expected, T actual)1439 private static <T> void assertOneOf(String msg, T[] expected, T actual) { 1440 for (int i = 0; i < expected.length; ++i) { 1441 if (Objects.equals(expected[i], actual)) { 1442 return; 1443 } 1444 } 1445 1446 fail(String.format("%s: (expected one of %s, actual %s)", 1447 msg, Arrays.toString(expected), actual)); 1448 } 1449 assertStartsWithAnyOf(String msg, String[] expected, String actual)1450 private static <T> void assertStartsWithAnyOf(String msg, String[] expected, String actual) { 1451 for (int i = 0; i < expected.length; ++i) { 1452 if (actual.startsWith(expected[i])) { 1453 return; 1454 } 1455 } 1456 1457 fail(String.format("%s: (expected to start with any of %s, but value was %s)", 1458 msg, Arrays.toString(expected), actual)); 1459 } 1460 1461 /** Return a positive int if left > right, 0 if left==right, negative int if left < right */ compareHardwareLevel(int left, int right)1462 private static int compareHardwareLevel(int left, int right) { 1463 return remapHardwareLevel(left) - remapHardwareLevel(right); 1464 } 1465 1466 /** Remap HW levels worst<->best, 0 = LEGACY, 1 = LIMITED, 2 = FULL, ..., N = LEVEL_N */ remapHardwareLevel(int level)1467 private static int remapHardwareLevel(int level) { 1468 switch (level) { 1469 case OPT: 1470 return Integer.MAX_VALUE; 1471 case LEGACY: 1472 return 0; // lowest 1473 case LIMITED: 1474 return 1; // second lowest 1475 case FULL: 1476 return 2; // good 1477 default: 1478 if (level >= LEVEL_3) { 1479 return level; // higher levels map directly 1480 } 1481 } 1482 1483 fail("Unknown HW level: " + level); 1484 return -1; 1485 } 1486 toStringHardwareLevel(int level)1487 private static String toStringHardwareLevel(int level) { 1488 switch (level) { 1489 case LEGACY: 1490 return "LEGACY"; 1491 case LIMITED: 1492 return "LIMITED"; 1493 case FULL: 1494 return "FULL"; 1495 default: 1496 if (level >= LEVEL_3) { 1497 return String.format("LEVEL_%d", level); 1498 } 1499 } 1500 1501 // unknown 1502 Log.w(TAG, "Unknown hardware level " + level); 1503 return Integer.toString(level); 1504 } 1505 } 1506