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 static android.hardware.camera2.CameraCharacteristics.*;
     20 
     21 import android.graphics.ImageFormat;
     22 import android.graphics.Rect;
     23 import android.hardware.camera2.CameraCharacteristics;
     24 import android.hardware.camera2.CameraMetadata;
     25 import android.hardware.camera2.CaptureRequest;
     26 import android.hardware.camera2.CaptureResult;
     27 import android.hardware.camera2.CameraCharacteristics.Key;
     28 import android.hardware.camera2.cts.helpers.StaticMetadata;
     29 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
     30 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
     31 import android.hardware.camera2.params.StreamConfigurationMap;
     32 import android.platform.test.annotations.AppModeFull;
     33 import android.util.Log;
     34 import android.util.Pair;
     35 import android.util.Size;
     36 
     37 import java.util.ArrayList;
     38 import java.util.Arrays;
     39 import java.util.Collection;
     40 import java.util.HashMap;
     41 import java.util.HashSet;
     42 import java.util.List;
     43 import java.util.Set;
     44 
     45 /**
     46  * <p>
     47  * This class covers the {@link CameraCharacteristics} tests that are not
     48  * covered by {@link CaptureRequestTest} and {@link ExtendedCameraCharacteristicsTest}
     49  * </p>
     50  * <p>
     51  * Note that most of the tests in this class don't require camera open.
     52  * </p>
     53  */
     54 @AppModeFull
     55 public class StaticMetadataTest extends Camera2AndroidTestCase {
     56     private static final String TAG = "StaticMetadataTest";
     57     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     58     private static final float MIN_FPS_FOR_FULL_DEVICE = 20.0f;
     59     private String mCameraId;
     60 
     61     // Last defined capability enum, for iterating over all of them
     62     private static final int LAST_CAPABILITY_ENUM = REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME;
     63 
     64     /**
     65      * Test the available capability for different hardware support level devices.
     66      */
     67     public void testHwSupportedLevel() throws Exception {
     68         Key<StreamConfigurationMap> key =
     69                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
     70         final float SIZE_ERROR_MARGIN = 0.03f;
     71         for (String id : mCameraIds) {
     72             initStaticMetadata(id);
     73             StreamConfigurationMap configs = mStaticInfo.getValueFromKeyNonNull(key);
     74             Rect activeRect = mStaticInfo.getActiveArraySizeChecked();
     75             Size sensorSize = new Size(activeRect.width(), activeRect.height());
     76             List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
     77 
     78             mCollector.expectTrue("All devices must contains BACKWARD_COMPATIBLE capability or " +
     79                     "DEPTH_OUTPUT capabillity" ,
     80                     availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ||
     81                     availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) );
     82 
     83             if (mStaticInfo.isHardwareLevelAtLeast(
     84                     CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) {
     85                 mCollector.expectTrue("Level 3 device must contain YUV_REPROCESSING capability",
     86                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING));
     87                 mCollector.expectTrue("Level 3 device must contain RAW capability",
     88                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_RAW));
     89             }
     90 
     91             if (mStaticInfo.isHardwareLevelAtLeastFull()) {
     92                 // Capability advertisement must be right.
     93                 mCollector.expectTrue("Full device must contain MANUAL_SENSOR capability",
     94                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR));
     95                 mCollector.expectTrue("Full device must contain MANUAL_POST_PROCESSING capability",
     96                         availableCaps.contains(
     97                                 REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING));
     98                 mCollector.expectTrue("Full device must contain BURST_CAPTURE capability",
     99                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE));
    100 
    101                 // Need support per frame control
    102                 mCollector.expectTrue("Full device must support per frame control",
    103                         mStaticInfo.isPerFrameControlSupported());
    104             }
    105 
    106             if (mStaticInfo.isHardwareLevelLegacy()) {
    107                 mCollector.expectTrue("Legacy devices must contain BACKWARD_COMPATIBLE capability",
    108                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE));
    109             }
    110 
    111             if (availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
    112                 mCollector.expectTrue("MANUAL_SENSOR capability always requires " +
    113                         "READ_SENSOR_SETTINGS capability as well",
    114                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS));
    115             }
    116 
    117             if (mStaticInfo.isColorOutputSupported()) {
    118                 // Max jpeg resolution must be very close to  sensor resolution
    119                 Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
    120                 Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
    121                 float croppedWidth = (float)sensorSize.getWidth();
    122                 float croppedHeight = (float)sensorSize.getHeight();
    123                 float sensorAspectRatio = (float)sensorSize.getWidth() / (float)sensorSize.getHeight();
    124                 float maxJpegAspectRatio = (float)maxJpegSize.getWidth() / (float)maxJpegSize.getHeight();
    125                 if (sensorAspectRatio < maxJpegAspectRatio) {
    126                     croppedHeight = (float)sensorSize.getWidth() / maxJpegAspectRatio;
    127                 } else if (sensorAspectRatio > maxJpegAspectRatio) {
    128                     croppedWidth = (float)sensorSize.getHeight() * maxJpegAspectRatio;
    129                 }
    130                 Size croppedSensorSize = new Size((int)croppedWidth, (int)croppedHeight);
    131                 mCollector.expectSizesAreSimilar(
    132                     "Active array size or cropped active array size and max JPEG size should be similar",
    133                     croppedSensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
    134             }
    135 
    136             // TODO: test all the keys mandatory for all capability devices.
    137         }
    138     }
    139 
    140     /**
    141      * Test max number of output stream reported by device
    142      */
    143     public void testMaxNumOutputStreams() throws Exception {
    144         for (String id : mCameraIds) {
    145             initStaticMetadata(id);
    146             int maxNumStreamsRaw = mStaticInfo.getMaxNumOutputStreamsRawChecked();
    147             int maxNumStreamsProc = mStaticInfo.getMaxNumOutputStreamsProcessedChecked();
    148             int maxNumStreamsProcStall = mStaticInfo.getMaxNumOutputStreamsProcessedStallChecked();
    149 
    150             mCollector.expectTrue("max number of raw output streams must be a non negative number",
    151                     maxNumStreamsRaw >= 0);
    152             mCollector.expectTrue("max number of processed (stalling) output streams must be >= 1",
    153                     maxNumStreamsProcStall >= 1);
    154 
    155             if (mStaticInfo.isHardwareLevelAtLeastFull()) {
    156                 mCollector.expectTrue("max number of processed (non-stalling) output streams" +
    157                         "must be >= 3 for FULL device",
    158                         maxNumStreamsProc >= 3);
    159             } else if (mStaticInfo.isColorOutputSupported()) {
    160                 mCollector.expectTrue("max number of processed (non-stalling) output streams" +
    161                         "must be >= 2 for devices that support color output",
    162                         maxNumStreamsProc >= 2);
    163             }
    164         }
    165 
    166     }
    167 
    168     /**
    169      * Test advertised capability does match available keys and vice versa
    170      */
    171     public void testCapabilities() throws Exception {
    172         for (String id : mCameraIds) {
    173             initStaticMetadata(id);
    174             List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
    175 
    176             for (Integer capability = REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
    177                     capability <= LAST_CAPABILITY_ENUM; capability++) {
    178                 boolean isCapabilityAvailable = availableCaps.contains(capability);
    179                 validateCapability(capability, isCapabilityAvailable);
    180             }
    181             // Note: Static metadata for capabilities is tested in ExtendedCameraCharacteristicsTest
    182         }
    183     }
    184 
    185     /**
    186      * Check if request keys' presence match expectation.
    187      *
    188      * @param capabilityName The name string of capability being tested. Used for output messages.
    189      * @param requestKeys The capture request keys to be checked
    190      * @param expectedPresence Expected presence of {@code requestKeys}. {@code true} for expecting
    191      *        all keys are available. Otherwise {@code false}
    192      * @return {@code true} if request keys' presence match expectation. Otherwise {@code false}
    193      */
    194     private boolean validateRequestKeysPresence(String capabilityName,
    195             Collection<CaptureRequest.Key<?>> requestKeys, boolean expectedPresence) {
    196         boolean actualPresence = mStaticInfo.areRequestKeysAvailable(requestKeys);
    197         if (expectedPresence != actualPresence) {
    198             if (expectedPresence) {
    199                 for (CaptureRequest.Key<?> key : requestKeys) {
    200                     if (!mStaticInfo.areKeysAvailable(key)) {
    201                         mCollector.addMessage(String.format(
    202                                 "Camera %s list capability %s but doesn't contain request key %s",
    203                                 mCameraId, capabilityName, key.getName()));
    204                     }
    205                 }
    206             } else {
    207                 Log.w(TAG, String.format(
    208                         "Camera %s doesn't list capability %s but contain all required keys",
    209                         mCameraId, capabilityName));
    210             }
    211             return false;
    212         }
    213         return true;
    214     }
    215 
    216     /**
    217      * Check if result keys' presence match expectation.
    218      *
    219      * @param capabilityName The name string of capability being tested. Used for output messages.
    220      * @param resultKeys The capture result keys to be checked
    221      * @param expectedPresence Expected presence of {@code resultKeys}. {@code true} for expecting
    222      *        all keys are available. Otherwise {@code false}
    223      * @return {@code true} if result keys' presence match expectation. Otherwise {@code false}
    224      */
    225     private boolean validateResultKeysPresence(String capabilityName,
    226             Collection<CaptureResult.Key<?>> resultKeys, boolean expectedPresence) {
    227         boolean actualPresence = mStaticInfo.areResultKeysAvailable(resultKeys);
    228         if (expectedPresence != actualPresence) {
    229             if (expectedPresence) {
    230                 for (CaptureResult.Key<?> key : resultKeys) {
    231                     if (!mStaticInfo.areKeysAvailable(key)) {
    232                         mCollector.addMessage(String.format(
    233                                 "Camera %s list capability %s but doesn't contain result key %s",
    234                                 mCameraId, capabilityName, key.getName()));
    235                     }
    236                 }
    237             } else {
    238                 Log.w(TAG, String.format(
    239                         "Camera %s doesn't list capability %s but contain all required keys",
    240                         mCameraId, capabilityName));
    241             }
    242             return false;
    243         }
    244         return true;
    245     }
    246 
    247     /**
    248      * Check if characteristics keys' presence match expectation.
    249      *
    250      * @param capabilityName The name string of capability being tested. Used for output messages.
    251      * @param characteristicsKeys The characteristics keys to be checked
    252      * @param expectedPresence Expected presence of {@code characteristicsKeys}. {@code true} for
    253      *        expecting all keys are available. Otherwise {@code false}
    254      * @return {@code true} if characteristics keys' presence match expectation.
    255      *         Otherwise {@code false}
    256      */
    257     private boolean validateCharacteristicsKeysPresence(String capabilityName,
    258             Collection<CameraCharacteristics.Key<?>> characteristicsKeys,
    259             boolean expectedPresence) {
    260         boolean actualPresence = mStaticInfo.areCharacteristicsKeysAvailable(characteristicsKeys);
    261         if (expectedPresence != actualPresence) {
    262             if (expectedPresence) {
    263                 for (CameraCharacteristics.Key<?> key : characteristicsKeys) {
    264                     if (!mStaticInfo.areKeysAvailable(key)) {
    265                         mCollector.addMessage(String.format(
    266                                 "Camera %s list capability %s but doesn't contain" +
    267                                 "characteristics key %s",
    268                                 mCameraId, capabilityName, key.getName()));
    269                     }
    270                 }
    271             } else {
    272                 Log.w(TAG, String.format(
    273                         "Camera %s doesn't list capability %s but contain all required keys",
    274                         mCameraId, capabilityName));
    275             }
    276             return false;
    277         }
    278         return true;
    279     }
    280 
    281     private void validateCapability(Integer capability, boolean isCapabilityAvailable) {
    282         List<CaptureRequest.Key<?>> requestKeys = new ArrayList<>();
    283         Set<CaptureResult.Key<?>> resultKeys = new HashSet<>();
    284         // Capability requirements other than key presences
    285         List<Pair<String, Boolean>> additionalRequirements = new ArrayList<>();
    286 
    287         /* For available capabilities, only check request keys in this test
    288            Characteristics keys are tested in ExtendedCameraCharacteristicsTest
    289            Result keys are tested in CaptureResultTest */
    290         String capabilityName;
    291         switch (capability) {
    292             case REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
    293                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE";
    294                 requestKeys.add(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE);
    295                 requestKeys.add(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION);
    296                 requestKeys.add(CaptureRequest.CONTROL_AE_MODE);
    297                 requestKeys.add(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
    298                 requestKeys.add(CaptureRequest.CONTROL_AF_MODE);
    299                 requestKeys.add(CaptureRequest.CONTROL_AF_TRIGGER);
    300                 requestKeys.add(CaptureRequest.CONTROL_AWB_MODE);
    301                 requestKeys.add(CaptureRequest.CONTROL_CAPTURE_INTENT);
    302                 requestKeys.add(CaptureRequest.CONTROL_EFFECT_MODE);
    303                 requestKeys.add(CaptureRequest.CONTROL_MODE);
    304                 requestKeys.add(CaptureRequest.CONTROL_SCENE_MODE);
    305                 requestKeys.add(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE);
    306                 requestKeys.add(CaptureRequest.FLASH_MODE);
    307                 requestKeys.add(CaptureRequest.JPEG_GPS_LOCATION);
    308                 requestKeys.add(CaptureRequest.JPEG_ORIENTATION);
    309                 requestKeys.add(CaptureRequest.JPEG_QUALITY);
    310                 requestKeys.add(CaptureRequest.JPEG_THUMBNAIL_QUALITY);
    311                 requestKeys.add(CaptureRequest.JPEG_THUMBNAIL_SIZE);
    312                 requestKeys.add(CaptureRequest.SCALER_CROP_REGION);
    313                 requestKeys.add(CaptureRequest.STATISTICS_FACE_DETECT_MODE);
    314                 if (mStaticInfo.getAeMaxRegionsChecked() > 0) {
    315                     requestKeys.add(CaptureRequest.CONTROL_AE_REGIONS);
    316                 } else {
    317                     mCollector.expectTrue(
    318                             "CONTROL_AE_REGIONS is available but aeMaxRegion is 0",
    319                             !mStaticInfo.areKeysAvailable(CaptureRequest.CONTROL_AE_REGIONS));
    320                 }
    321                 if (mStaticInfo.getAwbMaxRegionsChecked() > 0) {
    322                     requestKeys.add(CaptureRequest.CONTROL_AWB_REGIONS);
    323                 } else {
    324                     mCollector.expectTrue(
    325                             "CONTROL_AWB_REGIONS is available but awbMaxRegion is 0",
    326                             !mStaticInfo.areKeysAvailable(CaptureRequest.CONTROL_AWB_REGIONS));
    327                 }
    328                 if (mStaticInfo.getAfMaxRegionsChecked() > 0) {
    329                     requestKeys.add(CaptureRequest.CONTROL_AF_REGIONS);
    330                 } else {
    331                     mCollector.expectTrue(
    332                             "CONTROL_AF_REGIONS is available but afMaxRegion is 0",
    333                             !mStaticInfo.areKeysAvailable(CaptureRequest.CONTROL_AF_REGIONS));
    334                 }
    335                 break;
    336             case REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
    337                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING";
    338                 requestKeys.add(CaptureRequest.TONEMAP_MODE);
    339                 requestKeys.add(CaptureRequest.COLOR_CORRECTION_GAINS);
    340                 requestKeys.add(CaptureRequest.COLOR_CORRECTION_TRANSFORM);
    341                 requestKeys.add(CaptureRequest.SHADING_MODE);
    342                 requestKeys.add(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE);
    343                 requestKeys.add(CaptureRequest.TONEMAP_CURVE);
    344                 requestKeys.add(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
    345                 requestKeys.add(CaptureRequest.CONTROL_AWB_LOCK);
    346 
    347                 // Legacy mode always doesn't support these requirements
    348                 Boolean contrastCurveModeSupported = false;
    349                 Boolean gammaAndPresetModeSupported = false;
    350                 Boolean offColorAberrationModeSupported = false;
    351                 if (mStaticInfo.isHardwareLevelAtLeastLimited() && mStaticInfo.isColorOutputSupported()) {
    352                     int[] tonemapModes = mStaticInfo.getAvailableToneMapModesChecked();
    353                     List<Integer> modeList = (tonemapModes.length == 0) ?
    354                             new ArrayList<Integer>() :
    355                             Arrays.asList(CameraTestUtils.toObject(tonemapModes));
    356                     contrastCurveModeSupported =
    357                             modeList.contains(CameraMetadata.TONEMAP_MODE_CONTRAST_CURVE);
    358                     gammaAndPresetModeSupported =
    359                             modeList.contains(CameraMetadata.TONEMAP_MODE_GAMMA_VALUE) &&
    360                             modeList.contains(CameraMetadata.TONEMAP_MODE_PRESET_CURVE);
    361 
    362                     int[] colorAberrationModes =
    363                             mStaticInfo.getAvailableColorAberrationModesChecked();
    364                     modeList = (colorAberrationModes.length == 0) ?
    365                             new ArrayList<Integer>() :
    366                             Arrays.asList(CameraTestUtils.toObject(colorAberrationModes));
    367                     offColorAberrationModeSupported =
    368                             modeList.contains(CameraMetadata.COLOR_CORRECTION_ABERRATION_MODE_OFF);
    369                 }
    370                 Boolean tonemapModeQualified =
    371                         contrastCurveModeSupported || gammaAndPresetModeSupported;
    372                 additionalRequirements.add(new Pair<String, Boolean>(
    373                         "Tonemap mode must include {CONTRAST_CURVE} and/or " +
    374                         "{GAMMA_VALUE, PRESET_CURVE}",
    375                         tonemapModeQualified));
    376                 additionalRequirements.add(new Pair<String, Boolean>(
    377                         "Color aberration mode must include OFF", offColorAberrationModeSupported));
    378                 additionalRequirements.add(new Pair<String, Boolean>(
    379                         "Must support AWB lock", mStaticInfo.isAwbLockSupported()));
    380                 break;
    381             case REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
    382                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR";
    383                 requestKeys.add(CaptureRequest.CONTROL_AE_LOCK);
    384                 requestKeys.add(CaptureRequest.SENSOR_FRAME_DURATION);
    385                 requestKeys.add(CaptureRequest.SENSOR_EXPOSURE_TIME);
    386                 requestKeys.add(CaptureRequest.SENSOR_SENSITIVITY);
    387                 if (mStaticInfo.hasFocuser()) {
    388                     requestKeys.add(CaptureRequest.LENS_APERTURE);
    389                     requestKeys.add(CaptureRequest.LENS_FOCUS_DISTANCE);
    390                     requestKeys.add(CaptureRequest.LENS_FILTER_DENSITY);
    391                     requestKeys.add(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE);
    392                 }
    393                 requestKeys.add(CaptureRequest.BLACK_LEVEL_LOCK);
    394                 additionalRequirements.add(new Pair<String, Boolean>(
    395                         "Must support AE lock", mStaticInfo.isAeLockSupported()));
    396                 break;
    397             case REQUEST_AVAILABLE_CAPABILITIES_RAW:
    398                 // RAW_CAPABILITY needs to check for not just capture request keys
    399                 validateRawCapability(isCapabilityAvailable);
    400                 return;
    401             case REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
    402                 // Tested in ExtendedCameraCharacteristicsTest
    403                 return;
    404             case REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
    405                 capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS";
    406                 resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
    407                 resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
    408                 resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
    409                 if (mStaticInfo.hasFocuser()) {
    410                     resultKeys.add(CaptureResult.LENS_APERTURE);
    411                     resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
    412                     resultKeys.add(CaptureResult.LENS_FILTER_DENSITY);
    413                 }
    414                 break;
    415 
    416             case REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
    417             case REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
    418                 // Tested in ExtendedCameraCharacteristicsTest
    419                 return;
    420             case REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
    421                 // Tested in ExtendedCameracharacteristicsTest
    422                 return;
    423             case REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO:
    424             case REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING:
    425             case REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA:
    426             case REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME:
    427                 // Tested in ExtendedCameraCharacteristicsTest
    428                 return;
    429             default:
    430                 capabilityName = "Unknown";
    431                 assertTrue(String.format("Unknown capability set: %d", capability),
    432                            !isCapabilityAvailable);
    433                 return;
    434         }
    435 
    436         // Check additional requirements and exit early if possible
    437         if (!isCapabilityAvailable) {
    438             for (Pair<String, Boolean> p : additionalRequirements) {
    439                 String requirement = p.first;
    440                 Boolean meetRequirement = p.second;
    441                 // No further check is needed if we've found why capability cannot be advertised
    442                 if (!meetRequirement) {
    443                     Log.v(TAG, String.format(
    444                             "Camera %s doesn't list capability %s because of requirement: %s",
    445                             mCameraId, capabilityName, requirement));
    446                     return;
    447                 }
    448             }
    449         }
    450 
    451         boolean matchExpectation = true;
    452         if (!requestKeys.isEmpty()) {
    453             matchExpectation &= validateRequestKeysPresence(
    454                     capabilityName, requestKeys, isCapabilityAvailable);
    455         }
    456         if(!resultKeys.isEmpty()) {
    457             matchExpectation &= validateResultKeysPresence(
    458                     capabilityName, resultKeys, isCapabilityAvailable);
    459         }
    460 
    461         // Check additional requirements
    462         for (Pair<String, Boolean> p : additionalRequirements) {
    463             String requirement = p.first;
    464             Boolean meetRequirement = p.second;
    465             if (isCapabilityAvailable && !meetRequirement) {
    466                 mCollector.addMessage(String.format(
    467                         "Camera %s list capability %s but does not meet the requirement: %s",
    468                         mCameraId, capabilityName, requirement));
    469             }
    470         }
    471 
    472         // In case of isCapabilityAvailable == true, error has been filed in
    473         // validateRequest/ResultKeysPresence
    474         if (!matchExpectation && !isCapabilityAvailable) {
    475             mCollector.addMessage(String.format(
    476                     "Camera %s doesn't list capability %s but meets all requirements",
    477                     mCameraId, capabilityName));
    478         }
    479     }
    480 
    481     private void validateRawCapability(boolean isCapabilityAvailable) {
    482         String capabilityName = "REQUEST_AVAILABLE_CAPABILITIES_RAW";
    483 
    484         Set<CaptureRequest.Key<?>> requestKeys = new HashSet<>();
    485         requestKeys.add(CaptureRequest.HOT_PIXEL_MODE);
    486         requestKeys.add(CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE);
    487 
    488         Set<CameraCharacteristics.Key<?>> characteristicsKeys = new HashSet<>();
    489         characteristicsKeys.add(HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES);
    490         characteristicsKeys.add(SENSOR_BLACK_LEVEL_PATTERN);
    491         characteristicsKeys.add(SENSOR_CALIBRATION_TRANSFORM1);
    492         characteristicsKeys.add(SENSOR_COLOR_TRANSFORM1);
    493         characteristicsKeys.add(SENSOR_FORWARD_MATRIX1);
    494         characteristicsKeys.add(SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    495         characteristicsKeys.add(SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
    496         characteristicsKeys.add(SENSOR_INFO_WHITE_LEVEL);
    497         characteristicsKeys.add(SENSOR_REFERENCE_ILLUMINANT1);
    498         characteristicsKeys.add(STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES);
    499 
    500         Set<CaptureResult.Key<?>> resultKeys = new HashSet<>();
    501         resultKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
    502         resultKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
    503         resultKeys.add(CaptureResult.SENSOR_NOISE_PROFILE);
    504 
    505         boolean rawOutputSupported = mStaticInfo.getRawOutputSizesChecked().length > 0;
    506         boolean requestKeysPresent = mStaticInfo.areRequestKeysAvailable(requestKeys);
    507         boolean characteristicsKeysPresent =
    508                 mStaticInfo.areCharacteristicsKeysAvailable(characteristicsKeys);
    509         boolean resultKeysPresent = mStaticInfo.areResultKeysAvailable(resultKeys);
    510         boolean expectCapabilityPresent = rawOutputSupported && requestKeysPresent &&
    511                 characteristicsKeysPresent && resultKeysPresent;
    512 
    513         if (isCapabilityAvailable != expectCapabilityPresent) {
    514             if (isCapabilityAvailable) {
    515                 mCollector.expectTrue(
    516                         "REQUEST_AVAILABLE_CAPABILITIES_RAW should support RAW_SENSOR output",
    517                         rawOutputSupported);
    518                 validateRequestKeysPresence(capabilityName, requestKeys, isCapabilityAvailable);
    519                 validateResultKeysPresence(capabilityName, resultKeys, isCapabilityAvailable);
    520                 validateCharacteristicsKeysPresence(capabilityName, characteristicsKeys,
    521                         isCapabilityAvailable);
    522             } else {
    523                 mCollector.addMessage(String.format(
    524                         "Camera %s doesn't list capability %s but contain all required keys" +
    525                         " and RAW format output",
    526                         mCameraId, capabilityName));
    527             }
    528         }
    529     }
    530 
    531     /**
    532      * Test lens facing.
    533      */
    534     public void testLensFacing() throws Exception {
    535         for (String id : mCameraIds) {
    536             initStaticMetadata(id);
    537             mStaticInfo.getLensFacingChecked();
    538         }
    539     }
    540 
    541     private float getFpsForMaxSize(String cameraId) throws Exception {
    542         HashMap<Size, Long> minFrameDurationMap =
    543                 mStaticInfo.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.YUV_420_888);
    544 
    545         Size[] sizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.YUV_420_888,
    546                 cameraId, mCameraManager);
    547         Size maxSize = CameraTestUtils.getMaxSize(sizes);
    548         Long minDuration = minFrameDurationMap.get(maxSize);
    549         if (VERBOSE) {
    550             Log.v(TAG, "min frame duration for size " + maxSize + " is " + minDuration);
    551         }
    552         assertTrue("min duration for max size must be postive number",
    553                 minDuration != null && minDuration > 0);
    554 
    555         return 1e9f / minDuration;
    556     }
    557 
    558     /**
    559      * Initialize static metadata for a given camera id.
    560      */
    561     private void initStaticMetadata(String cameraId) throws Exception {
    562         mCameraId = cameraId;
    563         mCollector.setCameraId(cameraId);
    564         mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
    565                 CheckLevel.COLLECT, /* collector */mCollector);
    566     }
    567 }
    568