Home | History | Annotate | Download | only in cts
      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.SurfaceTexture;
     22 import android.hardware.camera2.CameraCharacteristics;
     23 import android.hardware.camera2.CameraCharacteristics.Key;
     24 import android.hardware.camera2.CameraManager;
     25 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
     26 import android.hardware.camera2.params.BlackLevelPattern;
     27 import android.hardware.camera2.params.ColorSpaceTransform;
     28 import android.hardware.camera2.params.StreamConfigurationMap;
     29 import android.media.ImageReader;
     30 import android.test.AndroidTestCase;
     31 import android.util.Log;
     32 import android.util.Rational;
     33 import android.util.Range;
     34 import android.util.Size;
     35 import android.view.Surface;
     36 
     37 import java.util.ArrayList;
     38 import java.util.Arrays;
     39 import java.util.List;
     40 import java.util.Objects;
     41 
     42 import static android.hardware.camera2.cts.helpers.AssertHelpers.*;
     43 
     44 /**
     45  * Extended tests for static camera characteristics.
     46  */
     47 public class ExtendedCameraCharacteristicsTest extends AndroidTestCase {
     48     private static final String TAG = "ExChrsTest"; // must be short so next line doesn't throw
     49     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     50 
     51     private static final String PREFIX_ANDROID = "android";
     52     private static final String PREFIX_VENDOR = "com";
     53 
     54     /*
     55      * Constants for static RAW metadata.
     56      */
     57     private static final int MIN_ALLOWABLE_WHITELEVEL = 32; // must have sensor bit depth > 5
     58 
     59     private CameraManager mCameraManager;
     60     private List<CameraCharacteristics> mCharacteristics;
     61     private String[] mIds;
     62     private CameraErrorCollector mCollector;
     63 
     64     private static final Size VGA = new Size(640, 480);
     65 
     66     /*
     67      * HW Levels short hand
     68      */
     69     private static final int LEGACY = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
     70     private static final int LIMITED = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
     71     private static final int FULL = CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
     72     private static final int OPT = Integer.MAX_VALUE;  // For keys that are optional on all hardware levels.
     73 
     74     /*
     75      * Capabilities short hand
     76      */
     77     private static final int NONE = -1;
     78     private static final int BC =
     79             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
     80     private static final int MANUAL_SENSOR =
     81             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR;
     82     private static final int MANUAL_POSTPROC =
     83             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING;
     84     private static final int RAW =
     85             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW;
     86 
     87     @Override
     88     public void setContext(Context context) {
     89         super.setContext(context);
     90         mCameraManager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
     91         assertNotNull("Can't connect to camera manager", mCameraManager);
     92     }
     93 
     94     @Override
     95     protected void setUp() throws Exception {
     96         super.setUp();
     97         mIds = mCameraManager.getCameraIdList();
     98         mCharacteristics = new ArrayList<>();
     99         mCollector = new CameraErrorCollector();
    100         for (int i = 0; i < mIds.length; i++) {
    101             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(mIds[i]);
    102             assertNotNull(String.format("Can't get camera characteristics from: ID %s", mIds[i]),
    103                     props);
    104             mCharacteristics.add(props);
    105         }
    106     }
    107 
    108     @Override
    109     protected void tearDown() throws Exception {
    110         mCharacteristics = null;
    111 
    112         try {
    113             mCollector.verify();
    114         } catch (Throwable e) {
    115             // When new Exception(e) is used, exception info will be printed twice.
    116             throw new Exception(e.getMessage());
    117         } finally {
    118             super.tearDown();
    119         }
    120     }
    121 
    122     /**
    123      * Test that the available stream configurations contain a few required formats and sizes.
    124      */
    125     public void testAvailableStreamConfigs() {
    126         int counter = 0;
    127         for (CameraCharacteristics c : mCharacteristics) {
    128             StreamConfigurationMap config =
    129                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    130             assertNotNull(String.format("No stream configuration map found for: ID %s",
    131                     mIds[counter]), config);
    132             int[] outputFormats = config.getOutputFormats();
    133 
    134             // Check required formats exist (JPEG, and YUV_420_888).
    135             assertArrayContains(
    136                     String.format("No valid YUV_420_888 preview formats found for: ID %s",
    137                             mIds[counter]), outputFormats, ImageFormat.YUV_420_888);
    138             assertArrayContains(String.format("No JPEG image format for: ID %s",
    139                     mIds[counter]), outputFormats, ImageFormat.JPEG);
    140 
    141             Size[] sizes = config.getOutputSizes(ImageFormat.YUV_420_888);
    142             CameraTestUtils.assertArrayNotEmpty(sizes,
    143                     String.format("No sizes for preview format %x for: ID %s",
    144                             ImageFormat.YUV_420_888, mIds[counter]));
    145 
    146             assertArrayContains(String.format(
    147                             "Required VGA size not found for format %x for: ID %s",
    148                             ImageFormat.YUV_420_888, mIds[counter]), sizes, VGA);
    149 
    150             counter++;
    151         }
    152     }
    153 
    154     /**
    155      * Test {@link CameraCharacteristics#getKeys}
    156      */
    157     public void testKeys() {
    158         int counter = 0;
    159         for (CameraCharacteristics c : mCharacteristics) {
    160             mCollector.setCameraId(mIds[counter]);
    161 
    162             if (VERBOSE) {
    163                 Log.v(TAG, "testKeys - testing characteristics for camera " + mIds[counter]);
    164             }
    165 
    166             List<CameraCharacteristics.Key<?>> allKeys = c.getKeys();
    167             assertNotNull("Camera characteristics keys must not be null", allKeys);
    168             assertFalse("Camera characteristics keys must have at least 1 key",
    169                     allKeys.isEmpty());
    170 
    171             for (CameraCharacteristics.Key<?> key : allKeys) {
    172                 assertKeyPrefixValid(key.getName());
    173 
    174                 // All characteristics keys listed must never be null
    175                 mCollector.expectKeyValueNotNull(c, key);
    176 
    177                 // TODO: add a check that key must not be @hide
    178             }
    179 
    180             /*
    181              * List of keys that must be present in camera characteristics (not null).
    182              *
    183              * Keys for LIMITED, FULL devices might be available despite lacking either
    184              * the hardware level or the capability. This is *OK*. This only lists the
    185              * *minimal* requirements for a key to be listed.
    186              *
    187              * LEGACY devices are a bit special since they map to api1 devices, so we know
    188              * for a fact most keys are going to be illegal there so they should never be
    189              * available.
    190              *
    191              * (TODO: Codegen this)
    192              */
    193             {
    194                 //                                           (Key Name)                                     (HW Level)  (Capabilities <Var-Arg>)
    195                 expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES     , LEGACY   ,   BC                   );
    196                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          , LEGACY   ,   BC                   );
    197                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      , LEGACY   ,   BC                   );
    198                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          , LEGACY   ,   BC                   );
    199                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   , LEGACY   ,   BC                   );
    200                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    , LEGACY   ,   BC                   );
    201                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      , LEGACY   ,   BC                   );
    202                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       , LEGACY   ,   BC                   );
    203                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   , LEGACY   ,   BC                   );
    204                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     , LEGACY   ,   BC                   );
    205                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     , LEGACY   ,   BC                   );
    206                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE                          , LEGACY   ,   BC                   );
    207                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF                          , LEGACY   ,   BC                   );
    208                 expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB                         , LEGACY   ,   BC                   );
    209                 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES                       , FULL     ,   NONE                 );
    210                 expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE                            , LEGACY   ,   BC                   );
    211                 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES             , OPT      ,   RAW                  );
    212                 expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   , LEGACY   ,   BC                   );
    213                 expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  , LEGACY   ,   BC                   );
    214                 expectKeyAvailable(c, CameraCharacteristics.LENS_FACING                                     , LEGACY   ,   BC                   );
    215                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES                   , FULL     ,   MANUAL_SENSOR        );
    216                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES            , FULL     ,   MANUAL_SENSOR        );
    217                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               , LEGACY   ,   BC                   );
    218                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION       , LIMITED  ,   MANUAL_SENSOR        );
    219                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION            , LIMITED  ,   MANUAL_SENSOR        );
    220                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE                   , LIMITED  ,   MANUAL_SENSOR        );
    221                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE                , LIMITED  ,   NONE                 );
    222                 expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , LEGACY   ,   BC                   );
    223                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  , LEGACY   ,   BC                   );
    224                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC                     , LEGACY   ,   BC                   );
    225                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING            , LEGACY   ,   BC                   );
    226                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW                      , LEGACY   ,   BC                   );
    227                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    , LEGACY   ,   BC                   );
    228                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      , LEGACY   ,   BC                   );
    229                 expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               , LEGACY   ,   BC                   );
    230                 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , LEGACY   ,   BC                   );
    231                 expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE                            , LEGACY   ,   BC                   );
    232                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             , LEGACY   ,   NONE                 );
    233                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN                      , FULL     ,   MANUAL_SENSOR, RAW   );
    234                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1                   , OPT      ,   RAW                  );
    235                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2                   , OPT      ,   RAW                  );
    236                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1                         , OPT      ,   RAW                  );
    237                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM2                         , OPT      ,   RAW                  );
    238                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1                          , OPT      ,   RAW                  );
    239                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX2                          , OPT      ,   RAW                  );
    240                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   , LEGACY   ,   BC, RAW              );
    241                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT            , FULL     ,   RAW                  );
    242                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE                 , FULL     ,   MANUAL_SENSOR        );
    243                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION                  , FULL     ,   MANUAL_SENSOR        );
    244                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       , LEGACY   ,   BC                   );
    245                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    , LEGACY   ,   BC                   );
    246                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE                   , FULL     ,   MANUAL_SENSOR        );
    247                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL                         , OPT      ,   RAW                  );
    248                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE                    , LEGACY   ,   BC                   );
    249                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY                   , FULL     ,   MANUAL_SENSOR        );
    250                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION                              , LEGACY   ,   BC                   );
    251                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1                    , OPT      ,   RAW                  );
    252                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2                    , OPT      ,   RAW                  );
    253                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     , LEGACY   ,   BC                   );
    254                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES   , OPT      ,   RAW                  );
    255                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  , LEGACY   ,   BC                   );
    256                 expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY                                , LEGACY   ,   BC                   );
    257                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES                , FULL     ,   MANUAL_POSTPROC      );
    258                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS                        , FULL     ,   MANUAL_POSTPROC      );
    259 
    260                 // Future: Use column editors for modifying above, ignore line length to keep 1 key per line
    261 
    262                 // TODO: check that no other 'android' keys are listed in #getKeys if they aren't in the above list
    263             }
    264 
    265             counter++;
    266         }
    267     }
    268 
    269     /**
    270      * Test values for static metadata used by the RAW capability.
    271      */
    272     public void testStaticRawCharacteristics() {
    273         int counter = 0;
    274         for (CameraCharacteristics c : mCharacteristics) {
    275             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
    276             assertNotNull("android.request.availableCapabilities must never be null",
    277                     actualCapabilities);
    278             if (!arrayContains(actualCapabilities,
    279                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
    280                 Log.i(TAG, "RAW capability is not supported in camera " + counter++ +
    281                         ". Skip the test.");
    282                 continue;
    283             }
    284 
    285             Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    286             if (actualHwLevel != null && actualHwLevel == FULL) {
    287                 mCollector.expectKeyValueContains(c,
    288                         CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
    289                         CameraCharacteristics.HOT_PIXEL_MODE_FAST);
    290             }
    291             mCollector.expectKeyValueContains(c,
    292                     CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, false);
    293             mCollector.expectKeyValueGreaterThan(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL,
    294                     MIN_ALLOWABLE_WHITELEVEL);
    295 
    296             mCollector.expectKeyValueIsIn(c,
    297                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
    298                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
    299                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
    300                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
    301                     CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR);
    302             // TODO: SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB isn't supported yet.
    303 
    304             mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1,
    305                     CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT,
    306                     CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN);
    307             mCollector.expectKeyValueInRange(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT2,
    308                     (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT,
    309                     (byte) CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN);
    310 
    311             Rational[] zeroes = new Rational[9];
    312             Arrays.fill(zeroes, Rational.ZERO);
    313 
    314             ColorSpaceTransform zeroed = new ColorSpaceTransform(zeroes);
    315             mCollector.expectNotEquals("Forward Matrix1 should not contain all zeroes.", zeroed,
    316                     c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX1));
    317             mCollector.expectNotEquals("Forward Matrix2 should not contain all zeroes.", zeroed,
    318                     c.get(CameraCharacteristics.SENSOR_FORWARD_MATRIX2));
    319             mCollector.expectNotEquals("Calibration Transform1 should not contain all zeroes.",
    320                     zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1));
    321             mCollector.expectNotEquals("Calibration Transform2 should not contain all zeroes.",
    322                     zeroed, c.get(CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM2));
    323             mCollector.expectNotEquals("Color Transform1 should not contain all zeroes.",
    324                     zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM1));
    325             mCollector.expectNotEquals("Color Transform2 should not contain all zeroes.",
    326                     zeroed, c.get(CameraCharacteristics.SENSOR_COLOR_TRANSFORM2));
    327 
    328             BlackLevelPattern blackLevel = mCollector.expectKeyValueNotNull(c,
    329                     CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
    330             if (blackLevel != null) {
    331                 int[] blackLevelPattern = new int[BlackLevelPattern.COUNT];
    332                 blackLevel.copyTo(blackLevelPattern, /*offset*/0);
    333                 Integer whitelevel = c.get(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
    334                 if (whitelevel != null) {
    335                     mCollector.expectValuesInRange("BlackLevelPattern", blackLevelPattern, 0,
    336                             whitelevel);
    337                 } else {
    338                     mCollector.addMessage(
    339                             "No WhiteLevel available, cannot check BlackLevelPattern range.");
    340                 }
    341             }
    342 
    343             // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
    344             counter++;
    345         }
    346     }
    347 
    348     /**
    349      * Test values for static metadata used by the BURST capability.
    350      */
    351     public void testStaticBurstCharacteristics() {
    352         int counter = 0;
    353         for (CameraCharacteristics c : mCharacteristics) {
    354             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
    355             assertNotNull("android.request.availableCapabilities must never be null",
    356                     actualCapabilities);
    357 
    358             // Check if the burst capability is defined
    359             boolean haveBurstCapability = arrayContains(actualCapabilities,
    360                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
    361 
    362             StreamConfigurationMap config =
    363                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    364             assertNotNull(String.format("No stream configuration map found for: ID %s",
    365                     mIds[counter]), config);
    366 
    367             // Ensure that max YUV size matches max JPEG size
    368             Size maxYuvSize = CameraTestUtils.getMaxSize(
    369                     config.getOutputSizes(ImageFormat.YUV_420_888));
    370             Size maxJpegSize = CameraTestUtils.getMaxSize(config.getOutputSizes(ImageFormat.JPEG));
    371 
    372             boolean haveMaxYuv = maxYuvSize != null ?
    373                 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
    374                         maxJpegSize.getHeight() <= maxYuvSize.getHeight()) : false;
    375 
    376             // Ensure that YUV output is fast enough - needs to be at least 20 fps
    377 
    378             long maxYuvRate =
    379                 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
    380             final long MIN_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps
    381 
    382             boolean haveMaxYuvRate = maxYuvRate <= MIN_DURATION_BOUND_NS;
    383 
    384             // Ensure that there's an FPS range that's fast enough to capture at above
    385             // minFrameDuration, for full-auto bursts
    386             Range[] fpsRanges = c.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
    387             float minYuvFps = 1.f / maxYuvRate;
    388 
    389             boolean haveFastAeTargetFps = false;
    390             for (Range<Integer> r : fpsRanges) {
    391                 if (r.getLower() >= minYuvFps) {
    392                     haveFastAeTargetFps = true;
    393                     break;
    394                 }
    395             }
    396 
    397             // Ensure that maximum sync latency is small enough for fast setting changes, even if
    398             // it's not quite per-frame
    399 
    400             Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY);
    401             assertNotNull(String.format("No sync latency declared for ID %s", mIds[counter]),
    402                     maxSyncLatencyValue);
    403 
    404             int maxSyncLatency = maxSyncLatencyValue;
    405             final long MAX_LATENCY_BOUND = 4;
    406             boolean haveFastSyncLatency =
    407                 (maxSyncLatency <= MAX_LATENCY_BOUND) && (maxSyncLatency >= 0);
    408 
    409             if (haveBurstCapability) {
    410                 assertTrue(
    411                         String.format("BURST-capable camera device %s does not have maximum YUV " +
    412                                 "size that is at least max JPEG size",
    413                                 mIds[counter]),
    414                         haveMaxYuv);
    415                 assertTrue(
    416                         String.format("BURST-capable camera device %s YUV frame rate is too slow" +
    417                                 "(%d ns min frame duration reported, less than %d ns expected)",
    418                                 mIds[counter], maxYuvRate, MIN_DURATION_BOUND_NS),
    419                         haveMaxYuvRate);
    420                 assertTrue(
    421                         String.format("BURST-capable camera device %s does not list an AE target " +
    422                                 " FPS range with min FPS >= %f, for full-AUTO bursts",
    423                                 mIds[counter], minYuvFps),
    424                         haveFastAeTargetFps);
    425                 assertTrue(
    426                         String.format("BURST-capable camera device %s YUV sync latency is too long" +
    427                                 "(%d frames reported, [0, %d] frames expected)",
    428                                 mIds[counter], maxSyncLatency, MAX_LATENCY_BOUND),
    429                         haveFastSyncLatency);
    430             } else {
    431                 assertTrue(
    432                         String.format("Camera device %s has all the requirements for BURST" +
    433                                 " capability but does not report it!", mIds[counter]),
    434                         !(haveMaxYuv && haveMaxYuvRate &&
    435                                 haveFastAeTargetFps && haveFastSyncLatency));
    436             }
    437 
    438             counter++;
    439         }
    440     }
    441 
    442     /**
    443      * Cross-check StreamConfigurationMap output
    444      */
    445     public void testStreamConfigurationMap() {
    446         int counter = 0;
    447         for (CameraCharacteristics c : mCharacteristics) {
    448             Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]);
    449             StreamConfigurationMap config =
    450                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    451             assertNotNull(String.format("No stream configuration map found for: ID %s",
    452                             mIds[counter]), config);
    453 
    454             assertTrue("ImageReader must be supported",
    455                     config.isOutputSupportedFor(android.media.ImageReader.class));
    456             assertTrue("MediaRecorder must be supported",
    457                     config.isOutputSupportedFor(android.media.MediaRecorder.class));
    458             assertTrue("MediaCodec must be supported",
    459                     config.isOutputSupportedFor(android.media.MediaCodec.class));
    460             assertTrue("Allocation must be supported",
    461                     config.isOutputSupportedFor(android.renderscript.Allocation.class));
    462             assertTrue("SurfaceHolder must be supported",
    463                     config.isOutputSupportedFor(android.view.SurfaceHolder.class));
    464             assertTrue("SurfaceTexture must be supported",
    465                     config.isOutputSupportedFor(android.graphics.SurfaceTexture.class));
    466 
    467             assertTrue("YUV_420_888 must be supported",
    468                     config.isOutputSupportedFor(ImageFormat.YUV_420_888));
    469             assertTrue("JPEG must be supported",
    470                     config.isOutputSupportedFor(ImageFormat.JPEG));
    471 
    472             // Legacy YUV formats should not be listed
    473             assertTrue("NV21 must not be supported",
    474                     !config.isOutputSupportedFor(ImageFormat.NV21));
    475 
    476             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
    477             assertNotNull("android.request.availableCapabilities must never be null",
    478                     actualCapabilities);
    479             if (arrayContains(actualCapabilities,
    480                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
    481                 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised",
    482                     config.isOutputSupportedFor(ImageFormat.RAW_SENSOR));
    483             }
    484 
    485             // Cross check public formats and sizes
    486 
    487             int[] supportedFormats = config.getOutputFormats();
    488             for (int format : supportedFormats) {
    489                 assertTrue("Format " + format + " fails cross check",
    490                         config.isOutputSupportedFor(format));
    491                 Size[] supportedSizes = config.getOutputSizes(format);
    492                 assertTrue("Supported format " + format + " has no sizes listed",
    493                         supportedSizes.length > 0);
    494                 for (Size size : supportedSizes) {
    495                     if (VERBOSE) {
    496                         Log.v(TAG,
    497                                 String.format("Testing camera %s, format %d, size %s",
    498                                         mIds[counter], format, size.toString()));
    499                     }
    500 
    501                     long stallDuration = config.getOutputStallDuration(format, size);
    502                     switch(format) {
    503                         case ImageFormat.YUV_420_888:
    504                             assertTrue("YUV_420_888 may not have a non-zero stall duration",
    505                                     stallDuration == 0);
    506                             break;
    507                         default:
    508                             assertTrue("Negative stall duration for format " + format,
    509                                     stallDuration >= 0);
    510                             break;
    511                     }
    512                     long minDuration = config.getOutputMinFrameDuration(format, size);
    513                     if (arrayContains(actualCapabilities,
    514                             CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
    515                         assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
    516                                 + "format " + format + " for size " + size + " minDuration " +
    517                                 minDuration,
    518                                 minDuration > 0);
    519                     } else {
    520                         assertTrue("Need non-negative min frame duration for format " + format,
    521                                 minDuration >= 0);
    522                     }
    523 
    524                     ImageReader testReader = ImageReader.newInstance(
    525                         size.getWidth(),
    526                         size.getHeight(),
    527                         format,
    528                         1);
    529                     Surface testSurface = testReader.getSurface();
    530 
    531                     assertTrue(
    532                         String.format("isOutputSupportedFor fails for config %s, format %d",
    533                                 size.toString(), format),
    534                         config.isOutputSupportedFor(testSurface));
    535 
    536                     testReader.close();
    537 
    538                 } // sizes
    539 
    540                 // Try an invalid size in this format, should round
    541                 Size invalidSize = findInvalidSize(supportedSizes);
    542                 int MAX_ROUNDING_WIDTH = 1920;
    543                 if (invalidSize.getWidth() <= MAX_ROUNDING_WIDTH) {
    544                     ImageReader testReader = ImageReader.newInstance(
    545                                                                      invalidSize.getWidth(),
    546                                                                      invalidSize.getHeight(),
    547                                                                      format,
    548                                                                      1);
    549                     Surface testSurface = testReader.getSurface();
    550 
    551                     assertTrue(
    552                                String.format("isOutputSupportedFor fails for config %s, %d",
    553                                        invalidSize.toString(), format),
    554                                config.isOutputSupportedFor(testSurface));
    555 
    556                     testReader.close();
    557                 }
    558             } // formats
    559 
    560             // Cross-check opaque format and sizes
    561 
    562             SurfaceTexture st = new SurfaceTexture(1);
    563             Surface surf = new Surface(st);
    564 
    565             Size[] opaqueSizes = config.getOutputSizes(SurfaceTexture.class);
    566             assertTrue("Opaque format has no sizes listed",
    567                     opaqueSizes.length > 0);
    568             for (Size size : opaqueSizes) {
    569                 long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size);
    570                 assertTrue("Opaque output may not have a non-zero stall duration",
    571                         stallDuration == 0);
    572 
    573                 long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size);
    574                 if (arrayContains(actualCapabilities,
    575                                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
    576                     assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
    577                             + "opaque format",
    578                             minDuration > 0);
    579                 } else {
    580                     assertTrue("Need non-negative min frame duration for opaque format ",
    581                             minDuration >= 0);
    582                 }
    583                 st.setDefaultBufferSize(size.getWidth(), size.getHeight());
    584 
    585                 assertTrue(
    586                     String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
    587                             size.toString()),
    588                     config.isOutputSupportedFor(surf));
    589 
    590             } // opaque sizes
    591 
    592             // Try invalid opaque size, should get rounded
    593             Size invalidSize = findInvalidSize(opaqueSizes);
    594             st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight());
    595             assertTrue(
    596                 String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
    597                         invalidSize.toString()),
    598                 config.isOutputSupportedFor(surf));
    599 
    600             counter++;
    601         } // mCharacteristics
    602 
    603     }
    604 
    605     /**
    606      * Create an invalid size that's close to one of the good sizes in the list, but not one of them
    607      */
    608     private Size findInvalidSize(Size[] goodSizes) {
    609         Size invalidSize = new Size(goodSizes[0].getWidth() + 1, goodSizes[0].getHeight());
    610         while(arrayContains(goodSizes, invalidSize)) {
    611             invalidSize = new Size(invalidSize.getWidth() + 1, invalidSize.getHeight());
    612         }
    613         return invalidSize;
    614     }
    615 
    616     /**
    617      * Check key is present in characteristics if the hardware level is at least {@code hwLevel};
    618      * check that the key is present if the actual capabilities are one of {@code capabilities}.
    619      *
    620      * @return value of the {@code key} from {@code c}
    621      */
    622     private <T> T expectKeyAvailable(CameraCharacteristics c, CameraCharacteristics.Key<T> key,
    623             int hwLevel, int... capabilities) {
    624 
    625         Integer actualHwLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
    626         assertNotNull("android.info.supportedHardwareLevel must never be null", actualHwLevel);
    627 
    628         int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
    629         assertNotNull("android.request.availableCapabilities must never be null",
    630                 actualCapabilities);
    631 
    632         List<Key<?>> allKeys = c.getKeys();
    633 
    634         T value = c.get(key);
    635 
    636         if (compareHardwareLevel(actualHwLevel, hwLevel) >= 0) {
    637             mCollector.expectTrue(
    638                     String.format("Key (%s) must be in characteristics for this hardware level " +
    639                             "(required minimal HW level %s, actual HW level %s)",
    640                             key.getName(), toStringHardwareLevel(hwLevel),
    641                             toStringHardwareLevel(actualHwLevel)),
    642                     value != null);
    643             mCollector.expectTrue(
    644                     String.format("Key (%s) must be in characteristics list of keys for this " +
    645                             "hardware level (required minimal HW level %s, actual HW level %s)",
    646                             key.getName(), toStringHardwareLevel(hwLevel),
    647                             toStringHardwareLevel(actualHwLevel)),
    648                     allKeys.contains(key));
    649         } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) {
    650             mCollector.expectTrue(
    651                     String.format("Key (%s) must be in characteristics for these capabilities " +
    652                             "(required capabilities %s, actual capabilities %s)",
    653                             key.getName(), Arrays.toString(capabilities),
    654                             Arrays.toString(actualCapabilities)),
    655                     value != null);
    656             mCollector.expectTrue(
    657                     String.format("Key (%s) must be in characteristics list of keys for " +
    658                             "these capabilities (required capabilities %s, actual capabilities %s)",
    659                             key.getName(), Arrays.toString(capabilities),
    660                             Arrays.toString(actualCapabilities)),
    661                     allKeys.contains(key));
    662         } else {
    663             if (actualHwLevel == LEGACY && hwLevel != OPT) {
    664                 if (value != null || allKeys.contains(key)) {
    665                     Log.w(TAG, String.format(
    666                             "Key (%s) is not required for LEGACY devices but still appears",
    667                             key.getName()));
    668                 }
    669             }
    670             // OK: Key may or may not be present.
    671         }
    672         return value;
    673     }
    674 
    675     private static boolean arrayContains(int[] arr, int needle) {
    676         if (arr == null) {
    677             return false;
    678         }
    679 
    680         for (int elem : arr) {
    681             if (elem == needle) {
    682                 return true;
    683             }
    684         }
    685 
    686         return false;
    687     }
    688 
    689     private static <T> boolean arrayContains(T[] arr, T needle) {
    690         if (arr == null) {
    691             return false;
    692         }
    693 
    694         for (T elem : arr) {
    695             if (elem.equals(needle)) {
    696                 return true;
    697             }
    698         }
    699 
    700         return false;
    701     }
    702 
    703     private static boolean arrayContainsAnyOf(int[] arr, int[] needles) {
    704         for (int needle : needles) {
    705             if (arrayContains(arr, needle)) {
    706                 return true;
    707             }
    708         }
    709         return false;
    710     }
    711 
    712     /**
    713      * The key name has a prefix of either "android." or "com."; other prefixes are not valid.
    714      */
    715     private static void assertKeyPrefixValid(String keyName) {
    716         assertStartsWithAnyOf(
    717                 "All metadata keys must start with 'android.' (built-in keys) " +
    718                 "or 'com.' (vendor-extended keys)", new String[] {
    719                         PREFIX_ANDROID + ".",
    720                         PREFIX_VENDOR + ".",
    721                 }, keyName);
    722     }
    723 
    724     private static void assertTrueForKey(String msg, CameraCharacteristics.Key<?> key,
    725             boolean actual) {
    726         assertTrue(msg + " (key = '" + key.getName() + "')", actual);
    727     }
    728 
    729     private static <T> void assertOneOf(String msg, T[] expected, T actual) {
    730         for (int i = 0; i < expected.length; ++i) {
    731             if (Objects.equals(expected[i], actual)) {
    732                 return;
    733             }
    734         }
    735 
    736         fail(String.format("%s: (expected one of %s, actual %s)",
    737                 msg, Arrays.toString(expected), actual));
    738     }
    739 
    740     private static <T> void assertStartsWithAnyOf(String msg, String[] expected, String actual) {
    741         for (int i = 0; i < expected.length; ++i) {
    742             if (actual.startsWith(expected[i])) {
    743                 return;
    744             }
    745         }
    746 
    747         fail(String.format("%s: (expected to start with any of %s, but value was %s)",
    748                 msg, Arrays.toString(expected), actual));
    749     }
    750 
    751     /** Return a positive int if left > right, 0 if left==right, negative int if left < right */
    752     private static int compareHardwareLevel(int left, int right) {
    753         return remapHardwareLevel(left) - remapHardwareLevel(right);
    754     }
    755 
    756     /** Remap HW levels worst<->best, 0 = worst, 2 = best */
    757     private static int remapHardwareLevel(int level) {
    758         switch (level) {
    759             case OPT:
    760                 return Integer.MAX_VALUE;
    761             case LEGACY:
    762                 return 0; // lowest
    763             case LIMITED:
    764                 return 1; // second lowest
    765             case FULL:
    766                 return 2; // best
    767         }
    768 
    769         fail("Unknown HW level: " + level);
    770         return -1;
    771     }
    772 
    773     private static String toStringHardwareLevel(int level) {
    774         switch (level) {
    775             case LEGACY:
    776                 return "LEGACY";
    777             case LIMITED:
    778                 return "LIMITED";
    779             case FULL:
    780                 return "FULL";
    781         }
    782 
    783         // unknown
    784         Log.w(TAG, "Unknown hardware level " + level);
    785         return Integer.toString(level);
    786     }
    787 }
    788