From df52dedf8e8619ce3208cda603ca395a1e4a612a Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 29 Aug 2023 23:55:40 +0200 Subject: [PATCH 01/22] Add biometric templates to RegistrationResult --- .../identity/model/RegistrationResult.java | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java index fe16353e6c..12f2dd109a 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java @@ -2,11 +2,16 @@ import android.os.Parcel; import android.os.Parcelable; +import org.commcare.commcaresupportlibrary.BiometricUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; @SuppressWarnings("unused") public class RegistrationResult implements Parcelable { - private String guid; + private Map templates; /** * Result of the identity enrollment workflow @@ -15,10 +20,25 @@ public class RegistrationResult implements Parcelable { */ public RegistrationResult(String guid) { this.guid = guid; + this.templates = new HashMap<>(0); + } + + public RegistrationResult(String guid, Map templates) { + this.guid = guid; + this.templates = templates; } protected RegistrationResult(Parcel in) { guid = in.readString(); + int numTemplates = in.readInt(); + templates = new HashMap<>(numTemplates); + for (int i=0;i < numTemplates; i++){ + BiometricUtils.BiometricIdentifier biometricIdentifier = BiometricUtils.BiometricIdentifier.values()[in.readInt()]; + int templateSize = in.readInt(); + byte[] template = new byte[templateSize]; + in.readByteArray(template); + templates.put(biometricIdentifier, template); + } } public static final Creator CREATOR = new Creator() { @@ -41,12 +61,26 @@ public int describeContents() { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(guid); + dest.writeInt(getNumberOfTemplates()); + for (Map.Entry template : templates.entrySet()){ + dest.writeInt(template.getKey().ordinal()); + dest.writeInt(template.getValue().length); + dest.writeByteArray(template.getValue()); + } } public String getGuid() { return guid; } + public Map getTemplates() { + return templates; + } + + public int getNumberOfTemplates() { + return templates.size(); + } + @Override public boolean equals(Object o) { if (o == this) { @@ -59,12 +93,25 @@ public boolean equals(Object o) { if (!guid.equals(other.guid)) { return false; } + if (getNumberOfTemplates() != other.getNumberOfTemplates()){ + return false; + } + + for (Map.Entry template : templates.entrySet()){ + byte[] otherTemplate = other.getTemplates().get(template.getKey()); + if (!Arrays.equals(template.getValue(), otherTemplate)) { + return false; + } + } return true; } @Override public int hashCode() { int hash = guid.hashCode(); + for (Map.Entry template : templates.entrySet()){ + hash += Arrays.hashCode(template.getValue()); + } return hash; } } From 35902ce5be78cdb76fdaefcdd6342f0c486040c5 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 00:12:30 +0200 Subject: [PATCH 02/22] Add new registrationResponse that support biometrics template --- .../identity/IdentityResponseBuilder.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java index a69f758bc4..0edcc167b4 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java @@ -3,12 +3,14 @@ import android.app.Activity; import android.content.Intent; +import org.commcare.commcaresupportlibrary.BiometricUtils; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; import org.commcare.commcaresupportlibrary.identity.model.RegistrationResult; import org.commcare.commcaresupportlibrary.identity.model.VerificationMatch; import java.util.ArrayList; +import java.util.Map; import static android.app.Activity.RESULT_OK; @@ -41,6 +43,18 @@ public static IdentityResponseBuilder registrationResponse(String guid) { return new IdentityResponseBuilder(intent); } + /** + * Creates response for result of a new Identity Registration with biometric templates + * + * @param templates data captured as part of the new registration in the Identity Provider + * @return IdentityResponseBuilder for a registration workflow response + */ + public static IdentityResponseBuilder registrationResponse(String guid, Map templates) { + Intent intent = new Intent(); + intent.putExtra(REGISTRATION, new RegistrationResult(guid, templates)); + return new IdentityResponseBuilder(intent); + } + /** * Creates response for result of a identification workflow * From e437a585c150191f8970574b918303c980d0c822 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 00:12:44 +0200 Subject: [PATCH 03/22] Add Gson dependency --- commcare-support-library/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commcare-support-library/build.gradle b/commcare-support-library/build.gradle index cb15028124..526f651704 100644 --- a/commcare-support-library/build.gradle +++ b/commcare-support-library/build.gradle @@ -57,6 +57,8 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.google.code.gson:gson:2.9.0' + testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' From 07aae647dc47be6cd91937a08d9e76d92cc2be8d Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 00:13:52 +0200 Subject: [PATCH 04/22] Add Biometrics utility class --- .../BiometricUtils.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java new file mode 100644 index 0000000000..9a81adaf50 --- /dev/null +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java @@ -0,0 +1,35 @@ +package org.commcare.commcaresupportlibrary; + +import android.util.Base64; + +import com.google.gson.Gson; + +import java.util.HashMap; +import java.util.Map; + +public class BiometricUtils { + + public enum BiometricIdentifier { + RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, + LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, + FACE + } + + /** + * This method converts the biometrics templates into a Base64 encoded String to send back to + * CommCare, as part of the response of the callout + * @param templates + * @return Base64 encoded string + */ + public static String convertTemplatesToBase64String(Map templates){ + // In order to reduce the size of the templates, we are converting each byte array into a + // Base64 encoded String + Map templatesBase64Encoded = new HashMap<>(templates.size()); + for (Map.Entry template : templates.entrySet()) { + templatesBase64Encoded.put(template.getKey().ordinal(), + Base64.encodeToString(template.getValue(), Base64.DEFAULT)); + } + String templatesInJson = new Gson().toJson(templatesBase64Encoded); + return Base64.encodeToString(templatesInJson.getBytes(), Base64.DEFAULT); + } +} From 770a9177448f8142d92f852ac9261c25dae57e36 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 00:15:10 +0200 Subject: [PATCH 05/22] Store templates in form --- app/src/org/commcare/provider/IdentityCalloutHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/org/commcare/provider/IdentityCalloutHandler.java b/app/src/org/commcare/provider/IdentityCalloutHandler.java index 3ec7d0359c..aad0ae7413 100644 --- a/app/src/org/commcare/provider/IdentityCalloutHandler.java +++ b/app/src/org/commcare/provider/IdentityCalloutHandler.java @@ -3,6 +3,7 @@ import android.content.Intent; import org.commcare.android.javarosa.IntentCallout; +import org.commcare.commcaresupportlibrary.BiometricUtils; import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; @@ -36,7 +37,7 @@ public class IdentityCalloutHandler { private static final String REF_MATCH_STRENGTH = "match_strength"; public static final String GENERALIZED_IDENTITY_PROVIDER = "generalized_identity_provider"; - + private static final String REF_TEMPLATES = "templates"; @StringDef({GENERALIZED_IDENTITY_PROVIDER, SimprintsCalloutProcessing.SIMPRINTS_IDENTITY_PROVIDER}) @Retention(RetentionPolicy.SOURCE) @@ -109,7 +110,10 @@ private static boolean processRegistrationReponse(FormDef formDef, Hashtable> responseToRefMap) { RegistrationResult registrationResult = intent.getParcelableExtra(IdentityResponseBuilder.REGISTRATION); String guid = registrationResult.getGuid(); + String templates = BiometricUtils.convertTemplatesToBase64String(registrationResult.getTemplates()); + storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_GUID, guid); + storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_TEMPLATES, templates); IntentCallout.setNodeValue(formDef, intentQuestionRef, guid); // Empty out any references present for duplicate handling From 8562c78d6b44963b35b9f40e103e49b4a6e0860f Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 11:17:47 +0200 Subject: [PATCH 06/22] Add method to convert Base64 string to map --- .../BiometricUtils.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java index 9a81adaf50..8fee262b42 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java @@ -3,6 +3,8 @@ import android.util.Base64; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; import java.util.HashMap; import java.util.Map; @@ -32,4 +34,34 @@ public static String convertTemplatesToBase64String(Map convertBase64StringTemplatesToMap(String base64EncodedTemplates){ + if (base64EncodedTemplates == null || base64EncodedTemplates.isEmpty()) { + return null; + } + + Map templatesBase64Encoded = null; + try { + String templatesInJson = new String(Base64.decode(base64EncodedTemplates.getBytes(), + Base64.DEFAULT)); + templatesBase64Encoded = new Gson().fromJson(templatesInJson, + (new TypeToken>() {}.getType())); + } + catch(IllegalArgumentException | UnsupportedOperationException | JsonSyntaxException e){ + return null; + } + + Map templates + = new HashMap<>(templatesBase64Encoded.size()); + for (Map.Entry template : templatesBase64Encoded.entrySet()) { + templates.put(BiometricIdentifier.values()[template.getKey()], + Base64.decode(template.getValue(), Base64.DEFAULT)); + } + return templates; + } } From 752c3cbf7153c6cd35792c91862ec587b8ef28eb Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 11:18:48 +0200 Subject: [PATCH 07/22] Refactor --- app/src/org/commcare/provider/IdentityCalloutHandler.java | 2 +- .../org/commcare/commcaresupportlibrary/BiometricUtils.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/org/commcare/provider/IdentityCalloutHandler.java b/app/src/org/commcare/provider/IdentityCalloutHandler.java index aad0ae7413..0c02aaa406 100644 --- a/app/src/org/commcare/provider/IdentityCalloutHandler.java +++ b/app/src/org/commcare/provider/IdentityCalloutHandler.java @@ -110,7 +110,7 @@ private static boolean processRegistrationReponse(FormDef formDef, Hashtable> responseToRefMap) { RegistrationResult registrationResult = intent.getParcelableExtra(IdentityResponseBuilder.REGISTRATION); String guid = registrationResult.getGuid(); - String templates = BiometricUtils.convertTemplatesToBase64String(registrationResult.getTemplates()); + String templates = BiometricUtils.convertMapTemplatesToBase64String(registrationResult.getTemplates()); storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_GUID, guid); storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_TEMPLATES, templates); diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java index 8fee262b42..6629f83c34 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java @@ -20,10 +20,11 @@ public enum BiometricIdentifier { /** * This method converts the biometrics templates into a Base64 encoded String to send back to * CommCare, as part of the response of the callout - * @param templates + * @param templates Map containing biometric templates * @return Base64 encoded string */ - public static String convertTemplatesToBase64String(Map templates){ + public static String convertMapTemplatesToBase64String(Map templates){ // In order to reduce the size of the templates, we are converting each byte array into a // Base64 encoded String Map templatesBase64Encoded = new HashMap<>(templates.size()); From 4a79c49079eb7d45de5e4036e0db542993fe76f5 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 30 Aug 2023 11:21:44 +0200 Subject: [PATCH 08/22] Update biometric identifiers --- .../org/commcare/commcaresupportlibrary/BiometricUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java index 6629f83c34..ed62843c63 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java @@ -14,7 +14,7 @@ public class BiometricUtils { public enum BiometricIdentifier { RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, - FACE + FACE, UNKNOWN, INVALID } /** From 8072f09e14e7dca1e1347df997e315413171710c Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Fri, 1 Sep 2023 16:43:51 +0200 Subject: [PATCH 09/22] Refactor --- .../BiometricIdentifier.java | 7 +++++ .../BiometricUtils.java | 28 ++++++++----------- .../identity/IdentityResponseBuilder.java | 4 +-- .../identity/model/RegistrationResult.java | 17 +++++------ 4 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java new file mode 100644 index 0000000000..3db4ace664 --- /dev/null +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java @@ -0,0 +1,7 @@ +package org.commcare.commcaresupportlibrary; + +public enum BiometricIdentifier { + RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, + LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, + FACE, UNKNOWN, INVALID +} diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java index ed62843c63..ae7d214755 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java @@ -6,29 +6,25 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; public class BiometricUtils { - public enum BiometricIdentifier { - RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, - LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, - FACE, UNKNOWN, INVALID - } - /** * This method converts the biometrics templates into a Base64 encoded String to send back to * CommCare, as part of the response of the callout + * * @param templates Map containing biometric templates * @return Base64 encoded string */ - public static String convertMapTemplatesToBase64String(Map templates){ + public static String convertMapTemplatesToBase64String(Map templates) { // In order to reduce the size of the templates, we are converting each byte array into a // Base64 encoded String Map templatesBase64Encoded = new HashMap<>(templates.size()); - for (Map.Entry template : templates.entrySet()) { + for (Map.Entry template : templates.entrySet()) { templatesBase64Encoded.put(template.getKey().ordinal(), Base64.encodeToString(template.getValue(), Base64.DEFAULT)); } @@ -38,10 +34,12 @@ public static String convertMapTemplatesToBase64String(Map convertBase64StringTemplatesToMap(String base64EncodedTemplates){ + public static Map convertBase64StringTemplatesToMap( + String base64EncodedTemplates) { if (base64EncodedTemplates == null || base64EncodedTemplates.isEmpty()) { return null; } @@ -50,15 +48,13 @@ public static Map convertBase64Strin try { String templatesInJson = new String(Base64.decode(base64EncodedTemplates.getBytes(), Base64.DEFAULT)); - templatesBase64Encoded = new Gson().fromJson(templatesInJson, - (new TypeToken>() {}.getType())); - } - catch(IllegalArgumentException | UnsupportedOperationException | JsonSyntaxException e){ + Type mapType = new TypeToken>() {}.getType(); + templatesBase64Encoded = new Gson().fromJson(templatesInJson, mapType); + } catch (IllegalArgumentException | UnsupportedOperationException | JsonSyntaxException e) { return null; } - Map templates - = new HashMap<>(templatesBase64Encoded.size()); + Map templates = new HashMap<>(templatesBase64Encoded.size()); for (Map.Entry template : templatesBase64Encoded.entrySet()) { templates.put(BiometricIdentifier.values()[template.getKey()], Base64.decode(template.getValue(), Base64.DEFAULT)); diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java index 0edcc167b4..7de7a1df9e 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java @@ -3,7 +3,7 @@ import android.app.Activity; import android.content.Intent; -import org.commcare.commcaresupportlibrary.BiometricUtils; +import org.commcare.commcaresupportlibrary.BiometricIdentifier; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; import org.commcare.commcaresupportlibrary.identity.model.RegistrationResult; @@ -49,7 +49,7 @@ public static IdentityResponseBuilder registrationResponse(String guid) { * @param templates data captured as part of the new registration in the Identity Provider * @return IdentityResponseBuilder for a registration workflow response */ - public static IdentityResponseBuilder registrationResponse(String guid, Map templates) { + public static IdentityResponseBuilder registrationResponse(String guid, Map templates) { Intent intent = new Intent(); intent.putExtra(REGISTRATION, new RegistrationResult(guid, templates)); return new IdentityResponseBuilder(intent); diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java index 12f2dd109a..649322078b 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java @@ -2,7 +2,8 @@ import android.os.Parcel; import android.os.Parcelable; -import org.commcare.commcaresupportlibrary.BiometricUtils; + +import org.commcare.commcaresupportlibrary.BiometricIdentifier; import java.util.Arrays; import java.util.HashMap; @@ -11,7 +12,7 @@ @SuppressWarnings("unused") public class RegistrationResult implements Parcelable { private String guid; - private Map templates; + private Map templates; /** * Result of the identity enrollment workflow @@ -23,7 +24,7 @@ public RegistrationResult(String guid) { this.templates = new HashMap<>(0); } - public RegistrationResult(String guid, Map templates) { + public RegistrationResult(String guid, Map templates) { this.guid = guid; this.templates = templates; } @@ -33,7 +34,7 @@ protected RegistrationResult(Parcel in) { int numTemplates = in.readInt(); templates = new HashMap<>(numTemplates); for (int i=0;i < numTemplates; i++){ - BiometricUtils.BiometricIdentifier biometricIdentifier = BiometricUtils.BiometricIdentifier.values()[in.readInt()]; + BiometricIdentifier biometricIdentifier = BiometricIdentifier.values()[in.readInt()]; int templateSize = in.readInt(); byte[] template = new byte[templateSize]; in.readByteArray(template); @@ -62,7 +63,7 @@ public int describeContents() { public void writeToParcel(Parcel dest, int flags) { dest.writeString(guid); dest.writeInt(getNumberOfTemplates()); - for (Map.Entry template : templates.entrySet()){ + for (Map.Entry template : templates.entrySet()){ dest.writeInt(template.getKey().ordinal()); dest.writeInt(template.getValue().length); dest.writeByteArray(template.getValue()); @@ -73,7 +74,7 @@ public String getGuid() { return guid; } - public Map getTemplates() { + public Map getTemplates() { return templates; } @@ -97,7 +98,7 @@ public boolean equals(Object o) { return false; } - for (Map.Entry template : templates.entrySet()){ + for (Map.Entry template : templates.entrySet()){ byte[] otherTemplate = other.getTemplates().get(template.getKey()); if (!Arrays.equals(template.getValue(), otherTemplate)) { return false; @@ -109,7 +110,7 @@ public boolean equals(Object o) { @Override public int hashCode() { int hash = guid.hashCode(); - for (Map.Entry template : templates.entrySet()){ + for (Map.Entry template : templates.entrySet()){ hash += Arrays.hashCode(template.getValue()); } return hash; From b01cf21a37e71000f6681d00c674bdb660b4b927 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Sat, 2 Sep 2023 00:26:10 +0200 Subject: [PATCH 10/22] Add Tests around registration with templates --- .../identity_callouts/default/app_strings.txt | 5 +- .../identity_callouts/en/app_strings.txt | 1 + .../identity_callouts/media_suite.xml | 2 +- .../identity_callouts/modules-0/forms-0.xml | 147 +++++++++++------- .../identity_callouts/modules-0/forms-1.xml | 66 ++++++++ .../identity_callouts/profile.ccpr | 31 ++-- .../commcare-apps/identity_callouts/suite.xml | 26 +++- .../tests/formentry/IdentityCalloutTests.kt | 35 +++++ 8 files changed, 231 insertions(+), 82 deletions(-) create mode 100644 app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/default/app_strings.txt b/app/unit-tests/resources/commcare-apps/identity_callouts/default/app_strings.txt index 90164a5a0f..89742f0f58 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/default/app_strings.txt +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/default/app_strings.txt @@ -10,8 +10,9 @@ case_autoload.raw.case_missing=Unable to find case referenced by auto-select cas case_autoload.raw.property_missing=The custom xpath expression specified for case auto-selecting could not be found: ${0} case_autoload.user.case_missing=Unable to find case referenced by auto-select case ID. case_autoload.user.property_missing=The user data key specified for case auto-selecting could not be found: ${0} -case_autoload.usercase.case_missing=Unable to find case referenced by auto-select case ID. +case_autoload.usercase.case_missing=This form affects the user case, but no user case id was found. Please contact your supervisor. case_autoload.usercase.property_missing=The user case specified for case auto-selecting could not be found: ${0} +case_search.claimed_case.case_missing=Unable to find the selected case after performing a sync. Please try again. case_sharing.exactly_one_group=The case sharing settings for your user are incorrect. This user must be in exactly one case sharing group. Please contact your supervisor. cchq.case=Case cchq.referral=Referral @@ -23,9 +24,9 @@ cchq.report_name_header=Report Name cchq.reports_last_updated_on=Reports last updated on en=English forms.m0f0=Registration Form +forms.m0f1=Registration with Templates homescreen.title=Identity Integration Test lang.current=en m0.case_long.case_name_1.header=Name m0.case_short.case_name_1.header=Name modules.m0=Case List -usercase.missing_id=This form affects the user case, but no user case id was found. Please contact your supervisor. diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/en/app_strings.txt b/app/unit-tests/resources/commcare-apps/identity_callouts/en/app_strings.txt index 42339f89e5..243b00ab79 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/en/app_strings.txt +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/en/app_strings.txt @@ -8,6 +8,7 @@ cchq.report_menu=Reports cchq.report_name_header=Report Name cchq.reports_last_updated_on=Reports last updated on forms.m0f0=Registration Form +forms.m0f1=Registration with Templates homescreen.title=Identity Integration Test lang.current=en m0.case_long.case_name_1.header=Name diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/media_suite.xml b/app/unit-tests/resources/commcare-apps/identity_callouts/media_suite.xml index 22824b89c8..89b829b6ea 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/media_suite.xml +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/media_suite.xml @@ -1,2 +1,2 @@ - + diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-0.xml b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-0.xml index 29de4d811f..5f3d0618e2 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-0.xml +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-0.xml @@ -1,58 +1,91 @@ - - Registration Form - - - - - - - - - - - - - case - - - - - - - - - - - - - - Registration - - - Verification - - - - - - - - - - - - - - - - - - - - + + Registration Form + + + + + + + + + + + + + + + + + case + + + + + + + + + + + + + + + + + + + + + + + + + + + + Register + + + Verification + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml new file mode 100644 index 0000000000..ec4a534266 --- /dev/null +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml @@ -0,0 +1,66 @@ + + + Registration with Templates + + + + + + + + + + + case + + + + + + + + + + + + + + + + + + + + + + Register + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/profile.ccpr b/app/unit-tests/resources/commcare-apps/identity_callouts/profile.ccpr index fb75ce8dd8..01a2868eed 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/profile.ccpr +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/profile.ccpr @@ -1,6 +1,6 @@ - - - - - + + + + - + @@ -29,17 +29,11 @@ - - - - - - - + @@ -55,20 +49,21 @@ + - + ./suite.xml - https://www.commcarehq.org/a/shubhamgoyaltest/apps/download/844a399d13204c2792e4f81ae878eb7e/suite.xml + https://www.commcarehq.org/a/shubhamgoyaltest/apps/download/4908aeeaceec4c0e8357028418db78f1/suite.xml - + ./media_suite.xml - https://www.commcarehq.org/a/shubhamgoyaltest/apps/download/844a399d13204c2792e4f81ae878eb7e/media_suite.xml + https://www.commcarehq.org/a/shubhamgoyaltest/apps/download/4908aeeaceec4c0e8357028418db78f1/media_suite.xml diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/suite.xml b/app/unit-tests/resources/commcare-apps/identity_callouts/suite.xml index 3206001933..5b8b28ddeb 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/suite.xml +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/suite.xml @@ -1,19 +1,25 @@ - + - + ./modules-0/forms-0.xml ./modules-0/forms-0.xml + + + ./modules-0/forms-1.xml + ./modules-0/forms-1.xml + + - + ./default/app_strings.txt ./default/app_strings.txt - + ./en/app_strings.txt ./en/app_strings.txt @@ -72,10 +78,22 @@ + +
http://openrosa.org/formdesigner/E3900AF4-43AC-435A-B0BB-E043AD9608A1
+ + + + + + + + +
+
diff --git a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt index 3258b001ca..abaefed7e4 100644 --- a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt +++ b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt @@ -16,6 +16,8 @@ import org.commcare.android.resource.installers.XFormAndroidInstaller import org.commcare.android.util.ActivityLaunchUtils import org.commcare.android.util.TestAppInstaller import org.commcare.android.util.TestUtils +import org.commcare.commcaresupportlibrary.BiometricIdentifier +import org.commcare.commcaresupportlibrary.BiometricUtils import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch import org.commcare.commcaresupportlibrary.identity.model.MatchResult @@ -96,6 +98,24 @@ class IdentityCalloutTests { assertEquals(guidToConfidenceMap.elementAt(2), "★★★") } + @Test + fun testRegistrationWithTemplates() { + val formEntryActivity = ActivityLaunchUtils.launchFormEntry("m0-f1") + + var templates : HashMap = + HashMap(2) + templates.put(BiometricIdentifier.LEFT_INDEX_FINGER, + byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58)) + templates.put(BiometricIdentifier.LEFT_MIDDLE_FINGER, + byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126)) + + intendRegistrationWithTemplatesIntent() + performIntentCallout(formEntryActivity) + TestUtils.assertFormValue("/data/guid", "test-case-unique-guid") + TestUtils.assertFormValue("/data/templates", + BiometricUtils.convertMapTemplatesToBase64String(templates)) + } + private fun getIdentificationIntent(): Intent { val identifications = ArrayList() identifications.add(IdentificationMatch("guid-1", MatchResult(80, MatchStrength.FOUR_STARS))) @@ -120,6 +140,21 @@ class IdentityCalloutTests { intending(hasAction("org.commcare.identity.bioenroll")).respondWith(result) } + private fun intendRegistrationWithTemplatesIntent() { + var templates : HashMap = + HashMap(2) + templates.put(BiometricIdentifier.LEFT_INDEX_FINGER, + byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58)) + templates.put(BiometricIdentifier.LEFT_MIDDLE_FINGER, + byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126)) + + val registration = IdentityResponseBuilder + .registrationResponse("test-case-unique-guid", templates) + .build() + val result = Instrumentation.ActivityResult(Activity.RESULT_OK, registration) + intending(hasAction("org.commcare.identity.bioenroll")).respondWith(result) + } + private fun intendDuplicatesDuringRegistration() { val result = Instrumentation.ActivityResult(Activity.RESULT_OK, getIdentificationIntent()) intending(hasAction("org.commcare.identity.bioenroll")).respondWith(result) From 7cbaa5d1b90d4238ba13e3a0cdf08d4f8ffc5a38 Mon Sep 17 00:00:00 2001 From: Ahmad Treptt Vazirna Date: Mon, 4 Sep 2023 10:26:19 +0200 Subject: [PATCH 11/22] Update documentation --- .../commcaresupportlibrary/identity/identity_integration.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md index ea34dd3ec9..741c0d2cc3 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md @@ -20,6 +20,11 @@ Often you will need this generated guid to be passed back to CommCare so that it IdentityResponseBuilder.registrationResponse(guid) .finalizeResponse(activity) ```` +Alternatively, in case the biometric templates are to be stored in CommCare, use the following instead - +```` +IdentityResponseBuilder.registrationResponse(guid, templates) + .finalizeResponse(activity) +```` This creates an appropriate resulting Intent for the Identity registration workflow and finish your activity after setting the response as a result to returning intent. From c19496bced827842183f3daeca51dc425d0ec157 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 5 Sep 2023 23:49:02 +0200 Subject: [PATCH 12/22] Refactor --- .../provider/IdentityCalloutHandler.java | 2 +- .../tests/formentry/IdentityCalloutTests.kt | 26 +++++++------------ .../{ => identity}/BiometricIdentifier.java | 2 +- .../{ => identity}/BiometricUtils.java | 2 +- .../identity/IdentityResponseBuilder.java | 1 - .../identity/model/RegistrationResult.java | 2 +- 6 files changed, 14 insertions(+), 21 deletions(-) rename commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/{ => identity}/BiometricIdentifier.java (82%) rename commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/{ => identity}/BiometricUtils.java (98%) diff --git a/app/src/org/commcare/provider/IdentityCalloutHandler.java b/app/src/org/commcare/provider/IdentityCalloutHandler.java index 0c02aaa406..5a60934b85 100644 --- a/app/src/org/commcare/provider/IdentityCalloutHandler.java +++ b/app/src/org/commcare/provider/IdentityCalloutHandler.java @@ -3,7 +3,7 @@ import android.content.Intent; import org.commcare.android.javarosa.IntentCallout; -import org.commcare.commcaresupportlibrary.BiometricUtils; +import org.commcare.commcaresupportlibrary.identity.BiometricUtils; import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; diff --git a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt index abaefed7e4..d0a1b79f30 100644 --- a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt +++ b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt @@ -16,8 +16,8 @@ import org.commcare.android.resource.installers.XFormAndroidInstaller import org.commcare.android.util.ActivityLaunchUtils import org.commcare.android.util.TestAppInstaller import org.commcare.android.util.TestUtils -import org.commcare.commcaresupportlibrary.BiometricIdentifier -import org.commcare.commcaresupportlibrary.BiometricUtils +import org.commcare.commcaresupportlibrary.identity.BiometricIdentifier +import org.commcare.commcaresupportlibrary.identity.BiometricUtils import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch import org.commcare.commcaresupportlibrary.identity.model.MatchResult @@ -41,6 +41,8 @@ class IdentityCalloutTests { @JvmField var intentsRule = ActivityScenarioRule(FormEntryActivity::class.java) + var templates : HashMap = HashMap(2) + @Before fun setup() { Intents.init() @@ -48,6 +50,12 @@ class IdentityCalloutTests { TestAppInstaller.installAppAndLogin( "jr://resource/commcare-apps/identity_callouts/profile.ccpr", "test", "123") + + // Initialize biometric templates + templates[BiometricIdentifier.LEFT_INDEX_FINGER] = + byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) + templates[BiometricIdentifier.LEFT_MIDDLE_FINGER] = + byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) } @After @@ -102,13 +110,6 @@ class IdentityCalloutTests { fun testRegistrationWithTemplates() { val formEntryActivity = ActivityLaunchUtils.launchFormEntry("m0-f1") - var templates : HashMap = - HashMap(2) - templates.put(BiometricIdentifier.LEFT_INDEX_FINGER, - byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58)) - templates.put(BiometricIdentifier.LEFT_MIDDLE_FINGER, - byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126)) - intendRegistrationWithTemplatesIntent() performIntentCallout(formEntryActivity) TestUtils.assertFormValue("/data/guid", "test-case-unique-guid") @@ -141,13 +142,6 @@ class IdentityCalloutTests { } private fun intendRegistrationWithTemplatesIntent() { - var templates : HashMap = - HashMap(2) - templates.put(BiometricIdentifier.LEFT_INDEX_FINGER, - byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58)) - templates.put(BiometricIdentifier.LEFT_MIDDLE_FINGER, - byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126)) - val registration = IdentityResponseBuilder .registrationResponse("test-case-unique-guid", templates) .build() diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java similarity index 82% rename from commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java rename to commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java index 3db4ace664..239b3eabc3 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricIdentifier.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java @@ -1,4 +1,4 @@ -package org.commcare.commcaresupportlibrary; +package org.commcare.commcaresupportlibrary.identity; public enum BiometricIdentifier { RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java similarity index 98% rename from commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java rename to commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java index ae7d214755..58d95e5a03 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java @@ -1,4 +1,4 @@ -package org.commcare.commcaresupportlibrary; +package org.commcare.commcaresupportlibrary.identity; import android.util.Base64; diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java index 7de7a1df9e..e8cfd628c2 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/IdentityResponseBuilder.java @@ -3,7 +3,6 @@ import android.app.Activity; import android.content.Intent; -import org.commcare.commcaresupportlibrary.BiometricIdentifier; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; import org.commcare.commcaresupportlibrary.identity.model.RegistrationResult; diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java index 649322078b..11e4b2e135 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/model/RegistrationResult.java @@ -3,7 +3,7 @@ import android.os.Parcel; import android.os.Parcelable; -import org.commcare.commcaresupportlibrary.BiometricIdentifier; +import org.commcare.commcaresupportlibrary.identity.BiometricIdentifier; import java.util.Arrays; import java.util.HashMap; From 73d6a98c861ffa373fb7195728375b0ab06bd018 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 5 Sep 2023 23:50:12 +0200 Subject: [PATCH 13/22] Remove unnecessary biometric identifiers --- .../commcaresupportlibrary/identity/BiometricIdentifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java index 239b3eabc3..87f3fbc74c 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java @@ -3,5 +3,5 @@ public enum BiometricIdentifier { RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, - FACE, UNKNOWN, INVALID + FACE } From 9d5df752257e2318ede4b31116c36e8d83ed800c Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Wed, 6 Sep 2023 10:37:03 +0200 Subject: [PATCH 14/22] Refactor --- .../tests/formentry/IdentityCalloutTests.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt index d0a1b79f30..1e020c8a8b 100644 --- a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt +++ b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt @@ -41,7 +41,7 @@ class IdentityCalloutTests { @JvmField var intentsRule = ActivityScenarioRule(FormEntryActivity::class.java) - var templates : HashMap = HashMap(2) + @Before fun setup() { @@ -50,12 +50,6 @@ class IdentityCalloutTests { TestAppInstaller.installAppAndLogin( "jr://resource/commcare-apps/identity_callouts/profile.ccpr", "test", "123") - - // Initialize biometric templates - templates[BiometricIdentifier.LEFT_INDEX_FINGER] = - byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) - templates[BiometricIdentifier.LEFT_MIDDLE_FINGER] = - byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) } @After @@ -110,7 +104,13 @@ class IdentityCalloutTests { fun testRegistrationWithTemplates() { val formEntryActivity = ActivityLaunchUtils.launchFormEntry("m0-f1") - intendRegistrationWithTemplatesIntent() + var templates : HashMap = HashMap(2) + templates[BiometricIdentifier.LEFT_INDEX_FINGER] = + byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) + templates[BiometricIdentifier.LEFT_MIDDLE_FINGER] = + byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) + + intendRegistrationWithTemplatesIntent(templates) performIntentCallout(formEntryActivity) TestUtils.assertFormValue("/data/guid", "test-case-unique-guid") TestUtils.assertFormValue("/data/templates", @@ -141,7 +141,7 @@ class IdentityCalloutTests { intending(hasAction("org.commcare.identity.bioenroll")).respondWith(result) } - private fun intendRegistrationWithTemplatesIntent() { + private fun intendRegistrationWithTemplatesIntent(templates: HashMap) { val registration = IdentityResponseBuilder .registrationResponse("test-case-unique-guid", templates) .build() From 9371986a1273fc05c9b695ef45da41a13ce86fbb Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 26 Sep 2023 15:32:59 +0200 Subject: [PATCH 15/22] Add callout response key to biometric identifiers --- .../identity/BiometricIdentifier.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java index 87f3fbc74c..637c6d599c 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricIdentifier.java @@ -1,7 +1,25 @@ package org.commcare.commcaresupportlibrary.identity; public enum BiometricIdentifier { - RIGHT_THUMB, RIGHT_INDEX_FINGER, RIGHT_MIDDLE_FINGER, RIGHT_RING_FINGER, RIGHT_PINKY_FINGER, - LEFT_THUMB, LEFT_INDEX_FINGER, LEFT_MIDDLE_FINGER, LEFT_RING_FINGER, LEFT_PINKY_FINGER, - FACE + RIGHT_THUMB("right_thumb_template"), + RIGHT_INDEX_FINGER("right_index_finger_template"), + RIGHT_MIDDLE_FINGER("right_middle_finger_template"), + RIGHT_RING_FINGER("right_ring_finger_template"), + RIGHT_PINKY_FINGER("right_pinky_finger_template"), + LEFT_THUMB("left_thumb_template"), + LEFT_INDEX_FINGER("left_index_finger_template"), + LEFT_MIDDLE_FINGER("left_middle_finger_template"), + LEFT_RING_FINGER("left_ring_finger_template"), + LEFT_PINKY_FINGER("left_pinky_finger_template"), + FACE("face_template"); + + private final String calloutResponseKey; + + BiometricIdentifier(String calloutResponseKey) { + this.calloutResponseKey = calloutResponseKey; + } + + public String getCalloutResponseKey() { + return calloutResponseKey; + } } From 1786eb243a3ebebcde20f4570c62281f08f25272 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 26 Sep 2023 15:34:32 +0200 Subject: [PATCH 16/22] Change conversions to work with individual templates instead of a map --- .../identity/BiometricUtils.java | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java index 58d95e5a03..b864f03366 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java @@ -1,64 +1,60 @@ package org.commcare.commcaresupportlibrary.identity; import android.util.Base64; +import android.util.Pair; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; public class BiometricUtils { /** - * This method converts the biometrics templates into a Base64 encoded String to send back to - * CommCare, as part of the response of the callout + * This method converts the biometric template into a Base64 encoded String to send back to + * CommCare, as part of the callout response * - * @param templates Map containing biometric templates + * @param biometricIdentifier indicates the type of biometric element captured + * @param template inputs the biometric template * @return Base64 encoded string */ - public static String convertMapTemplatesToBase64String(Map templates) { - // In order to reduce the size of the templates, we are converting each byte array into a - // Base64 encoded String - Map templatesBase64Encoded = new HashMap<>(templates.size()); - for (Map.Entry template : templates.entrySet()) { - templatesBase64Encoded.put(template.getKey().ordinal(), - Base64.encodeToString(template.getValue(), Base64.DEFAULT)); - } - String templatesInJson = new Gson().toJson(templatesBase64Encoded); + public static String convertTemplateToBase64String(BiometricIdentifier biometricIdentifier, + byte[] template) { + // In order to reduce the size of the outpput, the byte array is converted to Base64 before + // the instantiation of the pair object + Pair templatePairBase64Encoded = new Pair<>(biometricIdentifier.ordinal(), + Base64.encodeToString(template, Base64.DEFAULT)); + String templatesInJson = new Gson().toJson(templatePairBase64Encoded); return Base64.encodeToString(templatesInJson.getBytes(), Base64.DEFAULT); } /** - * This method converts the Base64 encoded biometric templates to its original form + * This method converts the Base64 encoded biometric template to its original form * - * @param base64EncodedTemplates String containing Base64 encoded biometric templates - * @return Map containing biometric templates + * @param base64EncodedTemplatePair String containing a Base64 encoded biometric template + * @return Pair containing the biometric template */ - public static Map convertBase64StringTemplatesToMap( - String base64EncodedTemplates) { - if (base64EncodedTemplates == null || base64EncodedTemplates.isEmpty()) { + public static Pair convertBase64StringToTemplatePair( + String base64EncodedTemplatePair) { + if (base64EncodedTemplatePair == null || base64EncodedTemplatePair.isEmpty()) { return null; } - Map templatesBase64Encoded = null; + Pair templatePairBase64Encoded = null; try { - String templatesInJson = new String(Base64.decode(base64EncodedTemplates.getBytes(), + String templatePairInJson = new String(Base64.decode(base64EncodedTemplatePair.getBytes(), Base64.DEFAULT)); - Type mapType = new TypeToken>() {}.getType(); - templatesBase64Encoded = new Gson().fromJson(templatesInJson, mapType); + Type mapType = new TypeToken>() { + }.getType(); + templatePairBase64Encoded = new Gson().fromJson(templatePairInJson, mapType); } catch (IllegalArgumentException | UnsupportedOperationException | JsonSyntaxException e) { return null; } - Map templates = new HashMap<>(templatesBase64Encoded.size()); - for (Map.Entry template : templatesBase64Encoded.entrySet()) { - templates.put(BiometricIdentifier.values()[template.getKey()], - Base64.decode(template.getValue(), Base64.DEFAULT)); - } - return templates; + Pair template = new Pair<>( + BiometricIdentifier.values()[templatePairBase64Encoded.first], + Base64.decode(templatePairBase64Encoded.second, Base64.DEFAULT)); + return template; } } From 756586fa289c69c28791b4d7b083813d3d5a5daf Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Tue, 26 Sep 2023 15:37:42 +0200 Subject: [PATCH 17/22] Add biometric templates to callout response individually --- .../locales/android_translatable_strings.txt | 3 ++ .../provider/IdentityCalloutHandler.java | 35 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/assets/locales/android_translatable_strings.txt b/app/assets/locales/android_translatable_strings.txt index d710245070..3919fe2dba 100644 --- a/app/assets/locales/android_translatable_strings.txt +++ b/app/assets/locales/android_translatable_strings.txt @@ -864,6 +864,9 @@ intent.callout.unable.to.process=Unable to process callout result intent.callout.activity.missing=Couldn't find intent for callout! intent.callout.not.supported=This intent callout is not supported on this device fingerprints.scanned=Fingerprints scanned: ${0} +intent.callout.biometrics.capture.result.success=All data stored successfully +intent.callout.biometrics.capture.result.fail=No data was stored +intent.callout.biometrics.capture.result.partialfail=Failed to store some data settings.developer.options=Developer Options settings.developer.title=Developer Options diff --git a/app/src/org/commcare/provider/IdentityCalloutHandler.java b/app/src/org/commcare/provider/IdentityCalloutHandler.java index 5a60934b85..a460aa004d 100644 --- a/app/src/org/commcare/provider/IdentityCalloutHandler.java +++ b/app/src/org/commcare/provider/IdentityCalloutHandler.java @@ -1,9 +1,10 @@ package org.commcare.provider; import android.content.Intent; +import android.util.Base64; import org.commcare.android.javarosa.IntentCallout; -import org.commcare.commcaresupportlibrary.identity.BiometricUtils; +import org.commcare.commcaresupportlibrary.identity.BiometricIdentifier; import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder; import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch; import org.commcare.commcaresupportlibrary.identity.model.MatchResult; @@ -24,6 +25,7 @@ import java.util.Collections; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.Vector; import androidx.annotation.StringDef; @@ -37,14 +39,12 @@ public class IdentityCalloutHandler { private static final String REF_MATCH_STRENGTH = "match_strength"; public static final String GENERALIZED_IDENTITY_PROVIDER = "generalized_identity_provider"; - private static final String REF_TEMPLATES = "templates"; @StringDef({GENERALIZED_IDENTITY_PROVIDER, SimprintsCalloutProcessing.SIMPRINTS_IDENTITY_PROVIDER}) @Retention(RetentionPolicy.SOURCE) public @interface IdentityProvider { } - public static boolean isIdentityCalloutResponse(Intent intent) { return isRegistrationResponse(intent) || isVerificationResponse(intent) || isIdentificationResponse(intent); } @@ -110,11 +110,34 @@ private static boolean processRegistrationReponse(FormDef formDef, Hashtable> responseToRefMap) { RegistrationResult registrationResult = intent.getParcelableExtra(IdentityResponseBuilder.REGISTRATION); String guid = registrationResult.getGuid(); - String templates = BiometricUtils.convertMapTemplatesToBase64String(registrationResult.getTemplates()); storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_GUID, guid); - storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_TEMPLATES, templates); - IntentCallout.setNodeValue(formDef, intentQuestionRef, guid); + + int numOfTemplatesStored = 0; + int numOfTemplates = 0; + for (Map.Entry template : registrationResult.getTemplates().entrySet()) { + boolean success = storeValueFromCalloutInForm(formDef, responseToRefMap, + intentQuestionRef, + template.getKey().getCalloutResponseKey(), + Base64.encodeToString(template.getValue(), Base64.DEFAULT)); + if (success) { + numOfTemplatesStored++; + } + numOfTemplates++; + } + + String result = ""; + if (registrationResult.getTemplates().isEmpty() || (numOfTemplates == numOfTemplatesStored)) { + result = Localization.get("intent.callout.biometrics.capture.result.success"); + } else if (numOfTemplates > 0) { + if (numOfTemplatesStored == 0) { + result = Localization.get("intent.callout.biometrics.capture.result.fail"); + } else { + result = Localization.get("intent.callout.biometrics.capture.result.partialfail"); + } + } + + IntentCallout.setNodeValue(formDef, intentQuestionRef, result); // Empty out any references present for duplicate handling storeValueFromCalloutInForm(formDef, responseToRefMap, intentQuestionRef, REF_MATCH_GUID, ""); From 2128bd8d7f0d3d60d36b3a4ae6ee8be48842922d Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Sat, 30 Sep 2023 00:26:45 +0200 Subject: [PATCH 18/22] Add method to retrieve value from form question --- .../src/org/commcare/android/util/TestUtils.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/unit-tests/src/org/commcare/android/util/TestUtils.java b/app/unit-tests/src/org/commcare/android/util/TestUtils.java index 01e7c0712a..86c04d4af6 100644 --- a/app/unit-tests/src/org/commcare/android/util/TestUtils.java +++ b/app/unit-tests/src/org/commcare/android/util/TestUtils.java @@ -47,6 +47,7 @@ import org.javarosa.test_utils.ExprEvalUtils; import org.javarosa.xml.util.InvalidStructureException; import org.javarosa.xml.util.UnfullfilledRequirementsException; +import org.javarosa.xpath.parser.XPathSyntaxException; import org.robolectric.RuntimeEnvironment; import org.xmlpull.v1.XmlPullParserException; @@ -362,7 +363,7 @@ private static EvaluationContext buildContextWithInstances(UserSandbox sandbox, return new EvaluationContext(null, instances); } - public static void assertFormValue(String expr, Object expectedValue){ + public static void assertFormValue(String expr, Object expectedValue) { FormDef formDef = FormEntryActivity.mFormController.getFormEntryController().getModel().getForm(); FormInstance instance = formDef.getMainInstance(); @@ -370,4 +371,11 @@ public static void assertFormValue(String expr, Object expectedValue){ errorMsg = ExprEvalUtils.expectedEval(expr, instance, null, expectedValue, null); assertTrue(errorMsg, "".equals(errorMsg)); } + + public static Object getFormValue(String expr) throws XPathSyntaxException { + FormDef formDef = FormEntryActivity.mFormController.getFormEntryController().getModel().getForm(); + FormInstance instance = formDef.getMainInstance(); + EvaluationContext ec = new EvaluationContext(instance); + return ExprEvalUtils.xpathEval(ec, expr); + } } From e81b21b8afcc47968eb929efc08e236ee995582f Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Sat, 30 Sep 2023 00:29:52 +0200 Subject: [PATCH 19/22] Update tests --- .../identity_callouts/modules-0/forms-1.xml | 9 ++++-- .../tests/formentry/IdentityCalloutTests.kt | 28 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml index ec4a534266..03050af4c6 100644 --- a/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml +++ b/app/unit-tests/resources/commcare-apps/identity_callouts/modules-0/forms-1.xml @@ -6,7 +6,8 @@ - + + @@ -29,7 +30,8 @@ - + + @@ -55,7 +57,8 @@ - + + diff --git a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt index 1e020c8a8b..954475a607 100644 --- a/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt +++ b/app/unit-tests/src/org/commcare/android/tests/formentry/IdentityCalloutTests.kt @@ -3,6 +3,7 @@ package org.commcare.android.tests.formentry import android.app.Activity import android.app.Instrumentation import android.content.Intent +import android.util.Base64 import android.widget.Button import android.widget.ImageButton import androidx.test.espresso.intent.Intents @@ -17,7 +18,6 @@ import org.commcare.android.util.ActivityLaunchUtils import org.commcare.android.util.TestAppInstaller import org.commcare.android.util.TestUtils import org.commcare.commcaresupportlibrary.identity.BiometricIdentifier -import org.commcare.commcaresupportlibrary.identity.BiometricUtils import org.commcare.commcaresupportlibrary.identity.IdentityResponseBuilder import org.commcare.commcaresupportlibrary.identity.model.IdentificationMatch import org.commcare.commcaresupportlibrary.identity.model.MatchResult @@ -25,6 +25,7 @@ import org.commcare.commcaresupportlibrary.identity.model.MatchStrength import org.commcare.dalvik.R import org.commcare.provider.IdentityCalloutHandler import org.junit.After +import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule @@ -42,7 +43,6 @@ class IdentityCalloutTests { var intentsRule = ActivityScenarioRule(FormEntryActivity::class.java) - @Before fun setup() { Intents.init() @@ -104,17 +104,27 @@ class IdentityCalloutTests { fun testRegistrationWithTemplates() { val formEntryActivity = ActivityLaunchUtils.launchFormEntry("m0-f1") - var templates : HashMap = HashMap(2) + var templates: HashMap = HashMap(2) templates[BiometricIdentifier.LEFT_INDEX_FINGER] = - byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) + byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) templates[BiometricIdentifier.LEFT_MIDDLE_FINGER] = - byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) + byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) + // get Identity response and save Base64 encoded template to form question intendRegistrationWithTemplatesIntent(templates) performIntentCallout(formEntryActivity) TestUtils.assertFormValue("/data/guid", "test-case-unique-guid") - TestUtils.assertFormValue("/data/templates", - BiometricUtils.convertMapTemplatesToBase64String(templates)) + for ((key, value) in templates) { + TestUtils.assertFormValue("/data/" + key.calloutResponseKey, + Base64.encodeToString(value, Base64.DEFAULT)) + } + + // retrieve Base64 encoded template from form question, decode and compare with initial + // value + for ((key, value) in templates) { + var base64EncodedTemplate = TestUtils.getFormValue("/data/" + key.calloutResponseKey) as String; + assertArrayEquals(Base64.decode(base64EncodedTemplate, Base64.DEFAULT), value) + } } private fun getIdentificationIntent(): Intent { @@ -143,8 +153,8 @@ class IdentityCalloutTests { private fun intendRegistrationWithTemplatesIntent(templates: HashMap) { val registration = IdentityResponseBuilder - .registrationResponse("test-case-unique-guid", templates) - .build() + .registrationResponse("test-case-unique-guid", templates) + .build() val result = Instrumentation.ActivityResult(Activity.RESULT_OK, registration) intending(hasAction("org.commcare.identity.bioenroll")).respondWith(result) } From 118435a4355c96be984a119f7a9ff79a7201da46 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Sat, 30 Sep 2023 00:41:21 +0200 Subject: [PATCH 20/22] update documentation --- .../identity/identity_integration.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md index 741c0d2cc3..51b48638cb 100644 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md +++ b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/identity_integration.md @@ -20,12 +20,17 @@ Often you will need this generated guid to be passed back to CommCare so that it IdentityResponseBuilder.registrationResponse(guid) .finalizeResponse(activity) ```` -Alternatively, in case the biometric templates are to be stored in CommCare, use the following instead - +Alternatively, in case the biometric templates are to be stored in CommCare, use the following instead: ```` IdentityResponseBuilder.registrationResponse(guid, templates) .finalizeResponse(activity) ```` - +* `templates` is a [`Map`](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html) containing all the biometric templates and whose _keys_ are [`BiometricIdentifier`](BiometricIdentifier.java) elements and _values_ are the actual biometric templates in the form of a byte array. See an example below in `kotlin`: +```` + var templates: HashMap = HashMap(2) + templates[BiometricIdentifier.LEFT_INDEX_FINGER] = byteArrayOf(0, 0, -21, -67, 0, -64, 25, 62, -69, -124, -91, 29, -50, -107, 58) + templates[BiometricIdentifier.LEFT_MIDDLE_FINGER] = byteArrayOf(122, -91, 114, 62, 107, -95, -69, 28, 110, 123, 72, 71, -86, -117, 126) +```` This creates an appropriate resulting Intent for the Identity registration workflow and finish your activity after setting the response as a result to returning intent. From 1d1d4397d31a7374a356386c5b88d7bc152922b1 Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Sat, 30 Sep 2023 00:43:43 +0200 Subject: [PATCH 21/22] Remove BiometricUtils class --- .../identity/BiometricUtils.java | 60 ------------------- 1 file changed, 60 deletions(-) delete mode 100644 commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java diff --git a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java b/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java deleted file mode 100644 index b864f03366..0000000000 --- a/commcare-support-library/src/main/java/org/commcare/commcaresupportlibrary/identity/BiometricUtils.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.commcare.commcaresupportlibrary.identity; - -import android.util.Base64; -import android.util.Pair; - -import com.google.gson.Gson; -import com.google.gson.JsonSyntaxException; -import com.google.gson.reflect.TypeToken; - -import java.lang.reflect.Type; - -public class BiometricUtils { - - /** - * This method converts the biometric template into a Base64 encoded String to send back to - * CommCare, as part of the callout response - * - * @param biometricIdentifier indicates the type of biometric element captured - * @param template inputs the biometric template - * @return Base64 encoded string - */ - public static String convertTemplateToBase64String(BiometricIdentifier biometricIdentifier, - byte[] template) { - // In order to reduce the size of the outpput, the byte array is converted to Base64 before - // the instantiation of the pair object - Pair templatePairBase64Encoded = new Pair<>(biometricIdentifier.ordinal(), - Base64.encodeToString(template, Base64.DEFAULT)); - String templatesInJson = new Gson().toJson(templatePairBase64Encoded); - return Base64.encodeToString(templatesInJson.getBytes(), Base64.DEFAULT); - } - - /** - * This method converts the Base64 encoded biometric template to its original form - * - * @param base64EncodedTemplatePair String containing a Base64 encoded biometric template - * @return Pair containing the biometric template - */ - public static Pair convertBase64StringToTemplatePair( - String base64EncodedTemplatePair) { - if (base64EncodedTemplatePair == null || base64EncodedTemplatePair.isEmpty()) { - return null; - } - - Pair templatePairBase64Encoded = null; - try { - String templatePairInJson = new String(Base64.decode(base64EncodedTemplatePair.getBytes(), - Base64.DEFAULT)); - Type mapType = new TypeToken>() { - }.getType(); - templatePairBase64Encoded = new Gson().fromJson(templatePairInJson, mapType); - } catch (IllegalArgumentException | UnsupportedOperationException | JsonSyntaxException e) { - return null; - } - - Pair template = new Pair<>( - BiometricIdentifier.values()[templatePairBase64Encoded.first], - Base64.decode(templatePairBase64Encoded.second, Base64.DEFAULT)); - return template; - } -} From 7fcc0a36ebd2530dd5aa27ad2f4dda1c6ca1b47c Mon Sep 17 00:00:00 2001 From: Ahmad Vazirna Date: Mon, 2 Oct 2023 23:41:21 +0200 Subject: [PATCH 22/22] Drop GSON library --- commcare-support-library/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/commcare-support-library/build.gradle b/commcare-support-library/build.gradle index 526f651704..883815b058 100644 --- a/commcare-support-library/build.gradle +++ b/commcare-support-library/build.gradle @@ -57,7 +57,6 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' - implementation 'com.google.code.gson:gson:2.9.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2'