1 /* <lambda>null2 * Copyright 2021 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 androidx.camera.camera2.internal 18 19 import android.content.Context 20 import android.graphics.SurfaceTexture 21 import android.hardware.camera2.CameraCaptureSession 22 import android.hardware.camera2.CameraCharacteristics 23 import android.hardware.camera2.CameraDevice 24 import android.hardware.camera2.CameraManager 25 import android.hardware.camera2.CameraMetadata 26 import android.hardware.camera2.CameraMetadata.CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY 27 import android.hardware.camera2.CaptureRequest 28 import android.hardware.camera2.CaptureResult 29 import android.hardware.camera2.TotalCaptureResult 30 import android.media.Image 31 import android.media.ImageWriter 32 import android.os.Build 33 import android.view.Surface 34 import androidx.annotation.RequiresApi 35 import androidx.camera.camera2.impl.Camera2ImplConfig 36 import androidx.camera.camera2.internal.Camera2CapturePipeline.ScreenFlashTask 37 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat 38 import androidx.camera.camera2.internal.compat.quirk.AutoFlashUnderExposedQuirk 39 import androidx.camera.camera2.internal.compat.quirk.CameraQuirks 40 import androidx.camera.camera2.internal.compat.quirk.TorchFlashRequiredFor3aUpdateQuirk 41 import androidx.camera.camera2.internal.compat.quirk.UseTorchAsFlashQuirk 42 import androidx.camera.camera2.internal.compat.workaround.OverrideAeModeForStillCapture 43 import androidx.camera.core.ImageCapture 44 import androidx.camera.core.ImageCapture.FLASH_MODE_AUTO 45 import androidx.camera.core.ImageCapture.FLASH_MODE_OFF 46 import androidx.camera.core.ImageCapture.FLASH_MODE_ON 47 import androidx.camera.core.ImageCaptureException 48 import androidx.camera.core.impl.CameraCaptureFailure 49 import androidx.camera.core.impl.CameraCaptureMetaData.AeState 50 import androidx.camera.core.impl.CameraCaptureMetaData.AfState 51 import androidx.camera.core.impl.CameraCaptureMetaData.AwbState 52 import androidx.camera.core.impl.CameraCaptureResult 53 import androidx.camera.core.impl.CameraControlInternal 54 import androidx.camera.core.impl.CaptureConfig 55 import androidx.camera.core.impl.DeferrableSurface 56 import androidx.camera.core.impl.ImmediateSurface 57 import androidx.camera.core.impl.Quirk 58 import androidx.camera.core.impl.Quirks 59 import androidx.camera.core.impl.SessionConfig 60 import androidx.camera.core.impl.utils.executor.CameraXExecutors 61 import androidx.camera.core.impl.utils.futures.Futures 62 import androidx.camera.core.internal.CameraCaptureResultImageInfo 63 import androidx.camera.testing.fakes.FakeCameraCaptureResult 64 import androidx.camera.testing.impl.fakes.FakeImageProxy 65 import androidx.camera.testing.impl.mocks.MockScreenFlash 66 import androidx.concurrent.futures.await 67 import androidx.test.core.app.ApplicationProvider 68 import com.google.common.truth.Truth 69 import com.google.common.truth.Truth.assertThat 70 import com.google.common.util.concurrent.ListenableFuture 71 import java.util.concurrent.CountDownLatch 72 import java.util.concurrent.ExecutionException 73 import java.util.concurrent.Executor 74 import java.util.concurrent.Executors 75 import java.util.concurrent.ScheduledFuture 76 import java.util.concurrent.TimeUnit 77 import java.util.concurrent.TimeoutException 78 import kotlinx.coroutines.runBlocking 79 import kotlinx.coroutines.withTimeout 80 import org.junit.After 81 import org.junit.Assert.assertThrows 82 import org.junit.Assume.assumeTrue 83 import org.junit.Before 84 import org.junit.Ignore 85 import org.junit.Test 86 import org.junit.runner.RunWith 87 import org.mockito.Mockito 88 import org.mockito.Mockito.mock 89 import org.robolectric.ParameterizedRobolectricTestRunner 90 import org.robolectric.annotation.Config 91 import org.robolectric.annotation.internal.DoNotInstrument 92 import org.robolectric.shadow.api.Shadow 93 import org.robolectric.shadows.ShadowCameraCharacteristics 94 import org.robolectric.shadows.ShadowCameraManager 95 96 private const val CAMERA_ID_0 = "0" 97 98 @RunWith(ParameterizedRobolectricTestRunner::class) 99 @DoNotInstrument 100 @Config( 101 minSdk = Build.VERSION_CODES.LOLLIPOP, 102 ) 103 class Camera2CapturePipelineTest(private val isLowLightBoostEnabled: Boolean) { 104 105 private val context = ApplicationProvider.getApplicationContext() as Context 106 private val executorService = Executors.newSingleThreadScheduledExecutor() 107 108 private val baseRepeatingResult: Map<CaptureResult.Key<*>, Any> = 109 mapOf( 110 CaptureResult.CONTROL_MODE to CaptureResult.CONTROL_MODE_AUTO, 111 CaptureResult.CONTROL_AF_MODE to CaptureResult.CONTROL_AF_MODE_AUTO, 112 CaptureResult.CONTROL_AE_STATE to CaptureResult.CONTROL_AE_STATE_CONVERGED, 113 CaptureResult.CONTROL_AWB_MODE to CaptureResult.CONTROL_AWB_MODE_AUTO, 114 CaptureResult.CONTROL_AE_MODE to CaptureResult.CONTROL_AE_MODE_ON, 115 ) 116 117 private val resultConverged: Map<CaptureResult.Key<*>, Any> = 118 mapOf( 119 CaptureResult.CONTROL_AF_MODE to CaptureResult.CONTROL_AF_MODE_AUTO, 120 CaptureResult.CONTROL_AF_STATE to CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED, 121 CaptureResult.CONTROL_AE_STATE to CaptureResult.CONTROL_AE_STATE_CONVERGED, 122 CaptureResult.CONTROL_AWB_STATE to CaptureResult.CONTROL_AWB_STATE_CONVERGED, 123 ) 124 125 private val resultConvergedWith3AModeOff: Map<CaptureResult.Key<*>, Any> = 126 mapOf( 127 CaptureResult.CONTROL_AF_MODE to CaptureResult.CONTROL_AF_MODE_OFF, 128 CaptureResult.CONTROL_AE_MODE to CaptureResult.CONTROL_AE_MODE_OFF, 129 CaptureResult.CONTROL_AWB_MODE to CaptureResult.CONTROL_AWB_MODE_OFF, 130 CaptureResult.CONTROL_AF_STATE to CaptureResult.CONTROL_AF_STATE_INACTIVE, 131 CaptureResult.CONTROL_AE_STATE to CaptureResult.CONTROL_AE_STATE_INACTIVE, 132 CaptureResult.CONTROL_AWB_STATE to CaptureResult.CONTROL_AWB_STATE_INACTIVE, 133 ) 134 135 private val fakeStillCaptureSurface = ImmediateSurface(Surface(SurfaceTexture(0))) 136 137 private val singleRequest = 138 CaptureConfig.Builder() 139 .apply { 140 templateType = CameraDevice.TEMPLATE_STILL_CAPTURE 141 addSurface(fakeStillCaptureSurface) 142 } 143 .build() 144 145 private var runningRepeatingStream: ScheduledFuture<*>? = null 146 set(value) { 147 runningRepeatingStream?.cancel(false) 148 field = value 149 } 150 151 private lateinit var testScreenFlash: MockScreenFlash 152 153 companion object { 154 @JvmStatic 155 @ParameterizedRobolectricTestRunner.Parameters(name = "isLowLightBoostEnabled: {0}") 156 fun data() = listOf(true, false) 157 } 158 159 @Before 160 fun setUp() { 161 if (isLowLightBoostEnabled) { 162 assumeTrue(Build.VERSION.SDK_INT >= 35) 163 } 164 initCameras() 165 testScreenFlash = MockScreenFlash() 166 } 167 168 @After 169 fun tearDown() { 170 runningRepeatingStream = null 171 fakeStillCaptureSurface.close() 172 executorService.shutdown() 173 } 174 175 @Ignore // b/228856476 176 @Test 177 fun pipelineTest_preCapturePostCaptureShouldCalled() { 178 // Arrange. 179 val fakeTask = 180 object : Camera2CapturePipeline.PipelineTask { 181 val preCaptureCountDown = CountDownLatch(1) 182 val postCaptureCountDown = CountDownLatch(1) 183 184 override fun preCapture( 185 captureResult: TotalCaptureResult? 186 ): ListenableFuture<Boolean> { 187 preCaptureCountDown.countDown() 188 return Futures.immediateFuture(false) 189 } 190 191 override fun isCaptureResultNeeded(): Boolean { 192 return false 193 } 194 195 override fun postCapture() { 196 postCaptureCountDown.countDown() 197 } 198 } 199 200 val cameraControl = 201 createCameraControl().apply { 202 simulateRepeatingResult(resultParameters = resultConverged) 203 } 204 205 val pipeline = 206 Camera2CapturePipeline.Pipeline( 207 CameraDevice.TEMPLATE_PREVIEW, 208 executorService, 209 executorService, 210 cameraControl, 211 false, 212 OverrideAeModeForStillCapture(Quirks(emptyList())), 213 ) 214 .apply { addTask(fakeTask) } 215 216 // Act. 217 pipeline.executeCapture( 218 listOf(singleRequest), 219 FLASH_MODE_OFF, 220 ) 221 222 // Assert. 223 assertThat(fakeTask.preCaptureCountDown.await(3, TimeUnit.SECONDS)).isTrue() 224 assertThat(fakeTask.postCaptureCountDown.await(3, TimeUnit.SECONDS)).isTrue() 225 } 226 227 @Test 228 fun maxQuality_afInactive_shouldTriggerAf(): Unit = runBlocking { 229 val cameraControl = 230 createCameraControl().apply { 231 232 // Arrange. Simulate the scenario that we need to triggerAF. 233 simulateRepeatingResult( 234 initialDelay = 100, 235 resultParameters = 236 mapOf( 237 CaptureResult.CONTROL_AF_MODE to CaptureResult.CONTROL_AF_MODE_AUTO, 238 CaptureResult.CONTROL_AF_STATE to 239 CaptureResult.CONTROL_AF_STATE_INACTIVE, 240 ) 241 ) 242 243 // Act. 244 submitStillCaptureRequests( 245 listOf(singleRequest), 246 ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY, 247 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 248 ) 249 } 250 251 // Assert 1, verify the CONTROL_AF_TRIGGER is triggered 252 immediateCompleteCapture.verifyRequestResult { 253 it.requestContains( 254 CaptureRequest.CONTROL_AF_TRIGGER, 255 CaptureRequest.CONTROL_AF_TRIGGER_START 256 ) 257 } 258 259 // Switch the repeating result to 3A converged state. 260 cameraControl.simulateRepeatingResult( 261 initialDelay = 500, 262 resultParameters = resultConverged 263 ) 264 265 // Assert 2, that CONTROL_AF_TRIGGER should be cancelled finally. 266 immediateCompleteCapture.verifyRequestResult { 267 it.requestContains( 268 CaptureRequest.CONTROL_AF_TRIGGER, 269 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL 270 ) 271 } 272 } 273 274 @Test 275 fun miniLatency_flashOn_shouldTriggerAe() { 276 flashOn_shouldTriggerAe(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) 277 } 278 279 @Test 280 fun maxQuality_flashOn_shouldTriggerAe() { 281 flashOn_shouldTriggerAe(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) 282 } 283 284 private fun flashOn_shouldTriggerAe(imageCaptureMode: Int) { 285 val cameraControl = 286 createCameraControl().apply { 287 // Arrange. 288 flashMode = FLASH_MODE_ON 289 290 // Act. 291 submitStillCaptureRequests( 292 listOf(singleRequest), 293 imageCaptureMode, 294 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 295 ) 296 simulateRepeatingResult(initialDelay = 100) 297 } 298 299 // Assert 1, verify the CONTROL_AE_PRECAPTURE_TRIGGER is triggered when low-light boost is 300 // off, otherwise, is not triggered. 301 immediateCompleteCapture.verifyRequestResult { 302 it.requestContains( 303 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 304 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START 305 ) != isLowLightBoostEnabled 306 } 307 308 // When low-light boost is on, AE pre-capture is not triggered. Therefore, converged stage 309 // is not required. 310 if (isLowLightBoostEnabled) { 311 return 312 } 313 314 // Switch the repeating result to 3A converged state. 315 cameraControl.simulateRepeatingResult( 316 initialDelay = 500, 317 resultParameters = resultConverged 318 ) 319 320 // Assert 2 that CONTROL_AE_PRECAPTURE_TRIGGER should be cancelled finally when low-light 321 // boost is off, otherwise, TRIGGER_CANCEL is not triggered. 322 if (Build.VERSION.SDK_INT >= 23) { 323 immediateCompleteCapture.verifyRequestResult { 324 it.requestContains( 325 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 326 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL 327 ) 328 } 329 } 330 } 331 332 @Test 333 fun miniLatency_flashAutoFlashRequired_shouldTriggerAe() { 334 flashAutoFlashRequired_shouldTriggerAe(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) 335 } 336 337 @Test 338 fun maxQuality_flashAutoFlashRequired_shouldTriggerAe(): Unit = runBlocking { 339 flashAutoFlashRequired_shouldTriggerAe(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) 340 } 341 342 private fun flashAutoFlashRequired_shouldTriggerAe(imageCaptureMode: Int) { 343 val cameraControl = 344 createCameraControl().apply { 345 // Arrange. 346 flashMode = FLASH_MODE_AUTO 347 simulateRepeatingResult( 348 initialDelay = 100, 349 resultParameters = 350 mapOf( 351 CaptureResult.CONTROL_AE_STATE to 352 CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED, 353 ) 354 ) 355 356 // Act. 357 submitStillCaptureRequests( 358 listOf(singleRequest), 359 imageCaptureMode, 360 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 361 ) 362 } 363 364 // Assert 1, verify the CONTROL_AE_PRECAPTURE_TRIGGER is triggered when low-light boost is 365 // off, otherwise, is not triggered. 366 immediateCompleteCapture.verifyRequestResult { 367 it.requestContains( 368 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 369 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START 370 ) != isLowLightBoostEnabled 371 } 372 373 // When low-light boost is on, AE pre-capture is not triggered. Therefore, converged stage 374 // is not required. 375 if (isLowLightBoostEnabled) { 376 return 377 } 378 379 // Switch the repeating result to 3A converged state. 380 cameraControl.simulateRepeatingResult( 381 initialDelay = 500, 382 resultParameters = resultConverged 383 ) 384 385 // Assert 2 that CONTROL_AE_PRECAPTURE_TRIGGER should be cancelled finally when low-light 386 // boost is off, otherwise, TRIGGER_CANCEL is not triggered. 387 if (Build.VERSION.SDK_INT >= 23) { 388 immediateCompleteCapture.verifyRequestResult { 389 it.requestContains( 390 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 391 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL 392 ) 393 } 394 } 395 } 396 397 @Test 398 fun createPipeline_screenFlashTaskAdded() { 399 val camera2CapturePipeline = 400 Camera2CapturePipeline( 401 createCameraControl(), 402 CameraCharacteristicsCompat.toCameraCharacteristicsCompat( 403 ShadowCameraCharacteristics.newCameraCharacteristics(), 404 CAMERA_ID_0, 405 ), 406 Quirks(emptyList()), 407 CameraXExecutors.directExecutor(), 408 CameraXExecutors.myLooperExecutor(), 409 ) 410 411 val pipeline = 412 camera2CapturePipeline.createPipeline( 413 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 414 ImageCapture.FLASH_MODE_SCREEN, 415 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH 416 ) 417 418 var hasScreenFlashTask = false 419 pipeline.mTasks.forEach { task -> 420 if (task is ScreenFlashTask) { 421 hasScreenFlashTask = true 422 } 423 } 424 425 assertThat(hasScreenFlashTask).isTrue() 426 } 427 428 @Test 429 fun miniLatency_withTorchAsFlashQuirk_shouldOpenTorch() { 430 withTorchAsFlashQuirk_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) 431 } 432 433 @Test 434 fun maxQuality_withTorchAsFlashQuirk_shouldOpenTorch() { 435 withTorchAsFlashQuirk_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) 436 } 437 438 private fun withTorchAsFlashQuirk_shouldOpenTorch(imageCaptureMode: Int) { 439 val cameraControl = 440 createCameraControl( 441 // Arrange. 442 quirks = Quirks(listOf(object : UseTorchAsFlashQuirk {})) 443 ) 444 .apply { 445 flashMode = FLASH_MODE_ON 446 simulateRepeatingResult(initialDelay = 100) 447 448 // Act. 449 submitStillCaptureRequests( 450 listOf(singleRequest), 451 imageCaptureMode, 452 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 453 ) 454 } 455 456 // Assert 1 torch should be turned on 457 cameraControl.waitForSessionConfig { 458 if (isLowLightBoostEnabled) { 459 it.isLowLightBoostEnabled() 460 } else { 461 it.isTorchParameterEnabled() 462 } 463 } 464 465 // When low-light boost is on, AE pre-capture is not triggered. Therefore, converged stage 466 // is not required. 467 if (isLowLightBoostEnabled) { 468 return 469 } 470 471 // Switch the repeating result to 3A converged state. 472 cameraControl.simulateRepeatingResult( 473 initialDelay = 500, 474 resultParameters = resultConverged 475 ) 476 477 // Assert 2 torch should be turned off 478 immediateCompleteCapture.verifyRequestResult { it.isTorchParameterDisabled() } 479 } 480 481 @Test 482 fun miniLatency_withTemplateRecord_shouldOpenTorch() { 483 withTemplateRecord_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) 484 } 485 486 @Test 487 fun maxQuality_withTemplateRecord_shouldOpenTorch() { 488 withTemplateRecord_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) 489 } 490 491 private fun withTemplateRecord_shouldOpenTorch(imageCaptureMode: Int) { 492 493 val cameraControl = 494 createCameraControl().apply { 495 // Arrange. 496 setTemplate(CameraDevice.TEMPLATE_RECORD) 497 flashMode = FLASH_MODE_ON 498 simulateRepeatingResult(initialDelay = 100) 499 submitStillCaptureRequests( 500 listOf(singleRequest), 501 imageCaptureMode, 502 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 503 ) 504 } 505 506 // Assert 1 torch should be turned on 507 cameraControl.waitForSessionConfig { 508 if (isLowLightBoostEnabled) { 509 it.isLowLightBoostEnabled() 510 } else { 511 it.isTorchParameterEnabled() 512 } 513 } 514 515 // When low-light boost is on, AE pre-capture is not triggered. Therefore, converged stage 516 // is not required. 517 if (isLowLightBoostEnabled) { 518 return 519 } 520 521 // Switch the repeating result to 3A converged state. 522 cameraControl.simulateRepeatingResult( 523 initialDelay = 500, 524 resultParameters = resultConverged 525 ) 526 527 // Assert 2 torch should be turned off 528 immediateCompleteCapture.verifyRequestResult { it.isTorchParameterDisabled() } 529 } 530 531 @Test 532 fun miniLatency_withFlashTypeTorch_shouldOpenTorch() { 533 withFlashTypeTorch_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) 534 } 535 536 @Test 537 fun maxQuality_withFlashTypeTorch_shouldOpenTorch() { 538 withFlashTypeTorch_shouldOpenTorch(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) 539 } 540 541 private fun withFlashTypeTorch_shouldOpenTorch(imageCaptureMode: Int) { 542 val cameraControl = 543 createCameraControl().apply { 544 flashMode = FLASH_MODE_ON 545 simulateRepeatingResult(initialDelay = 100) 546 submitStillCaptureRequests( 547 listOf(singleRequest), 548 imageCaptureMode, 549 ImageCapture.FLASH_TYPE_USE_TORCH_AS_FLASH, 550 ) 551 } 552 553 // Assert 1 torch should be turned on 554 cameraControl.waitForSessionConfig { 555 if (isLowLightBoostEnabled) { 556 it.isLowLightBoostEnabled() 557 } else { 558 it.isTorchParameterEnabled() 559 } 560 } 561 562 // When low-light boost is on, AE pre-capture is not triggered. Therefore, converged stage 563 // is not required. 564 if (isLowLightBoostEnabled) { 565 return 566 } 567 568 // Switch the repeating result to 3A converged state. 569 cameraControl.simulateRepeatingResult( 570 initialDelay = 500, 571 resultParameters = resultConverged 572 ) 573 574 // Assert 2 torch should be turned off 575 immediateCompleteCapture.verifyRequestResult { it.isTorchParameterDisabled() } 576 } 577 578 @Test 579 fun miniLatency_shouldNoPreCapture(): Unit = runBlocking { 580 // Arrange. 581 val cameraControl = 582 createCameraControl().apply { simulateRepeatingResult(initialDelay = 100) } 583 584 // Act. 585 cameraControl 586 .submitStillCaptureRequests( 587 listOf(singleRequest), 588 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 589 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 590 ) 591 .await() 592 593 // Assert, there is only 1 single capture request. 594 assertThat(immediateCompleteCapture.getAllResults().size).isEqualTo(1) 595 } 596 597 @Test 598 fun submitStillCaptureRequests_withTemplate_templateSent(): Unit = runBlocking { 599 // Arrange. 600 val imageCaptureConfig = 601 CaptureConfig.Builder().let { 602 it.addSurface(fakeStillCaptureSurface) 603 it.templateType = CameraDevice.TEMPLATE_MANUAL 604 it.build() 605 } 606 val cameraControl = 607 createCameraControl().apply { simulateRepeatingResult(initialDelay = 100) } 608 609 // Act. 610 cameraControl 611 .submitStillCaptureRequests( 612 listOf(imageCaptureConfig), 613 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 614 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 615 ) 616 .await() 617 618 // Assert. 619 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 620 captureConfigList 621 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 622 .map { captureConfig -> captureConfig.templateType } 623 .contains(CameraDevice.TEMPLATE_MANUAL) 624 } 625 } 626 627 @Test 628 fun submitStillCaptureRequests_withNoTemplate_templateStillCaptureSent(): Unit = runBlocking { 629 // Arrange. 630 val imageCaptureConfig = 631 CaptureConfig.Builder().apply { addSurface(fakeStillCaptureSurface) }.build() 632 val cameraControl = 633 createCameraControl().apply { simulateRepeatingResult(initialDelay = 100) } 634 635 // Act. 636 cameraControl 637 .submitStillCaptureRequests( 638 listOf(imageCaptureConfig), 639 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 640 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 641 ) 642 .await() 643 644 // Assert. 645 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 646 captureConfigList 647 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 648 .map { captureConfig -> captureConfig.templateType } 649 .contains(CameraDevice.TEMPLATE_STILL_CAPTURE) 650 } 651 } 652 653 @Test 654 fun submitStillCaptureRequests_withTemplateRecord_templateVideoSnapshotSent(): Unit = 655 runBlocking { 656 createCameraControl().apply { 657 // Arrange. 658 setTemplate(CameraDevice.TEMPLATE_RECORD) 659 simulateRepeatingResult(initialDelay = 100) 660 661 // Act. 662 submitStillCaptureRequests( 663 listOf(singleRequest), 664 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 665 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 666 ) 667 .await() 668 } 669 670 // Assert. 671 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 672 captureConfigList 673 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 674 .map { captureConfig -> captureConfig.templateType } 675 .contains(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) 676 } 677 } 678 679 @Config(minSdk = 23) 680 @Test 681 fun submitZslCaptureRequests_withZslTemplate_templateZeroShutterLagSent(): Unit = runBlocking { 682 // Arrange. 683 val imageCaptureConfig = 684 CaptureConfig.Builder().let { 685 it.addSurface(fakeStillCaptureSurface) 686 it.templateType = CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG 687 it.build() 688 } 689 690 val cameraControl = 691 initCameraControlWithZsl( 692 isZslDisabledByFlashMode = false, 693 isZslDisabledByUserCaseConfig = false 694 ) 695 696 // Act. 697 cameraControl 698 .submitStillCaptureRequests( 699 listOf(imageCaptureConfig), 700 ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG, 701 FLASH_MODE_OFF, 702 ) 703 .await() 704 705 // Assert. 706 val templateTypeToVerify = 707 if (Build.VERSION.SDK_INT >= 23) CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG 708 else CameraDevice.TEMPLATE_STILL_CAPTURE 709 710 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 711 captureConfigList 712 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 713 .map { captureConfig -> captureConfig.templateType } 714 .contains(templateTypeToVerify) 715 } 716 } 717 718 @Config(minSdk = 23) 719 @Test 720 fun submitZslCaptureRequests_withZslDisabledByFlashMode_templateStillPictureSent(): Unit = 721 runBlocking { 722 // Arrange. 723 val imageCaptureConfig = 724 CaptureConfig.Builder().let { 725 it.addSurface(fakeStillCaptureSurface) 726 it.templateType = CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG 727 it.build() 728 } 729 730 val cameraControl = 731 initCameraControlWithZsl( 732 isZslDisabledByFlashMode = true, 733 isZslDisabledByUserCaseConfig = false 734 ) 735 736 // Act. 737 cameraControl 738 .submitStillCaptureRequests( 739 listOf(imageCaptureConfig), 740 ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG, 741 FLASH_MODE_OFF, 742 ) 743 .await() 744 745 // Assert. 746 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 747 captureConfigList 748 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 749 .map { captureConfig -> captureConfig.templateType } 750 .contains(CameraDevice.TEMPLATE_STILL_CAPTURE) 751 } 752 } 753 754 @Config(minSdk = 23) 755 @Test 756 fun submitZslCaptureRequests_withZslDisabledByUseCaseConfig_templateStillPictureSent(): Unit = 757 runBlocking { 758 // Arrange. 759 val imageCaptureConfig = 760 CaptureConfig.Builder().let { 761 it.addSurface(fakeStillCaptureSurface) 762 it.templateType = CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG 763 it.build() 764 } 765 766 val cameraControl = 767 initCameraControlWithZsl( 768 isZslDisabledByFlashMode = false, 769 isZslDisabledByUserCaseConfig = true 770 ) 771 772 // Act. 773 cameraControl 774 .submitStillCaptureRequests( 775 listOf(imageCaptureConfig), 776 ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG, 777 FLASH_MODE_OFF, 778 ) 779 .await() 780 781 // Assert. 782 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 783 captureConfigList 784 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 785 .map { captureConfig -> captureConfig.templateType } 786 .contains(CameraDevice.TEMPLATE_STILL_CAPTURE) 787 } 788 } 789 790 @Config(minSdk = 23) 791 @Test 792 fun submitZslCaptureRequests_withNoTemplate_templateStillPictureSent(): Unit = runBlocking { 793 // Arrange. 794 val imageCaptureConfig = 795 CaptureConfig.Builder().let { 796 it.addSurface(fakeStillCaptureSurface) 797 it.build() 798 } 799 val cameraControl = 800 initCameraControlWithZsl( 801 isZslDisabledByFlashMode = false, 802 isZslDisabledByUserCaseConfig = false 803 ) 804 805 // Act. 806 cameraControl 807 .submitStillCaptureRequests( 808 listOf(imageCaptureConfig), 809 ImageCapture.CAPTURE_MODE_ZERO_SHUTTER_LAG, 810 FLASH_MODE_OFF, 811 ) 812 .await() 813 814 // Assert. 815 immediateCompleteCapture.verifyRequestResult { captureConfigList -> 816 captureConfigList 817 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 818 .map { captureConfig -> captureConfig.templateType } 819 .contains(CameraDevice.TEMPLATE_STILL_CAPTURE) 820 } 821 } 822 823 @Test 824 fun captureFailure_taskShouldFailure() { 825 // Arrange. 826 val immediateFailureCapture = 827 object : CameraControlInternal.ControlUpdateCallback { 828 829 override fun onCameraControlUpdateSessionConfig() {} 830 831 override fun onCameraControlCaptureRequests( 832 captureConfigs: MutableList<CaptureConfig> 833 ) { 834 captureConfigs.forEach { captureConfig -> 835 captureConfig.cameraCaptureCallbacks.forEach { 836 it.onCaptureFailed( 837 CaptureConfig.DEFAULT_ID, 838 CameraCaptureFailure(CameraCaptureFailure.Reason.ERROR) 839 ) 840 } 841 } 842 } 843 } 844 val cameraControl = createCameraControl(updateCallback = immediateFailureCapture) 845 846 // Act. 847 val future = 848 cameraControl.submitStillCaptureRequests( 849 listOf(CaptureConfig.Builder().build()), 850 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 851 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 852 ) 853 854 // Assert. 855 val exception = 856 assertThrows(ExecutionException::class.java) { future.get(1, TimeUnit.SECONDS) } 857 assertThat(exception.cause).isInstanceOf(ImageCaptureException::class.java) 858 assertThat((exception.cause as ImageCaptureException).imageCaptureError) 859 .isEqualTo(ImageCapture.ERROR_CAPTURE_FAILED) 860 } 861 862 @Test 863 fun captureCancel_taskShouldFailureWithCAMERA_CLOSED() { 864 // Arrange. 865 val immediateCancelCapture = 866 object : CameraControlInternal.ControlUpdateCallback { 867 868 override fun onCameraControlUpdateSessionConfig() {} 869 870 override fun onCameraControlCaptureRequests( 871 captureConfigs: MutableList<CaptureConfig> 872 ) { 873 captureConfigs.forEach { captureConfig -> 874 captureConfig.cameraCaptureCallbacks.forEach { 875 it.onCaptureCancelled(CaptureConfig.DEFAULT_ID) 876 } 877 } 878 } 879 } 880 val cameraControl = createCameraControl(updateCallback = immediateCancelCapture) 881 882 // Act. 883 val future = 884 cameraControl.submitStillCaptureRequests( 885 listOf(CaptureConfig.Builder().build()), 886 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 887 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 888 ) 889 890 // Assert. 891 val exception = 892 assertThrows(ExecutionException::class.java) { future.get(1, TimeUnit.SECONDS) } 893 assertThat(exception.cause).isInstanceOf(ImageCaptureException::class.java) 894 assertThat((exception.cause as ImageCaptureException).imageCaptureError) 895 .isEqualTo(ImageCapture.ERROR_CAMERA_CLOSED) 896 } 897 898 @Test 899 fun overrideAeModeForStillCapture_quirkAbsent_notOverride(): Unit = runBlocking { 900 // Arrange. Not have the quirk. 901 val cameraControl = 902 createCameraControl(quirks = Quirks(emptyList())).apply { 903 flashMode = FLASH_MODE_ON // Set flash ON to enable aePreCapture 904 simulateRepeatingResult(initialDelay = 100) // Make sures flashMode is updated. 905 } 906 907 // Act. 908 val deferred = 909 cameraControl.submitStillCaptureRequests( 910 listOf(singleRequest), 911 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 912 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 913 ) 914 // Switch the repeating result to 3A converged state. 915 cameraControl.simulateRepeatingResult( 916 initialDelay = 500, 917 resultParameters = resultConverged 918 ) 919 920 deferred.await() 921 922 // Assert. 923 // AE mode should not be overridden 924 immediateCompleteCapture 925 .getAllResults() 926 .flatten() 927 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 928 .let { stillCaptureRequests -> 929 assertThat(stillCaptureRequests).isNotEmpty() 930 stillCaptureRequests.forEach { config -> 931 assertThat( 932 config 933 .toCamera2Config() 934 .getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE) 935 ) 936 .isNull() 937 } 938 } 939 } 940 941 @Test 942 @Ignore("AutoFlashUnderExposedQuirk was disabled, ignoring the test.") 943 fun overrideAeModeForStillCapture_aePrecaptureStarted_override(): Unit = runBlocking { 944 // Arrange. 945 val cameraControl = 946 createCameraControl(quirks = Quirks(listOf(AutoFlashUnderExposedQuirk()))).apply { 947 flashMode = FLASH_MODE_AUTO // Set flash auto to enable aePreCapture 948 simulateRepeatingResult( 949 initialDelay = 100, 950 resultParameters = 951 mapOf( 952 CaptureResult.CONTROL_AE_STATE to 953 CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED, 954 ) 955 ) // Make sures flashMode is updated and the flash is required. 956 } 957 958 // Act. 959 cameraControl.submitStillCaptureRequests( 960 listOf(singleRequest), 961 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 962 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 963 ) 964 965 // Switch the repeating result to 3A converged state. 966 cameraControl.simulateRepeatingResult( 967 initialDelay = 500, 968 resultParameters = resultConverged 969 ) 970 971 // Assert. 972 // AE mode should be overridden to CONTROL_AE_MODE_ON_ALWAYS_FLASH 973 immediateCompleteCapture.verifyRequestResult { configList -> 974 configList.requestContains( 975 CaptureRequest.CONTROL_AE_MODE, 976 CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH 977 ) && configList.surfaceContains(fakeStillCaptureSurface) 978 } 979 } 980 981 @Test 982 fun overrideAeModeForStillCapture_aePrecaptureFinish_notOverride(): Unit = runBlocking { 983 // Arrange. 984 val cameraControl = 985 createCameraControl(quirks = Quirks(listOf(AutoFlashUnderExposedQuirk()))).apply { 986 flashMode = FLASH_MODE_AUTO // Set flash auto to enable aePreCapture 987 simulateRepeatingResult( 988 initialDelay = 100, 989 resultParameters = 990 mapOf( 991 CaptureResult.CONTROL_AE_STATE to 992 CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED, 993 ) 994 ) // Make sures flashMode is updated and the flash is required. 995 } 996 val firstCapture = 997 cameraControl.submitStillCaptureRequests( 998 listOf(singleRequest), 999 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 1000 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 1001 ) 1002 1003 // Switch the repeating result to 3A converged state. 1004 cameraControl.simulateRepeatingResult( 1005 initialDelay = 500, 1006 resultParameters = resultConverged 1007 ) 1008 firstCapture.await() 1009 immediateCompleteCapture.clearAllResults() // Clear the result of the firstCapture 1010 1011 // Act. 1012 // Set flash OFF to disable aePreCapture for testing 1013 cameraControl.flashMode = FLASH_MODE_OFF 1014 val result = 1015 cameraControl 1016 .submitStillCaptureRequests( 1017 listOf(singleRequest), 1018 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 1019 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 1020 ) 1021 .await() 1022 1023 // Assert. The second capturing should not override the AE mode. 1024 assertThat(result.size).isEqualTo(1) 1025 immediateCompleteCapture 1026 .getAllResults() 1027 .flatten() 1028 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 1029 .let { stillCaptureRequests -> 1030 assertThat(stillCaptureRequests).isNotEmpty() 1031 stillCaptureRequests.forEach { config -> 1032 assertThat( 1033 config 1034 .toCamera2Config() 1035 .getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE) 1036 ) 1037 .isNull() 1038 } 1039 } 1040 } 1041 1042 @Test 1043 fun overrideAeModeForStillCapture_noAePrecaptureTriggered_notOverride(): Unit = runBlocking { 1044 // Arrange. 1045 val cameraControl = 1046 createCameraControl(quirks = Quirks(listOf(AutoFlashUnderExposedQuirk()))).apply { 1047 flashMode = FLASH_MODE_AUTO // Set flash auto to enable aePreCapture 1048 1049 // Make sures flashMode is updated but the flash is not required. 1050 simulateRepeatingResult(initialDelay = 100) 1051 } 1052 1053 // Act. 1054 val deferred = 1055 cameraControl.submitStillCaptureRequests( 1056 listOf(singleRequest), 1057 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 1058 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 1059 ) 1060 1061 // Switch the repeating result to 3A converged state. 1062 cameraControl.simulateRepeatingResult( 1063 initialDelay = 500, 1064 resultParameters = resultConverged 1065 ) 1066 1067 deferred.await() 1068 1069 // Assert. 1070 // AE mode should not be overridden 1071 immediateCompleteCapture 1072 .getAllResults() 1073 .flatten() 1074 .filter { it.surfaces.contains(fakeStillCaptureSurface) } 1075 .let { stillCaptureRequests -> 1076 assertThat(stillCaptureRequests).isNotEmpty() 1077 stillCaptureRequests.forEach { config -> 1078 assertThat( 1079 config 1080 .toCamera2Config() 1081 .getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE) 1082 ) 1083 .isNull() 1084 } 1085 } 1086 } 1087 1088 @Test 1089 fun skip3AConvergenceInFlashOn_when3AModeOff(): Unit = runBlocking { 1090 // Arrange. Not have the quirk. 1091 val cameraControl = 1092 createCameraControl(quirks = Quirks(emptyList())).apply { 1093 flashMode = FLASH_MODE_ON // Set flash ON 1094 simulateRepeatingResult(initialDelay = 100) // Make sures flashMode is updated. 1095 } 1096 1097 // Act. 1098 val deferred = 1099 cameraControl.submitStillCaptureRequests( 1100 listOf(singleRequest), 1101 ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY, 1102 ImageCapture.FLASH_TYPE_ONE_SHOT_FLASH, 1103 ) 1104 // Switch the repeating result to 3A converged state with 3A modes being set to OFF. 1105 cameraControl.simulateRepeatingResult( 1106 initialDelay = 500, 1107 resultParameters = resultConvergedWith3AModeOff 1108 ) 1109 1110 // Ensure 3A is converged (skips 3A check) and capture request is sent. 1111 withTimeout(2000) { assertThat(deferred.await()) } 1112 } 1113 1114 @Test 1115 fun waitForResultCompletes_whenCaptureResultProvided_noTimeout_noCheckingCondition() { 1116 val cameraControl = 1117 createCameraControl().apply { simulateRepeatingResult(initialDelay = 1) } 1118 1119 val future = Camera2CapturePipeline.waitForResult(cameraControl, null) 1120 1121 future.get(500, TimeUnit.MILLISECONDS) 1122 } 1123 1124 @Test 1125 fun waitForResultCompletes_whenCaptureResultProvided_noTimeout_specificCheckingCondition() { 1126 val cameraControl = 1127 createCameraControl().apply { simulateRepeatingResult(initialDelay = 1) } 1128 1129 cameraControl.simulateRepeatingResult(initialDelay = 50, resultParameters = resultConverged) 1130 1131 val future = 1132 Camera2CapturePipeline.waitForResult(cameraControl) { result -> 1133 Camera2CapturePipeline.is3AConverged(result, false) 1134 } 1135 1136 future.get(500, TimeUnit.MILLISECONDS).verifyResultFields(resultConverged) 1137 } 1138 1139 @Test 1140 fun waitForResultDoesNotComplete_whenNoResult_noCheckingCondition() { 1141 // tested for 500ms 1142 Camera2CapturePipeline.waitForResult(createCameraControl(), null) 1143 .awaitException(500, TimeoutException::class.java) 1144 } 1145 1146 @Test 1147 fun waitForResultDoesNotComplete_whenNoMatchingResult() { 1148 // tested for 500ms 1149 Camera2CapturePipeline.waitForResult( 1150 createCameraControl().apply { simulateRepeatingResult(initialDelay = 1) } 1151 ) { result -> 1152 Camera2CapturePipeline.is3AConverged(result, false) 1153 } 1154 .awaitException(500, TimeoutException::class.java) 1155 } 1156 1157 @Test 1158 fun waitForResultCompletesWithNullResult_whenNoResultWithinTimeout_noCheckingCondition() { 1159 val result = 1160 Camera2CapturePipeline.waitForResult( 1161 TimeUnit.MILLISECONDS.toNanos(500), 1162 executorService, 1163 createCameraControl(), 1164 null 1165 ) 1166 .get( 1167 1, 1168 TimeUnit.SECONDS 1169 ) // timeout exception will be thrown if not completed within 1s 1170 1171 assertThat(result).isNull() 1172 } 1173 1174 @Test 1175 fun waitForResultCompletesWithNullResult_whenNoMatchingResultWithinTimeout() { 1176 val result = 1177 Camera2CapturePipeline.waitForResult( 1178 TimeUnit.MILLISECONDS.toNanos(500), 1179 executorService, 1180 createCameraControl().apply { simulateRepeatingResult(initialDelay = 1) } 1181 ) { result -> 1182 Camera2CapturePipeline.is3AConverged(result, false) 1183 } 1184 .get( 1185 1, 1186 TimeUnit.SECONDS 1187 ) // timeout exception will be thrown if not completed within 1s 1188 1189 assertThat(result).isNull() 1190 } 1191 1192 private fun TotalCaptureResult.verifyResultFields( 1193 expectedFields: Map<CaptureResult.Key<*>, Any> 1194 ) { 1195 assertThat(this).isNotNull() 1196 expectedFields.forEach { entry -> assertThat(this[entry.key]).isEqualTo(entry.value) } 1197 } 1198 1199 private fun ListenableFuture<*>.awaitException(timeoutMillis: Long, exceptionType: Class<*>) { 1200 try { 1201 get(timeoutMillis, TimeUnit.MILLISECONDS) 1202 } catch (e: ExecutionException) { 1203 if (exceptionType != ExecutionException::class.java) { 1204 assertThat(e.cause).isInstanceOf(exceptionType) 1205 } 1206 } catch (e: Exception) { 1207 assertThat(e).isInstanceOf(exceptionType) 1208 } 1209 } 1210 1211 private fun Camera2CameraControlImpl.waitForSessionConfig( 1212 checkResult: (sessionConfig: SessionConfig) -> Boolean = { true } 1213 ) { 1214 var verifyCount = 0 1215 while (true) { 1216 immediateCompleteCapture.waitForSessionConfigUpdate() 1217 if (checkResult(sessionConfig)) { 1218 return 1219 } 1220 Truth.assertWithMessage("Verify over 5 times").that(++verifyCount).isLessThan(5) 1221 } 1222 } 1223 1224 private fun SessionConfig.isTorchParameterEnabled(): Boolean { 1225 val config = toCamera2Config() 1226 1227 return config.getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, null) == 1228 CaptureRequest.CONTROL_AE_MODE_ON && 1229 config.getCaptureRequestOption(CaptureRequest.FLASH_MODE, null) == 1230 CameraMetadata.FLASH_MODE_TORCH 1231 } 1232 1233 private fun SessionConfig.isLowLightBoostEnabled(): Boolean { 1234 val config = toCamera2Config() 1235 1236 return config.getCaptureRequestOption(CaptureRequest.CONTROL_AE_MODE, null) == 1237 CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY 1238 } 1239 1240 private fun List<CaptureConfig>.isTorchParameterDisabled() = 1241 requestContains( 1242 CaptureRequest.CONTROL_AE_MODE, 1243 CaptureRequest.CONTROL_AE_MODE_ON, 1244 ) && 1245 requestContains( 1246 CaptureRequest.FLASH_MODE, 1247 CaptureRequest.FLASH_MODE_OFF, 1248 ) 1249 1250 private fun List<CaptureConfig>.requestContains( 1251 key: CaptureRequest.Key<*>, 1252 value: Any? 1253 ): Boolean { 1254 forEach { config -> 1255 if (value == config.toCamera2Config().getCaptureRequestOption(key, null)) { 1256 return true 1257 } 1258 } 1259 return false 1260 } 1261 1262 private fun List<CaptureConfig>.surfaceContains(surface: DeferrableSurface): Boolean { 1263 forEach { config -> 1264 if (config.surfaces.contains(surface)) { 1265 return true 1266 } 1267 } 1268 return false 1269 } 1270 1271 private fun Camera2CameraControlImpl.simulateRepeatingResult( 1272 initialDelay: Long = 100, 1273 period: Long = 100, // in milliseconds 1274 resultParameters: Map<CaptureResult.Key<*>, Any> = mutableMapOf(), 1275 requestCountLatch: CountDownLatch? = null, 1276 scheduledRunnableExecutor: Executor = executorService 1277 ) { 1278 runningRepeatingStream = 1279 executorService.scheduleAtFixedRate( 1280 { 1281 scheduledRunnableExecutor.execute { 1282 val tagBundle = sessionConfig.repeatingCaptureConfig.tagBundle 1283 val requestOptions = 1284 sessionConfig.repeatingCaptureConfig.implementationOptions 1285 val resultOptions = 1286 baseRepeatingResult.toMutableMap().apply { putAll(resultParameters) } 1287 sendRepeatingResult(tagBundle, requestOptions.toParameters(), resultOptions) 1288 requestCountLatch?.countDown() 1289 } 1290 }, 1291 initialDelay, 1292 period, 1293 TimeUnit.MILLISECONDS 1294 ) 1295 } 1296 1297 private fun Camera2CameraControlImpl.sendRepeatingResult( 1298 requestTag: Any? = null, 1299 requestParameters: Map<CaptureRequest.Key<*>, Any>, 1300 resultParameters: Map<CaptureResult.Key<*>, Any>, 1301 ) { 1302 val request = mock(CaptureRequest::class.java) 1303 Mockito.`when`(request.tag).thenReturn(requestTag) 1304 requestParameters.forEach { (key, any) -> Mockito.`when`(request.get(key)).thenReturn(any) } 1305 1306 val result = mock(TotalCaptureResult::class.java) 1307 Mockito.`when`(result.request).thenReturn(request) 1308 resultParameters.forEach { (key, any) -> Mockito.`when`(result.get(key)).thenReturn(any) } 1309 1310 sessionConfig.repeatingCameraCaptureCallbacks.toList().forEach { 1311 CaptureCallbackConverter.toCaptureCallback(it) 1312 .onCaptureCompleted(mock(CameraCaptureSession::class.java), request, result) 1313 } 1314 } 1315 1316 private fun CaptureConfig.toCamera2Config() = Camera2ImplConfig(implementationOptions) 1317 1318 private fun SessionConfig.toCamera2Config() = Camera2ImplConfig(implementationOptions) 1319 1320 private fun createCameraControl( 1321 cameraId: String = CAMERA_ID_0, 1322 quirks: Quirks? = null, 1323 updateCallback: CameraControlInternal.ControlUpdateCallback = immediateCompleteCapture, 1324 addTorchFlashRequiredFor3aUpdateQuirk: Boolean = false, 1325 executor: Executor = executorService, 1326 ): Camera2CameraControlImpl { 1327 val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager 1328 val characteristics = cameraManager.getCameraCharacteristics(cameraId) 1329 val characteristicsCompat = 1330 CameraCharacteristicsCompat.toCameraCharacteristicsCompat(characteristics, cameraId) 1331 var cameraQuirk = quirks ?: CameraQuirks.get(cameraId, characteristicsCompat) 1332 1333 if (addTorchFlashRequiredFor3aUpdateQuirk) { 1334 cameraQuirk = 1335 Quirks( 1336 cameraQuirk.getAll(Quirk::class.java).apply { 1337 add(TorchFlashRequiredFor3aUpdateQuirk(characteristicsCompat)) 1338 } 1339 ) 1340 } 1341 1342 return Camera2CameraControlImpl( 1343 characteristicsCompat, 1344 executorService, 1345 executor, 1346 updateCallback, 1347 cameraQuirk 1348 ) 1349 .apply { 1350 setActive(true) 1351 incrementUseCount() 1352 this.screenFlash = testScreenFlash 1353 // Applies low-light boost setting 1354 enableLowLightBoostAndAssert(this) 1355 } 1356 } 1357 1358 private fun initCameras() { 1359 Shadow.extract<ShadowCameraManager>(context.getSystemService(Context.CAMERA_SERVICE)) 1360 .apply { addCamera(CAMERA_ID_0, intiCharacteristic0()) } 1361 } 1362 1363 private fun intiCharacteristic0(): CameraCharacteristics { 1364 return ShadowCameraCharacteristics.newCameraCharacteristics().also { 1365 Shadow.extract<ShadowCameraCharacteristics>(it).apply { 1366 set(CameraCharacteristics.FLASH_INFO_AVAILABLE, true) 1367 set( 1368 CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES, 1369 mutableListOf<Int>() 1370 .apply { 1371 add(CaptureRequest.CONTROL_AE_MODE_OFF) 1372 add(CaptureRequest.CONTROL_AE_MODE_ON) 1373 add(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH) 1374 add(CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH) 1375 add(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) 1376 add(CaptureRequest.CONTROL_AE_MODE_ON_EXTERNAL_FLASH) 1377 if (Build.VERSION.SDK_INT >= 35) { 1378 add(CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY) 1379 } 1380 } 1381 .toIntArray() 1382 ) 1383 set(CameraCharacteristics.LENS_FACING, CameraMetadata.LENS_FACING_BACK) 1384 } 1385 } 1386 } 1387 1388 private val immediateCompleteCapture = 1389 object : CameraControlInternal.ControlUpdateCallback { 1390 private val lock = Any() 1391 private val allResults: MutableList<List<CaptureConfig>> = mutableListOf() 1392 val waitingList = 1393 mutableListOf< 1394 Pair<CountDownLatch, (captureRequests: List<CaptureConfig>) -> Boolean> 1395 >() 1396 var updateSessionCountDown = CountDownLatch(1) 1397 1398 fun verifyRequestResult( 1399 timeout: Long = TimeUnit.SECONDS.toMillis(5), 1400 verifyResults: (captureRequests: List<CaptureConfig>) -> Boolean = { true } 1401 ) { 1402 val resultPair = Pair(CountDownLatch(1), verifyResults) 1403 synchronized(lock) { 1404 allResults.forEach { 1405 if (verifyResults(it)) { 1406 return 1407 } 1408 } 1409 waitingList.add(resultPair) 1410 } 1411 assertThat(resultPair.first.await(timeout, TimeUnit.MILLISECONDS)).isTrue() 1412 waitingList.remove(resultPair) 1413 } 1414 1415 fun waitForSessionConfigUpdate(timeout: Long = TimeUnit.SECONDS.toMillis(5)) { 1416 // No matter onCameraControlUpdateSessionConfig is called before or after 1417 // the waitForSessionConfigUpdate call, the count down operation should be 1418 // executed correctly on the updateSessionCountDown object 1419 updateSessionCountDown.await(timeout, TimeUnit.MILLISECONDS) 1420 1421 // Reset count down latch here for next call of waitForSessionConfigUpdate 1422 updateSessionCountDown = CountDownLatch(1) 1423 } 1424 1425 override fun onCameraControlUpdateSessionConfig() { 1426 // Only count down when count is still larger than 1 1427 if (updateSessionCountDown.count > 0) { 1428 updateSessionCountDown.countDown() 1429 } 1430 } 1431 1432 override fun onCameraControlCaptureRequests( 1433 captureConfigs: MutableList<CaptureConfig> 1434 ) { 1435 synchronized(lock) { allResults.add(captureConfigs) } 1436 waitingList.toList().forEach { 1437 if (it.second(captureConfigs)) { 1438 it.first.countDown() 1439 } 1440 } 1441 1442 // Complete the single capture with an empty result. 1443 captureConfigs.forEach { captureConfig -> 1444 captureConfig.cameraCaptureCallbacks.forEach { 1445 it.onCaptureCompleted( 1446 CaptureConfig.DEFAULT_ID, 1447 CameraCaptureResult.EmptyCameraCaptureResult() 1448 ) 1449 } 1450 } 1451 } 1452 1453 fun clearAllResults() = synchronized(lock) { allResults.clear() } 1454 1455 fun getAllResults() = synchronized(lock) { allResults.toList() } 1456 } 1457 1458 /** Convert the Config to the CaptureRequest key-value map. */ 1459 private fun androidx.camera.core.impl.Config.toParameters(): Map<CaptureRequest.Key<*>, Any> { 1460 val parameters = mutableMapOf<CaptureRequest.Key<*>, Any>() 1461 for (configOption in listOptions()) { 1462 val requestKey = configOption.token as? CaptureRequest.Key<*> ?: continue 1463 val value = retrieveOption(configOption) ?: continue 1464 parameters[requestKey] = value 1465 } 1466 1467 return parameters 1468 } 1469 1470 private fun createCameraCharacteristicsCompat( 1471 hasCapabilities: Boolean, 1472 isYuvReprocessingSupported: Boolean, 1473 isPrivateReprocessingSupported: Boolean 1474 ): CameraCharacteristicsCompat { 1475 val characteristics = ShadowCameraCharacteristics.newCameraCharacteristics() 1476 val shadowCharacteristics = Shadow.extract<ShadowCameraCharacteristics>(characteristics) 1477 1478 val capabilities = arrayListOf<Int>() 1479 if (isYuvReprocessingSupported) { 1480 capabilities.add(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) 1481 } 1482 if (isPrivateReprocessingSupported) { 1483 capabilities.add( 1484 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING 1485 ) 1486 } 1487 1488 if (hasCapabilities) { 1489 shadowCharacteristics.set( 1490 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES, 1491 capabilities.toIntArray() 1492 ) 1493 } 1494 1495 return CameraCharacteristicsCompat.toCameraCharacteristicsCompat( 1496 characteristics, 1497 CAMERA_ID_0 1498 ) 1499 } 1500 1501 @RequiresApi(23) 1502 private fun initCameraControlWithZsl( 1503 isZslDisabledByFlashMode: Boolean, 1504 isZslDisabledByUserCaseConfig: Boolean 1505 ): Camera2CameraControlImpl { 1506 val cameraControl = 1507 createCameraControl().apply { simulateRepeatingResult(initialDelay = 100) } 1508 1509 val zslControl = 1510 ZslControlImpl( 1511 createCameraCharacteristicsCompat( 1512 hasCapabilities = true, 1513 isYuvReprocessingSupported = true, 1514 isPrivateReprocessingSupported = true 1515 ), 1516 executorService 1517 ) 1518 1519 // Only need to initialize when not disabled 1520 if (!isZslDisabledByFlashMode && !isZslDisabledByUserCaseConfig) { 1521 val captureResult = FakeCameraCaptureResult() 1522 captureResult.afState = AfState.LOCKED_FOCUSED 1523 captureResult.aeState = AeState.CONVERGED 1524 captureResult.awbState = AwbState.CONVERGED 1525 val imageProxy = FakeImageProxy(CameraCaptureResultImageInfo(captureResult)) 1526 imageProxy.image = mock(Image::class.java) 1527 zslControl.mImageRingBuffer.enqueue(imageProxy) 1528 zslControl.mReprocessingImageWriterHolder = 1529 ZslControlImpl.ImageWriterHolder(executorService).apply { 1530 onImageWriterCreated(mock(ImageWriter::class.java)) 1531 } 1532 } 1533 1534 zslControl.isZslDisabledByFlashMode = isZslDisabledByFlashMode 1535 zslControl.isZslDisabledByUserCaseConfig = isZslDisabledByUserCaseConfig 1536 1537 cameraControl.mZslControl = zslControl 1538 1539 // Applies low-light boost setting 1540 enableLowLightBoostAndAssert(cameraControl) 1541 1542 return cameraControl 1543 } 1544 1545 private fun enableLowLightBoostAndAssert(cameraControlImpl: Camera2CameraControlImpl) { 1546 if (isLowLightBoostEnabled) { 1547 executorService.run { cameraControlImpl.enableLowLightBoostInternal(true) } 1548 } 1549 assertThat(cameraControlImpl.isLowLightBoostOn).isEqualTo(isLowLightBoostEnabled) 1550 } 1551 } 1552