From d30e146729a2693933e1b441a66de2af43fc3d51 Mon Sep 17 00:00:00 2001 From: Melad Raouf Date: Tue, 27 Jan 2026 19:29:47 +0000 Subject: [PATCH 1/5] [MS-1256] Remove NEC SDK integration from Fingerprint Bio SDK module --- .github/workflows/pr-checks.yml | 1 - build-logic/build_properties.gradle.kts | 2 +- fingerprint/infra/bio-sdk/build.gradle.kts | 1 - .../infra/biosdk/FingerprintBioSdkModule.kt | 6 - .../infra/biosdk/NECBioSdkWrapper.kt | 70 ------- .../biosdk/ResolveBioSdkWrapperUseCase.kt | 4 +- .../infra/biosdk/NECBioSdkWrapperTest.kt | 156 --------------- .../biosdk/ResolveBioSdkWrapperUseCaseTest.kt | 9 +- fingerprint/infra/nec-bio-sdk/.gitignore | 1 - .../infra/nec-bio-sdk/build.gradle.kts | 21 --- .../nec-bio-sdk/src/main/AndroidManifest.xml | 2 - .../infra/necsdkimpl/NecSdkModule.kt | 55 ------ .../image/FingerprintImageProviderImpl.kt | 20 -- .../acquisition/image/ProcessedImageCache.kt | 14 -- ...uireImageDistortionConfigurationUseCase.kt | 41 ---- .../CalculateNecImageQualityUseCase.kt | 29 --- .../template/ExtractNecTemplateUseCase.kt | 40 ---- .../acquisition/template/FingerprintImage.kt | 14 -- .../FingerprintTemplateAcquisitionSettings.kt | 10 - .../template/FingerprintTemplateMetadata.kt | 6 - .../FingerprintTemplateProviderImpl.kt | 83 -------- .../template/ProcessRawImageUseCase.kt | 43 ----- .../initialization/SdkInitializerImpl.kt | 42 ----- .../matching/FingerprintMatcherImpl.kt | 119 ------------ .../matching/NecMatchingSettings.kt | 6 - .../image/FingerprintImageProviderImplTest.kt | 36 ---- ...ImageDistortionConfigurationUseCaseTest.kt | 80 -------- .../CalculateNecImageQualityUseCaseTest.kt | 59 ------ .../template/ExtractNecTemplateUseCaseTest.kt | 74 -------- .../FingerprintTemplateProviderImplTest.kt | 177 ------------------ .../template/ProcessRawImageUseCaseTest.kt | 117 ------------ .../initialization/SdkInitializerImplTest.kt | 100 ---------- .../matching/FingerprintMatcherImplTest.kt | 155 --------------- gradle/libs.versions.toml | 4 - settings.gradle.kts | 1 - 35 files changed, 5 insertions(+), 1593 deletions(-) delete mode 100644 fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapper.kt delete mode 100644 fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapperTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/.gitignore delete mode 100644 fingerprint/infra/nec-bio-sdk/build.gradle.kts delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/AndroidManifest.xml delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/NecSdkModule.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImpl.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/ProcessedImageCache.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCase.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCase.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCase.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintImage.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateAcquisitionSettings.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateMetadata.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImpl.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCase.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImpl.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImpl.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/NecMatchingSettings.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImplTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCaseTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCaseTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCaseTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImplTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCaseTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImplTest.kt delete mode 100644 fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImplTest.kt diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 5fe5ce0a91..141f5a0557 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -229,7 +229,6 @@ jobs: fingerprint:infra:scanner fingerprint:infra:simafis-wrapper fingerprint:infra:simprints-bio-sdk - fingerprint:infra:nec-bio-sdk fingerprint:infra:image-distortion-config reportsId: fingerprint testing-tools: diff --git a/build-logic/build_properties.gradle.kts b/build-logic/build_properties.gradle.kts index e65867a496..26c2ebe80f 100644 --- a/build-logic/build_properties.gradle.kts +++ b/build-logic/build_properties.gradle.kts @@ -19,7 +19,7 @@ extra.apply { * Dev version >= 2025.2.0 is required to support enrolment record updates and SimFace configuration * Dev version >= 2025.3.0 is required to receive smaples and structured down sync configuration */ - set("VERSION_NAME", "2025.4.0") + set("VERSION_NAME", "2026.1.0") /** * Build type. The version code describes which build type was used for the build. diff --git a/fingerprint/infra/bio-sdk/build.gradle.kts b/fingerprint/infra/bio-sdk/build.gradle.kts index 9fdbd9305b..dfe5de2f58 100644 --- a/fingerprint/infra/bio-sdk/build.gradle.kts +++ b/fingerprint/infra/bio-sdk/build.gradle.kts @@ -11,5 +11,4 @@ dependencies { implementation(project(":infra:config-store")) api(project(":fingerprint:infra:base-bio-sdk")) implementation(project(":fingerprint:infra:simprints-bio-sdk")) - implementation(project(":fingerprint:infra:nec-bio-sdk")) } diff --git a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/FingerprintBioSdkModule.kt b/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/FingerprintBioSdkModule.kt index fd93d4cc0d..b76fc99acd 100644 --- a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/FingerprintBioSdkModule.kt +++ b/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/FingerprintBioSdkModule.kt @@ -1,7 +1,6 @@ package com.simprints.fingerprint.infra.biosdk import com.simprints.fingerprint.infra.biosdkimpl.SimprintsSdk -import com.simprints.fingerprint.infra.necsdkimpl.NecSdk import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -15,9 +14,4 @@ internal abstract class FingerprintBioSdkModule { @SimprintsSdk @Singleton abstract fun provideSimprintsBioSdkWrapper(impl: SimprintsBioSdkWrapper): BioSdkWrapper - - @Binds - @NecSdk - @Singleton - abstract fun provideNecBioSdkWrapper(impl: NECBioSdkWrapper): BioSdkWrapper } diff --git a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapper.kt b/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapper.kt deleted file mode 100644 index 5ed4bd6810..0000000000 --- a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapper.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.simprints.fingerprint.infra.biosdk - -import com.simprints.core.domain.capture.BiometricReferenceCapture -import com.simprints.core.domain.comparison.ComparisonResult -import com.simprints.core.domain.reference.CandidateRecord -import com.simprints.fingerprint.infra.basebiosdk.FingerprintBioSdk -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.TemplateResponse -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.toDomain -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateAcquisitionSettings -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateMetadata -import com.simprints.fingerprint.infra.necsdkimpl.matching.NecMatchingSettings -import com.simprints.fingerprint.infra.scanner.domain.fingerprint.AcquireFingerprintTemplateResponse -import com.simprints.fingerprint.infra.scanner.v2.domain.main.message.un20.models.Dpi -import javax.inject.Inject - -class NECBioSdkWrapper @Inject constructor( - private val bioSdk: - FingerprintBioSdk, -) : BioSdkWrapper { - override val scanningTimeoutMs: Long - get() = 8000 // 8 seconds = maximum duration for scanning + image transfer + image processing + NEC template extraction - override val imageTransferTimeoutMs: Long - get() = 0 // 0 seconds as the image is already captured and stored in the memory from the scanning step - - override val minGoodScans: Int - get() = 0 // NEC SDK has a high rate of bad scans, so we don't need to enforce a minimum number of good scans - - override val addNewFingerOnBadScan: Boolean - get() = false // NEC SDK has a high rate of bad scans, so we don't need to add a new finger on bad scan - - override val matcherName: String = bioSdk.matcherName - - override val supportedTemplateFormat: String = bioSdk.supportedTemplateFormat - - override suspend fun initialize() = bioSdk.initialize() - - override suspend fun match( - probeReference: BiometricReferenceCapture, - candidates: List, - isCrossFingerMatchingEnabled: Boolean, - ): List = bioSdk.match(probeReference, candidates, NecMatchingSettings(isCrossFingerMatchingEnabled)) - - override suspend fun acquireFingerprintTemplate( - capturingResolution: Int?, - timeOutMs: Int, - qualityThreshold: Int, - allowLowQualityExtraction: Boolean, - ): AcquireFingerprintTemplateResponse { - val settings = FingerprintTemplateAcquisitionSettings( - capturingResolution?.let { Dpi(it.toShort()) }, - timeOutMs, - qualityThreshold, - allowLowQualityExtraction, - ) - return bioSdk.acquireFingerprintTemplate(settings).toDomain() - } - - override suspend fun acquireFingerprintImage() = bioSdk.acquireFingerprintImage().toDomain() -} - -fun TemplateResponse.toDomain(): AcquireFingerprintTemplateResponse { - require(templateMetadata != null) { - "Template metadata should not be null" - } - return AcquireFingerprintTemplateResponse( - template, - templateMetadata!!.templateFormat, - templateMetadata!!.imageQualityScore, - ) -} diff --git a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCase.kt b/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCase.kt index d0f75c53af..9ca018ee52 100644 --- a/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCase.kt +++ b/fingerprint/infra/bio-sdk/src/main/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCase.kt @@ -1,17 +1,15 @@ package com.simprints.fingerprint.infra.biosdk import com.simprints.fingerprint.infra.biosdkimpl.SimprintsSdk -import com.simprints.fingerprint.infra.necsdkimpl.NecSdk import com.simprints.infra.config.store.models.ModalitySdkType import javax.inject.Inject class ResolveBioSdkWrapperUseCase @Inject constructor( @param:SimprintsSdk private val simprintsWrapper: BioSdkWrapper, - @param:NecSdk private val necWrapper: BioSdkWrapper, ) { operator fun invoke(fingerprintSdk: ModalitySdkType): BioSdkWrapper = when (fingerprintSdk) { ModalitySdkType.SECUGEN_SIM_MATCHER -> simprintsWrapper - ModalitySdkType.NEC -> necWrapper + ModalitySdkType.NEC -> error("NEC not supported since v2026.1.0") else -> error("Unknown fingerprint configuration") } } diff --git a/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapperTest.kt b/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapperTest.kt deleted file mode 100644 index ef9089ff6e..0000000000 --- a/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/NECBioSdkWrapperTest.kt +++ /dev/null @@ -1,156 +0,0 @@ -package com.simprints.fingerprint.infra.biosdk - -import com.google.common.truth.Truth.* -import com.simprints.core.domain.capture.BiometricReferenceCapture -import com.simprints.core.domain.reference.CandidateRecord -import com.simprints.fingerprint.infra.basebiosdk.FingerprintBioSdk -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.ImageResponse -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.TemplateResponse -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateAcquisitionSettings -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateMetadata -import com.simprints.fingerprint.infra.necsdkimpl.matching.NecMatchingSettings -import com.simprints.testtools.common.syntax.assertThrows -import io.mockk.* -import io.mockk.impl.annotations.* -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -class NECBioSdkWrapperTest { - private lateinit var necBioSdkWrapper: NECBioSdkWrapper - - @RelaxedMockK - private lateinit var bioSdk: FingerprintBioSdk< - Unit, - Unit, - Unit, - FingerprintTemplateAcquisitionSettings, - FingerprintTemplateMetadata, - NecMatchingSettings, - > - - @Before - fun setUp() { - MockKAnnotations.init(this) - necBioSdkWrapper = NECBioSdkWrapper(bioSdk) - } - - @Test - fun `test Fixed Properties`() { - // Given - val expectedScanningTimeoutMs = 8000L - val expectedImageTransferTimeoutMs = 0L - val expectedMinGoodScans = 0 - val expectedAddNewFingerOnBadScan = false - - // When - val actualScanningTimeoutMs = necBioSdkWrapper.scanningTimeoutMs - val actualImageTransferTimeoutMs = necBioSdkWrapper.imageTransferTimeoutMs - val actualMinGoodScans = necBioSdkWrapper.minGoodScans - val actualAddNewFingerOnBadScan = necBioSdkWrapper.addNewFingerOnBadScan - - // Then - assertThat(actualScanningTimeoutMs).isEqualTo(expectedScanningTimeoutMs) - assertThat(actualImageTransferTimeoutMs).isEqualTo(expectedImageTransferTimeoutMs) - assertThat(actualMinGoodScans).isEqualTo(expectedMinGoodScans) - assertThat(actualAddNewFingerOnBadScan).isEqualTo(expectedAddNewFingerOnBadScan) - } - - @Test - fun `initializes bio sdk`() = runTest { - // When - necBioSdkWrapper.initialize() - // Then - coVerify { - bioSdk.initialize() - } - } - - @Test - fun `calls match on bio sdk`() = runTest { - // Given - val probe = mockk() - val candidates = listOf(mockk()) - val isCrossFingerMatchingEnabled = true - val settings = NecMatchingSettings(isCrossFingerMatchingEnabled) - // When - necBioSdkWrapper.match(probe, candidates, isCrossFingerMatchingEnabled) - - // Then - coVerify { bioSdk.match(probe, candidates, settings) } - } - - @Test - fun `calls fingerprint template acquisition from sdk`() = runTest { - // Given - val captureFingerprintStrategy = 1000 - val captureTimeOutMs = 1000 - val captureQualityThreshold = 100 - val captureAllowLowQualityExtraction = true - - val bioSdkResponse = TemplateResponse( - byteArrayOf(1, 2, 3), - FingerprintTemplateMetadata( - "TemplateFormat", - 100, - ), - ) - val settingsSlot = slot() - coEvery { bioSdk.acquireFingerprintTemplate(capture(settingsSlot)) } returns bioSdkResponse - - // When - val response = necBioSdkWrapper.acquireFingerprintTemplate( - captureFingerprintStrategy, - captureTimeOutMs, - captureQualityThreshold, - captureAllowLowQualityExtraction, - ) - - // Then - coVerify { bioSdk.acquireFingerprintTemplate(any()) } - with(settingsSlot.captured) { - assertThat(processingResolution?.value) - .isEqualTo(captureFingerprintStrategy.toShort()) - assertThat(timeOutMs).isEqualTo(captureTimeOutMs) - assertThat(qualityThreshold).isEqualTo(captureQualityThreshold) - assertThat(allowLowQualityExtraction).isEqualTo(captureAllowLowQualityExtraction) - } - assertThat(bioSdkResponse.template).isEqualTo(response.template) - - assertThat(bioSdkResponse.templateMetadata?.templateFormat) - .isEqualTo(response.templateFormat) - - assertThat(bioSdkResponse.templateMetadata?.imageQualityScore) - .isEqualTo(response.imageQualityScore) - } - - @Test - fun `fails if template does not have meta data`() = runTest { - coEvery { bioSdk.acquireFingerprintTemplate(any()) } returns TemplateResponse( - byteArrayOf( - 1, - 2, - 3, - ), - null, - ) - - assertThrows { - necBioSdkWrapper.acquireFingerprintTemplate(1, 1, 1, true) - } - } - - @Test - fun `calls fingerprint image acquisition from sdk`() = runTest { - // Given - val imageBytes = byteArrayOf(1, 2, 3) - val bioSdkResponse = ImageResponse(imageBytes) - coEvery { bioSdk.acquireFingerprintImage() } returns bioSdkResponse - - // When - val response = necBioSdkWrapper.acquireFingerprintImage() - // Then - coVerify { bioSdk.acquireFingerprintImage() } - assertThat(bioSdkResponse.imageBytes).isEqualTo(response.imageBytes) - } -} diff --git a/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCaseTest.kt b/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCaseTest.kt index 47f1d08df6..143ac87a0a 100644 --- a/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCaseTest.kt +++ b/fingerprint/infra/bio-sdk/src/test/java/com/simprints/fingerprint/infra/biosdk/ResolveBioSdkWrapperUseCaseTest.kt @@ -11,16 +11,13 @@ import org.junit.Test class ResolveBioSdkWrapperUseCaseTest { private lateinit var bioSdkResolverUseCase: ResolveBioSdkWrapperUseCase - @MockK - private lateinit var necBioSdkWrapper: BioSdkWrapper - @MockK private lateinit var simprintsBioSdkWrapper: BioSdkWrapper @Before fun setUp() { MockKAnnotations.init(this) - bioSdkResolverUseCase = ResolveBioSdkWrapperUseCase(simprintsBioSdkWrapper, necBioSdkWrapper) + bioSdkResolverUseCase = ResolveBioSdkWrapperUseCase(simprintsBioSdkWrapper) } @Test @@ -29,9 +26,9 @@ class ResolveBioSdkWrapperUseCaseTest { Truth.assertThat(simprintsBioSdkWrapper).isEqualTo(result) } - @Test + @Test(expected = IllegalStateException::class) fun `test with nec sdk`() = runTest { val result = bioSdkResolverUseCase(ModalitySdkType.NEC) - Truth.assertThat(necBioSdkWrapper).isEqualTo(result) + // should throw IllegalStateException } } diff --git a/fingerprint/infra/nec-bio-sdk/.gitignore b/fingerprint/infra/nec-bio-sdk/.gitignore deleted file mode 100644 index 796b96d1c4..0000000000 --- a/fingerprint/infra/nec-bio-sdk/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/fingerprint/infra/nec-bio-sdk/build.gradle.kts b/fingerprint/infra/nec-bio-sdk/build.gradle.kts deleted file mode 100644 index 86689bedbc..0000000000 --- a/fingerprint/infra/nec-bio-sdk/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - id("simprints.infra") -} - -android { - namespace = "com.simprints.fingerprint.infra.necbiosdk" -} - -dependencies { - implementation(project(":fingerprint:infra:scanner")) - implementation(project(":fingerprint:infra:image-distortion-config")) - implementation(project(":infra:license")) - implementation(project(":infra:security")) - implementation(project(":infra:recent-user-activity")) - api(project(":fingerprint:infra:base-bio-sdk")) - - // NEC SDK lib and wrapper - implementation(libs.nec.wrapper) - implementation(libs.nec.lib) - implementation(libs.secugen) -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/AndroidManifest.xml b/fingerprint/infra/nec-bio-sdk/src/main/AndroidManifest.xml deleted file mode 100644 index 5c3d3655b5..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/NecSdkModule.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/NecSdkModule.kt deleted file mode 100644 index 6ab1ec7ad8..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/NecSdkModule.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl - -import com.secugen.WSQConverter -import com.simprints.fingerprint.infra.basebiosdk.FingerprintBioSdk -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.image.FingerprintImageProviderImpl -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateAcquisitionSettings -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateMetadata -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.FingerprintTemplateProviderImpl -import com.simprints.fingerprint.infra.necsdkimpl.initialization.SdkInitializerImpl -import com.simprints.fingerprint.infra.necsdkimpl.matching.FingerprintMatcherImpl -import com.simprints.fingerprint.infra.necsdkimpl.matching.NecMatchingSettings -import com.simprints.necwrapper.nec.NEC -import com.simprints.sgimagecorrection.SecugenImageCorrection -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Qualifier -import javax.inject.Singleton - -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class NecSdk - -@Module -@InstallIn(SingletonComponent::class) -object NecSdkModule { - @Provides - @Singleton - internal fun provideFingerprintBioSdk( - sdkInitializer: SdkInitializerImpl, - fingerprintImageProvider: FingerprintImageProviderImpl, - fingerprintTemplateProvider: FingerprintTemplateProviderImpl, - fingerprintMatcher: FingerprintMatcherImpl, - ): FingerprintBioSdk = - FingerprintBioSdk( - sdkInitializer, - fingerprintImageProvider, - fingerprintTemplateProvider, - fingerprintMatcher, - ) - - // NEC instance must be a singleton because it is initialized only once - @Provides - @Singleton - internal fun provideNecInstance() = NEC() - - @Provides - @Singleton - internal fun provideWSQConverter() = WSQConverter() - - @Provides - @Singleton - internal fun provideSecugenImageCorrection() = SecugenImageCorrection() -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImpl.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImpl.kt deleted file mode 100644 index 16a9e9255f..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImpl.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.image - -import com.simprints.fingerprint.infra.basebiosdk.acquisition.FingerprintImageProvider -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.ImageResponse -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import javax.inject.Inject - -internal class FingerprintImageProviderImpl @Inject constructor( - private val imageCache: ProcessedImageCache, -) : FingerprintImageProvider { - /** - * Acquire fingerprint image from the image cache - * The image should be already captured by the time this method is called - * return the image if it is not null or throw an exception - * - */ - override suspend fun acquireFingerprintImage(settings: Unit?): ImageResponse = - imageCache.recentlyCapturedImage?.let { ImageResponse(it) } - ?: throw BioSdkException.CannotAcquireFingerprintImageException("Last captured image is null") -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/ProcessedImageCache.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/ProcessedImageCache.kt deleted file mode 100644 index eba735c74c..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/ProcessedImageCache.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.image - -import javax.inject.Inject -import javax.inject.Singleton - -/** - * Processed image cache - * This class stores the recently captured image - * - */ -@Singleton -internal class ProcessedImageCache @Inject constructor() { - var recentlyCapturedImage: ByteArray? = null -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCase.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCase.kt deleted file mode 100644 index 6f1d521dbd..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCase.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.simprints.fingerprint.infra.imagedistortionconfig.ImageDistortionConfigRepo -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapperFactory -import com.simprints.fingerprint.infra.scanner.v2.scanner.ScannerInfo -import javax.inject.Inject - -@OptIn(ExperimentalStdlibApi::class) -internal class AcquireImageDistortionConfigurationUseCase @Inject constructor( - private val fingerprintCaptureWrapperFactory: FingerprintCaptureWrapperFactory, - private val scannerInfo: ScannerInfo, - private val imageDistortionConfigRepo: ImageDistortionConfigRepo, -) { - /** - * Acquires the image distortion configuration. - * - First, attempts to retrieve the configuration from local storage. - * - If not available, acquires it from the scanner and saves it to local storage. - * - * Note: This method should be called after the image acquisition process - * to ensure the scanner's serial number is available. - */ - suspend operator fun invoke(): ByteArray { - val scannerId = scannerInfo.scannerId - val un20SerialNumber = scannerInfo.un20SerialNumber - - requireNotNull(scannerId) { "Scanner ID is null. Ensure the scanner info is correctly initialized." } - requireNotNull(un20SerialNumber) { "Serial number is null. Ensure the scanner info is correctly initialized." } - - return imageDistortionConfigRepo.getConfig(scannerId) - ?: acquireImageDistortionConfigurationFromScanner().also { imageDistortionConfiguration -> - imageDistortionConfigRepo.saveConfig( - scannerId, - un20SerialNumber, - imageDistortionConfiguration, - ) - } - } - - private suspend fun acquireImageDistortionConfigurationFromScanner() = - fingerprintCaptureWrapperFactory.captureWrapper.acquireImageDistortionMatrixConfiguration() -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCase.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCase.kt deleted file mode 100644 index c0144d6268..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCase.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.simprints.core.DispatcherBG -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.models.NecImage -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext -import javax.inject.Inject - -internal class CalculateNecImageQualityUseCase @Inject constructor( - private val necInstant: NEC, - @param:DispatcherBG private val dispatcher: CoroutineDispatcher, -) { - suspend operator fun invoke(image: FingerprintImage): Int = withContext(dispatcher) { - try { - necInstant.qualityCheck( - NecImage( - width = image.width, - height = image.height, - resolution = image.resolution, - imageBytes = image.imageBytes, - ), - ) - } catch (e: Exception) { - throw BioSdkException.ImageQualityCheckingException(e) - } - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCase.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCase.kt deleted file mode 100644 index decdf4ec3d..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCase.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.simprints.core.DispatcherBG -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.TemplateResponse -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.models.NecImage -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext -import javax.inject.Inject - -internal class ExtractNecTemplateUseCase @Inject constructor( - private val nec: NEC, - @param:DispatcherBG private val dispatcher: CoroutineDispatcher, -) { - suspend operator fun invoke( - fingerprintImage: FingerprintImage, - qualityScore: Int, - ): TemplateResponse = withContext(dispatcher) { - try { - val template = nec.extract( - NecImage( - width = fingerprintImage.width, - height = fingerprintImage.height, - resolution = fingerprintImage.resolution, - imageBytes = fingerprintImage.imageBytes, - ), - ) - TemplateResponse( - template.bytes, - FingerprintTemplateMetadata( - templateFormat = NEC_TEMPLATE_FORMAT, - imageQualityScore = qualityScore, - ), - ) - } catch (e: Exception) { - throw BioSdkException.TemplateExtractionException(e) - } - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintImage.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintImage.kt deleted file mode 100644 index daf1249d0a..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintImage.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -/** - * An already processed fingerprint image - * This class stores the image bytes and the image metadata - * This image is ready to be used for template extraction - */ -@Suppress("ArrayInDataClass") // Suppressed because there is no need to implement equals and hashcode for this data class -internal data class FingerprintImage( - val imageBytes: ByteArray, - val width: Int, - val height: Int, - val resolution: Int, -) diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateAcquisitionSettings.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateAcquisitionSettings.kt deleted file mode 100644 index 1280e51027..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateAcquisitionSettings.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.simprints.fingerprint.infra.scanner.v2.domain.main.message.un20.models.Dpi - -data class FingerprintTemplateAcquisitionSettings( - val processingResolution: Dpi?, - val timeOutMs: Int, - val qualityThreshold: Int, - val allowLowQualityExtraction: Boolean, -) diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateMetadata.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateMetadata.kt deleted file mode 100644 index cbd7ea92a3..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateMetadata.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -data class FingerprintTemplateMetadata( - val templateFormat: String, - val imageQualityScore: Int, -) diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImpl.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImpl.kt deleted file mode 100644 index 693483773d..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImpl.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.simprints.fingerprint.infra.basebiosdk.acquisition.FingerprintTemplateProvider -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.TemplateResponse -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.image.ProcessedImageCache -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapperFactory -import com.simprints.fingerprint.infra.scanner.v2.domain.main.message.un20.models.Dpi -import com.simprints.fingerprint.infra.scanner.v2.scanner.ScannerInfo -import com.simprints.infra.logging.Simber -import javax.inject.Inject - -internal class FingerprintTemplateProviderImpl @Inject constructor( - private val fingerprintCaptureWrapperFactory: FingerprintCaptureWrapperFactory, - private val calculateNecImageQualityUseCase: CalculateNecImageQualityUseCase, - private val captureProcessedImageCache: ProcessedImageCache, - private val extractNecTemplateUseCase: ExtractNecTemplateUseCase, - private val processImage: ProcessRawImageUseCase, - private val scannerInfo: ScannerInfo, -) : FingerprintTemplateProvider { - /** - * Acquires a fingerprint template from the scanner. - * - * Steps involved: - * 1. Acquire an unprocessed image from the scanner. - * 2. Decode the WSQ unprocessed image using the SecuGen decoder. - * 3. Apply the SecuGen algorithm to correct and upscale the raw image. - * 4. Check the image quality using the NEC SDK. - * 5. Convert the processed image into a template using the NEC SDK. - * 6. Return the generated template and cache the image for future use. - * - **/ - @OptIn(ExperimentalStdlibApi::class) - override suspend fun acquireFingerprintTemplate( - settings: FingerprintTemplateAcquisitionSettings?, - ): TemplateResponse { - require(settings != null) { "Settings cannot be null" } - val captureWrapper = fingerprintCaptureWrapperFactory.captureWrapper - - log("Acquiring unprocessed image") - // Always require a new image from the scanner using the minimum resolution it will upsampled latter using secugen image correction - val rawFingerprintScan = captureWrapper - .acquireUnprocessedImage( - Dpi(MIN_CAPTURE_DPI), - ).rawUnprocessedImage - // Store the recently captured image in the cache - captureProcessedImageCache.recentlyCapturedImage = rawFingerprintScan.imageData - // Store the serial number of the scanner for future use int the image upload - scannerInfo.setUn20SerialNumber(rawFingerprintScan.un20SerialNumber.toHexString()) - log("processing image using secugen image correction") - val secugenProcessedImage = processImage( - settings, - rawFingerprintScan, - rawFingerprintScan.un20SerialNumber, - rawFingerprintScan.brightness, - ) - log("quality checking image using nec sdk") - val qualityScore = calculateNecImageQualityUseCase(secugenProcessedImage) - log("quality score is $qualityScore the threshold is ${settings.qualityThreshold}") - return if (qualityScore < settings.qualityThreshold && !settings.allowLowQualityExtraction) { - // if the quality score is less than the threshold return an empty template - TemplateResponse( - byteArrayOf(), - FingerprintTemplateMetadata( - templateFormat = NEC_TEMPLATE_FORMAT, - imageQualityScore = qualityScore, - ), - ) - } else { - log("extracting template using nec sdk") - extractNecTemplateUseCase(secugenProcessedImage, qualityScore) - } - } - - private fun log(message: String) { - Simber.d(message, tag = "NEC_SDK") - } - - companion object { - private const val MIN_CAPTURE_DPI = 500.toShort() - } -} - -const val NEC_TEMPLATE_FORMAT = "NEC_1_5" diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCase.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCase.kt deleted file mode 100644 index e702ce7a81..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCase.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.secugen.WSQConverter -import com.simprints.core.DispatcherBG -import com.simprints.fingerprint.infra.scanner.domain.fingerprint.RawUnprocessedImage -import com.simprints.sgimagecorrection.SecugenImageCorrection -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext -import javax.inject.Inject - -internal class ProcessRawImageUseCase @Inject constructor( - private val secugenImageCorrection: SecugenImageCorrection, - private val acquireImageDistortionConfigurationUseCase: AcquireImageDistortionConfigurationUseCase, - private val wsqConverter: WSQConverter, - @param:DispatcherBG private val dispatcher: CoroutineDispatcher, -) { - suspend operator fun invoke( - settings: FingerprintTemplateAcquisitionSettings, - rawImage: RawUnprocessedImage, - un20SerialNumber: ByteArray, - brightness: Byte, - ): FingerprintImage = withContext(dispatcher) { - val decodedImage = wsqConverter.fromWSQToRaw(rawImage.imageData) - val scannerConfig = SecugenImageCorrection.ScannerConfig( - acquireImageDistortionConfigurationUseCase(), - settings.processingResolution?.value ?: DEFAULT_RESOLUTION, - un20SerialNumber, - brightness, - ) - val processedImage = - secugenImageCorrection.processRawImage(decodedImage.bytes, scannerConfig) - FingerprintImage( - processedImage.imageBytes, - processedImage.width, - processedImage.height, - processedImage.resolution, - ) - } - - companion object { - private const val DEFAULT_RESOLUTION: Short = 500 - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImpl.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImpl.kt deleted file mode 100644 index d3138695e6..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImpl.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.initialization - -import android.content.Context -import com.simprints.core.tools.utils.EncodingUtilsImpl -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.fingerprint.infra.basebiosdk.initialization.SdkInitializer -import com.simprints.infra.license.LicenseRepository -import com.simprints.infra.license.LicenseStatus -import com.simprints.infra.license.SaveLicenseCheckEventUseCase -import com.simprints.infra.license.determineLicenseStatus -import com.simprints.infra.license.models.Vendor -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.tools.toByteBuffer -import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject - -internal class SdkInitializerImpl @Inject constructor( - @ApplicationContext private val context: Context, - private val necInstance: NEC, - private val licenseRepository: LicenseRepository, - private val saveLicenseCheck: SaveLicenseCheckEventUseCase, -) : SdkInitializer { - override suspend fun initialize(initializationParams: Unit?) { - var licenseStatus: LicenseStatus? = null - try { - val licence = licenseRepository.getCachedLicense(Vendor.Nec) - licenseStatus = licence.determineLicenseStatus() - if (licenseStatus != LicenseStatus.VALID) { - throw BioSdkException.BioSdkInitializationException(message = "License is $licenseStatus") - } - necInstance.init(licence!!.data.encodeAndConvertToByteBuffer(), context) - } catch (e: Exception) { - licenseRepository.deleteCachedLicense(Vendor.Nec) - licenseStatus = LicenseStatus.ERROR - throw BioSdkException.BioSdkInitializationException(e) - } finally { - licenseStatus?.let { saveLicenseCheck(Vendor.Nec, it) } - } - } -} - -private fun String.encodeAndConvertToByteBuffer() = EncodingUtilsImpl.base64ToBytes(this).toByteBuffer() diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImpl.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImpl.kt deleted file mode 100644 index b86dc1ea13..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImpl.kt +++ /dev/null @@ -1,119 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.matching - -import com.simprints.core.domain.capture.BiometricReferenceCapture -import com.simprints.core.domain.capture.BiometricTemplateCapture -import com.simprints.core.domain.comparison.ComparisonResult -import com.simprints.core.domain.reference.BiometricTemplate -import com.simprints.core.domain.reference.CandidateRecord -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.fingerprint.infra.basebiosdk.matching.FingerprintMatcher -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.NEC_TEMPLATE_FORMAT -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.models.NECTemplate -import javax.inject.Inject - -internal class FingerprintMatcherImpl @Inject constructor( - private val nec: NEC, -) : FingerprintMatcher { - override val supportedTemplateFormat: String = NEC_TEMPLATE_FORMAT - override val matcherName: String = "NEC" - - override suspend fun match( - probeReference: BiometricReferenceCapture, - candidates: List, - settings: NecMatchingSettings?, - ): List { - // if probe template format is not supported by NEC matcher, return empty list - if (probeReference.templateFormatNotSupportedByNecMatcher()) { - return emptyList() - } - val probeTemplates = probeReference.templates - - return if (settings?.crossFingerComparison == true) { - crossFingerMatching(probeTemplates, candidates) - } else { - sameFingerMatching(probeTemplates, candidates) - } - } - - private fun sameFingerMatching( - probe: List, - candidates: List, - ) = candidates.map { - sameFingerMatching(probe, it) - } - - /** - * This method gets the matching score - * the matching score is calculated by - * - Getting the matching score for each similar finger pairs using NEC SDK - * - The overall score is the average of the individual finger match scores - * - We ignore probe fingers that doesn't have matching candidate fingers - * @param probeTemplates - * @param candidate - * @return MatchResult - */ - private fun sameFingerMatching( - probeTemplates: List, - candidate: CandidateRecord, - ): ComparisonResult { - var fingers = 0 // the number of fingers used in matching - val candidateTemplates = candidate.references.flatMap { it.templates } - - val total = probeTemplates.sumOf { probeTemplate -> - candidateTemplates.find { it.identifier == probeTemplate.identifier }?.let { candidateTemplate -> - fingers++ - verify(probeTemplate, candidateTemplate) - } ?: 0.toDouble() - } - return ComparisonResult(candidate.subjectId, getOverallScore(total, fingers)) - } - - private fun verify( - probe: BiometricTemplateCapture, - candidate: BiometricTemplate, - ) = try { - nec - .match( - probe.toNecTemplate(), - candidate.toNecTemplate(), - ).toDouble() - } catch (e: Exception) { - throw BioSdkException.TemplateMatchingException(e) - } - - private fun crossFingerMatching( - probe: List, - candidates: List, - ) = candidates.map { crossFingerMatching(probe, it) } - - private fun crossFingerMatching( - probe: List, - candidate: CandidateRecord, - ): ComparisonResult { - // Number of fingers used in matching - val fingers = probe.size - val candidateTemplates = candidate.references.flatMap { it.templates } - // Sum of maximum matching score for each finger - val total = probe.sumOf { probeTemplate -> - candidateTemplates.maxOf { candidateTemplate -> verify(probeTemplate, candidateTemplate) } - } - // Matching score = total/number of fingers - return ComparisonResult(candidate.subjectId, getOverallScore(total, fingers)) - } - - private fun BiometricTemplate.toNecTemplate() = NECTemplate(template, 0) // Quality score not used - - private fun BiometricTemplateCapture.toNecTemplate() = NECTemplate(template, 0) // Quality score not used - - private fun getOverallScore( - total: Double, - fingers: Int, - ) = if (fingers == 0) { - 0.toFloat() - } else { - (total / fingers).toFloat() - } -} - -private fun BiometricReferenceCapture.templateFormatNotSupportedByNecMatcher(): Boolean = format != NEC_TEMPLATE_FORMAT diff --git a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/NecMatchingSettings.kt b/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/NecMatchingSettings.kt deleted file mode 100644 index 4d91273d1b..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/main/java/com/simprints/fingerprint/infra/necsdkimpl/matching/NecMatchingSettings.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.matching - -@JvmInline -value class NecMatchingSettings( - val crossFingerComparison: Boolean = false, -) diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImplTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImplTest.kt deleted file mode 100644 index fefeec31ff..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/image/FingerprintImageProviderImplTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.image - -import com.google.common.truth.Truth -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -class FingerprintImageProviderImplTest { - private lateinit var fingerprintImageProvider: FingerprintImageProviderImpl - private val imageCache = ProcessedImageCache() - - @Before - fun setUp() { - fingerprintImageProvider = FingerprintImageProviderImpl(imageCache) - } - - @Test - fun `test acquireFingerprintImage success`() = runTest { - // Given - imageCache.recentlyCapturedImage = byteArrayOf(1, 2, 3) - // When - val result = fingerprintImageProvider.acquireFingerprintImage(null) - // Then - Truth.assertThat(result.imageBytes).isEqualTo(imageCache.recentlyCapturedImage) - } - - @Test(expected = BioSdkException.CannotAcquireFingerprintImageException::class) - fun `test acquireFingerprintImage failure`() = runTest { - // Given - imageCache.recentlyCapturedImage = null - // When - fingerprintImageProvider.acquireFingerprintImage(null) - // Then throw exception - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCaseTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCaseTest.kt deleted file mode 100644 index 7bccaa5555..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/AcquireImageDistortionConfigurationUseCaseTest.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.google.common.truth.Truth -import com.simprints.fingerprint.infra.imagedistortionconfig.ImageDistortionConfigRepo -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapper -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapperFactory -import com.simprints.fingerprint.infra.scanner.v2.scanner.ScannerInfo -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coJustRun -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -@OptIn(ExperimentalStdlibApi::class) -class AcquireImageDistortionConfigurationUseCaseTest { - @MockK - private lateinit var fingerprintCaptureWrapperFactory: FingerprintCaptureWrapperFactory - - @MockK - private lateinit var captureWrapper: FingerprintCaptureWrapper - - @MockK - private lateinit var imageDistortionConfigRepo: ImageDistortionConfigRepo - private lateinit var scannerInfo: ScannerInfo - - private lateinit var acquireImageDistortionConfigurationUseCase: AcquireImageDistortionConfigurationUseCase - - @Before - fun setUp() { - MockKAnnotations.init(this) - scannerInfo = ScannerInfo().apply { - setScannerId("scannerId") - setUn20SerialNumber("serialNumber") - } - every { fingerprintCaptureWrapperFactory.captureWrapper } returns captureWrapper - - acquireImageDistortionConfigurationUseCase = AcquireImageDistortionConfigurationUseCase( - fingerprintCaptureWrapperFactory, - scannerInfo, - imageDistortionConfigRepo, - ) - } - - @Test - fun `should acquire image distortion configuration from scanner if not stored locally`() = runTest { - // given - val distortionConfiguration = byteArrayOf(1, 2, 3).toHexString() - coEvery { imageDistortionConfigRepo.getConfig(any()) } returns null - coJustRun { imageDistortionConfigRepo.saveConfig(any(), any(), any()) } - coEvery { - captureWrapper.acquireImageDistortionMatrixConfiguration() - } returns distortionConfiguration.hexToByteArray() - - // when - val result = acquireImageDistortionConfigurationUseCase() - - // then - Truth.assertThat(result.toHexString()).isEqualTo(distortionConfiguration) - coVerify { captureWrapper.acquireImageDistortionMatrixConfiguration() } - coVerify { imageDistortionConfigRepo.saveConfig(any(), any(), any()) } - } - - @Test - fun `should acquire image distortion configuration from shared preferences if available`() = runTest { - // given - val distortionConfiguration = byteArrayOf(1, 2, 3) - coEvery { imageDistortionConfigRepo.getConfig(any()) } returns distortionConfiguration - - // when - val result = acquireImageDistortionConfigurationUseCase() - - // then - Truth.assertThat(result).isEqualTo(distortionConfiguration) - coVerify(exactly = 0) { captureWrapper.acquireImageDistortionMatrixConfiguration() } - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCaseTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCaseTest.kt deleted file mode 100644 index 8e589e7cbb..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/CalculateNecImageQualityUseCaseTest.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.google.common.truth.Truth -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.fingerprint.FingerprintImageQualityCheck -import com.simprints.testtools.common.coroutines.TestCoroutineRule -import io.mockk.MockKAnnotations -import io.mockk.every -import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -class CalculateNecImageQualityUseCaseTest { - companion object { - private const val DEFAULT_GOOD_IMAGE_QUALITY = 87 - } - - @MockK - private lateinit var nec: NEC - private val testImage = FingerprintImage(byteArrayOf(), 1, 1, 1) - private lateinit var calculateNecImageQualityUseCase: CalculateNecImageQualityUseCase - - @get:Rule - val rule = InstantTaskExecutorRule() - - @get:Rule - val testCoroutineRule = TestCoroutineRule() - - @Before - fun setUp() { - MockKAnnotations.init(this) - calculateNecImageQualityUseCase = - CalculateNecImageQualityUseCase(nec, testCoroutineRule.testCoroutineDispatcher) - } - - @Test - fun `test getNECQualityCheckResult`() = runTest { - // Given - every { nec.qualityCheck(any()) } returns DEFAULT_GOOD_IMAGE_QUALITY - - // When - val result = calculateNecImageQualityUseCase(testImage) - // Then - Truth.assertThat(result).isEqualTo(DEFAULT_GOOD_IMAGE_QUALITY) - } - - @Test(expected = BioSdkException.ImageQualityCheckingException::class) - fun `test isBadScan failure should throw`() = runTest { - every { - nec.qualityCheck(any()) - } throws FingerprintImageQualityCheck.QualityCheckFailedException(-1) - // When - calculateNecImageQualityUseCase(testImage) - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCaseTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCaseTest.kt deleted file mode 100644 index 3918825b56..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ExtractNecTemplateUseCaseTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.google.common.truth.Truth -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.necwrapper.nec.NEC -import com.simprints.necwrapper.nec.models.NecImage -import com.simprints.testtools.common.coroutines.TestCoroutineRule -import io.mockk.MockKAnnotations -import io.mockk.every -import io.mockk.impl.annotations.RelaxedMockK -import io.mockk.verify -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -class ExtractNecTemplateUseCaseTest { - @RelaxedMockK - private lateinit var nec: NEC - private lateinit var extractNecTemplateUseCase: ExtractNecTemplateUseCase - - @get:Rule - val rule = InstantTaskExecutorRule() - - @get:Rule - val testCoroutineRule = TestCoroutineRule() - - @Before - fun setUp() { - MockKAnnotations.init(this) - extractNecTemplateUseCase = ExtractNecTemplateUseCase(nec, testCoroutineRule.testCoroutineDispatcher) - } - - @Test - fun `test nec template extractor success`() = runTest { - // Given - val fingerprintImage = FingerprintImage( - width = 500, - height = 500, - resolution = 500, - imageBytes = ByteArray(0), - ) - // When - val result = extractNecTemplateUseCase(fingerprintImage, 100) - // Then - verify { - nec.extract( - NecImage( - width = fingerprintImage.width, - height = fingerprintImage.height, - resolution = fingerprintImage.resolution, - imageBytes = fingerprintImage.imageBytes, - ), - ) - } - Truth.assertThat(result.templateMetadata?.imageQualityScore).isEqualTo(100) - } - - @Test(expected = BioSdkException.TemplateExtractionException::class) - fun `test nec template extractor failure`() = runTest { - // Given - val fingerprintImage = FingerprintImage( - width = 500, - height = 500, - resolution = 500, - imageBytes = ByteArray(0), - ) - every { nec.extract(any()) } throws Exception() - // When - extractNecTemplateUseCase(fingerprintImage, 100) - // Then throw exception - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImplTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImplTest.kt deleted file mode 100644 index da66570ed0..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/FingerprintTemplateProviderImplTest.kt +++ /dev/null @@ -1,177 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import com.google.common.truth.Truth -import com.simprints.fingerprint.infra.basebiosdk.acquisition.domain.TemplateResponse -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.image.ProcessedImageCache -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapper -import com.simprints.fingerprint.infra.scanner.capture.FingerprintCaptureWrapperFactory -import com.simprints.fingerprint.infra.scanner.domain.fingerprint.AcquireUnprocessedImageResponse -import com.simprints.fingerprint.infra.scanner.domain.fingerprint.RawUnprocessedImage -import com.simprints.fingerprint.infra.scanner.v2.domain.main.message.un20.models.Dpi -import com.simprints.fingerprint.infra.scanner.v2.scanner.ScannerInfo -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.impl.annotations.RelaxedMockK -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -class FingerprintTemplateProviderImplTest { - private lateinit var fingerprintTemplateProviderImpl: FingerprintTemplateProviderImpl - - @RelaxedMockK - private lateinit var calculateNecImageQualityUseCase: CalculateNecImageQualityUseCase - - @MockK - private lateinit var fingerprintCaptureWrapperFactory: FingerprintCaptureWrapperFactory - - @MockK - private lateinit var extractNecTemplateUseCase: ExtractNecTemplateUseCase - - @RelaxedMockK - private lateinit var processedImageCache: ProcessedImageCache - - @MockK - private lateinit var captureWrapper: FingerprintCaptureWrapper - - @RelaxedMockK - private lateinit var processRawImage: ProcessRawImageUseCase - - private lateinit var scannerInfo: ScannerInfo - - @Before - fun setUp() { - MockKAnnotations.init(this) - scannerInfo = ScannerInfo() - every { fingerprintCaptureWrapperFactory.captureWrapper } returns captureWrapper - coEvery { - captureWrapper.acquireUnprocessedImage(any()) - } returns AcquireUnprocessedImageResponse( - rawUnprocessedImage = createDummyRawUnprocessedImage(), - ) - coEvery { - extractNecTemplateUseCase.invoke(any(), any()) - } returns TemplateResponse( - byteArrayOf(1, 2, 3), - FingerprintTemplateMetadata( - templateFormat = NEC_TEMPLATE_FORMAT, - imageQualityScore = 10, - ), - ) - fingerprintTemplateProviderImpl = FingerprintTemplateProviderImpl( - fingerprintCaptureWrapperFactory = fingerprintCaptureWrapperFactory, - calculateNecImageQualityUseCase = calculateNecImageQualityUseCase, - captureProcessedImageCache = processedImageCache, - extractNecTemplateUseCase = extractNecTemplateUseCase, - processImage = processRawImage, - scannerInfo = scannerInfo, - ) - } - - @Test(expected = IllegalArgumentException::class) - fun `test null settings throws exception`() = runTest { - // Given - val settings = null - // When - fingerprintTemplateProviderImpl.acquireFingerprintTemplate(settings) - // Then exception is thrown - } - - @OptIn(ExperimentalStdlibApi::class) - @Test - fun `test acquireFingerprintTemplate success`() = runTest { - // Given - val settings = FingerprintTemplateAcquisitionSettings( - processingResolution = Dpi(500), - qualityThreshold = 0, - timeOutMs = 0, - allowLowQualityExtraction = false, - ) - // When - fingerprintTemplateProviderImpl.acquireFingerprintTemplate(settings) - // Then - coVerify { - captureWrapper.acquireUnprocessedImage(any()) - processRawImage(any(), any(), any(), any()) - processedImageCache.recentlyCapturedImage = any() - calculateNecImageQualityUseCase.invoke(any()) - extractNecTemplateUseCase.invoke(any(), any()) - } - Truth.assertThat(scannerInfo.un20SerialNumber).isEqualTo(UN20_SERIAL_NUMBER.toHexString()) - } - - @Test - fun `test acquireFingerprintTemplate fails if quality score is less than threshold and allowLowQualityExtraction is false`() = runTest { - // Given - coEvery { calculateNecImageQualityUseCase.invoke(any()) } returns 10 - val settings = FingerprintTemplateAcquisitionSettings( - processingResolution = Dpi(500), - qualityThreshold = 20, - timeOutMs = 0, - allowLowQualityExtraction = false, - ) - // When - val result = fingerprintTemplateProviderImpl.acquireFingerprintTemplate(settings) - // Then - coVerify { - captureWrapper.acquireUnprocessedImage(any()) - processedImageCache.recentlyCapturedImage = any() - processRawImage(any(), any(), any(), any()) - calculateNecImageQualityUseCase.invoke(any()) - } - coVerify(exactly = 0) { - extractNecTemplateUseCase.invoke(any(), any()) - } - Truth.assertThat(result.template).isEmpty() - } - - @Test - fun `test acquireFingerprintTemplate extracts template if quality score is less than threshold and allowLowQualityExtraction is true`() = - runTest { - // Given - coEvery { calculateNecImageQualityUseCase.invoke(any()) } returns 10 - val settings = FingerprintTemplateAcquisitionSettings( - processingResolution = Dpi(500), - qualityThreshold = 20, - timeOutMs = 0, - allowLowQualityExtraction = true, - ) - // When - val result = fingerprintTemplateProviderImpl.acquireFingerprintTemplate(settings) - // Then - coVerify { - captureWrapper.acquireUnprocessedImage(any()) - processedImageCache.recentlyCapturedImage = any() - processRawImage(any(), any(), any(), any()) - calculateNecImageQualityUseCase.invoke(any()) - extractNecTemplateUseCase.invoke(any(), any()) - } - Truth.assertThat(result.template).isNotEmpty() - } - - fun createDummyRawUnprocessedImage(): RawUnprocessedImage { - // Create a ByteArray of size 50 (header + image data) - val imageBytes = ByteArray(50) - - val serialNumber = UN20_SERIAL_NUMBER - System.arraycopy(serialNumber, 0, imageBytes, 0, 15) - - // Set the brightness value (at index 15) - imageBytes[15] = 100.toByte() // Example brightness value - - // Fill dummy image data after the header - for (i in 20 until imageBytes.size) { - imageBytes[i] = (i % 256).toByte() - } - - // Create and return the RawUnprocessedImage instance - return RawUnprocessedImage(imageBytes) - } - - companion object { - private val UN20_SERIAL_NUMBER = "123456789123456".toByteArray() - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCaseTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCaseTest.kt deleted file mode 100644 index 3a9aa49f2d..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/acquisition/template/ProcessRawImageUseCaseTest.kt +++ /dev/null @@ -1,117 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.acquisition.template - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import com.google.common.truth.Truth -import com.secugen.RawImage -import com.secugen.WSQConverter -import com.simprints.fingerprint.infra.scanner.domain.fingerprint.RawUnprocessedImage -import com.simprints.fingerprint.infra.scanner.v2.domain.main.message.un20.models.Dpi -import com.simprints.sgimagecorrection.SecugenImageCorrection -import com.simprints.sgimagecorrection.SecugenImageCorrection.ProcessedImage -import com.simprints.testtools.common.coroutines.TestCoroutineRule -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Rule -import org.junit.Test - -class ProcessRawImageUseCaseTest { - @MockK - private lateinit var secugenImageCorrection: SecugenImageCorrection - - @MockK - private lateinit var acquireImageDistortionConfigurationUseCase: AcquireImageDistortionConfigurationUseCase - - @MockK - private lateinit var wsqConverter: WSQConverter - - private lateinit var processRawImage: ProcessRawImageUseCase - - @get:Rule - val rule = InstantTaskExecutorRule() - - @get:Rule - val testCoroutineRule = TestCoroutineRule() - - @Before - fun setUp() { - MockKAnnotations.init(this) - coEvery { acquireImageDistortionConfigurationUseCase() } returns byteArrayOf(1, 2, 3) - processRawImage = ProcessRawImageUseCase( - secugenImageCorrection, - acquireImageDistortionConfigurationUseCase, - wsqConverter, - testCoroutineRule.testCoroutineDispatcher, - ) - } - - @Test - fun `invoke should process raw image and return FingerprintImage`() = runTest { - // Arrange - val settings = FingerprintTemplateAcquisitionSettings( - processingResolution = Dpi(500), - qualityThreshold = 0, - timeOutMs = 0, - allowLowQualityExtraction = true, - ) - val rawImage = RawUnprocessedImage( - byteArrayOf( - 0x05, - 0x06, - 0x07, - 0x08, - 0x05, - 0x06, - 0x07, - 0x08, - 0x05, - 0x06, - 0x07, - 0x08, - 0x05, - 0x06, - 0x07, - 0x08, - 0x05, - 0x06, - 0x07, - 0x08, - 0x05, - 0x06, - 0x07, - 0x08, - ), - ) - - val decodedImage: RawImage = - RawImage(width = 400, height = 300, ppi = 500, depth = 1, bytes = ByteArray(20)) - - val expectedProcessedImage: ProcessedImage = ProcessedImage( - imageBytes = ByteArray(20), - width = 400, - height = 300, - resolution = 500, - ) - - coEvery { wsqConverter.fromWSQToRaw(rawImage.imageData) } returns decodedImage - coEvery { - secugenImageCorrection.processRawImage(decodedImage.bytes, any()) - } returns expectedProcessedImage - - val result = processRawImage(settings, rawImage, byteArrayOf(0), 1) - - Truth.assertThat(result.imageBytes).isEqualTo(expectedProcessedImage.imageBytes) - Truth.assertThat(result.width).isEqualTo(expectedProcessedImage.width) - Truth.assertThat(result.height).isEqualTo(expectedProcessedImage.height) - Truth.assertThat(result.resolution).isEqualTo(expectedProcessedImage.resolution) - - coVerify { wsqConverter.fromWSQToRaw(rawImage.imageData) } - coVerify { acquireImageDistortionConfigurationUseCase() } - coVerify { - secugenImageCorrection.processRawImage(decodedImage.bytes, any()) - } - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImplTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImplTest.kt deleted file mode 100644 index e572bc7d18..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/initialization/SdkInitializerImplTest.kt +++ /dev/null @@ -1,100 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.initialization - -import android.content.Context -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.common.truth.Truth.assertThat -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.fingerprint.infra.basebiosdk.initialization.SdkInitializer -import com.simprints.infra.license.LicenseRepository -import com.simprints.infra.license.LicenseStatus -import com.simprints.infra.license.SaveLicenseCheckEventUseCase -import com.simprints.infra.license.models.License -import com.simprints.infra.license.models.LicenseVersion -import com.simprints.infra.license.models.Vendor -import com.simprints.necwrapper.nec.NEC -import io.mockk.MockKAnnotations -import io.mockk.coEvery -import io.mockk.coJustRun -import io.mockk.coVerify -import io.mockk.every -import io.mockk.impl.annotations.MockK -import io.mockk.justRun -import io.mockk.slot -import io.mockk.verify -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -class SdkInitializerImplTest { - @MockK - lateinit var context: Context - - @MockK - lateinit var nec: NEC - - @MockK - lateinit var licenseRepository: LicenseRepository - - @MockK - lateinit var saveLicenseCheck: SaveLicenseCheckEventUseCase - - private lateinit var sdkInitializer: SdkInitializer - - @Before - fun setUp() { - MockKAnnotations.init(this) - justRun { nec.init(any(), context) } - coEvery { - licenseRepository.getCachedLicense(Vendor.Nec) - } returns License("2133-12-30T17:32:28Z", "license", LicenseVersion("1.0")) - - coJustRun { licenseRepository.deleteCachedLicense(Vendor.Nec) } - sdkInitializer = - SdkInitializerImpl(context, nec, licenseRepository, saveLicenseCheck) - } - - @Test - fun `test initialize success`() = runTest { - // Given - val licenseStatusSlot = slot() - coJustRun { saveLicenseCheck(Vendor.Nec, capture(licenseStatusSlot)) } - - // When - sdkInitializer.initialize(null) - // Then - verify { nec.init(any(), context) } - assertThat(licenseStatusSlot.captured).isEqualTo(LicenseStatus.VALID) - } - - @Test(expected = BioSdkException.BioSdkInitializationException::class) - fun `test initialize with expired license`() = runTest { - // Given - coEvery { - licenseRepository.getCachedLicense(Vendor.Nec) - } returns License("2011-12-30T17:32:28Z", "license", LicenseVersion("1.0")) - val licenseStatusSlot = slot() - coJustRun { saveLicenseCheck(Vendor.Nec, capture(licenseStatusSlot)) } - - // When - sdkInitializer.initialize(null) - // Then - coVerify { licenseRepository.deleteCachedLicense(Vendor.Nec) } - assertThat(licenseStatusSlot.captured).isEqualTo(LicenseStatus.EXPIRED) - } - - @Test(expected = BioSdkException.BioSdkInitializationException::class) - fun `test error during initialization`() = runTest { - // Given - every { nec.init(any(), context) } throws Exception() - val licenseStatusSlot = slot() - coJustRun { saveLicenseCheck(Vendor.Nec, capture(licenseStatusSlot)) } - - // When - sdkInitializer.initialize(null) - // Then - coVerify { licenseRepository.deleteCachedLicense(Vendor.Nec) } - assertThat(licenseStatusSlot.captured).isEqualTo(LicenseStatus.ERROR) - } -} diff --git a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImplTest.kt b/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImplTest.kt deleted file mode 100644 index 6d75335bc0..0000000000 --- a/fingerprint/infra/nec-bio-sdk/src/test/java/com/simprints/fingerprint/infra/necsdkimpl/matching/FingerprintMatcherImplTest.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.simprints.fingerprint.infra.necsdkimpl.matching - -import com.google.common.truth.* -import com.simprints.core.domain.common.Modality -import com.simprints.core.domain.reference.BiometricReference -import com.simprints.core.domain.capture.BiometricReferenceCapture -import com.simprints.core.domain.reference.BiometricTemplate -import com.simprints.core.domain.capture.BiometricTemplateCapture -import com.simprints.core.domain.reference.CandidateRecord -import com.simprints.core.domain.common.TemplateIdentifier -import com.simprints.fingerprint.infra.basebiosdk.exceptions.BioSdkException -import com.simprints.fingerprint.infra.necsdkimpl.acquisition.template.NEC_TEMPLATE_FORMAT -import com.simprints.necwrapper.nec.NEC -import io.mockk.* -import io.mockk.impl.annotations.MockK -import kotlinx.coroutines.test.runTest -import org.junit.Before -import org.junit.Test - -class FingerprintMatcherImplTest { - @MockK - private lateinit var nec: NEC - - private lateinit var matcher: FingerprintMatcherImpl - - @Before - fun setUp() { - MockKAnnotations.init(this) - matcher = FingerprintMatcherImpl(nec) - } - - @Test - fun `test match FingerprintIdentities with the same fingerprint IDs`() = runTest { - // Given - every { nec.match(any(), any(), any()) } returns 3 - val probe = generateProbe(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB) - val candidates = listOf( - generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB), - generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB), - generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB), - ) - // When - val result = matcher.match(probe, candidates, NecMatchingSettings(false)) - // Then - Truth.assertThat(result.size).isEqualTo(3) - Truth.assertThat(result[0].comparisonScore).isEqualTo(3) - } - - @Test - fun `test match FingerprintIdentities with different fingerprint IDs`() = runTest { - // Given - every { nec.match(any(), any(), any()) } returns 3 - val probe = generateProbe(TemplateIdentifier.LEFT_INDEX_FINGER, TemplateIdentifier.RIGHT_INDEX_FINGER) - val candidate = generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB) - // When - val result = matcher.match(probe, listOf(candidate), NecMatchingSettings(false)) - // Then - Truth.assertThat(result.size).isEqualTo(1) - Truth.assertThat(result[0].comparisonScore).isEqualTo(0) - } - - @Test - fun `test match FingerprintIdentities with different fingerprint IDs and crossFingerComparison`() = runTest { - // Given - every { nec.match(any(), any(), any()) } returns 3 - val probe = generateProbe(TemplateIdentifier.LEFT_INDEX_FINGER, TemplateIdentifier.RIGHT_INDEX_FINGER) - val candidate = generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB) - // When - val result = matcher.match(probe, listOf(candidate), NecMatchingSettings(true)) - // Then - Truth.assertThat(result.size).isEqualTo(1) - Truth.assertThat(result[0].comparisonScore).isEqualTo(3) - } - - @Test - fun `test match FingerprintIdentities with only one equal fingerprint IDs`() = runTest { - // Given - every { nec.match(any(), any(), any()) } returns 3 - val probe = generateProbe(TemplateIdentifier.LEFT_INDEX_FINGER, TemplateIdentifier.RIGHT_INDEX_FINGER) - val candidate = generateIdentity(TemplateIdentifier.LEFT_INDEX_FINGER, TemplateIdentifier.RIGHT_THUMB) - // When - val result = matcher.match(probe, listOf(candidate), NecMatchingSettings(false)) - // Then - Truth.assertThat(result.size).isEqualTo(1) - Truth.assertThat(result[0].comparisonScore).isEqualTo(3) - } - - @Test(expected = BioSdkException.TemplateMatchingException::class) - fun `test match FingerprintIdentifies before initialize NEC`() = runTest { - // Given - every { - nec.match(any(), any(), any()) - } throws NEC.AttemptedToRunBeforeInitializedException() - val probe = generateProbe( - TemplateIdentifier.LEFT_INDEX_FINGER, - TemplateIdentifier.RIGHT_INDEX_FINGER, - ) - val candidate = generateIdentity(TemplateIdentifier.LEFT_INDEX_FINGER, TemplateIdentifier.RIGHT_THUMB) - // When - matcher.match(probe, listOf(candidate), NecMatchingSettings(false)) - } - - @Test - fun `test match FingerprintIdentities probe with different template format`() = runTest { - // Given - val probe = - generateProbe( - TemplateIdentifier.LEFT_INDEX_FINGER, - TemplateIdentifier.RIGHT_INDEX_FINGER, - format = "Unsupported", - ) - val candidate = - generateIdentity(TemplateIdentifier.LEFT_THUMB, TemplateIdentifier.RIGHT_THUMB) - // When - val result = matcher.match(probe, listOf(candidate), NecMatchingSettings(false)) - // Then - Truth.assertThat(result.size).isEqualTo(0) - } - - private fun generateProbe( - vararg fingers: TemplateIdentifier, - format: String = NEC_TEMPLATE_FORMAT, - ) = BiometricReferenceCapture( - referenceId = "referenceId", - modality = Modality.FINGERPRINT, - format = format, - templates = fingers.map { - BiometricTemplateCapture( - captureEventId = it.name, - template = ByteArray(0), - identifier = it, - ) - }, - ) - - private fun generateIdentity( - vararg fingers: TemplateIdentifier, - format: String = NEC_TEMPLATE_FORMAT, - ) = CandidateRecord( - subjectId = "id", - references = fingers.map { - BiometricReference( - referenceId = it.name, - modality = Modality.FINGERPRINT, - format = format, - templates = listOf( - BiometricTemplate( - template = ByteArray(0), - identifier = it, - ), - ), - ) - }, - ) -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 256253941c..2d4e61328f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,7 +65,6 @@ libsimprints_version = "2025.2.2" simmatcher_version = "1.3.0" roc_wrapper_version = "1.23.0" roc_wrapper-v3_version = "3.1.0" -nec_version = "1.5.0" secugen_version = "1.1.0" simface = "2025.4.0" @@ -201,9 +200,6 @@ simmatcher = { module = "com.simprints:libsimmatcher", version.ref = "simmatcher roc-v1 = { module = "com.simprints:rocwrapper", version.ref = "roc_wrapper_version" } # roc v3 sdk hosted in https://github.com/Simprints/lib-roc-wrapper-v3 roc-v3 = { module = "com.simprints:rocwrapper-v3", version.ref = "roc_wrapper-v3_version" } -# nec sdk hosted in https://github.com/Simprints/NEC-wrapper/ -nec-wrapper = { module = " com.simprints:necwrapper", version.ref = "nec_version" } -nec-lib = { module = "com.nec:lib", version.ref = "nec_version" } # secugen sdk hosted in https://github.com/Simprints/secugen-wrapper secugen = { module = "com.simprints:secugenwrapper", version.ref = "secugen_version" } simface = { module = "com.simprints.biometrics:simface", version.ref = "simface" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 3fccd8b21c..46ca8063a2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -89,7 +89,6 @@ include( ":fingerprint:infra:base-bio-sdk", ":fingerprint:infra:bio-sdk", ":fingerprint:infra:simprints-bio-sdk", - ":fingerprint:infra:nec-bio-sdk", ":fingerprint:infra:simafis-wrapper", ":fingerprint:infra:image-distortion-config", ) From 002995e4335f00557ca9d3c3086d7764195dc4bd Mon Sep 17 00:00:00 2001 From: Melad Raouf Date: Wed, 28 Jan 2026 12:07:26 +0000 Subject: [PATCH 2/5] Update simface version to 2026.1.0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2d4e61328f..d217a80ce0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -66,7 +66,7 @@ simmatcher_version = "1.3.0" roc_wrapper_version = "1.23.0" roc_wrapper-v3_version = "3.1.0" secugen_version = "1.1.0" -simface = "2025.4.0" +simface = "2026.1.0" junit_version = "4.13.2" junit_ext_version = "1.3.0" From d6eef45ec6a0358448e4549c8335312b28e30f68 Mon Sep 17 00:00:00 2001 From: Melad Raouf Date: Wed, 28 Jan 2026 12:07:48 +0000 Subject: [PATCH 3/5] Remove x86 ABI filters from build configuration --- id/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/id/build.gradle.kts b/id/build.gradle.kts index 92085ce5c0..33419bf3c4 100644 --- a/id/build.gradle.kts +++ b/id/build.gradle.kts @@ -10,7 +10,7 @@ android { namespace = "com.simprints.id" defaultConfig { - ndk.abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")) + ndk.abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a")) } compileOptions { From 17ab73d907d91e778c7d6ffd2c177e3fda38a722 Mon Sep 17 00:00:00 2001 From: Melad Raouf Date: Sat, 31 Jan 2026 17:17:27 +0000 Subject: [PATCH 4/5] [MS-1315] Handle face detection state loss in ConfirmationFragment --- .../face/capture/screens/FaceCaptureViewModel.kt | 7 +++++-- .../capture/screens/confirmation/ConfirmationFragment.kt | 9 ++++++++- .../face/capture/screens/FaceCaptureViewModelTest.kt | 7 +++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/face/capture/src/main/java/com/simprints/face/capture/screens/FaceCaptureViewModel.kt b/face/capture/src/main/java/com/simprints/face/capture/screens/FaceCaptureViewModel.kt index b588440eda..977fb99fa1 100644 --- a/face/capture/src/main/java/com/simprints/face/capture/screens/FaceCaptureViewModel.kt +++ b/face/capture/src/main/java/com/simprints/face/capture/screens/FaceCaptureViewModel.kt @@ -178,7 +178,11 @@ internal class FaceCaptureViewModel @Inject constructor( if (faceConfiguration?.imageSavingStrategy?.shouldSaveImage() == true) { saveFaceDetections() } - + if (faceDetections.isEmpty()) { + Simber.i("No face captured", tag = FACE_CAPTURE) + recapture() + return@launch + } val items = faceDetections.map { detection -> BiometricTemplateCapture( captureEventId = detection.id, @@ -187,7 +191,6 @@ internal class FaceCaptureViewModel @Inject constructor( } val referenceId = UUID.randomUUID().toString() eventReporter.addBiometricReferenceCreationEvents(referenceId, items.map { it.captureEventId }) - val format = faceDetections .firstOrNull() ?.face diff --git a/face/capture/src/main/java/com/simprints/face/capture/screens/confirmation/ConfirmationFragment.kt b/face/capture/src/main/java/com/simprints/face/capture/screens/confirmation/ConfirmationFragment.kt index f5f8c90e54..4940b7f76f 100644 --- a/face/capture/src/main/java/com/simprints/face/capture/screens/confirmation/ConfirmationFragment.kt +++ b/face/capture/src/main/java/com/simprints/face/capture/screens/confirmation/ConfirmationFragment.kt @@ -38,7 +38,14 @@ internal class ConfirmationFragment : Fragment(R.layout.fragment_confirmation) { ) { super.onViewCreated(view, savedInstanceState) applySystemBarInsets(view) - + val detection = mainVm.getSampleDetection() + // Check if state was lost (Process Death) + if (detection == null) { + // it is safer to force a recapture in this case + Simber.i("Face detection state lost during confirmation, forcing recapture", tag = ORCHESTRATION) + mainVm.recapture() + return + } Simber.i("ConfirmationFragment started", tag = ORCHESTRATION) startTime = faceTimeHelper.now() diff --git a/face/capture/src/test/java/com/simprints/face/capture/screens/FaceCaptureViewModelTest.kt b/face/capture/src/test/java/com/simprints/face/capture/screens/FaceCaptureViewModelTest.kt index 49a3a6492d..0ef699ee2b 100644 --- a/face/capture/src/test/java/com/simprints/face/capture/screens/FaceCaptureViewModelTest.kt +++ b/face/capture/src/test/java/com/simprints/face/capture/screens/FaceCaptureViewModelTest.kt @@ -139,6 +139,13 @@ class FaceCaptureViewModelTest { } } + @Test + fun `restart capture when flow finishes and no face detected`() { + viewModel.initFaceBioSdk(mockk(), ModalitySdkType.SIM_FACE) + viewModel.flowFinished() + assertThat(viewModel.recaptureEvent.getOrAwaitValue()).isNotNull() + } + @Test fun `Recapture requests clears capture list`() { viewModel.captureFinished(faceDetections) From 7fab81dbae2e85768ec505cc445dd5d66b21e612 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Tue, 3 Feb 2026 16:06:31 +0200 Subject: [PATCH 5/5] MS-1312 Reset the frame processing flag if OCR process has been interrupted by configuration change --- .../scanocr/ExternalCredentialScanOcrFragment.kt | 6 +++--- .../scanocr/ExternalCredentialScanOcrViewModel.kt | 13 +++++++++---- .../ExternalCredentialScanOcrViewModelTest.kt | 11 ++++++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrFragment.kt b/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrFragment.kt index 6a55b6e4a2..e09a0240f6 100644 --- a/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrFragment.kt +++ b/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrFragment.kt @@ -112,8 +112,7 @@ internal class ExternalCredentialScanOcrFragment : Fragment(R.layout.fragment_ex override fun onResume() { super.onResume() - val currentPermission = requireActivity().getCurrentPermissionStatus(CAMERA) - when (currentPermission) { + when (val currentPermission = requireActivity().getCurrentPermissionStatus(CAMERA)) { PermissionStatus.Granted -> initializeFragment() PermissionStatus.Denied -> { // Permission dialog was already displayed, and user denied permissions. Showing rationale so to avoid constantly-appearing @@ -292,7 +291,7 @@ internal class ExternalCredentialScanOcrFragment : Fragment(R.layout.fragment_ex private fun startOcr() { imageAnalysis.setAnalyzer(cameraExecutor) { videoFrame: ImageProxy -> - if (viewModel.isRunningOcrOnFrame) { + if (viewModel.isRunningOcrOnFrame.get()) { videoFrame.close() return@setAnalyzer } @@ -360,6 +359,7 @@ internal class ExternalCredentialScanOcrFragment : Fragment(R.layout.fragment_ex if (::imageAnalysis.isInitialized) { imageAnalysis.clearAnalyzer() } + viewModel.ocrStopped() } /** diff --git a/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModel.kt b/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModel.kt index e2d5cff41a..b1df86a0dd 100644 --- a/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModel.kt +++ b/feature/external-credential/src/main/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModel.kt @@ -37,6 +37,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch +import java.util.concurrent.atomic.AtomicBoolean internal class ExternalCredentialScanOcrViewModel @AssistedInject constructor( @Assisted val ocrDocumentType: OcrDocumentType, @@ -57,8 +58,8 @@ internal class ExternalCredentialScanOcrViewModel @AssistedInject constructor( } private var detectedBlocks: List = emptyList() - var isRunningOcrOnFrame: Boolean = false - private set + val isRunningOcrOnFrame = AtomicBoolean(false) + val isOcrActive: Boolean get() = detectedBlocks.isNotEmpty() private var ocrState: ScanOcrState = ScanOcrState.EMPTY @@ -107,6 +108,10 @@ internal class ExternalCredentialScanOcrViewModel @AssistedInject constructor( } } + fun ocrStopped() { + isRunningOcrOnFrame.set(false) + } + fun runOcrOnFrame( frame: Bitmap, cropConfig: OcrCropConfig, @@ -127,7 +132,7 @@ internal class ExternalCredentialScanOcrViewModel @AssistedInject constructor( ) } } finally { - isRunningOcrOnFrame = false + isRunningOcrOnFrame.set(false) } } } @@ -179,7 +184,7 @@ internal class ExternalCredentialScanOcrViewModel @AssistedInject constructor( } fun ocrOnFrameStarted() { - isRunningOcrOnFrame = true + isRunningOcrOnFrame.set(true) } companion object { diff --git a/feature/external-credential/src/test/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModelTest.kt b/feature/external-credential/src/test/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModelTest.kt index e147294cfd..cdec3ca03b 100644 --- a/feature/external-credential/src/test/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModelTest.kt +++ b/feature/external-credential/src/test/java/com/simprints/feature/externalcredential/screens/scanocr/ExternalCredentialScanOcrViewModelTest.kt @@ -107,6 +107,15 @@ internal class ExternalCredentialScanOcrViewModelTest { assertThat(state.scansRequired).isEqualTo(3) } + @Test + fun `ocrStopped resets the flag for frame processing`() { + viewModel.ocrOnFrameStarted() + assertThat(viewModel.isRunningOcrOnFrame.get()).isTrue() + + viewModel.ocrStopped() + assertThat(viewModel.isRunningOcrOnFrame.get()).isFalse() + } + @Test fun `runOcrOnFrame updates detected blocks and state when successful`() = runTest { val mockDetectedBlock = mockk() @@ -122,7 +131,7 @@ internal class ExternalCredentialScanOcrViewModelTest { val state = observer.value() as ScanOcrState.ScanningInProgress assertThat(state.successfulCaptures).isEqualTo(1) - assertThat(viewModel.isRunningOcrOnFrame).isFalse() + assertThat(viewModel.isRunningOcrOnFrame.get()).isFalse() assertThat(viewModel.isOcrActive).isTrue() }