Home | History | Annotate | Download | only in cts
      1 /*
      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 
     17 package android.hardware.camera2.cts;
     18 
     19 import static android.hardware.camera2.cts.CameraTestUtils.*;
     20 
     21 import android.content.Context;
     22 import android.graphics.ImageFormat;
     23 import android.graphics.SurfaceTexture;
     24 import android.hardware.camera2.CameraCaptureSession;
     25 import android.hardware.camera2.CameraCharacteristics;
     26 import android.hardware.camera2.CameraDevice;
     27 import android.hardware.camera2.CameraManager;
     28 import android.hardware.camera2.CaptureRequest;
     29 import android.hardware.camera2.CaptureResult;
     30 import android.hardware.camera2.TotalCaptureResult;
     31 import android.hardware.camera2.CaptureFailure;
     32 import android.hardware.camera2.cts.helpers.StaticMetadata;
     33 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
     34 import android.hardware.camera2.params.InputConfiguration;
     35 import android.hardware.camera2.params.OisSample;
     36 import android.hardware.camera2.params.OutputConfiguration;
     37 import android.hardware.camera2.params.MandatoryStreamCombination;
     38 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation;
     39 import android.hardware.camera2.params.SessionConfiguration;
     40 import android.hardware.camera2.params.StreamConfigurationMap;
     41 import android.media.Image;
     42 import android.media.ImageReader;
     43 import android.media.ImageWriter;
     44 import android.util.Log;
     45 import android.util.Size;
     46 import android.view.Surface;
     47 
     48 import com.android.ex.camera2.blocking.BlockingSessionCallback;
     49 
     50 import java.util.Arrays;
     51 import java.util.ArrayList;
     52 import java.util.Comparator;
     53 import java.util.List;
     54 import java.util.Map;
     55 import java.util.Set;
     56 
     57 import static junit.framework.Assert.assertTrue;
     58 import static org.mockito.Mockito.*;
     59 
     60 /**
     61  * Tests exercising edge cases in camera setup, configuration, and usage.
     62  */
     63 public class RobustnessTest extends Camera2AndroidTestCase {
     64     private static final String TAG = "RobustnessTest";
     65     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     66 
     67     private static final int CONFIGURE_TIMEOUT = 5000; //ms
     68     private static final int CAPTURE_TIMEOUT = 1000; //ms
     69 
     70     // For testTriggerInteractions
     71     private static final int PREVIEW_WARMUP_FRAMES = 60;
     72     private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100;
     73     private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps
     74     private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10;
     75 
     76     /**
     77      * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing
     78      * a dimension other than one of the supported output dimensions.  The buffers produced into
     79      * this surface are expected have the dimensions of the closest possible buffer size in the
     80      * available stream configurations for a surface with this format.
     81      */
     82     public void testBadSurfaceDimensions() throws Exception {
     83         for (String id : mCameraIds) {
     84             try {
     85                 Log.i(TAG, "Testing Camera " + id);
     86                 openDevice(id);
     87 
     88                 List<Size> testSizes = null;
     89                 int format = mStaticInfo.isColorOutputSupported() ?
     90                     ImageFormat.YUV_420_888 : ImageFormat.DEPTH16;
     91 
     92                 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager,
     93                         format, null);
     94 
     95                 // Find some size not supported by the camera
     96                 Size weirdSize = new Size(643, 577);
     97                 int count = 0;
     98                 while(testSizes.contains(weirdSize)) {
     99                     // Really, they can't all be supported...
    100                     weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
    101                     count++;
    102                     assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100);
    103                 }
    104 
    105                 // Setup imageReader with invalid dimension
    106                 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
    107                         weirdSize.getHeight(), format, 3);
    108 
    109                 // Setup ImageReaderListener
    110                 SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
    111                 imageReader.setOnImageAvailableListener(imageListener, mHandler);
    112 
    113                 Surface surface = imageReader.getSurface();
    114                 List<Surface> surfaces = new ArrayList<>();
    115                 surfaces.add(surface);
    116 
    117                 // Setup a capture request and listener
    118                 CaptureRequest.Builder request =
    119                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    120                 request.addTarget(surface);
    121 
    122                 // Check that correct session callback is hit.
    123                 CameraCaptureSession.StateCallback sessionListener =
    124                         mock(CameraCaptureSession.StateCallback.class);
    125                 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera,
    126                         surfaces, sessionListener, mHandler);
    127 
    128                 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
    129                         onConfigured(any(CameraCaptureSession.class));
    130                 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
    131                         onReady(any(CameraCaptureSession.class));
    132                 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
    133                 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
    134                 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
    135 
    136                 CameraCaptureSession.CaptureCallback captureListener =
    137                         mock(CameraCaptureSession.CaptureCallback.class);
    138                 session.capture(request.build(), captureListener, mHandler);
    139 
    140                 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
    141                         onCaptureCompleted(any(CameraCaptureSession.class),
    142                                 any(CaptureRequest.class), any(TotalCaptureResult.class));
    143                 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
    144                         any(CaptureRequest.class), any(CaptureFailure.class));
    145 
    146                 Image image = imageListener.getImage(CAPTURE_TIMEOUT);
    147                 int imageWidth = image.getWidth();
    148                 int imageHeight = image.getHeight();
    149                 Size actualSize = new Size(imageWidth, imageHeight);
    150 
    151                 assertTrue("Camera does not contain outputted image resolution " + actualSize,
    152                         testSizes.contains(actualSize));
    153                 imageReader.close();
    154             } finally {
    155                 closeDevice(id);
    156             }
    157         }
    158     }
    159 
    160     /**
    161      * Test for making sure the mandatory stream combinations work as expected.
    162      */
    163     public void testMandatoryOutputCombinations() throws Exception {
    164         for (String id : mCameraIds) {
    165             openDevice(id);
    166             MandatoryStreamCombination[] combinations =
    167                     mStaticInfo.getCharacteristics().get(
    168                             CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS);
    169             if (combinations == null) {
    170                 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test");
    171                 closeDevice(id);
    172                 continue;
    173             }
    174 
    175             try {
    176                 for (MandatoryStreamCombination combination : combinations) {
    177                     if (!combination.isReprocessable()) {
    178                         testMandatoryStreamCombination(id, mStaticInfo,
    179                                 null/*physicalCameraId*/, combination);
    180                     }
    181                 }
    182 
    183                 // Make sure mandatory stream combinations for each physical camera work
    184                 // as expected.
    185                 if (mStaticInfo.isLogicalMultiCamera()) {
    186                     Set<String> physicalCameraIds =
    187                             mStaticInfo.getCharacteristics().getPhysicalCameraIds();
    188                     for (String physicalId : physicalCameraIds) {
    189                         if (Arrays.asList(mCameraIds).contains(physicalId)) {
    190                             // If physicalId is advertised in camera ID list, do not need to test
    191                             // its stream combination through logical camera.
    192                             continue;
    193                         }
    194                         StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId);
    195                         MandatoryStreamCombination[] phyCombinations =
    196                                 physicalStaticInfo.getCharacteristics().get(
    197                                         CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS);
    198 
    199                         for (MandatoryStreamCombination combination : phyCombinations) {
    200                             if (!combination.isReprocessable()) {
    201                                 testMandatoryStreamCombination(id, physicalStaticInfo,
    202                                         physicalId, combination);
    203                             }
    204                         }
    205                     }
    206                 }
    207 
    208             } finally {
    209                 closeDevice(id);
    210             }
    211         }
    212     }
    213 
    214     private void setupConfigurationTargets(List<MandatoryStreamInformation> streamsInfo,
    215             List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
    216             List<ImageReader> yuvTargets, List<ImageReader> y8Targets,
    217             List<ImageReader> rawTargets, List<ImageReader> heicTargets,
    218             List<OutputConfiguration> outputConfigs,
    219             int numBuffers, boolean substituteY8, boolean substituteHeic,
    220             String overridePhysicalCameraId) {
    221 
    222         ImageDropperListener imageDropperListener = new ImageDropperListener();
    223 
    224         for (MandatoryStreamInformation streamInfo : streamsInfo) {
    225             if (streamInfo.isInput()) {
    226                 continue;
    227             }
    228             int format = streamInfo.getFormat();
    229             if (substituteY8 && (format == ImageFormat.YUV_420_888)) {
    230                 format = ImageFormat.Y8;
    231             } else if (substituteHeic && (format == ImageFormat.JPEG)) {
    232                 format = ImageFormat.HEIC;
    233             }
    234             Surface newSurface;
    235             Size[] availableSizes = new Size[streamInfo.getAvailableSizes().size()];
    236             availableSizes = streamInfo.getAvailableSizes().toArray(availableSizes);
    237             Size targetSize = CameraTestUtils.getMaxSize(availableSizes);
    238 
    239             switch (format) {
    240                 case ImageFormat.PRIVATE: {
    241                     SurfaceTexture target = new SurfaceTexture(/*random int*/1);
    242                     target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight());
    243                     OutputConfiguration config = new OutputConfiguration(new Surface(target));
    244                     if (overridePhysicalCameraId != null) {
    245                         config.setPhysicalCameraId(overridePhysicalCameraId);
    246                     }
    247                     outputConfigs.add(config);
    248                     privTargets.add(target);
    249                     break;
    250                 }
    251                 case ImageFormat.JPEG: {
    252                     ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
    253                             targetSize.getHeight(), format, numBuffers);
    254                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
    255                     OutputConfiguration config = new OutputConfiguration(target.getSurface());
    256                     if (overridePhysicalCameraId != null) {
    257                         config.setPhysicalCameraId(overridePhysicalCameraId);
    258                     }
    259                     outputConfigs.add(config);
    260                     jpegTargets.add(target);
    261                     break;
    262                 }
    263                 case ImageFormat.YUV_420_888: {
    264                     ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
    265                             targetSize.getHeight(), format, numBuffers);
    266                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
    267                     OutputConfiguration config = new OutputConfiguration(target.getSurface());
    268                     if (overridePhysicalCameraId != null) {
    269                         config.setPhysicalCameraId(overridePhysicalCameraId);
    270                     }
    271                     outputConfigs.add(config);
    272                     yuvTargets.add(target);
    273                     break;
    274                 }
    275                 case ImageFormat.Y8: {
    276                     ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
    277                             targetSize.getHeight(), format, numBuffers);
    278                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
    279                     OutputConfiguration config = new OutputConfiguration(target.getSurface());
    280                     if (overridePhysicalCameraId != null) {
    281                         config.setPhysicalCameraId(overridePhysicalCameraId);
    282                     }
    283                     outputConfigs.add(config);
    284                     y8Targets.add(target);
    285                     break;
    286                 }
    287                 case ImageFormat.RAW_SENSOR: {
    288                     // targetSize could be null in the logical camera case where only
    289                     // physical camera supports RAW stream.
    290                     if (targetSize != null) {
    291                         ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
    292                                 targetSize.getHeight(), format, numBuffers);
    293                         target.setOnImageAvailableListener(imageDropperListener, mHandler);
    294                         OutputConfiguration config =
    295                                 new OutputConfiguration(target.getSurface());
    296                         if (overridePhysicalCameraId != null) {
    297                             config.setPhysicalCameraId(overridePhysicalCameraId);
    298                         }
    299                         outputConfigs.add(config);
    300                         rawTargets.add(target);
    301                     }
    302                     break;
    303                 }
    304                 case ImageFormat.HEIC: {
    305                     ImageReader target = ImageReader.newInstance(targetSize.getWidth(),
    306                             targetSize.getHeight(), format, numBuffers);
    307                     target.setOnImageAvailableListener(imageDropperListener, mHandler);
    308                     OutputConfiguration config = new OutputConfiguration(target.getSurface());
    309                     if (overridePhysicalCameraId != null) {
    310                         config.setPhysicalCameraId(overridePhysicalCameraId);
    311                     }
    312                     outputConfigs.add(config);
    313                     heicTargets.add(target);
    314                     break;
    315                 }
    316                 default:
    317                     fail("Unknown output format " + format);
    318             }
    319         }
    320     }
    321 
    322     private void testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo,
    323             String physicalCameraId, MandatoryStreamCombination combination) throws Exception {
    324         // Check whether substituting YUV_888 format with Y8 format
    325         boolean substituteY8 = false;
    326         if (staticInfo.isMonochromeWithY8()) {
    327             List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
    328             for (MandatoryStreamInformation streamInfo : streamsInfo) {
    329                 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) {
    330                     substituteY8 = true;
    331                     break;
    332                 }
    333             }
    334         }
    335 
    336         // Check whether substituting JPEG format with HEIC format
    337         boolean substituteHeic = false;
    338         if (staticInfo.isHeicSupported()) {
    339             List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
    340             for (MandatoryStreamInformation streamInfo : streamsInfo) {
    341                 if (streamInfo.getFormat() == ImageFormat.JPEG) {
    342                     substituteHeic = true;
    343                     break;
    344                 }
    345             }
    346         }
    347 
    348         // Test camera output combination
    349         String log = "Testing mandatory stream combination: " + combination.getDescription() +
    350                 " on camera: " + cameraId;
    351         if (physicalCameraId != null) {
    352             log += ", physical sub-camera: " + physicalCameraId;
    353         }
    354         Log.i(TAG, log);
    355         testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination,
    356                 /*substituteY8*/false, /*substituteHeic*/false);
    357 
    358         if (substituteY8) {
    359             Log.i(TAG, log + " with Y8");
    360             testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination,
    361                     /*substituteY8*/true, /*substituteHeic*/false);
    362         }
    363 
    364         if (substituteHeic) {
    365             Log.i(TAG, log + " with HEIC");
    366             testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination,
    367                     /*substituteY8*/false, /*substituteHeic*/true);
    368         }
    369     }
    370 
    371     private void testMandatoryStreamCombination(String cameraId,
    372             StaticMetadata staticInfo, String physicalCameraId,
    373             MandatoryStreamCombination combination,
    374             boolean substituteY8, boolean substituteHeic) throws Exception {
    375 
    376         // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
    377         final int TIMEOUT_FOR_RESULT_MS = (staticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
    378         final int MIN_RESULT_COUNT = 3;
    379 
    380         // Set up outputs
    381         List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
    382         List<SurfaceTexture> privTargets = new ArrayList<SurfaceTexture>();
    383         List<ImageReader> jpegTargets = new ArrayList<ImageReader>();
    384         List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
    385         List<ImageReader> y8Targets = new ArrayList<ImageReader>();
    386         List<ImageReader> rawTargets = new ArrayList<ImageReader>();
    387         List<ImageReader> heicTargets = new ArrayList<ImageReader>();
    388 
    389         setupConfigurationTargets(combination.getStreamsInformation(), privTargets, jpegTargets,
    390                 yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs, MIN_RESULT_COUNT,
    391                 substituteY8, substituteHeic, physicalCameraId);
    392 
    393         boolean haveSession = false;
    394         try {
    395             CaptureRequest.Builder requestBuilder =
    396                     mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    397 
    398             for (OutputConfiguration c : outputConfigs) {
    399                 requestBuilder.addTarget(c.getSurface());
    400             }
    401 
    402             CameraCaptureSession.CaptureCallback mockCaptureCallback =
    403                     mock(CameraCaptureSession.CaptureCallback.class);
    404 
    405             if (physicalCameraId == null) {
    406                 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs,
    407                         /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR,
    408                         true/*defaultSupport*/, String.format(
    409                         "Session configuration query from combination: %s failed",
    410                         combination.getDescription()));
    411             } else {
    412                 SessionConfigSupport sessionConfigSupport = isSessionConfigSupported(
    413                         mCamera, mHandler, outputConfigs, /*inputConfig*/ null,
    414                         SessionConfiguration.SESSION_REGULAR, false/*defaultSupport*/);
    415                 assertTrue(
    416                         String.format("Session configuration query from combination: %s failed",
    417                         combination.getDescription()), !sessionConfigSupport.error);
    418                 if (!sessionConfigSupport.callSupported) {
    419                     return;
    420                 }
    421                 assertTrue(
    422                         String.format("Session configuration must be supported for combination: " +
    423                         "%s", combination.getDescription()), sessionConfigSupport.configSupported);
    424             }
    425 
    426             createSessionByConfigs(outputConfigs);
    427             haveSession = true;
    428             CaptureRequest request = requestBuilder.build();
    429             mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler);
    430 
    431             verify(mockCaptureCallback,
    432                     timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT))
    433                     .onCaptureCompleted(
    434                         eq(mCameraSession),
    435                         eq(request),
    436                         isA(TotalCaptureResult.class));
    437             verify(mockCaptureCallback, never()).
    438                     onCaptureFailed(
    439                         eq(mCameraSession),
    440                         eq(request),
    441                         isA(CaptureFailure.class));
    442 
    443         } catch (Throwable e) {
    444             mCollector.addMessage(String.format("Mandatory stream combination: %s failed due: %s",
    445                     combination.getDescription(), e.getMessage()));
    446         }
    447         if (haveSession) {
    448             try {
    449                 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session",
    450                                 cameraId, combination.getDescription()));
    451                 stopCapture(/*fast*/false);
    452             } catch (Throwable e) {
    453                 mCollector.addMessage(
    454                     String.format("Closing down for combination: %s failed due to: %s",
    455                             combination.getDescription(), e.getMessage()));
    456             }
    457         }
    458 
    459         for (SurfaceTexture target : privTargets) {
    460             target.release();
    461         }
    462         for (ImageReader target : jpegTargets) {
    463             target.close();
    464         }
    465         for (ImageReader target : yuvTargets) {
    466             target.close();
    467         }
    468         for (ImageReader target : y8Targets) {
    469             target.close();
    470         }
    471         for (ImageReader target : rawTargets) {
    472             target.close();
    473         }
    474         for (ImageReader target : heicTargets) {
    475             target.close();
    476         }
    477     }
    478 
    479     /**
    480      * Test for making sure the required reprocess input/output combinations for each hardware
    481      * level and capability work as expected.
    482      */
    483     public void testMandatoryReprocessConfigurations() throws Exception {
    484         for (String id : mCameraIds) {
    485             openDevice(id);
    486             MandatoryStreamCombination[] combinations =
    487                     mStaticInfo.getCharacteristics().get(
    488                             CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS);
    489             if (combinations == null) {
    490                 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test");
    491                 closeDevice(id);
    492                 continue;
    493             }
    494 
    495             try {
    496                 for (MandatoryStreamCombination combination : combinations) {
    497                     if (combination.isReprocessable()) {
    498                         Log.i(TAG, "Testing mandatory reprocessable stream combination: " +
    499                                 combination.getDescription() + " on camera: " + id);
    500                         testMandatoryReprocessableStreamCombination(id, combination);
    501                     }
    502                 }
    503             } finally {
    504                 closeDevice(id);
    505             }
    506         }
    507     }
    508 
    509     private void testMandatoryReprocessableStreamCombination(String cameraId,
    510             MandatoryStreamCombination combination) {
    511         // Test reprocess stream combination
    512         testMandatoryReprocessableStreamCombination(cameraId, combination,
    513                 /*substituteY8*/false, /*substituteHeic*/false);
    514 
    515         // Test substituting YUV_888 format with Y8 format in reprocess stream combination.
    516         if (mStaticInfo.isMonochromeWithY8()) {
    517             List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
    518             boolean substituteY8 = false;
    519             for (MandatoryStreamInformation streamInfo : streamsInfo) {
    520                 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) {
    521                     substituteY8 = true;
    522                 }
    523             }
    524             if (substituteY8) {
    525                 testMandatoryReprocessableStreamCombination(cameraId, combination,
    526                         /*substituteY8*/true, /*substituteHeic*/false);
    527             }
    528         }
    529 
    530         if (mStaticInfo.isHeicSupported()) {
    531             List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation();
    532             boolean substituteHeic = false;
    533             for (MandatoryStreamInformation streamInfo : streamsInfo) {
    534                 if (streamInfo.getFormat() == ImageFormat.JPEG) {
    535                     substituteHeic = true;
    536                 }
    537             }
    538             if (substituteHeic) {
    539                 testMandatoryReprocessableStreamCombination(cameraId, combination,
    540                         /*substituteY8*/false, /*substituteHeic*/true);
    541             }
    542         }
    543     }
    544 
    545     private void testMandatoryReprocessableStreamCombination(String cameraId,
    546             MandatoryStreamCombination combination, boolean substituteY8,
    547             boolean substituteHeic) {
    548 
    549         final int TIMEOUT_FOR_RESULT_MS = 3000;
    550         final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3;
    551 
    552         List<SurfaceTexture> privTargets = new ArrayList<>();
    553         List<ImageReader> jpegTargets = new ArrayList<>();
    554         List<ImageReader> yuvTargets = new ArrayList<>();
    555         List<ImageReader> y8Targets = new ArrayList<>();
    556         List<ImageReader> rawTargets = new ArrayList<>();
    557         List<ImageReader> heicTargets = new ArrayList<>();
    558         ArrayList<Surface> outputSurfaces = new ArrayList<>();
    559         List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>();
    560         ImageReader inputReader = null;
    561         ImageWriter inputWriter = null;
    562         SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener();
    563         SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback();
    564         SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback();
    565 
    566         List<MandatoryStreamInformation> streamInfo = combination.getStreamsInformation();
    567         assertTrue("Reprocessable stream combinations should have at least 3 or more streams",
    568                     (streamInfo != null) && (streamInfo.size() >= 3));
    569 
    570         assertTrue("The first mandatory stream information in a reprocessable combination must " +
    571                 "always be input", streamInfo.get(0).isInput());
    572 
    573         List<Size> inputSizes = streamInfo.get(0).getAvailableSizes();
    574         int inputFormat = streamInfo.get(0).getFormat();
    575         if (substituteY8 && (inputFormat == ImageFormat.YUV_420_888)) {
    576             inputFormat = ImageFormat.Y8;
    577         }
    578 
    579         Log.i(TAG, "testMandatoryReprocessableStreamCombination: " +
    580                 combination.getDescription() + ", substituteY8 = " + substituteY8 +
    581                 ", substituteHeic = " + substituteHeic);
    582         try {
    583             // The second stream information entry is the ZSL stream, which is configured
    584             // separately.
    585             setupConfigurationTargets(streamInfo.subList(2, streamInfo.size()), privTargets,
    586                     jpegTargets, yuvTargets, y8Targets, rawTargets, heicTargets, outputConfigs,
    587                     NUM_REPROCESS_CAPTURES_PER_CONFIG, substituteY8,  substituteHeic,
    588                     null/*overridePhysicalCameraId*/);
    589 
    590             outputSurfaces.ensureCapacity(outputConfigs.size());
    591             for (OutputConfiguration config : outputConfigs) {
    592                 outputSurfaces.add(config.getSurface());
    593             }
    594 
    595             InputConfiguration inputConfig = new InputConfiguration(inputSizes.get(0).getWidth(),
    596                     inputSizes.get(0).getHeight(), inputFormat);
    597 
    598             // For each config, YUV and JPEG outputs will be tested. (For YUV/Y8 reprocessing,
    599             // the YUV/Y8 ImageReader for input is also used for output.)
    600             final boolean inputIsYuv = inputConfig.getFormat() == ImageFormat.YUV_420_888;
    601             final boolean inputIsY8 = inputConfig.getFormat() == ImageFormat.Y8;
    602             final boolean useYuv = inputIsYuv || yuvTargets.size() > 0;
    603             final boolean useY8 = inputIsY8 || y8Targets.size() > 0;
    604             final int totalNumReprocessCaptures =  NUM_REPROCESS_CAPTURES_PER_CONFIG * (
    605                     ((inputIsYuv || inputIsY8) ? 1 : 0) +
    606                     (substituteHeic ? heicTargets.size() : jpegTargets.size()) +
    607                     (useYuv ? yuvTargets.size() : y8Targets.size()));
    608 
    609             // It needs 1 input buffer for each reprocess capture + the number of buffers
    610             // that will be used as outputs.
    611             inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(),
    612                     inputConfig.getFormat(),
    613                     totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG);
    614             inputReader.setOnImageAvailableListener(inputReaderListener, mHandler);
    615             outputSurfaces.add(inputReader.getSurface());
    616 
    617             checkSessionConfigurationWithSurfaces(mCamera, mHandler, outputSurfaces,
    618                     inputConfig, SessionConfiguration.SESSION_REGULAR, /*defaultSupport*/ true,
    619                     String.format("Session configuration query %s failed",
    620                     combination.getDescription()));
    621 
    622             // Verify we can create a reprocessable session with the input and all outputs.
    623             BlockingSessionCallback sessionListener = new BlockingSessionCallback();
    624             CameraCaptureSession session = configureReprocessableCameraSession(mCamera,
    625                     inputConfig, outputSurfaces, sessionListener, mHandler);
    626             inputWriter = ImageWriter.newInstance(session.getInputSurface(),
    627                     totalNumReprocessCaptures);
    628 
    629             // Prepare a request for reprocess input
    630             CaptureRequest.Builder builder = mCamera.createCaptureRequest(
    631                     CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
    632             builder.addTarget(inputReader.getSurface());
    633 
    634             for (int i = 0; i < totalNumReprocessCaptures; i++) {
    635                 session.capture(builder.build(), inputCaptureListener, mHandler);
    636             }
    637 
    638             List<CaptureRequest> reprocessRequests = new ArrayList<>();
    639             List<Surface> reprocessOutputs = new ArrayList<>();
    640             if (inputIsYuv || inputIsY8) {
    641                 reprocessOutputs.add(inputReader.getSurface());
    642             }
    643 
    644             for (ImageReader reader : jpegTargets) {
    645                 reprocessOutputs.add(reader.getSurface());
    646             }
    647 
    648             for (ImageReader reader : heicTargets) {
    649                 reprocessOutputs.add(reader.getSurface());
    650             }
    651 
    652             for (ImageReader reader : yuvTargets) {
    653                 reprocessOutputs.add(reader.getSurface());
    654             }
    655 
    656             for (ImageReader reader : y8Targets) {
    657                 reprocessOutputs.add(reader.getSurface());
    658             }
    659 
    660             for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
    661                 for (Surface output : reprocessOutputs) {
    662                     TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult(
    663                             TIMEOUT_FOR_RESULT_MS);
    664                     builder =  mCamera.createReprocessCaptureRequest(result);
    665                     inputWriter.queueInputImage(
    666                             inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS));
    667                     builder.addTarget(output);
    668                     reprocessRequests.add(builder.build());
    669                 }
    670             }
    671 
    672             session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler);
    673 
    674             for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
    675                 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult(
    676                         TIMEOUT_FOR_RESULT_MS);
    677             }
    678         } catch (Throwable e) {
    679             mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s",
    680                     combination.getDescription(), e.getMessage()));
    681         } finally {
    682             inputReaderListener.drain();
    683             reprocessOutputCaptureListener.drain();
    684 
    685             for (SurfaceTexture target : privTargets) {
    686                 target.release();
    687             }
    688 
    689             for (ImageReader target : jpegTargets) {
    690                 target.close();
    691             }
    692 
    693             for (ImageReader target : yuvTargets) {
    694                 target.close();
    695             }
    696 
    697             for (ImageReader target : y8Targets) {
    698                 target.close();
    699             }
    700 
    701             for (ImageReader target : rawTargets) {
    702                 target.close();
    703             }
    704 
    705             for (ImageReader target : heicTargets) {
    706                 target.close();
    707             }
    708 
    709             if (inputReader != null) {
    710                 inputReader.close();
    711             }
    712 
    713             if (inputWriter != null) {
    714                 inputWriter.close();
    715             }
    716         }
    717     }
    718 
    719     public void testBasicTriggerSequence() throws Exception {
    720 
    721         for (String id : mCameraIds) {
    722             Log.i(TAG, String.format("Testing Camera %s", id));
    723 
    724             try {
    725                 // Legacy devices do not support precapture trigger; don't test devices that
    726                 // can't focus
    727                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
    728                 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) {
    729                     continue;
    730                 }
    731                 // Depth-only devices won't support AE
    732                 if (!staticInfo.isColorOutputSupported()) {
    733                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
    734                     continue;
    735                 }
    736 
    737                 openDevice(id);
    738                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
    739                 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked();
    740 
    741                 for (int afMode : availableAfModes) {
    742                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
    743                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
    744                         // Only test AF modes that have meaningful trigger behavior
    745                         continue;
    746                     }
    747 
    748                     for (int aeMode : availableAeModes) {
    749                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
    750                             // Only test AE modes that have meaningful trigger behavior
    751                             continue;
    752                         }
    753 
    754                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
    755 
    756                         CaptureRequest.Builder previewRequest =
    757                                 prepareTriggerTestSession(preview, aeMode, afMode);
    758 
    759                         SimpleCaptureCallback captureListener =
    760                                 new CameraTestUtils.SimpleCaptureCallback();
    761 
    762                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
    763                                 mHandler);
    764 
    765                         // Cancel triggers
    766 
    767                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
    768 
    769                         //
    770                         // Standard sequence - AF trigger then AE trigger
    771 
    772                         if (VERBOSE) {
    773                             Log.v(TAG, String.format("Triggering AF"));
    774                         }
    775 
    776                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
    777                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
    778                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
    779                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
    780 
    781                         CaptureRequest triggerRequest = previewRequest.build();
    782                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
    783 
    784                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
    785                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
    786                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
    787                         boolean focusComplete = false;
    788 
    789                         for (int i = 0;
    790                              i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete;
    791                              i++) {
    792 
    793                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
    794 
    795                             CaptureResult focusResult = captureListener.getCaptureResult(
    796                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
    797                             afState = focusResult.get(CaptureResult.CONTROL_AF_STATE);
    798                         }
    799 
    800                         assertTrue("Focusing never completed!", focusComplete);
    801 
    802                         // Standard sequence - Part 2 AE trigger
    803 
    804                         if (VERBOSE) {
    805                             Log.v(TAG, String.format("Triggering AE"));
    806                         }
    807 
    808                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
    809                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    810                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
    811                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
    812 
    813                         triggerRequest = previewRequest.build();
    814                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
    815 
    816                         triggerResult = captureListener.getCaptureResultForRequest(
    817                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
    818 
    819                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
    820 
    821                         boolean precaptureComplete = false;
    822 
    823                         for (int i = 0;
    824                              i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete;
    825                              i++) {
    826 
    827                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
    828 
    829                             CaptureResult precaptureResult = captureListener.getCaptureResult(
    830                                 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
    831                             aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE);
    832                         }
    833 
    834                         assertTrue("Precapture sequence never completed!", precaptureComplete);
    835 
    836                         for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) {
    837                             CaptureResult postPrecaptureResult = captureListener.getCaptureResult(
    838                                 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
    839                             aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE);
    840                             assertTrue("Late transition to PRECAPTURE state seen",
    841                                     aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
    842                         }
    843 
    844                         // Done
    845 
    846                         stopCapture(/*fast*/ false);
    847                         preview.release();
    848                     }
    849 
    850                 }
    851 
    852             } finally {
    853                 closeDevice(id);
    854             }
    855         }
    856 
    857     }
    858 
    859     public void testSimultaneousTriggers() throws Exception {
    860         for (String id : mCameraIds) {
    861             Log.i(TAG, String.format("Testing Camera %s", id));
    862 
    863             try {
    864                 // Legacy devices do not support precapture trigger; don't test devices that
    865                 // can't focus
    866                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
    867                 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) {
    868                     continue;
    869                 }
    870                 // Depth-only devices won't support AE
    871                 if (!staticInfo.isColorOutputSupported()) {
    872                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
    873                     continue;
    874                 }
    875 
    876                 openDevice(id);
    877                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
    878                 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked();
    879 
    880                 for (int afMode : availableAfModes) {
    881                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
    882                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
    883                         // Only test AF modes that have meaningful trigger behavior
    884                         continue;
    885                     }
    886 
    887                     for (int aeMode : availableAeModes) {
    888                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
    889                             // Only test AE modes that have meaningful trigger behavior
    890                             continue;
    891                         }
    892 
    893                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
    894 
    895                         CaptureRequest.Builder previewRequest =
    896                                 prepareTriggerTestSession(preview, aeMode, afMode);
    897 
    898                         SimpleCaptureCallback captureListener =
    899                                 new CameraTestUtils.SimpleCaptureCallback();
    900 
    901                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
    902                                 mHandler);
    903 
    904                         // Cancel triggers
    905 
    906                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
    907 
    908                         //
    909                         // Trigger AF and AE together
    910 
    911                         if (VERBOSE) {
    912                             Log.v(TAG, String.format("Triggering AF and AE together"));
    913                         }
    914 
    915                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
    916                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
    917                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
    918                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
    919 
    920                         CaptureRequest triggerRequest = previewRequest.build();
    921                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
    922 
    923                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
    924                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
    925                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
    926                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
    927 
    928                         boolean precaptureComplete = false;
    929                         boolean focusComplete = false;
    930 
    931                         for (int i = 0;
    932                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
    933                                      !(focusComplete && precaptureComplete);
    934                              i++) {
    935 
    936                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
    937                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
    938 
    939                             CaptureResult sequenceResult = captureListener.getCaptureResult(
    940                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
    941                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
    942                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
    943                         }
    944 
    945                         assertTrue("Precapture sequence never completed!", precaptureComplete);
    946                         assertTrue("Focus sequence never completed!", focusComplete);
    947 
    948                         // Done
    949 
    950                         stopCapture(/*fast*/ false);
    951                         preview.release();
    952 
    953                     }
    954                 }
    955             } finally {
    956                 closeDevice(id);
    957             }
    958         }
    959     }
    960 
    961     public void testAfThenAeTrigger() throws Exception {
    962         for (String id : mCameraIds) {
    963             Log.i(TAG, String.format("Testing Camera %s", id));
    964 
    965             try {
    966                 // Legacy devices do not support precapture trigger; don't test devices that
    967                 // can't focus
    968                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
    969                 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) {
    970                     continue;
    971                 }
    972                 // Depth-only devices won't support AE
    973                 if (!staticInfo.isColorOutputSupported()) {
    974                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
    975                     continue;
    976                 }
    977 
    978                 openDevice(id);
    979                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
    980                 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked();
    981 
    982                 for (int afMode : availableAfModes) {
    983                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
    984                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
    985                         // Only test AF modes that have meaningful trigger behavior
    986                         continue;
    987                     }
    988 
    989                     for (int aeMode : availableAeModes) {
    990                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
    991                             // Only test AE modes that have meaningful trigger behavior
    992                             continue;
    993                         }
    994 
    995                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
    996 
    997                         CaptureRequest.Builder previewRequest =
    998                                 prepareTriggerTestSession(preview, aeMode, afMode);
    999 
   1000                         SimpleCaptureCallback captureListener =
   1001                                 new CameraTestUtils.SimpleCaptureCallback();
   1002 
   1003                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
   1004                                 mHandler);
   1005 
   1006                         // Cancel triggers
   1007 
   1008                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
   1009 
   1010                         //
   1011                         // AF with AE a request later
   1012 
   1013                         if (VERBOSE) {
   1014                             Log.v(TAG, "Trigger AF, then AE trigger on next request");
   1015                         }
   1016 
   1017                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1018                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
   1019                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1020                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
   1021 
   1022                         CaptureRequest triggerRequest = previewRequest.build();
   1023                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
   1024 
   1025                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1026                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
   1027                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1028                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
   1029 
   1030                         CaptureRequest triggerRequest2 = previewRequest.build();
   1031                         mCameraSession.capture(triggerRequest2, captureListener, mHandler);
   1032 
   1033                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
   1034                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1035                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
   1036 
   1037                         boolean precaptureComplete = false;
   1038                         boolean focusComplete = false;
   1039 
   1040                         focusComplete = verifyAfSequence(afMode, afState, focusComplete);
   1041 
   1042                         triggerResult = captureListener.getCaptureResultForRequest(
   1043                                 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1044                         afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
   1045                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
   1046 
   1047                         for (int i = 0;
   1048                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
   1049                                      !(focusComplete && precaptureComplete);
   1050                              i++) {
   1051 
   1052                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
   1053                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
   1054 
   1055                             CaptureResult sequenceResult = captureListener.getCaptureResult(
   1056                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
   1057                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
   1058                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
   1059                         }
   1060 
   1061                         assertTrue("Precapture sequence never completed!", precaptureComplete);
   1062                         assertTrue("Focus sequence never completed!", focusComplete);
   1063 
   1064                         // Done
   1065 
   1066                         stopCapture(/*fast*/ false);
   1067                         preview.release();
   1068 
   1069                     }
   1070                 }
   1071             } finally {
   1072                 closeDevice(id);
   1073             }
   1074         }
   1075     }
   1076 
   1077     public void testAeThenAfTrigger() throws Exception {
   1078         for (String id : mCameraIds) {
   1079             Log.i(TAG, String.format("Testing Camera %s", id));
   1080 
   1081             try {
   1082                 // Legacy devices do not support precapture trigger; don't test devices that
   1083                 // can't focus
   1084                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
   1085                 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) {
   1086                     continue;
   1087                 }
   1088                 // Depth-only devices won't support AE
   1089                 if (!staticInfo.isColorOutputSupported()) {
   1090                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
   1091                     continue;
   1092                 }
   1093 
   1094                 openDevice(id);
   1095                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
   1096                 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked();
   1097 
   1098                 for (int afMode : availableAfModes) {
   1099                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
   1100                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
   1101                         // Only test AF modes that have meaningful trigger behavior
   1102                         continue;
   1103                     }
   1104 
   1105                     for (int aeMode : availableAeModes) {
   1106                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
   1107                             // Only test AE modes that have meaningful trigger behavior
   1108                             continue;
   1109                         }
   1110 
   1111                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1112 
   1113                         CaptureRequest.Builder previewRequest =
   1114                                 prepareTriggerTestSession(preview, aeMode, afMode);
   1115 
   1116                         SimpleCaptureCallback captureListener =
   1117                                 new CameraTestUtils.SimpleCaptureCallback();
   1118 
   1119                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
   1120                                 mHandler);
   1121 
   1122                         // Cancel triggers
   1123 
   1124                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
   1125 
   1126                         //
   1127                         // AE with AF a request later
   1128 
   1129                         if (VERBOSE) {
   1130                             Log.v(TAG, "Trigger AE, then AF trigger on next request");
   1131                         }
   1132 
   1133                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1134                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
   1135                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1136                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
   1137 
   1138                         CaptureRequest triggerRequest = previewRequest.build();
   1139                         mCameraSession.capture(triggerRequest, captureListener, mHandler);
   1140 
   1141                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1142                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
   1143                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1144                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
   1145 
   1146                         CaptureRequest triggerRequest2 = previewRequest.build();
   1147                         mCameraSession.capture(triggerRequest2, captureListener, mHandler);
   1148 
   1149                         CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
   1150                                 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1151                         int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
   1152 
   1153                         boolean precaptureComplete = false;
   1154                         boolean focusComplete = false;
   1155 
   1156                         precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
   1157 
   1158                         triggerResult = captureListener.getCaptureResultForRequest(
   1159                                 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1160                         int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
   1161                         aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
   1162 
   1163                         for (int i = 0;
   1164                              i < MAX_TRIGGER_SEQUENCE_FRAMES &&
   1165                                      !(focusComplete && precaptureComplete);
   1166                              i++) {
   1167 
   1168                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
   1169                             precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
   1170 
   1171                             CaptureResult sequenceResult = captureListener.getCaptureResult(
   1172                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
   1173                             afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
   1174                             aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
   1175                         }
   1176 
   1177                         assertTrue("Precapture sequence never completed!", precaptureComplete);
   1178                         assertTrue("Focus sequence never completed!", focusComplete);
   1179 
   1180                         // Done
   1181 
   1182                         stopCapture(/*fast*/ false);
   1183                         preview.release();
   1184 
   1185                     }
   1186                 }
   1187             } finally {
   1188                 closeDevice(id);
   1189             }
   1190         }
   1191     }
   1192 
   1193     public void testAeAndAfCausality() throws Exception {
   1194 
   1195         for (String id : mCameraIds) {
   1196             Log.i(TAG, String.format("Testing Camera %s", id));
   1197 
   1198             try {
   1199                 // Legacy devices do not support precapture trigger; don't test devices that
   1200                 // can't focus
   1201                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
   1202                 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) {
   1203                     continue;
   1204                 }
   1205                 // Depth-only devices won't support AE
   1206                 if (!staticInfo.isColorOutputSupported()) {
   1207                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
   1208                     continue;
   1209                 }
   1210 
   1211                 openDevice(id);
   1212                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
   1213                 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked();
   1214                 final int maxPipelineDepth = mStaticInfo.getCharacteristics().get(
   1215                         CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH);
   1216 
   1217                 for (int afMode : availableAfModes) {
   1218                     if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
   1219                             afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
   1220                         // Only test AF modes that have meaningful trigger behavior
   1221                         continue;
   1222                     }
   1223                     for (int aeMode : availableAeModes) {
   1224                         if (aeMode ==  CameraCharacteristics.CONTROL_AE_MODE_OFF) {
   1225                             // Only test AE modes that have meaningful trigger behavior
   1226                             continue;
   1227                         }
   1228 
   1229                         SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1230 
   1231                         CaptureRequest.Builder previewRequest =
   1232                                 prepareTriggerTestSession(preview, aeMode, afMode);
   1233 
   1234                         SimpleCaptureCallback captureListener =
   1235                                 new CameraTestUtils.SimpleCaptureCallback();
   1236 
   1237                         mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
   1238                                 mHandler);
   1239 
   1240                         List<CaptureRequest> triggerRequests =
   1241                                 new ArrayList<CaptureRequest>(maxPipelineDepth+1);
   1242                         for (int i = 0; i < maxPipelineDepth; i++) {
   1243                             triggerRequests.add(previewRequest.build());
   1244                         }
   1245 
   1246                         // Cancel triggers
   1247                         cancelTriggersAndWait(previewRequest, captureListener, afMode);
   1248 
   1249                         //
   1250                         // Standard sequence - Part 1 AF trigger
   1251 
   1252                         if (VERBOSE) {
   1253                             Log.v(TAG, String.format("Triggering AF"));
   1254                         }
   1255 
   1256                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1257                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
   1258                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1259                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
   1260                         triggerRequests.add(previewRequest.build());
   1261 
   1262                         mCameraSession.captureBurst(triggerRequests, captureListener, mHandler);
   1263 
   1264                         TotalCaptureResult[] triggerResults =
   1265                                 captureListener.getTotalCaptureResultsForRequests(
   1266                                 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1267                         for (int i = 0; i < maxPipelineDepth; i++) {
   1268                             TotalCaptureResult triggerResult = triggerResults[i];
   1269                             int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
   1270                             int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER);
   1271 
   1272                             verifyStartingAfState(afMode, afState);
   1273                             assertTrue(String.format("In AF mode %s, previous AF_TRIGGER must not "
   1274                                     + "be START before TRIGGER_START",
   1275                                     StaticMetadata.getAfModeName(afMode)),
   1276                                     afTrigger != CaptureResult.CONTROL_AF_TRIGGER_START);
   1277                         }
   1278 
   1279                         int afState =
   1280                                 triggerResults[maxPipelineDepth].get(CaptureResult.CONTROL_AF_STATE);
   1281                         boolean focusComplete = false;
   1282                         for (int i = 0;
   1283                              i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete;
   1284                              i++) {
   1285 
   1286                             focusComplete = verifyAfSequence(afMode, afState, focusComplete);
   1287 
   1288                             CaptureResult focusResult = captureListener.getCaptureResult(
   1289                                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
   1290                             afState = focusResult.get(CaptureResult.CONTROL_AF_STATE);
   1291                         }
   1292 
   1293                         assertTrue("Focusing never completed!", focusComplete);
   1294 
   1295                         // Standard sequence - Part 2 AE trigger
   1296 
   1297                         if (VERBOSE) {
   1298                             Log.v(TAG, String.format("Triggering AE"));
   1299                         }
   1300                         // Remove AF trigger request
   1301                         triggerRequests.remove(maxPipelineDepth);
   1302 
   1303                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1304                                 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
   1305                         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1306                                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
   1307                         triggerRequests.add(previewRequest.build());
   1308 
   1309                         mCameraSession.captureBurst(triggerRequests, captureListener, mHandler);
   1310 
   1311                         triggerResults = captureListener.getTotalCaptureResultsForRequests(
   1312                                 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1313 
   1314                         for (int i = 0; i < maxPipelineDepth; i++) {
   1315                             TotalCaptureResult triggerResult = triggerResults[i];
   1316                             int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
   1317                             int aeTrigger = triggerResult.get(
   1318                                     CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
   1319 
   1320                             assertTrue(String.format("In AE mode %s, previous AE_TRIGGER must not "
   1321                                     + "be START before TRIGGER_START",
   1322                                     StaticMetadata.getAeModeName(aeMode)),
   1323                                     aeTrigger != CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_START);
   1324                             assertTrue(String.format("In AE mode %s, previous AE_STATE must not be"
   1325                                     + " PRECAPTURE_TRIGGER before TRIGGER_START",
   1326                                     StaticMetadata.getAeModeName(aeMode)),
   1327                                     aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
   1328                         }
   1329 
   1330                         // Stand sequence - Part 3 Cancel AF trigger
   1331                         if (VERBOSE) {
   1332                             Log.v(TAG, String.format("Cancel AF trigger"));
   1333                         }
   1334                         // Remove AE trigger request
   1335                         triggerRequests.remove(maxPipelineDepth);
   1336                         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1337                                 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
   1338                         triggerRequests.add(previewRequest.build());
   1339 
   1340                         mCameraSession.captureBurst(triggerRequests, captureListener, mHandler);
   1341                         triggerResults = captureListener.getTotalCaptureResultsForRequests(
   1342                                 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
   1343                         for (int i = 0; i < maxPipelineDepth; i++) {
   1344                             TotalCaptureResult triggerResult = triggerResults[i];
   1345                             afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
   1346                             int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER);
   1347 
   1348                             assertTrue(
   1349                                     String.format("In AF mode %s, previous AF_TRIGGER must not " +
   1350                                     "be CANCEL before TRIGGER_CANCEL",
   1351                                     StaticMetadata.getAfModeName(afMode)),
   1352                                     afTrigger != CaptureResult.CONTROL_AF_TRIGGER_CANCEL);
   1353                             assertTrue(
   1354                                     String.format("In AF mode %s, previous AF_STATE must be LOCKED"
   1355                                     + " before CANCEL, but is %s",
   1356                                     StaticMetadata.getAfModeName(afMode),
   1357                                     StaticMetadata.AF_STATE_NAMES[afState]),
   1358                                     afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
   1359                                     afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
   1360                         }
   1361 
   1362                         stopCapture(/*fast*/ false);
   1363                         preview.release();
   1364                     }
   1365 
   1366                 }
   1367 
   1368             } finally {
   1369                 closeDevice(id);
   1370             }
   1371         }
   1372 
   1373     }
   1374 
   1375     public void testAbandonRepeatingRequestSurface() throws Exception {
   1376         for (String id : mCameraIds) {
   1377             Log.i(TAG, String.format(
   1378                     "Testing Camera %s for abandoning surface of a repeating request", id));
   1379 
   1380             StaticMetadata staticInfo = mAllStaticInfo.get(id);
   1381             if (!staticInfo.isColorOutputSupported()) {
   1382                 Log.i(TAG, "Camera " + id + " does not support color output, skipping");
   1383                 continue;
   1384             }
   1385 
   1386             openDevice(id);
   1387 
   1388             try {
   1389 
   1390                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1391                 Surface previewSurface = new Surface(preview);
   1392 
   1393                 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
   1394                 SimpleCaptureCallback captureListener = new CameraTestUtils.SimpleCaptureCallback();
   1395 
   1396                 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(),
   1397                         captureListener, mHandler);
   1398 
   1399                 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) {
   1400                     captureListener.getTotalCaptureResult(CAPTURE_TIMEOUT);
   1401                 }
   1402 
   1403                 // Abandon preview surface.
   1404                 preview.release();
   1405 
   1406                 // Check onCaptureSequenceCompleted is received.
   1407                 long sequenceLastFrameNumber = captureListener.getCaptureSequenceLastFrameNumber(
   1408                         sequenceId, CAPTURE_TIMEOUT);
   1409 
   1410                 mCameraSession.stopRepeating();
   1411 
   1412                 // Find the last frame number received in results and failures.
   1413                 long lastFrameNumber = -1;
   1414                 while (captureListener.hasMoreResults()) {
   1415                     TotalCaptureResult result = captureListener.getTotalCaptureResult(
   1416                             CAPTURE_TIMEOUT);
   1417                     if (lastFrameNumber < result.getFrameNumber()) {
   1418                         lastFrameNumber = result.getFrameNumber();
   1419                     }
   1420                 }
   1421 
   1422                 while (captureListener.hasMoreFailures()) {
   1423                     ArrayList<CaptureFailure> failures = captureListener.getCaptureFailures(
   1424                             /*maxNumFailures*/ 1);
   1425                     for (CaptureFailure failure : failures) {
   1426                         if (lastFrameNumber < failure.getFrameNumber()) {
   1427                             lastFrameNumber = failure.getFrameNumber();
   1428                         }
   1429                     }
   1430                 }
   1431 
   1432                 // Verify the last frame number received from capture sequence completed matches the
   1433                 // the last frame number of the results and failures.
   1434                 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " +
   1435                         "(%d) doesn't match the last frame number received from " +
   1436                         "results/failures (%d)", sequenceLastFrameNumber, lastFrameNumber),
   1437                         sequenceLastFrameNumber, lastFrameNumber);
   1438             } finally {
   1439                 closeDevice(id);
   1440             }
   1441         }
   1442     }
   1443 
   1444     public void testConfigureAbandonedSurface() throws Exception {
   1445         for (String id : mCameraIds) {
   1446             Log.i(TAG, String.format(
   1447                     "Testing Camera %s for configuring abandoned surface", id));
   1448 
   1449             openDevice(id);
   1450             try {
   1451                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1452                 Surface previewSurface = new Surface(preview);
   1453 
   1454                 // Abandon preview SurfaceTexture.
   1455                 preview.release();
   1456 
   1457                 try {
   1458                     CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
   1459                     fail("Configuring abandoned surfaces must fail!");
   1460                 } catch (IllegalArgumentException e) {
   1461                     // expected
   1462                     Log.i(TAG, "normal session check passed");
   1463                 }
   1464 
   1465                 // Try constrained high speed session/requests
   1466                 if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) {
   1467                     continue;
   1468                 }
   1469 
   1470                 List<Surface> surfaces = new ArrayList<>();
   1471                 surfaces.add(previewSurface);
   1472                 CameraCaptureSession.StateCallback sessionListener =
   1473                         mock(CameraCaptureSession.StateCallback.class);
   1474 
   1475                 try {
   1476                     mCamera.createConstrainedHighSpeedCaptureSession(surfaces,
   1477                             sessionListener, mHandler);
   1478                     fail("Configuring abandoned surfaces in high speed session must fail!");
   1479                 } catch (IllegalArgumentException e) {
   1480                     // expected
   1481                     Log.i(TAG, "high speed session check 1 passed");
   1482                 }
   1483 
   1484                 // Also try abandone the Surface directly
   1485                 previewSurface.release();
   1486 
   1487                 try {
   1488                     mCamera.createConstrainedHighSpeedCaptureSession(surfaces,
   1489                             sessionListener, mHandler);
   1490                     fail("Configuring abandoned surfaces in high speed session must fail!");
   1491                 } catch (IllegalArgumentException e) {
   1492                     // expected
   1493                     Log.i(TAG, "high speed session check 2 passed");
   1494                 }
   1495             } finally {
   1496                 closeDevice(id);
   1497             }
   1498         }
   1499     }
   1500 
   1501     public void testAfSceneChange() throws Exception {
   1502         final int NUM_FRAMES_VERIFIED = 3;
   1503 
   1504         for (String id : mCameraIds) {
   1505             Log.i(TAG, String.format("Testing Camera %s for AF scene change", id));
   1506 
   1507             StaticMetadata staticInfo =
   1508                     new StaticMetadata(mCameraManager.getCameraCharacteristics(id));
   1509             if (!staticInfo.isAfSceneChangeSupported()) {
   1510                 continue;
   1511             }
   1512 
   1513             openDevice(id);
   1514 
   1515             try {
   1516                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1517                 Surface previewSurface = new Surface(preview);
   1518 
   1519                 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
   1520                 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback();
   1521 
   1522                 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked();
   1523 
   1524                 // Test AF scene change in each AF mode.
   1525                 for (int afMode : availableAfModes) {
   1526                     previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode);
   1527 
   1528                     int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(),
   1529                             previewListener, mHandler);
   1530 
   1531                     // Verify that AF scene change is NOT_DETECTED or DETECTED.
   1532                     for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) {
   1533                         TotalCaptureResult result =
   1534                             previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT);
   1535                         mCollector.expectKeyValueIsIn(result,
   1536                                 CaptureResult.CONTROL_AF_SCENE_CHANGE,
   1537                                 CaptureResult.CONTROL_AF_SCENE_CHANGE_DETECTED,
   1538                                 CaptureResult.CONTROL_AF_SCENE_CHANGE_NOT_DETECTED);
   1539                     }
   1540 
   1541                     mCameraSession.stopRepeating();
   1542                     previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT);
   1543                     previewListener.drain();
   1544                 }
   1545             } finally {
   1546                 closeDevice(id);
   1547             }
   1548         }
   1549     }
   1550 
   1551     public void testOisDataMode() throws Exception {
   1552         final int NUM_FRAMES_VERIFIED = 3;
   1553 
   1554         for (String id : mCameraIds) {
   1555             Log.i(TAG, String.format("Testing Camera %s for OIS mode", id));
   1556 
   1557             StaticMetadata staticInfo =
   1558                     new StaticMetadata(mCameraManager.getCameraCharacteristics(id));
   1559             if (!staticInfo.isOisDataModeSupported()) {
   1560                 continue;
   1561             }
   1562 
   1563             openDevice(id);
   1564 
   1565             try {
   1566                 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
   1567                 Surface previewSurface = new Surface(preview);
   1568 
   1569                 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
   1570                 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback();
   1571 
   1572                 int[] availableOisDataModes = staticInfo.getCharacteristics().get(
   1573                         CameraCharacteristics.STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES);
   1574 
   1575                 // Test each OIS data mode
   1576                 for (int oisMode : availableOisDataModes) {
   1577                     previewRequest.set(CaptureRequest.STATISTICS_OIS_DATA_MODE, oisMode);
   1578 
   1579                     int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(),
   1580                             previewListener, mHandler);
   1581 
   1582                     // Check OIS data in each mode.
   1583                     for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) {
   1584                         TotalCaptureResult result =
   1585                             previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT);
   1586 
   1587                         OisSample[] oisSamples = result.get(CaptureResult.STATISTICS_OIS_SAMPLES);
   1588 
   1589                         if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_OFF) {
   1590                             mCollector.expectKeyValueEquals(result,
   1591                                     CaptureResult.STATISTICS_OIS_DATA_MODE,
   1592                                     CaptureResult.STATISTICS_OIS_DATA_MODE_OFF);
   1593                             mCollector.expectTrue("OIS samples reported in OIS_DATA_MODE_OFF",
   1594                                     oisSamples == null || oisSamples.length == 0);
   1595 
   1596                         } else if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_ON) {
   1597                             mCollector.expectKeyValueEquals(result,
   1598                                     CaptureResult.STATISTICS_OIS_DATA_MODE,
   1599                                     CaptureResult.STATISTICS_OIS_DATA_MODE_ON);
   1600                             mCollector.expectTrue("OIS samples not reported in OIS_DATA_MODE_ON",
   1601                                     oisSamples != null && oisSamples.length != 0);
   1602                         } else {
   1603                             mCollector.addMessage(String.format("Invalid OIS mode: %d", oisMode));
   1604                         }
   1605                     }
   1606 
   1607                     mCameraSession.stopRepeating();
   1608                     previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT);
   1609                     previewListener.drain();
   1610                 }
   1611             } finally {
   1612                 closeDevice(id);
   1613             }
   1614         }
   1615     }
   1616 
   1617     private CaptureRequest.Builder preparePreviewTestSession(SurfaceTexture preview)
   1618             throws Exception {
   1619         Surface previewSurface = new Surface(preview);
   1620 
   1621         preview.setDefaultBufferSize(640, 480);
   1622 
   1623         ArrayList<Surface> sessionOutputs = new ArrayList<>();
   1624         sessionOutputs.add(previewSurface);
   1625 
   1626         createSession(sessionOutputs);
   1627 
   1628         CaptureRequest.Builder previewRequest =
   1629                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
   1630 
   1631         previewRequest.addTarget(previewSurface);
   1632 
   1633         return previewRequest;
   1634     }
   1635 
   1636     private CaptureRequest.Builder prepareTriggerTestSession(
   1637             SurfaceTexture preview, int aeMode, int afMode) throws Exception {
   1638         Log.i(TAG, String.format("Testing AE mode %s, AF mode %s",
   1639                         StaticMetadata.getAeModeName(aeMode),
   1640                         StaticMetadata.getAfModeName(afMode)));
   1641 
   1642         CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview);
   1643         previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode);
   1644         previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode);
   1645 
   1646         return previewRequest;
   1647     }
   1648 
   1649     private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest,
   1650             SimpleCaptureCallback captureListener, int afMode) throws Exception {
   1651         previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
   1652                 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
   1653         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
   1654                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
   1655 
   1656         CaptureRequest triggerRequest = previewRequest.build();
   1657         mCameraSession.capture(triggerRequest, captureListener, mHandler);
   1658 
   1659         // Wait for a few frames to initialize 3A
   1660 
   1661         CaptureResult previewResult = null;
   1662         int afState;
   1663         int aeState;
   1664 
   1665         for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) {
   1666             previewResult = captureListener.getCaptureResult(
   1667                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
   1668             if (VERBOSE) {
   1669                 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
   1670                 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
   1671                 Log.v(TAG, String.format("AF state: %s, AE state: %s",
   1672                                 StaticMetadata.AF_STATE_NAMES[afState],
   1673                                 StaticMetadata.AE_STATE_NAMES[aeState]));
   1674             }
   1675         }
   1676 
   1677         // Verify starting states
   1678 
   1679         afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
   1680         aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
   1681 
   1682         verifyStartingAfState(afMode, afState);
   1683 
   1684         // After several frames, AE must no longer be in INACTIVE state
   1685         assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " +
   1686                         "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]),
   1687                 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING ||
   1688                 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED ||
   1689                 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED);
   1690     }
   1691 
   1692     private void verifyStartingAfState(int afMode, int afState) {
   1693         switch (afMode) {
   1694             case CaptureResult.CONTROL_AF_MODE_AUTO:
   1695             case CaptureResult.CONTROL_AF_MODE_MACRO:
   1696                 assertTrue(String.format("AF state not INACTIVE, is %s",
   1697                                 StaticMetadata.AF_STATE_NAMES[afState]),
   1698                         afState == CaptureResult.CONTROL_AF_STATE_INACTIVE);
   1699                 break;
   1700             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
   1701             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
   1702                 // After several frames, AF must no longer be in INACTIVE state
   1703                 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" +
   1704                                 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s",
   1705                                 StaticMetadata.getAfModeName(afMode),
   1706                                 StaticMetadata.AF_STATE_NAMES[afState]),
   1707                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
   1708                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED ||
   1709                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED);
   1710                 break;
   1711             default:
   1712                 fail("unexpected af mode");
   1713         }
   1714     }
   1715 
   1716     private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) {
   1717         if (focusComplete) {
   1718             assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s",
   1719                             StaticMetadata.getAfModeName(afMode),
   1720                             StaticMetadata.AF_STATE_NAMES[afState]),
   1721                     afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
   1722                     afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
   1723             return focusComplete;
   1724         }
   1725         if (VERBOSE) {
   1726             Log.v(TAG, String.format("AF mode: %s, AF state: %s",
   1727                             StaticMetadata.getAfModeName(afMode),
   1728                             StaticMetadata.AF_STATE_NAMES[afState]));
   1729         }
   1730         switch (afMode) {
   1731             case CaptureResult.CONTROL_AF_MODE_AUTO:
   1732             case CaptureResult.CONTROL_AF_MODE_MACRO:
   1733                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
   1734                                 StaticMetadata.getAfModeName(afMode),
   1735                                 StaticMetadata.AF_STATE_NAMES[afState]),
   1736                         afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN ||
   1737                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
   1738                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
   1739                 focusComplete =
   1740                         (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN);
   1741                 break;
   1742             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
   1743                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
   1744                                 StaticMetadata.getAfModeName(afMode),
   1745                                 StaticMetadata.AF_STATE_NAMES[afState]),
   1746                         afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
   1747                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
   1748                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
   1749                 focusComplete =
   1750                         (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN);
   1751                 break;
   1752             case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
   1753                 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
   1754                                 StaticMetadata.getAfModeName(afMode),
   1755                                 StaticMetadata.AF_STATE_NAMES[afState]),
   1756                         afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
   1757                         afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
   1758                 focusComplete = true;
   1759                 break;
   1760             default:
   1761                 fail("Unexpected AF mode: " + StaticMetadata.getAfModeName(afMode));
   1762         }
   1763         return focusComplete;
   1764     }
   1765 
   1766     private boolean verifyAeSequence(int aeState, boolean precaptureComplete) {
   1767         if (precaptureComplete) {
   1768             assertTrue("Precapture state seen after convergence",
   1769                     aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
   1770             return precaptureComplete;
   1771         }
   1772         if (VERBOSE) {
   1773             Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState]));
   1774         }
   1775         switch (aeState) {
   1776             case CaptureResult.CONTROL_AE_STATE_PRECAPTURE:
   1777                 // scan still continuing
   1778                 break;
   1779             case CaptureResult.CONTROL_AE_STATE_CONVERGED:
   1780             case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
   1781                 // completed
   1782                 precaptureComplete = true;
   1783                 break;
   1784             default:
   1785                 fail(String.format("Precapture sequence transitioned to "
   1786                                 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState]));
   1787                 break;
   1788         }
   1789         return precaptureComplete;
   1790     }
   1791 
   1792 }
   1793