Gon3s
Gon3s

Reputation: 177

How can I limit barcode scanner to once?

I try to code a barcode scanner with Jetpack Compose and Google ML Kit. I use ImageAnalysis with the STRATEGY_KEEP_ONLY_LATEST and call a class BarCodeAnalyzer who initialize and create the barcodeScanner.

But when I scan a barcode, my code detect two time the same barcode and open two screens.

So how can I pause scan ? Or stop the imageAnalysis when I found a barcode ?

AndroidView

AndroidView(
    factory = { context ->
        val previewView = PreviewView(context)
        val preview = Preview.Builder().build()
        val selector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build()
        preview.setSurfaceProvider(previewView.surfaceProvider)
        val imageAnalysis = ImageAnalysis.Builder()
            .setTargetResolution(
                Size(
                    previewView.width,
                    previewView.height
                )
            )
            .setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST)
            .build()
        imageAnalysis.setAnalyzer(
            ContextCompat.getMainExecutor(context),
            BarCodeAnalyzer { result ->
                code = result
                navController.navigate(
                    Screen.FormProduct.route + "?barcode=$code"
                )
            }
        )

        try {
            cameraProviderFuture.get().bindToLifecycle(
                lifecycleOwner,
                selector,
                preview,
                imageAnalysis
            )
        } catch (e: Exception) {
            e.printStackTrace()
        }
        previewView
    },
    modifier = Modifier.fillMaxSize()
)

BarCodeAnalyzer

class BarCodeAnalyzer(
    private val onBarCodeScanned: (String) -> Unit,
) : ImageAnalysis.Analyzer {

    var currentTimestamp: Long = 0

    @SuppressLint("UnsafeOptInUsageError")
    override fun analyze(imageProxy: ImageProxy) {
        currentTimestamp = System.currentTimeMillis()
        val options = BarcodeScannerOptions.Builder()
            .setBarcodeFormats(
                Barcode.FORMAT_EAN_13,
                Barcode.FORMAT_EAN_8
            )
            .build()

        val image = imageProxy.image

        if (image != null) {
            val inputImage = InputImage.fromMediaImage(image, imageProxy.imageInfo.rotationDegrees)

            val scanner = BarcodeScanning.getClient(options)

            scanner.process(inputImage)
                .addOnSuccessListener { barcodes ->
                    if (barcodes.isNotEmpty()) {
                        barcodes.firstOrNull()?.rawValue?.let { barcode ->
                            Log.i(TAG, "Barcode : $barcode")
                            onBarCodeScanned(barcode)
                        }
                    }
                }
                .addOnCompleteListener {
                    imageProxy.close()
                }
        }
    }
}

Thanks.

Upvotes: 5

Views: 1405

Answers (1)

Gon3s
Gon3s

Reputation: 177

I found a solution, in my BarCodeAnalyzer I created a variable firstCall initialize at true then where a barcode was founded I pass firstCall to false like this :

class BarCodeAnalyzer(
    private val onBarCodeScanned: (String) -> Unit,
) : ImageAnalysis.Analyzer {

    private var firstCall = true

    ...

    scanner.process(inputImage)
        .addOnSuccessListener { barcodes ->
             if (barcodes.isNotEmpty()) {
                 if (firstCall) {
                      firstCall = false
                       barcodes.firstOrNull()?.rawValue?.let { barcode ->
                       onBarCodeScanned(barcode)
                 }
             }
         }
    }

   ...
}

Upvotes: 2

Related Questions