Current section

Files

Jump to
mob_new priv templates mob.new android app src main java MobScannerActivity.kt.eex
Raw

priv/templates/mob.new/android/app/src/main/java/MobScannerActivity.kt.eex

package <%= java_package %>
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Size
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageButton
import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import java.util.concurrent.Executors
/**
* Full-screen barcode/QR scanner activity.
*
* Uses CameraX + ML Kit BarcodeScanning.
*
* Required build.gradle dependencies:
* implementation 'androidx.camera:camera-camera2:1.3.0'
* implementation 'androidx.camera:camera-lifecycle:1.3.0'
* implementation 'androidx.camera:camera-view:1.3.0'
* implementation 'com.google.mlkit:barcode-scanning:17.2.0'
*
* Required AndroidManifest.xml entry:
* <activity android:name=".MobScannerActivity" />
*/
class MobScannerActivity : AppCompatActivity() {
private val executor = Executors.newSingleThreadExecutor()
private var scanHandled = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val container = FrameLayout(this)
setContentView(container)
val previewView = PreviewView(this).also {
it.layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
container.addView(it)
}
// Cancel button
val cancelBtn = ImageButton(this).also {
it.setImageResource(android.R.drawable.ic_menu_close_clear_cancel)
it.layoutParams = FrameLayout.LayoutParams(128, 128).apply { setMargins(32, 80, 0, 0) }
it.setOnClickListener { setResult(Activity.RESULT_CANCELED); finish() }
container.addView(it)
}
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder().build().also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
val imageAnalyzer = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also { analysis ->
val scanner = BarcodeScanning.getClient()
analysis.setAnalyzer(executor) { imageProxy ->
@OptIn(ExperimentalGetImage::class)
val mediaImage = imageProxy.image
if (mediaImage != null && !scanHandled) {
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
scanner.process(image)
.addOnSuccessListener { barcodes ->
barcodes.firstOrNull()?.rawValue?.let { value ->
if (!scanHandled) {
scanHandled = true
val type = when (barcodes.first().format) {
Barcode.FORMAT_QR_CODE -> "qr"
Barcode.FORMAT_EAN_13 -> "ean13"
Barcode.FORMAT_EAN_8 -> "ean8"
Barcode.FORMAT_CODE_128 -> "code128"
Barcode.FORMAT_CODE_39 -> "code39"
Barcode.FORMAT_PDF417 -> "pdf417"
Barcode.FORMAT_AZTEC -> "aztec"
Barcode.FORMAT_DATA_MATRIX -> "data_matrix"
else -> "qr"
}
val result = Intent().apply {
putExtra("scan_value", value)
putExtra("scan_type", type)
}
setResult(Activity.RESULT_OK, result)
finish()
}
}
}
.addOnCompleteListener { imageProxy.close() }
} else {
imageProxy.close()
}
}
}
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageAnalyzer)
} catch (e: Exception) {
setResult(Activity.RESULT_CANCELED); finish()
}
}, ContextCompat.getMainExecutor(this))
}
override fun onDestroy() {
super.onDestroy()
executor.shutdown()
}
}