I'm currently experimenting with CameraX API and ML Kit for barcode scanning. I'm not receiving any data from PreviewView when I'm pointing camera to the QR code. Let me share with you my code, I think I'm so close, but sadly couldn't figure it out. :/ I'm using Preview and Image Analysis cases
MainActivity with ImageAnalysis.Analyser
class MainActivity : AppCompatActivity() {
private lateinit var outputDirectory: File
private lateinit var cameraExecutor: ExecutorService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
outputDirectory = getOutputDirectory()
cameraExecutor = Executors.newSingleThreadExecutor()
// Request camera permissions
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
)
}
}
private fun getOutputDirectory(): File {
val mediaDir = externalMediaDirs.firstOrNull()?.let {
File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists())
mediaDir else filesDir
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults:
IntArray
) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera()
} else {
Toast.makeText(
this,
"Permissions not granted by the user.",
Toast.LENGTH_SHORT
).show()
finish()
}
}
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext, it
) == PackageManager.PERMISSION_GRANTED
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(previewView.surfaceProvider)
}
// Image Analyzer
val imageAnalyzer = ImageAnalysis.Builder()
.build()
.also {
it.setAnalyzer(cameraExecutor, MyImageAnalyser())
}
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageAnalyzer
)
} catch (exc: Exception) {
Log.e(Constants.TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
inner class MyImageAnalyser : ImageAnalysis.Analyzer {
@SuppressLint("UnsafeExperimentalUsageError")
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image
if (mediaImage != null) {
val image =
InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
initializeBarcodeScanner(image)
}
}
private fun initializeBarcodeScanner(inputImage: InputImage) {
val options = BarcodeScannerOptions.Builder()
.setBarcodeFormats(
Barcode.QR_CODE,
Barcode.WIFI,
Barcode.URL
)
.build()
val scanner = BarcodeScanning.getClient(options)
scanner.process(inputImage)
.addOnSuccessListener { barcodes ->
for (barcode in barcodes) {
val bounds = barcode.boundingBox
val corners = barcode.cornerPoints
val rawValue = barcode.rawValue
Log.d("BARCODE", barcode.valueType.toString())
when (barcode.valueType) {
Barcode.WIFI -> {
val ssid = barcode.wifi!!.ssid
val password = barcode.wifi!!.password
val type = barcode.wifi!!.encryptionType
Log.d("BARCODE", ssid.toString())
Log.d("BARCODE", password.toString())
Log.d("BARCODE", type.toString())
}
Barcode.URL -> {
val title = barcode.url!!.title
val url = barcode.url!!.url
Log.d("BARCODE", title.toString())
Log.d("BARCODE", url.toString())
}
Barcode.QR_CODE -> {
Log.d("BARCODE", barcode.rawValue.toString())
}
else -> {
Log.d("BARCODE", "Else")
}
}
}
}
.addOnFailureListener {
Log.d("BARCODE", it.message.toString())
}
}
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
}
Constants.kt
class Constants {
companion object {
const val TAG = "CameraXBasic"
const val REQUEST_CODE_PERMISSIONS = 10
val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
}
}
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.camera.view.PreviewView>
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Dependencies
// Use this dependency to bundle the model with your app
implementation 'com.google.mlkit:barcode-scanning:16.0.3'
def camerax_version = "1.0.0-beta10"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha17"