From ecfa053497521c5fae4cb4ec1f7a7bac470d4024 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 15 Sep 2026 15:45:32 -0400 Subject: [PATCH] Fix crash when scanning a QR code from a non-ARGB_8888 image. --- .../usernamelinks/main/UsernameQrScanRepository.kt | 12 ++++++++++++ lib/qr/src/main/java/org/signal/qr/QrProcessor.kt | 7 +++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt index a71a72f382..4f704b2f21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameQrScanRepository.kt @@ -12,16 +12,20 @@ import com.bumptech.glide.load.DecodeFormat import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.schedulers.Schedulers +import org.signal.core.util.logging.Log import org.signal.core.util.toOptional import org.signal.qr.QrProcessor import org.thoughtcrime.securesms.profiles.manage.UsernameRepository import org.thoughtcrime.securesms.recipients.Recipient +import java.util.Optional /** * A collection of functions to help with scanning QR codes for usernames. */ object UsernameQrScanRepository { + private val TAG = Log.tag(UsernameQrScanRepository::class) + /** * Given a URL, will attempt to lookup the username, coercing it to a standard set of [QrScanResult]s. */ @@ -35,6 +39,10 @@ object UsernameQrScanRepository { is UsernameRepository.UsernameLinkConversionResult.NetworkError -> QrScanResult.NetworkError } } + .onErrorReturn { throwable -> + Log.w(TAG, "Failed to lookup the username link.", throwable) + QrScanResult.NetworkError + } .subscribeOn(Schedulers.io()) } @@ -50,6 +58,10 @@ object UsernameQrScanRepository { return Single.fromFuture(loadBitmap) .map { QrProcessor().getScannedData(it).toOptional() } + .onErrorReturn { throwable -> + Log.w(TAG, "Failed to load or scan the selected image.", throwable) + Optional.empty() + } .flatMap { if (it.isPresent) { lookupUsernameUrl(it.get()) diff --git a/lib/qr/src/main/java/org/signal/qr/QrProcessor.kt b/lib/qr/src/main/java/org/signal/qr/QrProcessor.kt index 7bb3edec35..368318892d 100644 --- a/lib/qr/src/main/java/org/signal/qr/QrProcessor.kt +++ b/lib/qr/src/main/java/org/signal/qr/QrProcessor.kt @@ -14,7 +14,6 @@ import com.google.zxing.Result import com.google.zxing.common.HybridBinarizer import com.google.zxing.qrcode.QRCodeReader import org.signal.core.util.logging.Log -import java.nio.IntBuffer /** * Wraps [QRCodeReader] for use from API19 or API21+. @@ -43,9 +42,9 @@ class QrProcessor { return null } - val buffer = IntBuffer.allocate((bitmap.byteCount / 4) + 1) - bitmap.copyPixelsToBuffer(buffer) - return getScannedData(RGBLuminanceSource(bitmap.width, bitmap.height, buffer.array())) + val pixels = IntArray(bitmap.width * bitmap.height) + bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) + return getScannedData(RGBLuminanceSource(bitmap.width, bitmap.height, pixels)) } private fun getScannedData(source: LuminanceSource): String? {