Barcode Scanner and QR code Scanner Android Kotlin.

Harshita Bambure
3 min readSep 29, 2021

Nowadays we need to scan many barcodes and QR codes for scanning purposes, we need a barcode scanner or QR code scanner so today we will learn how to create a barcode and QR code scanner in android Kotlin.

First of all, we need to add barcode scanner dependency in the build.Gradle(:app) file.

//barcode
implementation 'com.google.android.gms:play-services-vision:20.1.3'

In this project, I am using view binding so we need to add a build feature in the build.Gradle(: app) file.

android {
buildFeatures {
viewBinding = true
}
}

Now we need to add camera permission in the manifest file. We will add a user feature in the manifest file for accessing the camera hardware.

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />

Let's start with the scanner design.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<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">

<SurfaceView
android:id="@+id/cameraSurfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<View
android:id="@+id/barcode_line"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:background="#951C1C"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

We need to create a scanner animation file in res ->create directory ->anim ->create animation resource file->scanner_animation.xml

scanner_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fillAfter="false">

<translate
android:fromYDelta="0%p"
android:toYDelta="100%p"
android:duration="1000"
android:repeatCount="infinite"
android:repeatMode="reverse" />

</set>

Now we need to code for the main activity.

MainActivity.kt

package com.example.barcodescanner

import android.annotation.SuppressLint
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.SurfaceHolder
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.barcodescanner.databinding.ActivityMainBinding
import java.io.IOException
import com.google.android.gms.vision.CameraSource
import com.google.android.gms.vision.Detector
import com.google.android.gms.vision.barcode.Barcode
import com.google.android.gms.vision.barcode.BarcodeDetector
import com.google.android.gms.vision.Detector.Detections

class MainActivity : AppCompatActivity() {
private val requestCodeCameraPermission = 1001
private lateinit var cameraSource: CameraSource
private lateinit var barcodeDetector: BarcodeDetector
private var scannedValue = ""
private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)


if (ContextCompat.checkSelfPermission(
this@MainActivity, android.Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED
) {
askForCameraPermission()
} else {
setupControls()
}

val aniSlide: Animation =
AnimationUtils.loadAnimation(this@MainActivity, R.anim.scanner_animation)
binding.barcodeLine.startAnimation(aniSlide)
}


private fun setupControls() {
barcodeDetector =
BarcodeDetector.Builder(this).setBarcodeFormats(Barcode.ALL_FORMATS).build()

cameraSource = CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(1920, 1080)
.setAutoFocusEnabled(true) //you should add this feature
.build()

binding.cameraSurfaceView.getHolder().addCallback(object : SurfaceHolder.Callback {
@SuppressLint("MissingPermission")
override fun surfaceCreated(holder: SurfaceHolder) {
try {
//Start preview after 1s delay
cameraSource.start(holder)
} catch (e: IOException) {
e.printStackTrace()
}
}

@SuppressLint("MissingPermission")
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
try {
cameraSource.start(holder)
} catch (e: IOException) {
e.printStackTrace()
}
}

override fun surfaceDestroyed(holder: SurfaceHolder) {
cameraSource.stop()
}
})


barcodeDetector.setProcessor(object : Detector.Processor<Barcode> {
override fun release() {
Toast.makeText(applicationContext, "Scanner has been closed", Toast.LENGTH_SHORT)
.show()
}

override fun receiveDetections(detections: Detections<Barcode>) {
val barcodes = detections.detectedItems
if (barcodes.size() == 1) {
scannedValue = barcodes.valueAt(0).rawValue


//Don't forget to add this line printing value or finishing activity must run on main thread
runOnUiThread {
cameraSource.stop()
Toast.makeText(this@MainActivity, "value- $scannedValue", Toast.LENGTH_SHORT).show()
finish()
}
}else
{
Toast.makeText(this@MainActivity, "value- else", Toast.LENGTH_SHORT).show()

}
}
})
}

private fun askForCameraPermission() {
ActivityCompat.requestPermissions(
this@MainActivity,
arrayOf(android.Manifest.permission.CAMERA),
requestCodeCameraPermission
)
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == requestCodeCameraPermission && grantResults.isNotEmpty()) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setupControls()
} else {
Toast.makeText(applicationContext, "Permission Denied", Toast.LENGTH_SHORT).show()
}
}
}

override fun onDestroy() {
super.onDestroy()
cameraSource.stop()
}
}

That's it now your barcode scanner or Qr code scanner is ready for the scan.

Thank you Happy Coding!

--

--

Harshita Bambure

Android Developer || WomenTech Global Ambassador at WomenTech Network. || Yoga Teacher || Member @WTM .