blob: 35f623aeab89645c7f36679c6dd8ce0b8ffcb2b5 [file] [log] [blame]
Igor Murashkinde096f72013-12-16 17:18:33 -08001/*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware.camera2.cts.helpers;
18
Zhijun He984ff7e2014-03-30 12:40:27 -070019import android.graphics.Rect;
Zhijun He44efda22014-04-03 22:15:02 -070020import android.graphics.ImageFormat;
Igor Murashkinde096f72013-12-16 17:18:33 -080021import android.hardware.camera2.CameraCharacteristics;
Igor Murashkin94399742014-05-19 16:38:37 -070022import android.hardware.camera2.CameraCharacteristics.Key;
Igor Murashkinde096f72013-12-16 17:18:33 -080023import android.hardware.camera2.CameraMetadata;
Igor Murashkinb2b17eb2014-07-24 18:20:03 -070024import android.hardware.camera2.CaptureRequest;
25import android.hardware.camera2.CaptureResult;
Zhijun He91098b42014-03-26 13:11:08 -070026import android.hardware.camera2.cts.CameraTestUtils;
Igor Murashkinffb1ee52014-05-13 17:31:33 -070027import android.hardware.camera2.params.StreamConfigurationMap;
Yin-Chia Yehb6653592014-07-24 16:07:38 -070028import android.util.Range;
29import android.util.Size;
Igor Murashkinde096f72013-12-16 17:18:33 -080030import android.util.Log;
Igor Murashkind5a33df2014-05-14 17:01:09 -070031import android.util.Rational;
Igor Murashkinde096f72013-12-16 17:18:33 -080032
Zhijun He5f4d0082014-03-19 23:02:03 -070033import junit.framework.Assert;
34
Igor Murashkinde096f72013-12-16 17:18:33 -080035import java.lang.reflect.Array;
Zhijun He8c8fb1e2014-03-20 14:57:48 -070036import java.util.ArrayList;
Zhijun He91098b42014-03-26 13:11:08 -070037import java.util.Arrays;
Yin-Chia Yehe74968d2014-08-18 13:55:13 -070038import java.util.Collection;
Zhijun He99e05372014-04-13 20:11:22 -070039import java.util.HashMap;
Zhijun He91098b42014-03-26 13:11:08 -070040import java.util.HashSet;
Zhijun He8c8fb1e2014-03-20 14:57:48 -070041import java.util.List;
Zhijun He91098b42014-03-26 13:11:08 -070042import java.util.Set;
Igor Murashkinde096f72013-12-16 17:18:33 -080043
44/**
45 * Helpers to get common static info out of the camera.
46 *
47 * <p>Avoid boiler plate by putting repetitive get/set patterns in this class.</p>
48 *
49 * <p>Attempt to be durable against the camera device having bad or missing metadata
50 * by providing reasonable defaults and logging warnings when that happens.</p>
51 */
52public class StaticMetadata {
53
54 private static final String TAG = "StaticMetadata";
55 private static final int IGNORE_SIZE_CHECK = -1;
56
Zhijun He28f2b3e2014-02-26 14:15:18 -080057 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
Zhijun He5f4d0082014-03-19 23:02:03 -070058 private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
Zhijun He28f2b3e2014-02-26 14:15:18 -080059 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
Zhijun Hec0f01e32014-10-30 14:13:36 -070060 private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800;
Zhijun He984ff7e2014-03-30 12:40:27 -070061 private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
62 private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
Zhijun He39809f52014-04-23 16:06:59 -070063 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
64 private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX = 2;
65 private static final Rational CONTROL_AE_COMPENSATION_STEP_DEFAULT = new Rational(1, 2);
Zhijun He98dc8f92014-05-13 17:29:01 -070066 private static final byte REQUEST_PIPELINE_MAX_DEPTH_MAX = 8;
Zhijun He28f2b3e2014-02-26 14:15:18 -080067
Igor Murashkinde096f72013-12-16 17:18:33 -080068 // TODO: Consider making this work across any metadata object, not just camera characteristics
69 private final CameraCharacteristics mCharacteristics;
Zhijun He5f4d0082014-03-19 23:02:03 -070070 private final CheckLevel mLevel;
71 private final CameraErrorCollector mCollector;
72
73 public enum CheckLevel {
74 /** Only log warnings for metadata check failures. Execution continues. */
75 WARN,
76 /**
77 * Use ErrorCollector to collect the metadata check failures, Execution
78 * continues.
79 */
80 COLLECT,
81 /** Assert the metadata check failures. Execution aborts. */
82 ASSERT
83 }
Igor Murashkinde096f72013-12-16 17:18:33 -080084
85 /**
86 * Construct a new StaticMetadata object.
87 *
Zhijun He5f4d0082014-03-19 23:02:03 -070088 *<p> Default constructor, only log warnings for the static metadata check failures</p>
89 *
Igor Murashkinde096f72013-12-16 17:18:33 -080090 * @param characteristics static info for a camera
91 * @throws IllegalArgumentException if characteristics was null
92 */
93 public StaticMetadata(CameraCharacteristics characteristics) {
Zhijun He5f4d0082014-03-19 23:02:03 -070094 this(characteristics, CheckLevel.WARN, /*collector*/null);
95 }
96
97 /**
98 * Construct a new StaticMetadata object with {@link CameraErrorCollector}.
99 * <p>
100 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
101 * ignored, otherwise, it will be used to log the check failures.
102 * </p>
103 *
104 * @param characteristics static info for a camera
105 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
106 * @throws IllegalArgumentException if characteristics or collector was null.
107 */
108 public StaticMetadata(CameraCharacteristics characteristics, CameraErrorCollector collector) {
109 this(characteristics, CheckLevel.COLLECT, collector);
110 }
111
112 /**
113 * Construct a new StaticMetadata object with {@link CheckLevel} and
114 * {@link CameraErrorCollector}.
115 * <p>
116 * When level is not {@link CheckLevel.COLLECT}, the {@link CameraErrorCollector} will be
117 * ignored, otherwise, it will be used to log the check failures.
118 * </p>
119 *
120 * @param characteristics static info for a camera
121 * @param level The {@link CheckLevel} of this StaticMetadata
122 * @param collector The {@link CameraErrorCollector} used by this StaticMetadata
123 * @throws IllegalArgumentException if characteristics was null or level was
124 * {@link CheckLevel.COLLECT} but collector was null.
125 */
126 public StaticMetadata(CameraCharacteristics characteristics, CheckLevel level,
127 CameraErrorCollector collector) {
Igor Murashkinde096f72013-12-16 17:18:33 -0800128 if (characteristics == null) {
129 throw new IllegalArgumentException("characteristics was null");
130 }
Zhijun He5f4d0082014-03-19 23:02:03 -0700131 if (level == CheckLevel.COLLECT && collector == null) {
132 throw new IllegalArgumentException("collector must valid when COLLECT level is set");
133 }
Igor Murashkinde096f72013-12-16 17:18:33 -0800134
135 mCharacteristics = characteristics;
Zhijun He5f4d0082014-03-19 23:02:03 -0700136 mLevel = level;
137 mCollector = collector;
Igor Murashkinde096f72013-12-16 17:18:33 -0800138 }
139
140 /**
141 * Get the CameraCharacteristics associated with this StaticMetadata.
142 *
143 * @return A non-null CameraCharacteristics object
144 */
145 public CameraCharacteristics getCharacteristics() {
146 return mCharacteristics;
147 }
148
149 /**
150 * Whether or not the hardware level reported by android.info.supportedHardwareLevel
151 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL}.
152 *
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700153 * <p>If the camera device is not reporting the hardwareLevel, this
154 * will cause the test to fail.</p>
Igor Murashkinde096f72013-12-16 17:18:33 -0800155 *
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700156 * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
Igor Murashkinde096f72013-12-16 17:18:33 -0800157 */
158 public boolean isHardwareLevelFull() {
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700159 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
160 }
Igor Murashkinde096f72013-12-16 17:18:33 -0800161
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700162 /**
163 * Whether or not the hardware level reported by android.info.supportedHardwareLevel
Ruben Brunk77034932014-07-01 16:56:52 -0700164 * Return the supported hardware level of the device, or fail if no value is reported.
165 *
166 * @return the supported hardware level as a constant defined for
167 * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
168 */
169 public int getHardwareLevelChecked() {
170 Integer hwLevel = getValueFromKeyNonNull(
171 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
172 if (hwLevel == null) {
173 Assert.fail("No supported hardware level reported.");
174 }
175 return hwLevel;
176 }
177
178 /**
179 * Whether or not the hardware level reported by android.info.supportedHardwareLevel
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700180 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}.
181 *
182 * <p>If the camera device is not reporting the hardwareLevel, this
183 * will cause the test to fail.</p>
184 *
185 * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
186 */
187 public boolean isHardwareLevelLegacy() {
188 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
Igor Murashkinde096f72013-12-16 17:18:33 -0800189 }
190
191 /**
Zhijun Hefd84d852014-04-13 23:11:15 -0700192 * Whether or not the per frame control is supported by the camera device.
193 *
Ruben Brunkbc301062014-07-29 22:40:00 -0700194 * @return {@code true} if per frame control is supported, {@code false} otherwise.
Zhijun Hefd84d852014-04-13 23:11:15 -0700195 */
196 public boolean isPerFrameControlSupported() {
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700197 return getSyncMaxLatency() == CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
198 }
Zhijun Hefd84d852014-04-13 23:11:15 -0700199
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700200 /**
201 * Get the maximum number of frames to wait for a request settings being applied
202 *
203 * @return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN for unknown latency
204 * CameraMetadata.SYNC_MAX_LATENCY_PER_FRAME_CONTROL for per frame control
205 * a positive int otherwise
206 */
207 public int getSyncMaxLatency() {
208 Integer value = getValueFromKeyNonNull(CameraCharacteristics.SYNC_MAX_LATENCY);
209 if (value == null) {
210 return CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN;
Zhijun Hefd84d852014-04-13 23:11:15 -0700211 }
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700212 return value;
Zhijun Hefd84d852014-04-13 23:11:15 -0700213 }
214
215 /**
Igor Murashkinde096f72013-12-16 17:18:33 -0800216 * Whether or not the hardware level reported by android.info.supportedHardwareLevel
217 * is {@value CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
218 *
219 * <p>If the camera device is incorrectly reporting the hardwareLevel, this
220 * will always return {@code true}.</p>
221 *
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700222 * @return {@code true} if the device is {@code LIMITED}, {@code false} otherwise.
Igor Murashkinde096f72013-12-16 17:18:33 -0800223 */
224 public boolean isHardwareLevelLimited() {
Igor Murashkin62cd9c92014-07-07 11:20:00 -0700225 return getHardwareLevelChecked() == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
226 }
227
228 /**
229 * Whether or not the hardware level reported by {@code android.info.supportedHardwareLevel}
230 * is at least {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED}.
231 *
232 * <p>If the camera device is incorrectly reporting the hardwareLevel, this
233 * will always return {@code false}.</p>
234 *
235 * @return
236 * {@code true} if the device is {@code LIMITED} or {@code FULL},
237 * {@code false} otherwise (i.e. LEGACY).
238 */
239 public boolean isHardwareLevelLimitedOrBetter() {
240 Integer hwLevel = getValueFromKeyNonNull(
241 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
242
243 if (hwLevel == null) {
244 return false;
245 }
246
247 // Normal. Device could be limited.
248 int hwLevelInt = hwLevel;
249 return hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
250 hwLevelInt == CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
Igor Murashkinde096f72013-12-16 17:18:33 -0800251 }
252
253 /**
Yin-Chia Yehad0c9942014-08-17 16:31:19 -0700254 * Get the maximum number of partial result a request can expect
255 *
256 * @return 1 if partial result is not supported.
257 * a integer value larger than 1 if partial result is supported.
258 */
259 public int getPartialResultCount() {
260 Integer value = mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);
261 if (value == null) {
262 // Optional key. Default value is 1 if key is missing.
263 return 1;
264 }
265 return value;
266 }
267
268 /**
Zhijun He28f2b3e2014-02-26 14:15:18 -0800269 * Get the exposure time value and clamp to the range if needed.
270 *
271 * @param exposure Input exposure time value to check.
272 * @return Exposure value in the legal range.
273 */
274 public long getExposureClampToRange(long exposure) {
275 long minExposure = getExposureMinimumOrDefault(Long.MAX_VALUE);
276 long maxExposure = getExposureMaximumOrDefault(Long.MIN_VALUE);
277 if (minExposure > SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST) {
Zhijun He5f4d0082014-03-19 23:02:03 -0700278 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
Zhijun He28f2b3e2014-02-26 14:15:18 -0800279 String.format(
280 "Min value %d is too large, set to maximal legal value %d",
281 minExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST));
282 minExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST;
283 }
284 if (maxExposure < SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST) {
Zhijun He5f4d0082014-03-19 23:02:03 -0700285 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
Zhijun He28f2b3e2014-02-26 14:15:18 -0800286 String.format(
287 "Max value %d is too small, set to minimal legal value %d",
288 maxExposure, SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST));
289 maxExposure = SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST;
290 }
291
292 return Math.max(minExposure, Math.min(maxExposure, exposure));
293 }
294
295 /**
Zhijun Heea4bb052014-04-06 23:29:52 -0700296 * Check if the camera device support focuser.
297 *
298 * @return true if camera device support focuser, false otherwise.
299 */
300 public boolean hasFocuser() {
Igor Murashkinb2b17eb2014-07-24 18:20:03 -0700301 if (areKeysAvailable(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)) {
302 // LEGACY devices don't have lens.info.minimumFocusDistance, so guard this query
303 return (getMinimumFocusDistanceChecked() > 0);
304 } else {
305 // Check available AF modes
306 int[] availableAfModes = mCharacteristics.get(
307 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
308
309 if (availableAfModes == null) {
310 return false;
311 }
312
313 // Assume that if we have an AF mode which doesn't ignore AF trigger, we have a focuser
314 boolean hasFocuser = false;
315 loop: for (int mode : availableAfModes) {
316 switch (mode) {
317 case CameraMetadata.CONTROL_AF_MODE_AUTO:
318 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
319 case CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
320 case CameraMetadata.CONTROL_AF_MODE_MACRO:
321 hasFocuser = true;
322 break loop;
323 }
324 }
325
326 return hasFocuser;
327 }
Zhijun Hef2d26f12014-04-14 10:36:55 -0700328 }
329
330 /**
Zhijun Hed72b9502014-04-27 17:19:23 -0700331 * Check if the camera device has flash unit.
332 * @return true if flash unit is available, false otherwise.
333 */
334 public boolean hasFlash() {
335 return getFlashInfoChecked();
336 }
337
338 /**
Zhijun Hef2d26f12014-04-14 10:36:55 -0700339 * Get minimum focus distance.
340 *
341 * @return minimum focus distance, 0 if minimum focus distance is invalid.
342 */
343 public float getMinimumFocusDistanceChecked() {
Zhijun Heea4bb052014-04-06 23:29:52 -0700344 Key<Float> key = CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE;
Igor Murashkin9763b122014-06-19 15:45:27 -0700345 Float minFocusDistance;
346
347 /**
348 * android.lens.info.minimumFocusDistance - required for FULL and MANUAL_SENSOR-capable
349 * devices; optional for all other devices.
350 */
351 if (isHardwareLevelFull() || isCapabilitySupported(
352 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
353 minFocusDistance = getValueFromKeyNonNull(key);
354 } else {
355 minFocusDistance = mCharacteristics.get(key);
356 }
Zhijun Heea4bb052014-04-06 23:29:52 -0700357
358 if (minFocusDistance == null) {
Zhijun Hef2d26f12014-04-14 10:36:55 -0700359 return 0.0f;
Zhijun Heea4bb052014-04-06 23:29:52 -0700360 }
361
Zhijun Hef2d26f12014-04-14 10:36:55 -0700362 checkTrueForKey(key, " minFocusDistance value shouldn't be negative",
363 minFocusDistance >= 0);
364 if (minFocusDistance < 0) {
365 minFocusDistance = 0.0f;
366 }
367
368 return minFocusDistance;
369 }
370
371 /**
372 * Get focusDistanceCalibration.
373 *
374 * @return focusDistanceCalibration, UNCALIBRATED if value is invalid.
375 */
376 public int getFocusDistanceCalibrationChecked() {
377 Key<Integer> key = CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
378 Integer calibration = getValueFromKeyNonNull(key);
379
380 if (calibration == null) {
381 return CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
382 }
383
384 checkTrueForKey(key, " value is out of range" ,
385 calibration >= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED &&
386 calibration <= CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED);
387
388 return calibration;
Zhijun Heea4bb052014-04-06 23:29:52 -0700389 }
390
391 /**
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -0700392 * Get max AE regions and do sanity check.
Zhijun Heea4bb052014-04-06 23:29:52 -0700393 *
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -0700394 * @return AE max regions supported by the camera device
Zhijun Heea4bb052014-04-06 23:29:52 -0700395 */
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -0700396 public int getAeMaxRegionsChecked() {
397 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
398 if (regionCount == null) {
399 return 0;
Zhijun Heea4bb052014-04-06 23:29:52 -0700400 }
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -0700401 return regionCount;
Zhijun Heea4bb052014-04-06 23:29:52 -0700402 }
403
404 /**
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -0700405 * Get max AWB regions and do sanity check.
406 *
407 * @return AWB max regions supported by the camera device
408 */
409 public int getAwbMaxRegionsChecked() {
410 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
411 if (regionCount == null) {
412 return 0;
413 }
414 return regionCount;
415 }
416
417 /**
418 * Get max AF regions and do sanity check.
419 *
420 * @return AF max regions supported by the camera device
421 */
422 public int getAfMaxRegionsChecked() {
423 Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
424 if (regionCount == null) {
425 return 0;
426 }
427 return regionCount;
428 }
429 /**
Zhijun He5f4d0082014-03-19 23:02:03 -0700430 * Get the available anti-banding modes.
431 *
432 * @return The array contains available anti-banding modes.
433 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700434 public int[] getAeAvailableAntiBandingModesChecked() {
435 Key<int[]> key = CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
436 int[] modes = getValueFromKeyNonNull(key);
Zhijun He5f4d0082014-03-19 23:02:03 -0700437
438 boolean foundAuto = false;
Yin-Chia Yeh9ecdbaf2014-11-25 11:56:01 -0800439 boolean found50Hz = false;
440 boolean found60Hz = false;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700441 for (int mode : modes) {
Zhijun He5f4d0082014-03-19 23:02:03 -0700442 checkTrueForKey(key, "mode value " + mode + " is out if range",
443 mode >= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF ||
444 mode <= CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO);
445 if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_AUTO) {
446 foundAuto = true;
Yin-Chia Yeh9ecdbaf2014-11-25 11:56:01 -0800447 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_50HZ) {
448 found50Hz = true;
449 } else if (mode == CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_60HZ) {
450 found60Hz = true;
Zhijun He5f4d0082014-03-19 23:02:03 -0700451 }
452 }
Yin-Chia Yeh9ecdbaf2014-11-25 11:56:01 -0800453 // Must contain AUTO mode or one of 50/60Hz mode.
454 checkTrueForKey(key, "Either AUTO mode or both 50HZ/60HZ mode should present",
455 foundAuto || (found50Hz && found60Hz));
Zhijun He5f4d0082014-03-19 23:02:03 -0700456
457 return modes;
458 }
459
Zhijun He45942de2014-05-13 12:48:27 -0700460 /**
461 * Check if the antibanding OFF mode is supported.
462 *
463 * @return true if antibanding OFF mode is supported, false otherwise.
464 */
465 public boolean isAntiBandingOffModeSupported() {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700466 List<Integer> antiBandingModes =
Zhijun He45942de2014-05-13 12:48:27 -0700467 Arrays.asList(CameraTestUtils.toObject(getAeAvailableAntiBandingModesChecked()));
468
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700469 return antiBandingModes.contains(CameraMetadata.CONTROL_AE_ANTIBANDING_MODE_OFF);
Zhijun He45942de2014-05-13 12:48:27 -0700470 }
471
Zhijun Heed9cd312014-03-24 23:15:52 -0700472 public Boolean getFlashInfoChecked() {
Zhijun He984ff7e2014-03-30 12:40:27 -0700473 Key<Boolean> key = CameraCharacteristics.FLASH_INFO_AVAILABLE;
Zhijun Heed9cd312014-03-24 23:15:52 -0700474 Boolean hasFlash = getValueFromKeyNonNull(key);
475
476 // In case the failOnKey only gives warning.
477 if (hasFlash == null) {
478 return false;
479 }
480
481 return hasFlash;
482 }
483
Zhijun Hebf0b55f2014-03-27 23:57:15 -0700484 public int[] getAvailableTestPatternModesChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -0700485 Key<int[]> key =
Zhijun Hebf0b55f2014-03-27 23:57:15 -0700486 CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES;
487 int[] modes = getValueFromKeyNonNull(key);
488
489 if (modes == null) {
490 return new int[0];
491 }
492
493 int expectValue = CameraCharacteristics.SENSOR_TEST_PATTERN_MODE_OFF;
494 Integer[] boxedModes = CameraTestUtils.toObject(modes);
495 checkTrueForKey(key, " value must contain OFF mode",
496 Arrays.asList(boxedModes).contains(expectValue));
497
498 return modes;
499 }
500
Zhijun He5f4d0082014-03-19 23:02:03 -0700501 /**
Zhijun He91098b42014-03-26 13:11:08 -0700502 * Get available thumbnail sizes and do the sanity check.
503 *
504 * @return The array of available thumbnail sizes
505 */
506 public Size[] getAvailableThumbnailSizesChecked() {
Zhijun He984ff7e2014-03-30 12:40:27 -0700507 Key<Size[]> key = CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES;
Zhijun He91098b42014-03-26 13:11:08 -0700508 Size[] sizes = getValueFromKeyNonNull(key);
509 final List<Size> sizeList = Arrays.asList(sizes);
510
511 // Size must contain (0, 0).
512 checkTrueForKey(key, "size should contain (0, 0)", sizeList.contains(new Size(0, 0)));
513
514 // Each size must be distinct.
Zhijun He984ff7e2014-03-30 12:40:27 -0700515 checkElementDistinct(key, sizeList);
Zhijun He91098b42014-03-26 13:11:08 -0700516
517 // Must be sorted in ascending order by area, by width if areas are same.
518 List<Size> orderedSizes =
519 CameraTestUtils.getAscendingOrderSizes(sizeList, /*ascending*/true);
520 checkTrueForKey(key, "Sizes should be in ascending order: Original " + sizeList.toString()
521 + ", Expected " + orderedSizes.toString(), orderedSizes.equals(sizeList));
522
523 // TODO: Aspect ratio match, need wait for android.scaler.availableStreamConfigurations
524 // implementation see b/12958122.
525
526 return sizes;
527 }
528
529 /**
530 * Get available focal lengths and do the sanity check.
531 *
532 * @return The array of available focal lengths
533 */
534 public float[] getAvailableFocalLengthsChecked() {
Zhijun He984ff7e2014-03-30 12:40:27 -0700535 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS;
Zhijun He91098b42014-03-26 13:11:08 -0700536 float[] focalLengths = getValueFromKeyNonNull(key);
537
538 checkTrueForKey(key, "Array should contain at least one element", focalLengths.length >= 1);
539
540 for (int i = 0; i < focalLengths.length; i++) {
541 checkTrueForKey(key,
542 String.format("focalLength[%d] %f should be positive.", i, focalLengths[i]),
543 focalLengths[i] > 0);
544 }
Zhijun He984ff7e2014-03-30 12:40:27 -0700545 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(focalLengths)));
Zhijun He91098b42014-03-26 13:11:08 -0700546
547 return focalLengths;
548 }
549
550 /**
551 * Get available apertures and do the sanity check.
552 *
Zhijun He984ff7e2014-03-30 12:40:27 -0700553 * @return The non-null array of available apertures
Zhijun He91098b42014-03-26 13:11:08 -0700554 */
555 public float[] getAvailableAperturesChecked() {
Zhijun He984ff7e2014-03-30 12:40:27 -0700556 Key<float[]> key = CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES;
Zhijun He91098b42014-03-26 13:11:08 -0700557 float[] apertures = getValueFromKeyNonNull(key);
558
559 checkTrueForKey(key, "Array should contain at least one element", apertures.length >= 1);
560
561 for (int i = 0; i < apertures.length; i++) {
562 checkTrueForKey(key,
563 String.format("apertures[%d] %f should be positive.", i, apertures[i]),
564 apertures[i] > 0);
565 }
Zhijun He984ff7e2014-03-30 12:40:27 -0700566 checkElementDistinct(key, Arrays.asList(CameraTestUtils.toObject(apertures)));
Zhijun He91098b42014-03-26 13:11:08 -0700567
568 return apertures;
569 }
570
571 /**
Yin-Chia Yehb6653592014-07-24 16:07:38 -0700572 * Get and check the available hot pixel map modes.
573 *
574 * @return the available hot pixel map modes
575 */
Ruben Brunk43e260f2014-07-09 12:56:02 -0700576 public int[] getAvailableHotPixelModesChecked() {
Yin-Chia Yehb6653592014-07-24 16:07:38 -0700577 Key<int[]> key = CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
578 int[] modes = getValueFromKeyNonNull(key);
579
580 if (modes == null) {
581 return new int[0];
582 }
583
584 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
585 if (isHardwareLevelFull()) {
586 checkTrueForKey(key, "Full-capability camera devices must support FAST mode",
587 modeList.contains(CameraMetadata.HOT_PIXEL_MODE_FAST));
588 }
589 checkElementDistinct(key, modeList);
590 checkArrayValuesInRange(key, modes, CameraMetadata.HOT_PIXEL_MODE_OFF,
591 CameraMetadata.HOT_PIXEL_MODE_HIGH_QUALITY);
592
593 return modes;
594 }
595
596 /**
Zhijun He984ff7e2014-03-30 12:40:27 -0700597 * Get and check available face detection modes.
598 *
599 * @return The non-null array of available face detection modes
600 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700601 public int[] getAvailableFaceDetectModesChecked() {
602 Key<int[]> key = CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
603 int[] modes = getValueFromKeyNonNull(key);
Zhijun He984ff7e2014-03-30 12:40:27 -0700604
605 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700606 return new int[0];
Zhijun He984ff7e2014-03-30 12:40:27 -0700607 }
608
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700609 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Zhijun He984ff7e2014-03-30 12:40:27 -0700610 checkTrueForKey(key, "Array should contain OFF mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700611 modeList.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF));
Zhijun He984ff7e2014-03-30 12:40:27 -0700612 checkElementDistinct(key, modeList);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700613 checkArrayValuesInRange(key, modes, CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF,
614 CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL);
Zhijun He984ff7e2014-03-30 12:40:27 -0700615
616 return modes;
617 }
618
619 /**
620 * Get and check max face detected count.
621 *
622 * @return max number of faces that can be detected
623 */
624 public int getMaxFaceCountChecked() {
625 Key<Integer> key = CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT;
626 Integer count = getValueFromKeyNonNull(key);
627
628 if (count == null) {
629 return 0;
630 }
631
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700632 List<Integer> faceDetectModes =
Zhijun He984ff7e2014-03-30 12:40:27 -0700633 Arrays.asList(CameraTestUtils.toObject(getAvailableFaceDetectModesChecked()));
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700634 if (faceDetectModes.contains(CameraMetadata.STATISTICS_FACE_DETECT_MODE_OFF) &&
Zhijun He984ff7e2014-03-30 12:40:27 -0700635 faceDetectModes.size() == 1) {
636 checkTrueForKey(key, " value must be 0 if only OFF mode is supported in "
637 + "availableFaceDetectionModes", count == 0);
638 } else {
Ruben Brunk50a01a32014-09-19 16:16:31 -0700639 int maxFaceCountAtLeast = STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST;
640
641 // Legacy mode may support fewer than STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST faces.
642 if (isHardwareLevelLegacy()) {
643 maxFaceCountAtLeast = 1;
644 }
645 checkTrueForKey(key, " value must be no less than " + maxFaceCountAtLeast + " if SIMPLE"
Zhijun He984ff7e2014-03-30 12:40:27 -0700646 + "or FULL is also supported in availableFaceDetectionModes",
Ruben Brunk50a01a32014-09-19 16:16:31 -0700647 count >= maxFaceCountAtLeast);
Zhijun He984ff7e2014-03-30 12:40:27 -0700648 }
649
650 return count;
651 }
652
653 /**
654 * Get and check the available tone map modes.
655 *
Yin-Chia Yehb6653592014-07-24 16:07:38 -0700656 * @return the available tone map modes
Zhijun He984ff7e2014-03-30 12:40:27 -0700657 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700658 public int[] getAvailableToneMapModesChecked() {
659 Key<int[]> key = CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES;
660 int[] modes = getValueFromKeyNonNull(key);
Zhijun He984ff7e2014-03-30 12:40:27 -0700661
662 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700663 return new int[0];
Zhijun He984ff7e2014-03-30 12:40:27 -0700664 }
665
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700666 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Zhijun Hee04e84a2014-04-18 10:46:02 -0700667 checkTrueForKey(key, " Camera devices must always support FAST mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700668 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
Yin-Chia Yehe7933802014-12-19 13:35:24 -0800669 if (isCapabilitySupported(
670 CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING)) {
671 checkTrueForKey(key, "MANUAL_POST_PROCESSING supported camera devices must support"
Zhijun Hee04e84a2014-04-18 10:46:02 -0700672 + "CONTRAST_CURVE mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700673 modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE) &&
674 modeList.contains(CameraMetadata.TONEMAP_MODE_FAST));
Zhijun He984ff7e2014-03-30 12:40:27 -0700675 }
676 checkElementDistinct(key, modeList);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700677 checkArrayValuesInRange(key, modes, CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE,
678 CameraMetadata.TONEMAP_MODE_HIGH_QUALITY);
Zhijun He984ff7e2014-03-30 12:40:27 -0700679
680 return modes;
681 }
682
683 /**
684 * Get and check max tonemap curve point.
685 *
686 * @return Max tonemap curve points.
687 */
688 public int getMaxTonemapCurvePointChecked() {
689 Key<Integer> key = CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS;
690 Integer count = getValueFromKeyNonNull(key);
691
692 if (count == null) {
693 return 0;
694 }
695
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700696 List<Integer> modeList =
Zhijun He984ff7e2014-03-30 12:40:27 -0700697 Arrays.asList(CameraTestUtils.toObject(getAvailableToneMapModesChecked()));
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700698 if (modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE)) {
Zhijun He984ff7e2014-03-30 12:40:27 -0700699 checkTrueForKey(key, "Full-capability camera device must support maxCurvePoints "
700 + ">= " + TONEMAP_MAX_CURVE_POINTS_AT_LEAST,
701 count >= TONEMAP_MAX_CURVE_POINTS_AT_LEAST);
702 }
703
704 return count;
705 }
706
707 /**
708 * Get and check pixel array size.
709 */
710 public Size getPixelArraySizeChecked() {
711 Key<Size> key = CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE;
712 Size pixelArray = getValueFromKeyNonNull(key);
713 if (pixelArray == null) {
714 return new Size(0, 0);
715 }
716
717 return pixelArray;
718 }
719
720 /**
721 * Get and check active array size.
722 */
723 public Rect getActiveArraySizeChecked() {
724 Key<Rect> key = CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE;
725 Rect activeArray = getValueFromKeyNonNull(key);
726
727 if (activeArray == null) {
728 return new Rect(0, 0, 0, 0);
729 }
730
731 Size pixelArraySize = getPixelArraySizeChecked();
732 checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
733 checkTrueForKey(key, "values width/height are invalid",
734 activeArray.width() <= pixelArraySize.getWidth() &&
735 activeArray.height() <= pixelArraySize.getHeight());
736
737 return activeArray;
738 }
739
740 /**
Zhijun He28f2b3e2014-02-26 14:15:18 -0800741 * Get the sensitivity value and clamp to the range if needed.
742 *
743 * @param sensitivity Input sensitivity value to check.
744 * @return Sensitivity value in legal range.
745 */
746 public int getSensitivityClampToRange(int sensitivity) {
747 int minSensitivity = getSensitivityMinimumOrDefault(Integer.MAX_VALUE);
748 int maxSensitivity = getSensitivityMaximumOrDefault(Integer.MIN_VALUE);
749 if (minSensitivity > SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST) {
Zhijun He5f4d0082014-03-19 23:02:03 -0700750 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
Zhijun He28f2b3e2014-02-26 14:15:18 -0800751 String.format(
752 "Min value %d is too large, set to maximal legal value %d",
753 minSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST));
754 minSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST;
755 }
756 if (maxSensitivity < SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST) {
Zhijun He5f4d0082014-03-19 23:02:03 -0700757 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
Zhijun He28f2b3e2014-02-26 14:15:18 -0800758 String.format(
759 "Max value %d is too small, set to minimal legal value %d",
760 maxSensitivity, SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST));
761 maxSensitivity = SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST;
762 }
763
764 return Math.max(minSensitivity, Math.min(maxSensitivity, sensitivity));
765 }
766
767 /**
Zhijun Hedba6dd12014-04-29 18:41:49 -0700768 * Get maxAnalogSensitivity for a camera device.
769 * <p>
770 * This is only available for FULL capability device, return 0 if it is unavailable.
771 * </p>
772 *
773 * @return maxAnalogSensitivity, 0 if it is not available.
774 */
775 public int getMaxAnalogSensitivityChecked() {
Zhijun Hedba6dd12014-04-29 18:41:49 -0700776
Igor Murashkin94399742014-05-19 16:38:37 -0700777 Key<Integer> key = CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY;
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700778 Integer maxAnalogsensitivity = mCharacteristics.get(key);
Zhijun Hedba6dd12014-04-29 18:41:49 -0700779 if (maxAnalogsensitivity == null) {
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700780 if (isHardwareLevelFull()) {
781 Assert.fail("Full device should report max analog sensitivity");
782 }
Zhijun Hedba6dd12014-04-29 18:41:49 -0700783 return 0;
784 }
785
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700786 int minSensitivity = getSensitivityMinimumOrDefault();
787 int maxSensitivity = getSensitivityMaximumOrDefault();
Zhijun Hedba6dd12014-04-29 18:41:49 -0700788 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
789 + " should be no larger than max sensitivity " + maxSensitivity,
790 maxAnalogsensitivity <= maxSensitivity);
791 checkTrueForKey(key, " Max analog sensitivity " + maxAnalogsensitivity
792 + " should be larger than min sensitivity " + maxSensitivity,
793 maxAnalogsensitivity > minSensitivity);
794
795 return maxAnalogsensitivity;
796 }
797
798 /**
799 * Get hyperfocalDistance and do the sanity check.
800 * <p>
801 * Note that, this tag is optional, will return -1 if this tag is not
802 * available.
803 * </p>
804 *
805 * @return hyperfocalDistance of this device, -1 if this tag is not available.
806 */
807 public float getHyperfocalDistanceChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -0700808 Key<Float> key = CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE;
Zhijun Hedba6dd12014-04-29 18:41:49 -0700809 Float hyperfocalDistance = getValueFromKeyNonNull(key);
810 if (hyperfocalDistance == null) {
811 return -1;
812 }
813
814 if (hasFocuser()) {
815 float minFocusDistance = getMinimumFocusDistanceChecked();
816 checkTrueForKey(key, String.format(" hyperfocal distance %f should be in the range of"
Zhijun He76a03012014-05-06 17:01:30 -0700817 + " should be in the range of (%f, %f]", hyperfocalDistance, 0.0f,
Zhijun Hedba6dd12014-04-29 18:41:49 -0700818 minFocusDistance),
819 hyperfocalDistance > 0 && hyperfocalDistance <= minFocusDistance);
820 }
821
822 return hyperfocalDistance;
823 }
824
825 /**
Igor Murashkinde096f72013-12-16 17:18:33 -0800826 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
827 *
828 * <p>If the camera is incorrectly reporting values, log a warning and return
Igor Murashkin38271c72014-03-03 16:41:07 -0800829 * the default value instead, which is the largest minimum value required to be supported
830 * by all camera devices.</p>
831 *
832 * @return The value reported by the camera device or the defaultValue otherwise.
833 */
834 public int getSensitivityMinimumOrDefault() {
835 return getSensitivityMinimumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST);
836 }
837
838 /**
839 * Get the minimum value for a sensitivity range from android.sensor.info.sensitivityRange.
840 *
841 * <p>If the camera is incorrectly reporting values, log a warning and return
Igor Murashkinde096f72013-12-16 17:18:33 -0800842 * the default value instead.</p>
843 *
844 * @param defaultValue Value to return if no legal value is available
845 * @return The value reported by the camera device or the defaultValue otherwise.
846 */
847 public int getSensitivityMinimumOrDefault(int defaultValue) {
Ruben Brunka47c85a2014-05-27 18:56:57 -0700848 Range<Integer> range = getValueFromKeyNonNull(
849 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
850 if (range == null) {
851 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
852 "had no valid minimum value; using default of " + defaultValue);
853 return defaultValue;
854 }
855 return range.getLower();
Igor Murashkinde096f72013-12-16 17:18:33 -0800856 }
857
858 /**
859 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
860 *
861 * <p>If the camera is incorrectly reporting values, log a warning and return
Igor Murashkin38271c72014-03-03 16:41:07 -0800862 * the default value instead, which is the smallest maximum value required to be supported
863 * by all camera devices.</p>
864 *
865 * @return The value reported by the camera device or the defaultValue otherwise.
866 */
867 public int getSensitivityMaximumOrDefault() {
868 return getSensitivityMaximumOrDefault(SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST);
869 }
870
871 /**
872 * Get the maximum value for a sensitivity range from android.sensor.info.sensitivityRange.
873 *
874 * <p>If the camera is incorrectly reporting values, log a warning and return
Igor Murashkinde096f72013-12-16 17:18:33 -0800875 * the default value instead.</p>
876 *
877 * @param defaultValue Value to return if no legal value is available
878 * @return The value reported by the camera device or the defaultValue otherwise.
879 */
880 public int getSensitivityMaximumOrDefault(int defaultValue) {
Ruben Brunka47c85a2014-05-27 18:56:57 -0700881 Range<Integer> range = getValueFromKeyNonNull(
882 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
883 if (range == null) {
884 failKeyCheck(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
885 "had no valid maximum value; using default of " + defaultValue);
886 return defaultValue;
887 }
888 return range.getUpper();
Igor Murashkinde096f72013-12-16 17:18:33 -0800889 }
890
891 /**
892 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
893 *
894 * <p>If the camera is incorrectly reporting values, log a warning and return
895 * the default value instead.</p>
896 *
897 * @param defaultValue Value to return if no legal value is available
898 * @return The value reported by the camera device or the defaultValue otherwise.
899 */
900 public long getExposureMinimumOrDefault(long defaultValue) {
Ruben Brunka47c85a2014-05-27 18:56:57 -0700901 Range<Long> range = getValueFromKeyNonNull(
902 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
903 if (range == null) {
904 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
905 "had no valid minimum value; using default of " + defaultValue);
906 return defaultValue;
907 }
908 return range.getLower();
Igor Murashkinde096f72013-12-16 17:18:33 -0800909 }
910
911 /**
Igor Murashkin38271c72014-03-03 16:41:07 -0800912 * Get the minimum value for an exposure range from android.sensor.info.exposureTimeRange.
913 *
914 * <p>If the camera is incorrectly reporting values, log a warning and return
915 * the default value instead, which is the largest minimum value required to be supported
916 * by all camera devices.</p>
917 *
918 * @return The value reported by the camera device or the defaultValue otherwise.
919 */
920 public long getExposureMinimumOrDefault() {
921 return getExposureMinimumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST);
922 }
923
924 /**
Igor Murashkinde096f72013-12-16 17:18:33 -0800925 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
926 *
927 * <p>If the camera is incorrectly reporting values, log a warning and return
928 * the default value instead.</p>
929 *
930 * @param defaultValue Value to return if no legal value is available
931 * @return The value reported by the camera device or the defaultValue otherwise.
932 */
933 public long getExposureMaximumOrDefault(long defaultValue) {
Ruben Brunka47c85a2014-05-27 18:56:57 -0700934 Range<Long> range = getValueFromKeyNonNull(
935 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
936 if (range == null) {
937 failKeyCheck(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE,
938 "had no valid maximum value; using default of " + defaultValue);
939 return defaultValue;
940 }
941 return range.getUpper();
Igor Murashkinde096f72013-12-16 17:18:33 -0800942 }
943
944 /**
Igor Murashkin38271c72014-03-03 16:41:07 -0800945 * Get the maximum value for an exposure range from android.sensor.info.exposureTimeRange.
946 *
947 * <p>If the camera is incorrectly reporting values, log a warning and return
948 * the default value instead, which is the smallest maximum value required to be supported
949 * by all camera devices.</p>
950 *
951 * @return The value reported by the camera device or the defaultValue otherwise.
952 */
953 public long getExposureMaximumOrDefault() {
954 return getExposureMaximumOrDefault(SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST);
955 }
956
957 /**
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700958 * Get aeAvailableModes and do the sanity check.
959 *
960 * <p>Depending on the check level this class has, for WAR or COLLECT levels,
961 * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
962 * have to abort the execution even the aeMode list is invalid.</p>
963 * @return AE available modes
964 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700965 public int[] getAeAvailableModesChecked() {
966 Key<int[]> modesKey = CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES;
967 int[] modes = getValueFromKeyNonNull(modesKey);
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700968 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700969 modes = new int[0];
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700970 }
971 List<Integer> modeList = new ArrayList<Integer>();
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700972 for (int mode : modes) {
Igor Murashkin9763b122014-06-19 15:45:27 -0700973 modeList.add(mode);
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700974 }
975 checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
976
977 // All camera device must support ON
978 checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
979 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON));
980
981 // All camera devices with flash units support ON_AUTO_FLASH and ON_ALWAYS_FLASH
Igor Murashkin94399742014-05-19 16:38:37 -0700982 Key<Boolean> flashKey= CameraCharacteristics.FLASH_INFO_AVAILABLE;
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700983 Boolean hasFlash = getValueFromKeyNonNull(flashKey);
984 if (hasFlash == null) {
985 hasFlash = false;
986 }
987 if (hasFlash) {
988 boolean flashModeConsistentWithFlash =
989 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) &&
990 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
991 checkTrueForKey(modesKey,
992 "value must contain ON_AUTO_FLASH and ON_ALWAYS_FLASH and when flash is" +
993 "available", flashModeConsistentWithFlash);
994 } else {
995 boolean flashModeConsistentWithoutFlash =
996 !(modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH) ||
997 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH) ||
998 modeList.contains(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE));
999 checkTrueForKey(modesKey,
1000 "value must not contain ON_AUTO_FLASH, ON_ALWAYS_FLASH and" +
1001 "ON_AUTO_FLASH_REDEYE when flash is unavailable",
1002 flashModeConsistentWithoutFlash);
1003 }
1004
1005 // FULL mode camera devices always support OFF mode.
1006 boolean condition =
1007 !isHardwareLevelFull() || modeList.contains(CameraMetadata.CONTROL_AE_MODE_OFF);
1008 checkTrueForKey(modesKey, "Full capability device must have OFF mode", condition);
1009
1010 // Boundary check.
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001011 for (int mode : modes) {
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001012 checkTrueForKey(modesKey, "Value " + mode + " is out of bound",
1013 mode >= CameraMetadata.CONTROL_AE_MODE_OFF
1014 && mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE);
1015 }
1016
1017 return modes;
1018 }
1019
1020 /**
Zhijun Hed72b9502014-04-27 17:19:23 -07001021 * Get available AWB modes and do the sanity check.
1022 *
1023 * @return array that contains available AWB modes, empty array if awbAvailableModes is
1024 * unavailable.
1025 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001026 public int[] getAwbAvailableModesChecked() {
1027 Key<int[]> key =
Zhijun Hed72b9502014-04-27 17:19:23 -07001028 CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001029 int[] awbModes = getValueFromKeyNonNull(key);
Zhijun Hed72b9502014-04-27 17:19:23 -07001030
1031 if (awbModes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001032 return new int[0];
Zhijun Hed72b9502014-04-27 17:19:23 -07001033 }
1034
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001035 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(awbModes));
Zhijun Hed72b9502014-04-27 17:19:23 -07001036 checkTrueForKey(key, " All camera devices must support AUTO mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001037 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_AUTO));
Zhijun Hed72b9502014-04-27 17:19:23 -07001038 if (isHardwareLevelFull()) {
1039 checkTrueForKey(key, " Full capability camera devices must support OFF mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001040 modesList.contains(CameraMetadata.CONTROL_AWB_MODE_OFF));
Zhijun Hed72b9502014-04-27 17:19:23 -07001041 }
1042
1043 return awbModes;
1044 }
1045
1046 /**
1047 * Get available AF modes and do the sanity check.
1048 *
1049 * @return array that contains available AF modes, empty array if afAvailableModes is
1050 * unavailable.
1051 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001052 public int[] getAfAvailableModesChecked() {
1053 Key<int[]> key =
Zhijun Hed72b9502014-04-27 17:19:23 -07001054 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001055 int[] afModes = getValueFromKeyNonNull(key);
Zhijun Hed72b9502014-04-27 17:19:23 -07001056
1057 if (afModes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001058 return new int[0];
Zhijun Hed72b9502014-04-27 17:19:23 -07001059 }
1060
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001061 List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes));
Ruben Brunk30033ae2014-09-22 15:29:24 -07001062 if (isHardwareLevelLimitedOrBetter()) {
1063 // Some LEGACY mode devices do not support AF OFF
1064 checkTrueForKey(key, " All camera devices must support OFF mode",
1065 modesList.contains(CameraMetadata.CONTROL_AF_MODE_OFF));
1066 }
Zhijun Hed72b9502014-04-27 17:19:23 -07001067 if (hasFocuser()) {
1068 checkTrueForKey(key, " Camera devices that have focuser units must support AUTO mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001069 modesList.contains(CameraMetadata.CONTROL_AF_MODE_AUTO));
Zhijun Hed72b9502014-04-27 17:19:23 -07001070 }
1071
1072 return afModes;
1073 }
1074
1075 /**
Zhijun He44efda22014-04-03 22:15:02 -07001076 * Get supported raw output sizes and do the check.
1077 *
1078 * @return Empty size array if raw output is not supported
1079 */
1080 public Size[] getRawOutputSizesChecked() {
1081 return getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001082 StreamDirection.Output);
Zhijun He44efda22014-04-03 22:15:02 -07001083 }
1084
1085 /**
1086 * Get supported jpeg output sizes and do the check.
1087 *
1088 * @return Empty size array if jpeg output is not supported
1089 */
1090 public Size[] getJpegOutputSizeChecked() {
1091 return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001092 StreamDirection.Output);
Zhijun He44efda22014-04-03 22:15:02 -07001093 }
1094
1095 /**
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001096 * Used to determine the stream direction for various helpers that look up
1097 * format or size information.
1098 */
1099 public enum StreamDirection {
1100 /** Stream is used with {@link android.hardware.camera2.CameraDevice#configureOutputs} */
1101 Output,
1102 /** Stream is used with {@code CameraDevice#configureInputs} -- NOT YET PUBLIC */
1103 Input
1104 }
1105
1106 /**
1107 * Get available sizes for given user-defined format.
1108 *
1109 * <p><strong>Does not</strong> work with implementation-defined format.</p>
Zhijun He44efda22014-04-03 22:15:02 -07001110 *
1111 * @param format The format for the requested size array.
1112 * @param direction The stream direction, input or output.
1113 * @return The sizes of the given format, empty array if no available size is found.
1114 */
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001115 public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
Igor Murashkin94399742014-05-19 16:38:37 -07001116 Key<StreamConfigurationMap> key =
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001117 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1118 StreamConfigurationMap config = getValueFromKeyNonNull(key);
Zhijun He44efda22014-04-03 22:15:02 -07001119
1120 if (config == null) {
1121 return new Size[0];
1122 }
1123
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001124 android.util.Size[] utilSizes;
1125
1126 switch (direction) {
1127 case Output:
1128 utilSizes = config.getOutputSizes(format);
1129 break;
1130 case Input:
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001131 utilSizes = null;
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001132 break;
1133 default:
1134 throw new IllegalArgumentException("direction must be output or input");
Zhijun He44efda22014-04-03 22:15:02 -07001135 }
1136
Igor Murashkind5a33df2014-05-14 17:01:09 -07001137 // TODO: Get rid of android.util.Size
Zhijun Heb7189a42014-05-20 15:28:39 -07001138 if (utilSizes == null) {
1139 Log.i(TAG, "This camera doesn't support format " + format + " for " + direction);
1140 return new Size[0];
1141 }
1142
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001143 Size[] sizes = new Size[utilSizes.length];
1144 for (int i = 0; i < utilSizes.length; ++i) {
1145 sizes[i] = new Size(utilSizes[i].getWidth(), utilSizes[i].getHeight());
1146 }
1147
1148 return sizes;
Zhijun He44efda22014-04-03 22:15:02 -07001149 }
1150
1151 /**
Zhijun He99e05372014-04-13 20:11:22 -07001152 * Get available AE target fps ranges.
1153 *
1154 * @return Empty int array if aeAvailableTargetFpsRanges is invalid.
1155 */
Igor Murashkina6e6d532014-05-27 18:31:34 -07001156 @SuppressWarnings("raw")
1157 public Range<Integer>[] getAeAvailableTargetFpsRangesChecked() {
1158 Key<Range<Integer>[]> key =
Zhijun He99e05372014-04-13 20:11:22 -07001159 CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
Igor Murashkina6e6d532014-05-27 18:31:34 -07001160 Range<Integer>[] fpsRanges = getValueFromKeyNonNull(key);
Zhijun He99e05372014-04-13 20:11:22 -07001161
1162 if (fpsRanges == null) {
Igor Murashkina6e6d532014-05-27 18:31:34 -07001163 return new Range[0];
Zhijun He99e05372014-04-13 20:11:22 -07001164 }
1165
Zhijun He99e05372014-04-13 20:11:22 -07001166 // Round down to 2 boundary if it is not integer times of 2, to avoid array out of bound
1167 // in case the above check fails.
Igor Murashkina6e6d532014-05-27 18:31:34 -07001168 int fpsRangeLength = fpsRanges.length;
Zhijun He99e05372014-04-13 20:11:22 -07001169 int minFps, maxFps;
1170 long maxFrameDuration = getMaxFrameDurationChecked();
Igor Murashkina6e6d532014-05-27 18:31:34 -07001171 for (int i = 0; i < fpsRangeLength; i += 1) {
1172 minFps = fpsRanges[i].getLower();
1173 maxFps = fpsRanges[i].getUpper();
Zhijun He99e05372014-04-13 20:11:22 -07001174 checkTrueForKey(key, " min fps must be no larger than max fps!",
1175 minFps > 0 && maxFps >= minFps);
1176 long maxDuration = (long) (1e9 / minFps);
1177 checkTrueForKey(key, String.format(
1178 " the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
1179 maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
1180 }
1181
1182 return fpsRanges;
1183 }
1184
1185 /**
1186 * Get max frame duration.
1187 *
1188 * @return 0 if maxFrameDuration is null
1189 */
1190 public long getMaxFrameDurationChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -07001191 Key<Long> key =
Zhijun He99e05372014-04-13 20:11:22 -07001192 CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION;
1193 Long maxDuration = getValueFromKeyNonNull(key);
1194
1195 if (maxDuration == null) {
1196 return 0;
1197 }
1198
1199 return maxDuration;
1200 }
1201
1202 /**
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001203 * Get available minimal frame durations for a given user-defined format.
1204 *
1205 * <p><strong>Does not</strong> work with implementation-defined format.</p>
Zhijun He99e05372014-04-13 20:11:22 -07001206 *
1207 * @param format One of the format from {@link ImageFormat}.
1208 * @return HashMap of minimal frame durations for different sizes, empty HashMap
1209 * if availableMinFrameDurations is null.
1210 */
1211 public HashMap<Size, Long> getAvailableMinFrameDurationsForFormatChecked(int format) {
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001212
Zhijun He99e05372014-04-13 20:11:22 -07001213 HashMap<Size, Long> minDurationMap = new HashMap<Size, Long>();
1214
Igor Murashkin94399742014-05-19 16:38:37 -07001215 Key<StreamConfigurationMap> key =
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001216 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
1217 StreamConfigurationMap config = getValueFromKeyNonNull(key);
1218
1219 if (config == null) {
Zhijun He99e05372014-04-13 20:11:22 -07001220 return minDurationMap;
1221 }
1222
Igor Murashkinffb1ee52014-05-13 17:31:33 -07001223 for (android.util.Size size : config.getOutputSizes(format)) {
1224 long minFrameDuration = config.getOutputMinFrameDuration(format, size);
1225
Eino-Ville Talvalac8fe8ce2014-07-28 12:55:23 -07001226 if (minFrameDuration != 0) {
Ruben Brunkd027cf32014-06-18 17:11:07 -07001227 minDurationMap.put(new Size(size.getWidth(), size.getHeight()), minFrameDuration);
1228 }
Zhijun He99e05372014-04-13 20:11:22 -07001229 }
1230
1231 return minDurationMap;
1232 }
1233
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001234 public int[] getAvailableEdgeModesChecked() {
1235 Key<int[]> key = CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES;
1236 int[] edgeModes = getValueFromKeyNonNull(key);
Zhijun Hefd84d852014-04-13 23:11:15 -07001237
1238 if (edgeModes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001239 return new int[0];
Zhijun Hefd84d852014-04-13 23:11:15 -07001240 }
1241
1242 // Full device should always include OFF and FAST
1243 if (isHardwareLevelFull()) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001244 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(edgeModes));
Zhijun Hefd84d852014-04-13 23:11:15 -07001245 checkTrueForKey(key, "Full device must contain OFF and FAST edge modes",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001246 modeList.contains(CameraMetadata.EDGE_MODE_OFF) &&
1247 modeList.contains(CameraMetadata.EDGE_MODE_FAST));
Zhijun Hefd84d852014-04-13 23:11:15 -07001248 }
1249
1250 return edgeModes;
1251 }
1252
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001253 public int[] getAvailableNoiseReductionModesChecked() {
1254 Key<int[]> key =
Zhijun He99211e42014-04-17 19:09:36 -07001255 CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001256 int[] noiseReductionModes = getValueFromKeyNonNull(key);
Zhijun He99211e42014-04-17 19:09:36 -07001257
1258 if (noiseReductionModes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001259 return new int[0];
Zhijun He99211e42014-04-17 19:09:36 -07001260 }
1261
1262 // Full device should always include OFF and FAST
1263 if (isHardwareLevelFull()) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001264 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(noiseReductionModes));
Zhijun He99211e42014-04-17 19:09:36 -07001265 checkTrueForKey(key, "Full device must contain OFF and FAST noise reduction modes",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001266 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_OFF) &&
1267 modeList.contains(CameraMetadata.NOISE_REDUCTION_MODE_FAST));
Zhijun He99211e42014-04-17 19:09:36 -07001268 }
1269
1270 return noiseReductionModes;
1271 }
1272
Zhijun He99e05372014-04-13 20:11:22 -07001273 /**
Zhijun He39809f52014-04-23 16:06:59 -07001274 * Get value of key android.control.aeCompensationStep and do the sanity check.
1275 *
1276 * @return default value if the value is null.
1277 */
1278 public Rational getAeCompensationStepChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -07001279 Key<Rational> key =
Zhijun He39809f52014-04-23 16:06:59 -07001280 CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP;
1281 Rational compensationStep = getValueFromKeyNonNull(key);
1282
1283 if (compensationStep == null) {
1284 // Return default step.
1285 return CONTROL_AE_COMPENSATION_STEP_DEFAULT;
1286 }
1287
Igor Murashkin24e1f9d2014-07-09 17:19:51 -07001288 // Legacy devices don't have a minimum step requirement
1289 if (isHardwareLevelLimitedOrBetter()) {
1290 float compensationStepF =
1291 (float) compensationStep.getNumerator() / compensationStep.getDenominator();
Yin-Chia Yeh6bd89852014-10-07 10:04:20 -07001292 checkTrueForKey(key, " value must be no more than 1/2", compensationStepF <= 0.5f);
Igor Murashkin24e1f9d2014-07-09 17:19:51 -07001293 }
1294
Zhijun He39809f52014-04-23 16:06:59 -07001295 return compensationStep;
1296 }
1297
1298 /**
1299 * Get value of key android.control.aeCompensationRange and do the sanity check.
1300 *
1301 * @return default value if the value is null or malformed.
1302 */
Igor Murashkina6e6d532014-05-27 18:31:34 -07001303 public Range<Integer> getAeCompensationRangeChecked() {
1304 Key<Range<Integer>> key =
Zhijun He39809f52014-04-23 16:06:59 -07001305 CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE;
Igor Murashkina6e6d532014-05-27 18:31:34 -07001306 Range<Integer> compensationRange = getValueFromKeyNonNull(key);
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001307 Rational compensationStep = getAeCompensationStepChecked();
Igor Murashkin24e1f9d2014-07-09 17:19:51 -07001308 float compensationStepF = compensationStep.floatValue();
Igor Murashkina6e6d532014-05-27 18:31:34 -07001309 final Range<Integer> DEFAULT_RANGE = Range.create(
Zhijun He503da802015-02-04 14:35:38 -08001310 (int)(0 / compensationStepF),
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001311 (int)(CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MAX / compensationStepF));
Zhijun He503da802015-02-04 14:35:38 -08001312 final Range<Integer> ZERO_RANGE = Range.create(0, 0);
Zhijun He39809f52014-04-23 16:06:59 -07001313 if (compensationRange == null) {
Zhijun He503da802015-02-04 14:35:38 -08001314 return ZERO_RANGE;
Zhijun He39809f52014-04-23 16:06:59 -07001315 }
1316
Igor Murashkin24e1f9d2014-07-09 17:19:51 -07001317 // Legacy devices don't have a minimum range requirement
Zhijun He503da802015-02-04 14:35:38 -08001318 if (isHardwareLevelLimitedOrBetter() && !compensationRange.equals(ZERO_RANGE)) {
Igor Murashkin24e1f9d2014-07-09 17:19:51 -07001319 checkTrueForKey(key, " range value must be at least " + DEFAULT_RANGE
1320 + ", actual " + compensationRange + ", compensation step " + compensationStep,
1321 compensationRange.getLower() <= DEFAULT_RANGE.getLower() &&
1322 compensationRange.getUpper() >= DEFAULT_RANGE.getUpper());
1323 }
Zhijun He39809f52014-04-23 16:06:59 -07001324
1325 return compensationRange;
1326 }
Zhijun Hed72b9502014-04-27 17:19:23 -07001327
Zhijun He39809f52014-04-23 16:06:59 -07001328 /**
Zhijun He68f3ecf2014-04-29 17:11:32 -07001329 * Get availableVideoStabilizationModes and do the sanity check.
1330 *
1331 * @return available video stabilization modes, empty array if it is unavailable.
1332 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001333 public int[] getAvailableVideoStabilizationModesChecked() {
1334 Key<int[]> key =
Zhijun He68f3ecf2014-04-29 17:11:32 -07001335 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001336 int[] modes = getValueFromKeyNonNull(key);
Zhijun He68f3ecf2014-04-29 17:11:32 -07001337
1338 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001339 return new int[0];
Zhijun He68f3ecf2014-04-29 17:11:32 -07001340 }
1341
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001342 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Zhijun He68f3ecf2014-04-29 17:11:32 -07001343 checkTrueForKey(key, " All device should support OFF mode",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001344 modeList.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF));
Zhijun He68f3ecf2014-04-29 17:11:32 -07001345 checkArrayValuesInRange(key, modes,
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001346 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF,
1347 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
Zhijun He68f3ecf2014-04-29 17:11:32 -07001348
1349 return modes;
1350 }
1351
1352 /**
1353 * Get availableOpticalStabilization and do the sanity check.
1354 *
1355 * @return available optical stabilization modes, empty array if it is unavailable.
1356 */
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001357 public int[] getAvailableOpticalStabilizationChecked() {
1358 Key<int[]> key =
Zhijun He68f3ecf2014-04-29 17:11:32 -07001359 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001360 int[] modes = getValueFromKeyNonNull(key);
Zhijun He68f3ecf2014-04-29 17:11:32 -07001361
1362 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001363 return new int[0];
Zhijun He68f3ecf2014-04-29 17:11:32 -07001364 }
1365
1366 checkArrayValuesInRange(key, modes,
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001367 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_OFF,
1368 CameraMetadata.LENS_OPTICAL_STABILIZATION_MODE_ON);
Zhijun He68f3ecf2014-04-29 17:11:32 -07001369
1370 return modes;
1371 }
1372
1373 /**
Igor Murashkin9662a562014-07-07 14:30:49 -07001374 * Get the scaler's max digital zoom ({@code >= 1.0f}) ratio between crop and active array
1375 * @return the max zoom ratio, or {@code 1.0f} if the value is unavailable
Zhijun Hedba6dd12014-04-29 18:41:49 -07001376 */
1377 public float getAvailableMaxDigitalZoomChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -07001378 Key<Float> key =
Zhijun Hedba6dd12014-04-29 18:41:49 -07001379 CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
Igor Murashkin9662a562014-07-07 14:30:49 -07001380
Zhijun Hedba6dd12014-04-29 18:41:49 -07001381 Float maxZoom = getValueFromKeyNonNull(key);
1382 if (maxZoom == null) {
1383 return 1.0f;
1384 }
1385
Igor Murashkin9662a562014-07-07 14:30:49 -07001386 checkTrueForKey(key, " max digital zoom should be no less than 1",
1387 maxZoom >= 1.0f && !Float.isNaN(maxZoom) && !Float.isInfinite(maxZoom));
Zhijun Hedba6dd12014-04-29 18:41:49 -07001388
1389 return maxZoom;
1390 }
1391
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001392 public int[] getAvailableSceneModesChecked() {
1393 Key<int[]> key =
Zhijun He496c0c72014-04-30 17:52:17 -07001394 CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001395 int[] modes = getValueFromKeyNonNull(key);
Zhijun He496c0c72014-04-30 17:52:17 -07001396
1397 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001398 return new int[0];
Zhijun He496c0c72014-04-30 17:52:17 -07001399 }
1400
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001401 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Zhijun He496c0c72014-04-30 17:52:17 -07001402 // FACE_PRIORITY must be included if face detection is supported.
Ruben Brunk33bc28f2014-07-29 10:33:26 -07001403 if (areKeysAvailable(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT) &&
1404 getMaxFaceCountChecked() > 0) {
Zhijun He496c0c72014-04-30 17:52:17 -07001405 checkTrueForKey(key, " FACE_PRIORITY must be included if face detection is supported",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001406 modeList.contains(CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY));
Zhijun He496c0c72014-04-30 17:52:17 -07001407 }
1408
1409 return modes;
1410 }
1411
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001412 public int[] getAvailableEffectModesChecked() {
1413 Key<int[]> key =
Zhijun He496c0c72014-04-30 17:52:17 -07001414 CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001415 int[] modes = getValueFromKeyNonNull(key);
Zhijun He496c0c72014-04-30 17:52:17 -07001416
1417 if (modes == null) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001418 return new int[0];
Zhijun He496c0c72014-04-30 17:52:17 -07001419 }
1420
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001421 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Zhijun He496c0c72014-04-30 17:52:17 -07001422 // OFF must be included.
1423 checkTrueForKey(key, " OFF must be included",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001424 modeList.contains(CameraMetadata.CONTROL_EFFECT_MODE_OFF));
Zhijun He496c0c72014-04-30 17:52:17 -07001425
1426 return modes;
1427 }
1428
Zhijun Hedba6dd12014-04-29 18:41:49 -07001429 /**
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001430 * Get and check the available color aberration modes
1431 *
1432 * @return the available color aberration modes
1433 */
1434 public int[] getAvailableColorAberrationModesChecked() {
1435 Key<int[]> key =
Zhijun He3efef942014-08-20 22:09:57 -07001436 CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001437 int[] modes = getValueFromKeyNonNull(key);
1438
1439 if (modes == null) {
1440 return new int[0];
1441 }
1442
1443 List<Integer> modeList = Arrays.asList(CameraTestUtils.toObject(modes));
Yin-Chia Yehe7933802014-12-19 13:35:24 -08001444 checkTrueForKey(key, " Camera devices must always support either OFF or FAST mode",
1445 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF) ||
1446 modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_FAST));
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001447 checkElementDistinct(key, modeList);
1448 checkArrayValuesInRange(key, modes,
Zhijun He3efef942014-08-20 22:09:57 -07001449 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF,
1450 CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001451
1452 return modes;
1453 }
1454
1455 /**
Zhijun He98dc8f92014-05-13 17:29:01 -07001456 * Get max pipeline depth and do the sanity check.
1457 *
1458 * @return max pipeline depth, default value if it is not available.
1459 */
1460 public byte getPipelineMaxDepthChecked() {
Igor Murashkin94399742014-05-19 16:38:37 -07001461 Key<Byte> key =
Zhijun He98dc8f92014-05-13 17:29:01 -07001462 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH;
1463 Byte maxDepth = getValueFromKeyNonNull(key);
1464
1465 if (maxDepth == null) {
1466 return REQUEST_PIPELINE_MAX_DEPTH_MAX;
1467 }
1468
1469 checkTrueForKey(key, " max pipeline depth should be no larger than "
1470 + REQUEST_PIPELINE_MAX_DEPTH_MAX, maxDepth <= REQUEST_PIPELINE_MAX_DEPTH_MAX);
1471
1472 return maxDepth;
1473 }
1474
1475 /**
Zhijun Heb9ea4002014-05-29 16:05:30 -07001476 * Get available capabilities and do the sanity check.
1477 *
1478 * @return reported available capabilities list, empty list if the value is unavailable.
1479 */
1480 public List<Integer> getAvailableCapabilitiesChecked() {
1481 Key<int[]> key =
1482 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES;
1483 int[] availableCaps = getValueFromKeyNonNull(key);
1484 List<Integer> capList;
1485
1486 if (availableCaps == null) {
1487 return new ArrayList<Integer>();
1488 }
1489
Zhijun Hec5011112014-07-10 10:28:06 -07001490 checkArrayValuesInRange(key, availableCaps,
Zhijun Heb9ea4002014-05-29 16:05:30 -07001491 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
Eino-Ville Talvala35a52702014-11-13 13:36:58 -08001492 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
Zhijun Heb9ea4002014-05-29 16:05:30 -07001493 capList = Arrays.asList(CameraTestUtils.toObject(availableCaps));
1494 return capList;
1495 }
1496
1497 /**
Igor Murashkin9763b122014-06-19 15:45:27 -07001498 * Determine whether the current device supports a capability or not.
1499 *
1500 * @param capability (non-negative)
1501 *
1502 * @return {@code true} if the capability is supported, {@code false} otherwise.
1503 *
1504 * @throws IllegalArgumentException if {@code capability} was negative
1505 *
1506 * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
1507 */
1508 public boolean isCapabilitySupported(int capability) {
1509 if (capability < 0) {
1510 throw new IllegalArgumentException("capability must be non-negative");
1511 }
1512
1513 List<Integer> availableCapabilities = getAvailableCapabilitiesChecked();
1514
1515 return availableCapabilities.contains(capability);
1516 }
1517
1518 /**
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001519 * Determine whether or not all the {@code keys} are available characteristics keys
1520 * (as in {@link CameraCharacteristics#getKeys}.
1521 *
1522 * <p>If this returns {@code true}, then querying for this key from a characteristics
1523 * object will always return a non-{@code null} value.</p>
1524 *
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001525 * @param keys collection of camera characteristics keys
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001526 * @return whether or not all characteristics keys are available
1527 */
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001528 public final boolean areCharacteristicsKeysAvailable(
1529 Collection<CameraCharacteristics.Key<?>> keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001530 return mCharacteristics.getKeys().containsAll(keys);
1531 }
1532
1533 /**
1534 * Determine whether or not all the {@code keys} are available result keys
1535 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1536 *
1537 * <p>If this returns {@code true}, then querying for this key from a result
1538 * object will almost always return a non-{@code null} value.</p>
1539 *
1540 * <p>In some cases (e.g. lens shading map), the request must have additional settings
1541 * configured in order for the key to correspond to a value.</p>
1542 *
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001543 * @param keys collection of capture result keys
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001544 * @return whether or not all result keys are available
1545 */
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001546 public final boolean areResultKeysAvailable(Collection<CaptureResult.Key<?>> keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001547 return mCharacteristics.getAvailableCaptureResultKeys().containsAll(keys);
1548 }
1549
1550 /**
1551 * Determine whether or not all the {@code keys} are available request keys
1552 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1553 *
1554 * <p>If this returns {@code true}, then setting this key in the request builder
1555 * may have some effect (and if it's {@code false}, then the camera device will
1556 * definitely ignore it).</p>
1557 *
1558 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1559 * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1560 *
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001561 * @param keys collection of capture request keys
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001562 * @return whether or not all result keys are available
1563 */
Yin-Chia Yehe74968d2014-08-18 13:55:13 -07001564 public final boolean areRequestKeysAvailable(Collection<CaptureRequest.Key<?>> keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001565 return mCharacteristics.getAvailableCaptureRequestKeys().containsAll(keys);
1566 }
1567
1568 /**
1569 * Determine whether or not all the {@code keys} are available characteristics keys
1570 * (as in {@link CameraCharacteristics#getKeys}.
1571 *
1572 * <p>If this returns {@code true}, then querying for this key from a characteristics
1573 * object will always return a non-{@code null} value.</p>
1574 *
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001575 * @param keys one or more camera characteristic keys
1576 * @return whether or not all characteristics keys are available
1577 */
1578 @SafeVarargs
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001579 public final boolean areKeysAvailable(CameraCharacteristics.Key<?>... keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001580 return areCharacteristicsKeysAvailable(Arrays.asList(keys));
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001581 }
1582
1583 /**
1584 * Determine whether or not all the {@code keys} are available result keys
1585 * (as in {@link CameraCharacteristics#getAvailableCaptureResultKeys}.
1586 *
1587 * <p>If this returns {@code true}, then querying for this key from a result
1588 * object will almost always return a non-{@code null} value.</p>
1589 *
1590 * <p>In some cases (e.g. lens shading map), the request must have additional settings
1591 * configured in order for the key to correspond to a value.</p>
1592 *
1593 * @param keys one or more capture result keys
1594 * @return whether or not all result keys are available
1595 */
1596 @SafeVarargs
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001597 public final boolean areKeysAvailable(CaptureResult.Key<?>... keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001598 return areResultKeysAvailable(Arrays.asList(keys));
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001599 }
1600
1601 /**
1602 * Determine whether or not all the {@code keys} are available request keys
1603 * (as in {@link CameraCharacteristics#getAvailableCaptureRequestKeys}.
1604 *
1605 * <p>If this returns {@code true}, then setting this key in the request builder
1606 * may have some effect (and if it's {@code false}, then the camera device will
1607 * definitely ignore it).</p>
1608 *
1609 * <p>In some cases (e.g. manual control of exposure), other keys must be also be set
1610 * in order for a key to take effect (e.g. control.mode set to OFF).</p>
1611 *
1612 * @param keys one or more capture request keys
1613 * @return whether or not all result keys are available
1614 */
1615 @SafeVarargs
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001616 public final boolean areKeysAvailable(CaptureRequest.Key<?>... keys) {
Yin-Chia Yeh43bb9202014-08-12 14:16:41 -07001617 return areRequestKeysAvailable(Arrays.asList(keys));
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001618 }
1619
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001620 /*
1621 * Determine if camera device support manual lens shading map control
1622 *
1623 * @return {@code true} if manual lens shading map control is supported
1624 */
1625 public boolean isManualLensShadingMapSupported() {
1626 return areKeysAvailable(CaptureRequest.SHADING_MODE);
1627 }
1628
1629 /**
1630 * Determine if camera device support manual color correction control
1631 *
1632 * @return {@code true} if manual color correction control is supported
1633 */
1634 public boolean isManualColorCorrectionSupported() {
1635 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_MODE);
1636 }
1637
1638 /**
1639 * Determine if camera device support manual tone mapping control
1640 *
1641 * @return {@code true} if manual tone mapping control is supported
1642 */
1643 public boolean isManualToneMapSupported() {
1644 return areKeysAvailable(CaptureRequest.TONEMAP_MODE);
1645 }
1646
1647 /**
1648 * Determine if camera device support manual color aberration control
1649 *
1650 * @return {@code true} if manual color aberration control is supported
1651 */
1652 public boolean isManualColorAberrationControlSupported() {
Zhijun He3efef942014-08-20 22:09:57 -07001653 return areKeysAvailable(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
Yin-Chia Yehb6653592014-07-24 16:07:38 -07001654 }
1655
1656 /**
1657 * Determine if camera device support edge mode control
1658 *
1659 * @return {@code true} if edge mode control is supported
1660 */
1661 public boolean isEdgeModeControlSupported() {
1662 return areKeysAvailable(CaptureRequest.EDGE_MODE);
1663 }
1664
1665 /**
1666 * Determine if camera device support hot pixel mode control
1667 *
1668 * @return {@code true} if hot pixel mode control is supported
1669 */
1670 public boolean isHotPixelMapModeControlSupported() {
1671 return areKeysAvailable(CaptureRequest.HOT_PIXEL_MODE);
1672 }
1673
1674 /**
1675 * Determine if camera device support noise reduction mode control
1676 *
1677 * @return {@code true} if noise reduction mode control is supported
1678 */
1679 public boolean isNoiseReductionModeControlSupported() {
1680 return areKeysAvailable(CaptureRequest.NOISE_REDUCTION_MODE);
1681 }
1682
Igor Murashkinb2b17eb2014-07-24 18:20:03 -07001683 /**
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001684 * Get max number of output raw streams and do the basic sanity check.
Zhijun Heb9ea4002014-05-29 16:05:30 -07001685 *
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001686 * @return reported max number of raw output stream
Zhijun Heb9ea4002014-05-29 16:05:30 -07001687 */
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001688 public int getMaxNumOutputStreamsRawChecked() {
1689 Integer maxNumStreams =
1690 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW);
1691 if (maxNumStreams == null)
1692 return 0;
1693 return maxNumStreams;
1694 }
Zhijun Heb9ea4002014-05-29 16:05:30 -07001695
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001696 /**
1697 * Get max number of output processed streams and do the basic sanity check.
1698 *
1699 * @return reported max number of processed output stream
1700 */
1701 public int getMaxNumOutputStreamsProcessedChecked() {
1702 Integer maxNumStreams =
1703 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC);
1704 if (maxNumStreams == null)
1705 return 0;
1706 return maxNumStreams;
1707 }
Zhijun Heb9ea4002014-05-29 16:05:30 -07001708
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07001709 /**
1710 * Get max number of output stalling processed streams and do the basic sanity check.
1711 *
1712 * @return reported max number of stalling processed output stream
1713 */
1714 public int getMaxNumOutputStreamsProcessedStallChecked() {
1715 Integer maxNumStreams =
1716 getValueFromKeyNonNull(CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING);
1717 if (maxNumStreams == null)
1718 return 0;
Zhijun Heb9ea4002014-05-29 16:05:30 -07001719 return maxNumStreams;
1720 }
1721
1722 /**
1723 * Get lens facing and do the sanity check
1724 * @return lens facing, return default value (BACK) if value is unavailable.
1725 */
1726 public int getLensFacingChecked() {
1727 Key<Integer> key =
1728 CameraCharacteristics.LENS_FACING;
1729 Integer facing = getValueFromKeyNonNull(key);
1730
1731 if (facing == null) {
1732 return CameraCharacteristics.LENS_FACING_BACK;
1733 }
1734
1735 checkTrueForKey(key, " value is out of range ",
1736 facing >= CameraCharacteristics.LENS_FACING_FRONT &&
1737 facing <= CameraCharacteristics.LENS_FACING_BACK);
1738 return facing;
1739 }
1740
1741 /**
Igor Murashkin9662a562014-07-07 14:30:49 -07001742 * Get the scaler's cropping type (center only or freeform)
1743 * @return cropping type, return default value (CENTER_ONLY) if value is unavailable
1744 */
1745 public int getScalerCroppingTypeChecked() {
1746 Key<Integer> key =
1747 CameraCharacteristics.SCALER_CROPPING_TYPE;
1748 Integer value = getValueFromKeyNonNull(key);
1749
1750 if (value == null) {
1751 return CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY;
1752 }
1753
1754 checkTrueForKey(key, " value is out of range ",
1755 value >= CameraCharacteristics.SCALER_CROPPING_TYPE_CENTER_ONLY &&
1756 value <= CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM);
1757
1758 return value;
1759 }
1760
1761 /**
Zhijun He4a3a58e2014-07-10 19:24:31 -07001762 * Check if high speed video is supported (HIGH_SPEED_VIDEO scene mode is
1763 * supported, supported high speed fps ranges and sizes are valid).
1764 *
1765 * @return true if high speed video is supported.
1766 */
1767 public boolean isHighSpeedVideoSupported() {
1768 List<Integer> sceneModes =
1769 Arrays.asList(CameraTestUtils.toObject(getAvailableSceneModesChecked()));
1770 if (sceneModes.contains(CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO)) {
1771 StreamConfigurationMap config =
1772 getValueFromKeyNonNull(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
1773 if (config == null) {
1774 return false;
1775 }
1776 Size[] availableSizes = config.getHighSpeedVideoSizes();
1777 if (availableSizes.length == 0) {
1778 return false;
1779 }
1780
1781 for (Size size : availableSizes) {
1782 Range<Integer>[] availableFpsRanges = config.getHighSpeedVideoFpsRangesFor(size);
1783 if (availableFpsRanges.length == 0) {
1784 return false;
1785 }
1786 }
1787
1788 return true;
1789 } else {
1790 return false;
1791 }
1792 }
1793
1794 /**
Igor Murashkinde096f72013-12-16 17:18:33 -08001795 * Get the value in index for a fixed-size array from a given key.
1796 *
1797 * <p>If the camera device is incorrectly reporting values, log a warning and return
1798 * the default value instead.</p>
1799 *
1800 * @param key Key to fetch
1801 * @param defaultValue Default value to return if camera device uses invalid values
1802 * @param name Human-readable name for the array index (logging only)
1803 * @param index Array index of the subelement
1804 * @param size Expected fixed size of the array
1805 *
1806 * @return The value reported by the camera device, or the defaultValue otherwise.
1807 */
1808 private <T> T getArrayElementOrDefault(Key<?> key, T defaultValue, String name, int index,
1809 int size) {
1810 T elementValue = getArrayElementCheckRangeNonNull(
1811 key,
1812 index,
1813 size);
1814
1815 if (elementValue == null) {
Zhijun He5f4d0082014-03-19 23:02:03 -07001816 failKeyCheck(key,
Igor Murashkinde096f72013-12-16 17:18:33 -08001817 "had no valid " + name + " value; using default of " + defaultValue);
1818 elementValue = defaultValue;
1819 }
1820
1821 return elementValue;
1822 }
1823
1824 /**
1825 * Fetch an array sub-element from an array value given by a key.
1826 *
1827 * <p>
1828 * Prints a warning if the sub-element was null.
1829 * </p>
1830 *
1831 * <p>Use for variable-size arrays since this does not check the array size.</p>
1832 *
1833 * @param key Metadata key to look up
1834 * @param element A non-negative index value.
1835 * @return The array sub-element, or null if the checking failed.
1836 */
1837 private <T> T getArrayElementNonNull(Key<?> key, int element) {
1838 return getArrayElementCheckRangeNonNull(key, element, IGNORE_SIZE_CHECK);
1839 }
1840
1841 /**
1842 * Fetch an array sub-element from an array value given by a key.
1843 *
1844 * <p>
1845 * Prints a warning if the array size does not match the size, or if the sub-element was null.
1846 * </p>
1847 *
1848 * @param key Metadata key to look up
1849 * @param element The index in [0,size)
1850 * @param size A positive size value or otherwise {@value #IGNORE_SIZE_CHECK}
1851 * @return The array sub-element, or null if the checking failed.
1852 */
1853 private <T> T getArrayElementCheckRangeNonNull(Key<?> key, int element, int size) {
1854 Object array = getValueFromKeyNonNull(key);
1855
1856 if (array == null) {
1857 // Warning already printed
1858 return null;
1859 }
1860
1861 if (size != IGNORE_SIZE_CHECK) {
1862 int actualLength = Array.getLength(array);
1863 if (actualLength != size) {
Zhijun He5f4d0082014-03-19 23:02:03 -07001864 failKeyCheck(key,
Igor Murashkinde096f72013-12-16 17:18:33 -08001865 String.format("had the wrong number of elements (%d), expected (%d)",
1866 actualLength, size));
1867 return null;
1868 }
1869 }
1870
1871 @SuppressWarnings("unchecked")
1872 T val = (T) Array.get(array, element);
1873
1874 if (val == null) {
Zhijun He5f4d0082014-03-19 23:02:03 -07001875 failKeyCheck(key, "had a null element at index" + element);
Igor Murashkinde096f72013-12-16 17:18:33 -08001876 return null;
1877 }
1878
1879 return val;
1880 }
1881
1882 /**
1883 * Gets the key, logging warnings for null values.
1884 */
Ruben Brunk77034932014-07-01 16:56:52 -07001885 public <T> T getValueFromKeyNonNull(Key<T> key) {
Igor Murashkinde096f72013-12-16 17:18:33 -08001886 if (key == null) {
1887 throw new IllegalArgumentException("key was null");
1888 }
1889
1890 T value = mCharacteristics.get(key);
1891
1892 if (value == null) {
Zhijun He5f4d0082014-03-19 23:02:03 -07001893 failKeyCheck(key, "was null");
Igor Murashkinde096f72013-12-16 17:18:33 -08001894 }
1895
1896 return value;
1897 }
1898
Zhijun Hedba6dd12014-04-29 18:41:49 -07001899 private void checkArrayValuesInRange(Key<int[]> key, int[] array, int min, int max) {
1900 for (int value : array) {
1901 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
1902 value <= max && value >= min);
1903 }
1904 }
1905
Zhijun He984ff7e2014-03-30 12:40:27 -07001906 private void checkArrayValuesInRange(Key<byte[]> key, byte[] array, byte min, byte max) {
1907 for (byte value : array) {
1908 checkTrueForKey(key, String.format(" value is out of range [%d, %d]", min, max),
1909 value <= max && value >= min);
1910 }
1911 }
1912
1913 /**
1914 * Check the uniqueness of the values in a list.
1915 *
1916 * @param key The key to be checked
1917 * @param list The list contains the value of the key
1918 */
1919 private <U, T> void checkElementDistinct(Key<U> key, List<T> list) {
1920 // Each size must be distinct.
1921 Set<T> sizeSet = new HashSet<T>(list);
1922 checkTrueForKey(key, "Each size must be distinct", sizeSet.size() == list.size());
1923 }
1924
Zhijun He5f4d0082014-03-19 23:02:03 -07001925 private <T> void checkTrueForKey(Key<T> key, String message, boolean condition) {
1926 if (!condition) {
1927 failKeyCheck(key, message);
1928 }
1929 }
1930
1931 private <T> void failKeyCheck(Key<T> key, String message) {
Igor Murashkinde096f72013-12-16 17:18:33 -08001932 // TODO: Consider only warning once per key/message combination if it's too spammy.
1933 // TODO: Consider offering other options such as throwing an assertion exception
Zhijun He5f4d0082014-03-19 23:02:03 -07001934 String failureCause = String.format("The static info key '%s' %s", key.getName(), message);
1935 switch (mLevel) {
1936 case WARN:
1937 Log.w(TAG, failureCause);
1938 break;
1939 case COLLECT:
1940 mCollector.addMessage(failureCause);
1941 break;
1942 case ASSERT:
1943 Assert.fail(failureCause);
1944 default:
1945 throw new UnsupportedOperationException("Unhandled level " + mLevel);
1946 }
Igor Murashkinde096f72013-12-16 17:18:33 -08001947 }
1948}