Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware.camera2.cts;
     18 
     19 import static android.hardware.camera2.cts.CameraTestUtils.*;
     20 
     21 import android.graphics.Bitmap;
     22 import android.graphics.ImageFormat;
     23 import android.graphics.PixelFormat;
     24 import android.graphics.SurfaceTexture;
     25 import android.hardware.camera2.CameraDevice;
     26 import android.hardware.camera2.CameraAccessException;
     27 import android.hardware.camera2.CaptureRequest;
     28 import android.hardware.camera2.CaptureFailure;
     29 import android.hardware.camera2.TotalCaptureResult;
     30 import android.hardware.camera2.cts.CameraTestUtils.ImageVerifierListener;
     31 import android.hardware.camera2.cts.helpers.StaticMetadata;
     32 import android.hardware.camera2.cts.rs.BitmapUtils;
     33 import android.hardware.camera2.cts.testcases.Camera2MultiViewTestCase;
     34 import android.hardware.camera2.cts.testcases.Camera2MultiViewTestCase.CameraPreviewListener;
     35 import android.hardware.camera2.params.OutputConfiguration;
     36 import android.hardware.HardwareBuffer;
     37 import android.media.Image;
     38 import android.media.ImageReader;
     39 import android.media.ImageWriter;
     40 import android.os.SystemClock;
     41 import android.os.ConditionVariable;
     42 import android.util.Log;
     43 import android.util.Size;
     44 import android.view.Surface;
     45 import android.view.TextureView;
     46 
     47 import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException;
     48 
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 import java.util.List;
     52 
     53 import org.junit.Test;
     54 
     55 /**
     56  * CameraDevice test by using combination of SurfaceView, TextureView and ImageReader
     57  */
     58 public class MultiViewTest extends Camera2MultiViewTestCase {
     59     private static final String TAG = "MultiViewTest";
     60     private final static long WAIT_FOR_COMMAND_TO_COMPLETE = 5000; //ms
     61     private final static long PREVIEW_TIME_MS = 2000;
     62     private final static long PREVIEW_FLUSH_TIME_MS = 1000;
     63     private final static int NUM_SURFACE_SWITCHES = 30;
     64     private final static int IMG_READER_COUNT = 2;
     65     private final static int YUV_IMG_READER_COUNT = 3;
     66     private final static double BITMAP_DIFF_THRESHOLD = 0.1;
     67 
     68     @Test
     69     public void testTextureViewPreview() throws Exception {
     70         for (String cameraId : mCameraIds) {
     71             Exception prior = null;
     72 
     73             try {
     74                 openCamera(cameraId);
     75                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
     76                     Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
     77                     continue;
     78                 }
     79                 List<TextureView> views = Arrays.asList(mTextureView[0]);
     80                 textureViewPreview(cameraId, views, /*ImageReader*/null);
     81             } catch (Exception e) {
     82                 prior = e;
     83             } finally {
     84                 try {
     85                     closeCamera(cameraId);
     86                 } catch (Exception e) {
     87                     if (prior != null) {
     88                         Log.e(TAG, "Prior exception received: " + prior);
     89                     }
     90                     prior = e;
     91                 }
     92                 if (prior != null) throw prior; // Rethrow last exception.
     93             }
     94         }
     95     }
     96 
     97     @Test
     98     public void testTextureViewPreviewWithImageReader() throws Exception {
     99         for (String cameraId : mCameraIds) {
    100             Exception prior = null;
    101 
    102             ImageVerifierListener yuvListener;
    103             ImageReader yuvReader = null;
    104 
    105             try {
    106                 openCamera(cameraId);
    107                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    108                     Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
    109                     continue;
    110                 }
    111                 Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    112                 yuvListener =
    113                         new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888);
    114                 yuvReader = makeImageReader(previewSize,
    115                         ImageFormat.YUV_420_888, MAX_READER_IMAGES, yuvListener, mHandler);
    116                 int maxNumStreamsProc =
    117                         getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked();
    118                 if (maxNumStreamsProc < 2) {
    119                     continue;
    120                 }
    121                 List<TextureView> views = Arrays.asList(mTextureView[0]);
    122                 textureViewPreview(cameraId, views, yuvReader);
    123             } catch (Exception e) {
    124                 prior = e;
    125             } finally {
    126                 try {
    127                     // Close camera device first. This will give some more time for
    128                     // ImageVerifierListener to finish the validation before yuvReader is closed
    129                     // (all image will be closed after that)
    130                     closeCamera(cameraId);
    131                     if (yuvReader != null) {
    132                         yuvReader.close();
    133                     }
    134                 } catch (Exception e) {
    135                     if (prior != null) {
    136                         Log.e(TAG, "Prior exception received: " + prior);
    137                     }
    138                     prior = e;
    139                 }
    140                 if (prior != null) throw prior; // Rethrow last exception.
    141             }
    142         }
    143     }
    144 
    145     @Test
    146     public void testDualTextureViewPreview() throws Exception {
    147         for (String cameraId : mCameraIds) {
    148             Exception prior = null;
    149             try {
    150                 openCamera(cameraId);
    151                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    152                     Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
    153                     continue;
    154                 }
    155                 int maxNumStreamsProc =
    156                         getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked();
    157                 if (maxNumStreamsProc < 2) {
    158                     continue;
    159                 }
    160                 List<TextureView> views = Arrays.asList(mTextureView[0], mTextureView[1]);
    161                 textureViewPreview(cameraId, views, /*ImageReader*/null);
    162             } catch (Exception e) {
    163                 prior = e;
    164             } finally {
    165                 try {
    166                     closeCamera(cameraId);
    167                 } catch (Exception e) {
    168                     if (prior != null) {
    169                         Log.e(TAG, "Prior exception received: " + prior);
    170                     }
    171                     prior = e;
    172                 }
    173                 if (prior != null) throw prior; // Rethrow last exception.
    174             }
    175         }
    176     }
    177 
    178     @Test
    179     public void testDualTextureViewAndImageReaderPreview() throws Exception {
    180         for (String cameraId : mCameraIds) {
    181             Exception prior = null;
    182 
    183             ImageVerifierListener yuvListener;
    184             ImageReader yuvReader = null;
    185 
    186             try {
    187                 openCamera(cameraId);
    188                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    189                     Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
    190                     continue;
    191                 }
    192                 Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    193                 yuvListener =
    194                         new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888);
    195                 yuvReader = makeImageReader(previewSize,
    196                         ImageFormat.YUV_420_888, MAX_READER_IMAGES, yuvListener, mHandler);
    197                 int maxNumStreamsProc =
    198                         getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked();
    199                 if (maxNumStreamsProc < 3) {
    200                     continue;
    201                 }
    202                 List<TextureView> views = Arrays.asList(mTextureView[0], mTextureView[1]);
    203                 textureViewPreview(cameraId, views, yuvReader);
    204             } catch (Exception e) {
    205                 prior = e;
    206             } finally {
    207                 try {
    208                     if (yuvReader != null) {
    209                         yuvReader.close();
    210                     }
    211                     closeCamera(cameraId);
    212                 } catch (Exception e) {
    213                     if (prior != null) {
    214                         Log.e(TAG, "Prior exception received: " + prior);
    215                     }
    216                     prior = e;
    217                 }
    218                 if (prior != null) throw prior; // Rethrow last exception.
    219             }
    220         }
    221     }
    222 
    223     @Test
    224     public void testDualCameraPreview() throws Exception {
    225         final int NUM_CAMERAS_TESTED = 2;
    226         if (mCameraIds.length < NUM_CAMERAS_TESTED) {
    227             return;
    228         }
    229 
    230         try {
    231             for (int i = 0; i < NUM_CAMERAS_TESTED; i++) {
    232                 openCamera(mCameraIds[i]);
    233                 if (!getStaticInfo(mCameraIds[i]).isColorOutputSupported()) {
    234                     Log.i(TAG, "Camera " + mCameraIds[i] +
    235                             " does not support color outputs, skipping");
    236                     continue;
    237                 }
    238                 List<TextureView> views = Arrays.asList(mTextureView[i]);
    239 
    240                 startTextureViewPreview(mCameraIds[i], views, /*ImageReader*/null);
    241             }
    242             // TODO: check the framerate is correct
    243             SystemClock.sleep(PREVIEW_TIME_MS);
    244             for (int i = 0; i < NUM_CAMERAS_TESTED; i++) {
    245                 if (!getStaticInfo(mCameraIds[i]).isColorOutputSupported()) {
    246                     Log.i(TAG, "Camera " + mCameraIds[i] +
    247                             " does not support color outputs, skipping");
    248                     continue;
    249                 }
    250                 stopPreview(mCameraIds[i]);
    251             }
    252         } catch (BlockingOpenException e) {
    253             // The only error accepted is ERROR_MAX_CAMERAS_IN_USE, which means HAL doesn't support
    254             // concurrent camera streaming
    255             assertEquals("Camera device open failed",
    256                     CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE, e.getCode());
    257             Log.i(TAG, "Camera HAL does not support dual camera preview. Skip the test");
    258         } finally {
    259             for (int i = 0; i < NUM_CAMERAS_TESTED; i++) {
    260                 closeCamera(mCameraIds[i]);
    261             }
    262         }
    263     }
    264 
    265     /*
    266      * Verify dynamic shared surface behavior.
    267      */
    268     @Test
    269     public void testSharedSurfaceBasic() throws Exception {
    270         for (String cameraId : mCameraIds) {
    271             try {
    272                 openCamera(cameraId);
    273                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
    274                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
    275                     continue;
    276                 }
    277                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    278                     Log.i(TAG, "Camera " + cameraId +
    279                             " does not support color outputs, skipping");
    280                     continue;
    281                 }
    282 
    283                 testSharedSurfaceBasicByCamera(cameraId);
    284             }
    285             finally {
    286                 closeCamera(cameraId);
    287             }
    288         }
    289     }
    290 
    291     private void testSharedSurfaceBasicByCamera(String cameraId) throws Exception {
    292         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    293         CameraPreviewListener[] previewListener = new CameraPreviewListener[2];
    294         SurfaceTexture[] previewTexture = new SurfaceTexture[2];
    295         Surface[] surfaces = new Surface[2];
    296         OutputConfiguration[] outputConfigs = new OutputConfiguration[2];
    297         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
    298 
    299         // Create surface textures with the same size
    300         for (int i = 0; i < 2; i++) {
    301             previewListener[i] = new CameraPreviewListener();
    302             mTextureView[i].setSurfaceTextureListener(previewListener[i]);
    303             previewTexture[i] = getAvailableSurfaceTexture(
    304                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
    305             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
    306             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
    307             // Correct the preview display rotation.
    308             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
    309             surfaces[i] = new Surface(previewTexture[i]);
    310             outputConfigs[i] = new OutputConfiguration(surfaces[i]);
    311             outputConfigs[i].enableSurfaceSharing();
    312             outputConfigurations.add(outputConfigs[i]);
    313         }
    314 
    315         startPreviewWithConfigs(cameraId, outputConfigurations, null);
    316 
    317         boolean previewDone =
    318                 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    319         assertTrue("Unable to start preview", previewDone);
    320 
    321         //try to dynamically add and remove any of the initial configured outputs
    322         try {
    323             outputConfigs[1].addSurface(surfaces[0]);
    324             updateOutputConfiguration(cameraId, outputConfigs[1]);
    325             fail("should get IllegalArgumentException due to invalid output");
    326         } catch (IllegalArgumentException e) {
    327             // expected exception
    328             outputConfigs[1].removeSurface(surfaces[0]);
    329         }
    330 
    331         try {
    332             outputConfigs[1].removeSurface(surfaces[1]);
    333             fail("should get IllegalArgumentException due to invalid output");
    334         } catch (IllegalArgumentException e) {
    335             // expected exception
    336         }
    337 
    338         try {
    339             outputConfigs[0].addSurface(surfaces[1]);
    340             updateOutputConfiguration(cameraId, outputConfigs[0]);
    341             fail("should get IllegalArgumentException due to invalid output");
    342         } catch (IllegalArgumentException e) {
    343             // expected exception
    344             outputConfigs[0].removeSurface(surfaces[1]);
    345         }
    346 
    347         try {
    348             outputConfigs[0].removeSurface(surfaces[0]);
    349             fail("should get IllegalArgumentException due to invalid output");
    350         } catch (IllegalArgumentException e) {
    351             // expected exception
    352         }
    353 
    354         //Check that we are able to add a shared texture surface with different size
    355         List<Size> orderedPreviewSizes = getOrderedPreviewSizes(cameraId);
    356         Size textureSize = previewSize;
    357         for (Size s : orderedPreviewSizes) {
    358             if (!s.equals(previewSize)) {
    359                 textureSize = s;
    360                 break;
    361             }
    362         }
    363         if (textureSize.equals(previewSize)) {
    364             return;
    365         }
    366         SurfaceTexture outputTexture = new SurfaceTexture(/* random texture ID*/ 5);
    367         outputTexture.setDefaultBufferSize(textureSize.getWidth(), textureSize.getHeight());
    368         Surface outputSurface = new Surface(outputTexture);
    369         //Add a valid output surface and then verify that it cannot be added any more
    370         outputConfigs[1].addSurface(outputSurface);
    371         updateOutputConfiguration(cameraId, outputConfigs[1]);
    372         try {
    373             outputConfigs[1].addSurface(outputSurface);
    374             fail("should get IllegalStateException due to duplicate output");
    375         } catch (IllegalStateException e) {
    376             // expected exception
    377         }
    378 
    379         outputConfigs[0].addSurface(outputSurface);
    380         try {
    381             updateOutputConfiguration(cameraId, outputConfigs[0]);
    382             fail("should get IllegalArgumentException due to duplicate output");
    383         } catch (IllegalArgumentException e) {
    384             // expected exception
    385             outputConfigs[0].removeSurface(outputSurface);
    386         }
    387 
    388         //Verify that the same surface cannot be removed twice
    389         outputConfigs[1].removeSurface(outputSurface);
    390         updateOutputConfiguration(cameraId, outputConfigs[1]);
    391         try {
    392             outputConfigs[0].removeSurface(outputSurface);
    393             fail("should get IllegalArgumentException due to invalid output");
    394         } catch (IllegalArgumentException e) {
    395             // expected exception
    396         }
    397         try {
    398             outputConfigs[1].removeSurface(outputSurface);
    399             fail("should get IllegalArgumentException due to invalid output");
    400         } catch (IllegalArgumentException e) {
    401             // expected exception
    402         }
    403 
    404         stopPreview(cameraId);
    405     }
    406 
    407     /*
    408      * Verify dynamic shared surface behavior using multiple ImageReaders.
    409      */
    410     @Test
    411     public void testSharedSurfaceImageReaderSwitch() throws Exception {
    412         for (String cameraId : mCameraIds) {
    413             try {
    414                 openCamera(cameraId);
    415                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
    416                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
    417                     continue;
    418                 }
    419                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    420                     Log.i(TAG, "Camera " + cameraId +
    421                             " does not support color outputs, skipping");
    422                     continue;
    423                 }
    424 
    425                 testSharedSurfaceImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES);
    426             }
    427             finally {
    428                 closeCamera(cameraId);
    429             }
    430         }
    431     }
    432 
    433     private void testSharedSurfaceImageReaderSwitch(String cameraId, int switchCount)
    434             throws Exception {
    435         SimpleImageListener imageListeners[] = new SimpleImageListener[IMG_READER_COUNT];
    436         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    437         ImageReader imageReaders[] = new ImageReader[IMG_READER_COUNT];
    438         Surface readerSurfaces[] = new Surface[IMG_READER_COUNT];
    439         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    440         CameraPreviewListener previewListener = new CameraPreviewListener();
    441         mTextureView[0].setSurfaceTextureListener(previewListener);
    442         SurfaceTexture previewTexture = getAvailableSurfaceTexture(WAIT_FOR_COMMAND_TO_COMPLETE,
    443                 mTextureView[0]);
    444         assertNotNull("Unable to get preview surface texture", previewTexture);
    445         previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
    446         updatePreviewDisplayRotation(previewSize, mTextureView[0]);
    447         Surface previewSurface = new Surface(previewTexture);
    448         OutputConfiguration outputConfig = new OutputConfiguration(previewSurface);
    449         outputConfig.enableSurfaceSharing();
    450         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
    451         outputConfigurations.add(outputConfig);
    452 
    453         if (outputConfig.getMaxSharedSurfaceCount() < (IMG_READER_COUNT + 1)) {
    454             return;
    455         }
    456 
    457         //Start regular preview streaming
    458         startPreviewWithConfigs(cameraId, outputConfigurations, null);
    459 
    460         boolean previewDone = previewListener.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    461         assertTrue("Unable to start preview", previewDone);
    462 
    463         //Test shared image reader outputs
    464         for (int i = 0; i < IMG_READER_COUNT; i++) {
    465             imageListeners[i] = new SimpleImageListener();
    466             imageReaders[i] = ImageReader.newInstance(previewSize.getWidth(),
    467                     previewSize.getHeight(), ImageFormat.PRIVATE, 2);
    468             imageReaders[i].setOnImageAvailableListener(imageListeners[i], mHandler);
    469             readerSurfaces[i] = imageReaders[i].getSurface();
    470         }
    471 
    472         for (int j = 0; j < switchCount; j++) {
    473             for (int i = 0; i < IMG_READER_COUNT; i++) {
    474                 outputConfig.addSurface(readerSurfaces[i]);
    475                 updateOutputConfiguration(cameraId, outputConfig);
    476                 CaptureRequest.Builder imageReaderRequestBuilder = getCaptureBuilder(cameraId,
    477                         CameraDevice.TEMPLATE_PREVIEW);
    478                 imageReaderRequestBuilder.addTarget(readerSurfaces[i]);
    479                 capture(cameraId, imageReaderRequestBuilder.build(), resultListener);
    480                 imageListeners[i].waitForAnyImageAvailable(PREVIEW_TIME_MS);
    481                 Image img = imageReaders[i].acquireLatestImage();
    482                 assertNotNull("Invalid image acquired!", img);
    483                 img.close();
    484                 outputConfig.removeSurface(readerSurfaces[i]);
    485                 updateOutputConfiguration(cameraId, outputConfig);
    486             }
    487         }
    488 
    489         for (int i = 0; i < IMG_READER_COUNT; i++) {
    490             imageReaders[i].close();
    491         }
    492 
    493         stopPreview(cameraId);
    494     }
    495 
    496     /*
    497      * Verify dynamic shared surface behavior using YUV ImageReaders.
    498      */
    499     @Test
    500     public void testSharedSurfaceYUVImageReaderSwitch() throws Exception {
    501         int YUVFormats[] = {ImageFormat.YUV_420_888, ImageFormat.YUV_422_888,
    502             ImageFormat.YUV_444_888, ImageFormat.YUY2, ImageFormat.YV12,
    503             ImageFormat.NV16, ImageFormat.NV21};
    504         for (String cameraId : mCameraIds) {
    505             try {
    506                 openCamera(cameraId);
    507                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
    508                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
    509                     continue;
    510                 }
    511                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    512                     Log.i(TAG, "Camera " + cameraId +
    513                             " does not support color outputs, skipping");
    514                     continue;
    515                 }
    516                 Size frameSize = null;
    517                 int yuvFormat = -1;
    518                 for (int it : YUVFormats) {
    519                     Size yuvSizes[] = getStaticInfo(cameraId).getAvailableSizesForFormatChecked(
    520                             it, StaticMetadata.StreamDirection.Output);
    521                     if (yuvSizes != null) {
    522                         frameSize = yuvSizes[0];
    523                         yuvFormat = it;
    524                         break;
    525                     }
    526                 }
    527 
    528                 if ((yuvFormat != -1) && (frameSize.getWidth() > 0) &&
    529                         (frameSize.getHeight() > 0)) {
    530                     testSharedSurfaceYUVImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES, yuvFormat,
    531                             frameSize, /*blockMaxAcquired*/ false);
    532                     testSharedSurfaceYUVImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES, yuvFormat,
    533                             frameSize, /*blockMaxAcquired*/ true);
    534                 } else {
    535                     Log.i(TAG, "Camera " + cameraId +
    536                             " does not support YUV outputs, skipping");
    537                 }
    538             }
    539             finally {
    540                 closeCamera(cameraId);
    541             }
    542         }
    543     }
    544 
    545     private void testSharedSurfaceYUVImageReaderSwitch(String cameraId, int switchCount, int format,
    546             Size frameSize, boolean blockMaxAcquired) throws Exception {
    547 
    548         assertTrue("YUV_IMG_READER_COUNT should be equal or greater than 2",
    549                 (YUV_IMG_READER_COUNT >= 2));
    550 
    551         SimpleImageListener imageListeners[] = new SimpleImageListener[YUV_IMG_READER_COUNT];
    552         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    553         ImageReader imageReaders[] = new ImageReader[YUV_IMG_READER_COUNT];
    554         Surface readerSurfaces[] = new Surface[YUV_IMG_READER_COUNT];
    555 
    556         for (int i = 0; i < YUV_IMG_READER_COUNT; i++) {
    557             imageListeners[i] = new SimpleImageListener();
    558             imageReaders[i] = ImageReader.newInstance(frameSize.getWidth(), frameSize.getHeight(),
    559                     format, 2);
    560             imageReaders[i].setOnImageAvailableListener(imageListeners[i], mHandler);
    561             readerSurfaces[i] = imageReaders[i].getSurface();
    562         }
    563 
    564         OutputConfiguration outputConfig = new OutputConfiguration(readerSurfaces[0]);
    565         outputConfig.enableSurfaceSharing();
    566         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
    567         outputConfigurations.add(outputConfig);
    568         if (outputConfig.getMaxSharedSurfaceCount() < YUV_IMG_READER_COUNT) {
    569             return;
    570         }
    571 
    572         createSessionWithConfigs(cameraId, outputConfigurations);
    573 
    574         // Test YUV ImageReader surface sharing. The first ImageReader will
    575         // always be part of the capture request, the rest will switch on each
    576         // iteration.
    577         // If 'blockMaxAcquired' is enabled, the first image reader will acquire
    578         // the maximum possible amount of buffers and also block a few more.
    579         int maxAcquiredImages = imageReaders[0].getMaxImages();
    580         int acquiredCount = 0;
    581         Image[] acquiredImages = new Image[maxAcquiredImages];
    582         for (int j = 0; j < switchCount; j++) {
    583             for (int i = 1; i < YUV_IMG_READER_COUNT; i++) {
    584                 outputConfig.addSurface(readerSurfaces[i]);
    585                 updateOutputConfiguration(cameraId, outputConfig);
    586                 CaptureRequest.Builder imageReaderRequestBuilder = getCaptureBuilder(cameraId,
    587                         CameraDevice.TEMPLATE_PREVIEW);
    588                 imageReaderRequestBuilder.addTarget(readerSurfaces[i]);
    589                 if (blockMaxAcquired) {
    590                     if (acquiredCount <= (maxAcquiredImages + 1)) {
    591                         // Camera should be able to handle cases where
    592                         // one output blocks more buffers than the respective
    593                         // maximum acquired count.
    594                         imageReaderRequestBuilder.addTarget(readerSurfaces[0]);
    595                     }
    596                 } else {
    597                     imageReaderRequestBuilder.addTarget(readerSurfaces[0]);
    598                 }
    599                 capture(cameraId, imageReaderRequestBuilder.build(), resultListener);
    600                 imageListeners[i].waitForAnyImageAvailable(PREVIEW_TIME_MS);
    601                 Image img = imageReaders[i].acquireLatestImage();
    602                 assertNotNull("Invalid image acquired!", img);
    603                 assertNotNull("Image planes are invalid!", img.getPlanes());
    604                 img.close();
    605                 if (blockMaxAcquired) {
    606                     if (acquiredCount < maxAcquiredImages) {
    607                         imageListeners[0].waitForAnyImageAvailable(PREVIEW_TIME_MS);
    608                         acquiredImages[acquiredCount] = imageReaders[0].acquireNextImage();
    609                     }
    610                     acquiredCount++;
    611                 } else {
    612                     imageListeners[0].waitForAnyImageAvailable(PREVIEW_TIME_MS);
    613                     img = imageReaders[0].acquireLatestImage();
    614                     assertNotNull("Invalid image acquired!", img);
    615                     img.close();
    616                 }
    617                 outputConfig.removeSurface(readerSurfaces[i]);
    618                 updateOutputConfiguration(cameraId, outputConfig);
    619             }
    620         }
    621 
    622         for (int i = 0; i < YUV_IMG_READER_COUNT; i++) {
    623             imageReaders[i].close();
    624         }
    625     }
    626 
    627     /*
    628      * Test the dynamic shared surface limit.
    629      */
    630     @Test
    631     public void testSharedSurfaceLimit() throws Exception {
    632         for (String cameraId : mCameraIds) {
    633             try {
    634                 openCamera(cameraId);
    635                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
    636                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
    637                     continue;
    638                 }
    639                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    640                     Log.i(TAG, "Camera " + cameraId +
    641                             " does not support color outputs, skipping");
    642                     continue;
    643                 }
    644 
    645                 testSharedSurfaceLimitByCamera(cameraId,
    646                         Camera2MultiViewCtsActivity.MAX_TEXTURE_VIEWS);
    647             }
    648             finally {
    649                 closeCamera(cameraId);
    650             }
    651         }
    652     }
    653 
    654     private void testSharedSurfaceLimitByCamera(String cameraId, int surfaceLimit)
    655             throws Exception {
    656         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    657         CameraPreviewListener[] previewListener = new CameraPreviewListener[surfaceLimit];
    658         SurfaceTexture[] previewTexture = new SurfaceTexture[surfaceLimit];
    659         Surface[] surfaces = new Surface[surfaceLimit];
    660         int sequenceId = -1;
    661 
    662         // Create surface textures with the same size
    663         for (int i = 0; i < surfaceLimit; i++) {
    664             previewListener[i] = new CameraPreviewListener();
    665             mTextureView[i].setSurfaceTextureListener(previewListener[i]);
    666             previewTexture[i] = getAvailableSurfaceTexture(
    667                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
    668             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
    669             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
    670             // Correct the preview display rotation.
    671             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
    672             surfaces[i] = new Surface(previewTexture[i]);
    673         }
    674 
    675         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    676 
    677         // Create shared outputs for the two surface textures
    678         OutputConfiguration surfaceSharedOutput = new OutputConfiguration(surfaces[0]);
    679         surfaceSharedOutput.enableSurfaceSharing();
    680 
    681         if ((surfaceLimit <= 1) ||
    682                 (surfaceLimit < surfaceSharedOutput.getMaxSharedSurfaceCount())) {
    683             return;
    684         }
    685 
    686         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
    687         outputConfigurations.add(surfaceSharedOutput);
    688 
    689         startPreviewWithConfigs(cameraId, outputConfigurations, null);
    690 
    691         boolean previewDone =
    692                 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    693         assertTrue("Unable to start preview", previewDone);
    694         mTextureView[0].setSurfaceTextureListener(null);
    695 
    696         SystemClock.sleep(PREVIEW_TIME_MS);
    697 
    698         int i = 1;
    699         for (; i < surfaceLimit; i++) {
    700             //Add one more output surface while preview is streaming
    701             if (i >= surfaceSharedOutput.getMaxSharedSurfaceCount()){
    702                 try {
    703                     surfaceSharedOutput.addSurface(surfaces[i]);
    704                     fail("should get IllegalArgumentException due to output surface limit");
    705                 } catch (IllegalArgumentException e) {
    706                     //expected
    707                     break;
    708                 }
    709             } else {
    710                 surfaceSharedOutput.addSurface(surfaces[i]);
    711                 assertTrue("Session configuration should not fail",
    712                         isSessionConfigurationSupported(cameraId, outputConfigurations));
    713                 updateOutputConfiguration(cameraId, surfaceSharedOutput);
    714                 sequenceId = updateRepeatingRequest(cameraId, outputConfigurations, resultListener);
    715 
    716                 SystemClock.sleep(PREVIEW_TIME_MS);
    717             }
    718         }
    719 
    720         for (; i > 0; i--) {
    721             if (i >= surfaceSharedOutput.getMaxSharedSurfaceCount()) {
    722                 try {
    723                     surfaceSharedOutput.removeSurface(surfaces[i]);
    724                     fail("should get IllegalArgumentException due to output surface limit");
    725                 } catch (IllegalArgumentException e) {
    726                     // expected exception
    727                 }
    728             } else {
    729                 surfaceSharedOutput.removeSurface(surfaces[i]);
    730                 assertTrue("Session configuration should not fail",
    731                         isSessionConfigurationSupported(cameraId, outputConfigurations));
    732             }
    733         }
    734         //Remove all previously added shared outputs in one call
    735         updateRepeatingRequest(cameraId, outputConfigurations, resultListener);
    736         long lastSequenceFrameNumber = resultListener.getCaptureSequenceLastFrameNumber(
    737                 sequenceId, PREVIEW_TIME_MS);
    738         checkForLastFrameInSequence(lastSequenceFrameNumber, resultListener);
    739         updateOutputConfiguration(cameraId, surfaceSharedOutput);
    740         SystemClock.sleep(PREVIEW_TIME_MS);
    741 
    742         stopPreview(cameraId);
    743     }
    744 
    745     /*
    746      * Test dynamic shared surface switch behavior.
    747      */
    748     @Test(timeout=60*60*1000) // timeout = 60 mins for long running tests
    749     public void testSharedSurfaceSwitch() throws Exception {
    750         for (String cameraId : mCameraIds) {
    751             try {
    752                 openCamera(cameraId);
    753                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
    754                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
    755                     continue;
    756                 }
    757                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
    758                     Log.i(TAG, "Camera " + cameraId +
    759                             " does not support color outputs, skipping");
    760                     continue;
    761                 }
    762 
    763                 testSharedSurfaceSwitchByCamera(cameraId, NUM_SURFACE_SWITCHES);
    764             }
    765             finally {
    766                 closeCamera(cameraId);
    767             }
    768         }
    769     }
    770 
    771     private void testSharedSurfaceSwitchByCamera(String cameraId, int switchCount)
    772             throws Exception {
    773         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
    774         CameraPreviewListener[] previewListener = new CameraPreviewListener[2];
    775         SurfaceTexture[] previewTexture = new SurfaceTexture[2];
    776         Surface[] surfaces = new Surface[2];
    777 
    778         // Create surface textures with the same size
    779         for (int i = 0; i < 2; i++) {
    780             previewListener[i] = new CameraPreviewListener();
    781             mTextureView[i].setSurfaceTextureListener(previewListener[i]);
    782             previewTexture[i] = getAvailableSurfaceTexture(
    783                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
    784             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
    785             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
    786             // Correct the preview display rotation.
    787             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
    788             surfaces[i] = new Surface(previewTexture[i]);
    789         }
    790 
    791         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    792 
    793         // Create shared outputs for the two surface textures
    794         OutputConfiguration surfaceSharedOutput = new OutputConfiguration(surfaces[0]);
    795         surfaceSharedOutput.enableSurfaceSharing();
    796 
    797         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
    798         outputConfigurations.add(surfaceSharedOutput);
    799 
    800         startPreviewWithConfigs(cameraId, outputConfigurations, null);
    801 
    802         boolean previewDone =
    803                 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    804         assertTrue("Unable to start preview", previewDone);
    805         mTextureView[0].setSurfaceTextureListener(null);
    806 
    807         SystemClock.sleep(PREVIEW_TIME_MS);
    808 
    809         for (int i = 0; i < switchCount; i++) {
    810             //Add one more output surface while preview is streaming
    811             surfaceSharedOutput.addSurface(surfaces[1]);
    812             updateOutputConfiguration(cameraId, surfaceSharedOutput);
    813             int sequenceId = updateRepeatingRequest(cameraId, outputConfigurations, resultListener);
    814 
    815             SystemClock.sleep(PREVIEW_TIME_MS);
    816 
    817             //Try to remove the shared surface while while we still have active requests that
    818             //use it as output.
    819             surfaceSharedOutput.removeSurface(surfaces[1]);
    820             try {
    821                 updateOutputConfiguration(cameraId, surfaceSharedOutput);
    822                 fail("should get IllegalArgumentException due to pending requests");
    823             } catch (IllegalArgumentException e) {
    824                 // expected exception
    825             }
    826 
    827             //Wait for all pending requests to arrive and remove the shared output during active
    828             //streaming
    829             updateRepeatingRequest(cameraId, outputConfigurations, resultListener);
    830             long lastSequenceFrameNumber = resultListener.getCaptureSequenceLastFrameNumber(
    831                     sequenceId, PREVIEW_TIME_MS);
    832             checkForLastFrameInSequence(lastSequenceFrameNumber, resultListener);
    833             updateOutputConfiguration(cameraId, surfaceSharedOutput);
    834 
    835             SystemClock.sleep(PREVIEW_TIME_MS);
    836         }
    837 
    838         stopPreview(cameraId);
    839     }
    840 
    841 
    842     /*
    843      * Two output Surface of the same size are configured: one from TextureView and
    844      * the other is ImageReader with usage flag USAGE_GPU_SAMPLED_IMAGE. The
    845      * ImageReader queues Image to a ImageWriter of the same usage flag, the
    846      * ImageWriter then is connected to another TextureView. Verify the Bitmap
    847      * from the first TextureView is identical to the second TextureView.
    848      */
    849     @Test
    850     public void testTextureImageWriterReaderOperation() throws Exception {
    851         for (String id : mCameraIds) {
    852             ImageReader reader = null;
    853             ImageWriter writer = null;
    854             Surface writerOutput = null;
    855             try {
    856                 Log.i(TAG, "Testing Camera " + id);
    857                 openCamera(id);
    858 
    859                 if (!getStaticInfo(id).isColorOutputSupported()) {
    860                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
    861                     continue;
    862                 }
    863 
    864                 int maxNumStreamsProc =
    865                         getStaticInfo(id).getMaxNumOutputStreamsProcessedChecked();
    866                 if (maxNumStreamsProc < 2) {
    867                     continue;
    868                 }
    869 
    870                 // mTextureView[0..2] each shared 1/3 of the horizontal space but their size can
    871                 // differ up to one pixel if the total width is not divisible by 3. Here we try to
    872                 // pick two of them that have matching size.
    873                 Size size0 = new Size(mTextureView[0].getWidth(), mTextureView[0].getHeight());
    874                 Size size1 = new Size(mTextureView[1].getWidth(), mTextureView[1].getHeight());
    875                 Size size2 = new Size(mTextureView[2].getWidth(), mTextureView[2].getHeight());
    876                 Log.v(TAG, "Size0: " + size0 + ", Size1: " + size1 + ", size2: " + size2);
    877 
    878                 int viewIdx0 = 0;
    879                 int viewIdx1 = 1;
    880                 if (!size0.equals(size1)) {
    881                     assertTrue("No matching view sizes! Size0: " + size0 +
    882                             ", Size1: " + size1 + ", size2: " + size2,
    883                             size0.equals(size2) || size1.equals(size2));
    884                     if (size0.equals(size2)) {
    885                         viewIdx0 = 0;
    886                         viewIdx1 = 2;
    887                     } else {
    888                         viewIdx0 = 1;
    889                         viewIdx1 = 2;
    890                     }
    891                 }
    892 
    893                 Size previewSize = getOrderedPreviewSizes(id).get(0);
    894                 List<TextureView> views = Arrays.asList(mTextureView[viewIdx0]);
    895 
    896                 // view[0] is normal camera -> TextureView path
    897                 // view[1] is camera -> ImageReader -> TextureView path
    898                 SurfaceTexture surfaceTexture0 = getAvailableSurfaceTexture(
    899                         WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[viewIdx0]);
    900                 assertNotNull("Unable to get preview surface texture 0", surfaceTexture0);
    901                 surfaceTexture0.setDefaultBufferSize(
    902                         previewSize.getWidth(), previewSize.getHeight());
    903 
    904                 SurfaceTexture surfaceTexture1 = getAvailableSurfaceTexture(
    905                         WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[viewIdx1]);
    906                 assertNotNull("Unable to get preview surface texture 1", surfaceTexture1);
    907                 surfaceTexture1.setDefaultBufferSize(
    908                         previewSize.getWidth(), previewSize.getHeight());
    909 
    910                 updatePreviewDisplayRotation(previewSize, mTextureView[viewIdx1]);
    911 
    912                 reader = ImageReader.newInstance(
    913                         previewSize.getWidth(), previewSize.getHeight(),
    914                         ImageFormat.PRIVATE,
    915                         MAX_READER_IMAGES,
    916                         HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
    917 
    918                 writerOutput = new Surface(surfaceTexture1);
    919                 writer = ImageWriter.newInstance(
    920                         writerOutput, MAX_READER_IMAGES,
    921                         ImageFormat.PRIVATE);
    922 
    923                 ImageWriterQueuer writerInput = new ImageWriterQueuer(writer);
    924 
    925                 reader.setOnImageAvailableListener(writerInput, mHandler);
    926 
    927                 startTextureViewPreview(id, views, reader);
    928                 SystemClock.sleep(PREVIEW_TIME_MS);
    929                 stopRepeating(id);
    930                 // Extra sleep to make sure all previous preview frames are delivered to
    931                 // SurfaceTexture
    932                 SystemClock.sleep(PREVIEW_FLUSH_TIME_MS);
    933 
    934                 Surface preview = new Surface(surfaceTexture0);
    935                 CaptureRequest.Builder requestBuilder = getCaptureBuilder(id,
    936                         CameraDevice.TEMPLATE_PREVIEW);
    937                 requestBuilder.addTarget(reader.getSurface());
    938                 requestBuilder.addTarget(preview);
    939                 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
    940                 CameraPreviewListener stListener0 = new CameraPreviewListener();
    941                 CameraPreviewListener stListener1 = new CameraPreviewListener();
    942                 mTextureView[viewIdx0].setSurfaceTextureListener(stListener0);
    943                 mTextureView[viewIdx1].setSurfaceTextureListener(stListener1);
    944 
    945                 // do a single capture
    946                 capture(id, requestBuilder.build(), resultListener);
    947                 // wait for capture done
    948                 stListener0.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    949                 stListener1.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
    950 
    951                 // get bitmap from both TextureView and compare
    952                 Bitmap bitmap0 = mTextureView[viewIdx0].getBitmap();
    953                 Bitmap bitmap1 = mTextureView[viewIdx1].getBitmap();
    954                 BitmapUtils.BitmapCompareResult result =
    955                         BitmapUtils.compareBitmap(bitmap0, bitmap1);
    956 
    957                 Log.i(TAG, "Bitmap difference is " + result.mDiff);
    958                 assertTrue(String.format(
    959                         "Bitmap difference exceeds threshold: diff %f > threshold %f",
    960                         result.mDiff, BITMAP_DIFF_THRESHOLD),
    961                         result.mDiff <= BITMAP_DIFF_THRESHOLD);
    962 
    963                 assertTrue(String.format(
    964                         "Bitmap from direct Textureview is flat. All pixels are (%f, %f, %f)",
    965                         result.mLhsAverage[0], result.mLhsAverage[1], result.mLhsAverage[2]),
    966                         !result.mLhsFlat);
    967 
    968                 assertTrue(String.format(
    969                         "Bitmap from ImageWriter Textureview is flat. All pixels are (%f, %f, %f)",
    970                         result.mRhsAverage[0], result.mRhsAverage[1], result.mRhsAverage[2]),
    971                         !result.mRhsFlat);
    972             } finally {
    973                 if (reader != null) {
    974                     reader.close();
    975                 }
    976                 if (writer != null) {
    977                     writer.close();
    978                 }
    979                 if (writerOutput != null) {
    980                     writerOutput.release();
    981                 }
    982                 closeCamera(id);
    983             }
    984         }
    985     }
    986 
    987     public static class ImageWriterQueuer implements ImageReader.OnImageAvailableListener {
    988         @Override
    989         public void onImageAvailable(ImageReader reader) {
    990             Image image = null;
    991             try {
    992                 image = reader.acquireNextImage();
    993             } finally {
    994                 if (image != null && mWriter != null) {
    995                     mWriter.queueInputImage(image);
    996                 }
    997             }
    998         }
    999 
   1000         public ImageWriterQueuer(ImageWriter writer) {
   1001             mWriter = writer;
   1002         }
   1003         private ImageWriter mWriter = null;
   1004     }
   1005 
   1006     private void checkForLastFrameInSequence(long lastSequenceFrameNumber,
   1007             SimpleCaptureCallback listener) throws Exception {
   1008         // Find the last frame number received in results and failures.
   1009         long lastFrameNumber = -1;
   1010         while (listener.hasMoreResults()) {
   1011             TotalCaptureResult result = listener.getTotalCaptureResult(PREVIEW_TIME_MS);
   1012             if (lastFrameNumber < result.getFrameNumber()) {
   1013                 lastFrameNumber = result.getFrameNumber();
   1014             }
   1015         }
   1016 
   1017         while (listener.hasMoreFailures()) {
   1018             ArrayList<CaptureFailure> failures = listener.getCaptureFailures(
   1019                     /*maxNumFailures*/ 1);
   1020             for (CaptureFailure failure : failures) {
   1021                 if (lastFrameNumber < failure.getFrameNumber()) {
   1022                     lastFrameNumber = failure.getFrameNumber();
   1023                 }
   1024             }
   1025         }
   1026 
   1027         // Verify the last frame number received from capture sequence completed matches the
   1028         // the last frame number of the results and failures.
   1029         assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " +
   1030                 "(%d) doesn't match the last frame number received from " +
   1031                 "results/failures (%d)", lastSequenceFrameNumber, lastFrameNumber),
   1032                 lastSequenceFrameNumber, lastFrameNumber);
   1033     }
   1034 
   1035     /*
   1036      * Verify behavior of sharing surfaces within one OutputConfiguration
   1037      */
   1038     @Test
   1039     public void testSharedSurfaces() throws Exception {
   1040         for (String cameraId : mCameraIds) {
   1041             try {
   1042                 openCamera(cameraId);
   1043                 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) {
   1044                     Log.i(TAG, "Camera " + cameraId + " is legacy, skipping");
   1045                     continue;
   1046                 }
   1047                 if (!getStaticInfo(cameraId).isColorOutputSupported()) {
   1048                     Log.i(TAG, "Camera " + cameraId +
   1049                             " does not support color outputs, skipping");
   1050                     continue;
   1051                 }
   1052 
   1053                 testSharedSurfacesConfigByCamera(cameraId);
   1054 
   1055                 testSharedSurfacesCaptureSessionByCamera(cameraId);
   1056 
   1057                 testSharedDeferredSurfacesByCamera(cameraId);
   1058             }
   1059             finally {
   1060                 closeCamera(cameraId);
   1061             }
   1062         }
   1063     }
   1064 
   1065 
   1066     /**
   1067      * Start camera preview using input texture views and/or one image reader
   1068      */
   1069     private void startTextureViewPreview(
   1070             String cameraId, List<TextureView> views, ImageReader imageReader)
   1071             throws Exception {
   1072         int numPreview = views.size();
   1073         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
   1074         CameraPreviewListener[] previewListener =
   1075                 new CameraPreviewListener[numPreview];
   1076         SurfaceTexture[] previewTexture = new SurfaceTexture[numPreview];
   1077         List<Surface> surfaces = new ArrayList<Surface>();
   1078 
   1079         // Prepare preview surface.
   1080         int i = 0;
   1081         for (TextureView view : views) {
   1082             previewListener[i] = new CameraPreviewListener();
   1083             view.setSurfaceTextureListener(previewListener[i]);
   1084             previewTexture[i] = getAvailableSurfaceTexture(WAIT_FOR_COMMAND_TO_COMPLETE, view);
   1085             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
   1086             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
   1087             // Correct the preview display rotation.
   1088             updatePreviewDisplayRotation(previewSize, view);
   1089             surfaces.add(new Surface(previewTexture[i]));
   1090             i++;
   1091         }
   1092         if (imageReader != null) {
   1093             surfaces.add(imageReader.getSurface());
   1094         }
   1095 
   1096         startPreview(cameraId, surfaces, null);
   1097 
   1098         i = 0;
   1099         for (TextureView view : views) {
   1100             boolean previewDone =
   1101                     previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1102             assertTrue("Unable to start preview " + i, previewDone);
   1103             view.setSurfaceTextureListener(null);
   1104             i++;
   1105         }
   1106     }
   1107 
   1108     /**
   1109      * Test camera preview using input texture views and/or one image reader
   1110      */
   1111     private void textureViewPreview(
   1112             String cameraId, List<TextureView> views, ImageReader testImagerReader)
   1113             throws Exception {
   1114         startTextureViewPreview(cameraId, views, testImagerReader);
   1115 
   1116         // TODO: check the framerate is correct
   1117         SystemClock.sleep(PREVIEW_TIME_MS);
   1118 
   1119         stopPreview(cameraId);
   1120     }
   1121 
   1122     /*
   1123      * Verify behavior of OutputConfiguration when sharing surfaces
   1124      */
   1125     private void testSharedSurfacesConfigByCamera(String cameraId) throws Exception {
   1126         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
   1127 
   1128         SurfaceTexture[] previewTexture = new SurfaceTexture[2];
   1129         Surface[] surfaces = new Surface[2];
   1130 
   1131         // Create surface textures with the same size
   1132         for (int i = 0; i < 2; i++) {
   1133             previewTexture[i] = getAvailableSurfaceTexture(
   1134                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
   1135             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
   1136             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
   1137             // Correct the preview display rotation.
   1138             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
   1139             surfaces[i] = new Surface(previewTexture[i]);
   1140         }
   1141 
   1142         // Verify that outputConfiguration can be created with 2 surfaces with the same setting.
   1143         OutputConfiguration previewConfiguration = new OutputConfiguration(
   1144                 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]);
   1145         previewConfiguration.enableSurfaceSharing();
   1146         previewConfiguration.addSurface(surfaces[1]);
   1147         List<Surface> previewSurfaces = previewConfiguration.getSurfaces();
   1148         List<Surface> inputSurfaces = Arrays.asList(surfaces);
   1149         assertTrue(
   1150                 String.format("Surfaces returned from getSurfaces() don't match those passed in"),
   1151                 previewSurfaces.equals(inputSurfaces));
   1152 
   1153         // Verify that createCaptureSession fails if 2 surfaces are different size
   1154         SurfaceTexture outputTexture2 = new SurfaceTexture(/* random texture ID*/ 5);
   1155         outputTexture2.setDefaultBufferSize(previewSize.getWidth()/2,
   1156                 previewSize.getHeight()/2);
   1157         Surface outputSurface2 = new Surface(outputTexture2);
   1158         OutputConfiguration configuration = new OutputConfiguration(
   1159                 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]);
   1160         configuration.enableSurfaceSharing();
   1161         configuration.addSurface(outputSurface2);
   1162         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
   1163         outputConfigurations.add(configuration);
   1164         verifyCreateSessionWithConfigsFailure(cameraId, outputConfigurations);
   1165 
   1166         // Verify that outputConfiguration throws exception if 2 surfaces are different format
   1167         ImageReader imageReader = makeImageReader(previewSize, ImageFormat.YUV_420_888,
   1168                 MAX_READER_IMAGES, new ImageDropperListener(), mHandler);
   1169         try {
   1170             configuration = new OutputConfiguration(OutputConfiguration.SURFACE_GROUP_ID_NONE,
   1171                     surfaces[0]);
   1172             configuration.enableSurfaceSharing();
   1173             configuration.addSurface(imageReader.getSurface());
   1174             fail("No error for invalid output config created from different format surfaces");
   1175         } catch (IllegalArgumentException e) {
   1176             // expected
   1177         }
   1178 
   1179         // Verify that outputConfiguration can be created with deferred surface with the same
   1180         // setting.
   1181         OutputConfiguration deferredPreviewConfigure = new OutputConfiguration(
   1182                 previewSize, SurfaceTexture.class);
   1183         deferredPreviewConfigure.addSurface(surfaces[0]);
   1184         assertTrue(String.format("Number of surfaces %d doesn't match expected value 1",
   1185                 deferredPreviewConfigure.getSurfaces().size()),
   1186                 deferredPreviewConfigure.getSurfaces().size() == 1);
   1187         assertEquals("Surface 0 in OutputConfiguration doesn't match input",
   1188                 deferredPreviewConfigure.getSurfaces().get(0), surfaces[0]);
   1189 
   1190         // Verify that outputConfiguration throws exception if deferred surface and non-deferred
   1191         // surface properties don't match
   1192         try {
   1193             configuration = new OutputConfiguration(previewSize, SurfaceTexture.class);
   1194             configuration.addSurface(imageReader.getSurface());
   1195             fail("No error for invalid output config created deferred class with different type");
   1196         } catch (IllegalArgumentException e) {
   1197             // expected;
   1198         }
   1199     }
   1200 
   1201     private void testSharedSurfacesCaptureSessionByCamera(String cameraId) throws Exception {
   1202         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
   1203         CameraPreviewListener[] previewListener = new CameraPreviewListener[2];
   1204         SurfaceTexture[] previewTexture = new SurfaceTexture[2];
   1205         Surface[] surfaces = new Surface[2];
   1206 
   1207         // Create surface textures with the same size
   1208         for (int i = 0; i < 2; i++) {
   1209             previewListener[i] = new CameraPreviewListener();
   1210             mTextureView[i].setSurfaceTextureListener(previewListener[i]);
   1211             previewTexture[i] = getAvailableSurfaceTexture(
   1212                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
   1213             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
   1214             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
   1215             // Correct the preview display rotation.
   1216             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
   1217             surfaces[i] = new Surface(previewTexture[i]);
   1218         }
   1219 
   1220         // Create shared outputs for the two surface textures
   1221         OutputConfiguration surfaceSharedOutput = new OutputConfiguration(
   1222                 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]);
   1223         surfaceSharedOutput.enableSurfaceSharing();
   1224         surfaceSharedOutput.addSurface(surfaces[1]);
   1225 
   1226         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
   1227         outputConfigurations.add(surfaceSharedOutput);
   1228 
   1229         startPreviewWithConfigs(cameraId, outputConfigurations, null);
   1230 
   1231         for (int i = 0; i < 2; i++) {
   1232             boolean previewDone =
   1233                     previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1234             assertTrue("Unable to start preview " + i, previewDone);
   1235             mTextureView[i].setSurfaceTextureListener(null);
   1236         }
   1237 
   1238         SystemClock.sleep(PREVIEW_TIME_MS);
   1239 
   1240         stopPreview(cameraId);
   1241     }
   1242 
   1243     private void testSharedDeferredSurfacesByCamera(String cameraId) throws Exception {
   1244         Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
   1245         CameraPreviewListener[] previewListener = new CameraPreviewListener[2];
   1246         SurfaceTexture[] previewTexture = new SurfaceTexture[2];
   1247         Surface[] surfaces = new Surface[2];
   1248 
   1249         // Create surface textures with the same size
   1250         for (int i = 0; i < 2; i++) {
   1251             previewListener[i] = new CameraPreviewListener();
   1252             mTextureView[i].setSurfaceTextureListener(previewListener[i]);
   1253             previewTexture[i] = getAvailableSurfaceTexture(
   1254                     WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]);
   1255             assertNotNull("Unable to get preview surface texture", previewTexture[i]);
   1256             previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
   1257             // Correct the preview display rotation.
   1258             updatePreviewDisplayRotation(previewSize, mTextureView[i]);
   1259             surfaces[i] = new Surface(previewTexture[i]);
   1260         }
   1261 
   1262         //
   1263         // Create deferred outputConfiguration, addSurface, createCaptureSession, addSurface, and
   1264         // finalizeOutputConfigurations.
   1265         //
   1266 
   1267         OutputConfiguration surfaceSharedOutput = new OutputConfiguration(
   1268                 previewSize, SurfaceTexture.class);
   1269         surfaceSharedOutput.enableSurfaceSharing();
   1270         surfaceSharedOutput.addSurface(surfaces[0]);
   1271 
   1272         List<OutputConfiguration> outputConfigurations = new ArrayList<>();
   1273         outputConfigurations.add(surfaceSharedOutput);
   1274 
   1275         // Run preview with one surface, and verify at least one frame is received.
   1276         startPreviewWithConfigs(cameraId, outputConfigurations, null);
   1277         boolean previewDone =
   1278                 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1279         assertTrue("Unable to start preview 0", previewDone);
   1280 
   1281         SystemClock.sleep(PREVIEW_TIME_MS);
   1282 
   1283         // Add deferred surface to the output configuration
   1284         surfaceSharedOutput.addSurface(surfaces[1]);
   1285         List<OutputConfiguration> deferredConfigs = new ArrayList<OutputConfiguration>();
   1286         deferredConfigs.add(surfaceSharedOutput);
   1287 
   1288         // Run preview with both surfaces, and verify at least one frame is received for each
   1289         // surface.
   1290         finalizeOutputConfigs(cameraId, deferredConfigs, null);
   1291         previewDone =
   1292                 previewListener[1].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1293         assertTrue("Unable to start preview 1", previewDone);
   1294 
   1295         stopPreview(cameraId);
   1296 
   1297         previewListener[0].reset();
   1298         previewListener[1].reset();
   1299 
   1300         //
   1301         // Create outputConfiguration with a surface, createCaptureSession, addSurface, and
   1302         // finalizeOutputConfigurations.
   1303         //
   1304 
   1305         surfaceSharedOutput = new OutputConfiguration(
   1306                 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]);
   1307         surfaceSharedOutput.enableSurfaceSharing();
   1308         outputConfigurations.clear();
   1309         outputConfigurations.add(surfaceSharedOutput);
   1310 
   1311         startPreviewWithConfigs(cameraId, outputConfigurations, null);
   1312         previewDone =
   1313                 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1314         assertTrue("Unable to start preview 0", previewDone);
   1315 
   1316         // Add deferred surface to the output configuration, and continue running preview
   1317         surfaceSharedOutput.addSurface(surfaces[1]);
   1318         deferredConfigs.clear();
   1319         deferredConfigs.add(surfaceSharedOutput);
   1320         finalizeOutputConfigs(cameraId, deferredConfigs, null);
   1321         previewDone =
   1322                 previewListener[1].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1323         assertTrue("Unable to start preview 1", previewDone);
   1324 
   1325         SystemClock.sleep(PREVIEW_TIME_MS);
   1326         stopPreview(cameraId);
   1327 
   1328         previewListener[0].reset();
   1329         previewListener[1].reset();
   1330 
   1331         //
   1332         // Create deferred output configuration, createCaptureSession, addSurface, addSurface, and
   1333         // finalizeOutputConfigurations.
   1334 
   1335         surfaceSharedOutput = new OutputConfiguration(
   1336                 previewSize, SurfaceTexture.class);
   1337         surfaceSharedOutput.enableSurfaceSharing();
   1338         outputConfigurations.clear();
   1339         outputConfigurations.add(surfaceSharedOutput);
   1340         createSessionWithConfigs(cameraId, outputConfigurations);
   1341 
   1342         // Add 2 surfaces to the output configuration, and run preview
   1343         surfaceSharedOutput.addSurface(surfaces[0]);
   1344         surfaceSharedOutput.addSurface(surfaces[1]);
   1345         deferredConfigs.clear();
   1346         deferredConfigs.add(surfaceSharedOutput);
   1347         finalizeOutputConfigs(cameraId, deferredConfigs, null);
   1348         for (int i = 0; i < 2; i++) {
   1349             previewDone =
   1350                     previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE);
   1351             assertTrue("Unable to start preview " + i, previewDone);
   1352         }
   1353 
   1354         SystemClock.sleep(PREVIEW_TIME_MS);
   1355         stopPreview(cameraId);
   1356     }
   1357 
   1358     private final class SimpleImageListener implements ImageReader.OnImageAvailableListener {
   1359         private final ConditionVariable imageAvailable = new ConditionVariable();
   1360         @Override
   1361         public void onImageAvailable(ImageReader reader) {
   1362             imageAvailable.open();
   1363         }
   1364 
   1365         public void waitForAnyImageAvailable(long timeout) {
   1366             if (imageAvailable.block(timeout)) {
   1367                 imageAvailable.close();
   1368             } else {
   1369                 fail("wait for image available timed out after " + timeout + "ms");
   1370             }
   1371         }
   1372     }
   1373 }
   1374