diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index 5d27f28f..55822299 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -56,7 +56,7 @@ class AndroidLibraryConventionPlugin : Plugin { val credentialOfferScheme = "openid-credential-offer" val credentialOfferHost = "*" - val openId4VciAuthorizationScheme = "eudi-issuance" + val openId4VciAuthorizationScheme = "eu.europa.ec.euidi" val openId4VciAuthorizationHost = "authorization" val storedVersion = getProperty( diff --git a/common-feature/src/main/java/eu/europa/ec/commonfeature/model/DocumentTypeUi.kt b/common-feature/src/main/java/eu/europa/ec/commonfeature/model/DocumentTypeUi.kt index e9cb9b5c..7bcafb01 100644 --- a/common-feature/src/main/java/eu/europa/ec/commonfeature/model/DocumentTypeUi.kt +++ b/common-feature/src/main/java/eu/europa/ec/commonfeature/model/DocumentTypeUi.kt @@ -36,6 +36,7 @@ fun DocumentIdentifier.toUiName(resourceProvider: ResourceProvider): String { return when (this) { is DocumentIdentifier.PID -> resourceProvider.getString(R.string.pid) is DocumentIdentifier.MDL -> resourceProvider.getString(R.string.mdl) + is DocumentIdentifier.AGE -> resourceProvider.getString(R.string.age_verification) is DocumentIdentifier.SAMPLE -> resourceProvider.getString(R.string.load_sample_data) is DocumentIdentifier.OTHER -> docType } diff --git a/common-feature/src/main/java/eu/europa/ec/commonfeature/util/TestsData.kt b/common-feature/src/main/java/eu/europa/ec/commonfeature/util/TestsData.kt index 198bde16..9552d889 100644 --- a/common-feature/src/main/java/eu/europa/ec/commonfeature/util/TestsData.kt +++ b/common-feature/src/main/java/eu/europa/ec/commonfeature/util/TestsData.kt @@ -60,10 +60,12 @@ object TestsData { const val mockedMdlDocName = "mDL" const val mockedPidId = "000001" const val mockedMdlId = "000002" + const val mockedAgeVerificationId = "000003" const val mockedUserFirstName = "JAN" const val mockedUserBase64Portrait = "SE" const val mockedDocUiNamePid = "National ID" const val mockedDocUiNameMdl = "Driving License" + const val mockedDocUiNameAge = "Age Verification" const val mockedDocUiNameSampleData = "Load Sample Documents" const val mockedNoUserFistNameFound = "" const val mockedNoUserBase64PortraitFound = "" @@ -78,6 +80,8 @@ object TestsData { const val mockedPidDocType = "eu.europa.ec.eudiw.pid.1" const val mockedPidCodeName = "eu.europa.ec.eudiw.pid.1" const val mockedMdlDocType = "org.iso.18013.5.1.mDL" + const val mockedAgeVerificationDocType = "eu.europa.ec.eudiw.pseudonym.age_over_18.1" + const val mockedAgeVerificationCodeName = "eu.europa.ec.eudiw.pseudonym.age_over_18.1" const val mockedMdlCodeName = "org.iso.18013.5.1" val mockedValidReaderAuth = ReaderAuth( @@ -174,6 +178,25 @@ object TestsData { readerAuth = mockedValidReaderAuth ) + val mockedAgeVerificationWithBasicFieldsDocRequest = DocRequest( + docType = mockedAgeVerificationDocType, + requestItems = listOf( + DocItem( + namespace = mockedAgeVerificationCodeName, + elementIdentifier = "age_over_18" + ), + DocItem( + namespace = mockedAgeVerificationCodeName, + elementIdentifier = "expiry_date" + ), + DocItem( + namespace = mockedAgeVerificationCodeName, + elementIdentifier = "issuing_country", + ) + ), + readerAuth = mockedValidReaderAuth + ) + val mockedValidPidWithBasicFieldsRequestDocument = RequestDocument( documentId = mockedPidId, docType = mockedPidDocType, @@ -364,6 +387,13 @@ object TestsData { available = true ) + val mockedAgeOptionItemUi = DocumentOptionItemUi( + text = mockedDocUiNameAge, + icon = AppIcons.Id, + type = DocumentIdentifier.AGE, + available = true + ) + val mockedSampleDataOptionItemUi = DocumentOptionItemUi( text = mockedDocUiNameSampleData, icon = AppIcons.Id, @@ -497,6 +527,12 @@ object TestsData { value = testFieldUi.value, ) + is DocumentIdentifier.AGE -> mockCreateOptionalFieldForAgeVerification( + docId = transformedRequestDataUi.documentId, + elementIdentifier = testFieldUi.elementIdentifier, + value = testFieldUi.value, + ) + is DocumentIdentifier.SAMPLE, is DocumentIdentifier.OTHER -> throw NotSupportedDocumentTypeException } @@ -572,6 +608,25 @@ object TestsData { ) } + private fun mockCreateOptionalFieldForAgeVerification( + docId: String, + elementIdentifier: String, + value: String, + checked: Boolean = true, + enabled: Boolean = true, + ): RequestDataUi.OptionalField { + val uniqueId = mockedAgeVerificationDocType + elementIdentifier + docId + return mockCreateOptionalField( + documentIdentifierUi = DocumentIdentifier.MDL, + uniqueId = uniqueId, + elementIdentifier = elementIdentifier, + value = value, + checked = checked, + enabled = enabled, + event = Event.UserIdentificationClicked(itemId = uniqueId) + ) + } + private fun mockCreateOptionalField( documentIdentifierUi: DocumentIdentifier, uniqueId: String, @@ -625,6 +680,13 @@ object TestsData { docRequest = mockedMdlWithBasicFieldsDocRequest } + is DocumentIdentifier.AGE -> { + namespace = mockedAgeVerificationCodeName + docId = mockedAgeVerificationId + docType = mockedAgeVerificationDocType + docRequest = mockedAgeVerificationWithBasicFieldsDocRequest + } + is DocumentIdentifier.SAMPLE, is DocumentIdentifier.OTHER -> throw NotSupportedDocumentTypeException } diff --git a/core-logic/src/main/java/eu/europa/ec/corelogic/model/DocumentIdentifier.kt b/core-logic/src/main/java/eu/europa/ec/corelogic/model/DocumentIdentifier.kt index 1899fc97..76be482d 100644 --- a/core-logic/src/main/java/eu/europa/ec/corelogic/model/DocumentIdentifier.kt +++ b/core-logic/src/main/java/eu/europa/ec/corelogic/model/DocumentIdentifier.kt @@ -41,6 +41,13 @@ sealed interface DocumentIdentifier { get() = "load_sample_documents" } + data object AGE : DocumentIdentifier { + override val nameSpace: String + get() = "eu.europa.ec.eudiw.pseudonym.age_over_18.1" + override val docType: String + get() = "eu.europa.ec.eudiw.pseudonym.age_over_18.1" + } + data class OTHER( override val nameSpace: String, override val docType: String, @@ -49,7 +56,7 @@ sealed interface DocumentIdentifier { fun DocumentIdentifier.isSupported(): Boolean { return when (this) { - is DocumentIdentifier.PID, DocumentIdentifier.MDL -> true + is DocumentIdentifier.PID, DocumentIdentifier.MDL, DocumentIdentifier.AGE -> true is DocumentIdentifier.SAMPLE, is DocumentIdentifier.OTHER -> false } } @@ -58,6 +65,7 @@ fun String.toDocumentIdentifier(): DocumentIdentifier = when (this) { "eu.europa.ec.eudiw.pid.1" -> DocumentIdentifier.PID "org.iso.18013.5.1.mDL" -> DocumentIdentifier.MDL "load_sample_documents" -> DocumentIdentifier.SAMPLE + "eu.europa.ec.eudiw.pseudonym.age_over_18.1" -> DocumentIdentifier.AGE else -> DocumentIdentifier.OTHER( nameSpace = this, docType = this diff --git a/issuance-feature/src/main/java/eu/europa/ec/issuancefeature/interactor/document/AddDocumentInteractor.kt b/issuance-feature/src/main/java/eu/europa/ec/issuancefeature/interactor/document/AddDocumentInteractor.kt index 1882c1f5..804cfef6 100644 --- a/issuance-feature/src/main/java/eu/europa/ec/issuancefeature/interactor/document/AddDocumentInteractor.kt +++ b/issuance-feature/src/main/java/eu/europa/ec/issuancefeature/interactor/document/AddDocumentInteractor.kt @@ -80,7 +80,13 @@ class AddDocumentInteractorImpl( text = DocumentIdentifier.MDL.toUiName(resourceProvider), icon = AppIcons.Id, type = DocumentIdentifier.MDL, - available = canCreateMdl(flowType) + available = canCreateExtraDocument(flowType) + ), + DocumentOptionItemUi( + text = DocumentIdentifier.AGE.toUiName(resourceProvider), + icon = AppIcons.Id, + type = DocumentIdentifier.AGE, + available = canCreateExtraDocument(flowType) ) ) if (flowType == IssuanceFlowUiConfig.NO_DOCUMENT) { @@ -147,6 +153,6 @@ class AddDocumentInteractorImpl( } } - private fun canCreateMdl(flowType: IssuanceFlowUiConfig): Boolean = + private fun canCreateExtraDocument(flowType: IssuanceFlowUiConfig): Boolean = flowType != IssuanceFlowUiConfig.NO_DOCUMENT } \ No newline at end of file diff --git a/issuance-feature/src/test/java/eu/europa/ec/issuancefeature/interactor/document/TestAddDocumentInteractor.kt b/issuance-feature/src/test/java/eu/europa/ec/issuancefeature/interactor/document/TestAddDocumentInteractor.kt index e21704cf..d5794a41 100644 --- a/issuance-feature/src/test/java/eu/europa/ec/issuancefeature/interactor/document/TestAddDocumentInteractor.kt +++ b/issuance-feature/src/test/java/eu/europa/ec/issuancefeature/interactor/document/TestAddDocumentInteractor.kt @@ -22,6 +22,7 @@ import eu.europa.ec.authenticationlogic.controller.authentication.DeviceAuthenti import eu.europa.ec.authenticationlogic.model.BiometricCrypto import eu.europa.ec.commonfeature.config.IssuanceFlowUiConfig import eu.europa.ec.commonfeature.interactor.DeviceAuthenticationInteractor +import eu.europa.ec.commonfeature.util.TestsData.mockedAgeOptionItemUi import eu.europa.ec.commonfeature.util.TestsData.mockedMdlOptionItemUi import eu.europa.ec.commonfeature.util.TestsData.mockedPidId import eu.europa.ec.commonfeature.util.TestsData.mockedPidOptionItemUi @@ -128,6 +129,9 @@ class TestAddDocumentInteractor { mockedMdlOptionItemUi.copy( available = false ), + mockedAgeOptionItemUi.copy( + available = false + ), mockedSampleDataOptionItemUi ) ), @@ -160,7 +164,8 @@ class TestAddDocumentInteractor { AddDocumentInteractorPartialState.Success( options = listOf( mockedPidOptionItemUi, - mockedMdlOptionItemUi + mockedMdlOptionItemUi, + mockedAgeOptionItemUi ) ), awaitItem() diff --git a/resources-logic/src/main/res/values/strings.xml b/resources-logic/src/main/res/values/strings.xml index 38aac656..e190a194 100644 --- a/resources-logic/src/main/res/values/strings.xml +++ b/resources-logic/src/main/res/values/strings.xml @@ -63,6 +63,7 @@ National ID Driving License + Age Verification Load Sample Documents @@ -166,6 +167,7 @@ Shown above Vehicle category code + User Pseudonym yes no diff --git a/test-feature/src/main/java/eu/europa/ec/testfeature/Utils.kt b/test-feature/src/main/java/eu/europa/ec/testfeature/Utils.kt index 3718a563..084009e8 100644 --- a/test-feature/src/main/java/eu/europa/ec/testfeature/Utils.kt +++ b/test-feature/src/main/java/eu/europa/ec/testfeature/Utils.kt @@ -24,6 +24,7 @@ import org.mockito.kotlin.whenever private const val mockedDocUiNamePid = "National ID" private const val mockedDocUiNameMdl = "Driving License" +private const val mockedDocUiNameAgeVerification = "Age Verification" private const val mockedDocUiNameSampleData = "Load Sample Documents" @VisibleForTesting(otherwise = VisibleForTesting.NONE) @@ -41,6 +42,9 @@ object MockResourceProviderForStringCalls { whenever(resourceProvider.getString(R.string.load_sample_data)) .thenReturn(mockedDocUiNameSampleData) + + whenever(resourceProvider.getString(R.string.age_verification)) + .thenReturn(mockedDocUiNameAgeVerification) } /**