Compare commits

...

2 commits

2 changed files with 37 additions and 30 deletions

View file

@ -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 {
@ -189,3 +191,9 @@ class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizard
}
}
private fun <T> Bitmap.use(block: Bitmap.() -> T): T = try {
block()
} finally {
recycle()
}

View file

@ -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
}