From 155df3fa6f736653b6ef3173c38dd7a5b810bcdc Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Wed, 1 Jul 2026 12:54:37 -0400 Subject: [PATCH] fix(accesskey): don't crash when access-key bitmap render fails Signed-off-by: Brandon McAnsh --- .../app/accesskey/BaseAccessKeyViewModel.kt | 33 ++++++++++++++----- .../com/getcode/libs/qr/QRCodeGenerator.kt | 8 +++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt b/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt index a48f66b69..7ff1e6b7c 100644 --- a/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt +++ b/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt @@ -25,7 +25,9 @@ import com.getcode.theme.GradientSpec import com.getcode.theme.White import com.getcode.ui.utils.toAGColor import com.getcode.util.resources.ResourceHelper +import com.getcode.utils.TraceType import com.getcode.utils.decodeBase64 +import com.getcode.utils.trace import androidx.lifecycle.ViewModel import com.getcode.view.LoadingSuccessState import kotlinx.coroutines.flow.MutableStateFlow @@ -91,15 +93,28 @@ abstract class BaseAccessKeyViewModel( } viewModelScope.launch(dispatchers.IO) { - val accessKeyBitmap = createBitmapForExport(drawBackground = true, words = words, entropyB64 = entropyB64) - val accessKeyBitmapDisplay = createBitmapForExport(drawBackground = false, words, entropyB64) - val accessKeyCroppedBitmap = - Bitmap.createBitmap(accessKeyBitmapDisplay, 0, 500, 1200, 1450) - - uiFlow.update { - it.copy( - accessKeyBitmap = accessKeyBitmap, - accessKeyCroppedBitmap = accessKeyCroppedBitmap + runCatching { + val accessKeyBitmap = createBitmapForExport(drawBackground = true, words = words, entropyB64 = entropyB64) + val accessKeyBitmapDisplay = createBitmapForExport(drawBackground = false, words, entropyB64) + val accessKeyCroppedBitmap = + Bitmap.createBitmap(accessKeyBitmapDisplay, 0, 500, 1200, 1450) + + uiFlow.update { + it.copy( + accessKeyBitmap = accessKeyBitmap, + accessKeyCroppedBitmap = accessKeyCroppedBitmap + ) + } + }.onFailure { error -> + if (error is kotlin.coroutines.cancellation.CancellationException) throw error + // Bitmap rendering can fail on some OEM devices with + // "width and height must be > 0". Report as a non-fatal instead + // of crashing; the UI handles null bitmaps. Refs Bugsnag 6a4528ca. + trace( + tag = "access-key", + message = "Failed to render access key bitmap", + error = error, + type = TraceType.Error, ) } } diff --git a/libs/quickresponse/src/main/kotlin/com/getcode/libs/qr/QRCodeGenerator.kt b/libs/quickresponse/src/main/kotlin/com/getcode/libs/qr/QRCodeGenerator.kt index 1086c832f..475b44d8b 100644 --- a/libs/quickresponse/src/main/kotlin/com/getcode/libs/qr/QRCodeGenerator.kt +++ b/libs/quickresponse/src/main/kotlin/com/getcode/libs/qr/QRCodeGenerator.kt @@ -44,10 +44,12 @@ internal fun generateQr( null } - val matrixWidth = bitmapMatrix?.width ?: size - val matrixHeight = bitmapMatrix?.height ?: size + // Guard against a zero/negative dimension reaching Bitmap.createBitmap, + // which throws IllegalArgumentException("width and height must be > 0"). + val matrixWidth = (bitmapMatrix?.width ?: size).coerceAtLeast(1) + val matrixHeight = (bitmapMatrix?.height ?: size).coerceAtLeast(1) - val newBitmap = createBitmap(bitmapMatrix?.width ?: size, bitmapMatrix?.height ?: size) + val newBitmap = createBitmap(matrixWidth, matrixHeight) val pixels = IntArray(matrixWidth * matrixHeight)