1 /* 2 * Copyright 2020 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 org.mockito.ArgumentMatchers.anyBoolean; 20 import static org.mockito.Matchers.any; 21 import static org.mockito.Matchers.anyInt; 22 import static org.mockito.Matchers.anyLong; 23 import static org.mockito.Matchers.eq; 24 import static org.mockito.Mockito.atLeastOnce; 25 import static org.mockito.Mockito.mock; 26 import static org.mockito.Mockito.reset; 27 import static org.mockito.Mockito.timeout; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 31 import com.android.compatibility.common.util.DeviceReportLog; 32 import com.android.compatibility.common.util.ResultType; 33 import com.android.compatibility.common.util.ResultUnit; 34 import com.android.compatibility.common.util.Stat; 35 import com.android.ex.camera2.blocking.BlockingSessionCallback; 36 import com.android.ex.camera2.blocking.BlockingExtensionSessionCallback; 37 import com.android.ex.camera2.blocking.BlockingStateCallback; 38 import com.android.ex.camera2.exceptions.TimeoutRuntimeException; 39 import com.android.ex.camera2.pos.AutoFocusStateMachine; 40 41 import android.graphics.ImageFormat; 42 import android.graphics.Rect; 43 import android.graphics.SurfaceTexture; 44 import android.hardware.HardwareBuffer; 45 import android.hardware.camera2.CameraCaptureSession; 46 import android.hardware.camera2.CameraDevice; 47 import android.hardware.camera2.CameraExtensionCharacteristics; 48 import android.hardware.camera2.CameraExtensionSession; 49 import android.hardware.camera2.CameraMetadata; 50 import android.hardware.camera2.CaptureRequest; 51 import android.hardware.camera2.CaptureResult; 52 import android.hardware.camera2.TotalCaptureResult; 53 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 54 import android.hardware.camera2.cts.helpers.StaticMetadata; 55 import android.hardware.camera2.cts.testcases.Camera2AndroidTestRule; 56 import android.hardware.camera2.params.ExtensionSessionConfiguration; 57 import android.hardware.camera2.params.MeteringRectangle; 58 import android.hardware.camera2.params.OutputConfiguration; 59 import android.hardware.camera2.params.SessionConfiguration; 60 import android.media.ExifInterface; 61 import android.media.Image; 62 import android.media.ImageReader; 63 import android.os.SystemClock; 64 import android.util.Range; 65 import android.util.Size; 66 67 import static android.hardware.camera2.cts.CameraTestUtils.*; 68 import static android.hardware.cts.helpers.CameraUtils.*; 69 70 import android.util.Log; 71 import android.view.Surface; 72 import android.view.TextureView; 73 74 import androidx.test.platform.app.InstrumentationRegistry; 75 import androidx.test.rule.ActivityTestRule; 76 77 import org.junit.Rule; 78 import org.junit.Test; 79 import org.junit.runner.RunWith; 80 import org.junit.runners.Parameterized; 81 82 import java.io.IOException; 83 import java.util.ArrayList; 84 import java.util.Arrays; 85 import java.util.HashSet; 86 import java.util.List; 87 import java.util.Set; 88 import java.util.stream.Collectors; 89 90 @RunWith(Parameterized.class) 91 public class CameraExtensionSessionTest extends Camera2ParameterizedTestCase { 92 private static final String TAG = "CameraExtensionSessionTest"; 93 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 94 private static final long WAIT_FOR_COMMAND_TO_COMPLETE_MS = 5000; 95 private static final long REPEATING_REQUEST_TIMEOUT_MS = 5000; 96 private static final int MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS = 10000; 97 private static final float ZOOM_ERROR_MARGIN = 0.05f; 98 99 private SurfaceTexture mSurfaceTexture = null; 100 private Camera2AndroidTestRule mTestRule = null; 101 private CameraErrorCollector mCollector = null; 102 103 private DeviceReportLog mReportLog; 104 105 @Override setUp()106 public void setUp() throws Exception { 107 super.setUp(); 108 mTestRule = new Camera2AndroidTestRule(mContext); 109 mTestRule.before(); 110 mCollector = new CameraErrorCollector(); 111 } 112 113 @Override tearDown()114 public void tearDown() throws Exception { 115 if (mTestRule != null) { 116 mTestRule.after(); 117 } 118 if (mSurfaceTexture != null) { 119 mSurfaceTexture.release(); 120 mSurfaceTexture = null; 121 } 122 if (mCollector != null) { 123 try { 124 mCollector.verify(); 125 } catch (Throwable e) { 126 throw new Exception(e.getMessage()); 127 } 128 } 129 super.tearDown(); 130 } 131 132 @Rule 133 public ActivityTestRule<CameraExtensionTestActivity> mActivityRule = 134 new ActivityTestRule<>(CameraExtensionTestActivity.class); 135 updatePreviewSurfaceTexture()136 private void updatePreviewSurfaceTexture() { 137 if (mSurfaceTexture != null) { 138 return; 139 } 140 141 TextureView textureView = mActivityRule.getActivity().getTextureView(); 142 mSurfaceTexture = getAvailableSurfaceTexture(WAIT_FOR_COMMAND_TO_COMPLETE_MS, textureView); 143 assertNotNull("Failed to acquire valid preview surface texture!", mSurfaceTexture); 144 } 145 146 // Verify that camera extension sessions can be created and closed as expected. 147 @Test testBasicExtensionLifecycle()148 public void testBasicExtensionLifecycle() throws Exception { 149 for (String id : mCameraIdsUnderTest) { 150 StaticMetadata staticMeta = 151 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 152 if (!staticMeta.isColorOutputSupported()) { 153 continue; 154 } 155 updatePreviewSurfaceTexture(); 156 CameraExtensionCharacteristics extensionChars = 157 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 158 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 159 for (Integer extension : supportedExtensions) { 160 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 161 mSurfaceTexture.getClass()); 162 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 163 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), maxSize.getHeight()); 164 OutputConfiguration outputConfig = new OutputConfiguration( 165 new Surface(mSurfaceTexture)); 166 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 167 outputConfigs.add(outputConfig); 168 169 BlockingExtensionSessionCallback sessionListener = 170 new BlockingExtensionSessionCallback( 171 mock(CameraExtensionSession.StateCallback.class)); 172 ExtensionSessionConfiguration configuration = 173 new ExtensionSessionConfiguration(extension, outputConfigs, 174 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 175 176 try { 177 mTestRule.openDevice(id); 178 CameraDevice camera = mTestRule.getCamera(); 179 camera.createExtensionSession(configuration); 180 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 181 SESSION_CONFIGURE_TIMEOUT_MS); 182 183 extensionSession.close(); 184 sessionListener.getStateWaiter().waitForState( 185 BlockingExtensionSessionCallback.SESSION_CLOSED, 186 SESSION_CLOSE_TIMEOUT_MS); 187 } finally { 188 mTestRule.closeDevice(id); 189 } 190 } 191 } 192 } 193 194 // Verify that regular camera sessions close as expected after creating a camera extension 195 // session. 196 @Test testCloseCaptureSession()197 public void testCloseCaptureSession() throws Exception { 198 for (String id : mCameraIdsUnderTest) { 199 StaticMetadata staticMeta = 200 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 201 if (!staticMeta.isColorOutputSupported()) { 202 continue; 203 } 204 updatePreviewSurfaceTexture(); 205 CameraExtensionCharacteristics extensionChars = 206 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 207 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 208 for (Integer extension : supportedExtensions) { 209 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 210 mSurfaceTexture.getClass()); 211 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 212 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), maxSize.getHeight()); 213 Surface repeatingSurface = new Surface(mSurfaceTexture); 214 OutputConfiguration textureOutput = new OutputConfiguration(repeatingSurface); 215 List<OutputConfiguration> outputs = new ArrayList<>(); 216 outputs.add(textureOutput); 217 BlockingSessionCallback regularSessionListener = new BlockingSessionCallback( 218 mock(CameraCaptureSession.StateCallback.class)); 219 SessionConfiguration regularConfiguration = new SessionConfiguration( 220 SessionConfiguration.SESSION_REGULAR, outputs, 221 new HandlerExecutor(mTestRule.getHandler()), regularSessionListener); 222 223 BlockingExtensionSessionCallback sessionListener = 224 new BlockingExtensionSessionCallback(mock( 225 CameraExtensionSession.StateCallback.class)); 226 ExtensionSessionConfiguration configuration = 227 new ExtensionSessionConfiguration(extension, outputs, 228 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 229 230 try { 231 mTestRule.openDevice(id); 232 mTestRule.getCamera().createCaptureSession(regularConfiguration); 233 234 CameraCaptureSession session = 235 regularSessionListener 236 .waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS); 237 assertNotNull(session); 238 239 CameraDevice camera = mTestRule.getCamera(); 240 camera.createExtensionSession(configuration); 241 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 242 SESSION_CONFIGURE_TIMEOUT_MS); 243 assertNotNull(extensionSession); 244 245 regularSessionListener.getStateWaiter().waitForState( 246 BlockingExtensionSessionCallback.SESSION_CLOSED, 247 SESSION_CLOSE_TIMEOUT_MS); 248 249 extensionSession.close(); 250 sessionListener.getStateWaiter().waitForState( 251 BlockingExtensionSessionCallback.SESSION_CLOSED, 252 SESSION_CLOSE_TIMEOUT_MS); 253 } finally { 254 mTestRule.closeDevice(id); 255 } 256 } 257 } 258 } 259 260 // Verify that camera extension sessions close as expected when creating a regular capture 261 // session. 262 @Test testCloseExtensionSession()263 public void testCloseExtensionSession() throws Exception { 264 for (String id : mCameraIdsUnderTest) { 265 StaticMetadata staticMeta = 266 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 267 if (!staticMeta.isColorOutputSupported()) { 268 continue; 269 } 270 updatePreviewSurfaceTexture(); 271 CameraExtensionCharacteristics extensionChars = 272 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 273 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 274 for (Integer extension : supportedExtensions) { 275 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 276 mSurfaceTexture.getClass()); 277 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 278 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), maxSize.getHeight()); 279 Surface surface = new Surface(mSurfaceTexture); 280 OutputConfiguration textureOutput = new OutputConfiguration(surface); 281 List<OutputConfiguration> outputs = new ArrayList<>(); 282 outputs.add(textureOutput); 283 BlockingSessionCallback regularSessionListener = new BlockingSessionCallback( 284 mock(CameraCaptureSession.StateCallback.class)); 285 SessionConfiguration regularConfiguration = new SessionConfiguration( 286 SessionConfiguration.SESSION_REGULAR, outputs, 287 new HandlerExecutor(mTestRule.getHandler()), regularSessionListener); 288 289 BlockingExtensionSessionCallback sessionListener = 290 new BlockingExtensionSessionCallback(mock( 291 CameraExtensionSession.StateCallback.class)); 292 ExtensionSessionConfiguration configuration = 293 new ExtensionSessionConfiguration(extension, outputs, 294 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 295 296 try { 297 mTestRule.openDevice(id); 298 CameraDevice camera = mTestRule.getCamera(); 299 camera.createExtensionSession(configuration); 300 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 301 SESSION_CONFIGURE_TIMEOUT_MS); 302 assertNotNull(extensionSession); 303 304 mTestRule.getCamera().createCaptureSession(regularConfiguration); 305 sessionListener.getStateWaiter().waitForState( 306 BlockingExtensionSessionCallback.SESSION_CLOSED, 307 SESSION_CLOSE_TIMEOUT_MS); 308 309 CameraCaptureSession session = 310 regularSessionListener.waitAndGetSession( 311 SESSION_CONFIGURE_TIMEOUT_MS); 312 session.close(); 313 regularSessionListener.getStateWaiter().waitForState( 314 BlockingSessionCallback.SESSION_CLOSED, SESSION_CLOSE_TIMEOUT_MS); 315 } finally { 316 mTestRule.closeDevice(id); 317 } 318 } 319 } 320 } 321 322 // Verify camera device query 323 @Test testGetDevice()324 public void testGetDevice() throws Exception { 325 for (String id : mCameraIdsUnderTest) { 326 StaticMetadata staticMeta = 327 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 328 if (!staticMeta.isColorOutputSupported()) { 329 continue; 330 } 331 updatePreviewSurfaceTexture(); 332 CameraExtensionCharacteristics extensionChars = 333 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 334 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 335 for (Integer extension : supportedExtensions) { 336 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 337 mSurfaceTexture.getClass()); 338 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 339 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), maxSize.getHeight()); 340 OutputConfiguration privateOutput = new OutputConfiguration( 341 new Surface(mSurfaceTexture)); 342 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 343 outputConfigs.add(privateOutput); 344 345 BlockingExtensionSessionCallback sessionListener = 346 new BlockingExtensionSessionCallback( 347 mock(CameraExtensionSession.StateCallback.class)); 348 ExtensionSessionConfiguration configuration = 349 new ExtensionSessionConfiguration(extension, outputConfigs, 350 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 351 352 try { 353 mTestRule.openDevice(id); 354 CameraDevice camera = mTestRule.getCamera(); 355 camera.createExtensionSession(configuration); 356 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 357 SESSION_CONFIGURE_TIMEOUT_MS); 358 359 assertEquals("Unexpected/Invalid camera device", mTestRule.getCamera(), 360 extensionSession.getDevice()); 361 } finally { 362 mTestRule.closeDevice(id); 363 } 364 365 try { 366 sessionListener.getStateWaiter().waitForState( 367 BlockingExtensionSessionCallback.SESSION_CLOSED, 368 SESSION_CLOSE_TIMEOUT_MS); 369 fail("should get TimeoutRuntimeException due to previously closed camera " 370 + "device"); 371 } catch (TimeoutRuntimeException e) { 372 // Expected, per API spec we should not receive any further session callbacks 373 // besides the device state 'onClosed' callback. 374 } 375 } 376 } 377 } 378 379 // Test case for repeating/stopRepeating on all supported extensions and expected state/capture 380 // callbacks. 381 @Test testRepeatingCapture()382 public void testRepeatingCapture() throws Exception { 383 for (String id : mCameraIdsUnderTest) { 384 StaticMetadata staticMeta = 385 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 386 if (!staticMeta.isColorOutputSupported()) { 387 continue; 388 } 389 updatePreviewSurfaceTexture(); 390 CameraExtensionCharacteristics extensionChars = 391 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 392 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 393 for (Integer extension : supportedExtensions) { 394 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 395 mSurfaceTexture.getClass()); 396 Size maxSize = 397 CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 398 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), 399 maxSize.getHeight()); 400 Surface texturedSurface = new Surface(mSurfaceTexture); 401 402 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 403 outputConfigs.add(new OutputConfiguration(texturedSurface)); 404 405 BlockingExtensionSessionCallback sessionListener = 406 new BlockingExtensionSessionCallback(mock( 407 CameraExtensionSession.StateCallback.class)); 408 ExtensionSessionConfiguration configuration = 409 new ExtensionSessionConfiguration(extension, outputConfigs, 410 new HandlerExecutor(mTestRule.getHandler()), 411 sessionListener); 412 413 boolean captureResultsSupported = 414 !extensionChars.getAvailableCaptureResultKeys(extension).isEmpty(); 415 416 try { 417 mTestRule.openDevice(id); 418 CameraDevice camera = mTestRule.getCamera(); 419 camera.createExtensionSession(configuration); 420 CameraExtensionSession extensionSession = 421 sessionListener.waitAndGetSession( 422 SESSION_CONFIGURE_TIMEOUT_MS); 423 assertNotNull(extensionSession); 424 425 CaptureRequest.Builder captureBuilder = 426 mTestRule.getCamera().createCaptureRequest( 427 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 428 captureBuilder.addTarget(texturedSurface); 429 CameraExtensionSession.ExtensionCaptureCallback captureCallbackMock = 430 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 431 SimpleCaptureCallback simpleCaptureCallback = 432 new SimpleCaptureCallback(captureCallbackMock, 433 extensionChars.getAvailableCaptureResultKeys(extension), 434 mCollector); 435 CaptureRequest request = captureBuilder.build(); 436 int sequenceId = extensionSession.setRepeatingRequest(request, 437 new HandlerExecutor(mTestRule.getHandler()), simpleCaptureCallback); 438 439 verify(captureCallbackMock, 440 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 441 .onCaptureStarted(eq(extensionSession), eq(request), anyLong()); 442 verify(captureCallbackMock, 443 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 444 .onCaptureProcessStarted(extensionSession, request); 445 if (captureResultsSupported) { 446 verify(captureCallbackMock, 447 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).atLeastOnce()) 448 .onCaptureResultAvailable(eq(extensionSession), eq(request), 449 any(TotalCaptureResult.class)); 450 } 451 452 extensionSession.stopRepeating(); 453 454 verify(captureCallbackMock, 455 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 456 .onCaptureSequenceCompleted(extensionSession, sequenceId); 457 458 verify(captureCallbackMock, times(0)) 459 .onCaptureSequenceAborted(any(CameraExtensionSession.class), 460 anyInt()); 461 462 extensionSession.close(); 463 464 sessionListener.getStateWaiter().waitForState( 465 BlockingExtensionSessionCallback.SESSION_CLOSED, 466 SESSION_CLOSE_TIMEOUT_MS); 467 468 assertTrue("The sum of onCaptureProcessStarted and onCaptureFailed" + 469 " callbacks must be greater or equal than the number of calls" + 470 " to onCaptureStarted!", 471 simpleCaptureCallback.getTotalFramesArrived() + 472 simpleCaptureCallback.getTotalFramesFailed() >= 473 simpleCaptureCallback.getTotalFramesStarted()); 474 assertTrue(String.format("The last repeating request surface timestamp " + 475 "%d must be less than or equal to the last " + 476 "onCaptureStarted " + 477 "timestamp %d", mSurfaceTexture.getTimestamp(), 478 simpleCaptureCallback.getLastTimestamp()), 479 mSurfaceTexture.getTimestamp() <= 480 simpleCaptureCallback.getLastTimestamp()); 481 } finally { 482 mTestRule.closeDevice(id); 483 texturedSurface.release(); 484 } 485 } 486 } 487 } 488 489 // Test case for multi-frame only capture on all supported extensions and expected state 490 // callbacks. Verify still frame output, measure the average capture latency and if possible 491 // ensure that the value is within the reported range. 492 @Test testMultiFrameCapture()493 public void testMultiFrameCapture() throws Exception { 494 final int IMAGE_COUNT = 10; 495 final int SUPPORTED_CAPTURE_OUTPUT_FORMATS[] = { 496 ImageFormat.YUV_420_888, 497 ImageFormat.JPEG 498 }; 499 for (String id : mCameraIdsUnderTest) { 500 StaticMetadata staticMeta = 501 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 502 if (!staticMeta.isColorOutputSupported()) { 503 continue; 504 } 505 updatePreviewSurfaceTexture(); 506 CameraExtensionCharacteristics extensionChars = 507 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 508 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 509 for (Integer extension : supportedExtensions) { 510 for (int captureFormat : SUPPORTED_CAPTURE_OUTPUT_FORMATS) { 511 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 512 captureFormat); 513 if (extensionSizes.isEmpty()) { 514 continue; 515 } 516 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 517 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(false, 518 1); 519 ImageReader extensionImageReader = CameraTestUtils.makeImageReader(maxSize, 520 captureFormat, /*maxImages*/ 1, imageListener, 521 mTestRule.getHandler()); 522 Surface imageReaderSurface = extensionImageReader.getSurface(); 523 OutputConfiguration readerOutput = new OutputConfiguration(imageReaderSurface); 524 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 525 outputConfigs.add(readerOutput); 526 527 BlockingExtensionSessionCallback sessionListener = 528 new BlockingExtensionSessionCallback(mock( 529 CameraExtensionSession.StateCallback.class)); 530 ExtensionSessionConfiguration configuration = 531 new ExtensionSessionConfiguration(extension, outputConfigs, 532 new HandlerExecutor(mTestRule.getHandler()), 533 sessionListener); 534 String streamName = "test_extension_capture"; 535 mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName); 536 mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE); 537 mReportLog.addValue("extension_id", extension, ResultType.NEUTRAL, 538 ResultUnit.NONE); 539 double[] captureTimes = new double[IMAGE_COUNT]; 540 boolean captureResultsSupported = 541 !extensionChars.getAvailableCaptureResultKeys(extension).isEmpty(); 542 543 try { 544 mTestRule.openDevice(id); 545 CameraDevice camera = mTestRule.getCamera(); 546 camera.createExtensionSession(configuration); 547 CameraExtensionSession extensionSession = 548 sessionListener.waitAndGetSession( 549 SESSION_CONFIGURE_TIMEOUT_MS); 550 assertNotNull(extensionSession); 551 552 CaptureRequest.Builder captureBuilder = 553 mTestRule.getCamera().createCaptureRequest( 554 CameraDevice.TEMPLATE_STILL_CAPTURE); 555 captureBuilder.addTarget(imageReaderSurface); 556 CameraExtensionSession.ExtensionCaptureCallback captureMockCallback = 557 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 558 SimpleCaptureCallback captureCallback = 559 new SimpleCaptureCallback(captureMockCallback, 560 extensionChars.getAvailableCaptureResultKeys(extension), 561 mCollector); 562 563 for (int i = 0; i < IMAGE_COUNT; i++) { 564 int jpegOrientation = (i * 90) % 360; // degrees [0..270] 565 if (captureFormat == ImageFormat.JPEG) { 566 captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, 567 jpegOrientation); 568 } 569 CaptureRequest request = captureBuilder.build(); 570 long startTimeMs = SystemClock.elapsedRealtime(); 571 int sequenceId = extensionSession.capture(request, 572 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 573 574 Image img = 575 imageListener.getImage(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS); 576 captureTimes[i] = SystemClock.elapsedRealtime() - startTimeMs; 577 if (captureFormat == ImageFormat.JPEG) { 578 verifyJpegOrientation(img, maxSize, jpegOrientation); 579 } else { 580 validateImage(img, maxSize.getWidth(), maxSize.getHeight(), 581 captureFormat, null); 582 } 583 Long imgTs = img.getTimestamp(); 584 img.close(); 585 586 verify(captureMockCallback, 587 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 588 .onCaptureStarted(eq(extensionSession), eq(request), eq(imgTs)); 589 verify(captureMockCallback, times(1)) 590 .onCaptureStarted(eq(extensionSession), eq(request), anyLong()); 591 verify(captureMockCallback, 592 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 593 .onCaptureProcessStarted(extensionSession, request); 594 verify(captureMockCallback, 595 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 596 .onCaptureSequenceCompleted(extensionSession, sequenceId); 597 if (captureResultsSupported) { 598 verify(captureMockCallback, 599 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 600 .onCaptureResultAvailable(eq(extensionSession), eq(request), 601 any(TotalCaptureResult.class)); 602 } 603 } 604 605 mReportLog.addValue("width", maxSize.getWidth(), ResultType.NEUTRAL, 606 ResultUnit.NONE); 607 mReportLog.addValue("height", maxSize.getHeight(), 608 ResultType.NEUTRAL, ResultUnit.NONE); 609 mReportLog.addValue("format", captureFormat, ResultType.NEUTRAL, 610 ResultUnit.NONE); 611 long avgCaptureLatency = (long) Stat.getAverage(captureTimes); 612 mReportLog.addValue("avg_latency", avgCaptureLatency, 613 ResultType.LOWER_BETTER, ResultUnit.MS); 614 615 verify(captureMockCallback, times(0)) 616 .onCaptureSequenceAborted(any(CameraExtensionSession.class), 617 anyInt()); 618 verify(captureMockCallback, times(0)) 619 .onCaptureFailed(any(CameraExtensionSession.class), 620 any(CaptureRequest.class)); 621 Range<Long> latencyRange = 622 extensionChars.getEstimatedCaptureLatencyRangeMillis(extension, 623 maxSize, captureFormat); 624 if (latencyRange != null) { 625 String msg = String.format("Camera [%s]: The measured average " 626 + "capture latency of %d ms. for extension type %d " 627 + "with image format: %d and size: %dx%d must be " 628 + "within the advertised range of [%d, %d] ms.", 629 id, avgCaptureLatency, extension, captureFormat, 630 maxSize.getWidth(), maxSize.getHeight(), 631 latencyRange.getLower(), latencyRange.getUpper()); 632 assertTrue(msg, latencyRange.contains(avgCaptureLatency)); 633 } 634 635 extensionSession.close(); 636 637 sessionListener.getStateWaiter().waitForState( 638 BlockingExtensionSessionCallback.SESSION_CLOSED, 639 SESSION_CLOSE_TIMEOUT_MS); 640 } finally { 641 mTestRule.closeDevice(id); 642 extensionImageReader.close(); 643 mReportLog.submit(InstrumentationRegistry.getInstrumentation()); 644 } 645 } 646 } 647 } 648 } 649 650 // Verify concurrent extension sessions behavior 651 @Test testConcurrentSessions()652 public void testConcurrentSessions() throws Exception { 653 Set<Set<String>> concurrentCameraIdSet = 654 mTestRule.getCameraManager().getConcurrentCameraIds(); 655 if (concurrentCameraIdSet.isEmpty()) { 656 return; 657 } 658 659 for (String id : mCameraIdsUnderTest) { 660 StaticMetadata staticMeta = 661 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 662 if (!staticMeta.isColorOutputSupported()) { 663 continue; 664 } 665 CameraExtensionCharacteristics extensionChars = 666 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 667 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 668 if (supportedExtensions.isEmpty()) { 669 continue; 670 } 671 672 Set<String> concurrentCameraIds = null; 673 for (Set<String> entry : concurrentCameraIdSet) { 674 if (entry.contains(id)) { 675 concurrentCameraIds = entry; 676 break; 677 } 678 } 679 if (concurrentCameraIds == null) { 680 continue; 681 } 682 683 String concurrentCameraId = null; 684 CameraExtensionCharacteristics concurrentExtensionChars = null; 685 for (String entry : concurrentCameraIds) { 686 if (entry.equals(id)) { 687 continue; 688 } 689 if (!(new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics( 690 entry))).isColorOutputSupported()) { 691 continue; 692 } 693 CameraExtensionCharacteristics chars = 694 mTestRule.getCameraManager().getCameraExtensionCharacteristics(entry); 695 if (chars.getSupportedExtensions().isEmpty()) { 696 continue; 697 } 698 concurrentCameraId = entry; 699 concurrentExtensionChars = chars; 700 break; 701 } 702 if ((concurrentCameraId == null) || (concurrentExtensionChars == null)) { 703 continue; 704 } 705 706 updatePreviewSurfaceTexture(); 707 int extensionId = supportedExtensions.get(0); 708 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extensionId, 709 mSurfaceTexture.getClass()); 710 Size maxSize = CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 711 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), maxSize.getHeight()); 712 OutputConfiguration outputConfig = new OutputConfiguration( 713 new Surface(mSurfaceTexture)); 714 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 715 outputConfigs.add(outputConfig); 716 717 BlockingExtensionSessionCallback sessionListener = 718 new BlockingExtensionSessionCallback( 719 mock(CameraExtensionSession.StateCallback.class)); 720 ExtensionSessionConfiguration configuration = 721 new ExtensionSessionConfiguration(extensionId, outputConfigs, 722 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 723 724 CameraDevice concurrentCameraDevice = null; 725 ImageReader extensionImageReader = null; 726 try { 727 mTestRule.openDevice(id); 728 CameraDevice camera = mTestRule.getCamera(); 729 camera.createExtensionSession(configuration); 730 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 731 SESSION_CONFIGURE_TIMEOUT_MS); 732 assertNotNull(extensionSession); 733 734 concurrentCameraDevice = CameraTestUtils.openCamera(mTestRule.getCameraManager(), 735 concurrentCameraId, new BlockingStateCallback(), mTestRule.getHandler()); 736 assertNotNull(concurrentCameraDevice); 737 int concurrentExtensionId = 738 concurrentExtensionChars.getSupportedExtensions().get(0); 739 List<Size> captureSizes = concurrentExtensionChars.getExtensionSupportedSizes( 740 concurrentExtensionId, mSurfaceTexture.getClass()); 741 assertFalse("No SurfaceTexture output supported", captureSizes.isEmpty()); 742 Size captureMaxSize = 743 CameraTestUtils.getMaxSize(captureSizes.toArray(new Size[0])); 744 745 extensionImageReader = ImageReader.newInstance( 746 captureMaxSize.getWidth(), captureMaxSize.getHeight(), ImageFormat.PRIVATE, 747 /*maxImages*/ 1, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); 748 Surface imageReaderSurface = extensionImageReader.getSurface(); 749 OutputConfiguration readerOutput = new OutputConfiguration(imageReaderSurface); 750 outputConfigs = new ArrayList<>(); 751 outputConfigs.add(readerOutput); 752 CameraExtensionSession.StateCallback mockSessionListener = 753 mock(CameraExtensionSession.StateCallback.class); 754 ExtensionSessionConfiguration concurrentConfiguration = 755 new ExtensionSessionConfiguration(concurrentExtensionId, outputConfigs, 756 new HandlerExecutor(mTestRule.getHandler()), 757 mockSessionListener); 758 concurrentCameraDevice.createExtensionSession(concurrentConfiguration); 759 // Trying to initialize multiple concurrent extension sessions is expected to fail 760 verify(mockSessionListener, timeout(SESSION_CONFIGURE_TIMEOUT_MS).times(1)) 761 .onConfigureFailed(any(CameraExtensionSession.class)); 762 verify(mockSessionListener, times(0)).onConfigured( 763 any(CameraExtensionSession.class)); 764 765 extensionSession.close(); 766 sessionListener.getStateWaiter().waitForState( 767 BlockingExtensionSessionCallback.SESSION_CLOSED, 768 SESSION_CLOSE_TIMEOUT_MS); 769 770 // Initialization of another extension session must now be possible 771 BlockingExtensionSessionCallback concurrentSessionListener = 772 new BlockingExtensionSessionCallback( 773 mock(CameraExtensionSession.StateCallback.class)); 774 concurrentConfiguration = new ExtensionSessionConfiguration(concurrentExtensionId, 775 outputConfigs, new HandlerExecutor(mTestRule.getHandler()), 776 concurrentSessionListener); 777 concurrentCameraDevice.createExtensionSession(concurrentConfiguration); 778 extensionSession = concurrentSessionListener.waitAndGetSession( 779 SESSION_CONFIGURE_TIMEOUT_MS); 780 assertNotNull(extensionSession); 781 extensionSession.close(); 782 concurrentSessionListener.getStateWaiter().waitForState( 783 BlockingExtensionSessionCallback.SESSION_CLOSED, 784 SESSION_CLOSE_TIMEOUT_MS); 785 } finally { 786 mTestRule.closeDevice(id); 787 if (concurrentCameraDevice != null) { 788 concurrentCameraDevice.close(); 789 } 790 if (extensionImageReader != null) { 791 extensionImageReader.close(); 792 } 793 } 794 } 795 } 796 797 // Test case combined repeating with multi frame capture on all supported extensions. 798 // Verify still frame output. 799 @Test testRepeatingAndCaptureCombined()800 public void testRepeatingAndCaptureCombined() throws Exception { 801 for (String id : mCameraIdsUnderTest) { 802 StaticMetadata staticMeta = 803 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 804 if (!staticMeta.isColorOutputSupported()) { 805 continue; 806 } 807 updatePreviewSurfaceTexture(); 808 CameraExtensionCharacteristics extensionChars = 809 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 810 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 811 for (Integer extension : supportedExtensions) { 812 int captureFormat = ImageFormat.JPEG; 813 List<Size> captureSizes = extensionChars.getExtensionSupportedSizes(extension, 814 captureFormat); 815 assertFalse("No Jpeg output supported", captureSizes.isEmpty()); 816 Size captureMaxSize = 817 CameraTestUtils.getMaxSize(captureSizes.toArray(new Size[0])); 818 819 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(false 820 , 1); 821 ImageReader extensionImageReader = CameraTestUtils.makeImageReader( 822 captureMaxSize, captureFormat, /*maxImages*/ 1, imageListener, 823 mTestRule.getHandler()); 824 Surface imageReaderSurface = extensionImageReader.getSurface(); 825 OutputConfiguration readerOutput = new OutputConfiguration(imageReaderSurface); 826 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 827 outputConfigs.add(readerOutput); 828 829 // Pick a supported preview/repeating size with aspect ratio close to the 830 // multi-frame capture size 831 List<Size> repeatingSizes = extensionChars.getExtensionSupportedSizes(extension, 832 mSurfaceTexture.getClass()); 833 Size maxRepeatingSize = 834 CameraTestUtils.getMaxSize(repeatingSizes.toArray(new Size[0])); 835 List<Size> previewSizes = getSupportedPreviewSizes(id, 836 mTestRule.getCameraManager(), 837 getPreviewSizeBound(mTestRule.getWindowManager(), PREVIEW_SIZE_BOUND)); 838 List<Size> supportedPreviewSizes = 839 previewSizes.stream().filter(repeatingSizes::contains).collect( 840 Collectors.toList()); 841 if (!supportedPreviewSizes.isEmpty()) { 842 float targetAr = 843 ((float) captureMaxSize.getWidth()) / captureMaxSize.getHeight(); 844 for (Size s : supportedPreviewSizes) { 845 float currentAr = ((float) s.getWidth()) / s.getHeight(); 846 if (Math.abs(targetAr - currentAr) < 0.01) { 847 maxRepeatingSize = s; 848 break; 849 } 850 } 851 } 852 853 boolean captureResultsSupported = 854 !extensionChars.getAvailableCaptureResultKeys(extension).isEmpty(); 855 856 mSurfaceTexture.setDefaultBufferSize(maxRepeatingSize.getWidth(), 857 maxRepeatingSize.getHeight()); 858 Surface texturedSurface = new Surface(mSurfaceTexture); 859 outputConfigs.add(new OutputConfiguration(texturedSurface)); 860 861 BlockingExtensionSessionCallback sessionListener = 862 new BlockingExtensionSessionCallback(mock( 863 CameraExtensionSession.StateCallback.class)); 864 ExtensionSessionConfiguration configuration = 865 new ExtensionSessionConfiguration(extension, outputConfigs, 866 new HandlerExecutor(mTestRule.getHandler()), 867 sessionListener); 868 try { 869 mTestRule.openDevice(id); 870 CameraDevice camera = mTestRule.getCamera(); 871 camera.createExtensionSession(configuration); 872 CameraExtensionSession extensionSession = 873 sessionListener.waitAndGetSession( 874 SESSION_CONFIGURE_TIMEOUT_MS); 875 assertNotNull(extensionSession); 876 877 CaptureRequest.Builder captureBuilder = 878 mTestRule.getCamera().createCaptureRequest( 879 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 880 captureBuilder.addTarget(texturedSurface); 881 CameraExtensionSession.ExtensionCaptureCallback repeatingCallbackMock = 882 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 883 SimpleCaptureCallback repeatingCaptureCallback = 884 new SimpleCaptureCallback(repeatingCallbackMock, 885 extensionChars.getAvailableCaptureResultKeys(extension), 886 mCollector); 887 CaptureRequest repeatingRequest = captureBuilder.build(); 888 int repeatingSequenceId = 889 extensionSession.setRepeatingRequest(repeatingRequest, 890 new HandlerExecutor(mTestRule.getHandler()), 891 repeatingCaptureCallback); 892 893 Thread.sleep(REPEATING_REQUEST_TIMEOUT_MS); 894 895 verify(repeatingCallbackMock, atLeastOnce()) 896 .onCaptureStarted(eq(extensionSession), eq(repeatingRequest), 897 anyLong()); 898 verify(repeatingCallbackMock, atLeastOnce()) 899 .onCaptureProcessStarted(extensionSession, repeatingRequest); 900 if (captureResultsSupported) { 901 verify(repeatingCallbackMock, 902 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).atLeastOnce()) 903 .onCaptureResultAvailable(eq(extensionSession), 904 eq(repeatingRequest), any(TotalCaptureResult.class)); 905 } 906 907 captureBuilder = mTestRule.getCamera().createCaptureRequest( 908 android.hardware.camera2.CameraDevice.TEMPLATE_STILL_CAPTURE); 909 captureBuilder.addTarget(imageReaderSurface); 910 CameraExtensionSession.ExtensionCaptureCallback captureCallback = 911 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 912 913 CaptureRequest captureRequest = captureBuilder.build(); 914 int captureSequenceId = extensionSession.capture(captureRequest, 915 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 916 917 Image img = 918 imageListener.getImage(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS); 919 validateImage(img, captureMaxSize.getWidth(), 920 captureMaxSize.getHeight(), captureFormat, null); 921 Long imgTs = img.getTimestamp(); 922 img.close(); 923 924 verify(captureCallback, times(1)) 925 .onCaptureStarted(eq(extensionSession), eq(captureRequest), eq(imgTs)); 926 verify(captureCallback, timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 927 .onCaptureProcessStarted(extensionSession, captureRequest); 928 if (captureResultsSupported) { 929 verify(captureCallback, 930 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 931 .onCaptureResultAvailable(eq(extensionSession), 932 eq(captureRequest), any(TotalCaptureResult.class)); 933 } 934 verify(captureCallback, timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 935 .onCaptureSequenceCompleted(extensionSession, 936 captureSequenceId); 937 verify(captureCallback, times(0)) 938 .onCaptureSequenceAborted(any(CameraExtensionSession.class), 939 anyInt()); 940 verify(captureCallback, times(0)) 941 .onCaptureFailed(any(CameraExtensionSession.class), 942 any(CaptureRequest.class)); 943 944 extensionSession.stopRepeating(); 945 946 verify(repeatingCallbackMock, 947 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 948 .onCaptureSequenceCompleted(extensionSession, repeatingSequenceId); 949 950 verify(repeatingCallbackMock, times(0)) 951 .onCaptureSequenceAborted(any(CameraExtensionSession.class), 952 anyInt()); 953 954 extensionSession.close(); 955 956 sessionListener.getStateWaiter().waitForState( 957 BlockingExtensionSessionCallback.SESSION_CLOSED, 958 SESSION_CLOSE_TIMEOUT_MS); 959 960 assertTrue("The sum of onCaptureProcessStarted and onCaptureFailed" + 961 " callbacks must be greater or equal than the number of calls" + 962 " to onCaptureStarted!", 963 repeatingCaptureCallback.getTotalFramesArrived() + 964 repeatingCaptureCallback.getTotalFramesFailed() >= 965 repeatingCaptureCallback.getTotalFramesStarted()); 966 assertTrue(String.format("The last repeating request surface timestamp " + 967 "%d must be less than or equal to the last " + 968 "onCaptureStarted " + 969 "timestamp %d", mSurfaceTexture.getTimestamp(), 970 repeatingCaptureCallback.getLastTimestamp()), 971 mSurfaceTexture.getTimestamp() <= 972 repeatingCaptureCallback.getLastTimestamp()); 973 974 } finally { 975 mTestRule.closeDevice(id); 976 texturedSurface.release(); 977 extensionImageReader.close(); 978 } 979 } 980 } 981 } 982 verifyJpegOrientation(Image img, Size jpegSize, int requestedOrientation)983 private void verifyJpegOrientation(Image img, Size jpegSize, int requestedOrientation) 984 throws IOException { 985 byte[] blobBuffer = getDataFromImage(img); 986 String blobFilename = mTestRule.getDebugFileNameBase() + "/verifyJpegKeys.jpeg"; 987 dumpFile(blobFilename, blobBuffer); 988 ExifInterface exif = new ExifInterface(blobFilename); 989 int exifWidth = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, /*defaultValue*/0); 990 int exifHeight = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, /*defaultValue*/0); 991 Size exifSize = new Size(exifWidth, exifHeight); 992 int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 993 /*defaultValue*/ ExifInterface.ORIENTATION_UNDEFINED); 994 final int ORIENTATION_MIN = ExifInterface.ORIENTATION_UNDEFINED; 995 final int ORIENTATION_MAX = ExifInterface.ORIENTATION_ROTATE_270; 996 assertTrue(String.format("Exif orientation must be in range of [%d, %d]", 997 ORIENTATION_MIN, ORIENTATION_MAX), 998 exifOrientation >= ORIENTATION_MIN && exifOrientation <= ORIENTATION_MAX); 999 1000 /** 1001 * Device captured image doesn't respect the requested orientation, 1002 * which means it rotates the image buffer physically. Then we 1003 * should swap the exif width/height accordingly to compare. 1004 */ 1005 boolean deviceRotatedImage = exifOrientation == ExifInterface.ORIENTATION_UNDEFINED; 1006 1007 if (deviceRotatedImage) { 1008 // Case 1. 1009 boolean needSwap = (requestedOrientation % 180 == 90); 1010 if (needSwap) { 1011 exifSize = new Size(exifHeight, exifWidth); 1012 } 1013 } else { 1014 // Case 2. 1015 assertEquals("Exif orientation should match requested orientation", 1016 requestedOrientation, getExifOrientationInDegree(exifOrientation)); 1017 } 1018 1019 assertEquals("Exif size should match jpeg capture size", jpegSize, exifSize); 1020 } 1021 getExifOrientationInDegree(int exifOrientation)1022 private static int getExifOrientationInDegree(int exifOrientation) { 1023 switch (exifOrientation) { 1024 case ExifInterface.ORIENTATION_NORMAL: 1025 return 0; 1026 case ExifInterface.ORIENTATION_ROTATE_90: 1027 return 90; 1028 case ExifInterface.ORIENTATION_ROTATE_180: 1029 return 180; 1030 case ExifInterface.ORIENTATION_ROTATE_270: 1031 return 270; 1032 default: 1033 fail("It is impossible to get non 0, 90, 180, 270 degress exif" + 1034 "info based on the request orientation range"); 1035 return -1; 1036 } 1037 } 1038 1039 public static class SimpleCaptureCallback 1040 extends CameraExtensionSession.ExtensionCaptureCallback { 1041 private long mLastTimestamp = -1; 1042 private int mNumFramesArrived = 0; 1043 private int mNumFramesStarted = 0; 1044 private int mNumFramesFailed = 0; 1045 private boolean mNonIncreasingTimestamps = false; 1046 private HashSet<Long> mExpectedResultTimestamps = new HashSet<>(); 1047 private final CameraExtensionSession.ExtensionCaptureCallback mProxy; 1048 private final AutoFocusStateMachine mAFStateMachine; 1049 private final FlashStateListener mFlashStateListener; 1050 private final AutoExposureStateListener mAEStateListener; 1051 private final HashSet<CaptureResult.Key> mSupportedResultKeys; 1052 private final CameraErrorCollector mCollector; 1053 private final boolean mPerFrameControl; 1054 SimpleCaptureCallback(CameraExtensionSession.ExtensionCaptureCallback proxy, Set<CaptureResult.Key> supportedResultKeys, CameraErrorCollector errorCollector)1055 public SimpleCaptureCallback(CameraExtensionSession.ExtensionCaptureCallback proxy, 1056 Set<CaptureResult.Key> supportedResultKeys, CameraErrorCollector errorCollector) { 1057 this(proxy, supportedResultKeys, errorCollector, null /*afListener*/, 1058 null /*flashState*/, null /*aeState*/, false /*perFrameControl*/); 1059 } 1060 SimpleCaptureCallback(CameraExtensionSession.ExtensionCaptureCallback proxy, Set<CaptureResult.Key> supportedResultKeys, CameraErrorCollector errorCollector, AutoFocusStateMachine afState, FlashStateListener flashState, AutoExposureStateListener aeState, boolean perFrameControl)1061 public SimpleCaptureCallback(CameraExtensionSession.ExtensionCaptureCallback proxy, 1062 Set<CaptureResult.Key> supportedResultKeys, CameraErrorCollector errorCollector, 1063 AutoFocusStateMachine afState, FlashStateListener flashState, 1064 AutoExposureStateListener aeState, boolean perFrameControl) { 1065 mProxy = proxy; 1066 mSupportedResultKeys = new HashSet<>(supportedResultKeys); 1067 mCollector = errorCollector; 1068 mAFStateMachine = afState; 1069 mFlashStateListener = flashState; 1070 mAEStateListener = aeState; 1071 mPerFrameControl = perFrameControl; 1072 } 1073 1074 @Override onCaptureStarted(CameraExtensionSession session, CaptureRequest request, long timestamp)1075 public void onCaptureStarted(CameraExtensionSession session, 1076 CaptureRequest request, long timestamp) { 1077 mExpectedResultTimestamps.add(timestamp); 1078 if (timestamp < mLastTimestamp) { 1079 mNonIncreasingTimestamps = true; 1080 } 1081 mLastTimestamp = timestamp; 1082 mNumFramesStarted++; 1083 if (mProxy != null) { 1084 mProxy.onCaptureStarted(session, request, timestamp); 1085 } 1086 } 1087 1088 @Override onCaptureProcessStarted(CameraExtensionSession session, CaptureRequest request)1089 public void onCaptureProcessStarted(CameraExtensionSession session, 1090 CaptureRequest request) { 1091 mNumFramesArrived++; 1092 if (mProxy != null) { 1093 mProxy.onCaptureProcessStarted(session, request); 1094 } 1095 } 1096 1097 @Override onCaptureFailed(CameraExtensionSession session, CaptureRequest request)1098 public void onCaptureFailed(CameraExtensionSession session, 1099 CaptureRequest request) { 1100 mNumFramesFailed++; 1101 if (mProxy != null) { 1102 mProxy.onCaptureFailed(session, request); 1103 } 1104 } 1105 1106 @Override onCaptureSequenceAborted(CameraExtensionSession session, int sequenceId)1107 public void onCaptureSequenceAborted(CameraExtensionSession session, 1108 int sequenceId) { 1109 if (mProxy != null) { 1110 mProxy.onCaptureSequenceAborted(session, sequenceId); 1111 } 1112 } 1113 1114 @Override onCaptureSequenceCompleted(CameraExtensionSession session, int sequenceId)1115 public void onCaptureSequenceCompleted(CameraExtensionSession session, 1116 int sequenceId) { 1117 if (mProxy != null) { 1118 mProxy.onCaptureSequenceCompleted(session, sequenceId); 1119 } 1120 } 1121 1122 @Override onCaptureResultAvailable(CameraExtensionSession session, CaptureRequest request, TotalCaptureResult result)1123 public void onCaptureResultAvailable(CameraExtensionSession session, 1124 CaptureRequest request, TotalCaptureResult result) { 1125 final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f; 1126 if (mSupportedResultKeys.isEmpty()) { 1127 mCollector.addMessage("Capture results not supported, but " + 1128 "onCaptureResultAvailable still got triggered!"); 1129 return; 1130 } 1131 1132 List<CaptureResult.Key<?>> resultKeys = result.getKeys(); 1133 for (CaptureResult.Key<?> resultKey : resultKeys) { 1134 mCollector.expectTrue("Capture result " + resultKey + " is not among the" 1135 + " supported result keys!", mSupportedResultKeys.contains(resultKey)); 1136 } 1137 1138 Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP); 1139 assertNotNull(timeStamp); 1140 assertTrue("Capture result sensor timestamp: " + timeStamp + " must match " 1141 + " with the timestamp passed to onCaptureStarted!", 1142 mExpectedResultTimestamps.contains(timeStamp)); 1143 1144 Integer jpegOrientation = request.get(CaptureRequest.JPEG_ORIENTATION); 1145 if (jpegOrientation != null) { 1146 Integer resultJpegOrientation = result.get(CaptureResult.JPEG_ORIENTATION); 1147 mCollector.expectTrue("Request Jpeg orientation: " + jpegOrientation + 1148 " doesn't match with result: " + resultJpegOrientation, 1149 jpegOrientation.equals(resultJpegOrientation)); 1150 } 1151 1152 Byte jpegQuality = request.get(CaptureRequest.JPEG_QUALITY); 1153 if (jpegQuality != null) { 1154 Byte resultJpegQuality = result.get(CaptureResult.JPEG_QUALITY); 1155 mCollector.expectTrue("Request Jpeg quality: " + jpegQuality + 1156 " doesn't match with result: " + resultJpegQuality, 1157 jpegQuality.equals(resultJpegQuality)); 1158 } 1159 1160 if (resultKeys.contains(CaptureResult.CONTROL_ZOOM_RATIO) && mPerFrameControl) { 1161 Float zoomRatio = request.get(CaptureRequest.CONTROL_ZOOM_RATIO); 1162 if (zoomRatio != null) { 1163 Float resultZoomRatio = result.get(CaptureResult.CONTROL_ZOOM_RATIO); 1164 mCollector.expectTrue( 1165 String.format("Request and result zoom ratio should be similar " + 1166 "(requested = %f, result = %f", zoomRatio, resultZoomRatio), 1167 Math.abs(zoomRatio - resultZoomRatio) / zoomRatio <= ZOOM_ERROR_MARGIN); 1168 } 1169 } 1170 1171 if (mFlashStateListener != null) { 1172 Integer flashMode = request.get(CaptureRequest.FLASH_MODE); 1173 if ((flashMode != null) && mPerFrameControl) { 1174 Integer resultFlashMode = result.get(CaptureResult.FLASH_MODE); 1175 mCollector.expectTrue("Request flash mode: " + flashMode + 1176 " doesn't match with result: " + resultFlashMode, 1177 flashMode.equals(resultFlashMode)); 1178 } 1179 1180 Integer flashState = result.get(CaptureResult.FLASH_STATE); 1181 if (flashState != null) { 1182 switch (flashState) { 1183 case CaptureResult.FLASH_STATE_UNAVAILABLE: 1184 mFlashStateListener.onUnavailable(); 1185 break; 1186 case CaptureResult.FLASH_STATE_FIRED: 1187 mFlashStateListener.onFired(); 1188 break; 1189 case CaptureResult.FLASH_STATE_CHARGING: 1190 mFlashStateListener.onCharging(); 1191 break; 1192 case CaptureResult.FLASH_STATE_PARTIAL: 1193 mFlashStateListener.onPartial(); 1194 break; 1195 case CaptureResult.FLASH_STATE_READY: 1196 mFlashStateListener.onReady(); 1197 break; 1198 default: 1199 mCollector.addMessage("Unexpected flash state: " + flashState); 1200 } 1201 } 1202 } 1203 1204 if (mAEStateListener != null) { 1205 Integer aeMode = request.get(CaptureRequest.CONTROL_AE_MODE); 1206 if ((aeMode != null) && mPerFrameControl) { 1207 Integer resultAeMode = result.get(CaptureResult.CONTROL_AE_MODE); 1208 mCollector.expectTrue("Request AE mode: " + aeMode + 1209 " doesn't match with result: " + resultAeMode, 1210 aeMode.equals(resultAeMode)); 1211 } 1212 1213 Boolean aeLock = request.get(CaptureRequest.CONTROL_AE_LOCK); 1214 if ((aeLock != null) && mPerFrameControl) { 1215 Boolean resultAeLock = result.get(CaptureResult.CONTROL_AE_LOCK); 1216 mCollector.expectTrue("Request AE lock: " + aeLock + 1217 " doesn't match with result: " + resultAeLock, 1218 aeLock.equals(resultAeLock)); 1219 } 1220 1221 Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); 1222 if (aeState != null) { 1223 switch (aeState) { 1224 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 1225 mAEStateListener.onConverged(); 1226 break; 1227 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 1228 mAEStateListener.onFlashRequired(); 1229 break; 1230 case CaptureResult.CONTROL_AE_STATE_INACTIVE: 1231 mAEStateListener.onInactive(); 1232 break; 1233 case CaptureResult.CONTROL_AE_STATE_LOCKED: 1234 mAEStateListener.onLocked(); 1235 break; 1236 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE: 1237 mAEStateListener.onPrecapture(); 1238 break; 1239 case CaptureResult.CONTROL_AE_STATE_SEARCHING: 1240 mAEStateListener.onSearching(); 1241 break; 1242 default: 1243 mCollector.addMessage("Unexpected AE state: " + aeState); 1244 } 1245 } 1246 } 1247 1248 if (mAFStateMachine != null) { 1249 Integer afMode = request.get(CaptureRequest.CONTROL_AF_MODE); 1250 if ((afMode != null) && mPerFrameControl) { 1251 Integer resultAfMode = result.get(CaptureResult.CONTROL_AF_MODE); 1252 mCollector.expectTrue("Request AF mode: " + afMode + 1253 " doesn't match with result: " + resultAfMode, 1254 afMode.equals(resultAfMode)); 1255 } 1256 1257 MeteringRectangle[] afRegions = request.get(CaptureRequest.CONTROL_AF_REGIONS); 1258 if ((afRegions != null) && mPerFrameControl) { 1259 MeteringRectangle[] resultAfRegions = result.get( 1260 CaptureResult.CONTROL_AF_REGIONS); 1261 mCollector.expectMeteringRegionsAreSimilar( 1262 "AF regions in result and request should be similar", 1263 afRegions, resultAfRegions, METERING_REGION_ERROR_PERCENT_DELTA); 1264 } 1265 1266 Integer afTrigger = request.get(CaptureRequest.CONTROL_AF_TRIGGER); 1267 if ((afTrigger != null) && mPerFrameControl) { 1268 Integer resultAfTrigger = result.get(CaptureResult.CONTROL_AF_TRIGGER); 1269 mCollector.expectTrue("Request AF trigger: " + afTrigger + 1270 " doesn't match with result: " + resultAfTrigger, 1271 afTrigger.equals(resultAfTrigger)); 1272 } 1273 1274 mAFStateMachine.onCaptureCompleted(result); 1275 } 1276 1277 if (mProxy != null) { 1278 mProxy.onCaptureResultAvailable(session, request, result); 1279 } 1280 } 1281 getTotalFramesArrived()1282 public int getTotalFramesArrived() { 1283 return mNumFramesArrived; 1284 } 1285 getTotalFramesStarted()1286 public int getTotalFramesStarted() { 1287 return mNumFramesStarted; 1288 } 1289 getTotalFramesFailed()1290 public int getTotalFramesFailed() { 1291 return mNumFramesFailed; 1292 } 1293 getLastTimestamp()1294 public long getLastTimestamp() throws IllegalStateException { 1295 if (mNonIncreasingTimestamps) { 1296 throw new IllegalStateException("Non-monotonically increasing timestamps!"); 1297 } 1298 return mLastTimestamp; 1299 } 1300 } 1301 1302 public interface AutoFocusStateListener { onDone(boolean success)1303 void onDone(boolean success); onScan()1304 void onScan(); onInactive()1305 void onInactive(); 1306 } 1307 1308 private class TestAutoFocusProxy implements AutoFocusStateMachine.AutoFocusStateListener { 1309 private final AutoFocusStateListener mListener; 1310 TestAutoFocusProxy(AutoFocusStateListener listener)1311 TestAutoFocusProxy(AutoFocusStateListener listener) { 1312 mListener = listener; 1313 } 1314 1315 @Override onAutoFocusSuccess(CaptureResult result, boolean locked)1316 public void onAutoFocusSuccess(CaptureResult result, boolean locked) { 1317 mListener.onDone(true); 1318 } 1319 1320 @Override onAutoFocusFail(CaptureResult result, boolean locked)1321 public void onAutoFocusFail(CaptureResult result, boolean locked) { 1322 mListener.onDone(false); 1323 } 1324 1325 @Override onAutoFocusScan(CaptureResult result)1326 public void onAutoFocusScan(CaptureResult result) { 1327 mListener.onScan(); 1328 } 1329 1330 @Override onAutoFocusInactive(CaptureResult result)1331 public void onAutoFocusInactive(CaptureResult result) { 1332 mListener.onInactive(); 1333 } 1334 } 1335 1336 // Verify that camera extension sessions can support AF and AF metering controls. The test 1337 // goal is to check that AF related controls and results are supported and can be used to 1338 // lock the AF state and not to do an exhaustive check of the AF state transitions or manual AF. 1339 @Test testAFMetering()1340 public void testAFMetering() throws Exception { 1341 final CaptureRequest.Key[] FOCUS_CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_AF_MODE, 1342 CaptureRequest.CONTROL_AF_REGIONS, CaptureRequest.CONTROL_AF_TRIGGER}; 1343 final CaptureResult.Key[] FOCUS_CAPTURE_RESULT_SET = {CaptureResult.CONTROL_AF_MODE, 1344 CaptureResult.CONTROL_AF_REGIONS, CaptureResult.CONTROL_AF_TRIGGER, 1345 CaptureResult.CONTROL_AF_STATE}; 1346 final int METERING_REGION_SCALE_RATIO = 8; 1347 final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000; 1348 for (String id : mCameraIdsUnderTest) { 1349 StaticMetadata staticMeta = 1350 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 1351 if (!staticMeta.isColorOutputSupported()) { 1352 continue; 1353 } 1354 if (!staticMeta.hasFocuser()) { 1355 continue; 1356 } 1357 1358 boolean perFrameControl = staticMeta.isPerFrameControlSupported(); 1359 final Rect activeArraySize = staticMeta.getActiveArraySizeChecked(); 1360 int regionWidth = activeArraySize.width() / METERING_REGION_SCALE_RATIO - 1; 1361 int regionHeight = activeArraySize.height() / METERING_REGION_SCALE_RATIO - 1; 1362 int centerX = activeArraySize.width() / 2; 1363 int centerY = activeArraySize.height() / 2; 1364 1365 // Center region 1366 MeteringRectangle[] afMeteringRects = {new MeteringRectangle( 1367 centerX - regionWidth / 2, centerY - regionHeight / 2, 1368 regionWidth, regionHeight, 1369 MeteringRectangle.METERING_WEIGHT_MAX)}; 1370 1371 updatePreviewSurfaceTexture(); 1372 CameraExtensionCharacteristics extensionChars = 1373 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 1374 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 1375 for (Integer extension : supportedExtensions) { 1376 Set<CaptureRequest.Key> supportedRequestKeys = 1377 extensionChars.getAvailableCaptureRequestKeys(extension); 1378 if (!supportedRequestKeys.containsAll(Arrays.asList(FOCUS_CAPTURE_REQUEST_SET))) { 1379 continue; 1380 } 1381 Set<CaptureResult.Key> supportedResultKeys = 1382 extensionChars.getAvailableCaptureResultKeys(extension); 1383 assertTrue(supportedResultKeys.containsAll( 1384 Arrays.asList(FOCUS_CAPTURE_RESULT_SET))); 1385 1386 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 1387 mSurfaceTexture.getClass()); 1388 Size maxSize = 1389 CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 1390 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), 1391 maxSize.getHeight()); 1392 Surface texturedSurface = new Surface(mSurfaceTexture); 1393 1394 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 1395 outputConfigs.add(new OutputConfiguration(texturedSurface)); 1396 1397 BlockingExtensionSessionCallback sessionListener = 1398 new BlockingExtensionSessionCallback(mock( 1399 CameraExtensionSession.StateCallback.class)); 1400 ExtensionSessionConfiguration configuration = 1401 new ExtensionSessionConfiguration(extension, outputConfigs, 1402 new HandlerExecutor(mTestRule.getHandler()), 1403 sessionListener); 1404 1405 try { 1406 mTestRule.openDevice(id); 1407 CameraDevice camera = mTestRule.getCamera(); 1408 camera.createExtensionSession(configuration); 1409 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 1410 SESSION_CONFIGURE_TIMEOUT_MS); 1411 assertNotNull(extensionSession); 1412 1413 // Check passive AF 1414 AutoFocusStateListener mockAFListener = 1415 mock(AutoFocusStateListener.class); 1416 AutoFocusStateMachine afState = new AutoFocusStateMachine( 1417 new TestAutoFocusProxy(mockAFListener)); 1418 CameraExtensionSession.ExtensionCaptureCallback repeatingCallbackMock = 1419 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 1420 SimpleCaptureCallback repeatingCaptureCallback = 1421 new SimpleCaptureCallback(repeatingCallbackMock, 1422 extensionChars.getAvailableCaptureResultKeys(extension), 1423 mCollector, afState, null /*flashState*/, 1424 null /*aeState*/, perFrameControl); 1425 1426 CaptureRequest.Builder captureBuilder = 1427 mTestRule.getCamera().createCaptureRequest( 1428 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 1429 captureBuilder.addTarget(texturedSurface); 1430 afState.setPassiveAutoFocus(true /*picture*/, captureBuilder); 1431 captureBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, afMeteringRects); 1432 CaptureRequest request = captureBuilder.build(); 1433 int passiveSequenceId = extensionSession.setRepeatingRequest(request, 1434 new HandlerExecutor(mTestRule.getHandler()), repeatingCaptureCallback); 1435 assertTrue(passiveSequenceId > 0); 1436 1437 verify(repeatingCallbackMock, 1438 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1439 .onCaptureResultAvailable(eq(extensionSession), eq(request), 1440 any(TotalCaptureResult.class)); 1441 1442 verify(mockAFListener, 1443 timeout(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS).atLeastOnce()) 1444 .onDone(anyBoolean()); 1445 1446 // Check active AF 1447 mockAFListener = mock(AutoFocusStateListener.class); 1448 CameraExtensionSession.ExtensionCaptureCallback callbackMock = mock( 1449 CameraExtensionSession.ExtensionCaptureCallback.class); 1450 AutoFocusStateMachine activeAFState = new AutoFocusStateMachine( 1451 new TestAutoFocusProxy(mockAFListener)); 1452 CameraExtensionSession.ExtensionCaptureCallback captureCallback = 1453 new SimpleCaptureCallback(callbackMock, 1454 extensionChars.getAvailableCaptureResultKeys(extension), 1455 mCollector, activeAFState, null /*flashState*/, 1456 null /*aeState*/, perFrameControl); 1457 1458 CaptureRequest.Builder triggerBuilder = 1459 mTestRule.getCamera().createCaptureRequest( 1460 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 1461 triggerBuilder.addTarget(texturedSurface); 1462 afState.setActiveAutoFocus(captureBuilder, triggerBuilder); 1463 afState.unlockAutoFocus(captureBuilder, triggerBuilder); 1464 triggerBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, afMeteringRects); 1465 request = captureBuilder.build(); 1466 int activeSequenceId = extensionSession.setRepeatingRequest(request, 1467 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 1468 assertTrue((activeSequenceId > 0) && 1469 (activeSequenceId != passiveSequenceId)); 1470 1471 verify(callbackMock, 1472 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1473 .onCaptureResultAvailable(eq(extensionSession), eq(request), 1474 any(TotalCaptureResult.class)); 1475 1476 CaptureRequest triggerRequest = triggerBuilder.build(); 1477 reset(mockAFListener); 1478 int triggerSequenceId = extensionSession.capture(triggerRequest, 1479 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 1480 assertTrue((triggerSequenceId > 0) && 1481 (activeSequenceId != triggerSequenceId) && 1482 (triggerSequenceId != passiveSequenceId)); 1483 1484 verify(callbackMock, 1485 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1486 .onCaptureResultAvailable(eq(extensionSession), eq(triggerRequest), 1487 any(TotalCaptureResult.class)); 1488 1489 afState.lockAutoFocus(captureBuilder, triggerBuilder); 1490 triggerRequest = triggerBuilder.build(); 1491 reset(mockAFListener); 1492 extensionSession.capture(triggerRequest, 1493 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 1494 1495 verify(callbackMock, 1496 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1497 .onCaptureResultAvailable(eq(extensionSession), eq(triggerRequest), 1498 any(TotalCaptureResult.class)); 1499 1500 verify(mockAFListener, timeout(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS) 1501 .atLeast(1)).onDone(anyBoolean()); 1502 1503 extensionSession.stopRepeating(); 1504 1505 extensionSession.close(); 1506 1507 sessionListener.getStateWaiter().waitForState( 1508 BlockingExtensionSessionCallback.SESSION_CLOSED, 1509 SESSION_CLOSE_TIMEOUT_MS); 1510 } finally { 1511 mTestRule.closeDevice(id); 1512 texturedSurface.release(); 1513 } 1514 } 1515 } 1516 } 1517 1518 // Verify that camera extension sessions can support the zoom ratio control. 1519 @Test testZoomRatio()1520 public void testZoomRatio() throws Exception { 1521 final CaptureRequest.Key[] ZOOM_CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_ZOOM_RATIO}; 1522 final CaptureResult.Key[] ZOOM_CAPTURE_RESULT_SET = {CaptureResult.CONTROL_ZOOM_RATIO}; 1523 final int ZOOM_RATIO_STEPS = 10; 1524 for (String id : mCameraIdsUnderTest) { 1525 StaticMetadata staticMeta = 1526 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 1527 if (!staticMeta.isColorOutputSupported()) { 1528 continue; 1529 } 1530 Range<Float> zoomRatioRange = staticMeta.getZoomRatioRangeChecked(); 1531 if (zoomRatioRange.getUpper().equals(zoomRatioRange.getLower())) { 1532 continue; 1533 } 1534 1535 final float maxZoom = staticMeta.getAvailableMaxDigitalZoomChecked(); 1536 if (Math.abs(maxZoom - 1.0f) < ZOOM_ERROR_MARGIN) { 1537 return; 1538 } 1539 1540 Float zoomStep = 1541 (zoomRatioRange.getUpper() - zoomRatioRange.getLower()) / ZOOM_RATIO_STEPS; 1542 if (zoomStep < ZOOM_ERROR_MARGIN) { 1543 continue; 1544 } 1545 1546 ArrayList<Float> candidateZoomRatios = new ArrayList<>(ZOOM_RATIO_STEPS); 1547 for (int step = 0; step < (ZOOM_RATIO_STEPS - 1); step++) { 1548 candidateZoomRatios.add(step, zoomRatioRange.getLower() + step * zoomStep); 1549 } 1550 candidateZoomRatios.add(ZOOM_RATIO_STEPS - 1, zoomRatioRange.getUpper()); 1551 1552 updatePreviewSurfaceTexture(); 1553 CameraExtensionCharacteristics extensionChars = 1554 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 1555 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 1556 for (Integer extension : supportedExtensions) { 1557 Set<CaptureRequest.Key> supportedRequestKeys = 1558 extensionChars.getAvailableCaptureRequestKeys(extension); 1559 if (!supportedRequestKeys.containsAll(Arrays.asList(ZOOM_CAPTURE_REQUEST_SET))) { 1560 continue; 1561 } 1562 Set<CaptureResult.Key> supportedResultKeys = 1563 extensionChars.getAvailableCaptureResultKeys(extension); 1564 assertTrue(supportedResultKeys.containsAll( 1565 Arrays.asList(ZOOM_CAPTURE_RESULT_SET))); 1566 1567 List<Size> extensionSizes = extensionChars.getExtensionSupportedSizes(extension, 1568 mSurfaceTexture.getClass()); 1569 Size maxSize = 1570 CameraTestUtils.getMaxSize(extensionSizes.toArray(new Size[0])); 1571 mSurfaceTexture.setDefaultBufferSize(maxSize.getWidth(), 1572 maxSize.getHeight()); 1573 Surface texturedSurface = new Surface(mSurfaceTexture); 1574 1575 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 1576 outputConfigs.add(new OutputConfiguration(texturedSurface)); 1577 1578 BlockingExtensionSessionCallback sessionListener = 1579 new BlockingExtensionSessionCallback(mock( 1580 CameraExtensionSession.StateCallback.class)); 1581 ExtensionSessionConfiguration configuration = 1582 new ExtensionSessionConfiguration(extension, outputConfigs, 1583 new HandlerExecutor(mTestRule.getHandler()), 1584 sessionListener); 1585 1586 try { 1587 mTestRule.openDevice(id); 1588 CameraDevice camera = mTestRule.getCamera(); 1589 camera.createExtensionSession(configuration); 1590 CameraExtensionSession extensionSession = sessionListener.waitAndGetSession( 1591 SESSION_CONFIGURE_TIMEOUT_MS); 1592 assertNotNull(extensionSession); 1593 1594 CameraExtensionSession.ExtensionCaptureCallback repeatingCallbackMock = 1595 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 1596 SimpleCaptureCallback repeatingCaptureCallback = 1597 new SimpleCaptureCallback(repeatingCallbackMock, 1598 extensionChars.getAvailableCaptureResultKeys(extension), 1599 mCollector); 1600 1601 CaptureRequest.Builder captureBuilder = 1602 mTestRule.getCamera().createCaptureRequest( 1603 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 1604 captureBuilder.addTarget(texturedSurface); 1605 for (Float currentZoomRatio : candidateZoomRatios) { 1606 captureBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, currentZoomRatio); 1607 CaptureRequest request = captureBuilder.build(); 1608 1609 int seqId = extensionSession.setRepeatingRequest(request, 1610 new HandlerExecutor(mTestRule.getHandler()), 1611 repeatingCaptureCallback); 1612 assertTrue(seqId > 0); 1613 1614 verify(repeatingCallbackMock, 1615 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1616 .onCaptureResultAvailable(eq(extensionSession), eq(request), 1617 any(TotalCaptureResult.class)); 1618 } 1619 1620 extensionSession.stopRepeating(); 1621 1622 extensionSession.close(); 1623 1624 sessionListener.getStateWaiter().waitForState( 1625 BlockingExtensionSessionCallback.SESSION_CLOSED, 1626 SESSION_CLOSE_TIMEOUT_MS); 1627 } finally { 1628 mTestRule.closeDevice(id); 1629 texturedSurface.release(); 1630 } 1631 } 1632 } 1633 } 1634 1635 public interface FlashStateListener { onFired()1636 public void onFired(); onReady()1637 public void onReady(); onCharging()1638 public void onCharging(); onPartial()1639 public void onPartial(); onUnavailable()1640 public void onUnavailable(); 1641 } 1642 1643 public interface AutoExposureStateListener { onInactive()1644 public void onInactive(); onSearching()1645 public void onSearching(); onConverged()1646 public void onConverged(); onLocked()1647 public void onLocked(); onFlashRequired()1648 public void onFlashRequired(); onPrecapture()1649 public void onPrecapture(); 1650 } 1651 1652 // Verify that camera extension sessions can support Flash related controls. The test 1653 // goal is to check that Flash controls and results are supported and can be used to 1654 // turn on torch, run the pre-capture sequence and active the main flash. 1655 @Test testFlash()1656 public void testFlash() throws Exception { 1657 final CaptureRequest.Key[] FLASH_CAPTURE_REQUEST_SET = {CaptureRequest.CONTROL_AE_MODE, 1658 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_LOCK, 1659 CaptureRequest.FLASH_MODE}; 1660 final CaptureResult.Key[] FLASH_CAPTURE_RESULT_SET = {CaptureResult.CONTROL_AE_MODE, 1661 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureResult.CONTROL_AE_LOCK, 1662 CaptureResult.CONTROL_AE_STATE, CaptureResult.FLASH_MODE, 1663 CaptureResult.FLASH_STATE}; 1664 for (String id : mCameraIdsUnderTest) { 1665 StaticMetadata staticMeta = 1666 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 1667 if (!staticMeta.isColorOutputSupported()) { 1668 continue; 1669 } 1670 if (!staticMeta.hasFlash()) { 1671 continue; 1672 } 1673 1674 boolean perFrameControl = staticMeta.isPerFrameControlSupported(); 1675 updatePreviewSurfaceTexture(); 1676 CameraExtensionCharacteristics extensionChars = 1677 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 1678 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 1679 for (Integer extension : supportedExtensions) { 1680 Set<CaptureRequest.Key> supportedRequestKeys = 1681 extensionChars.getAvailableCaptureRequestKeys(extension); 1682 if (!supportedRequestKeys.containsAll(Arrays.asList(FLASH_CAPTURE_REQUEST_SET))) { 1683 continue; 1684 } 1685 Set<CaptureResult.Key> supportedResultKeys = 1686 extensionChars.getAvailableCaptureResultKeys(extension); 1687 assertTrue(supportedResultKeys.containsAll( 1688 Arrays.asList(FLASH_CAPTURE_RESULT_SET))); 1689 1690 int captureFormat = ImageFormat.JPEG; 1691 List<Size> captureSizes = extensionChars.getExtensionSupportedSizes(extension, 1692 captureFormat); 1693 assertFalse("No Jpeg output supported", captureSizes.isEmpty()); 1694 Size captureMaxSize = captureSizes.get(0); 1695 1696 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(false, 1); 1697 ImageReader extensionImageReader = CameraTestUtils.makeImageReader( 1698 captureMaxSize, captureFormat, /*maxImages*/ 1, imageListener, 1699 mTestRule.getHandler()); 1700 Surface imageReaderSurface = extensionImageReader.getSurface(); 1701 OutputConfiguration readerOutput = new OutputConfiguration(imageReaderSurface); 1702 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 1703 outputConfigs.add(readerOutput); 1704 1705 List<Size> repeatingSizes = extensionChars.getExtensionSupportedSizes(extension, 1706 mSurfaceTexture.getClass()); 1707 Size previewSize = repeatingSizes.get(0); 1708 1709 mSurfaceTexture.setDefaultBufferSize(previewSize.getWidth(), 1710 previewSize.getHeight()); 1711 Surface texturedSurface = new Surface(mSurfaceTexture); 1712 outputConfigs.add(new OutputConfiguration(texturedSurface)); 1713 1714 BlockingExtensionSessionCallback sessionListener = 1715 new BlockingExtensionSessionCallback(mock( 1716 CameraExtensionSession.StateCallback.class)); 1717 ExtensionSessionConfiguration configuration = 1718 new ExtensionSessionConfiguration(extension, outputConfigs, 1719 new HandlerExecutor(mTestRule.getHandler()), 1720 sessionListener); 1721 try { 1722 mTestRule.openDevice(id); 1723 CameraDevice camera = mTestRule.getCamera(); 1724 camera.createExtensionSession(configuration); 1725 CameraExtensionSession extensionSession = 1726 sessionListener.waitAndGetSession( 1727 SESSION_CONFIGURE_TIMEOUT_MS); 1728 assertNotNull(extensionSession); 1729 1730 // Test torch on and off 1731 CaptureRequest.Builder captureBuilder = 1732 mTestRule.getCamera().createCaptureRequest( 1733 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 1734 captureBuilder.addTarget(texturedSurface); 1735 captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, 1736 CameraMetadata.CONTROL_AE_MODE_ON); 1737 captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false); 1738 captureBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH); 1739 FlashStateListener mockFlashListener = mock(FlashStateListener.class); 1740 AutoExposureStateListener mockAEStateListener = 1741 mock(AutoExposureStateListener.class); 1742 CameraExtensionSession.ExtensionCaptureCallback repeatingCallbackMock = 1743 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 1744 SimpleCaptureCallback repeatingCaptureCallback = 1745 new SimpleCaptureCallback(repeatingCallbackMock, 1746 extensionChars.getAvailableCaptureResultKeys(extension), 1747 mCollector, null /*afState*/, mockFlashListener, 1748 mockAEStateListener, perFrameControl); 1749 CaptureRequest repeatingRequest = captureBuilder.build(); 1750 int repeatingSequenceId = 1751 extensionSession.setRepeatingRequest(repeatingRequest, 1752 new HandlerExecutor(mTestRule.getHandler()), 1753 repeatingCaptureCallback); 1754 assertTrue(repeatingSequenceId > 0); 1755 1756 verify(repeatingCallbackMock, 1757 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1758 .onCaptureResultAvailable(eq(extensionSession), 1759 eq(repeatingRequest), any(TotalCaptureResult.class)); 1760 verify(mockFlashListener, 1761 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()).onFired(); 1762 1763 captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, 1764 CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); 1765 captureBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF); 1766 repeatingRequest = captureBuilder.build(); 1767 reset(mockFlashListener); 1768 repeatingSequenceId = extensionSession.setRepeatingRequest(repeatingRequest, 1769 new HandlerExecutor(mTestRule.getHandler()), 1770 repeatingCaptureCallback); 1771 assertTrue(repeatingSequenceId > 0); 1772 1773 verify(repeatingCallbackMock, 1774 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1775 .onCaptureResultAvailable(eq(extensionSession), 1776 eq(repeatingRequest), any(TotalCaptureResult.class)); 1777 verify(mockFlashListener, 1778 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()).onReady(); 1779 1780 // Test AE pre-capture sequence 1781 captureBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF); 1782 captureBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1783 CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1784 CaptureRequest triggerRequest = captureBuilder.build(); 1785 int triggerSeqId = extensionSession.capture(triggerRequest, 1786 new HandlerExecutor(mTestRule.getHandler()), repeatingCaptureCallback); 1787 assertTrue(triggerSeqId > 0); 1788 1789 verify(repeatingCallbackMock, 1790 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()) 1791 .onCaptureResultAvailable(eq(extensionSession), 1792 eq(triggerRequest), any(TotalCaptureResult.class)); 1793 verify(mockAEStateListener, 1794 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()).onPrecapture(); 1795 verify(mockAEStateListener, 1796 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()).onConverged(); 1797 1798 // Test main flash 1799 captureBuilder = mTestRule.getCamera().createCaptureRequest( 1800 android.hardware.camera2.CameraDevice.TEMPLATE_STILL_CAPTURE); 1801 captureBuilder.addTarget(imageReaderSurface); 1802 captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, 1803 CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH); 1804 captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true); 1805 captureBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_SINGLE); 1806 CameraExtensionSession.ExtensionCaptureCallback mockCaptureCallback = 1807 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 1808 reset(mockFlashListener); 1809 SimpleCaptureCallback captureCallback = 1810 new SimpleCaptureCallback(mockCaptureCallback, 1811 extensionChars.getAvailableCaptureResultKeys(extension), 1812 mCollector, null /*afState*/, mockFlashListener, 1813 mockAEStateListener, perFrameControl); 1814 1815 CaptureRequest captureRequest = captureBuilder.build(); 1816 int captureSequenceId = extensionSession.capture(captureRequest, 1817 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 1818 assertTrue(captureSequenceId > 0); 1819 1820 Image img = 1821 imageListener.getImage(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS); 1822 validateImage(img, captureMaxSize.getWidth(), 1823 captureMaxSize.getHeight(), captureFormat, null); 1824 long imgTs = img.getTimestamp(); 1825 img.close(); 1826 1827 verify(mockCaptureCallback, 1828 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 1829 .onCaptureStarted(eq(extensionSession), eq(captureRequest), eq(imgTs)); 1830 verify(mockCaptureCallback, 1831 timeout(MULTI_FRAME_CAPTURE_IMAGE_TIMEOUT_MS).times(1)) 1832 .onCaptureResultAvailable(eq(extensionSession), 1833 eq(captureRequest), any(TotalCaptureResult.class)); 1834 verify(mockFlashListener, 1835 timeout(REPEATING_REQUEST_TIMEOUT_MS).atLeastOnce()).onFired(); 1836 1837 extensionSession.stopRepeating(); 1838 1839 extensionSession.close(); 1840 1841 sessionListener.getStateWaiter().waitForState( 1842 BlockingExtensionSessionCallback.SESSION_CLOSED, 1843 SESSION_CLOSE_TIMEOUT_MS); 1844 } finally { 1845 mTestRule.closeDevice(id); 1846 texturedSurface.release(); 1847 extensionImageReader.close(); 1848 } 1849 } 1850 } 1851 } 1852 1853 @Test testIllegalArguments()1854 public void testIllegalArguments() throws Exception { 1855 for (String id : mCameraIdsUnderTest) { 1856 StaticMetadata staticMeta = 1857 new StaticMetadata(mTestRule.getCameraManager().getCameraCharacteristics(id)); 1858 if (!staticMeta.isColorOutputSupported()) { 1859 continue; 1860 } 1861 updatePreviewSurfaceTexture(); 1862 CameraExtensionCharacteristics extensionChars = 1863 mTestRule.getCameraManager().getCameraExtensionCharacteristics(id); 1864 List<Integer> supportedExtensions = extensionChars.getSupportedExtensions(); 1865 for (Integer extension : supportedExtensions) { 1866 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 1867 BlockingExtensionSessionCallback sessionListener = 1868 new BlockingExtensionSessionCallback(mock( 1869 CameraExtensionSession.StateCallback.class)); 1870 ExtensionSessionConfiguration configuration = 1871 new ExtensionSessionConfiguration(extension, outputConfigs, 1872 new HandlerExecutor(mTestRule.getHandler()), 1873 sessionListener); 1874 1875 try { 1876 mTestRule.openDevice(id); 1877 CameraDevice camera = mTestRule.getCamera(); 1878 try { 1879 camera.createExtensionSession(configuration); 1880 fail("should get IllegalArgumentException due to absent output surfaces"); 1881 } catch (IllegalArgumentException e) { 1882 // Expected, we can proceed further 1883 } 1884 1885 int captureFormat = ImageFormat.YUV_420_888; 1886 List<Size> captureSizes = extensionChars.getExtensionSupportedSizes(extension, 1887 captureFormat); 1888 if (captureSizes.isEmpty()) { 1889 captureFormat = ImageFormat.JPEG; 1890 captureSizes = extensionChars.getExtensionSupportedSizes(extension, 1891 captureFormat); 1892 } 1893 Size captureMaxSize = 1894 CameraTestUtils.getMaxSize(captureSizes.toArray(new Size[0])); 1895 1896 mSurfaceTexture.setDefaultBufferSize(1, 1); 1897 Surface texturedSurface = new Surface(mSurfaceTexture); 1898 outputConfigs.add(new OutputConfiguration(texturedSurface)); 1899 configuration = new ExtensionSessionConfiguration(extension, outputConfigs, 1900 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 1901 1902 try { 1903 camera.createExtensionSession(configuration); 1904 fail("should get IllegalArgumentException due to illegal repeating request" 1905 + " output surface"); 1906 } catch (IllegalArgumentException e) { 1907 // Expected, we can proceed further 1908 } finally { 1909 outputConfigs.clear(); 1910 } 1911 1912 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(false, 1913 1); 1914 Size invalidCaptureSize = new Size(1, 1); 1915 ImageReader extensionImageReader = CameraTestUtils.makeImageReader( 1916 invalidCaptureSize, captureFormat, /*maxImages*/ 1, 1917 imageListener, mTestRule.getHandler()); 1918 Surface imageReaderSurface = extensionImageReader.getSurface(); 1919 OutputConfiguration readerOutput = new OutputConfiguration(imageReaderSurface); 1920 outputConfigs.add(readerOutput); 1921 configuration = new ExtensionSessionConfiguration(extension, outputConfigs, 1922 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 1923 1924 try{ 1925 camera.createExtensionSession(configuration); 1926 fail("should get IllegalArgumentException due to illegal multi-frame" 1927 + " request output surface"); 1928 } catch (IllegalArgumentException e) { 1929 // Expected, we can proceed further 1930 } finally { 1931 outputConfigs.clear(); 1932 extensionImageReader.close(); 1933 } 1934 1935 // Pick a supported preview/repeating size with aspect ratio close to the 1936 // multi-frame capture size 1937 List<Size> repeatingSizes = extensionChars.getExtensionSupportedSizes(extension, 1938 mSurfaceTexture.getClass()); 1939 Size maxRepeatingSize = 1940 CameraTestUtils.getMaxSize(repeatingSizes.toArray(new Size[0])); 1941 List<Size> previewSizes = getSupportedPreviewSizes(id, 1942 mTestRule.getCameraManager(), 1943 getPreviewSizeBound(mTestRule.getWindowManager(), PREVIEW_SIZE_BOUND)); 1944 List<Size> supportedPreviewSizes = 1945 previewSizes.stream().filter(repeatingSizes::contains).collect( 1946 Collectors.toList()); 1947 if (!supportedPreviewSizes.isEmpty()) { 1948 float targetAr = 1949 ((float) captureMaxSize.getWidth()) / captureMaxSize.getHeight(); 1950 for (Size s : supportedPreviewSizes) { 1951 float currentAr = ((float) s.getWidth()) / s.getHeight(); 1952 if (Math.abs(targetAr - currentAr) < 0.01) { 1953 maxRepeatingSize = s; 1954 break; 1955 } 1956 } 1957 } 1958 1959 imageListener = new SimpleImageReaderListener(false, 1); 1960 extensionImageReader = CameraTestUtils.makeImageReader(captureMaxSize, 1961 captureFormat, /*maxImages*/ 1, imageListener, mTestRule.getHandler()); 1962 imageReaderSurface = extensionImageReader.getSurface(); 1963 readerOutput = new OutputConfiguration(imageReaderSurface); 1964 outputConfigs.add(readerOutput); 1965 1966 mSurfaceTexture.setDefaultBufferSize(maxRepeatingSize.getWidth(), 1967 maxRepeatingSize.getHeight()); 1968 texturedSurface = new Surface(mSurfaceTexture); 1969 outputConfigs.add(new OutputConfiguration(texturedSurface)); 1970 1971 configuration = new ExtensionSessionConfiguration(extension, outputConfigs, 1972 new HandlerExecutor(mTestRule.getHandler()), sessionListener); 1973 camera.createExtensionSession(configuration); 1974 CameraExtensionSession extensionSession = 1975 sessionListener.waitAndGetSession( 1976 SESSION_CONFIGURE_TIMEOUT_MS); 1977 assertNotNull(extensionSession); 1978 1979 CaptureRequest.Builder captureBuilder = 1980 mTestRule.getCamera().createCaptureRequest( 1981 android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW); 1982 captureBuilder.addTarget(imageReaderSurface); 1983 CameraExtensionSession.ExtensionCaptureCallback repeatingCallbackMock = 1984 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 1985 SimpleCaptureCallback repeatingCaptureCallback = 1986 new SimpleCaptureCallback(repeatingCallbackMock, 1987 extensionChars.getAvailableCaptureResultKeys(extension), 1988 mCollector); 1989 CaptureRequest repeatingRequest = captureBuilder.build(); 1990 try { 1991 extensionSession.setRepeatingRequest(repeatingRequest, 1992 new HandlerExecutor(mTestRule.getHandler()), 1993 repeatingCaptureCallback); 1994 fail("should get IllegalArgumentException due to illegal repeating request" 1995 + " output target"); 1996 } catch (IllegalArgumentException e) { 1997 // Expected, we can proceed further 1998 } 1999 2000 extensionSession.close(); 2001 2002 sessionListener.getStateWaiter().waitForState( 2003 BlockingExtensionSessionCallback.SESSION_CLOSED, 2004 SESSION_CLOSE_TIMEOUT_MS); 2005 2006 texturedSurface.release(); 2007 extensionImageReader.close(); 2008 2009 captureBuilder = mTestRule.getCamera().createCaptureRequest( 2010 CameraDevice.TEMPLATE_PREVIEW); 2011 captureBuilder.addTarget(texturedSurface); 2012 CameraExtensionSession.ExtensionCaptureCallback captureCallback = 2013 mock(CameraExtensionSession.ExtensionCaptureCallback.class); 2014 2015 CaptureRequest captureRequest = captureBuilder.build(); 2016 try { 2017 extensionSession.setRepeatingRequest(captureRequest, 2018 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 2019 fail("should get IllegalStateException due to closed session"); 2020 } catch (IllegalStateException e) { 2021 // Expected, we can proceed further 2022 } 2023 2024 try { 2025 extensionSession.stopRepeating(); 2026 fail("should get IllegalStateException due to closed session"); 2027 } catch (IllegalStateException e) { 2028 // Expected, we can proceed further 2029 } 2030 2031 try { 2032 extensionSession.capture(captureRequest, 2033 new HandlerExecutor(mTestRule.getHandler()), captureCallback); 2034 fail("should get IllegalStateException due to closed session"); 2035 } catch (IllegalStateException e) { 2036 // Expected, we can proceed further 2037 } 2038 } finally { 2039 mTestRule.closeDevice(id); 2040 } 2041 } 2042 } 2043 } 2044 } 2045