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