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