package org.commcare.provider; import android.content.Intent; import android.support.annotation.NonNull; import android.util.Base64; import android.util.Log; import com.simprints.libsimprints.Constants; import com.simprints.libsimprints.FingerIdentifier; import com.simprints.libsimprints.Identification; import com.simprints.libsimprints.Registration; import com.simprints.libsimprints.Tier; import org.javarosa.core.model.FormDef; import org.javarosa.core.model.condition.EvaluationContext; import org.javarosa.core.model.instance.AbstractTreeElement; import org.javarosa.core.model.instance.TreeReference; import org.javarosa.core.services.locale.Localization; import org.javarosa.core.util.OrderedHashtable; import org.commcare.android.javarosa.IntentCallout; import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Vector; /** * Process simprints fingerprint registration and identification callout results. * * @author Phillip Mates (pmates@dimagi.com). */ public class SimprintsCalloutProcessing { private static final String TAG = SimprintsCalloutProcessing.class.getSimpleName(); /** * Fingerprint lookup response from Simprints scanner app. * Idenficiation responses contain a list of top matching Case IDs with an * associated confidence score. */ public static boolean isIdentificationResponse(Intent intent) { return intent.hasExtra(Constants.SIMPRINTS_IDENTIFICATIONS); } /** * Fingerprint registration response from Simprints scanner app. * Registration responses contain fingerprint templates for the scanned fingerprints */ public static boolean isRegistrationResponse(Intent intent) { return intent.hasExtra(Constants.SIMPRINTS_REGISTRATION); } public static OrderedHashtable<String, String> getConfidenceMatchesFromCalloutResponse(Intent intent) { List<Identification> idReadings = (List)intent.getParcelableArrayListExtra(Constants.SIMPRINTS_IDENTIFICATIONS); Collections.sort(idReadings); OrderedHashtable<String, String> guidToConfidenceMap = new OrderedHashtable<>(); for (Identification id : idReadings) { guidToConfidenceMap.put(id.getGuid(), getTierText(id.getTier())); } return guidToConfidenceMap; } private static String getTierText(@NonNull Tier tier) { switch (tier) { case TIER_1: return Localization.get("fingerprint.match.100"); case TIER_2: return Localization.get("fingerprint.match.75"); case TIER_3: return Localization.get("fingerprint.match.50"); case TIER_4: return Localization.get("fingerprint.match.25"); case TIER_5: return Localization.get("fingerprint.match.0"); default: return Localization.get("fingerprint.match.unknown"); } } private static Registration getRegistrationData(Intent intent) { return intent.getParcelableExtra(Constants.SIMPRINTS_REGISTRATION); } public static boolean processRegistrationResponse(FormDef formDef, Intent intent, TreeReference intentQuestionRef, Hashtable<String, Vector<TreeReference>> responseToRefMap) { Registration registration = getRegistrationData(intent); int numOfFingersScanned = 0; for (FingerIdentifier fingerIdentifier : FingerIdentifier.values()) { Vector<TreeReference> fingerRefs = responseToRefMap.get(fingerIdentifier.toString()); if (fingerRefs != null && !fingerRefs.isEmpty()) { byte[] template = registration.getTemplate(fingerIdentifier); storeFingerprintTemplate(formDef, fingerRefs, intentQuestionRef, template); numOfFingersScanned += countTemplateScanned(template); } } String resultMessage = Localization.get("fingerprints.scanned", new String[]{"" + numOfFingersScanned}); IntentCallout.setNodeValue(formDef, intentQuestionRef, resultMessage); return (numOfFingersScanned > 0); } private static int countTemplateScanned(byte[] template) { return (template == null || template.length == 0) ? 0 : 1; } private static void storeFingerprintTemplate(FormDef formDef, Vector<TreeReference> treeRefs, TreeReference contextRef, byte[] digitTemplate) { for (TreeReference ref : treeRefs) { storeFingerprintTemplateAtReference(formDef, ref, contextRef, digitTemplate); } } private static void storeFingerprintTemplateAtReference(FormDef formDef, TreeReference ref, TreeReference contextRef, byte[] digitTemplate) { EvaluationContext context = new EvaluationContext(formDef.getEvaluationContext(), contextRef); TreeReference fullRef = ref.contextualize(contextRef); AbstractTreeElement node = context.resolveReference(fullRef); if (node == null) { Log.e(TAG, "Unable to resolve ref " + ref); return; } int dataType = node.getDataType(); IntentCallout.setValueInFormDef(formDef, fullRef, Base64.encodeToString(digitTemplate, Base64.DEFAULT), dataType); } }