From 986ce7131c83d47a63ba1bd51a5b4c6dee4f5b1e Mon Sep 17 00:00:00 2001 From: JNdhlovu Date: Wed, 16 Oct 2024 10:52:40 +0200 Subject: [PATCH 1/2] feat: scale document bitmaps based on available memory (#465) * feat: scale document bitmaps based on available memory * chore: fix docv tests * feat: refactor on capture get memory first * chore: undo test crashlytics * fix: throw oom error when encountered * chore: update changelog * Update CHANGELOG.md Co-authored-by: Ed Fricker <888909+beastawakens@users.noreply.github.com> --------- Co-authored-by: Ed Fricker <888909+beastawakens@users.noreply.github.com> --- CHANGELOG.md | 4 ++ .../main/java/com/smileidentity/util/Util.kt | 3 + .../document/DocumentCaptureViewModel.kt | 68 ++++++++++++++++--- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b70141d..dbfdbd22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Notes +## 10.3.2 + +* Document capture throw OOM when encountered + ## 10.3.1 * Fix insecure object serialization on fragments diff --git a/lib/src/main/java/com/smileidentity/util/Util.kt b/lib/src/main/java/com/smileidentity/util/Util.kt index 503443c7..cdaf3210 100644 --- a/lib/src/main/java/com/smileidentity/util/Util.kt +++ b/lib/src/main/java/com/smileidentity/util/Util.kt @@ -213,6 +213,7 @@ internal fun postProcessImageBitmap( /** * Post-processes the image stored in [file] in-place */ +@Throws(IOException::class, OutOfMemoryError::class) internal fun postProcessImage( file: File, processRotation: Boolean = true, @@ -221,6 +222,8 @@ internal fun postProcessImage( ): File { val options = Options().apply { inMutable = true } val bitmap = BitmapFactory.decodeFile(file.absolutePath, options) + ?: throw IOException("Failed to decode file: ${file.absolutePath}") + return postProcessImageBitmap( bitmap = bitmap, file = file, diff --git a/lib/src/main/java/com/smileidentity/viewmodel/document/DocumentCaptureViewModel.kt b/lib/src/main/java/com/smileidentity/viewmodel/document/DocumentCaptureViewModel.kt index 0c6c435d..afd3aa0d 100644 --- a/lib/src/main/java/com/smileidentity/viewmodel/document/DocumentCaptureViewModel.kt +++ b/lib/src/main/java/com/smileidentity/viewmodel/document/DocumentCaptureViewModel.kt @@ -15,6 +15,7 @@ import com.google.mlkit.vision.objects.ObjectDetection import com.google.mlkit.vision.objects.ObjectDetector import com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions import com.smileidentity.R +import com.smileidentity.SmileIDCrashReporting import com.smileidentity.compose.document.DocumentCaptureSide import com.smileidentity.models.v2.DocumentImageOriginValue import com.smileidentity.models.v2.Metadatum @@ -23,15 +24,20 @@ import com.smileidentity.util.createDocumentFile import com.smileidentity.util.postProcessImage import com.ujizin.camposer.state.CameraState import com.ujizin.camposer.state.ImageCaptureResult +import io.sentry.Breadcrumb +import io.sentry.SentryLevel import java.io.File +import java.io.IOException import kotlin.math.abs import kotlin.time.Duration.Companion.seconds import kotlin.time.TimeSource +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import timber.log.Timber private const val ANALYSIS_SAMPLE_INTERVAL_MS = 350 @@ -148,19 +154,63 @@ class DocumentCaptureViewModel( cameraState.takePicture(documentFile) { result -> when (result) { is ImageCaptureResult.Success -> { - _uiState.update { - it.copy( - documentImageToConfirm = postProcessImage( - documentFile, - desiredAspectRatio = uiState.value.idAspectRatio, - ), - showCaptureInProgress = false, - ) + viewModelScope.launch { + try { + val processedImage = withContext(Dispatchers.Default) { + postProcessImage( + documentFile, + desiredAspectRatio = uiState.value.idAspectRatio, + ) + } + _uiState.update { + it.copy( + documentImageToConfirm = processedImage, + showCaptureInProgress = false, + ) + } + } catch (e: IOException) { + Timber.e(e, "IOException processing captured image") + SmileIDCrashReporting.hub.captureException(e) { + it.level = SentryLevel.INFO + it.addBreadcrumb( + Breadcrumb( + "Smile ID DocumentCaptureViewModel " + + "IOException", + ), + ) + } + _uiState.update { + it.copy(captureError = e, showCaptureInProgress = false) + } + } catch (e: OutOfMemoryError) { + Timber.e(e, "OutOfMemoryError processing captured image") + SmileIDCrashReporting.hub.captureException(e) { + it.level = SentryLevel.INFO + it.addBreadcrumb( + Breadcrumb( + "Smile ID DocumentCaptureViewModel " + + "OutOfMemoryError", + ), + ) + } + _uiState.update { + it.copy(captureError = e, showCaptureInProgress = false) + } + } } } is ImageCaptureResult.Error -> { - Timber.e("Error capturing document", result.throwable) + Timber.e("ImageCaptureResult.Error capturing document", result.throwable) + SmileIDCrashReporting.hub.captureException(result.throwable) { + it.level = SentryLevel.INFO + it.addBreadcrumb( + Breadcrumb( + "Smile ID DocumentCaptureViewModel " + + "ImageCaptureResult.Error", + ), + ) + } _uiState.update { it.copy(captureError = result.throwable, showCaptureInProgress = false) } From 03112e1abb07a06cb74c35afa047222dd9e17278 Mon Sep 17 00:00:00 2001 From: JNdhlovu Date: Thu, 17 Oct 2024 13:32:25 +0200 Subject: [PATCH 2/2] chore: bump sdk version to 10.3.3 (#467) --- lib/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/VERSION b/lib/VERSION index a1b210f5..f1099404 100644 --- a/lib/VERSION +++ b/lib/VERSION @@ -1 +1 @@ -10.3.2-SNAPSHOT +10.3.3-SNAPSHOT