From 2729321573c63907b535676000955de5eddf689a Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Tue, 4 Jun 2024 20:39:12 +0300 Subject: [PATCH 1/6] [MS-464] Parse subjectAge from Intent metadata and add it to ActionRequest --- .../clientapi/mappers/request/IntentToActionMapper.kt | 5 +---- .../mappers/request/builders/EnrolRequestBuilder.kt | 3 ++- .../request/builders/IdentifyRequestBuilder.kt | 1 + .../mappers/request/builders/VerifyRequestBuilder.kt | 1 + .../request/extractors/ActionRequestExtractor.kt | 8 +++++++- gradle/libs.versions.toml | 2 +- .../infra/orchestration/data/ActionRequest.kt | 11 +++++++++++ 7 files changed, 24 insertions(+), 7 deletions(-) diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/IntentToActionMapper.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/IntentToActionMapper.kt index 95e594d595..acc66e2bf1 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/IntentToActionMapper.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/IntentToActionMapper.kt @@ -50,10 +50,7 @@ internal class IntentToActionMapper @Inject constructor( return when (actionIdentifier.packageName) { OdkConstants.PACKAGE_NAME -> mapOdkAction(actionIdentifier, extras, project) CommCareConstants.PACKAGE_NAME -> mapCommCareAction(actionIdentifier, extras, project) - LibSimprintsConstants.PACKAGE_NAME -> { - mapLibSimprintsAction(actionIdentifier, extras, project) - } - + LibSimprintsConstants.PACKAGE_NAME -> mapLibSimprintsAction(actionIdentifier, extras, project) else -> throw InvalidRequestException( "Unsupported package name", ClientApiError.INVALID_STATE_FOR_INTENT_ACTION ) diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/EnrolRequestBuilder.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/EnrolRequestBuilder.kt index f2cc5d549b..be759f7246 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/EnrolRequestBuilder.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/EnrolRequestBuilder.kt @@ -40,9 +40,10 @@ internal class EnrolRequestBuilder( actionIdentifier = actionIdentifier, projectId = extractor.getProjectId(), userId = extractor.getUserId().asTokenizableRaw(), + moduleId = extractor.getModuleId().asTokenizableRaw(), biometricDataSource = extractor.getBiometricDataSource(), + subjectAge = extractor.getSubjectAge(), metadata = extractor.getMetadata(), - moduleId = extractor.getModuleId().asTokenizableRaw(), unknownExtras = extractor.getUnknownExtras() ) } diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/IdentifyRequestBuilder.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/IdentifyRequestBuilder.kt index fe13a64870..8c6aaa7d5a 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/IdentifyRequestBuilder.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/IdentifyRequestBuilder.kt @@ -44,6 +44,7 @@ internal class IdentifyRequestBuilder( userId = extractor.getUserId().asTokenizableRaw(), moduleId = extractor.getModuleId().asTokenizableRaw(), biometricDataSource = extractor.getBiometricDataSource(), + subjectAge = extractor.getSubjectAge(), metadata = extractor.getMetadata(), unknownExtras = extractor.getUnknownExtras() ) diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/VerifyRequestBuilder.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/VerifyRequestBuilder.kt index ad3f8e0f35..727b66b2c4 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/VerifyRequestBuilder.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/builders/VerifyRequestBuilder.kt @@ -43,6 +43,7 @@ internal class VerifyRequestBuilder( userId = extractor.getUserId().asTokenizableRaw(), moduleId = extractor.getModuleId().asTokenizableRaw(), biometricDataSource = extractor.getBiometricDataSource(), + subjectAge = extractor.getSubjectAge(), metadata = extractor.getMetadata(), verifyGuid = extractor.getVerifyGuid(), unknownExtras = extractor.getUnknownExtras() diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/extractors/ActionRequestExtractor.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/extractors/ActionRequestExtractor.kt index dd8c9e8f34..17fa7280e7 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/extractors/ActionRequestExtractor.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/request/extractors/ActionRequestExtractor.kt @@ -1,6 +1,7 @@ package com.simprints.feature.clientapi.mappers.request.extractors import android.content.Intent +import com.simprints.core.tools.json.JsonHelper import com.simprints.feature.clientapi.extensions.extractString import com.simprints.libsimprints.Constants @@ -13,7 +14,7 @@ internal abstract class ActionRequestExtractor(private val extras: Map>(getMetadata()) + return parsedMetadata[Constants.SIMPRINTS_SUBJECT_AGE] as? Int + } + protected open fun Intent.extractString(key: String): String = this.getStringExtra(key) ?: "" open fun getUnknownExtras(): Map = extras.filter { it.key.isNotBlank() && !expectedKeys.contains(it.key) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6666ecf353..5e275a66fb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,7 +65,7 @@ protobuf_version = "4.26.1" circleImageView_version = "3.1.0" timber_version = "5.0.1" -libsimprints_version = "2024.1.1" +libsimprints_version = "2024.2.0" simmatcher_version = "1.2.0" roc_wrapper_version = "1.23" nec_version = "1.5.0" diff --git a/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/ActionRequest.kt b/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/ActionRequest.kt index 290908b425..df274b227d 100644 --- a/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/ActionRequest.kt +++ b/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/ActionRequest.kt @@ -25,6 +25,14 @@ sealed class ActionRequest( open val unknownExtras: Map, ) : Serializable { + fun getSubjectAgeIfAvailable(): Int? = + when (this) { + is EnrolActionRequest -> subjectAge + is IdentifyActionRequest -> subjectAge + is VerifyActionRequest ->subjectAge + else -> null + } + @Keep data class EnrolActionRequest( override val actionIdentifier: ActionRequestIdentifier, @@ -32,6 +40,7 @@ sealed class ActionRequest( override val userId: TokenizableString, override val moduleId: TokenizableString, val biometricDataSource: String, + val subjectAge: Int? = null, val metadata: String, override val unknownExtras: Map, ) : ActionRequest(actionIdentifier, projectId, userId, unknownExtras), FlowAction @@ -43,6 +52,7 @@ sealed class ActionRequest( override val userId: TokenizableString, override val moduleId: TokenizableString, val biometricDataSource: String, + val subjectAge: Int? = null, val metadata: String, override val unknownExtras: Map, ) : ActionRequest(actionIdentifier, projectId, userId, unknownExtras), FlowAction @@ -54,6 +64,7 @@ sealed class ActionRequest( override val userId: TokenizableString, override val moduleId: TokenizableString, val biometricDataSource: String, + val subjectAge: Int? = null, val metadata: String, val verifyGuid: String, override val unknownExtras: Map, From dd333351ffc0b4665c250f1839955177341d2d20 Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Tue, 4 Jun 2024 20:48:54 +0300 Subject: [PATCH 2/6] [MS-464] Bind fingerprint capture ViewModels to their fragments instead of the single Activity to allow for capture with two fingerprint SDKs down the line --- .../fingerprint/capture/screen/FingerprintCaptureFragment.kt | 4 ++-- .../capture/views/fingerviewpager/FingerFragment.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt index d0a9882b9d..ae8e100ca8 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt @@ -6,7 +6,7 @@ import android.view.View import androidx.activity.addCallback import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -54,7 +54,7 @@ internal class FingerprintCaptureFragment : Fragment(R.layout.fragment_fingerpri private val args: FingerprintCaptureFragmentArgs by navArgs() private val binding by viewBinding(FragmentFingerprintCaptureBinding::bind) - private val vm: FingerprintCaptureViewModel by activityViewModels() + private val vm: FingerprintCaptureViewModel by viewModels() private lateinit var fingerViewPagerManager: FingerViewPagerManager private var confirmDialog: AlertDialog? = null diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/views/fingerviewpager/FingerFragment.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/views/fingerviewpager/FingerFragment.kt index 3a2b1d602c..b362daacc4 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/views/fingerviewpager/FingerFragment.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/views/fingerviewpager/FingerFragment.kt @@ -6,7 +6,7 @@ import android.widget.LinearLayout import android.widget.ProgressBar import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels import com.simprints.core.domain.fingerprint.IFingerIdentifier import com.simprints.fingerprint.capture.R import com.simprints.fingerprint.capture.databinding.FragmentFingerBinding @@ -30,7 +30,7 @@ import dagger.hilt.android.AndroidEntryPoint internal class FingerFragment : Fragment(R.layout.fragment_finger) { private val binding by viewBinding(FragmentFingerBinding::bind) - private val vm: FingerprintCaptureViewModel by activityViewModels() + private val vm: FingerprintCaptureViewModel by viewModels(ownerProducer = { requireParentFragment() }) private lateinit var fingerId: IFingerIdentifier From e3817e08c023e30f01bc0b2597051ac7652ff4cf Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Tue, 4 Jun 2024 21:10:33 +0300 Subject: [PATCH 3/6] [MS-464] Pass fingerprint SDK to fingerprint capture screen through params --- .../capture/FingerprintCaptureContract.kt | 4 +++- .../capture/FingerprintCaptureParams.kt | 4 +++- .../screen/FingerprintCaptureFragment.kt | 5 +++- .../screen/FingerprintCaptureViewModel.kt | 24 ++++++++++++------- .../biosdk/ResolveBioSdkWrapperUseCase.kt | 11 ++------- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureContract.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureContract.kt index 43f8a331bd..7965860677 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureContract.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureContract.kt @@ -3,6 +3,7 @@ package com.simprints.fingerprint.capture import com.simprints.core.domain.common.FlowType import com.simprints.fingerprint.capture.screen.FingerprintCaptureFragmentArgs import com.simprints.core.domain.fingerprint.IFingerIdentifier +import com.simprints.infra.config.store.models.FingerprintConfiguration object FingerprintCaptureContract { @@ -11,6 +12,7 @@ object FingerprintCaptureContract { fun getArgs( flowType: FlowType, fingers: List, - ) = FingerprintCaptureFragmentArgs(FingerprintCaptureParams(flowType, fingers)).toBundle() + fingerprintSDK: FingerprintConfiguration.BioSdk, + ) = FingerprintCaptureFragmentArgs(FingerprintCaptureParams(flowType, fingers, fingerprintSDK)).toBundle() } diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureParams.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureParams.kt index 498646eaeb..67c5037ba0 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureParams.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/FingerprintCaptureParams.kt @@ -4,11 +4,13 @@ import android.os.Parcelable import androidx.annotation.Keep import com.simprints.core.domain.common.FlowType import com.simprints.core.domain.fingerprint.IFingerIdentifier +import com.simprints.infra.config.store.models.FingerprintConfiguration import kotlinx.parcelize.Parcelize @Keep @Parcelize data class FingerprintCaptureParams( val flowType: FlowType, - val fingerprintsToCapture: List + val fingerprintsToCapture: List, + val fingerprintSDK: FingerprintConfiguration.BioSdk, ) : Parcelable diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt index ae8e100ca8..e81f9d192a 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureFragment.kt @@ -99,7 +99,10 @@ internal class FingerprintCaptureFragment : Fragment(R.layout.fragment_fingerpri vm.launchReconnect.observe(viewLifecycleOwner, LiveDataEventObserver { launchConnection() }) - vm.handleOnViewCreated(args.params.fingerprintsToCapture) + vm.handleOnViewCreated( + args.params.fingerprintsToCapture, + args.params.fingerprintSDK, + ) initUI() } diff --git a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureViewModel.kt b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureViewModel.kt index 939ea1aa6d..d8e57b7fde 100644 --- a/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureViewModel.kt +++ b/fingerprint/capture/src/main/java/com/simprints/fingerprint/capture/screen/FingerprintCaptureViewModel.kt @@ -57,7 +57,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import java.util.UUID import javax.inject.Inject import kotlin.math.min @@ -161,16 +160,18 @@ internal class FingerprintCaptureViewModel @Inject constructor( } - private fun start(fingerprintsToCapture: List) { + private fun start( + fingerprintsToCapture: List, + fingerprintSdk: FingerprintConfiguration.BioSdk + ) { if (!hasStarted) { hasStarted = true runBlocking { - initBioSdk() // Configuration must be initialised when start returns for UI to be initialised correctly, // and since fetching happens on IO thread execution must be suspended until it is available configuration = configManager.getProjectConfiguration().fingerprint!! - bioSdkConfiguration = configuration.bioSdkConfiguration + initBioSdk(fingerprintSdk) } originalFingerprintsToCapture = fingerprintsToCapture @@ -179,10 +180,14 @@ internal class FingerprintCaptureViewModel @Inject constructor( } } - private suspend fun initBioSdk() { + private suspend fun initBioSdk(fingerprintSdk: FingerprintConfiguration.BioSdk) { try { - bioSdkWrapper = resolveBioSdkWrapperUseCase() + bioSdkWrapper = resolveBioSdkWrapperUseCase(fingerprintSdk) bioSdkWrapper.initialize() + bioSdkConfiguration = when (fingerprintSdk) { + FingerprintConfiguration.BioSdk.NEC -> configuration.nec!! + FingerprintConfiguration.BioSdk.SECUGEN_SIM_MATCHER -> configuration.secugenSimMatcher!! + } } catch (e: BioSdkException.BioSdkInitializationException) { Simber.e(e) _invalidLicense.send() @@ -645,13 +650,16 @@ internal class FingerprintCaptureViewModel @Inject constructor( setStartingState(originalFingerprintsToCapture) } - fun handleOnViewCreated(fingerprintsToCapture: List) { + fun handleOnViewCreated( + fingerprintsToCapture: List, + fingerprintSdk: FingerprintConfiguration.BioSdk + ) { updateState { it.copy( isShowingConnectionScreen = false ) } - start(fingerprintsToCapture) + start(fingerprintsToCapture, fingerprintSdk) } fun handleOnResume() { 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 7cfc6eedec..bf18829a21 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 @@ -3,24 +3,19 @@ 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.FingerprintConfiguration -import com.simprints.infra.config.sync.ConfigManager import javax.inject.Inject class ResolveBioSdkWrapperUseCase @Inject constructor( - private val configManager: ConfigManager, @SimprintsSdk private val simprintsWrapper: BioSdkWrapper, @NecSdk private val necWrapper: BioSdkWrapper, ) { private lateinit var bioSdkWrapper: BioSdkWrapper - suspend operator fun invoke(): BioSdkWrapper { + operator fun invoke(fingerprintSdk: FingerprintConfiguration.BioSdk): BioSdkWrapper { if (::bioSdkWrapper.isInitialized) return bioSdkWrapper - // Todo we didn't yet implement the logic to select the SDK based on the configuration - // so we are just using the first allowed SDK for now - // See tickets in SIM-81 for more details bioSdkWrapper = - when (configManager.getProjectConfiguration().fingerprint?.allowedSDKs?.first()) { + when (fingerprintSdk) { FingerprintConfiguration.BioSdk.SECUGEN_SIM_MATCHER -> simprintsWrapper FingerprintConfiguration.BioSdk.NEC -> necWrapper else -> error("Unknown fingerprint configuration") @@ -28,6 +23,4 @@ class ResolveBioSdkWrapperUseCase @Inject constructor( return bioSdkWrapper } - - } From 389475231d80115b7ff202c841e0317e3c36f112 Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Thu, 6 Jun 2024 13:53:33 +0300 Subject: [PATCH 4/6] [MS-464] Pass fingerprint SDK to fingerprint match screen through params --- .../com/simprints/matcher/MatchContract.kt | 3 +++ .../java/com/simprints/matcher/MatchParams.kt | 2 ++ .../matcher/screen/MatchViewModel.kt | 14 +++++------ .../matcher/usecases/FaceMatcherUseCase.kt | 14 +++++------ .../usecases/FingerprintMatcherUseCase.kt | 24 +++++++++++-------- .../matcher/usecases/MatcherUseCase.kt | 12 ++++++---- .../orchestrator/OrchestratorViewModel.kt | 9 ++++++- .../steps/MatchStepStubPayload.kt | 6 ++++- .../biosdk/ResolveBioSdkWrapperUseCase.kt | 19 +++++---------- 9 files changed, 60 insertions(+), 43 deletions(-) diff --git a/feature/matcher/src/main/java/com/simprints/matcher/MatchContract.kt b/feature/matcher/src/main/java/com/simprints/matcher/MatchContract.kt index fd2a7f223d..5fc1990c57 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/MatchContract.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/MatchContract.kt @@ -1,6 +1,7 @@ package com.simprints.matcher import com.simprints.core.domain.common.FlowType +import com.simprints.infra.config.store.models.FingerprintConfiguration import com.simprints.infra.enrolment.records.store.domain.models.BiometricDataSource import com.simprints.infra.enrolment.records.store.domain.models.SubjectQuery import com.simprints.matcher.screen.MatchFragmentArgs @@ -12,12 +13,14 @@ object MatchContract { fun getArgs( fingerprintSamples: List = emptyList(), faceSamples: List = emptyList(), + fingerprintSDK: FingerprintConfiguration.BioSdk? = null, flowType: FlowType, subjectQuery: SubjectQuery, biometricDataSource: BiometricDataSource, ) = MatchFragmentArgs(MatchParams( faceSamples, fingerprintSamples, + fingerprintSDK, flowType, subjectQuery, biometricDataSource, diff --git a/feature/matcher/src/main/java/com/simprints/matcher/MatchParams.kt b/feature/matcher/src/main/java/com/simprints/matcher/MatchParams.kt index 4b639322c2..9ad88642bd 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/MatchParams.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/MatchParams.kt @@ -6,6 +6,7 @@ import com.simprints.core.domain.common.FlowType import com.simprints.infra.enrolment.records.store.domain.models.SubjectQuery import com.simprints.infra.uibase.annotations.ExcludedFromGeneratedTestCoverageReports import com.simprints.core.domain.fingerprint.IFingerIdentifier +import com.simprints.infra.config.store.models.FingerprintConfiguration import com.simprints.infra.enrolment.records.store.domain.models.BiometricDataSource import kotlinx.parcelize.Parcelize @@ -14,6 +15,7 @@ import kotlinx.parcelize.Parcelize data class MatchParams( val probeFaceSamples: List = emptyList(), val probeFingerprintSamples: List = emptyList(), + val fingerprintSDK: FingerprintConfiguration.BioSdk? = null, val flowType: FlowType, val queryForCandidates: SubjectQuery, val biometricDataSource: BiometricDataSource, diff --git a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt index 78d6ecaed9..930c9cd8aa 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/screen/MatchViewModel.kt @@ -47,7 +47,7 @@ internal class MatchViewModel @Inject constructor( else -> fingerprintMatcher } - val (sortedResults, totalCandidates) = matcherUseCase( + val matcherResult = matcherUseCase( params, onLoadingCandidates = { tag -> Simber.tag(tag).i("Loading candidates") @@ -61,19 +61,19 @@ internal class MatchViewModel @Inject constructor( startTime, endTime, params, - totalCandidates, - matcherUseCase.matcherName(), - sortedResults + matcherResult.totalCandidates, + matcherResult.matcherName, + matcherResult.matchResultItems ) - setMatchState(totalCandidates, sortedResults) + setMatchState(matcherResult.totalCandidates, matcherResult.matchResultItems) // wait a bit for the user to see the results delay(matchingEndWaitTimeInMillis) _matchResponse.send(when { - isFaceMatch -> FaceMatchResult(sortedResults) - else -> FingerprintMatchResult(sortedResults) + isFaceMatch -> FaceMatchResult(matcherResult.matchResultItems) + else -> FingerprintMatchResult(matcherResult.matchResultItems) }) } diff --git a/feature/matcher/src/main/java/com/simprints/matcher/usecases/FaceMatcherUseCase.kt b/feature/matcher/src/main/java/com/simprints/matcher/usecases/FaceMatcherUseCase.kt index 1702a77d70..5c1edb4b4b 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/usecases/FaceMatcherUseCase.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/usecases/FaceMatcherUseCase.kt @@ -10,7 +10,7 @@ import com.simprints.infra.facebiosdk.matching.FaceSample import com.simprints.infra.logging.LoggingConstants import com.simprints.matcher.FaceMatchResult import com.simprints.matcher.MatchParams -import com.simprints.matcher.MatchResultItem +import com.simprints.matcher.usecases.MatcherUseCase.MatcherResult import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -25,23 +25,22 @@ internal class FaceMatcherUseCase @Inject constructor( ) : MatcherUseCase { override val crashReportTag = LoggingConstants.CrashReportTag.FACE_MATCHING.name - override suspend fun matcherName ()= faceMatcher.matcherName override suspend operator fun invoke( matchParams: MatchParams, onLoadingCandidates: (tag: String) -> Unit, - ): Pair, Int> = coroutineScope { + ): MatcherResult = coroutineScope { if (matchParams.probeFaceSamples.isEmpty()) { - return@coroutineScope Pair(emptyList(), 0) + return@coroutineScope MatcherResult(emptyList(), 0, faceMatcher.matcherName) } val samples = mapSamples(matchParams.probeFaceSamples) val totalCandidates = enrolmentRecordRepository.count(matchParams.queryForCandidates, dataSource = matchParams.biometricDataSource) if (totalCandidates == 0) { - return@coroutineScope Pair(emptyList(), 0) + return@coroutineScope MatcherResult(emptyList(), 0, faceMatcher.matcherName) } onLoadingCandidates(crashReportTag) - createRanges(totalCandidates) + val resultItems = createRanges(totalCandidates) .map { range -> async(dispatcher) { val batchCandidates = getCandidates(matchParams.queryForCandidates, range, dataSource = matchParams.biometricDataSource) @@ -50,7 +49,8 @@ internal class FaceMatcherUseCase @Inject constructor( } .awaitAll() .reduce { acc, subSet -> acc.addAll(subSet) } - .toList() to totalCandidates + .toList() + MatcherResult(resultItems, totalCandidates, faceMatcher.matcherName) } private fun mapSamples(probes: List) = probes diff --git a/feature/matcher/src/main/java/com/simprints/matcher/usecases/FingerprintMatcherUseCase.kt b/feature/matcher/src/main/java/com/simprints/matcher/usecases/FingerprintMatcherUseCase.kt index ccbba93e06..8c1d6e8d8d 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/usecases/FingerprintMatcherUseCase.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/usecases/FingerprintMatcherUseCase.kt @@ -6,6 +6,7 @@ import com.simprints.core.domain.fingerprint.IFingerIdentifier import com.simprints.fingerprint.infra.basebiosdk.matching.domain.FingerIdentifier import com.simprints.fingerprint.infra.basebiosdk.matching.domain.Fingerprint import com.simprints.fingerprint.infra.basebiosdk.matching.domain.FingerprintIdentity +import com.simprints.fingerprint.infra.biosdk.BioSdkWrapper import com.simprints.fingerprint.infra.biosdk.ResolveBioSdkWrapperUseCase import com.simprints.infra.config.store.models.FingerprintConfiguration.FingerComparisonStrategy.CROSS_FINGER_USING_MEAN_OF_MAX import com.simprints.infra.config.sync.ConfigManager @@ -15,7 +16,7 @@ import com.simprints.infra.enrolment.records.store.domain.models.SubjectQuery import com.simprints.infra.logging.LoggingConstants import com.simprints.matcher.FingerprintMatchResult import com.simprints.matcher.MatchParams -import com.simprints.matcher.MatchResultItem +import com.simprints.matcher.usecases.MatcherUseCase.MatcherResult import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll @@ -31,32 +32,33 @@ internal class FingerprintMatcherUseCase @Inject constructor( ) : MatcherUseCase { override val crashReportTag = LoggingConstants.CrashReportTag.MATCHING.name - override suspend fun matcherName() = resolveBioSdkWrapper().matcherName override suspend operator fun invoke( matchParams: MatchParams, onLoadingCandidates: (tag: String) -> Unit, - ): Pair, Int> = coroutineScope { + ): MatcherResult = coroutineScope { + val bioSdkWrapper = resolveBioSdkWrapper(matchParams.fingerprintSDK!!) + if (matchParams.probeFingerprintSamples.isEmpty()) { - return@coroutineScope Pair(emptyList(), 0) + return@coroutineScope MatcherResult(emptyList(), 0, bioSdkWrapper.matcherName) } val samples = mapSamples(matchParams.probeFingerprintSamples) // Only candidates with supported template format are considered val queryWithSupportedFormat = matchParams.queryForCandidates.copy( - fingerprintSampleFormat = resolveBioSdkWrapper().supportedTemplateFormat + fingerprintSampleFormat = bioSdkWrapper.supportedTemplateFormat ) val totalCandidates = enrolmentRecordRepository.count(queryWithSupportedFormat, dataSource = matchParams.biometricDataSource) if (totalCandidates == 0) { - return@coroutineScope Pair(emptyList(), 0) + return@coroutineScope MatcherResult(emptyList(), 0, bioSdkWrapper.matcherName) } onLoadingCandidates(crashReportTag) - createRanges(totalCandidates) + val resultItems = createRanges(totalCandidates) .map { range -> async(dispatcher) { val batchCandidates = getCandidates(queryWithSupportedFormat, range, matchParams.biometricDataSource) - match(samples, batchCandidates, matchParams.flowType) + match(samples, batchCandidates, matchParams.flowType, bioSdkWrapper) .fold(MatchResultSet()) { acc, item -> acc.add(FingerprintMatchResult.Item(item.id, item.score)) } @@ -64,7 +66,8 @@ internal class FingerprintMatcherUseCase @Inject constructor( } .awaitAll() .reduce { acc, subSet -> acc.addAll(subSet) } - .toList() to totalCandidates + .toList() + MatcherResult(resultItems, totalCandidates, bioSdkWrapper.matcherName) } private fun mapSamples(probes: List) = probes @@ -93,7 +96,8 @@ internal class FingerprintMatcherUseCase @Inject constructor( probes: List, candidates: List, flowType: FlowType, - ) = resolveBioSdkWrapper().match( + bioSdkWrapper: BioSdkWrapper, + ) = bioSdkWrapper.match( FingerprintIdentity("", probes), candidates, isCrossFingerMatchingEnabled(flowType), diff --git a/feature/matcher/src/main/java/com/simprints/matcher/usecases/MatcherUseCase.kt b/feature/matcher/src/main/java/com/simprints/matcher/usecases/MatcherUseCase.kt index 3a69e548d8..3ac20ab2ac 100644 --- a/feature/matcher/src/main/java/com/simprints/matcher/usecases/MatcherUseCase.kt +++ b/feature/matcher/src/main/java/com/simprints/matcher/usecases/MatcherUseCase.kt @@ -6,15 +6,19 @@ import com.simprints.matcher.MatchResultItem internal interface MatcherUseCase { val crashReportTag: String - suspend fun matcherName(): String /** - * Returns a list of [MatchResultItem]s sorted by confidence score in descending order - * and the total number of candidates that were considered. + * Returns a MatcherResult which contains a list of [MatchResultItem]s sorted by confidence score in descending order, + * the total number of candidates that were considered and the name of the matcher that was used */ suspend operator fun invoke( matchParams: MatchParams, onLoadingCandidates: (tag: String) -> Unit = {}, - ): Pair, Int> + ): MatcherResult + data class MatcherResult( + val matchResultItems: List, + val totalCandidates: Int, + val matcherName: String, + ) } diff --git a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/OrchestratorViewModel.kt b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/OrchestratorViewModel.kt index 448d4d6df9..fa83510274 100644 --- a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/OrchestratorViewModel.kt +++ b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/OrchestratorViewModel.kt @@ -27,6 +27,7 @@ import com.simprints.feature.orchestrator.usecases.UpdateDailyActivityUseCase import com.simprints.feature.orchestrator.usecases.response.AppResponseBuilderUseCase import com.simprints.feature.orchestrator.usecases.steps.BuildStepsUseCase import com.simprints.feature.setup.LocationStore +import com.simprints.fingerprint.capture.FingerprintCaptureParams import com.simprints.fingerprint.capture.FingerprintCaptureResult import com.simprints.infra.config.store.models.GeneralConfiguration import com.simprints.infra.config.sync.ConfigManager @@ -169,7 +170,13 @@ internal class OrchestratorViewModel @Inject constructor( } } if (currentStep.id == StepId.FINGERPRINT_CAPTURE && result is FingerprintCaptureResult) { - val matchingStep = steps.firstOrNull { it.id == StepId.FINGERPRINT_MATCHER } + val captureParams = currentStep.payload.getParcelable("params") + // Find the matching step for the same fingerprint SDK as there may be multiple match steps + val matchingStep = steps.firstOrNull { step -> + (step.id == StepId.FINGERPRINT_MATCHER) + && (step.payload.getParcelable(MatchStepStubPayload.STUB_KEY)?.fingerprintSDK + == captureParams?.fingerprintSDK) + } if (matchingStep != null) { val fingerprintSamples = result.results.mapNotNull { it.sample } diff --git a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/steps/MatchStepStubPayload.kt b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/steps/MatchStepStubPayload.kt index 33ae07756f..d122f4502c 100644 --- a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/steps/MatchStepStubPayload.kt +++ b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/steps/MatchStepStubPayload.kt @@ -3,6 +3,7 @@ package com.simprints.feature.orchestrator.steps import android.os.Parcelable import androidx.core.os.bundleOf import com.simprints.core.domain.common.FlowType +import com.simprints.infra.config.store.models.FingerprintConfiguration import com.simprints.infra.enrolment.records.store.domain.models.BiometricDataSource import com.simprints.matcher.MatchContract import com.simprints.matcher.MatchParams @@ -20,6 +21,7 @@ internal data class MatchStepStubPayload( val flowType: FlowType, val subjectQuery: SubjectQuery, val biometricDataSource: BiometricDataSource, + val fingerprintSDK: FingerprintConfiguration.BioSdk?, ) : Parcelable { fun toFaceStepArgs(samples: List) = MatchContract.getArgs( @@ -31,6 +33,7 @@ internal data class MatchStepStubPayload( fun toFingerprintStepArgs(samples: List) = MatchContract.getArgs( fingerprintSamples = samples, + fingerprintSDK = fingerprintSDK, flowType = flowType, subjectQuery = subjectQuery, biometricDataSource = biometricDataSource, @@ -43,6 +46,7 @@ internal data class MatchStepStubPayload( flowType: FlowType, subjectQuery: SubjectQuery, biometricDataSource: BiometricDataSource, - ) = bundleOf(STUB_KEY to MatchStepStubPayload(flowType, subjectQuery, biometricDataSource)) + fingerprintSDK: FingerprintConfiguration.BioSdk? = null, + ) = bundleOf(STUB_KEY to MatchStepStubPayload(flowType, subjectQuery, biometricDataSource, fingerprintSDK)) } } 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 bf18829a21..2da7896cf3 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 @@ -9,18 +9,11 @@ class ResolveBioSdkWrapperUseCase @Inject constructor( @SimprintsSdk private val simprintsWrapper: BioSdkWrapper, @NecSdk private val necWrapper: BioSdkWrapper, ) { - private lateinit var bioSdkWrapper: BioSdkWrapper - operator fun invoke(fingerprintSdk: FingerprintConfiguration.BioSdk): BioSdkWrapper { - if (::bioSdkWrapper.isInitialized) return bioSdkWrapper - - bioSdkWrapper = - when (fingerprintSdk) { - FingerprintConfiguration.BioSdk.SECUGEN_SIM_MATCHER -> simprintsWrapper - FingerprintConfiguration.BioSdk.NEC -> necWrapper - else -> error("Unknown fingerprint configuration") - } - - return bioSdkWrapper - } + operator fun invoke(fingerprintSdk: FingerprintConfiguration.BioSdk): BioSdkWrapper = + when (fingerprintSdk) { + FingerprintConfiguration.BioSdk.SECUGEN_SIM_MATCHER -> simprintsWrapper + FingerprintConfiguration.BioSdk.NEC -> necWrapper + else -> error("Unknown fingerprint configuration") + } } From 34acd9fcd5d815019f93fc0a5311c4672e75d6d2 Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Tue, 18 Jun 2024 18:05:47 +0300 Subject: [PATCH 5/6] MS-515 Add new fields to fingerprint configuration --- .../local/models/FingerprintConfiguration.kt | 16 ++++--- .../store/models/FingerprintConfiguration.kt | 1 + .../store/models/ProjectConfiguration.kt | 14 +++--- .../store/remote/models/ApiAllowedAgeRange.kt | 17 +++++++ .../models/ApiFingerprintConfiguration.kt | 9 ++-- .../src/main/proto/project_config.proto | 2 +- .../infra/config/store/testtools/Models.kt | 45 +++++++++++++++++-- 7 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiAllowedAgeRange.kt diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FingerprintConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FingerprintConfiguration.kt index 839e1106da..d1b296a704 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FingerprintConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FingerprintConfiguration.kt @@ -23,8 +23,8 @@ internal fun FingerprintConfiguration.FingerprintSdkConfiguration.toProto() = .also { if (vero1 != null) it.vero1 = vero1.toProto() if (vero2 != null) it.vero2 = vero2.toProto() - if (allowedAgeRange != null) - it.allowedAgeRange = allowedAgeRange.toProto() + if (allowedAgeRange != null) it.allowedAgeRange = allowedAgeRange.toProto() + if (verificationMatchThreshold != null) it.verificationMatchThreshold = verificationMatchThreshold }.build() @@ -90,7 +90,8 @@ internal fun ProtoFingerprintConfiguration.ProtoFingerprintSdkConfiguration.toDo comparisonStrategyForVerification.toDomain(), if (hasVero1()) vero1.toDomain() else null, if (hasVero2()) vero2.toDomain() else null, - if (hasAllowedAgeRange()) allowedAgeRange.toDomain() else null + if (hasAllowedAgeRange()) allowedAgeRange.toDomain() else null, + if (hasVerificationMatchThreshold()) verificationMatchThreshold else null, ) @@ -112,8 +113,9 @@ internal fun ProtoFingerprintConfiguration.FingerComparisonStrategy.toDomain() = internal fun ProtoAllowedAgeRange.toDomain() = AgeGroup(startInclusive, endExclusive) -internal fun AgeGroup.toProto() = - ProtoAllowedAgeRange.newBuilder().setStartInclusive(startInclusive).let { builder -> - endExclusive?.let { builder.setEndExclusive(it) } - builder.build() +internal fun AgeGroup.toProto() = ProtoAllowedAgeRange.newBuilder() + .also { + it.setStartInclusive(startInclusive) + if (endExclusive != null) it.setEndExclusive(endExclusive) } + .build() diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FingerprintConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FingerprintConfiguration.kt index 2b1666da55..6b978dfb22 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FingerprintConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FingerprintConfiguration.kt @@ -15,6 +15,7 @@ data class FingerprintConfiguration( val vero1: Vero1Configuration? = null, val vero2: Vero2Configuration? = null, val allowedAgeRange: AgeGroup? = null, + val verificationMatchThreshold: Float? = null, ) enum class VeroGeneration { diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt index c4dbb773c9..5ce7ad216f 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt @@ -1,7 +1,5 @@ package com.simprints.infra.config.store.models -import com.simprints.infra.logging.Simber - data class ProjectConfiguration( val projectId: String, val updatedAt: String, @@ -44,10 +42,8 @@ fun ProjectConfiguration.isEventDownSyncAllowed(): Boolean = fun ProjectConfiguration.imagesUploadRequiresUnmeteredConnection(): Boolean = synchronization.up.simprints.imagesRequireUnmeteredConnection -fun ProjectConfiguration.allowedAgeRanges(): List { - return listOf( - //Todo add face roc sdk , - fingerprint?.secugenSimMatcher?.allowedAgeRange, - fingerprint?.nec?.allowedAgeRange - ).mapNotNull { it } -} +fun ProjectConfiguration.allowedAgeRanges(): List = listOf( + //Todo add face roc sdk , + fingerprint?.secugenSimMatcher?.allowedAgeRange, + fingerprint?.nec?.allowedAgeRange +).mapNotNull { it } diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiAllowedAgeRange.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiAllowedAgeRange.kt new file mode 100644 index 0000000000..bbe012fa16 --- /dev/null +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiAllowedAgeRange.kt @@ -0,0 +1,17 @@ +package com.simprints.infra.config.store.remote.models + +import androidx.annotation.Keep +import com.simprints.infra.config.store.models.AgeGroup + +@Keep +data class ApiAllowedAgeRange( + val startInclusive: Int?, + val endExclusive: Int?, +) { + + fun toDomain() = + // When allowedAgeRange is disabled the API returns an empty object + // which is then parsed as {null, null} + if (startInclusive == null && endExclusive == null) null + else AgeGroup(startInclusive ?: 0, endExclusive) +} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFingerprintConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFingerprintConfiguration.kt index 1f95f3f66f..4f619779a7 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFingerprintConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFingerprintConfiguration.kt @@ -27,15 +27,18 @@ internal data class ApiFingerprintConfiguration( val decisionPolicy: ApiDecisionPolicy, val comparisonStrategyForVerification: FingerComparisonStrategy, val vero1: ApiVero1Configuration? = null, - val vero2: ApiVero2Configuration? = null + val vero2: ApiVero2Configuration? = null, + val allowedAgeRange: ApiAllowedAgeRange? = null, + val verificationMatchThreshold: Float? = null, ) { fun toDomain() = FingerprintConfiguration.FingerprintSdkConfiguration( fingersToCapture.map { it.toDomain() }, decisionPolicy.toDomain(), comparisonStrategyForVerification.toDomain(), vero1?.toDomain(), - vero2?.toDomain() - + vero2?.toDomain(), + allowedAgeRange?.toDomain(), + verificationMatchThreshold, ) } diff --git a/infra/config-store/src/main/proto/project_config.proto b/infra/config-store/src/main/proto/project_config.proto index ea7726b06a..9222eee904 100644 --- a/infra/config-store/src/main/proto/project_config.proto +++ b/infra/config-store/src/main/proto/project_config.proto @@ -77,7 +77,7 @@ message ProtoFingerprintConfiguration { optional ProtoVero2Configuration vero_2 = 4; optional ProtoVero1Configuration vero_1 = 5; optional ProtoAllowedAgeRange allowed_age_range = 6; - + optional float verification_match_threshold = 7; } } message ProtoAllowedAgeRange { diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt index 51ece29ca7..1a8da409d0 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt @@ -1,6 +1,7 @@ package com.simprints.infra.config.store.testtools import com.simprints.core.domain.tokenization.asTokenizableEncrypted +import com.simprints.infra.config.store.local.models.ProtoAllowedAgeRange import com.simprints.infra.config.store.local.models.ProtoConsentConfiguration import com.simprints.infra.config.store.local.models.ProtoDecisionPolicy import com.simprints.infra.config.store.local.models.ProtoDeviceConfiguration @@ -17,6 +18,7 @@ import com.simprints.infra.config.store.local.models.ProtoVero2Configuration import com.simprints.infra.config.store.local.models.toProto import com.simprints.infra.config.store.models.* import com.simprints.infra.config.store.remote.models.* +import com.simprints.infra.config.store.models.AgeGroup import com.simprints.infra.config.store.remote.models.ApiConsentConfiguration import com.simprints.infra.config.store.remote.models.ApiDecisionPolicy import com.simprints.infra.config.store.remote.models.ApiFaceConfiguration @@ -98,6 +100,10 @@ internal val protoConsentConfiguration = ProtoConsentConfiguration.newBuilder() ) .build() +internal val apiAllowedAgeRange = ApiAllowedAgeRange(2, 10) +internal val allowedAgeRange = AgeGroup(2, 10) +internal val protoAllowedAgeRange = ProtoAllowedAgeRange.newBuilder().setStartInclusive(2).setEndExclusive(10).build() + internal val apiDecisionPolicy = ApiDecisionPolicy(10, 30, 40) internal val decisionPolicy = DecisionPolicy(10, 30, 40) internal val protoDecisionPolicy = @@ -152,14 +158,45 @@ internal val apiFingerprintConfiguration = ApiFingerprintConfiguration( apiDecisionPolicy, ApiFingerprintConfiguration.FingerComparisonStrategy.SAME_FINGER, ApiVero1Configuration(10), - apiVero2Configuration + apiVero2Configuration, + apiAllowedAgeRange, + 42.0f, ), null, ) -internal val fingerprintConfiguration = apiFingerprintConfiguration.toDomain() +internal val fingerprintConfiguration = FingerprintConfiguration( + allowedScanners = listOf(FingerprintConfiguration.VeroGeneration.VERO_2), + allowedSDKs = listOf(FingerprintConfiguration.BioSdk.SECUGEN_SIM_MATCHER), + displayHandIcons = true, + secugenSimMatcher = FingerprintConfiguration.FingerprintSdkConfiguration( + fingersToCapture = listOf(Finger.LEFT_3RD_FINGER), + decisionPolicy = decisionPolicy, + comparisonStrategyForVerification = FingerprintConfiguration.FingerComparisonStrategy.SAME_FINGER, + vero1 = Vero1Configuration(qualityThreshold = 10), + vero2 = vero2Configuration, + allowedAgeRange = allowedAgeRange, + verificationMatchThreshold = 42.0f, + ), + nec = null, +) -internal val protoFingerprintConfiguration = fingerprintConfiguration.toProto() +internal val protoFingerprintConfiguration = ProtoFingerprintConfiguration.newBuilder() + .addAllowedScanners(ProtoFingerprintConfiguration.VeroGeneration.VERO_2) + .addAllowedSdks(ProtoFingerprintConfiguration.ProtoBioSdk.SECUGEN_SIM_MATCHER) + .setDisplayHandIcons(true) + .setSecugenSimMatcher( + ProtoFingerprintConfiguration.ProtoFingerprintSdkConfiguration.newBuilder() + .addFingersToCapture(ProtoFinger.LEFT_3RD_FINGER) + .setDecisionPolicy(protoDecisionPolicy) + .setComparisonStrategyForVerification(ProtoFingerprintConfiguration.FingerComparisonStrategy.SAME_FINGER) + .setVero1(ProtoVero1Configuration.newBuilder().setQualityThreshold(10).build()) + .setVero2(protoVero2Configuration) + .setAllowedAgeRange(protoAllowedAgeRange) + .setVerificationMatchThreshold(42.0f) + .build() + ) + .build() internal val apiGeneralConfiguration = ApiGeneralConfiguration( listOf(ApiGeneralConfiguration.Modality.FACE), @@ -369,6 +406,6 @@ internal val apiDeviceState = ApiDeviceState( ) internal val deviceState = DeviceState( "deviceId", - false, + false, null ) From 45e30a6b58008925fd490e347a072478c0b2c00f Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Wed, 19 Jun 2024 09:34:16 +0300 Subject: [PATCH 6/6] MS-515 Update face configuration to rankOne object --- .../infra/config/store/ConfigStoreModule.kt | 7 +- .../ProjectConfigFaceBioSdkMigration.kt | 46 ++++++++++++ .../migrations/models/OldProjectConfig.kt | 23 +++--- .../store/local/models/FaceConfiguration.kt | 39 ++++++++-- .../config/store/models/FaceConfiguration.kt | 31 ++++++-- .../store/models/ProjectConfiguration.kt | 7 +- .../remote/models/ApiFaceConfiguration.kt | 40 ++++++++--- .../src/main/proto/project_config.proto | 24 +++++-- .../ProjectConfigSharedPrefsMigrationTest.kt | 37 ++++++---- .../infra/config/store/testtools/Models.kt | 72 ++++++++++++++++--- 10 files changed, 264 insertions(+), 62 deletions(-) create mode 100644 infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigFaceBioSdkMigration.kt diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt index d89c981636..3926a59dac 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/ConfigStoreModule.kt @@ -7,6 +7,7 @@ import androidx.datastore.dataStoreFile import com.simprints.infra.config.store.local.ConfigLocalDataSource import com.simprints.infra.config.store.local.ConfigLocalDataSourceImpl import com.simprints.infra.config.store.local.migrations.DeviceConfigSharedPrefsMigration +import com.simprints.infra.config.store.local.migrations.ProjectConfigFaceBioSdkMigration import com.simprints.infra.config.store.local.migrations.ProjectConfigFingerprintBioSdkMigration import com.simprints.infra.config.store.local.migrations.ProjectConfigQualityThresholdMigration import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPrefsMigration @@ -70,7 +71,8 @@ object DataStoreModule { @ApplicationContext appContext: Context, projectConfigSharedPrefsMigration: ProjectConfigSharedPrefsMigration, projectConfigQualityThresholdMigration: ProjectConfigQualityThresholdMigration, - projectConfigFingerprintBioSdkMigration: ProjectConfigFingerprintBioSdkMigration + projectConfigFingerprintBioSdkMigration: ProjectConfigFingerprintBioSdkMigration, + projectConfigFaceBioSdkMigration: ProjectConfigFaceBioSdkMigration, ): DataStore { return DataStoreFactory.create( serializer = ProjectConfigurationSerializer, @@ -78,7 +80,8 @@ object DataStoreModule { migrations = listOf( projectConfigSharedPrefsMigration, projectConfigQualityThresholdMigration, - projectConfigFingerprintBioSdkMigration + projectConfigFingerprintBioSdkMigration, + projectConfigFaceBioSdkMigration, ) ) } diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigFaceBioSdkMigration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigFaceBioSdkMigration.kt new file mode 100644 index 0000000000..a0f9d42e09 --- /dev/null +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/ProjectConfigFaceBioSdkMigration.kt @@ -0,0 +1,46 @@ +package com.simprints.infra.config.store.local.migrations + +import androidx.datastore.core.DataMigration +import com.simprints.infra.config.store.local.models.ProtoFaceConfiguration +import com.simprints.infra.config.store.local.models.ProtoFaceConfiguration.ProtoFaceSdkConfiguration +import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration +import com.simprints.infra.logging.Simber +import javax.inject.Inject + +/** + * Can be removed once all the devices have been updated to 2024.2.0 + */ +class ProjectConfigFaceBioSdkMigration @Inject constructor() : + DataMigration { + override suspend fun cleanUp() { + Simber.i("Migration of project configuration face bio sdk is done") + } + + override suspend fun shouldMigrate(currentData: ProtoProjectConfiguration): Boolean = + !currentData.face.hasRankOne() + + override suspend fun migrate(currentData: ProtoProjectConfiguration): ProtoProjectConfiguration { + Simber.i("Start migration of project configuration from face to specific bio sdk") + + val face = currentData.face + + val faceProto = face.toBuilder() + // 1 - move generic "face" config into "rankOne" config + .addAllowedSdks(ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE) + .setRankOne( + ProtoFaceSdkConfiguration.newBuilder() + .setNbOfImagesToCapture(face.nbOfImagesToCapture) + .setQualityThreshold(face.qualityThreshold) + .setImageSavingStrategy(face.imageSavingStrategy) + .setDecisionPolicy(face.decisionPolicy) + .build() + ) + // 2 - remove generic config + .clearNbOfImagesToCapture() + .clearQualityThreshold() + .clearImageSavingStrategy() + .clearDecisionPolicy() + + return currentData.toBuilder().setFace(faceProto.build()).build() + } +} diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt index 40b8590f4f..b76e34d4c9 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/migrations/models/OldProjectConfig.kt @@ -81,16 +81,19 @@ internal data class OldProjectConfig( if (faceQualityThreshold == null) null else FaceConfiguration( - nbOfImagesToCapture = faceNbOfFramesCaptured?.toIntOrNull() - ?: DEFAULT_FACE_FRAMES_TO_CAPTURE, - qualityThreshold = faceQualityThreshold.toInt(), - imageSavingStrategy = if (saveFaceImages.toBoolean()) { - FaceConfiguration.ImageSavingStrategy.ONLY_USED_IN_REFERENCE - } else { - FaceConfiguration.ImageSavingStrategy.NEVER - }, - decisionPolicy = faceConfidenceThresholds?.let { parseDecisionPolicy(it) } - ?: DecisionPolicy(0, 0, 0), + allowedSDKs = listOf(FaceConfiguration.BioSdk.RANK_ONE), + rankOne = FaceConfiguration.FaceSdkConfiguration( + nbOfImagesToCapture = faceNbOfFramesCaptured?.toIntOrNull() + ?: DEFAULT_FACE_FRAMES_TO_CAPTURE, + qualityThreshold = faceQualityThreshold.toInt(), + imageSavingStrategy = if (saveFaceImages.toBoolean()) { + FaceConfiguration.ImageSavingStrategy.ONLY_USED_IN_REFERENCE + } else { + FaceConfiguration.ImageSavingStrategy.NEVER + }, + decisionPolicy = faceConfidenceThresholds?.let { parseDecisionPolicy(it) } + ?: DecisionPolicy(0, 0, 0), + ), ) private fun fingerprintConfiguration(): FingerprintConfiguration? = diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FaceConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FaceConfiguration.kt index e1a811f86a..396e54e155 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FaceConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/local/models/FaceConfiguration.kt @@ -5,11 +5,26 @@ import com.simprints.infra.config.store.exceptions.InvalidProtobufEnumException internal fun FaceConfiguration.toProto(): ProtoFaceConfiguration = ProtoFaceConfiguration.newBuilder() + .addAllAllowedSdks(allowedSDKs.map { it.toProto() }) + .also { + if (rankOne != null) it.rankOne = rankOne.toProto() + } + .build() + +internal fun FaceConfiguration.BioSdk.toProto() = when (this) { + FaceConfiguration.BioSdk.RANK_ONE -> ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE +} + +internal fun FaceConfiguration.FaceSdkConfiguration.toProto() = + ProtoFaceConfiguration.ProtoFaceSdkConfiguration.newBuilder() .setNbOfImagesToCapture(nbOfImagesToCapture) .setQualityThreshold(qualityThreshold) .setImageSavingStrategy(imageSavingStrategy.toProto()) .setDecisionPolicy(decisionPolicy.toProto()) - .build() + .also { + if (allowedAgeRange != null) it.allowedAgeRange = allowedAgeRange.toProto() + if (verificationMatchThreshold != null) it.verificationMatchThreshold = verificationMatchThreshold + }.build() internal fun FaceConfiguration.ImageSavingStrategy.toProto(): ProtoFaceConfiguration.ImageSavingStrategy = when (this) { @@ -20,10 +35,24 @@ internal fun FaceConfiguration.ImageSavingStrategy.toProto(): ProtoFaceConfigura internal fun ProtoFaceConfiguration.toDomain(): FaceConfiguration = FaceConfiguration( - nbOfImagesToCapture, - qualityThreshold, - imageSavingStrategy.toDomain(), - decisionPolicy.toDomain(), + allowedSDKs = allowedSdksList.map { it.toDomain() }, + if (hasRankOne()) rankOne.toDomain() else null, + ) + +@Suppress("SameReturnValue") +internal fun ProtoFaceConfiguration.ProtoBioSdk.toDomain() = when (this) { + ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE -> FaceConfiguration.BioSdk.RANK_ONE + ProtoFaceConfiguration.ProtoBioSdk.UNRECOGNIZED -> FaceConfiguration.BioSdk.RANK_ONE +} + +internal fun ProtoFaceConfiguration.ProtoFaceSdkConfiguration.toDomain() = + FaceConfiguration.FaceSdkConfiguration( + nbOfImagesToCapture = nbOfImagesToCapture, + qualityThreshold = qualityThreshold, + imageSavingStrategy = imageSavingStrategy.toDomain(), + decisionPolicy = decisionPolicy.toDomain(), + if (hasAllowedAgeRange()) allowedAgeRange.toDomain() else null, + if (hasVerificationMatchThreshold()) verificationMatchThreshold else null ) internal fun ProtoFaceConfiguration.ImageSavingStrategy.toDomain(): FaceConfiguration.ImageSavingStrategy = diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt index 372ae6c5c1..932af9fa07 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt @@ -1,12 +1,35 @@ package com.simprints.infra.config.store.models data class FaceConfiguration( - val nbOfImagesToCapture: Int, - val qualityThreshold: Int, - val imageSavingStrategy: ImageSavingStrategy, - val decisionPolicy: DecisionPolicy, + val allowedSDKs: List, + val rankOne: FaceSdkConfiguration?, ) { + val nbOfImagesToCapture: Int + get() = rankOne?.nbOfImagesToCapture!! + + val qualityThreshold: Int + get() = rankOne?.qualityThreshold!! + + val imageSavingStrategy: ImageSavingStrategy + get() = rankOne?.imageSavingStrategy!! + + val decisionPolicy: DecisionPolicy + get() = rankOne?.decisionPolicy!! + + data class FaceSdkConfiguration( + val nbOfImagesToCapture: Int, + val qualityThreshold: Int, + val imageSavingStrategy: ImageSavingStrategy, + val decisionPolicy: DecisionPolicy, + val allowedAgeRange: AgeGroup? = null, + val verificationMatchThreshold: Float? = null, + ) + + enum class BioSdk { + RANK_ONE, + } + enum class ImageSavingStrategy { NEVER, ONLY_USED_IN_REFERENCE, diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt index 5ce7ad216f..d29ff0e682 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/ProjectConfiguration.kt @@ -9,8 +9,7 @@ data class ProjectConfiguration( val consent: ConsentConfiguration, val identification: IdentificationConfiguration, val synchronization: SynchronizationConfiguration, -) { -} +) fun ProjectConfiguration.canCoSyncAllData(): Boolean = synchronization.up.coSync.kind == UpSynchronizationConfiguration.UpSynchronizationKind.ALL @@ -43,7 +42,7 @@ fun ProjectConfiguration.imagesUploadRequiresUnmeteredConnection(): Boolean = synchronization.up.simprints.imagesRequireUnmeteredConnection fun ProjectConfiguration.allowedAgeRanges(): List = listOf( - //Todo add face roc sdk , fingerprint?.secugenSimMatcher?.allowedAgeRange, - fingerprint?.nec?.allowedAgeRange + fingerprint?.nec?.allowedAgeRange, + face?.rankOne?.allowedAgeRange, ).mapNotNull { it } diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFaceConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFaceConfiguration.kt index ae8b2b933f..bdcb6969e5 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFaceConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/remote/models/ApiFaceConfiguration.kt @@ -5,20 +5,44 @@ import com.simprints.infra.config.store.models.FaceConfiguration @Keep internal data class ApiFaceConfiguration( - val nbOfImagesToCapture: Int, - val qualityThreshold: Int, - val imageSavingStrategy: ImageSavingStrategy, - val decisionPolicy: ApiDecisionPolicy, + val allowedSDKs: List, + val rankOne: ApiFaceSdkConfiguration, ) { fun toDomain(): FaceConfiguration = FaceConfiguration( - nbOfImagesToCapture, - qualityThreshold, - imageSavingStrategy.toDomain(), - decisionPolicy.toDomain() + allowedSDKs = allowedSDKs.map { it.toDomain() }, + rankOne = rankOne.toDomain() ) + @Keep + data class ApiFaceSdkConfiguration( + val nbOfImagesToCapture: Int, + val qualityThreshold: Int, + val decisionPolicy: ApiDecisionPolicy, + val imageSavingStrategy: ImageSavingStrategy, + val allowedAgeRange: ApiAllowedAgeRange?, + val verificationMatchThreshold: Float?, + ) { + fun toDomain() = FaceConfiguration.FaceSdkConfiguration( + nbOfImagesToCapture = nbOfImagesToCapture, + qualityThreshold = qualityThreshold, + decisionPolicy = decisionPolicy.toDomain(), + imageSavingStrategy = imageSavingStrategy.toDomain(), + allowedAgeRange = allowedAgeRange?.toDomain(), + verificationMatchThreshold = verificationMatchThreshold + ) + } + + @Keep + enum class BioSdk { + RANK_ONE; + + fun toDomain() = when (this) { + RANK_ONE -> FaceConfiguration.BioSdk.RANK_ONE + } + } + @Keep enum class ImageSavingStrategy { NEVER, diff --git a/infra/config-store/src/main/proto/project_config.proto b/infra/config-store/src/main/proto/project_config.proto index 9222eee904..0ee64dd934 100644 --- a/infra/config-store/src/main/proto/project_config.proto +++ b/infra/config-store/src/main/proto/project_config.proto @@ -29,10 +29,26 @@ message ProtoGeneralConfiguration { } message ProtoFaceConfiguration { - int32 nb_of_images_to_capture = 1; - int32 quality_threshold = 2; - ImageSavingStrategy image_saving_strategy = 3; - ProtoDecisionPolicy decision_policy = 4; + int32 nb_of_images_to_capture = 1; // TODO: remove this field after migration to 2024.2.0 + int32 quality_threshold = 2; // TODO: remove this field after migration to 2024.2.0 + ImageSavingStrategy image_saving_strategy = 3; // TODO: remove this field after migration to 2024.2.0 + ProtoDecisionPolicy decision_policy = 4; // TODO: remove this field after migration to 2024.2.0 + + repeated ProtoBioSdk allowed_sdks = 5; + optional ProtoFaceSdkConfiguration rank_one = 6; + + enum ProtoBioSdk { + RANK_ONE = 0; + } + + message ProtoFaceSdkConfiguration{ + int32 nb_of_images_to_capture = 1; + int32 quality_threshold = 2; + ImageSavingStrategy image_saving_strategy = 3; + ProtoDecisionPolicy decision_policy = 4; + optional ProtoAllowedAgeRange allowed_age_range = 5; + optional float verification_match_threshold = 6; + } enum ImageSavingStrategy { NEVER = 0; diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt index 352f05f4be..3e74228922 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/local/migrations/ProjectConfigSharedPrefsMigrationTest.kt @@ -10,6 +10,8 @@ import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPref import com.simprints.infra.config.store.local.migrations.ProjectConfigSharedPrefsMigration.Companion.PROJECT_SETTINGS_JSON_STRING_KEY import com.simprints.infra.config.store.local.migrations.models.OldProjectConfig import com.simprints.infra.config.store.local.models.* +import com.simprints.infra.config.store.local.models.ProtoFaceConfiguration.ProtoFaceSdkConfiguration +import com.simprints.infra.config.store.models.FaceConfiguration import com.simprints.infra.config.store.testtools.protoProjectConfiguration import com.simprints.testtools.common.syntax.assertThrows import io.mockk.* @@ -628,20 +630,26 @@ class ProjectConfigSharedPrefsMigrationTest { "{\"FaceMatchThreshold\":30, \"FaceConfidenceThresholds\":\"{\\\"LOW\\\":\\\"1\\\",\\\"MEDIUM\\\":\\\"20\\\",\\\"HIGH\\\":\\\"100\\\"}\",\"FaceNbOfFramesCaptured\":\"2\",\"FaceQualityThreshold\":\"-1\",\"SaveFaceImages\":\"true\"}" ) private val PROTO_FACE_CONFIGURATION = ProtoFaceConfiguration.newBuilder() - .setNbOfImagesToCapture(2) - .setQualityThreshold(-1) - .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.ONLY_USED_IN_REFERENCE) - .setDecisionPolicy( - ProtoDecisionPolicy.newBuilder().setLow(1).setMedium(20).setHigh(100).build() + .addAllowedSdks(ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE) + .setRankOne( + ProtoFaceSdkConfiguration.newBuilder() + .setNbOfImagesToCapture(2) + .setQualityThreshold(-1) + .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.ONLY_USED_IN_REFERENCE) + .setDecisionPolicy(ProtoDecisionPolicy.newBuilder().setLow(1).setMedium(20).setHigh(100).build()) + .build() ) .build() private val PROTO_FACE_DEFAULT_CONFIGURATION = ProtoFaceConfiguration.newBuilder() - .setNbOfImagesToCapture(2) - .setQualityThreshold(-1) - .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.NEVER) - .setDecisionPolicy( - ProtoDecisionPolicy.newBuilder().setLow(0).setMedium(0).setHigh(0).build() + .addAllowedSdks(ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE) + .setRankOne( + ProtoFaceSdkConfiguration.newBuilder() + .setNbOfImagesToCapture(2) + .setQualityThreshold(-1) + .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.NEVER) + .setDecisionPolicy(ProtoDecisionPolicy.newBuilder().setLow(0).setMedium(0).setHigh(0).build()) + .build() ) .build() @@ -690,14 +698,14 @@ class ProjectConfigSharedPrefsMigrationTest { ) ) .setDecisionPolicy( - ProtoDecisionPolicy.newBuilder().setLow(10).setMedium(40).setHigh(200) - .build() + ProtoDecisionPolicy.newBuilder().setLow(10).setMedium(40).setHigh(200).build() ) .setComparisonStrategyForVerification(ProtoFingerprintConfiguration.FingerComparisonStrategy.SAME_FINGER) .setVero1(ProtoVero1Configuration.newBuilder().setQualityThreshold(60).build()) .setVero2(PROTO_VERO_2_CONFIGURATION) .build() - ).build() + ) + .build() private val PROTO_FINGERPRINT_DEFAULT_CONFIGURATION = ProtoFingerprintConfiguration.newBuilder() @@ -721,6 +729,7 @@ class ProjectConfigSharedPrefsMigrationTest { ProtoVero1Configuration.newBuilder().setQualityThreshold(60).build() ) .build() - ).build() + ) + .build() } } diff --git a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt index 1a8da409d0..169a760ac0 100644 --- a/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt +++ b/infra/config-store/src/test/java/com/simprints/infra/config/store/testtools/Models.kt @@ -7,6 +7,9 @@ import com.simprints.infra.config.store.local.models.ProtoDecisionPolicy import com.simprints.infra.config.store.local.models.ProtoDeviceConfiguration import com.simprints.infra.config.store.local.models.ProtoDownSynchronizationConfiguration import com.simprints.infra.config.store.local.models.ProtoFaceConfiguration +import com.simprints.infra.config.store.local.models.ProtoFaceConfiguration.ProtoFaceSdkConfiguration +import com.simprints.infra.config.store.local.models.ProtoFinger +import com.simprints.infra.config.store.local.models.ProtoFingerprintConfiguration import com.simprints.infra.config.store.local.models.ProtoGeneralConfiguration import com.simprints.infra.config.store.local.models.ProtoIdentificationConfiguration import com.simprints.infra.config.store.local.models.ProtoProject @@ -14,19 +17,39 @@ import com.simprints.infra.config.store.local.models.ProtoProjectConfiguration import com.simprints.infra.config.store.local.models.ProtoSynchronizationConfiguration import com.simprints.infra.config.store.local.models.ProtoUpSyncBatchSizes import com.simprints.infra.config.store.local.models.ProtoUpSynchronizationConfiguration +import com.simprints.infra.config.store.local.models.ProtoVero1Configuration import com.simprints.infra.config.store.local.models.ProtoVero2Configuration -import com.simprints.infra.config.store.local.models.toProto -import com.simprints.infra.config.store.models.* -import com.simprints.infra.config.store.remote.models.* import com.simprints.infra.config.store.models.AgeGroup +import com.simprints.infra.config.store.models.ConsentConfiguration +import com.simprints.infra.config.store.models.DecisionPolicy +import com.simprints.infra.config.store.models.DeviceConfiguration +import com.simprints.infra.config.store.models.DeviceState +import com.simprints.infra.config.store.models.DownSynchronizationConfiguration +import com.simprints.infra.config.store.models.FaceConfiguration +import com.simprints.infra.config.store.models.Finger +import com.simprints.infra.config.store.models.FingerprintConfiguration +import com.simprints.infra.config.store.models.GeneralConfiguration +import com.simprints.infra.config.store.models.IdentificationConfiguration +import com.simprints.infra.config.store.models.Project +import com.simprints.infra.config.store.models.ProjectConfiguration +import com.simprints.infra.config.store.models.ProjectState +import com.simprints.infra.config.store.models.SettingsPasswordConfig +import com.simprints.infra.config.store.models.SynchronizationConfiguration +import com.simprints.infra.config.store.models.TokenKeyType +import com.simprints.infra.config.store.models.UpSynchronizationConfiguration +import com.simprints.infra.config.store.models.Vero1Configuration +import com.simprints.infra.config.store.models.Vero2Configuration +import com.simprints.infra.config.store.remote.models.ApiAllowedAgeRange import com.simprints.infra.config.store.remote.models.ApiConsentConfiguration import com.simprints.infra.config.store.remote.models.ApiDecisionPolicy +import com.simprints.infra.config.store.remote.models.ApiDeviceState import com.simprints.infra.config.store.remote.models.ApiFaceConfiguration import com.simprints.infra.config.store.remote.models.ApiFingerprintConfiguration import com.simprints.infra.config.store.remote.models.ApiGeneralConfiguration import com.simprints.infra.config.store.remote.models.ApiIdentificationConfiguration import com.simprints.infra.config.store.remote.models.ApiProject import com.simprints.infra.config.store.remote.models.ApiProjectConfiguration +import com.simprints.infra.config.store.remote.models.ApiProjectState import com.simprints.infra.config.store.remote.models.ApiSynchronizationConfiguration import com.simprints.infra.config.store.remote.models.ApiVero1Configuration import com.simprints.infra.config.store.remote.models.ApiVero2Configuration @@ -109,15 +132,42 @@ internal val decisionPolicy = DecisionPolicy(10, 30, 40) internal val protoDecisionPolicy = ProtoDecisionPolicy.newBuilder().setLow(10).setMedium(30).setHigh(40).build() -internal val apiFaceConfiguration = - ApiFaceConfiguration(2, -1, ApiFaceConfiguration.ImageSavingStrategy.NEVER, apiDecisionPolicy) -internal val faceConfiguration = - FaceConfiguration(2, -1, FaceConfiguration.ImageSavingStrategy.NEVER, decisionPolicy) +internal val apiFaceConfiguration = ApiFaceConfiguration( + allowedSDKs = listOf(ApiFaceConfiguration.BioSdk.RANK_ONE), + rankOne = ApiFaceConfiguration.ApiFaceSdkConfiguration( + nbOfImagesToCapture = 2, + qualityThreshold = -1, + imageSavingStrategy = ApiFaceConfiguration.ImageSavingStrategy.NEVER, + decisionPolicy = apiDecisionPolicy, + allowedAgeRange = apiAllowedAgeRange, + verificationMatchThreshold = 42f, + ) +) + +internal val faceConfiguration = FaceConfiguration( + allowedSDKs = listOf(FaceConfiguration.BioSdk.RANK_ONE), + rankOne = FaceConfiguration.FaceSdkConfiguration( + nbOfImagesToCapture = 2, + qualityThreshold = -1, + imageSavingStrategy = FaceConfiguration.ImageSavingStrategy.NEVER, + decisionPolicy = decisionPolicy, + allowedAgeRange = allowedAgeRange, + verificationMatchThreshold = 42f, + ), +) + internal val protoFaceConfiguration = ProtoFaceConfiguration.newBuilder() - .setNbOfImagesToCapture(2) - .setQualityThreshold(-1) - .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.NEVER) - .setDecisionPolicy(protoDecisionPolicy) + .addAllowedSdks(ProtoFaceConfiguration.ProtoBioSdk.RANK_ONE) + .setRankOne( + ProtoFaceSdkConfiguration.newBuilder() + .setNbOfImagesToCapture(2) + .setQualityThreshold(-1) + .setImageSavingStrategy(ProtoFaceConfiguration.ImageSavingStrategy.NEVER) + .setDecisionPolicy(protoDecisionPolicy) + .setAllowedAgeRange(protoAllowedAgeRange) + .setVerificationMatchThreshold(42f) + .build() + ) .build() internal val apiVero2Configuration = ApiVero2Configuration(