diff --git a/build.gradle b/build.gradle index b6733a5..c3a61e6 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,6 @@ buildscript { apply plugin: "com.android.library" apply plugin: "org.jetbrains.kotlin.android" -apply plugin: "kotlin-parcelize" repositories { google() @@ -21,6 +20,9 @@ repositories { } project.version = "2024.8.1" +ext { + VERSION_CODE = 20240801 +} android { namespace = "com.simprints.libsimprints" @@ -30,8 +32,10 @@ android { minSdkVersion 23 targetSdkVersion 35 - versionCode 2 versionName project.version + // Version code should match the name as it is used in SID + // to determine the most appropriate response data format + versionCode project.property("VERSION_CODE") testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -53,11 +57,14 @@ android { debug { minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + + buildConfigField("Integer", "LIBRARY_VERSION_CODE", "${project.property("VERSION_CODE")}") } release { minifyEnabled false proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" buildConfigField("String", "LIBRARY_PACKAGE_VERSION", "\"${project.version}\"") + buildConfigField("Integer", "LIBRARY_VERSION_CODE", "${project.property("VERSION_CODE")}") } staging { initWith release diff --git a/src/main/java/com/simprints/libsimprints/Constants.kt b/src/main/java/com/simprints/libsimprints/Constants.kt index db99153..74ae0e3 100644 --- a/src/main/java/com/simprints/libsimprints/Constants.kt +++ b/src/main/java/com/simprints/libsimprints/Constants.kt @@ -28,13 +28,15 @@ object Constants { const val SIMPRINTS_SELECTED_GUID_NONE = "none_selected" // Optional extras - const val SIMPRINTS_CALLING_PACKAGE = "packageName" const val SIMPRINTS_BIOMETRIC_DATA_SOURCE = "biometricDataSource" const val SIMPRINTS_METADATA = "metadata" // Optional keys in SIMPRINTS_METADATA const val SIMPRINTS_SUBJECT_AGE = "subjectAge" + // Request meta data added to the intent + const val SIMPRINTS_LIB_VERSION = "versionCode" + // Custom callout parameters for particular integrations: Don't include if not needed const val SIMPRINTS_RESULT_FORMAT = "resultFormat" const val SIMPRINTS_ODK_RESULT_FORMAT_V01 = "ODKv01" @@ -83,6 +85,7 @@ object Constants { // Result extras const val SIMPRINTS_REGISTRATION = "registration" + const val SIMPRINTS_ENROLMENT = "enrolment" const val SIMPRINTS_IDENTIFICATIONS = "identification" const val SIMPRINTS_VERIFICATION = "verification" const val SIMPRINTS_VERIFICATION_SUCCESS = "verificationSuccess" diff --git a/src/main/java/com/simprints/libsimprints/FingerIdentifier.kt b/src/main/java/com/simprints/libsimprints/FingerIdentifier.kt index 2957a38..8f0bcdb 100644 --- a/src/main/java/com/simprints/libsimprints/FingerIdentifier.kt +++ b/src/main/java/com/simprints/libsimprints/FingerIdentifier.kt @@ -1,5 +1,6 @@ package com.simprints.libsimprints +@Deprecated("Used only in a deprecated data class") enum class FingerIdentifier { RIGHT_5TH_FINGER, RIGHT_4TH_FINGER, diff --git a/src/main/java/com/simprints/libsimprints/Identification.kt b/src/main/java/com/simprints/libsimprints/Identification.kt index 065a629..d256492 100644 --- a/src/main/java/com/simprints/libsimprints/Identification.kt +++ b/src/main/java/com/simprints/libsimprints/Identification.kt @@ -1,7 +1,8 @@ -package com.simprints.libsimprints +package com.simprints.libsimprints; +import android.os.Parcel import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import android.os.Parcelable.Creator /** * This constructor creates a new identification @@ -10,7 +11,7 @@ import kotlinx.parcelize.Parcelize * @param confidence An int containing the (matching) confidence * @param tier The tier score derived from the confidence */ -@Parcelize +@Deprecated("Use contracts.data.Identification instead") data class Identification( val guid: String, private val confidence: Int, @@ -24,4 +25,28 @@ data class Identification( confidence < other.confidence -> 1 else -> -1 } + + override fun describeContents(): Int = 0 + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(guid) + dest.writeInt(this.confidence) + dest.writeInt(this.tier.ordinal) + } + + companion object { + @JvmField + val CREATOR = object : Creator { + + override fun createFromParcel(parcel: Parcel): Identification? { + val guid = parcel.readString().orEmpty() + val confidence = parcel.readInt() + val tier = Tier.entries[parcel.readInt()] + + return Identification(guid, confidence, tier) + } + + override fun newArray(p0: Int): Array = arrayOfNulls(p0) + } + } } diff --git a/src/main/java/com/simprints/libsimprints/RefusalForm.kt b/src/main/java/com/simprints/libsimprints/RefusalForm.kt index 8951b8b..567b886 100644 --- a/src/main/java/com/simprints/libsimprints/RefusalForm.kt +++ b/src/main/java/com/simprints/libsimprints/RefusalForm.kt @@ -1,10 +1,38 @@ -package com.simprints.libsimprints +package com.simprints.libsimprints; -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Parcelable.Creator -@Parcelize +@Deprecated("Use contracts.data.RefusalForm instead") data class RefusalForm( val reason: String, val extra: String, -) : Parcelable +) : Parcelable { + + override fun describeContents(): Int { + return 0 + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(reason) + dest.writeString(extra) + } + + companion object { + @JvmField + val CREATOR = object : Creator { + + override fun createFromParcel(parcel: Parcel): RefusalForm? { + val reason = parcel.readString().orEmpty() + val extra = parcel.readString().orEmpty() + + return RefusalForm(reason, extra) + } + + override fun newArray(p0: Int): Array { + return arrayOfNulls(p0) + } + } + } +} diff --git a/src/main/java/com/simprints/libsimprints/Registration.kt b/src/main/java/com/simprints/libsimprints/Registration.kt index ef7194c..a67a620 100644 --- a/src/main/java/com/simprints/libsimprints/Registration.kt +++ b/src/main/java/com/simprints/libsimprints/Registration.kt @@ -1,9 +1,70 @@ package com.simprints.libsimprints +import android.os.Parcel import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import android.os.Parcelable.Creator -@Parcelize -data class Registration( +@Deprecated("Use contracts.data.Enrolment instead") +data class Registration @JvmOverloads constructor( val guid: String, -) : Parcelable + private val templates: MutableMap = mutableMapOf() +) : Parcelable { + + fun setTemplate(fingerId: FingerIdentifier, fingerTemplate: ByteArray) { + templates[fingerId] = fingerTemplate + } + + fun getTemplate(fingerId: FingerIdentifier): ByteArray = templates[fingerId] ?: byteArrayOf() + + override fun describeContents(): Int = 0 + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(guid) + dest.writeInt(templates.size) + + for ((fingerId, fingerTemplate) in templates) { + dest.writeInt(fingerId.ordinal) + dest.writeInt(fingerTemplate.size) + dest.writeByteArray(fingerTemplate) + } + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + guid.hashCode() + result = 31 * result + templates.hashCode() + return result + } + + override fun equals(other: Any?): Boolean { + if (other === this) return true + if (other !is Registration) return false + if (guid != other.guid) return false + for (fingerId in FingerIdentifier.entries) { + if (!templates[fingerId].contentEquals(other.templates[fingerId])) return false + } + return true; + } + + companion object { + @JvmField + val CREATOR = object : Creator { + + override fun createFromParcel(parcel: Parcel): Registration? { + val guid = parcel.readString().orEmpty() + val nbOfTemplates = parcel.readInt() + + val templates = mutableMapOf() + for (i in 0 until nbOfTemplates) { + val fingerId = FingerIdentifier.entries[parcel.readInt()] + val fingerTemplate = ByteArray(parcel.readInt()) + parcel.readByteArray(fingerTemplate) + templates[fingerId] = fingerTemplate + } + return Registration(guid, templates) + } + + override fun newArray(p0: Int): Array = arrayOfNulls(p0) + } + } +} diff --git a/src/main/java/com/simprints/libsimprints/Tier.kt b/src/main/java/com/simprints/libsimprints/Tier.kt index 6d19173..8cf8495 100644 --- a/src/main/java/com/simprints/libsimprints/Tier.kt +++ b/src/main/java/com/simprints/libsimprints/Tier.kt @@ -1,5 +1,6 @@ package com.simprints.libsimprints +@Deprecated("Use contracts.data.Tier instead") enum class Tier { TIER_1, TIER_2, diff --git a/src/main/java/com/simprints/libsimprints/Verification.kt b/src/main/java/com/simprints/libsimprints/Verification.kt index 187ec58..cac27f9 100644 --- a/src/main/java/com/simprints/libsimprints/Verification.kt +++ b/src/main/java/com/simprints/libsimprints/Verification.kt @@ -1,23 +1,40 @@ package com.simprints.libsimprints +import android.os.Parcel import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -/** - * This constructor creates a new verification - * - * @param confidence An int containing the (matching) confidence - * @param tier The tier score derived from the confidence - * @param guid Global unique id of the verified person - */ -@Parcelize +import android.os.Parcelable.Creator + +@SuppressWarnings("unused", "WeakerAccess") +@Deprecated("Use contracts.data.Verification instead") data class Verification @JvmOverloads constructor( private val confidence: Int, val tier: Tier, val guid: String, - // TODO change to val once it is correctly returned from SID - var isSuccess: Boolean = false, ) : Parcelable { fun getConfidence(): Float = confidence.toFloat() + + override fun describeContents(): Int = 0 + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeInt(this.confidence) + dest.writeInt(this.tier.ordinal) + dest.writeString(this.guid) + } + + companion object { + @JvmField + val CREATOR = object : Creator { + + override fun createFromParcel(parcel: Parcel): Verification? { + val confidence = parcel.readInt() + val tier = Tier.entries[parcel.readInt()] + val guid = parcel.readString().orEmpty() + + return Verification(confidence, tier, guid) + } + + override fun newArray(p0: Int): Array = arrayOfNulls(p0) + } + } } diff --git a/src/main/java/com/simprints/libsimprints/contracts/SimprintsRequest.kt b/src/main/java/com/simprints/libsimprints/contracts/SimprintsRequest.kt index f5624d2..505418c 100644 --- a/src/main/java/com/simprints/libsimprints/contracts/SimprintsRequest.kt +++ b/src/main/java/com/simprints/libsimprints/contracts/SimprintsRequest.kt @@ -1,6 +1,7 @@ package com.simprints.libsimprints.contracts import android.content.Intent +import com.simprints.libsimprints.BuildConfig import com.simprints.libsimprints.Constants import com.simprints.libsimprints.Metadata @@ -47,6 +48,7 @@ sealed class SimprintsRequest { override fun toIntent() = Intent(Constants.SIMPRINTS_ENROL_INTENT) .appendAuthFields(projectId, userId) + .appendRequestMetaInformation() .putExtra(Constants.SIMPRINTS_MODULE_ID, moduleId) .appendOptionalMetadata(metadata) } @@ -71,6 +73,7 @@ sealed class SimprintsRequest { ) : SimprintsRequest() { override fun toIntent() = Intent(Constants.SIMPRINTS_IDENTIFY_INTENT) .appendAuthFields(projectId, userId) + .appendRequestMetaInformation() .putExtra(Constants.SIMPRINTS_MODULE_ID, moduleId) .appendOptionalMetadata(metadata) } @@ -97,6 +100,7 @@ sealed class SimprintsRequest { ) : SimprintsRequest() { override fun toIntent() = Intent(Constants.SIMPRINTS_VERIFY_INTENT) .appendAuthFields(projectId, userId) + .appendRequestMetaInformation() .putExtra(Constants.SIMPRINTS_MODULE_ID, moduleId) .putExtra(Constants.SIMPRINTS_VERIFY_GUID, verifyId) .appendOptionalMetadata(metadata) @@ -120,6 +124,7 @@ sealed class SimprintsRequest { ) : SimprintsRequest() { override fun toIntent() = Intent(Constants.SIMPRINTS_CONFIRM_IDENTITY_INTENT) .appendAuthFields(projectId, userId) + .appendRequestMetaInformation() .putExtra(Constants.SIMPRINTS_SESSION_ID, sessionId) .putExtra(Constants.SIMPRINTS_SELECTED_GUID, selectedGuid) } @@ -146,15 +151,19 @@ sealed class SimprintsRequest { ) : SimprintsRequest() { override fun toIntent() = Intent(Constants.SIMPRINTS_ENROL_LAST_BIOMETRICS_INTENT) .appendAuthFields(projectId, userId) + .appendRequestMetaInformation() .putExtra(Constants.SIMPRINTS_MODULE_ID, moduleId) .putExtra(Constants.SIMPRINTS_SESSION_ID, sessionId) .appendOptionalMetadata(metadata) } - protected fun Intent.appendAuthFields(projectId: String, userId: String) = this + protected fun Intent.appendAuthFields(projectId: String, userId: String): Intent = this .putExtra(Constants.SIMPRINTS_PROJECT_ID, projectId) .putExtra(Constants.SIMPRINTS_USER_ID, userId) + protected fun Intent.appendRequestMetaInformation() = this + .putExtra(Constants.SIMPRINTS_LIB_VERSION, BuildConfig.LIBRARY_VERSION_CODE) + protected fun Intent.appendOptionalMetadata(metadata: Metadata?) = if (metadata == null) this else putExtra(Constants.SIMPRINTS_METADATA, metadata.toString()) diff --git a/src/main/java/com/simprints/libsimprints/contracts/SimprintsResponse.kt b/src/main/java/com/simprints/libsimprints/contracts/SimprintsResponse.kt index b2421d7..2da8c1f 100644 --- a/src/main/java/com/simprints/libsimprints/contracts/SimprintsResponse.kt +++ b/src/main/java/com/simprints/libsimprints/contracts/SimprintsResponse.kt @@ -2,10 +2,11 @@ package com.simprints.libsimprints.contracts import android.content.Intent import com.simprints.libsimprints.Constants -import com.simprints.libsimprints.Identification -import com.simprints.libsimprints.RefusalForm -import com.simprints.libsimprints.Registration -import com.simprints.libsimprints.Verification +import com.simprints.libsimprints.contracts.data.Enrolment +import com.simprints.libsimprints.contracts.data.Identification +import com.simprints.libsimprints.contracts.data.RefusalForm +import com.simprints.libsimprints.contracts.data.Verification +import kotlin.let /** * Container class for all possible response data that Simprints ID can return. @@ -25,7 +26,7 @@ data class SimprintsResponse( val sessionId: String? = null, // Request-specific data - only one field will be non-null - val registration: Registration? = null, + val enrolment: Enrolment? = null, val verification: Verification? = null, val identifications: List? = null, val refusal: RefusalForm? = null, @@ -38,60 +39,36 @@ data class SimprintsResponse( @Suppress("UNCHECKED_CAST") @JvmStatic - fun fromIntent(intent: Intent?, resultCode: Int): SimprintsResponse = when { - resultCode != Constants.SIMPRINTS_OK -> SimprintsResponse(resultCode = resultCode) - intent == null -> SimprintsResponse(resultCode = Constants.SIMPRINTS_CANCELLED) + fun fromIntent(intent: Intent?, resultCode: Int): SimprintsResponse { + if (resultCode != Constants.SIMPRINTS_OK) { + return SimprintsResponse(resultCode = resultCode) + } + if (intent == null) { + return SimprintsResponse(resultCode = Constants.SIMPRINTS_CANCELLED) + } - intent.hasExtra(Constants.SIMPRINTS_REFUSAL_FORM) -> SimprintsResponse( + return SimprintsResponse( resultCode = resultCode, biometricsComplete = intent.getBooleanExtra( Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK, false ), sessionId = intent.getStringExtra(Constants.SIMPRINTS_SESSION_ID), - refusal = intent.getParcelableExtra(Constants.SIMPRINTS_REFUSAL_FORM), - ) - intent.hasExtra(Constants.SIMPRINTS_REGISTRATION) -> SimprintsResponse( - resultCode = resultCode, - biometricsComplete = intent.getBooleanExtra( - Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK, - false - ), - sessionId = intent.getStringExtra(Constants.SIMPRINTS_SESSION_ID), - registration = intent.getParcelableExtra(Constants.SIMPRINTS_REGISTRATION), - subjectActions = intent.getStringExtra(Constants.SIMPRINTS_COSYNC_SUBJECT_ACTIONS), - ) + refusal = intent.getStringExtra(Constants.SIMPRINTS_REFUSAL_FORM) + ?.let { RefusalForm.fromJson(it) }, + enrolment = intent + .getStringExtra(Constants.SIMPRINTS_ENROLMENT) + ?.let { Enrolment.fromJson(it) }, + identifications = intent + .getStringExtra(Constants.SIMPRINTS_IDENTIFICATIONS) + ?.let { Identification.fromJson(it) }, + verification = intent + .getStringExtra(Constants.SIMPRINTS_VERIFICATION) + ?.let { Verification.fromJson(it) }, - intent.hasExtra(Constants.SIMPRINTS_IDENTIFICATIONS) -> SimprintsResponse( - resultCode = resultCode, - biometricsComplete = intent.getBooleanExtra( - Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK, - false - ), - sessionId = intent.getStringExtra(Constants.SIMPRINTS_SESSION_ID), - identifications = intent.getParcelableArrayListExtra(Constants.SIMPRINTS_IDENTIFICATIONS) as List?, + subjectActions = intent.getStringExtra(Constants.SIMPRINTS_COSYNC_SUBJECT_ACTIONS), ) - - intent.hasExtra(Constants.SIMPRINTS_VERIFICATION) -> { - val verification = intent.getParcelableExtra(Constants.SIMPRINTS_VERIFICATION) as Verification? - - SimprintsResponse( - resultCode = resultCode, - biometricsComplete = intent.getBooleanExtra( - Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK, - false - ), - sessionId = intent.getStringExtra(Constants.SIMPRINTS_SESSION_ID), - verification = verification?.also { - // In SID 2024.2.0 this value is returned next to the verification object, - // so it needs to be updated on during response parsing - it.isSuccess = intent.getBooleanExtra(Constants.SIMPRINTS_VERIFICATION_SUCCESS, false) - }, - ) - } - - else -> SimprintsResponse(resultCode = Constants.SIMPRINTS_CANCELLED) } } } diff --git a/src/main/java/com/simprints/libsimprints/contracts/VersionsList.kt b/src/main/java/com/simprints/libsimprints/contracts/VersionsList.kt new file mode 100644 index 0000000..a785f20 --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/VersionsList.kt @@ -0,0 +1,17 @@ +package com.simprints.libsimprints.contracts + +/** + * List of versions in which specific changes to external API were introduced. + * + * These constant are mainly for Simprints ID to determine the optimal + * response data format based on the calling app integration version. + */ +object VersionsList { + + /** + * In this version Activity contracts were introduced with a new set of returned data classes. + * The new API uses JSON as marshalling format instead of parcelable to make + * adding and removing data fields simpler. + */ + const val INITIAL_REWORK = 20240801 +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/Enrolment.kt b/src/main/java/com/simprints/libsimprints/contracts/data/Enrolment.kt new file mode 100644 index 0000000..4108071 --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/Enrolment.kt @@ -0,0 +1,20 @@ +package com.simprints.libsimprints.contracts.data + +data class Enrolment( + val guid: String, +) { + + fun toJson(): String = asJsonObject { + it.put(KEY_GUID, guid) + }.toString() + + companion object { + private const val KEY_GUID = "guid" + + fun fromJson(jsonString: String): Enrolment? = fromJsonString(jsonString) { json -> + val guid = json.getString(KEY_GUID) + + Enrolment(guid) + } + } +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/Identification.kt b/src/main/java/com/simprints/libsimprints/contracts/data/Identification.kt new file mode 100644 index 0000000..d8bdb0f --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/Identification.kt @@ -0,0 +1,45 @@ +package com.simprints.libsimprints.contracts.data + +import org.json.JSONArray + +/** + * This constructor creates a new identification + * + * @param guid Global unique id of the verified person + * @param confidence An int containing the (matching) confidence + * @param tier The tier score derived from the confidence + */ +data class Identification( + val guid: String, + val confidence: Float, + val tier: Tier, +) : Comparable { + + override fun compareTo(other: Identification): Int = when { + confidence == other.confidence -> 0 + confidence < other.confidence -> 1 + else -> -1 + } + + companion object { + private const val KEY_GUID = "guid" + private const val KEY_TIER = "tier" + private const val KEY_CONFIDENCE = "confidence" + + fun List.toJson(): String = map { id -> + id.asJsonObject { json -> + json.put(KEY_GUID, id.guid) + json.put(KEY_TIER, id.tier.name) + json.put(KEY_CONFIDENCE, id.confidence) + } + }.let { JSONArray(it) }.toString() + + fun fromJson(jsonString: String): List? = + fromJsonArrayString(jsonString) { json -> + val guid = json.getString(KEY_GUID) + val tier = json.getString(KEY_TIER).let { Tier.valueOf(it) } + val confidence = json.getDouble(KEY_CONFIDENCE).toFloat() + Identification(guid, confidence, tier) + } + } +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/JsonExt.kt b/src/main/java/com/simprints/libsimprints/contracts/data/JsonExt.kt new file mode 100644 index 0000000..cff3f3b --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/JsonExt.kt @@ -0,0 +1,34 @@ +package com.simprints.libsimprints.contracts.data + +import org.json.JSONArray +import org.json.JSONException +import org.json.JSONObject + +internal inline fun T.asJsonObject( + crossinline block: (JSONObject) -> JSONObject, +): JSONObject = JSONObject().also { block(it) } + +internal inline fun fromJsonString( + jsonString: String, + crossinline block: (JSONObject) -> T, +): T? = try { + val json = JSONObject(jsonString) + block(json) +} catch (_: JSONException) { + null +} + +internal inline fun fromJsonArrayString( + jsonString: String, + crossinline block: (JSONObject) -> T, +): List? = try { + val array = JSONArray(jsonString) + val list = mutableListOf() + for (i in 0 until array.length()) { + val json = array.getJSONObject(i) + list.add(block(json)) + } + list +} catch (_: JSONException) { + null +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/RefusalForm.kt b/src/main/java/com/simprints/libsimprints/contracts/data/RefusalForm.kt new file mode 100644 index 0000000..d1f7882 --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/RefusalForm.kt @@ -0,0 +1,25 @@ +package com.simprints.libsimprints.contracts.data + +data class RefusalForm( + val reason: String, + val extra: String, +) { + + fun toJson(): String = asJsonObject { + it.put(KEY_REASON, reason) + it.put(KEY_EXTRA, extra) + }.toString() + + companion object { + private const val KEY_REASON = "reason" + private const val KEY_EXTRA = "extra" + + + fun fromJson(jsonString: String): RefusalForm? = fromJsonString(jsonString) { json -> + val reason = json.getString(KEY_REASON) + val extra = json.getString(KEY_EXTRA) + + RefusalForm(reason, extra) + } + } +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/Tier.kt b/src/main/java/com/simprints/libsimprints/contracts/data/Tier.kt new file mode 100644 index 0000000..c2b7af5 --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/Tier.kt @@ -0,0 +1,9 @@ +package com.simprints.libsimprints.contracts.data + +enum class Tier { + TIER_1, + TIER_2, + TIER_3, + TIER_4, + TIER_5 +} diff --git a/src/main/java/com/simprints/libsimprints/contracts/data/Verification.kt b/src/main/java/com/simprints/libsimprints/contracts/data/Verification.kt new file mode 100644 index 0000000..dcc54fd --- /dev/null +++ b/src/main/java/com/simprints/libsimprints/contracts/data/Verification.kt @@ -0,0 +1,39 @@ +package com.simprints.libsimprints.contracts.data + +/** + * This constructor creates a new identification + * + * @param guid Global unique id of the verified person + * @param confidence An int containing the (matching) confidence + * @param tier The tier score derived from the confidence + */ +data class Verification( + val guid: String, + val confidence: Float, + val tier: Tier, + val isSuccess: Boolean, +) { + + fun toJson(): String = asJsonObject { + it.put(KEY_GUID, guid) + it.put(KEY_TIER, tier.name) + it.put(KEY_CONFIDENCE, confidence) + it.put(KEY_IS_SUCCESS, isSuccess) + }.toString() + + companion object { + private const val KEY_GUID = "guid" + private const val KEY_TIER = "tier" + private const val KEY_CONFIDENCE = "confidence" + private const val KEY_IS_SUCCESS = "isSuccess" + + fun fromJson(jsonString: String): Verification? = fromJsonString(jsonString) { json -> + val guid = json.getString(KEY_GUID) + val tier = json.getString(KEY_TIER).let { Tier.valueOf(it) } + val confidence = json.getDouble(KEY_CONFIDENCE).toFloat() + val isSuccess = json.getBoolean(KEY_IS_SUCCESS) + + Verification(guid, confidence, tier, isSuccess) + } + } +} diff --git a/src/test/java/com/simprints/libsimprints/VerificationTest.kt b/src/test/java/com/simprints/libsimprints/VerificationTest.kt index c6b9dfe..52a9975 100644 --- a/src/test/java/com/simprints/libsimprints/VerificationTest.kt +++ b/src/test/java/com/simprints/libsimprints/VerificationTest.kt @@ -13,7 +13,7 @@ class VerificationTest { @Test fun `test verification parcelling`() { - val expected = Verification(42, Tier.TIER_2, "case-id", true) + val expected = Verification(42, Tier.TIER_2, "case-id") val actual = bundleOf("test" to expected).getParcelable("test") assertEquals(expected, actual) @@ -21,7 +21,7 @@ class VerificationTest { @Test fun `test verification confidence`() { - val verification = Verification(42, Tier.TIER_2, "case-id", true) + val verification = Verification(42, Tier.TIER_2, "case-id") assertEquals(42.0f, verification.getConfidence()) } diff --git a/src/test/java/com/simprints/libsimprints/contracts/SimprintsResponseTest.kt b/src/test/java/com/simprints/libsimprints/contracts/SimprintsResponseTest.kt index 717b393..f05cda8 100644 --- a/src/test/java/com/simprints/libsimprints/contracts/SimprintsResponseTest.kt +++ b/src/test/java/com/simprints/libsimprints/contracts/SimprintsResponseTest.kt @@ -3,11 +3,12 @@ package com.simprints.libsimprints.contracts import android.content.Intent import androidx.test.ext.junit.runners.AndroidJUnit4 import com.simprints.libsimprints.Constants -import com.simprints.libsimprints.Identification -import com.simprints.libsimprints.RefusalForm -import com.simprints.libsimprints.Registration -import com.simprints.libsimprints.Tier -import com.simprints.libsimprints.Verification +import com.simprints.libsimprints.contracts.data.Enrolment +import com.simprints.libsimprints.contracts.data.Identification +import com.simprints.libsimprints.contracts.data.Identification.Companion.toJson +import com.simprints.libsimprints.contracts.data.RefusalForm +import com.simprints.libsimprints.contracts.data.Tier +import com.simprints.libsimprints.contracts.data.Verification import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -35,69 +36,76 @@ class SimprintsResponseTest { @Test fun `correctly parses error result intent`() { - val intent = Intent() + val intent = Intent().putExtra( // This should be ignored in final data - .putExtra(Constants.SIMPRINTS_REFUSAL_FORM, RefusalForm("reason", "action")) + Constants.SIMPRINTS_REFUSAL_FORM, + RefusalForm("reason", "action").toJson() + ) val result = SimprintsResponse.fromIntent(intent, Constants.SIMPRINTS_UNEXPECTED_ERROR) assertEquals(Constants.SIMPRINTS_UNEXPECTED_ERROR, result.resultCode) assertNull(result.refusal) - assertNull(result.registration) + assertNull(result.enrolment) assertNull(result.identifications) assertNull(result.verification) } @Test fun `correctly parses refusal intent`() { - val intent = Intent() - .putExtra(Constants.SIMPRINTS_REFUSAL_FORM, RefusalForm("reason", "action")) + val intent = Intent().putExtra( + Constants.SIMPRINTS_REFUSAL_FORM, + RefusalForm("reason", "action").toJson() + ) val result = SimprintsResponse.fromIntent(intent, Constants.SIMPRINTS_OK) assertEquals(Constants.SIMPRINTS_OK, result.resultCode) assertNotNull(result.refusal) - assertNull(result.registration) + assertNull(result.enrolment) assertNull(result.identifications) assertNull(result.verification) } @Test fun `correctly parses enrolment intent`() { - val intent = Intent() - .putExtra(Constants.SIMPRINTS_REGISTRATION, Registration("guid")) + val intent = Intent().putExtra( + Constants.SIMPRINTS_ENROLMENT, + Enrolment("guid").toJson() + ) val result = SimprintsResponse.fromIntent(intent, Constants.SIMPRINTS_OK) assertEquals(Constants.SIMPRINTS_OK, result.resultCode) assertNull(result.refusal) - assertNotNull(result.registration) + assertNotNull(result.enrolment) assertNull(result.identifications) assertNull(result.verification) } @Test fun `correctly parses identification intent`() { - val intent = Intent() - .putExtra( - Constants.SIMPRINTS_IDENTIFICATIONS, - arrayListOf(Identification("guid", 42, Tier.TIER_1)) - ) + val intent = Intent().putExtra( + Constants.SIMPRINTS_IDENTIFICATIONS, + listOf(Identification("guid", 42f, Tier.TIER_1)).toJson() + ) val result = SimprintsResponse.fromIntent(intent, Constants.SIMPRINTS_OK) assertEquals(Constants.SIMPRINTS_OK, result.resultCode) assertNull(result.refusal) - assertNull(result.registration) + assertNull(result.enrolment) assertNotNull(result.identifications) assertNull(result.verification) } @Test fun `correctly parses verification intent`() { - val intent = Intent() - .putExtra(Constants.SIMPRINTS_VERIFICATION, Verification(42, Tier.TIER_1, "guid")) + val intent = Intent().putExtra( + Constants.SIMPRINTS_VERIFICATION, + Verification("guid", 42f, Tier.TIER_1, true).toJson() + ) val result = SimprintsResponse.fromIntent(intent, Constants.SIMPRINTS_OK) assertEquals(Constants.SIMPRINTS_OK, result.resultCode) assertNull(result.refusal) - assertNull(result.registration) + assertNull(result.enrolment) assertNull(result.identifications) assertNotNull(result.verification) } diff --git a/src/test/java/com/simprints/libsimprints/contracts/data/EnrolmentTest.kt b/src/test/java/com/simprints/libsimprints/contracts/data/EnrolmentTest.kt new file mode 100644 index 0000000..49d9425 --- /dev/null +++ b/src/test/java/com/simprints/libsimprints/contracts/data/EnrolmentTest.kt @@ -0,0 +1,19 @@ +package com.simprints.libsimprints.contracts.data; + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(AndroidJUnit4::class) +class EnrolmentTest { + + @Test + fun `test enrolment parcelling`() { + val expected = Enrolment("case-id") + val actual = Enrolment.fromJson(expected.toJson()) + + assertEquals(expected, actual) + } +} diff --git a/src/test/java/com/simprints/libsimprints/contracts/data/IdentificationTest.kt b/src/test/java/com/simprints/libsimprints/contracts/data/IdentificationTest.kt new file mode 100644 index 0000000..8e9a044 --- /dev/null +++ b/src/test/java/com/simprints/libsimprints/contracts/data/IdentificationTest.kt @@ -0,0 +1,25 @@ +package com.simprints.libsimprints.contracts.data + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.simprints.libsimprints.contracts.data.Identification.Companion.toJson +import junit.framework.TestCase.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class IdentificationTest { + + @Test + fun `test enrolment parcelling`() { + val expected = listOf( + Identification("case1", 99f, Tier.TIER_1), + Identification("case2", 70f, Tier.TIER_2), + Identification("case3", 50f, Tier.TIER_3), + Identification("case4", 30f, Tier.TIER_4), + Identification("case5", 10f, Tier.TIER_5), + ) + val actual = Identification.fromJson(expected.toJson()) + + assertEquals(expected, actual) + } +} diff --git a/src/test/java/com/simprints/libsimprints/contracts/data/RefusalFormTest.kt b/src/test/java/com/simprints/libsimprints/contracts/data/RefusalFormTest.kt new file mode 100644 index 0000000..595db6a --- /dev/null +++ b/src/test/java/com/simprints/libsimprints/contracts/data/RefusalFormTest.kt @@ -0,0 +1,18 @@ +package com.simprints.libsimprints.contracts.data + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class RefusalFormTest { + + @Test + fun `test refusal parcelling`() { + val expected = RefusalForm("reason", "extra") + val actual = RefusalForm.fromJson(expected.toJson()) + + Assert.assertEquals(expected, actual) + } +} diff --git a/src/test/java/com/simprints/libsimprints/contracts/data/VerificationTest.kt b/src/test/java/com/simprints/libsimprints/contracts/data/VerificationTest.kt new file mode 100644 index 0000000..57b1ce4 --- /dev/null +++ b/src/test/java/com/simprints/libsimprints/contracts/data/VerificationTest.kt @@ -0,0 +1,18 @@ +package com.simprints.libsimprints.contracts.data + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class VerificationTest { + + @Test + fun `test verification parcelling`() { + val expected = Verification("case-id", 42f, Tier.TIER_4, false) + val actual = Verification.fromJson(expected.toJson()) + + Assert.assertEquals(expected, actual) + } +}