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.app.AlertDialog
import android.content.ClipboardManager import android.content.ClipboardManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@ -20,7 +22,9 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions
import im.angry.openeuicc.common.R 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.Dispatchers
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -28,6 +32,10 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() { class DownloadWizardMethodSelectFragment : DownloadWizardActivity.DownloadWizardStepFragment() {
companion object {
const val TAG = "DownloadWizardMethodSelectFragment"
}
data class DownloadMethod( data class DownloadMethod(
val iconRes: Int, val iconRes: Int,
val titleRes: 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?) // TODO: Maybe we should find a better barcode scanner (or an external one?)
private val barcodeScannerLauncher = registerForActivityResult(ScanContract()) { result -> private val barcodeScannerLauncher =
result.contents?.let { content -> registerForActivityResult(ScanContract()) {
processLpaString(content) processLpaString(it.contents ?: return@registerForActivityResult)
} }
}
private val gallerySelectorLauncher = private val gallerySelectorLauncher =
registerForActivityResult(ActivityResultContracts.GetContent()) { result -> registerForActivityResult(ActivityResultContracts.GetContent()) {
if (result == null) return@registerForActivityResult
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
runCatching { val decoded = onGalleryResult(it ?: return@launch) ?: return@launch
requireContext().contentResolver.openInputStream(result)?.let { input -> withContext(Dispatchers.Main) { processLpaString(decoded) }
val bmp = BitmapFactory.decodeStream(input)
input.close()
decodeQrFromBitmap(bmp)?.let {
withContext(Dispatchers.Main) {
processLpaString(it)
}
}
bmp.recycle()
}
}
} }
} }
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( val downloadMethods = arrayOf(
DownloadMethod(R.drawable.ic_scan_black, R.string.download_wizard_method_qr_code) { DownloadMethod(R.drawable.ic_scan_black, R.string.download_wizard_method_qr_code) {
barcodeScannerLauncher.launch(ScanOptions().apply { barcodeScannerLauncher.launch(ScanOptions().apply {
@ -188,4 +190,10 @@ 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? = fun decodeQrFromBitmap(bmp: Bitmap): String {
runCatching { val pixels = IntArray(bmp.width * bmp.height)
val pixels = IntArray(bmp.width * bmp.height) bmp.getPixels(pixels, 0, bmp.width, 0, 0, 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 luminanceSource = RGBLuminanceSource(bmp.width, bmp.height, pixels)
val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource)) val binaryBmp = BinaryBitmap(HybridBinarizer(luminanceSource))
QRCodeReader().decode(binaryBmp).text return QRCodeReader().decode(binaryBmp).text
}.getOrNull() }