Skip to content

Commit

Permalink
[Identity] Send image_upload analytics (#5245)
Browse files Browse the repository at this point in the history
  • Loading branch information
ccen-stripe committed Jul 6, 2022
1 parent c3f252e commit 17d31c8
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 64 deletions.
Expand Up @@ -198,16 +198,33 @@ internal class IdentityAnalyticsRequestFactory @Inject constructor(
)
)

fun imageUpload(
value: Long,
compressionQuality: Float,
scanType: IdentityScanState.ScanType,
id: String?,
fileName: String?,
fileSize: Long
) = requestFactory.createRequest(
eventName = EVENT_IMAGE_UPLOAD,
additionalParams = additionalParamWithEventMetadata(
PARAM_VALUE to value,
PARAM_COMPRESSION_QUALITY to compressionQuality,
PARAM_SCAN_TYPE to scanType.toParam(),
PARAM_ID to id,
PARAM_FILE_NAME to fileName,
PARAM_FILE_SIZE to fileSize
)
)

private fun IdentityScanState.ScanType.toParam(): String =
when (this) {
IdentityScanState.ScanType.ID_FRONT -> ID
IdentityScanState.ScanType.ID_BACK -> ID
IdentityScanState.ScanType.PASSPORT -> PASSPORT
IdentityScanState.ScanType.DL_FRONT -> DRIVER_LICENSE
IdentityScanState.ScanType.DL_BACK -> DRIVER_LICENSE
else -> {
throw IllegalArgumentException("Unknown type: $this")
}
IdentityScanState.ScanType.SELFIE -> SELFIE
}

private fun IdentityScanState.ScanType.toSide(): String =
Expand All @@ -228,6 +245,7 @@ internal class IdentityAnalyticsRequestFactory @Inject constructor(
const val ID = "id"
const val PASSPORT = "passport"
const val DRIVER_LICENSE = "driver_license"
const val SELFIE = "selfie"
const val FRONT = "front"
const val BACK = "back"

Expand All @@ -245,6 +263,7 @@ internal class IdentityAnalyticsRequestFactory @Inject constructor(
const val EVENT_AVERAGE_FPS = "average_fps"
const val EVENT_MODEL_PERFORMANCE = "model_performance"
const val EVENT_TIME_TO_SCREEN = "time_to_screen"
const val EVENT_IMAGE_UPLOAD = "image_upload"

const val PARAM_EVENT_META_DATA = "event_metadata"
const val PARAM_FROM_FALLBACK_URL = "from_fallback_url"
Expand Down Expand Up @@ -275,14 +294,16 @@ internal class IdentityAnalyticsRequestFactory @Inject constructor(
const val PARAM_NETWORK_TIME = "network_time"
const val PARAM_FROM_SCREEN_NAME = "from_screen_name"
const val PARAM_TO_SCREEN_NAME = "to_screen_name"
const val PARAM_COMPRESSION_QUALITY = "compression_quality"
const val PARAM_ID = "id"
const val PARAM_FILE_NAME = "file_name"
const val PARAM_FILE_SIZE = "file_size"

const val SCREEN_NAME_CONSENT = "consent"
const val SCREEN_NAME_DOC_SELECT = "document_select"
const val SCREEN_NAME_LIVE_CAPTURE = "live_capture"
const val SCREEN_NAME_LIVE_CAPTURE_PASSPORT = "live_capture_passport"
const val SCREEN_NAME_LIVE_CAPTURE_ID = "live_capture_id"
const val SCREEN_NAME_LIVE_CAPTURE_DRIVER_LICENSE = "live_capture_driver_license"
const val SCREEN_NAME_FILE_UPLOAD = "file_upload"
const val SCREEN_NAME_FILE_UPLOAD_PASSPORT = "file_upload_passport"
const val SCREEN_NAME_FILE_UPLOAD_ID = "file_upload_id"
const val SCREEN_NAME_FILE_UPLOAD_DRIVER_LICENSE = "file_upload_driver_license"
Expand Down
Expand Up @@ -258,15 +258,17 @@ internal abstract class IdentityUploadFragment(
uploadResult(
uri = it,
uploadMethod = DocumentUploadParam.UploadMethod.MANUALCAPTURE,
isFront = true
isFront = true,
scanType
)
}
} else if (scanType == backScanType) {
identityUploadViewModel.takePhotoBack(requireContext()) {
uploadResult(
uri = it,
uploadMethod = DocumentUploadParam.UploadMethod.MANUALCAPTURE,
isFront = false
isFront = false,
scanType
)
}
}
Expand All @@ -283,15 +285,17 @@ internal abstract class IdentityUploadFragment(
uploadResult(
uri = it,
uploadMethod = DocumentUploadParam.UploadMethod.FILEUPLOAD,
isFront = true
isFront = true,
scanType
)
}
} else if (scanType == backScanType) {
identityUploadViewModel.chooseImageBack {
uploadResult(
uri = it,
uploadMethod = DocumentUploadParam.UploadMethod.FILEUPLOAD,
isFront = false
isFront = false,
scanType
)
}
}
Expand Down Expand Up @@ -319,7 +323,8 @@ internal abstract class IdentityUploadFragment(
private fun uploadResult(
uri: Uri,
uploadMethod: DocumentUploadParam.UploadMethod,
isFront: Boolean
isFront: Boolean,
scanType: IdentityScanState.ScanType
) {
if (isFront) {
showFrontUploading()
Expand All @@ -331,7 +336,8 @@ internal abstract class IdentityUploadFragment(
uri = uri,
isFront = isFront,
docCapturePage = docCapturePage,
uploadMethod = uploadMethod
uploadMethod = uploadMethod,
scanType = scanType
)
}
}
Expand Down
Expand Up @@ -2,6 +2,7 @@ package com.stripe.android.identity.networking

import android.util.Log
import androidx.annotation.VisibleForTesting
import com.stripe.android.camera.framework.time.Clock
import com.stripe.android.core.exception.APIConnectionException
import com.stripe.android.core.exception.APIException
import com.stripe.android.core.model.StripeFile
Expand Down Expand Up @@ -96,7 +97,8 @@ internal class DefaultIdentityRepository @Inject constructor(
verificationId: String,
ephemeralKey: String,
imageFile: File,
filePurpose: StripeFilePurpose
filePurpose: StripeFilePurpose,
onSuccessExecutionTimeBlock: (Long) -> Unit
): StripeFile = executeRequestWithModelJsonParser(
request = IdentityFileUploadRequest(
fileParams = StripeFileParams(
Expand All @@ -108,7 +110,8 @@ internal class DefaultIdentityRepository @Inject constructor(
),
verificationId = verificationId
),
responseJsonParser = stripeFileJsonParser
responseJsonParser = stripeFileJsonParser,
onSuccessExecutionTimeBlock = onSuccessExecutionTimeBlock
)

override suspend fun downloadModel(modelUrl: String) = runCatching {
Expand Down Expand Up @@ -210,35 +213,42 @@ internal class DefaultIdentityRepository @Inject constructor(

private suspend fun <Response : StripeModel> executeRequestWithModelJsonParser(
request: StripeRequest,
responseJsonParser: ModelJsonParser<Response>
): Response = runCatching {
stripeNetworkClient.executeRequest(
request
)
}.fold(
onSuccess = { response ->
if (response.isError) {
// TODO(ccen) Parse the response code and throw different exceptions
throw APIException(
stripeError = stripeErrorJsonParser.parse(response.responseJson()),
requestId = response.requestId?.value,
statusCode = response.code
)
} else {
responseJsonParser.parse(response.responseJson()) ?: run {
responseJsonParser: ModelJsonParser<Response>,
onSuccessExecutionTimeBlock: (Long) -> Unit = {}
): Response {
val started = Clock.markNow()
return runCatching {
stripeNetworkClient.executeRequest(
request
)
}.fold(
onSuccess = { response ->
if (response.isError) {
// TODO(ccen) Parse the response code and throw different exceptions
throw APIException(
message = "$responseJsonParser returns null for ${response.responseJson()}"
stripeError = stripeErrorJsonParser.parse(response.responseJson()),
requestId = response.requestId?.value,
statusCode = response.code
)
} else {
responseJsonParser.parse(response.responseJson())?.let { response ->
onSuccessExecutionTimeBlock(started.elapsedSince().inMilliseconds.toLong())
response
} ?: run {
throw APIException(
message = "$responseJsonParser returns null for ${response.responseJson()}"
)
}
}
},
onFailure = {
throw APIConnectionException(
"Failed to execute $request",
cause = it
)
}
},
onFailure = {
throw APIConnectionException(
"Failed to execute $request",
cause = it
)
}
)
)
}

internal companion object {
const val SUBMIT = "submit"
Expand Down
Expand Up @@ -52,7 +52,8 @@ internal interface IdentityRepository {
verificationId: String,
ephemeralKey: String,
imageFile: File,
filePurpose: StripeFilePurpose
filePurpose: StripeFilePurpose,
onSuccessExecutionTimeBlock: (Long) -> Unit = {}
): StripeFile

@Throws(
Expand Down

0 comments on commit 17d31c8

Please sign in to comment.