1 /* <lambda>null2 * 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 androidx.camera.extensions 18 19 import android.content.Context 20 import android.hardware.camera2.CameraCharacteristics 21 import android.hardware.camera2.CaptureRequest 22 import android.util.Pair 23 import android.util.Range 24 import android.util.Size 25 import androidx.camera.core.Camera 26 import androidx.camera.core.CameraInfo 27 import androidx.camera.core.CameraSelector 28 import androidx.camera.core.CameraXConfig 29 import androidx.camera.core.impl.AdapterCameraInfo 30 import androidx.camera.core.impl.CameraInfoInternal 31 import androidx.camera.core.impl.SessionProcessor 32 import androidx.camera.extensions.impl.ExtensionsTestlibControl 33 import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl 34 import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl 35 import androidx.camera.extensions.impl.advanced.OutputSurfaceConfigurationImpl 36 import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl 37 import androidx.camera.extensions.impl.advanced.RequestProcessorImpl 38 import androidx.camera.extensions.impl.advanced.SessionProcessorImpl 39 import androidx.camera.extensions.internal.Camera2ExtensionsUtil.shouldUseCamera2Extensions 40 import androidx.camera.extensions.internal.ClientVersion 41 import androidx.camera.extensions.internal.ExtensionVersion 42 import androidx.camera.extensions.internal.ExtensionsUtils 43 import androidx.camera.extensions.internal.VendorExtender 44 import androidx.camera.extensions.internal.Version 45 import androidx.camera.extensions.internal.sessionprocessor.AdvancedSessionProcessor 46 import androidx.camera.extensions.internal.sessionprocessor.BasicExtenderSessionProcessor 47 import androidx.camera.extensions.internal.sessionprocessor.Camera2ExtensionsSessionProcessor 48 import androidx.camera.extensions.util.ExtensionsTestUtil 49 import androidx.camera.extensions.util.ExtensionsTestUtil.CAMERA_PIPE_IMPLEMENTATION_OPTION 50 import androidx.camera.lifecycle.ProcessCameraProvider 51 import androidx.camera.testing.impl.CameraPipeConfigTestRule 52 import androidx.camera.testing.impl.CameraUtil 53 import androidx.camera.testing.impl.fakes.FakeLifecycleOwner 54 import androidx.camera.testing.impl.fakes.FakeUseCase 55 import androidx.test.core.app.ApplicationProvider 56 import androidx.test.filters.SdkSuppress 57 import androidx.test.filters.SmallTest 58 import androidx.test.platform.app.InstrumentationRegistry 59 import androidx.testutils.assertThrows 60 import com.google.common.truth.Truth.assertThat 61 import java.util.Collections 62 import java.util.concurrent.TimeUnit 63 import kotlinx.coroutines.Dispatchers 64 import kotlinx.coroutines.runBlocking 65 import kotlinx.coroutines.withContext 66 import org.junit.After 67 import org.junit.Assume.assumeFalse 68 import org.junit.Assume.assumeTrue 69 import org.junit.Before 70 import org.junit.Rule 71 import org.junit.Test 72 import org.junit.runner.RunWith 73 import org.junit.runners.Parameterized 74 75 @SmallTest 76 @RunWith(Parameterized::class) 77 @SdkSuppress(minSdkVersion = 21) 78 class ExtensionsManagerTest( 79 private val implName: String, 80 private val cameraXConfig: CameraXConfig, 81 private val implType: ExtensionsTestlibControl.ImplementationType, 82 @field:ExtensionMode.Mode @param:ExtensionMode.Mode private val extensionMode: Int, 83 @field:CameraSelector.LensFacing @param:CameraSelector.LensFacing private val lensFacing: Int 84 ) { 85 @get:Rule 86 val cameraPipeConfigTestRule = 87 CameraPipeConfigTestRule(active = implName == CAMERA_PIPE_IMPLEMENTATION_OPTION) 88 89 private val context = InstrumentationRegistry.getInstrumentation().context 90 91 private lateinit var cameraProvider: ProcessCameraProvider 92 93 private lateinit var extensionsManager: ExtensionsManager 94 95 private lateinit var baseCameraSelector: CameraSelector 96 97 @Before 98 @Throws(Exception::class) 99 fun setUp() { 100 assumeTrue( 101 ExtensionsTestUtil.isTargetDeviceAvailableForExtensions(lensFacing, extensionMode) 102 ) 103 104 ProcessCameraProvider.configureInstance(cameraXConfig) 105 cameraProvider = ProcessCameraProvider.getInstance(context)[10000, TimeUnit.MILLISECONDS] 106 107 assumeTrue(CameraUtil.hasCameraWithLensFacing(lensFacing)) 108 109 baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build() 110 ExtensionsTestlibControl.getInstance().setImplementationType(implType) 111 } 112 113 @After 114 fun teardown(): Unit = runBlocking { 115 if (::cameraProvider.isInitialized) { 116 cameraProvider.shutdownAsync()[10000, TimeUnit.MILLISECONDS] 117 } 118 119 if (::extensionsManager.isInitialized) { 120 extensionsManager.shutdown()[10000, TimeUnit.MILLISECONDS] 121 } 122 } 123 124 companion object { 125 val context: Context = ApplicationProvider.getApplicationContext() 126 127 @JvmStatic 128 @Parameterized.Parameters( 129 name = "cameraXConfig = {0}, implType = {2}, mode = {3}, facing = {4}" 130 ) 131 fun data(): Collection<Array<Any>> { 132 return ExtensionsTestUtil.getAllImplExtensionsLensFacingCombinations(context, false) 133 } 134 } 135 136 @Test 137 fun getInstanceSuccessfully_whenExtensionAvailabilityIsNotAvailable() { 138 extensionsManager = 139 ExtensionsManager.getInstanceAsync(context, cameraProvider, ClientVersion("99.0.0"))[ 140 10000, TimeUnit.MILLISECONDS] 141 142 assumeTrue( 143 extensionsManager.extensionsAvailability != 144 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 145 ) 146 assertThat(extensionsManager).isNotNull() 147 } 148 149 @Test 150 fun getExtensionsCameraSelectorThrowsException_whenExtensionAvailabilityIsNotAvailable() { 151 extensionsManager = 152 ExtensionsManager.getInstanceAsync(context, cameraProvider, ClientVersion("99.0.0"))[ 153 10000, TimeUnit.MILLISECONDS] 154 155 assumeTrue( 156 extensionsManager.extensionsAvailability != 157 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 158 ) 159 160 val baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build() 161 162 assertThrows<IllegalArgumentException> { 163 extensionsManager.getExtensionEnabledCameraSelector(baseCameraSelector, extensionMode) 164 } 165 } 166 167 @Test 168 fun getExtensionsCameraSelectorThrowsException_whenExtensionModeIsNotSupported() { 169 extensionsManager = 170 ExtensionsManager.getInstanceAsync(context, cameraProvider)[ 171 10000, TimeUnit.MILLISECONDS] 172 val baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build() 173 174 assumeFalse(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode)) 175 176 assertThrows<IllegalArgumentException> { 177 extensionsManager.getExtensionEnabledCameraSelector(baseCameraSelector, extensionMode) 178 } 179 } 180 181 @Test 182 fun returnNewCameraSelector_whenExtensionModeIsSupprted() { 183 checkExtensionAvailabilityAndInit() 184 185 val resultCameraSelector = 186 extensionsManager.getExtensionEnabledCameraSelector(baseCameraSelector, extensionMode) 187 assertThat(resultCameraSelector).isNotNull() 188 assertThat(resultCameraSelector).isNotEqualTo(baseCameraSelector) 189 } 190 191 @Test 192 fun correctAvailability_whenExtensionIsNotAvailable() { 193 // Skips the test if extensions availability is disabled by quirk. 194 assumeFalse( 195 ExtensionsTestUtil.extensionsDisabledByQuirk( 196 CameraUtil.getCameraIdWithLensFacing(lensFacing)!! 197 ) 198 ) 199 200 extensionsManager = 201 ExtensionsManager.getInstanceAsync(context, cameraProvider)[ 202 10000, TimeUnit.MILLISECONDS] 203 val baseCameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build() 204 205 assumeFalse(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode)) 206 207 for (cameraInfo in cameraProvider.availableCameraInfos) { 208 val characteristics = 209 (cameraInfo as CameraInfoInternal).cameraCharacteristics as CameraCharacteristics 210 // Checks lens facing first 211 val currentLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) 212 if (currentLensFacing != lensFacing) { 213 continue 214 } 215 216 // Checks whether the specified extension mode is available by camera info and it 217 // must be false 218 assertThat(isExtensionAvailableByCameraInfo(cameraInfo)).isFalse() 219 } 220 } 221 222 @Test 223 fun filterCorrectCamera_whenExtensionIsAvailable(): Unit = runBlocking { 224 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 225 226 // Calls bind to lifecycle to get the selected camera 227 lateinit var camera: Camera 228 withContext(Dispatchers.Main) { 229 camera = cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 230 } 231 232 val cameraId = (camera.cameraInfo as CameraInfoInternal).cameraId 233 234 // Checks each camera in the available camera list that the selected camera must be the 235 // first one supporting the specified extension mode in the same lens facing 236 for (cameraInfo in cameraProvider.availableCameraInfos) { 237 val characteristics = 238 (cameraInfo as CameraInfoInternal).cameraCharacteristics as CameraCharacteristics 239 240 // Checks lens facing first 241 val currentLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) 242 if (currentLensFacing != lensFacing) { 243 continue 244 } 245 246 // Checks whether the specified extension mode is available by camera info 247 val isSupported = isExtensionAvailableByCameraInfo(cameraInfo) 248 val currentCameraId = cameraInfo.cameraId 249 250 if (currentCameraId.equals(cameraId)) { 251 assertThat(isSupported).isTrue() 252 break 253 } else { 254 // Any other camera in front of the selected camera in the available cameras list 255 // must not support the specified extension mode. 256 assertThat(isSupported).isFalse() 257 } 258 } 259 } 260 261 @Test 262 fun correctCameraConfigIsSet_withSupportedExtensionCameraSelector(): Unit = runBlocking { 263 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 264 265 lateinit var camera: Camera 266 withContext(Dispatchers.Main) { 267 camera = cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 268 } 269 270 var extensionsConfig = camera.extendedConfig as ExtensionsConfig 271 assertThat(extensionsConfig.extensionMode).isEqualTo(extensionMode) 272 } 273 274 @Test 275 fun getEstimatedCaptureLatencyRange_returnValueFromExtender() { 276 extensionsManager = 277 ExtensionsManager.getInstanceAsync( 278 context, 279 cameraProvider, 280 )[10000, TimeUnit.MILLISECONDS] 281 282 assumeTrue( 283 extensionsManager.extensionsAvailability == 284 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 285 ) 286 // Skips the test when the extension version is 1.1 or below. It is the case that the 287 // device has its own implementation and ExtensionsInfo will directly return null to impact 288 // the test result. 289 assumeTrue(ExtensionVersion.getRuntimeVersion()!! >= Version.VERSION_1_2) 290 291 val estimatedCaptureLatency = Range(100L, 1000L) 292 293 val fakeVendorExtender = 294 object : VendorExtender { 295 override fun isExtensionAvailable( 296 cameraId: String, 297 characteristicsMap: MutableMap<String, CameraCharacteristics> 298 ): Boolean { 299 return true 300 } 301 302 override fun getEstimatedCaptureLatencyRange(size: Size?): Range<Long> { 303 return estimatedCaptureLatency 304 } 305 } 306 extensionsManager.setVendorExtenderFactory { _, _ -> fakeVendorExtender } 307 308 assertThat( 309 extensionsManager.getEstimatedCaptureLatencyRange(baseCameraSelector, extensionMode) 310 ) 311 .isEqualTo(estimatedCaptureLatency) 312 } 313 314 @Test 315 fun getEstimatedCaptureLatencyRangeReturnNull_whenExtensionAvailabilityIsNotAvailable() { 316 extensionsManager = 317 ExtensionsManager.getInstanceAsync(context, cameraProvider, ClientVersion("99.0.0"))[ 318 10000, TimeUnit.MILLISECONDS] 319 320 assumeTrue( 321 extensionsManager.extensionsAvailability != 322 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 323 ) 324 325 assertThat( 326 extensionsManager.getEstimatedCaptureLatencyRange(baseCameraSelector, extensionMode) 327 ) 328 .isNull() 329 } 330 331 @Test 332 fun getEstimatedCaptureLatencyRangeReturnNull_belowVersion1_2() { 333 assumeTrue(ExtensionVersion.getRuntimeVersion()!!.compareTo(Version.VERSION_1_2) < 0) 334 335 checkExtensionAvailabilityAndInit() 336 337 // This call should not cause any exception even if the vendor library doesn't implement 338 // the getEstimatedCaptureLatencyRange function. 339 val latencyInfo = 340 extensionsManager.getEstimatedCaptureLatencyRange(baseCameraSelector, extensionMode) 341 342 assertThat(latencyInfo).isNull() 343 } 344 345 @Test 346 fun getEstimatedCaptureLatencyRangeReturnsNull_whenNoCameraCanBeFound() { 347 checkExtensionAvailabilityAndInit() 348 349 val emptyCameraSelector = 350 CameraSelector.Builder().addCameraFilter { _ -> ArrayList<CameraInfo>() }.build() 351 352 assertThat( 353 extensionsManager.getEstimatedCaptureLatencyRange( 354 emptyCameraSelector, 355 extensionMode 356 ) 357 ) 358 .isNull() 359 } 360 361 @Test 362 fun canSetExtensionsConfig_whenNoUseCase(): Unit = runBlocking { 363 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 364 365 withContext(Dispatchers.Main) { 366 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 367 } 368 } 369 370 @Test 371 fun canNotSetExtensionsConfig_whenUseCaseHasExisted(): Unit = runBlocking { 372 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 373 374 withContext(Dispatchers.Main) { 375 val fakeLifecycleOwner = FakeLifecycleOwner() 376 377 // This test works only if the camera is the same no matter running normal or 378 // extension modes. 379 val normalCamera = 380 cameraProvider.bindToLifecycle(fakeLifecycleOwner, baseCameraSelector) 381 val extensionCamera = 382 cameraProvider.bindToLifecycle(fakeLifecycleOwner, extensionCameraSelector) 383 assumeTrue(extensionCamera == normalCamera) 384 385 // Binds a use case with the basic camera selector first. 386 cameraProvider.bindToLifecycle(fakeLifecycleOwner, baseCameraSelector, FakeUseCase()) 387 388 // IllegalStateException should be thrown when bindToLifecycle is called with 389 // different extension camera config 390 assertThrows<IllegalStateException> { 391 cameraProvider.bindToLifecycle(fakeLifecycleOwner, extensionCameraSelector) 392 } 393 } 394 } 395 396 @Test 397 fun canSetSameExtensionsConfig_whenUseCaseHasExisted(): Unit = runBlocking { 398 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 399 400 withContext(Dispatchers.Main) { 401 val fakeLifecycleOwner = FakeLifecycleOwner() 402 403 // Binds a use case with extension camera config first. 404 cameraProvider.bindToLifecycle( 405 fakeLifecycleOwner, 406 extensionCameraSelector, 407 FakeUseCase() 408 ) 409 410 // Binds another use case with the same extension camera config. 411 cameraProvider.bindToLifecycle( 412 fakeLifecycleOwner, 413 extensionCameraSelector, 414 FakeUseCase() 415 ) 416 } 417 } 418 419 @Test 420 fun canSwitchExtendedCameraConfig_afterUnbindUseCases(): Unit = runBlocking { 421 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 422 423 withContext(Dispatchers.Main) { 424 val fakeLifecycleOwner = FakeLifecycleOwner() 425 426 // Binds a use case with extension camera config first. 427 cameraProvider.bindToLifecycle( 428 fakeLifecycleOwner, 429 extensionCameraSelector, 430 FakeUseCase() 431 ) 432 433 // Unbinds all use cases 434 cameraProvider.unbindAll() 435 436 // Binds another use case with the basic camera selector. 437 cameraProvider.bindToLifecycle(fakeLifecycleOwner, baseCameraSelector, FakeUseCase()) 438 } 439 } 440 441 @Test 442 fun isImageAnalysisSupportedReturnsFalse_whenHasNoAnalysisSizes() { 443 extensionsManager = 444 ExtensionsManager.getInstanceAsync( 445 context, 446 cameraProvider, 447 )[10000, TimeUnit.MILLISECONDS] 448 449 val fakeVendorExtender = 450 object : VendorExtender { 451 override fun isExtensionAvailable( 452 cameraId: String, 453 characteristicsMap: MutableMap<String, CameraCharacteristics> 454 ): Boolean { 455 return true 456 } 457 458 override fun getSupportedYuvAnalysisResolutions(): Array<Size> { 459 return emptyArray() 460 } 461 } 462 extensionsManager.setVendorExtenderFactory { _, _ -> fakeVendorExtender } 463 464 assumeTrue( 465 extensionsManager.extensionsAvailability == 466 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 467 ) 468 469 assertThat(extensionsManager.isImageAnalysisSupported(baseCameraSelector, extensionMode)) 470 .isFalse() 471 } 472 473 @Test 474 fun isImageAnalysisSupportedReturnsTrue_whenHasAnalysisSizes() { 475 extensionsManager = 476 ExtensionsManager.getInstanceAsync( 477 context, 478 cameraProvider, 479 )[10000, TimeUnit.MILLISECONDS] 480 481 val fakeVendorExtender = 482 object : VendorExtender { 483 override fun isExtensionAvailable( 484 cameraId: String, 485 characteristicsMap: MutableMap<String, CameraCharacteristics> 486 ): Boolean { 487 return true 488 } 489 490 override fun getSupportedYuvAnalysisResolutions(): Array<Size> { 491 return arrayOf(Size(1920, 1080)) 492 } 493 } 494 extensionsManager.setVendorExtenderFactory { _, _ -> fakeVendorExtender } 495 496 assumeTrue( 497 extensionsManager.extensionsAvailability == 498 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 499 ) 500 501 assertThat(extensionsManager.isImageAnalysisSupported(baseCameraSelector, extensionMode)) 502 .isTrue() 503 } 504 505 @Test 506 fun isImageAnalysisSupportedIsFalse_whenExtensionAvailabilityIsNotAvailable() { 507 extensionsManager = 508 ExtensionsManager.getInstanceAsync(context, cameraProvider, ClientVersion("99.0.0"))[ 509 10000, TimeUnit.MILLISECONDS] 510 511 assumeTrue( 512 extensionsManager.extensionsAvailability != 513 ExtensionsManager.ExtensionsAvailability.LIBRARY_AVAILABLE 514 ) 515 516 assertThat(extensionsManager.isImageAnalysisSupported(baseCameraSelector, extensionMode)) 517 .isFalse() 518 } 519 520 @Test 521 fun isImageAnalysisSupportedIsFalse_whenNoCameraCanBeFound() { 522 checkExtensionAvailabilityAndInit() 523 val emptyCameraSelector = 524 CameraSelector.Builder().addCameraFilter { _ -> ArrayList<CameraInfo>() }.build() 525 526 assertThat(extensionsManager.isImageAnalysisSupported(emptyCameraSelector, extensionMode)) 527 .isFalse() 528 } 529 530 @Test 531 fun postviewSupportedIsSetCorrectlyOnCameraConfig() = runBlocking { 532 // 1. Arrange 533 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 534 val fakeVendorExtender = 535 object : VendorExtender { 536 override fun isExtensionAvailable( 537 cameraId: String, 538 characteristicsMap: MutableMap<String, CameraCharacteristics> 539 ): Boolean { 540 return true 541 } 542 543 override fun isPostviewAvailable(): Boolean { 544 return true 545 } 546 } 547 extensionsManager.setVendorExtenderFactory { _, _ -> fakeVendorExtender } 548 549 // 2. Act 550 val camera = 551 withContext(Dispatchers.Main) { 552 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 553 } 554 555 // 3. Assert 556 assertThat(camera.extendedConfig.isPostviewSupported).isTrue() 557 } 558 559 @Test 560 fun captureProcessProgressSupportedIsSetCorrectlyOnCameraConfig() = runBlocking { 561 // 1. Arrange 562 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 563 val fakeVendorExtender = 564 object : VendorExtender { 565 override fun isExtensionAvailable( 566 cameraId: String, 567 characteristicsMap: MutableMap<String, CameraCharacteristics> 568 ): Boolean { 569 return true 570 } 571 572 override fun isCaptureProcessProgressAvailable(): Boolean { 573 return true 574 } 575 } 576 extensionsManager.setVendorExtenderFactory { _, _ -> fakeVendorExtender } 577 578 // 2. Act 579 val camera = 580 withContext(Dispatchers.Main) { 581 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 582 } 583 584 // 3. Assert 585 assertThat(camera.extendedConfig.isCaptureProcessProgressSupported).isTrue() 586 } 587 588 @Test 589 fun returnsCorrectInitialTypeFromSessionProcessor() = runBlocking { 590 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 591 592 val camera = 593 withContext(Dispatchers.Main) { 594 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 595 } 596 597 val sessionProcessor = camera.extendedConfig.sessionProcessor 598 val cameraExtensionsInfo = sessionProcessor as CameraExtensionsInfo 599 val currentType = cameraExtensionsInfo.currentExtensionMode 600 if (cameraExtensionsInfo.isCurrentExtensionModeAvailable) { 601 assertThat(currentType!!.value).isEqualTo(extensionMode) 602 } else { 603 assertThat(currentType).isNull() 604 } 605 } 606 607 @Test 608 fun returnsCorrectExtensionTypeFromCameraExtensionsInfo() = runBlocking { 609 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 610 611 val camera = 612 withContext(Dispatchers.Main) { 613 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 614 } 615 616 val cameraExtensionsInfo = extensionsManager.getCameraExtensionsInfo(camera.cameraInfo) 617 618 if (cameraExtensionsInfo.isCurrentExtensionModeAvailable) { 619 assertThat(cameraExtensionsInfo.currentExtensionMode!!.value).isEqualTo(extensionMode) 620 } else { 621 assertThat(cameraExtensionsInfo.currentExtensionMode).isNull() 622 } 623 } 624 625 @Test 626 fun returnsCorrectExtensionStrengthAvailabilityFromCameraExtensionsInfo() = runBlocking { 627 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 628 629 val camera = 630 withContext(Dispatchers.Main) { 631 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 632 } 633 634 val cameraExtensionsInfo = extensionsManager.getCameraExtensionsInfo(camera.cameraInfo) 635 636 assertThat(cameraExtensionsInfo.isExtensionStrengthAvailable) 637 .isEqualTo( 638 camera.extendedConfig.sessionProcessor.supportedCameraOperations.contains( 639 AdapterCameraInfo.CAMERA_OPERATION_EXTENSION_STRENGTH 640 ) 641 ) 642 } 643 644 @Test 645 fun returnsCorrectCurrentExtensionTypeAvailabilityFromCameraExtensionsInfo() = runBlocking { 646 assumeTrue(ExtensionVersion.isAdvancedExtenderSupported()) 647 assumeTrue(ExtensionVersion.isMinimumCompatibleVersion(Version.VERSION_1_4)) 648 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 649 650 // Inject fake VendorExtenderFactory to provide custom VendorExtender 651 extensionsManager.setVendorExtenderFactory { _, _ -> 652 object : VendorExtender { 653 override fun isExtensionAvailable( 654 cameraId: String, 655 characteristicsMap: MutableMap<String, CameraCharacteristics> 656 ): Boolean { 657 return true 658 } 659 660 override fun isCurrentExtensionModeAvailable(): Boolean { 661 return true 662 } 663 664 override fun createSessionProcessor(context: Context): SessionProcessor? { 665 return AdvancedSessionProcessor( 666 FakeSessionProcessorImpl(), 667 Collections.emptyList(), 668 this, 669 context, 670 extensionMode 671 ) 672 } 673 } 674 } 675 676 val camera = 677 withContext(Dispatchers.Main) { 678 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 679 } 680 val cameraExtensionsInfo = extensionsManager.getCameraExtensionsInfo(camera.cameraInfo) 681 assertThat(cameraExtensionsInfo.isCurrentExtensionModeAvailable).isTrue() 682 } 683 684 @Test 685 fun returnsCorrectInitialExtensionStrengthFromCameraExtensionsInfo() = runBlocking { 686 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 687 688 val camera = 689 withContext(Dispatchers.Main) { 690 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 691 } 692 693 val cameraExtensionsInfo = extensionsManager.getCameraExtensionsInfo(camera.cameraInfo) 694 if (cameraExtensionsInfo.isExtensionStrengthAvailable) { 695 assertThat(cameraExtensionsInfo.extensionStrength!!.value).isEqualTo(100) 696 } else { 697 assertThat(cameraExtensionsInfo.extensionStrength).isNull() 698 } 699 } 700 701 private fun checkExtensionAvailabilityAndInit(): CameraSelector { 702 extensionsManager = 703 ExtensionsManager.getInstanceAsync(context, cameraProvider)[ 704 10000, TimeUnit.MILLISECONDS] 705 706 assumeTrue(extensionsManager.isExtensionAvailable(baseCameraSelector, extensionMode)) 707 708 return extensionsManager.getExtensionEnabledCameraSelector( 709 baseCameraSelector, 710 extensionMode 711 ) 712 } 713 714 @Test 715 fun returnsCorrectExtensionStrengthFromCameraExtensionsInfoForNormalMode() = runBlocking { 716 // Runs the test only when the parameterized extension mode is BOKEH to avoid wasting time 717 assumeTrue(extensionMode == ExtensionMode.BOKEH) 718 extensionsManager = 719 ExtensionsManager.getInstanceAsync(context, cameraProvider)[ 720 10000, TimeUnit.MILLISECONDS] 721 722 val camera = 723 withContext(Dispatchers.Main) { 724 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), baseCameraSelector) 725 } 726 727 val cameraExtensionsInfo = extensionsManager.getCameraExtensionsInfo(camera.cameraInfo) 728 assertThat(cameraExtensionsInfo.isExtensionStrengthAvailable).isFalse() 729 assertThat(cameraExtensionsInfo.extensionStrength).isNull() 730 } 731 732 @Test 733 fun retrievesCameraExtensionsControlFromCameraControl(): Unit = runBlocking { 734 val extensionCameraSelector = checkExtensionAvailabilityAndInit() 735 736 // Retrieves null CameraExtensionsControl from normal mode camera's CameraControl 737 withContext(Dispatchers.Main) { 738 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), baseCameraSelector) 739 } 740 .also { 741 assertThat(extensionsManager.getCameraExtensionsControl(it.cameraControl)).isNull() 742 } 743 744 // Retrieves non-null CameraExtensionsControl from extensions-enabled camera's CameraControl 745 withContext(Dispatchers.Main) { 746 cameraProvider.bindToLifecycle(FakeLifecycleOwner(), extensionCameraSelector) 747 } 748 .also { 749 assertThat(extensionsManager.getCameraExtensionsControl(it.cameraControl)) 750 .isNotNull() 751 } 752 } 753 754 @SdkSuppress(minSdkVersion = 31) 755 @Test 756 fun canProvideCorrectTypeOfSessionProcessor(): Unit = runBlocking { 757 var extensionCameraSelector = checkExtensionAvailabilityAndInit() 758 759 // Get and check the session processor type is correct 760 (cameraProvider.getCameraInfo(extensionCameraSelector) as AdapterCameraInfo) 761 .sessionProcessor 762 ?.also { 763 if (shouldUseCamera2Extensions(cameraProvider.configImplType)) { 764 assertThat(it).isInstanceOf(Camera2ExtensionsSessionProcessor::class.java) 765 } else if (ExtensionVersion.isAdvancedExtenderSupported()) { 766 assertThat(it).isInstanceOf(AdvancedSessionProcessor::class.java) 767 } else { 768 assertThat(it).isInstanceOf(BasicExtenderSessionProcessor::class.java) 769 } 770 } 771 } 772 773 private fun isExtensionAvailableByCameraInfo(cameraInfo: CameraInfo): Boolean { 774 var vendorExtender = 775 ExtensionsTestUtil.createVendorExtender( 776 context, 777 extensionMode, 778 cameraProvider.configImplType 779 ) 780 val cameraId = (cameraInfo as CameraInfoInternal).cameraId 781 782 return vendorExtender.isExtensionAvailable( 783 cameraId, 784 ExtensionsUtils.getCameraCharacteristicsMap(cameraInfo) 785 ) 786 } 787 788 private class FakeSessionProcessorImpl : SessionProcessorImpl { 789 override fun initSession( 790 cameraId: String, 791 cameraCharacteristicsMap: MutableMap<String, CameraCharacteristics>, 792 context: Context, 793 surfaceConfigs: OutputSurfaceConfigurationImpl 794 ): Camera2SessionConfigImpl = FakeCamera2SessionConfigImpl() 795 796 override fun initSession( 797 cameraId: String, 798 cameraCharacteristicsMap: MutableMap<String, CameraCharacteristics>, 799 context: Context, 800 previewSurfaceConfig: OutputSurfaceImpl, 801 imageCaptureSurfaceConfig: OutputSurfaceImpl, 802 imageAnalysisSurfaceConfig: OutputSurfaceImpl? 803 ): Camera2SessionConfigImpl = FakeCamera2SessionConfigImpl() 804 805 override fun deInitSession() {} 806 807 override fun setParameters(parameters: MutableMap<CaptureRequest.Key<*>, Any>) {} 808 809 override fun startTrigger( 810 triggers: MutableMap<CaptureRequest.Key<*>, Any>, 811 callback: SessionProcessorImpl.CaptureCallback 812 ): Int = 0 813 814 override fun onCaptureSessionStart(requestProcessor: RequestProcessorImpl) {} 815 816 override fun onCaptureSessionEnd() {} 817 818 override fun startRepeating(callback: SessionProcessorImpl.CaptureCallback): Int = 0 819 820 override fun stopRepeating() {} 821 822 override fun startCapture(callback: SessionProcessorImpl.CaptureCallback): Int = 0 823 824 override fun startCaptureWithPostview(callback: SessionProcessorImpl.CaptureCallback): Int = 825 0 826 827 override fun abortCapture(captureSequenceId: Int) {} 828 829 override fun getRealtimeCaptureLatency(): Pair<Long, Long>? = null 830 } 831 832 private class FakeCamera2SessionConfigImpl : Camera2SessionConfigImpl { 833 override fun getOutputConfigs(): MutableList<Camera2OutputConfigImpl> = mutableListOf() 834 835 override fun getSessionParameters(): MutableMap<CaptureRequest.Key<*>, Any> = mutableMapOf() 836 837 override fun getSessionTemplateId(): Int = 0 838 839 override fun getSessionType(): Int = 0 840 } 841 } 842