From 24258d0bd876e0e5431f5a16c48d1c1e0ed6f9db Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Wed, 2 Oct 2024 06:52:11 +1000 Subject: [PATCH] Add icons to the registered document types. Also show these icons in the consent prompt, if available. Also use a smaller font in the consent dialog since some of the data element names won't fit. Test: Manually tested. Signed-off-by: David Zeuthen --- .../android/identity/appsupport/ui/Icon.kt | 93 +++++++++++++++++++ .../documenttype/knowntypes/DrivingLicense.kt | 68 +++++++++++++- .../documenttype/knowntypes/EUPersonalID.kt | 30 ++++++ .../documenttype/knowntypes/PhotoID.kt | 63 +++++++++++++ .../documenttype/DocumentAttribute.kt | 4 +- .../identity/documenttype/DocumentType.kt | 18 +++- .../com/android/identity/documenttype/Icon.kt | 29 ++++++ .../identity/documenttype/MdocDocumentType.kt | 3 + .../identity/documenttype/MdocNamespace.kt | 4 +- .../identity/documenttype/VcDocumentType.kt | 6 +- .../prompt/consent/ConsentPromptEntryField.kt | 12 ++- 11 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 identity-appsupport/src/commonMain/kotlin/com/android/identity/appsupport/ui/Icon.kt create mode 100644 identity/src/commonMain/kotlin/com/android/identity/documenttype/Icon.kt diff --git a/identity-appsupport/src/commonMain/kotlin/com/android/identity/appsupport/ui/Icon.kt b/identity-appsupport/src/commonMain/kotlin/com/android/identity/appsupport/ui/Icon.kt new file mode 100644 index 000000000..ab46d6822 --- /dev/null +++ b/identity-appsupport/src/commonMain/kotlin/com/android/identity/appsupport/ui/Icon.kt @@ -0,0 +1,93 @@ +package com.android.identity.appsupport.ui + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBalance +import androidx.compose.material.icons.filled.AccountBox +import androidx.compose.material.icons.filled.AirportShuttle +import androidx.compose.material.icons.filled.CalendarToday +import androidx.compose.material.icons.filled.DateRange +import androidx.compose.material.icons.filled.DirectionsCar +import androidx.compose.material.icons.filled.Draw +import androidx.compose.material.icons.filled.Emergency +import androidx.compose.material.icons.filled.Face +import androidx.compose.material.icons.filled.Fingerprint +import androidx.compose.material.icons.filled.Language +import androidx.compose.material.icons.filled.MilitaryTech +import androidx.compose.material.icons.filled.Numbers +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.Place +import androidx.compose.material.icons.filled.Stars +import androidx.compose.material.icons.filled.Today +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.outlined.AccountBalance +import androidx.compose.material.icons.outlined.AccountBox +import androidx.compose.material.icons.outlined.AirportShuttle +import androidx.compose.material.icons.outlined.CalendarToday +import androidx.compose.material.icons.outlined.DateRange +import androidx.compose.material.icons.outlined.DirectionsCar +import androidx.compose.material.icons.outlined.Draw +import androidx.compose.material.icons.outlined.Emergency +import androidx.compose.material.icons.outlined.Face +import androidx.compose.material.icons.outlined.Fingerprint +import androidx.compose.material.icons.outlined.Language +import androidx.compose.material.icons.outlined.MilitaryTech +import androidx.compose.material.icons.outlined.Numbers +import androidx.compose.material.icons.outlined.Person +import androidx.compose.material.icons.outlined.Place +import androidx.compose.material.icons.outlined.Stars +import androidx.compose.material.icons.outlined.Today +import androidx.compose.material.icons.outlined.Visibility +import androidx.compose.ui.graphics.vector.ImageVector +import com.android.identity.documenttype.Icon + +/** + * Extension function to get an [ImageVector] for an icon. + */ +fun Icon.getDefaultImageVector(): ImageVector { + return when (this) { + Icon.PERSON -> Icons.Default.Person + Icon.TODAY -> Icons.Default.Today + Icon.DATE_RANGE -> Icons.Default.DateRange + Icon.CALENDAR_CLOCK -> Icons.Default.CalendarToday // TODO: CalendarClock not available + Icon.ACCOUNT_BALANCE -> Icons.Default.AccountBalance + Icon.NUMBERS -> Icons.Default.Numbers + Icon.ACCOUNT_BOX -> Icons.Default.AccountBox + Icon.DIRECTIONS_CAR -> Icons.Default.DirectionsCar + Icon.LANGUAGE -> Icons.Default.Language + Icon.EMERGENCY -> Icons.Default.Emergency + Icon.PLACE -> Icons.Default.Place + Icon.SIGNATURE -> Icons.Default.Draw // TODO: Signature not available + Icon.MILITARY_TECH -> Icons.Default.MilitaryTech + Icon.STARS -> Icons.Default.Stars + Icon.FACE -> Icons.Default.Face + Icon.FINGERPRINT -> Icons.Default.Fingerprint + Icon.EYE_TRACKING -> Icons.Default.Visibility // TODO: EyeTracking not available + Icon.AIRPORT_SHUTTLE -> Icons.Default.AirportShuttle + } +} + +/** + * Extension function to get an [ImageVector] for an icon. + */ +fun Icon.getOutlinedImageVector(): ImageVector { + return when (this) { + Icon.PERSON -> Icons.Outlined.Person + Icon.TODAY -> Icons.Outlined.Today + Icon.DATE_RANGE -> Icons.Outlined.DateRange + Icon.CALENDAR_CLOCK -> Icons.Outlined.CalendarToday // TODO: CalendarClock not available + Icon.ACCOUNT_BALANCE -> Icons.Outlined.AccountBalance + Icon.NUMBERS -> Icons.Outlined.Numbers + Icon.ACCOUNT_BOX -> Icons.Outlined.AccountBox + Icon.DIRECTIONS_CAR -> Icons.Outlined.DirectionsCar + Icon.LANGUAGE -> Icons.Outlined.Language + Icon.EMERGENCY -> Icons.Outlined.Emergency + Icon.PLACE -> Icons.Outlined.Place + Icon.SIGNATURE -> Icons.Outlined.Draw // TODO: Signature not available + Icon.MILITARY_TECH -> Icons.Outlined.MilitaryTech + Icon.STARS -> Icons.Outlined.Stars + Icon.FACE -> Icons.Outlined.Face + Icon.FINGERPRINT -> Icons.Outlined.Fingerprint + Icon.EYE_TRACKING -> Icons.Outlined.Visibility // TODO: EyeTracking not available + Icon.AIRPORT_SHUTTLE -> Icons.Outlined.AirportShuttle + } +} \ No newline at end of file diff --git a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/DrivingLicense.kt b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/DrivingLicense.kt index 41e00da87..8a6ea2284 100644 --- a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/DrivingLicense.kt +++ b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/DrivingLicense.kt @@ -23,6 +23,7 @@ import com.android.identity.cbor.toDataItem import com.android.identity.cbor.toDataItemFullDate import com.android.identity.documenttype.DocumentAttributeType import com.android.identity.documenttype.DocumentType +import com.android.identity.documenttype.Icon import com.android.identity.documenttype.IntegerOption import com.android.identity.documenttype.StringOption @@ -52,6 +53,7 @@ object DrivingLicense { "Last name, surname, or primary identifier, of the mDL holder.", true, MDL_NAMESPACE, + Icon.PERSON, SampleData.FAMILY_NAME.toDataItem() ) .addAttribute( @@ -61,6 +63,7 @@ object DrivingLicense { "First name(s), other name(s), or secondary identifier, of the mDL holder", true, MDL_NAMESPACE, + Icon.PERSON, SampleData.GIVEN_NAME.toDataItem() ) .addAttribute( @@ -70,6 +73,7 @@ object DrivingLicense { "Day, month and year on which the mDL holder was born. If unknown, approximate date of birth", true, MDL_NAMESPACE, + Icon.TODAY, SampleData.birthDate.toDataItemFullDate() ) .addAttribute( @@ -79,6 +83,7 @@ object DrivingLicense { "Date when mDL was issued", true, MDL_NAMESPACE, + Icon.DATE_RANGE, SampleData.issueDate.toDataItemFullDate() ) .addAttribute( @@ -88,6 +93,7 @@ object DrivingLicense { "Date when mDL expires", true, MDL_NAMESPACE, + Icon.CALENDAR_CLOCK, SampleData.expiryDate.toDataItemFullDate() ) .addAttribute( @@ -97,6 +103,7 @@ object DrivingLicense { "Alpha-2 country code, as defined in ISO 3166-1, of the issuing authority’s country or territory", true, MDL_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_COUNTRY.toDataItem() ) .addAttribute( @@ -106,6 +113,7 @@ object DrivingLicense { "Issuing authority name.", true, MDL_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_AUTHORITY_MDL.toDataItem() ) .addAttribute( @@ -115,6 +123,7 @@ object DrivingLicense { "The number assigned or calculated by the issuing authority.", true, MDL_NAMESPACE, + Icon.NUMBERS, SampleData.DOCUMENT_NUMBER.toDataItem() ) .addAttribute( @@ -124,6 +133,7 @@ object DrivingLicense { "A reproduction of the mDL holder’s portrait.", true, MDL_NAMESPACE, + Icon.ACCOUNT_BOX, null // TODO: include img_erika_portrait.jpg ) .addAttribute( @@ -133,6 +143,7 @@ object DrivingLicense { "Driving privileges of the mDL holder", true, MDL_NAMESPACE, + Icon.DIRECTIONS_CAR, CborArray.builder() .addMap() .put("vehicle_category_code", "A") @@ -154,6 +165,7 @@ object DrivingLicense { "Distinguishing sign of the issuing country", true, MDL_NAMESPACE, + Icon.LANGUAGE, SampleData.UN_DISTINGUISHING_SIGN.toDataItem() ) .addAttribute( @@ -163,6 +175,7 @@ object DrivingLicense { "An audit control number assigned by the issuing authority", false, MDL_NAMESPACE, + Icon.NUMBERS, SampleData.ADMINISTRATIVE_NUMBER.toDataItem() ) .addAttribute( @@ -172,6 +185,7 @@ object DrivingLicense { "mDL holder’s sex", false, MDL_NAMESPACE, + Icon.EMERGENCY, SampleData.SEX_ISO218.toDataItem() ) .addAttribute( @@ -181,6 +195,7 @@ object DrivingLicense { "mDL holder’s height in centimetres", false, MDL_NAMESPACE, + Icon.EMERGENCY, SampleData.HEIGHT_CM.toDataItem() ) .addAttribute( @@ -190,6 +205,7 @@ object DrivingLicense { "mDL holder’s weight in kilograms", false, MDL_NAMESPACE, + Icon.EMERGENCY, SampleData.WEIGHT_KG.toDataItem() ) .addAttribute( @@ -213,6 +229,7 @@ object DrivingLicense { "mDL holder’s eye color", false, MDL_NAMESPACE, + Icon.PERSON, "blue".toDataItem() ) .addAttribute( @@ -236,6 +253,7 @@ object DrivingLicense { "mDL holder’s hair color", false, MDL_NAMESPACE, + Icon.PERSON, "blond".toDataItem() ) .addAttribute( @@ -245,6 +263,7 @@ object DrivingLicense { "Country and municipality or state/province where the mDL holder was born", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_PLACE.toDataItem() ) .addAttribute( @@ -254,6 +273,7 @@ object DrivingLicense { "The place where the mDL holder resides and/or may be contacted (street/house number, municipality etc.)", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_ADDRESS.toDataItem() ) .addAttribute( @@ -263,6 +283,7 @@ object DrivingLicense { "Date when portrait was taken", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.portraitCaptureDate.toDataItemFullDate() ) .addAttribute( @@ -272,6 +293,7 @@ object DrivingLicense { "The age of the mDL holder", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_IN_YEARS.toDataItem() ) .addAttribute( @@ -281,6 +303,7 @@ object DrivingLicense { "The year when the mDL holder was born", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_BIRTH_YEAR.toDataItem() ) .addMdocAttribute( @@ -290,6 +313,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 13", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_13.toDataItem() ) .addMdocAttribute( @@ -299,6 +323,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 16", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_16.toDataItem() ) .addAttribute( @@ -308,6 +333,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 18", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_18.toDataItem() ) .addAttribute( @@ -317,6 +343,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 21", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_21.toDataItem() ) .addAttribute( @@ -326,6 +353,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 25", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_25.toDataItem() ) .addAttribute( @@ -335,6 +363,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 60", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_60.toDataItem() ) .addAttribute( @@ -344,6 +373,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 62", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_62.toDataItem() ) .addAttribute( @@ -353,6 +383,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 65", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_65.toDataItem() ) .addAttribute( @@ -362,6 +393,7 @@ object DrivingLicense { "Indication whether the mDL holder is as old or older than 68", false, MDL_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_68.toDataItem() ) .addAttribute( @@ -371,6 +403,7 @@ object DrivingLicense { "Country subdivision code of the jurisdiction that issued the mDL", false, MDL_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_JURISDICTION.toDataItem() ) .addAttribute( @@ -380,6 +413,7 @@ object DrivingLicense { "Nationality of the mDL holder", false, MDL_NAMESPACE, + Icon.LANGUAGE, SampleData.NATIONALITY.toDataItem() ) .addAttribute( @@ -389,6 +423,7 @@ object DrivingLicense { "The city where the mDL holder lives", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_CITY.toDataItem() ) .addAttribute( @@ -398,6 +433,7 @@ object DrivingLicense { "The state/province/district where the mDL holder lives", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_STATE.toDataItem() ) .addAttribute( @@ -407,6 +443,7 @@ object DrivingLicense { "The postal code of the mDL holder", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_POSTAL_CODE.toDataItem() ) .addAttribute( @@ -416,6 +453,7 @@ object DrivingLicense { "The country where the mDL holder lives", false, MDL_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_COUNTRY.toDataItem() ) .addAttribute( @@ -425,6 +463,7 @@ object DrivingLicense { "The family name of the mDL holder", false, MDL_NAMESPACE, + Icon.PERSON, SampleData.FAMILY_NAME_NATIONAL_CHARACTER.toDataItem() ) .addAttribute( @@ -434,6 +473,7 @@ object DrivingLicense { "The given name of the mDL holder", false, MDL_NAMESPACE, + Icon.PERSON, SampleData.GIVEN_NAMES_NATIONAL_CHARACTER.toDataItem() ) .addAttribute( @@ -443,6 +483,7 @@ object DrivingLicense { "Image of the signature or usual mark of the mDL holder,", false, MDL_NAMESPACE, + Icon.SIGNATURE, null // TODO: include img_erika_signature.jpg ) .addAttribute( @@ -453,6 +494,7 @@ object DrivingLicense { "Vehicle types the license holder is authorized to operate", false, AAMVA_NAMESPACE, + Icon.DIRECTIONS_CAR, null ) .addAttribute( @@ -463,7 +505,8 @@ object DrivingLicense { "Name suffix of the individual that has been issued the driver license or identification document.", false, AAMVA_NAMESPACE, - null, + Icon.PERSON, + null ) .addAttribute( DocumentAttributeType.IntegerOptions( @@ -478,6 +521,7 @@ object DrivingLicense { "An indicator that denotes whether the credential holder is an organ donor.", false, AAMVA_NAMESPACE, + Icon.EMERGENCY, 1.toDataItem() ) .addAttribute( @@ -493,6 +537,7 @@ object DrivingLicense { "An indicator that denotes whether the credential holder is a veteran.", false, AAMVA_NAMESPACE, + Icon.MILITARY_TECH, null ) .addAttribute( @@ -510,6 +555,7 @@ object DrivingLicense { "A code that indicates whether the field has been truncated", true, AAMVA_NAMESPACE, + Icon.PERSON, null ) .addAttribute( @@ -527,6 +573,7 @@ object DrivingLicense { "A code that indicates whether either the first name or the middle name(s) have been truncated", true, AAMVA_NAMESPACE, + Icon.PERSON, null ) .addAttribute( @@ -537,6 +584,7 @@ object DrivingLicense { "Other family name by which credential holder is known.", false, AAMVA_NAMESPACE, + Icon.PERSON, null ) .addAttribute( @@ -547,6 +595,7 @@ object DrivingLicense { "Other given name by which credential holder is known.", false, AAMVA_NAMESPACE, + Icon.PERSON, null ) .addAttribute( @@ -557,6 +606,7 @@ object DrivingLicense { "Other suffix by which credential holder is known.", false, AAMVA_NAMESPACE, + Icon.PERSON, null ) .addAttribute( @@ -581,6 +631,7 @@ object DrivingLicense { "Indicates the approximate weight range of the cardholder", false, AAMVA_NAMESPACE, + Icon.EMERGENCY, 3.toDataItem() ) .addAttribute( @@ -602,6 +653,7 @@ object DrivingLicense { "Codes for race or ethnicity of the cardholder", false, AAMVA_NAMESPACE, + Icon.EMERGENCY, "W".toDataItem() ) .addAttribute( @@ -618,6 +670,7 @@ object DrivingLicense { "DHS required field that indicates compliance", false, AAMVA_NAMESPACE, + Icon.STARS, "F".toDataItem() ) .addAttribute( @@ -633,6 +686,7 @@ object DrivingLicense { "DHS required field that denotes whether the credential holder has temporary lawful status. 1: Temporary lawful status", false, AAMVA_NAMESPACE, + Icon.STARS, null ) .addAttribute( @@ -649,6 +703,7 @@ object DrivingLicense { "Present if the credential is an EDL", false, AAMVA_NAMESPACE, + Icon.DIRECTIONS_CAR, 1.toDataItem() ) .addAttribute( @@ -659,6 +714,7 @@ object DrivingLicense { "The 3-digit county code of the county where the mDL holder lives", false, AAMVA_NAMESPACE, + Icon.PLACE, null ) .addAttribute( @@ -669,6 +725,7 @@ object DrivingLicense { "Date on which the hazardous material endorsement granted by the document is no longer valid.", true, AAMVA_NAMESPACE, + Icon.CALENDAR_CLOCK, null ) .addAttribute( @@ -679,6 +736,7 @@ object DrivingLicense { "mDL holder’s sex", true, AAMVA_NAMESPACE, + Icon.EMERGENCY, SampleData.SEX_ISO218.toDataItem() ) /* @@ -691,6 +749,7 @@ object DrivingLicense { "Facial biometric information of the mDL holder", false, MDL_NAMESPACE, + Icon.FACE, null ) .addMdocAttribute( @@ -700,6 +759,7 @@ object DrivingLicense { "Fingerprint of the mDL holder", false, MDL_NAMESPACE, + Icon.FINGERPRINT, null ) .addMdocAttribute( @@ -709,6 +769,7 @@ object DrivingLicense { "Signature/sign of the mDL holder", false, MDL_NAMESPACE, + Icon.SIGNATURE, null ) .addMdocAttribute( @@ -718,6 +779,7 @@ object DrivingLicense { "Iris of the mDL holder", false, MDL_NAMESPACE, + Icon.EYE_TRACKING, null ) /* @@ -730,6 +792,7 @@ object DrivingLicense { "FMCSA required field that denotes whether the credential is a 'Commercial " + "Driver’s License' or a 'Commercial Learner’s Permit'. This field is " + "either absent or has value '1' (Commercial Driver’s License).", + Icon.AIRPORT_SHUTTLE, null ) .addVcAttribute( @@ -738,6 +801,7 @@ object DrivingLicense { "Non-REAL ID Credential Text", "Text, agreed on between the Issuing Authority and DHS, appearing on credentials " + "not meeting REAL ID requirements.", + Icon.STARS, null ) .addAttribute( @@ -747,6 +811,7 @@ object DrivingLicense { "A string of letters and/or numbers that identifies when, where, and by whom the credential was initially provisioned.", false, AAMVA_NAMESPACE, + Icon.STARS, null ) .addAttribute( @@ -756,6 +821,7 @@ object DrivingLicense { "A number identifying the version of the AAMVA mDL data element set", true, AAMVA_NAMESPACE, + Icon.NUMBERS, null ) .addSampleRequest( diff --git a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/EUPersonalID.kt b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/EUPersonalID.kt index 788431e1c..88fb1a037 100644 --- a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/EUPersonalID.kt +++ b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/EUPersonalID.kt @@ -20,6 +20,7 @@ import com.android.identity.cbor.toDataItem import com.android.identity.cbor.toDataItemFullDate import com.android.identity.documenttype.DocumentAttributeType import com.android.identity.documenttype.DocumentType +import com.android.identity.documenttype.Icon /** * Object containing the metadata of the EU Personal ID Document Type. @@ -45,6 +46,7 @@ object EUPersonalID { "Current last name(s), surname(s), or primary identifier of the PID holder", true, EUPID_NAMESPACE, + Icon.PERSON, SampleData.FAMILY_NAME.toDataItem() ) .addAttribute( @@ -54,6 +56,7 @@ object EUPersonalID { "Current first name(s), other name(s), or secondary identifier of the PID holder", true, EUPID_NAMESPACE, + Icon.PERSON, SampleData.GIVEN_NAME.toDataItem() ) .addAttribute( @@ -63,6 +66,7 @@ object EUPersonalID { "Day, month, and year on which the PID holder was born. If unknown, approximate date of birth.", true, EUPID_NAMESPACE, + Icon.TODAY, SampleData.birthDate.toDataItemFullDate() ) .addAttribute( @@ -72,6 +76,7 @@ object EUPersonalID { "The age of the PID holder in years", false, EUPID_NAMESPACE, + Icon.TODAY, SampleData.AGE_IN_YEARS.toDataItem() ) .addAttribute( @@ -81,6 +86,7 @@ object EUPersonalID { "The year when the PID holder was born", false, EUPID_NAMESPACE, + Icon.TODAY, SampleData.AGE_BIRTH_YEAR.toDataItem() ) .addAttribute( @@ -90,6 +96,7 @@ object EUPersonalID { "Age over 18?", false, EUPID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_18.toDataItem() ) .addAttribute( @@ -99,6 +106,7 @@ object EUPersonalID { "Age over 21?", false, EUPID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_21.toDataItem() ) .addAttribute( @@ -108,6 +116,7 @@ object EUPersonalID { "Last name(s), surname(s), or primary identifier of the PID holder at birth", false, EUPID_NAMESPACE, + Icon.PERSON, SampleData.FAMILY_NAME_BIRTH.toDataItem() ) .addAttribute( @@ -117,6 +126,7 @@ object EUPersonalID { "First name(s), other name(s), or secondary identifier of the PID holder at birth", false, EUPID_NAMESPACE, + Icon.PERSON, SampleData.GIVEN_NAME_BIRTH.toDataItem() ) .addAttribute( @@ -126,6 +136,7 @@ object EUPersonalID { "Country and municipality or state/province where the PID holder was born", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_PLACE.toDataItem() ) .addAttribute( @@ -135,6 +146,7 @@ object EUPersonalID { "The country where the PID User was born, as an Alpha-2 country code as specified in ISO 3166-1", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_COUNTRY.toDataItem() ) .addAttribute( @@ -144,6 +156,7 @@ object EUPersonalID { "The state, province, district, or local area where the PID User was born", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_STATE.toDataItem() ) .addAttribute( @@ -153,6 +166,7 @@ object EUPersonalID { "The municipality, city, town, or village where the PID User was born", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_CITY.toDataItem() ) .addAttribute( @@ -162,6 +176,7 @@ object EUPersonalID { "The full address of the place where the PID holder currently resides and/or may be contacted (street/house number, municipality etc.)", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_ADDRESS.toDataItem() ) .addAttribute( @@ -171,6 +186,7 @@ object EUPersonalID { "The country where the PID User currently resides, as an Alpha-2 country code as specified in ISO 3166-1", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_COUNTRY.toDataItem() ) .addAttribute( @@ -180,6 +196,7 @@ object EUPersonalID { "The state, province, district, or local area where the PID User currently resides.", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_STATE.toDataItem() ) .addAttribute( @@ -189,6 +206,7 @@ object EUPersonalID { "The city where the PID holder currently resides", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_CITY.toDataItem() ) .addAttribute( @@ -198,6 +216,7 @@ object EUPersonalID { "The postal code of the place where the PID holder currently resides", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_POSTAL_CODE.toDataItem() ) .addAttribute( @@ -207,6 +226,7 @@ object EUPersonalID { "The name of the street where the PID User currently resides.", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_STREET.toDataItem() ) .addAttribute( @@ -216,6 +236,7 @@ object EUPersonalID { "The house number where the PID User currently resides, including any affix or suffix", false, EUPID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_HOUSE_NUMBER.toDataItem() ) .addAttribute( @@ -225,6 +246,7 @@ object EUPersonalID { "PID holder’s gender", false, EUPID_NAMESPACE, + Icon.EMERGENCY, SampleData.SEX_ISO218.toDataItem() ) .addAttribute( @@ -234,6 +256,7 @@ object EUPersonalID { "Alpha-2 country code as specified in ISO 3166-1, representing the nationality of the PID User.", true, EUPID_NAMESPACE, + Icon.LANGUAGE, SampleData.NATIONALITY.toDataItem() ) .addAttribute( @@ -243,6 +266,7 @@ object EUPersonalID { "Date (and possibly time) when the PID was issued.", true, EUPID_NAMESPACE, + Icon.DATE_RANGE, SampleData.issueDate.toDataItemFullDate() ) .addAttribute( @@ -252,6 +276,7 @@ object EUPersonalID { "Date (and possibly time) when the PID will expire.", true, EUPID_NAMESPACE, + Icon.CALENDAR_CLOCK, SampleData.expiryDate.toDataItemFullDate() ) .addAttribute( @@ -263,6 +288,7 @@ object EUPersonalID { "no separate authority authorized to issue PIDs.", true, EUPID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_AUTHORITY_EU_PID.toDataItem() ) .addAttribute( @@ -272,6 +298,7 @@ object EUPersonalID { "A number for the PID, assigned by the PID Provider.", false, EUPID_NAMESPACE, + Icon.NUMBERS, SampleData.DOCUMENT_NUMBER.toDataItem() ) .addAttribute( @@ -281,6 +308,7 @@ object EUPersonalID { "A number assigned by the PID Provider for audit control or other purposes.", false, EUPID_NAMESPACE, + Icon.NUMBERS, SampleData.ADMINISTRATIVE_NUMBER.toDataItem() ) .addAttribute( @@ -292,6 +320,7 @@ object EUPersonalID { "as the value for issuing_country.", false, EUPID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_JURISDICTION.toDataItem() ) .addAttribute( @@ -302,6 +331,7 @@ object EUPersonalID { "country or territory", true, EUPID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_COUNTRY.toDataItem() ) .addSampleRequest( diff --git a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/PhotoID.kt b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/PhotoID.kt index 64b07fa1f..6aeb87727 100644 --- a/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/PhotoID.kt +++ b/identity-doctypes/src/commonMain/kotlin/com/android/identity/documenttype/knowntypes/PhotoID.kt @@ -5,6 +5,7 @@ import com.android.identity.cbor.toDataItem import com.android.identity.cbor.toDataItemFullDate import com.android.identity.documenttype.DocumentAttributeType import com.android.identity.documenttype.DocumentType +import com.android.identity.documenttype.Icon import com.android.identity.documenttype.knowntypes.EUPersonalID.EUPID_VCT /** @@ -31,6 +32,7 @@ object PhotoID { "Last name, surname, or primary identifier, of the document holder", true, PHOTO_ID_NAMESPACE, + Icon.PERSON, SampleData.FAMILY_NAME.toDataItem() ) .addMdocAttribute( @@ -40,6 +42,7 @@ object PhotoID { "First name(s), other name(s), or secondary identifier, of the document holder", true, PHOTO_ID_NAMESPACE, + Icon.PERSON, SampleData.GIVEN_NAME.toDataItem() ) // Note, this is more complicated than mDL and EU PID, according to ISO/IEC 23220-2 @@ -62,6 +65,7 @@ object PhotoID { "Day, month and year on which the document holder was born. If unknown, approximate date of birth", true, PHOTO_ID_NAMESPACE, + Icon.TODAY, CborMap.builder() .put("birth_date", SampleData.birthDate.toDataItemFullDate()) .end() @@ -74,6 +78,7 @@ object PhotoID { "A reproduction of the document holder’s portrait.", true, PHOTO_ID_NAMESPACE, + Icon.ACCOUNT_BOX, null // TODO: include img_erika_portrait.jpg ) .addMdocAttribute( @@ -83,6 +88,7 @@ object PhotoID { "Date when document was issued", true, PHOTO_ID_NAMESPACE, + Icon.DATE_RANGE, SampleData.issueDate.toDataItemFullDate() ) .addMdocAttribute( @@ -92,6 +98,7 @@ object PhotoID { "Date when document expires", true, PHOTO_ID_NAMESPACE, + Icon.CALENDAR_CLOCK, SampleData.expiryDate.toDataItemFullDate() ) .addMdocAttribute( @@ -101,6 +108,7 @@ object PhotoID { "Issuing authority name.", true, PHOTO_ID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_AUTHORITY_PHOTO_ID.toDataItem() ) .addMdocAttribute( @@ -110,6 +118,7 @@ object PhotoID { "Alpha-2 country code, as defined in ISO 3166-1, of the issuing authority’s country or territory", true, PHOTO_ID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_COUNTRY.toDataItem() ) .addMdocAttribute( @@ -119,6 +128,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 18", true, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_18.toDataItem() ) .addMdocAttribute( @@ -128,6 +138,7 @@ object PhotoID { "The age of the document holder", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_IN_YEARS.toDataItem() ) .addMdocAttribute( @@ -137,6 +148,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 13", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_13.toDataItem() ) .addMdocAttribute( @@ -146,6 +158,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 16", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_16.toDataItem() ) .addMdocAttribute( @@ -155,6 +168,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 18", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_18.toDataItem() ) .addMdocAttribute( @@ -164,6 +178,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 21", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_21.toDataItem() ) .addMdocAttribute( @@ -173,6 +188,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 25", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_25.toDataItem() ) .addMdocAttribute( @@ -182,6 +198,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 60", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_60.toDataItem() ) .addMdocAttribute( @@ -191,6 +208,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 62", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_62.toDataItem() ) .addMdocAttribute( @@ -200,6 +218,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 65", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_65.toDataItem() ) .addMdocAttribute( @@ -209,6 +228,7 @@ object PhotoID { "Indication whether the document holder is as old or older than 68", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_OVER_68.toDataItem() ) .addMdocAttribute( @@ -218,6 +238,7 @@ object PhotoID { "The year when the document holder was born", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.AGE_BIRTH_YEAR.toDataItem() ) .addMdocAttribute( @@ -227,6 +248,7 @@ object PhotoID { "Date when portrait was taken", false, PHOTO_ID_NAMESPACE, + Icon.TODAY, SampleData.portraitCaptureDate.toDataItemFullDate() ) .addMdocAttribute( @@ -236,6 +258,7 @@ object PhotoID { "Country and municipality or state/province where the document holder was born", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.BIRTH_PLACE.toDataItem() ) .addMdocAttribute( @@ -245,6 +268,7 @@ object PhotoID { "The name(s) which holder was born.", false, PHOTO_ID_NAMESPACE, + Icon.PERSON, null ) .addMdocAttribute( @@ -254,6 +278,7 @@ object PhotoID { "The place where the document holder resides and/or may be contacted (street/house number, municipality etc.)", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_ADDRESS.toDataItem() ) .addMdocAttribute( @@ -263,6 +288,7 @@ object PhotoID { "The city where the document holder lives", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_CITY.toDataItem() ) .addMdocAttribute( @@ -272,6 +298,7 @@ object PhotoID { "The postal code of the document holder", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_POSTAL_CODE.toDataItem() ) .addMdocAttribute( @@ -281,6 +308,7 @@ object PhotoID { "The country where the document holder lives", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_COUNTRY.toDataItem() ) .addMdocAttribute( @@ -290,6 +318,7 @@ object PhotoID { "The city where the document holder lives, in Latin 1 characters", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, null ) .addMdocAttribute( @@ -299,6 +328,7 @@ object PhotoID { "document holder’s sex", false, PHOTO_ID_NAMESPACE, + Icon.EMERGENCY, SampleData.SEX_ISO218.toDataItem() ) .addMdocAttribute( @@ -308,6 +338,7 @@ object PhotoID { "Nationality of the document holder", false, PHOTO_ID_NAMESPACE, + Icon.LANGUAGE, SampleData.NATIONALITY.toDataItem() ) .addMdocAttribute( @@ -317,6 +348,7 @@ object PhotoID { "The number assigned or calculated by the issuing authority.", true, PHOTO_ID_NAMESPACE, + Icon.NUMBERS, SampleData.DOCUMENT_NUMBER.toDataItem() ) .addMdocAttribute( @@ -328,6 +360,7 @@ object PhotoID { "authority is located.", false, PHOTO_ID_NAMESPACE, + Icon.ACCOUNT_BALANCE, SampleData.ISSUING_JURISDICTION.toDataItem() ) .addMdocAttribute( @@ -337,6 +370,7 @@ object PhotoID { "Last name, surname, or primary identifier, of the document holder. In Latin 1", true, PHOTO_ID_NAMESPACE, + Icon.PERSON, null ) .addMdocAttribute( @@ -346,6 +380,7 @@ object PhotoID { "First name(s), other name(s), or secondary identifier, of the document holder. In Latin 1", true, PHOTO_ID_NAMESPACE, + Icon.PERSON, null ) @@ -358,6 +393,7 @@ object PhotoID { "Person identifier of the Photo ID holder.", false, PHOTO_ID_NAMESPACE, + Icon.NUMBERS, SampleData.PERSON_ID.toDataItem() ) .addMdocAttribute( @@ -368,6 +404,7 @@ object PhotoID { "Alpha-2 country code as specified in ISO 3166-1.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, null ) .addMdocAttribute( @@ -378,6 +415,7 @@ object PhotoID { "Photo ID holder was born.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, null ) .addMdocAttribute( @@ -388,6 +426,7 @@ object PhotoID { "ID holder was born.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, null ) .addMdocAttribute( @@ -398,6 +437,7 @@ object PhotoID { "control or other purposes.", false, PHOTO_ID_NAMESPACE, + Icon.NUMBERS, SampleData.ADMINISTRATIVE_NUMBER.toDataItem() ) .addMdocAttribute( @@ -408,6 +448,7 @@ object PhotoID { "currently resides.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_STREET.toDataItem() ) .addMdocAttribute( @@ -418,6 +459,7 @@ object PhotoID { "resides, including any affix or suffix.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_HOUSE_NUMBER.toDataItem() ) .addMdocAttribute( @@ -429,6 +471,7 @@ object PhotoID { "document).", false, PHOTO_ID_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -438,6 +481,7 @@ object PhotoID { "The state/province/district where the Photo ID holder lives.", false, PHOTO_ID_NAMESPACE, + Icon.PLACE, SampleData.RESIDENT_STATE.toDataItem() ) @@ -450,6 +494,7 @@ object PhotoID { "Version of the DTC-VC definition", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -459,6 +504,7 @@ object PhotoID { "Binary data of the eMRTD Document Security Object", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -468,6 +514,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 1", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -477,6 +524,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 2", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -486,6 +534,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 3", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -495,6 +544,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 4", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -504,6 +554,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 5", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -513,6 +564,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 6", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -522,6 +574,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 7", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -531,6 +584,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 8", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -540,6 +594,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 9", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -549,6 +604,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 10", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -558,6 +614,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 11", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -567,6 +624,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 12", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -576,6 +634,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 13", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -585,6 +644,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 14", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -594,6 +654,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 15", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -603,6 +664,7 @@ object PhotoID { "Binary data of the eMRTD Data Group 16", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) .addMdocAttribute( @@ -612,6 +674,7 @@ object PhotoID { "Binary data of the DTCContentInfo", false, DTC_NAMESPACE, + Icon.NUMBERS, null ) diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentAttribute.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentAttribute.kt index 538388bf2..5f45878d2 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentAttribute.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentAttribute.kt @@ -25,6 +25,7 @@ import com.android.identity.cbor.DataItem * @param identifier the identifier of this attribute. * @param displayName the name suitable for display of the attribute. * @param description a description of the attribute. + * @param icon the icon for the attribute, if available. * @param sampleValue a sample value for the attribute, if available. */ class DocumentAttribute( @@ -32,5 +33,6 @@ class DocumentAttribute( val identifier: String, val displayName: String, val description: String, - val sampleValue: DataItem?, + val icon: Icon?, + val sampleValue: DataItem? ) \ No newline at end of file diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt index 8b57ad1eb..4f5f8001d 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt @@ -85,6 +85,7 @@ class DocumentType private constructor( * @param description a description of the attribute. * @param mandatory indication whether the mDoc attribute is mandatory. * @param mdocNamespace the namespace of the mDoc attribute. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addAttribute( @@ -94,11 +95,12 @@ class DocumentType private constructor( description: String, mandatory: Boolean, mdocNamespace: String, + icon: Icon? = null, sampleValue: DataItem? = null, ) = apply { addMdocAttribute(type, identifier, displayName, description, mandatory, - mdocNamespace, sampleValue) - addVcAttribute(type, identifier, displayName, description, sampleValue) + mdocNamespace, icon, sampleValue) + addVcAttribute(type, identifier, displayName, description, icon, sampleValue) } /** @@ -111,6 +113,7 @@ class DocumentType private constructor( * @param description a description of the attribute. * @param mandatory indication whether the mDoc attribute is mandatory. * @param mdocNamespace the namespace of the mDoc attribute. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addAttribute( @@ -121,6 +124,7 @@ class DocumentType private constructor( description: String, mandatory: Boolean, mdocNamespace: String, + icon: Icon? = null, sampleValue: DataItem? = null ) = apply { addMdocAttribute( @@ -130,9 +134,10 @@ class DocumentType private constructor( description, mandatory, mdocNamespace, + icon, sampleValue ) - addVcAttribute(type, vcIdentifier, displayName, description, sampleValue) + addVcAttribute(type, vcIdentifier, displayName, description, icon, sampleValue) } /** @@ -144,6 +149,7 @@ class DocumentType private constructor( * @param description a description of the attribute. * @param mandatory indication whether the mDoc attribute is mandatory. * @param mdocNamespace the namespace of the mDoc attribute. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addMdocAttribute( @@ -153,6 +159,7 @@ class DocumentType private constructor( description: String, mandatory: Boolean, mdocNamespace: String, + icon: Icon? = null, sampleValue: DataItem? = null ) = apply { mdocBuilder?.addDataElement( @@ -162,6 +169,7 @@ class DocumentType private constructor( displayName, description, mandatory, + icon, sampleValue ) ?: throw Exception("The mDoc Document Type was not initialized") } @@ -173,6 +181,7 @@ class DocumentType private constructor( * @param identifier the identifier of this attribute. * @param displayName a name suitable for display of the attribute. * @param description a description of the attribute. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addVcAttribute( @@ -180,9 +189,10 @@ class DocumentType private constructor( identifier: String, displayName: String, description: String, + icon: Icon? = null, sampleValue: DataItem? = null ) = apply { - vcBuilder?.addClaim(type, identifier, displayName, description, sampleValue) + vcBuilder?.addClaim(type, identifier, displayName, description, icon, sampleValue) ?: throw Exception("The VC Document Type was not initialized") } diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/Icon.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/Icon.kt new file mode 100644 index 000000000..c8ff65d6a --- /dev/null +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/Icon.kt @@ -0,0 +1,29 @@ +package com.android.identity.documenttype + +/** + * An enumeration of icons used to represent ISO mdoc data elements or VC claims. + * + * @property iconName the icon name according to https://fonts.google.com/icons + */ +enum class Icon( + val iconName: String +) { + PERSON("person"), + TODAY("today"), + DATE_RANGE("date_range"), + CALENDAR_CLOCK("calendar_clock"), + ACCOUNT_BALANCE("account_balance"), + NUMBERS("numbers"), + ACCOUNT_BOX("account_box"), + DIRECTIONS_CAR("directions_car"), + LANGUAGE("language"), + EMERGENCY("emergency"), + PLACE("place"), + SIGNATURE("signature"), + MILITARY_TECH("military_tech"), + STARS("stars"), + FACE("face"), + FINGERPRINT("fingerprint"), + EYE_TRACKING("eye_tracking"), + AIRPORT_SHUTTLE("airport_shuttle"), +} \ No newline at end of file diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocDocumentType.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocDocumentType.kt index e164d1a9e..5d18a36e5 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocDocumentType.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocDocumentType.kt @@ -47,6 +47,7 @@ class MdocDocumentType private constructor( * @param displayName the name suitable for display of the attribute. * @param description a description of the attribute. * @param mandatory indication whether the mDoc attribute is mandatory. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addDataElement( @@ -56,6 +57,7 @@ class MdocDocumentType private constructor( displayName: String, description: String, mandatory: Boolean, + icon: Icon? = null, sampleValue: DataItem? = null, ) = apply { if (!namespaces.containsKey(namespace)) { @@ -67,6 +69,7 @@ class MdocDocumentType private constructor( displayName, description, mandatory, + icon, sampleValue ) } diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocNamespace.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocNamespace.kt index 87226f54e..66d2ff24d 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocNamespace.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/MdocNamespace.kt @@ -47,6 +47,7 @@ class MdocNamespace private constructor( * @param displayName the name suitable for display of the attribute. * @param description a description of the attribute. * @param mandatory indication whether the mDoc attribute is mandatory. + * @param icon the icon, if available. * @param sampleValue a sample value for the attribute, if available. */ fun addDataElement( @@ -55,10 +56,11 @@ class MdocNamespace private constructor( displayName: String, description: String, mandatory: Boolean, + icon: Icon?, sampleValue: DataItem?, ) = apply { dataElements[identifier] = MdocDataElement( - DocumentAttribute(type, identifier, displayName, description, sampleValue), + DocumentAttribute(type, identifier, displayName, description, icon, sampleValue), mandatory ) } diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcDocumentType.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcDocumentType.kt index 8d30caa67..d2d08bfeb 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcDocumentType.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcDocumentType.kt @@ -40,17 +40,19 @@ class VcDocumentType private constructor( * @param identifier the identifier of this claim. * @param displayName a name suitable for display of the claim. * @param description a description of the claim. - * @param sampleValue a sample value for the attribute. + * @param icon the icon, if available. + * @param sampleValue a sample value for the attribute, if available. */ fun addClaim( type: DocumentAttributeType, identifier: String, displayName: String, description: String, + icon: Icon? = null, sampleValue: DataItem? = null ) = apply { claims[identifier] = DocumentAttribute( - type, identifier, displayName, description, sampleValue + type, identifier, displayName, description, icon, sampleValue ) } diff --git a/wallet/src/main/java/com/android/identity_credential/wallet/ui/prompt/consent/ConsentPromptEntryField.kt b/wallet/src/main/java/com/android/identity_credential/wallet/ui/prompt/consent/ConsentPromptEntryField.kt index b8bbd87b6..9eb567c86 100644 --- a/wallet/src/main/java/com/android/identity_credential/wallet/ui/prompt/consent/ConsentPromptEntryField.kt +++ b/wallet/src/main/java/com/android/identity_credential/wallet/ui/prompt/consent/ConsentPromptEntryField.kt @@ -42,6 +42,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.android.identity.appsupport.ui.getOutlinedImageVector import com.android.identity.trustmanagement.TrustPoint import com.android.identity_credential.wallet.R import com.android.identity_credential.wallet.util.toImageBitmap @@ -296,10 +297,17 @@ private fun DataElementView( onClick = {}, label = { + if (consentField.attribute?.icon != null) { + Icon( + consentField.attribute!!.icon!!.getOutlinedImageVector(), + contentDescription = "${consentField.attribute!!.icon!!.iconName} icon" + ) + Spacer(modifier = Modifier.width(8.dp)) + } Text( - text = "• ${consentField.displayName}", + text = "${consentField.displayName}", fontWeight = FontWeight.Normal, - style = MaterialTheme.typography.bodyLarge + style = MaterialTheme.typography.bodySmall ) }, )