diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardMethodSelectFragment.kt b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardMethodSelectFragment.kt index 6d86f6c..794109c 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardMethodSelectFragment.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/wizard/DownloadWizardMethodSelectFragment.kt @@ -2,7 +2,9 @@ package im.angry.openeuicc.ui.wizard import android.app.AlertDialog import android.content.ClipboardManager +import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.net.Uri import android.os.Bundle import android.util.Log import android.view.LayoutInflater @@ -20,7 +22,9 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions import im.angry.openeuicc.common.R -import im.angry.openeuicc.util.* +import im.angry.openeuicc.util.ActivationCode +import im.angry.openeuicc.util.decodeQrFromBitmap +import im.angry.openeuicc.util.preferenceRepository import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch @@ -28,6 +32,10 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() { + companion object { + const val TAG = "DownloadWizardMethodSelectFragment" + } + data class DownloadMethod( val iconRes: Int, val titleRes: Int, @@ -35,34 +43,28 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard ) // TODO: Maybe we should find a better barcode scanner (or an external one?) - private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result -> - result.contents?.let { content -> - processLpaString(content) + private val barcodeScannerLauncher = + registerForActivityResult(ScanContract()) { + processLpaString(it.contents ?: return@registerForActivityResult) } - } private val gallerySelectorLauncher = - registerForActivityResult(ActivityResultContracts.GetContent()) { result -> - if (result == null) return@registerForActivityResult - + registerForActivityResult(ActivityResultContracts.GetContent()) { lifecycleScope.launch(Dispatchers.IO) { - runCatching { - requireContext().contentResolver.openInputStream(result)?.let { input -> - val bmp = BitmapFactory.decodeStream(input) - input.close() - - decodeQrFromBitmap(bmp)?.let { - withContext(Dispatchers.Main) { - processLpaString(it) - } - } - - bmp.recycle() - } - } + val decoded = onGalleryResult(it ?: return@launch) ?: return@launch + withContext(Dispatchers.Main) { processLpaString(decoded) } } } + private fun onGalleryResult(result: Uri) = try { + requireContext().contentResolver.openInputStream(result) + .use(BitmapFactory::decodeStream) + .use(::decodeQrFromBitmap) + } catch (e: Exception) { + Log.e(TAG, "Failed to decode QR code from gallery", e) + null + } + val downloadMethods = arrayOf( DownloadMethod(R.drawable.ic_scan_black, R.string.download_wizard_method_qr_code) { barcodeScannerLauncher.launch(ScanOptions().apply { @@ -188,4 +190,10 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard } } +} + +private fun Bitmap.use(block: Bitmap.() -> T): T = try { + block() +} finally { + recycle() } \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt index 444c176..fd32eac 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/Utils.kt @@ -86,13 +86,12 @@ suspend fun connectSEService(context: Context): SEService = suspendCoroutine { c } } -fun decodeQrFromBitmap(bmp: Bitmap): String? = - runCatching { - val pixels = IntArray(bmp.width * bmp.height) - bmp.getPixels(pixels, 0, bmp.width, 0, 0, bmp.width, bmp.height) +fun decodeQrFromBitmap(bmp: Bitmap): String { + val pixels = IntArray(bmp.width * bmp.height) + bmp.getPixels(pixels, 0, bmp.width, 0, 0, bmp.width, bmp.height) - val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels) - val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource)) + val luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels) + val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource)) - QRCodeReader().decode(binaryBmp).text - }.getOrNull() + return QRCodeReader().decode(binaryBmp).text +}