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