Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Identity] Send image_upload analytics #5245

Merged
merged 1 commit into from Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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