diff --git a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/ConsentViewModel.kt b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/ConsentViewModel.kt index 8f8606c54c..0affc90d14 100644 --- a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/ConsentViewModel.kt +++ b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/ConsentViewModel.kt @@ -82,20 +82,23 @@ internal class ConsentViewModel @Inject constructor( selectedTabIndex: Int, ): ConsentViewState { val allowParentalConsent = projectConfig.consent.allowParentalConsent + val isMultiFactorIdEnabled = projectConfig.multifactorId?.allowedExternalCredentials?.isNotEmpty() ?: false return ConsentViewState( showLogo = projectConfig.consent.displaySimprintsLogo, showParentalConsent = allowParentalConsent, consentTextBuilder = GeneralConsentTextHelper( - projectConfig.consent, - projectConfig.general.modalities, - consentType, + config = projectConfig.consent, + modalities = projectConfig.general.modalities, + consentType = consentType, + isMultiFactorIdEnabled = isMultiFactorIdEnabled, ), parentalTextBuilder = if (allowParentalConsent) { ParentalConsentTextHelper( - projectConfig.consent, - projectConfig.general.modalities, - consentType, + config = projectConfig.consent, + modalities = projectConfig.general.modalities, + consentType = consentType, + isMultiFactorIdEnabled = isMultiFactorIdEnabled, ) } else { null diff --git a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelper.kt b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelper.kt index 6fcb535638..c8e234d80e 100644 --- a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelper.kt +++ b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelper.kt @@ -10,17 +10,21 @@ internal data class GeneralConsentTextHelper( private val config: ConsentConfiguration, private val modalities: List, private val consentType: ConsentType, + private val isMultiFactorIdEnabled: Boolean, ) { // TODO All the `getString(id).format(arg,arg)` calls should be `getString(id,arg,arg)` one strings are fixed - // First argument in consent text should always be program name, second is modality specific access/use case text fun assembleText(context: Context) = StringBuilder() .apply { val modalityUseCase = getModalitySpecificUseCaseText(context, modalities) - val modalityAccess = getModalitySpecificAccessText(context, modalities) + val modalityAccess = + getModalitySpecificAccessText(context, modalities) + getMultiFactorIdAccessText(context, isMultiFactorIdEnabled) - filterAppRequestForConsent(context, consentType, config, modalityUseCase) - filterForDataSharingOptions(context, config, modalityUseCase, modalityAccess) + val requestModalityUseCase = modalityUseCase + getMultiFactorIdUseCaseText(context, isMultiFactorIdEnabled) + val dataSharingModalityUseCase = modalityUseCase + getMultiFactorIdSharingText(context, isMultiFactorIdEnabled) + + filterAppRequestForConsent(context, consentType, config, requestModalityUseCase) + filterForDataSharingOptions(context, config, dataSharingModalityUseCase, modalityAccess) }.toString() private fun StringBuilder.filterAppRequestForConsent( @@ -134,4 +138,42 @@ internal data class GeneralConsentTextHelper( Modality.FACE -> context.getString(R.string.consent_biometrics_access_face) Modality.FINGERPRINT -> context.getString(R.string.consent_biometrics_access_fingerprint) } + + private fun getMultiFactorIdUseCaseText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_biometric_concat_modalities), + context.getString(R.string.consent_credentials_general), + ).joinToString(separator = " ") + } else { + "" + } + + private fun getMultiFactorIdAccessText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_credentials_access), + ).joinToString(separator = " ") + } else { + "" + } + + private fun getMultiFactorIdSharingText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_biometric_concat_modalities), + context.getString(R.string.consent_credentials_your_id), + ).joinToString(separator = " ") + } else { + "" + } } diff --git a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelper.kt b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelper.kt index bf73ec7eb4..66ae44a2f7 100644 --- a/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelper.kt +++ b/feature/consent/src/main/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelper.kt @@ -10,17 +10,20 @@ internal data class ParentalConsentTextHelper( private val config: ConsentConfiguration, private val modalities: List, private val consentType: ConsentType, + private val isMultiFactorIdEnabled: Boolean, ) { // TODO All the `getString(id).format(arg,arg)` calls should be `getString(id,arg,arg)` one strings are fixed - // First argument in consent text should always be program name, second is modality specific access/use case text fun assembleText(context: Context): String = StringBuilder() .apply { val modalityUseCase = getModalitySpecificUseCaseText(context, modalities) - val modalityAccess = getModalitySpecificAccessText(context, modalities) + val modalityAccess = + getModalitySpecificAccessText(context, modalities) + getMultiFactorIdAccessText(context, isMultiFactorIdEnabled) - filterAppRequestForParentalConsent(context, consentType, config, modalityUseCase) - extractDataSharingOptions(context, config, modalityUseCase, modalityAccess) + val requestModalityUseCase = modalityUseCase + getMultiFactorIdUseCaseText(context, isMultiFactorIdEnabled) + val dataSharingModalityUseCase = modalityUseCase + getMultiFactorIdSharingText(context, isMultiFactorIdEnabled) + filterAppRequestForParentalConsent(context, consentType, config, requestModalityUseCase) + extractDataSharingOptions(context, config, dataSharingModalityUseCase, modalityAccess) }.toString() private fun StringBuilder.filterAppRequestForParentalConsent( @@ -136,4 +139,42 @@ internal data class ParentalConsentTextHelper( Modality.FINGERPRINT -> context.getString(R.string.consent_biometrics_access_fingerprint) else -> "" } + + private fun getMultiFactorIdAccessText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_credentials_parental_access), + ).joinToString(separator = " ") + } else { + "" + } + + private fun getMultiFactorIdUseCaseText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_biometric_concat_modalities), + context.getString(R.string.consent_credentials_parental_general), + ).joinToString(separator = " ") + } else { + "" + } + + private fun getMultiFactorIdSharingText( + context: Context, + isMultiFactorIdEnabled: Boolean, + ): String = if (isMultiFactorIdEnabled) { + listOf( + ",", + context.getString(R.string.consent_biometric_concat_modalities), + context.getString(R.string.consent_credentials_parental_your_id), + ).joinToString(separator = " ") + } else { + "" + } } diff --git a/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelperTest.kt b/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelperTest.kt index 985d9c4087..cda8dba7b1 100644 --- a/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelperTest.kt +++ b/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/GeneralConsentTextHelperTest.kt @@ -40,6 +40,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -63,6 +64,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -86,6 +88,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -109,6 +112,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -132,6 +136,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.VERIFY, + false, ).assembleText(context) val expectedString = context @@ -155,6 +160,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -178,6 +184,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -201,6 +208,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -225,6 +233,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -249,6 +258,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -273,6 +283,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -296,6 +307,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -318,6 +330,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -340,6 +353,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -362,6 +376,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -384,6 +399,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -407,6 +423,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -429,6 +446,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(generalConsentText).doesNotContainMatch("\\.\\w") @@ -448,6 +466,7 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(generalConsentText).doesNotContainMatch("^\\s.*") @@ -467,11 +486,84 @@ class GeneralConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(generalConsentText).doesNotContain(" ") } + @Test + fun `should add multi-factor ID use case text when isMultiFactorIdEnabled is true`() { + val generalConsentText = GeneralConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = false, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.ENROL, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + val expectedText = String.format( + ", %s %s", + context.getString(R.string.consent_biometric_concat_modalities), + context.getString(R.string.consent_credentials_general), + ) + + assertThat(generalConsentText).contains(expectedText) + } + + @Test + fun `should add multi-factor ID sharing text when isMultiFactorIdEnabled is true`() { + val generalConsentText = GeneralConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = true, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.IDENTIFY, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + // Just check for the key identifying phrase from the credentials text + assertThat(generalConsentText).contains("national ID document or other external credentials") + } + + @Test + fun `should add multi-factor ID access text when isMultiFactorIdEnabled is true`() { + val generalConsentText = GeneralConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = false, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.IDENTIFY, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + val expectedText = String.format( + ", %s", + context.getString(R.string.consent_credentials_access), + ) + + assertThat(generalConsentText).contains(expectedText) + } + private fun configWithPrompt(prompt: ConsentConfiguration.ConsentPromptConfiguration) = ConsentConfiguration( programName = PROGRAM_NAME, organizationName = ORGANIZATION_NAME, diff --git a/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelperTest.kt b/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelperTest.kt index 7fe9694c79..542eae823a 100644 --- a/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelperTest.kt +++ b/feature/consent/src/test/java/com/simprints/feature/consent/screens/consent/helpers/ParentalConsentTextHelperTest.kt @@ -40,6 +40,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -63,6 +64,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -86,6 +88,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -109,6 +112,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.ENROL, + false, ).assembleText(context) val expectedString = context @@ -132,6 +136,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.VERIFY, + false, ).assembleText(context) val expectedString = context @@ -155,6 +160,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -178,6 +184,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -201,6 +208,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -225,6 +233,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -249,6 +258,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT, GeneralConfiguration.Modality.FACE), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -273,6 +283,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -296,6 +307,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -318,6 +330,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -340,6 +353,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -362,6 +376,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -384,6 +399,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -407,6 +423,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) val expectedString = context @@ -429,6 +446,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(parentalConsentText).doesNotContainMatch("\\.\\w") @@ -448,6 +466,7 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(parentalConsentText).doesNotContainMatch("^\\s.*") @@ -467,11 +486,72 @@ class ParentalConsentTextHelperTest { ), listOf(GeneralConfiguration.Modality.FINGERPRINT), ConsentType.IDENTIFY, + false, ).assembleText(context) assertThat(parentalConsentText).doesNotContain(" ") } + @Test + fun `should add multi-factor ID use case text when isMultiFactorIdEnabled is true`() { + val parentalConsentText = ParentalConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = false, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.ENROL, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + assertThat(parentalConsentText).contains(context.getString(R.string.consent_credentials_parental_general)) + } + + @Test + fun `should add multi-factor ID access text when isMultiFactorIdEnabled is true`() { + val parentalConsentText = ParentalConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = false, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.IDENTIFY, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + assertThat(parentalConsentText).contains(context.getString(R.string.consent_credentials_parental_access)) + } + + @Test + fun `should add multi-factor ID sharing text when isMultiFactorIdEnabled is true`() { + val parentalConsentText = ParentalConsentTextHelper( + configWithPrompt( + ConsentConfiguration.ConsentPromptConfiguration( + enrolmentVariant = ConsentConfiguration.ConsentEnrolmentVariant.STANDARD, + dataSharedWithPartner = true, + dataUsedForRAndD = false, + privacyRights = false, + confirmation = false, + ), + ), + listOf(GeneralConfiguration.Modality.FINGERPRINT), + ConsentType.IDENTIFY, + isMultiFactorIdEnabled = true, + ).assembleText(context) + + assertThat(parentalConsentText).contains("child's national ID document or other external credentials") + } + private fun configWithPrompt(prompt: ConsentConfiguration.ConsentPromptConfiguration) = ConsentConfiguration( programName = PROGRAM_NAME, organizationName = ORGANIZATION_NAME, diff --git a/infra/resources/src/main/res/values/strings.xml b/infra/resources/src/main/res/values/strings.xml index 478e2ff150..b84eeb8975 100644 --- a/infra/resources/src/main/res/values/strings.xml +++ b/infra/resources/src/main/res/values/strings.xml @@ -29,9 +29,15 @@ take photographs of your face fingerprint information photographs + scan your national ID document or other external credentials with their unique number(s) + national ID details + capture your national ID or other external credential information fingerprint information, photographs use your child\'s fingerprints take photographs of your child\'s face + scan your child\'s national ID document or other external credentials with their unique number(s) + child\'s national ID details + capture your child\'s national ID or other external credential information and Decline Accept