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 // Only check the range if the second reference illuminant is avaliable 450 if (c.get(CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2) != null) { 451 mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2, 452 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT, 453 (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN); 454 } 455 456 Rational[] zeroes = new Rational[9]; 457 Arrays.fill(zeroes, Rational.ZERO); 458 459 ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes); 460 mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed, 461 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1)); 462 mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed, 463 c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2)); 464 mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.", 465 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1)); 466 mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.", 467 zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2)); 468 mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.", 469 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1)); 470 mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.", 471 zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2)); 472 473 BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c, 474 CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN); 475 if (blackLevel != null) { 476 String blackLevelPatternString = blackLevel.toString(); 477 if (VERBOSE) { 478 Log.v(TAG, "Black level pattern: " + blackLevelPatternString); 479 } 480 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT]; 481 blackLevel.copyTo(blackLevelPattern, /*offset*/0); 482 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL); 483 if (whitelevel != null) { 484 mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0, 485 whitelevel); 486 } else { 487 mCollector.addMessage( 488 "No WhiteLevel available, cannot check BlackLevelPattern range."); 489 } 490 } 491 492 // TODO: profileHueSatMap, and profileToneCurve aren't supported yet. 493 counter++; 494 } 495 } 496 497 /** 498 * Test values for static metadata used by the BURST capability. 499 */ testStaticBurstCharacteristics()500 public void testStaticBurstCharacteristics() throws Exception { 501 int counter = 0; 502 final float SIZE_ERROR_MARGIN = 0.03f; 503 for (CameraCharacteristics c : mCharacteristics) { 504 int[] actualCapabilities = CameraTestUtils.getValueNotNull( 505 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 506 507 // Check if the burst capability is defined 508 boolean haveBurstCapability = arrayContains(actualCapabilities, 509 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE); 510 boolean haveBC = arrayContains(actualCapabilities, 511 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); 512 513 if(haveBurstCapability && !haveBC) { 514 fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined"); 515 } 516 517 if (!haveBC) continue; 518 519 StreamConfigurationMap config = 520 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 521 assertNotNull(String.format("No stream configuration map found for: ID %s", 522 mIds[counter]), config); 523 Rect activeRect = CameraTestUtils.getValueNotNull( 524 c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 525 Size sensorSize = new Size(activeRect.width(), activeRect.height()); 526 527 // Ensure that max YUV size matches max JPEG size 528 Size maxYuvSize = CameraTestUtils.getMaxSize( 529 config.getOutputSizes(ImageFormat.YUV_420_888)); 530 Size maxFastYuvSize = maxYuvSize; 531 532 Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888); 533 if (haveBurstCapability && slowYuvSizes != null && slowYuvSizes.length > 0) { 534 Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes); 535 maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize}); 536 } 537 538 Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat( 539 ImageFormat.JPEG, mIds[counter], mCameraManager)); 540 541 boolean haveMaxYuv = maxYuvSize != null ? 542 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() && 543 maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false; 544 545 float croppedWidth = (float)sensorSize.getWidth(); 546 float croppedHeight = (float)sensorSize.getHeight(); 547 float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight(); 548 float maxYuvAspectRatio = (float)maxYuvSize.getWidth() / (float)maxYuvSize.getHeight(); 549 if (sensorAspectRatio < maxYuvAspectRatio) { 550 croppedHeight = (float)sensorSize.getWidth() / maxYuvAspectRatio; 551 } else if (sensorAspectRatio > maxYuvAspectRatio) { 552 croppedWidth = (float)sensorSize.getHeight() * maxYuvAspectRatio; 553 } 554 Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight); 555 556 boolean maxYuvMatchSensor = 557 (maxYuvSize.getWidth() <= croppedSensorSize.getWidth() * (1.0 + SIZE_ERROR_MARGIN) && 558 maxYuvSize.getWidth() >= croppedSensorSize.getWidth() * (1.0 - SIZE_ERROR_MARGIN) && 559 maxYuvSize.getHeight() <= croppedSensorSize.getHeight() * (1.0 + SIZE_ERROR_MARGIN) && 560 maxYuvSize.getHeight() >= croppedSensorSize.getHeight() * (1.0 - SIZE_ERROR_MARGIN)); 561 562 // No need to do null check since framework will generate the key if HAL don't supply 563 boolean haveAeLock = CameraTestUtils.getValueNotNull( 564 c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE); 565 boolean haveAwbLock = CameraTestUtils.getValueNotNull( 566 c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE); 567 568 // Ensure that max YUV output is fast enough - needs to be at least 10 fps 569 570 long maxYuvRate = 571 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize); 572 final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps 573 boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS; 574 575 // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps 576 577 long maxFastYuvRate = 578 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize); 579 final long MIN_8MP_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps 580 boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS; 581 582 final int SIZE_8MP_BOUND = 8000000; 583 boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) > 584 SIZE_8MP_BOUND; 585 586 // Ensure that there's an FPS range that's fast enough to capture at above 587 // minFrameDuration, for full-auto bursts at the fast resolutions 588 Range[] fpsRanges = CameraTestUtils.getValueNotNull( 589 c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); 590 float minYuvFps = 1.f / maxFastYuvRate; 591 592 boolean haveFastAeTargetFps = false; 593 for (Range<Integer> r : fpsRanges) { 594 if (r.getLower() >= minYuvFps) { 595 haveFastAeTargetFps = true; 596 break; 597 } 598 } 599 600 // Ensure that maximum sync latency is small enough for fast setting changes, even if 601 // it's not quite per-frame 602 603 Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY); 604 assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]), 605 maxSyncLatencyValue); 606 607 int maxSyncLatency = maxSyncLatencyValue; 608 final long MAX_LATENCY_BOUND = 4; 609 boolean haveFastSyncLatency = 610 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0); 611 612 if (haveBurstCapability) { 613 assertTrue("Must have slow YUV size array when BURST_CAPTURE capability is defined!", 614 slowYuvSizes != null); 615 assertTrue( 616 String.format("BURST-capable camera device %s does not have maximum YUV " + 617 "size that is at least max JPEG size", 618 mIds[counter]), 619 haveMaxYuv); 620 assertTrue( 621 String.format("BURST-capable camera device %s max-resolution " + 622 "YUV frame rate is too slow" + 623 "(%d ns min frame duration reported, less than %d ns expected)", 624 mIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS), 625 haveMaxYuvRate); 626 assertTrue( 627 String.format("BURST-capable camera device %s >= 8MP YUV output " + 628 "frame rate is too slow" + 629 "(%d ns min frame duration reported, less than %d ns expected)", 630 mIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS), 631 haveFastYuvRate); 632 assertTrue( 633 String.format("BURST-capable camera device %s does not list an AE target " + 634 " FPS range with min FPS >= %f, for full-AUTO bursts", 635 mIds[counter], minYuvFps), 636 haveFastAeTargetFps); 637 assertTrue( 638 String.format("BURST-capable camera device %s YUV sync latency is too long" + 639 "(%d frames reported, [0, %d] frames expected)", 640 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND), 641 haveFastSyncLatency); 642 assertTrue( 643 String.format("BURST-capable camera device %s max YUV size %s should be" + 644 "close to active array size %s or cropped active array size %s", 645 mIds[counter], maxYuvSize.toString(), sensorSize.toString(), 646 croppedSensorSize.toString()), 647 maxYuvMatchSensor); 648 assertTrue( 649 String.format("BURST-capable camera device %s does not support AE lock", 650 mIds[counter]), 651 haveAeLock); 652 assertTrue( 653 String.format("BURST-capable camera device %s does not support AWB lock", 654 mIds[counter]), 655 haveAwbLock); 656 } else { 657 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!", 658 slowYuvSizes == null); 659 assertTrue( 660 String.format("Camera device %s has all the requirements for BURST" + 661 " capability but does not report it!", mIds[counter]), 662 !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps && 663 haveFastSyncLatency && maxYuvMatchSensor && 664 haveAeLock && haveAwbLock)); 665 } 666 667 counter++; 668 } 669 } 670 671 /** 672 * Check reprocessing capabilities. 673 */ testReprocessingCharacteristics()674 public void testReprocessingCharacteristics() { 675 int counter = 0; 676 677 for (CameraCharacteristics c : mCharacteristics) { 678 Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mIds[counter]); 679 680 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 681 assertNotNull("android.request.availableCapabilities must never be null", 682 capabilities); 683 boolean supportYUV = arrayContains(capabilities, 684 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 685 boolean supportOpaque = arrayContains(capabilities, 686 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 687 StreamConfigurationMap configs = 688 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 689 Integer maxNumInputStreams = 690 c.get(CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS); 691 int[] availableEdgeModes = c.get(CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES); 692 int[] availableNoiseReductionModes = c.get( 693 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES); 694 695 int[] inputFormats = configs.getInputFormats(); 696 697 boolean supportZslEdgeMode = false; 698 boolean supportZslNoiseReductionMode = false; 699 boolean supportHiQNoiseReductionMode = false; 700 boolean supportHiQEdgeMode = false; 701 702 if (availableEdgeModes != null) { 703 supportZslEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 704 contains(CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG); 705 supportHiQEdgeMode = Arrays.asList(CameraTestUtils.toObject(availableEdgeModes)). 706 contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY); 707 } 708 709 if (availableNoiseReductionModes != null) { 710 supportZslNoiseReductionMode = Arrays.asList( 711 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 712 CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG); 713 supportHiQNoiseReductionMode = Arrays.asList( 714 CameraTestUtils.toObject(availableNoiseReductionModes)).contains( 715 CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY); 716 } 717 718 if (supportYUV || supportOpaque) { 719 mCollector.expectTrue("Support reprocessing but max number of input stream is " + 720 maxNumInputStreams, maxNumInputStreams != null && maxNumInputStreams > 0); 721 mCollector.expectTrue("Support reprocessing but EDGE_MODE_ZERO_SHUTTER_LAG is " + 722 "not supported", supportZslEdgeMode); 723 mCollector.expectTrue("Support reprocessing but " + 724 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is not supported", 725 supportZslNoiseReductionMode); 726 727 // For reprocessing, if we only require OFF and ZSL mode, it will be just like jpeg 728 // encoding. We implicitly require FAST to make reprocessing meaningful, which means 729 // that we also require HIGH_QUALITY. 730 mCollector.expectTrue("Support reprocessing but EDGE_MODE_HIGH_QUALITY is " + 731 "not supported", supportHiQEdgeMode); 732 mCollector.expectTrue("Support reprocessing but " + 733 "NOISE_REDUCTION_MODE_HIGH_QUALITY is not supported", 734 supportHiQNoiseReductionMode); 735 736 // Verify mandatory input formats are supported 737 mCollector.expectTrue("YUV_420_888 input must be supported for YUV reprocessing", 738 !supportYUV || arrayContains(inputFormats, ImageFormat.YUV_420_888)); 739 mCollector.expectTrue("PRIVATE input must be supported for OPAQUE reprocessing", 740 !supportOpaque || arrayContains(inputFormats, ImageFormat.PRIVATE)); 741 742 // max capture stall must be reported if one of the reprocessing is supported. 743 final int MAX_ALLOWED_STALL_FRAMES = 4; 744 Integer maxCaptureStall = c.get(CameraCharacteristics.REPROCESS_MAX_CAPTURE_STALL); 745 mCollector.expectTrue("max capture stall must be non-null and no larger than " 746 + MAX_ALLOWED_STALL_FRAMES, 747 maxCaptureStall != null && maxCaptureStall <= MAX_ALLOWED_STALL_FRAMES); 748 749 for (int input : inputFormats) { 750 // Verify mandatory output formats are supported 751 int[] outputFormats = configs.getValidOutputFormatsForInput(input); 752 mCollector.expectTrue("YUV_420_888 output must be supported for reprocessing", 753 arrayContains(outputFormats, ImageFormat.YUV_420_888)); 754 mCollector.expectTrue("JPEG output must be supported for reprocessing", 755 arrayContains(outputFormats, ImageFormat.JPEG)); 756 757 // Verify camera can output the reprocess input formats and sizes. 758 Size[] inputSizes = configs.getInputSizes(input); 759 Size[] outputSizes = configs.getOutputSizes(input); 760 Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input); 761 mCollector.expectTrue("no input size supported for format " + input, 762 inputSizes.length > 0); 763 mCollector.expectTrue("no output size supported for format " + input, 764 outputSizes.length > 0); 765 766 for (Size inputSize : inputSizes) { 767 mCollector.expectTrue("Camera must be able to output the supported " + 768 "reprocessing input size", 769 arrayContains(outputSizes, inputSize) || 770 arrayContains(highResOutputSizes, inputSize)); 771 } 772 } 773 } else { 774 mCollector.expectTrue("Doesn't support reprocessing but report input format: " + 775 Arrays.toString(inputFormats), inputFormats.length == 0); 776 mCollector.expectTrue("Doesn't support reprocessing but max number of input " + 777 "stream is " + maxNumInputStreams, 778 maxNumInputStreams == null || maxNumInputStreams == 0); 779 mCollector.expectTrue("Doesn't support reprocessing but " + 780 "EDGE_MODE_ZERO_SHUTTER_LAG is supported", !supportZslEdgeMode); 781 mCollector.expectTrue("Doesn't support reprocessing but " + 782 "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported", 783 !supportZslNoiseReductionMode); 784 } 785 counter++; 786 } 787 } 788 789 /** 790 * Check depth output capability 791 */ testDepthOutputCharacteristics()792 public void testDepthOutputCharacteristics() { 793 int counter = 0; 794 795 for (CameraCharacteristics c : mCharacteristics) { 796 Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mIds[counter]); 797 798 int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 799 assertNotNull("android.request.availableCapabilities must never be null", 800 capabilities); 801 boolean supportDepth = arrayContains(capabilities, 802 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT); 803 StreamConfigurationMap configs = 804 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 805 806 int[] outputFormats = configs.getOutputFormats(); 807 boolean hasDepth16 = arrayContains(outputFormats, ImageFormat.DEPTH16); 808 809 Boolean depthIsExclusive = c.get(CameraCharacteristics.DEPTH_DEPTH_IS_EXCLUSIVE); 810 811 float[] poseRotation = c.get(CameraCharacteristics.LENS_POSE_ROTATION); 812 float[] poseTranslation = c.get(CameraCharacteristics.LENS_POSE_TRANSLATION); 813 float[] cameraIntrinsics = c.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION); 814 float[] radialDistortion = c.get(CameraCharacteristics.LENS_RADIAL_DISTORTION); 815 816 if (supportDepth) { 817 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not support DEPTH16", 818 hasDepth16); 819 if (hasDepth16) { 820 Size[] depthSizes = configs.getOutputSizes(ImageFormat.DEPTH16); 821 mCollector.expectTrue("Supports DEPTH_OUTPUT but no sizes for DEPTH16 supported!", 822 depthSizes != null && depthSizes.length > 0); 823 if (depthSizes != null) { 824 for (Size depthSize : depthSizes) { 825 mCollector.expectTrue("All depth16 sizes must be positive", 826 depthSize.getWidth() > 0 && depthSize.getHeight() > 0); 827 long minFrameDuration = configs.getOutputMinFrameDuration( 828 ImageFormat.DEPTH16, depthSize); 829 mCollector.expectTrue("Non-negative min frame duration for depth size " 830 + depthSize + " expected, got " + minFrameDuration, 831 minFrameDuration >= 0); 832 long stallDuration = configs.getOutputStallDuration( 833 ImageFormat.DEPTH16, depthSize); 834 mCollector.expectTrue("Non-negative stall duration for depth size " 835 + depthSize + " expected, got " + stallDuration, 836 stallDuration >= 0); 837 } 838 } 839 } 840 if (arrayContains(outputFormats, ImageFormat.DEPTH_POINT_CLOUD)) { 841 Size[] depthCloudSizes = configs.getOutputSizes(ImageFormat.DEPTH_POINT_CLOUD); 842 mCollector.expectTrue("Supports DEPTH_POINT_CLOUD " + 843 "but no sizes for DEPTH_POINT_CLOUD supported!", 844 depthCloudSizes != null && depthCloudSizes.length > 0); 845 if (depthCloudSizes != null) { 846 for (Size depthCloudSize : depthCloudSizes) { 847 mCollector.expectTrue("All depth point cloud sizes must be nonzero", 848 depthCloudSize.getWidth() > 0); 849 mCollector.expectTrue("All depth point cloud sizes must be N x 1", 850 depthCloudSize.getHeight() == 1); 851 long minFrameDuration = configs.getOutputMinFrameDuration( 852 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 853 mCollector.expectTrue("Non-negative min frame duration for depth size " 854 + depthCloudSize + " expected, got " + minFrameDuration, 855 minFrameDuration >= 0); 856 long stallDuration = configs.getOutputStallDuration( 857 ImageFormat.DEPTH_POINT_CLOUD, depthCloudSize); 858 mCollector.expectTrue("Non-negative stall duration for depth size " 859 + depthCloudSize + " expected, got " + stallDuration, 860 stallDuration >= 0); 861 } 862 } 863 } 864 865 mCollector.expectTrue("Supports DEPTH_OUTPUT but DEPTH_IS_EXCLUSIVE is not defined", 866 depthIsExclusive != null); 867 868 mCollector.expectTrue( 869 "Supports DEPTH_OUTPUT but LENS_POSE_ROTATION not right size", 870 poseRotation != null && poseRotation.length == 4); 871 mCollector.expectTrue( 872 "Supports DEPTH_OUTPUT but LENS_POSE_TRANSLATION not right size", 873 poseTranslation != null && poseTranslation.length == 3); 874 mCollector.expectTrue( 875 "Supports DEPTH_OUTPUT but LENS_INTRINSIC_CALIBRATION not right size", 876 cameraIntrinsics != null && cameraIntrinsics.length == 5); 877 mCollector.expectTrue( 878 "Supports DEPTH_OUTPUT but LENS_RADIAL_DISTORTION not right size", 879 radialDistortion != null && radialDistortion.length == 6); 880 881 if (poseRotation != null && poseRotation.length == 4) { 882 float normSq = 883 poseRotation[0] * poseRotation[0] + 884 poseRotation[1] * poseRotation[1] + 885 poseRotation[2] * poseRotation[2] + 886 poseRotation[3] * poseRotation[3]; 887 mCollector.expectTrue( 888 "LENS_POSE_ROTATION quarternion must be unit-length", 889 0.9999f < normSq && normSq < 1.0001f); 890 891 // TODO: Cross-validate orientation/facing and poseRotation 892 Integer orientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION); 893 Integer facing = c.get(CameraCharacteristics.LENS_FACING); 894 } 895 896 if (poseTranslation != null && poseTranslation.length == 3) { 897 float normSq = 898 poseTranslation[0] * poseTranslation[0] + 899 poseTranslation[1] * poseTranslation[1] + 900 poseTranslation[2] * poseTranslation[2]; 901 mCollector.expectTrue("Pose translation is larger than 1 m", 902 normSq < 1.f); 903 } 904 905 Rect precorrectionArray = 906 c.get(CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 907 mCollector.expectTrue("Supports DEPTH_OUTPUT but does not have " + 908 "precorrection active array defined", precorrectionArray != null); 909 910 if (cameraIntrinsics != null && precorrectionArray != null) { 911 float fx = cameraIntrinsics[0]; 912 float fy = cameraIntrinsics[1]; 913 float cx = cameraIntrinsics[2]; 914 float cy = cameraIntrinsics[3]; 915 float s = cameraIntrinsics[4]; 916 mCollector.expectTrue("Optical center expected to be within precorrection array", 917 0 <= cx && cx < precorrectionArray.width() && 918 0 <= cy && cy < precorrectionArray.height()); 919 920 // TODO: Verify focal lengths and skew are reasonable 921 } 922 923 if (radialDistortion != null) { 924 // TODO: Verify radial distortion 925 } 926 927 } else { 928 boolean hasFields = 929 hasDepth16 && (poseTranslation != null) && 930 (poseRotation != null) && (cameraIntrinsics != null) && 931 (radialDistortion != null) && (depthIsExclusive != null); 932 933 mCollector.expectTrue( 934 "All necessary depth fields defined, but DEPTH_OUTPUT capability is not listed", 935 !hasFields); 936 } 937 counter++; 938 } 939 } 940 941 /** 942 * Cross-check StreamConfigurationMap output 943 */ testStreamConfigurationMap()944 public void testStreamConfigurationMap() throws Exception { 945 int counter = 0; 946 for (CameraCharacteristics c : mCharacteristics) { 947 Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]); 948 StreamConfigurationMap config = 949 c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 950 assertNotNull(String.format("No stream configuration map found for: ID %s", 951 mIds[counter]), config); 952 953 int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 954 assertNotNull("android.request.availableCapabilities must never be null", 955 actualCapabilities); 956 957 if (arrayContains(actualCapabilities, BC)) { 958 assertTrue("ImageReader must be supported", 959 config.isOutputSupportedFor(android.media.ImageReader.class)); 960 assertTrue("MediaRecorder must be supported", 961 config.isOutputSupportedFor(android.media.MediaRecorder.class)); 962 assertTrue("MediaCodec must be supported", 963 config.isOutputSupportedFor(android.media.MediaCodec.class)); 964 assertTrue("Allocation must be supported", 965 config.isOutputSupportedFor(android.renderscript.Allocation.class)); 966 assertTrue("SurfaceHolder must be supported", 967 config.isOutputSupportedFor(android.view.SurfaceHolder.class)); 968 assertTrue("SurfaceTexture must be supported", 969 config.isOutputSupportedFor(android.graphics.SurfaceTexture.class)); 970 971 assertTrue("YUV_420_888 must be supported", 972 config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 973 assertTrue("JPEG must be supported", 974 config.isOutputSupportedFor(ImageFormat.JPEG)); 975 } else { 976 assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed", 977 !config.isOutputSupportedFor(ImageFormat.YUV_420_888)); 978 assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed", 979 !config.isOutputSupportedFor(ImageFormat.JPEG)); 980 } 981 982 // Check RAW 983 984 if (arrayContains(actualCapabilities, 985 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 986 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised", 987 config.isOutputSupportedFor(ImageFormat.RAW_SENSOR)); 988 } 989 990 // Cross check public formats and sizes 991 992 int[] supportedFormats = config.getOutputFormats(); 993 for (int format : supportedFormats) { 994 assertTrue("Format " + format + " fails cross check", 995 config.isOutputSupportedFor(format)); 996 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes( 997 Arrays.asList(config.getOutputSizes(format)), /*ascending*/true); 998 if (arrayContains(actualCapabilities, 999 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 1000 supportedSizes.addAll( 1001 Arrays.asList(config.getHighResolutionOutputSizes(format))); 1002 supportedSizes = CameraTestUtils.getAscendingOrderSizes( 1003 supportedSizes, /*ascending*/true); 1004 } 1005 assertTrue("Supported format " + format + " has no sizes listed", 1006 supportedSizes.size() > 0); 1007 for (int i = 0; i < supportedSizes.size(); i++) { 1008 Size size = supportedSizes.get(i); 1009 if (VERBOSE) { 1010 Log.v(TAG, 1011 String.format("Testing camera %s, format %d, size %s", 1012 mIds[counter], format, size.toString())); 1013 } 1014 1015 long stallDuration = config.getOutputStallDuration(format, size); 1016 switch(format) { 1017 case ImageFormat.YUV_420_888: 1018 assertTrue("YUV_420_888 may not have a non-zero stall duration", 1019 stallDuration == 0); 1020 break; 1021 case ImageFormat.JPEG: 1022 case ImageFormat.RAW_SENSOR: 1023 final float TOLERANCE_FACTOR = 2.0f; 1024 long prevDuration = 0; 1025 if (i > 0) { 1026 prevDuration = config.getOutputStallDuration( 1027 format, supportedSizes.get(i - 1)); 1028 } 1029 long nextDuration = Long.MAX_VALUE; 1030 if (i < (supportedSizes.size() - 1)) { 1031 nextDuration = config.getOutputStallDuration( 1032 format, supportedSizes.get(i + 1)); 1033 } 1034 long curStallDuration = config.getOutputStallDuration(format, size); 1035 // Stall duration should be in a reasonable range: larger size should 1036 // normally have larger stall duration. 1037 mCollector.expectInRange("Stall duration (format " + format + 1038 " and size " + size + ") is not in the right range", 1039 curStallDuration, 1040 (long) (prevDuration / TOLERANCE_FACTOR), 1041 (long) (nextDuration * TOLERANCE_FACTOR)); 1042 break; 1043 default: 1044 assertTrue("Negative stall duration for format " + format, 1045 stallDuration >= 0); 1046 break; 1047 } 1048 long minDuration = config.getOutputMinFrameDuration(format, size); 1049 if (arrayContains(actualCapabilities, 1050 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1051 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1052 + "format " + format + " for size " + size + " minDuration " + 1053 minDuration, 1054 minDuration > 0); 1055 } else { 1056 assertTrue("Need non-negative min frame duration for format " + format, 1057 minDuration >= 0); 1058 } 1059 1060 // todo: test opaque image reader when it's supported. 1061 if (format != ImageFormat.PRIVATE) { 1062 ImageReader testReader = ImageReader.newInstance( 1063 size.getWidth(), 1064 size.getHeight(), 1065 format, 1066 1); 1067 Surface testSurface = testReader.getSurface(); 1068 1069 assertTrue( 1070 String.format("isOutputSupportedFor fails for config %s, format %d", 1071 size.toString(), format), 1072 config.isOutputSupportedFor(testSurface)); 1073 1074 testReader.close(); 1075 } 1076 } // sizes 1077 1078 // Try an invalid size in this format, should round 1079 Size invalidSize = findInvalidSize(supportedSizes); 1080 int MAX_ROUNDING_WIDTH = 1920; 1081 // todo: test opaque image reader when it's supported. 1082 if (format != ImageFormat.PRIVATE && 1083 invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) { 1084 ImageReader testReader = ImageReader.newInstance( 1085 invalidSize.getWidth(), 1086 invalidSize.getHeight(), 1087 format, 1088 1); 1089 Surface testSurface = testReader.getSurface(); 1090 1091 assertTrue( 1092 String.format("isOutputSupportedFor fails for config %s, %d", 1093 invalidSize.toString(), format), 1094 config.isOutputSupportedFor(testSurface)); 1095 1096 testReader.close(); 1097 } 1098 } // formats 1099 1100 // Cross-check opaque format and sizes 1101 if (arrayContains(actualCapabilities, BC)) { 1102 SurfaceTexture st = new SurfaceTexture(1); 1103 Surface surf = new Surface(st); 1104 1105 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class, 1106 mIds[counter], mCameraManager); 1107 assertTrue("Opaque format has no sizes listed", 1108 opaqueSizes.length > 0); 1109 for (Size size : opaqueSizes) { 1110 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size); 1111 assertTrue("Opaque output may not have a non-zero stall duration", 1112 stallDuration == 0); 1113 1114 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size); 1115 if (arrayContains(actualCapabilities, 1116 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 1117 assertTrue("MANUAL_SENSOR capability, need positive min frame duration for" 1118 + "opaque format", 1119 minDuration > 0); 1120 } else { 1121 assertTrue("Need non-negative min frame duration for opaque format ", 1122 minDuration >= 0); 1123 } 1124 st.setDefaultBufferSize(size.getWidth(), size.getHeight()); 1125 1126 assertTrue( 1127 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1128 size.toString()), 1129 config.isOutputSupportedFor(surf)); 1130 1131 } // opaque sizes 1132 1133 // Try invalid opaque size, should get rounded 1134 Size invalidSize = findInvalidSize(opaqueSizes); 1135 st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight()); 1136 assertTrue( 1137 String.format("isOutputSupportedFor fails for SurfaceTexture config %s", 1138 invalidSize.toString()), 1139 config.isOutputSupportedFor(surf)); 1140 1141 } 1142 counter++; 1143 } // mCharacteristics 1144 } 1145 1146 /** 1147 * Test high speed capability and cross-check the high speed sizes and fps ranges from 1148 * the StreamConfigurationMap. 1149 */ testConstrainedHighSpeedCapability()1150 public void testConstrainedHighSpeedCapability() throws Exception { 1151 int counter = 0; 1152 for (CameraCharacteristics c : mCharacteristics) { 1153 int[] capabilities = CameraTestUtils.getValueNotNull( 1154 c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); 1155 boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED); 1156 if (supportHighSpeed) { 1157 StreamConfigurationMap config = 1158 CameraTestUtils.getValueNotNull( 1159 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1160 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes()); 1161 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0); 1162 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE, 1163 mIds[counter], mCameraManager); 1164 assertTrue("Normal size for PRIVATE format shouldn't be null or empty", 1165 allSizes != null && allSizes.length > 0); 1166 for (Size size: highSpeedSizes) { 1167 // The sizes must be a subset of the normal sizes 1168 assertTrue("High speed size " + size + 1169 " must be part of normal sizes " + Arrays.toString(allSizes), 1170 Arrays.asList(allSizes).contains(size)); 1171 1172 // Sanitize the high speed FPS ranges for each size 1173 List<Range<Integer>> ranges = 1174 Arrays.asList(config.getHighSpeedVideoFpsRangesFor(size)); 1175 for (Range<Integer> range : ranges) { 1176 assertTrue("The range " + range + " doesn't satisfy the" 1177 + " min/max boundary requirements.", 1178 range.getLower() >= HIGH_SPEED_FPS_LOWER_MIN && 1179 range.getUpper() >= HIGH_SPEED_FPS_UPPER_MIN); 1180 assertTrue("The range " + range + " should be multiple of 30fps", 1181 range.getLower() % 30 == 0 && range.getUpper() % 30 == 0); 1182 // If the range is fixed high speed range, it should contain the 1183 // [30, fps_max] in the high speed range list; if it's variable FPS range, 1184 // the corresponding fixed FPS Range must be included in the range list. 1185 if (range.getLower() == range.getUpper()) { 1186 Range<Integer> variableRange = new Range<Integer>(30, range.getUpper()); 1187 assertTrue("The variable FPS range " + variableRange + 1188 " shoould be included in the high speed ranges for size " + 1189 size, ranges.contains(variableRange)); 1190 } else { 1191 Range<Integer> fixedRange = 1192 new Range<Integer>(range.getUpper(), range.getUpper()); 1193 assertTrue("The fixed FPS range " + fixedRange + 1194 " shoould be included in the high speed ranges for size " + 1195 size, ranges.contains(fixedRange)); 1196 } 1197 } 1198 } 1199 // If the device advertise some high speed profiles, the sizes and FPS ranges 1200 // should be advertise by the camera. 1201 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P; 1202 quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) { 1203 int cameraId = Integer.valueOf(mIds[counter]); 1204 if (CamcorderProfile.hasProfile(cameraId, quality)) { 1205 CamcorderProfile profile = CamcorderProfile.get(cameraId, 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