Add in-app qr code scanner

This commit is contained in:
世界
2024-03-16 16:38:42 +08:00
parent df51284af0
commit 29e02d2696
15 changed files with 471 additions and 2 deletions

View File

@@ -0,0 +1,63 @@
package io.nekohasekai.sfa.vendor
import android.util.Log
import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScannerOptions
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
// kanged from: https://github.com/G00fY2/quickie/blob/main/quickie/src/main/kotlin/io/github/g00fy2/quickie/QRCodeAnalyzer.kt
class MLKitQRCodeAnalyzer(
private val onSuccess: ((String) -> Unit),
private val onFailure: ((Exception) -> Unit),
) : ImageAnalysis.Analyzer {
private val barcodeScanner =
BarcodeScanning.getClient(
BarcodeScannerOptions.Builder().setBarcodeFormats(Barcode.FORMAT_QR_CODE).build()
)
@Volatile
private var failureOccurred = false
private var failureTimestamp = 0L
@ExperimentalGetImage
override fun analyze(image: ImageProxy) {
if (image.image == null) return
if (failureOccurred && System.currentTimeMillis() - failureTimestamp < 1000L) {
Log.d("MLKitQRCodeAnalyzer", "throttled analysis since error occurred in previous pass")
image.close()
return
}
failureOccurred = false
barcodeScanner.process(image.toInputImage())
.addOnSuccessListener { codes ->
if (codes.isNotEmpty()) {
val rawValue = codes.firstOrNull()?.rawValue
if (rawValue != null) {
Log.d("MLKitQRCodeAnalyzer", "barcode decode success: $rawValue")
onSuccess(rawValue)
}
}
}
.addOnFailureListener {
failureOccurred = true
failureTimestamp = System.currentTimeMillis()
onFailure(it)
}
.addOnCompleteListener {
image.close()
}
}
@ExperimentalGetImage
@Suppress("UnsafeCallOnNullableType")
private fun ImageProxy.toInputImage() =
InputImage.fromMediaImage(image!!, imageInfo.rotationDegrees)
}

View File

@@ -3,12 +3,14 @@ package io.nekohasekai.sfa.vendor
import android.app.Activity
import android.content.Context
import android.util.Log
import androidx.camera.core.ImageAnalysis
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus
import com.google.android.play.core.install.model.UpdateAvailability
import com.google.mlkit.common.MlKitException
import io.nekohasekai.sfa.R
object Vendor : VendorInterface {
@@ -74,4 +76,18 @@ object Vendor : VendorInterface {
.setMessage(R.string.no_updates_available).setPositiveButton(R.string.ok, null).show()
}
override fun createQRCodeAnalyzer(
onSuccess: (String) -> Unit,
onFailure: (Exception) -> Unit
): ImageAnalysis.Analyzer? {
try {
return MLKitQRCodeAnalyzer(onSuccess, onFailure)
} catch (exception: Exception) {
if (exception !is MlKitException || exception.errorCode != MlKitException.UNAVAILABLE) {
Log.e(TAG, "failed to create MLKitQRCodeAnalyzer", exception)
}
return null
}
}
}