11package nl.storegear.android.mlbarcodescanner
22
33import android.Manifest
4- import android.content.Context
5- import android.content.pm.PackageManager
64import android.os.Bundle
7- import android.util.Log
8- import android.util.Size
95import androidx.appcompat.app.AppCompatActivity
10- import androidx.camera.core.CameraSelector
11- import androidx.camera.core.ImageAnalysis
12- import androidx.camera.core.ImageProxy
13- import androidx.camera.core.Preview
14- import androidx.camera.lifecycle.ProcessCameraProvider
15- import androidx.core.app.ActivityCompat
16- import androidx.core.content.ContextCompat
17- import androidx.lifecycle.ViewModelProvider
18- import com.google.mlkit.common.MlKitException
6+ import com.buildtoapp.mlbarcodescanner.MLBarcodeCallback
7+ import com.buildtoapp.mlbarcodescanner.MLBarcodeScanner
198import nl.storegear.android.mlbarcodescanner.databinding.ActivityMainBinding
20- import nl.storegear.android.mlbarcodescanner.mlkit.BarcodeScannerProcessor
21- import nl.storegear.android.mlbarcodescanner.mlkit.CameraXBarcodeCallback
22- import nl.storegear.android.mlbarcodescanner.mlkit.CameraXViewModel
23- import nl.storegear.android.mlbarcodescanner.mlkit.VisionImageProcessor
24- import nl.storegear.android.mlbarcodescanner.util.MetricUtils.dpToPx
9+ import nl.storegear.android.mlbarcodescanner.util.MetricUtils
10+ import nl.storegear.android.mlbarcodescanner.util.PermissionUtils
2511
26- class MainActivity : AppCompatActivity (), CameraXBarcodeCallback {
27- lateinit var binding: ActivityMainBinding
28-
29- private lateinit var cameraXViewModel: CameraXViewModel
30- private var cameraProvider: ProcessCameraProvider ? = null
31- private var previewUseCase: Preview ? = null
32- private var analysisUseCase: ImageAnalysis ? = null
33- private var imageProcessor: VisionImageProcessor ? = null
34- private var needUpdateGraphicOverlayImageSourceInfo = false
35- private var lensFacing = CameraSelector .LENS_FACING_BACK
36- private lateinit var cameraSelector: CameraSelector
12+ class MainActivity : AppCompatActivity (), MLBarcodeCallback {
13+ private lateinit var binding: ActivityMainBinding
14+ private lateinit var barcodeScanner: MLBarcodeScanner
3715
3816 override fun onCreate (savedInstanceState : Bundle ? ) {
3917 super .onCreate(savedInstanceState)
4018 binding = ActivityMainBinding .inflate(layoutInflater)
4119 setContentView(binding.root)
4220
43- if (! allRuntimePermissionsGranted()) {
44- getRuntimePermissions()
45- }
46- cameraXViewModel = ViewModelProvider (this ).get(CameraXViewModel ::class .java)
47-
48- cameraSelector = CameraSelector .Builder ().requireLensFacing(lensFacing).build()
49- cameraXViewModel.processCameraProvider.observe(this ) { provider: ProcessCameraProvider ? ->
50- cameraProvider = provider
51- bindAllCameraUseCases()
21+ if (! PermissionUtils .allRuntimePermissionsGranted(this , REQUIRED_RUNTIME_PERMISSIONS )) {
22+ PermissionUtils .getRuntimePermissions(this , REQUIRED_RUNTIME_PERMISSIONS )
5223 }
24+ initBarcodeScanner()
5325 }
5426
55- override fun onPause () {
56- super .onPause()
57- imageProcessor?.stop()
58- }
59-
60- override fun onResume () {
61- super .onResume()
62- bindAllCameraUseCases()
63- }
64-
65- override fun onDestroy () {
66- imageProcessor?.stop()
67- super .onDestroy()
27+ private fun initBarcodeScanner () {
28+ barcodeScanner = MLBarcodeScanner (
29+ callback = this ,
30+ focusBoxSize = MetricUtils .dpToPx(264 ),
31+ graphicOverlay = binding.graphicOverlay,
32+ previewView = binding.previewViewCameraScanning,
33+ lifecycleOwner = this ,
34+ context = this ,
35+ drawOverlay = true , // show rectangle around detected barcode
36+ drawBanner = true // show detected barcode value on top of it
37+ )
6838 }
6939
7040 override fun onNewBarcodeScanned (displayValue : String , rawValue : String ) {
7141 // todo: you can process your barcode here
7242 }
7343
74- private fun bindAllCameraUseCases () {
75- // As required by CameraX API, unbinds all use cases before trying to re-bind any of them.
76- cameraProvider?.unbindAll()
77- bindPreviewUseCase()
78- bindAnalysisUseCase()
79- }
80-
81- private fun bindPreviewUseCase () {
82- if (cameraProvider == null ) {
83- return
84- }
85- cameraProvider?.unbind(previewUseCase)
86- val builder = Preview .Builder ()
87- previewUseCase = builder.build()
88- previewUseCase?.setSurfaceProvider(binding.previewViewCameraScanning.surfaceProvider)
89- cameraProvider?.bindToLifecycle(this , cameraSelector, previewUseCase)
90- }
91-
92- private fun bindAnalysisUseCase () {
93- if (cameraProvider == null ) {
94- return
95- }
96- cameraProvider?.unbind(analysisUseCase)
97- imageProcessor?.stop()
98- imageProcessor = BarcodeScannerProcessor (this , focusBoxSize = dpToPx(264 ))
99-
100- val builder = ImageAnalysis .Builder ()
101- builder.setTargetResolution(Size (768 , 1024 ))
102- analysisUseCase = builder.build()
103-
104- needUpdateGraphicOverlayImageSourceInfo = true
105-
106- analysisUseCase?.setAnalyzer(
107- // imageProcessor.processImageProxy will use another thread to run the detection underneath,
108- // thus we can just runs the analyzer itself on main thread.
109- ContextCompat .getMainExecutor(this )
110- ) { imageProxy: ImageProxy ->
111- if (needUpdateGraphicOverlayImageSourceInfo) {
112- val rotationDegrees = imageProxy.imageInfo.rotationDegrees
113- if (rotationDegrees == 0 || rotationDegrees == 180 ) {
114- binding.graphicOverlay.setImageSourceInfo(imageProxy.width, imageProxy.height, false )
115- } else {
116- binding.graphicOverlay.setImageSourceInfo(imageProxy.height, imageProxy.width, false )
117- }
118- needUpdateGraphicOverlayImageSourceInfo = false
119- }
120-
121- try {
122- imageProcessor?.processImageProxy(imageProxy, binding.graphicOverlay)
123- } catch (e: MlKitException ) {
124- Log .e(" TAG" , " Failed to process image. Error: " + e.localizedMessage)
125- }
126- }
127- cameraProvider?.bindToLifecycle(this , cameraSelector, analysisUseCase)
128- }
129-
130-
131- // GET PERMISSIONS //
132- private fun allRuntimePermissionsGranted (): Boolean {
133- for (permission in REQUIRED_RUNTIME_PERMISSIONS ) {
134- permission.let {
135- if (! isPermissionGranted(this , it)) {
136- return false
137- }
138- }
139- }
140- return true
141- }
142-
143- private fun getRuntimePermissions () {
144- val permissionsToRequest = ArrayList <String >()
145- for (permission in REQUIRED_RUNTIME_PERMISSIONS ) {
146- permission.let {
147- if (! isPermissionGranted(this , it)) {
148- permissionsToRequest.add(permission)
149- }
150- }
151- }
152-
153- if (permissionsToRequest.isNotEmpty()) {
154- ActivityCompat .requestPermissions(this , permissionsToRequest.toTypedArray(), PERMISSION_REQUESTS )
155- }
156- }
157-
158- private fun isPermissionGranted (context : Context , permission : String ): Boolean {
159- if (ContextCompat .checkSelfPermission(context, permission) == PackageManager .PERMISSION_GRANTED ) {
160- Log .i(TAG , " Permission granted: $permission " )
161- return true
162- }
163- Log .i(TAG , " Permission NOT granted: $permission " )
164- return false
165- }
166-
16744 companion object {
168- private const val TAG = " MLBarcodeScanner"
169- private const val PERMISSION_REQUESTS = 1
170-
171- private val REQUIRED_RUNTIME_PERMISSIONS = arrayOf(
172- Manifest .permission.CAMERA ,
173- Manifest .permission.WRITE_EXTERNAL_STORAGE ,
174- Manifest .permission.READ_EXTERNAL_STORAGE
175- )
45+ private val REQUIRED_RUNTIME_PERMISSIONS = arrayOf(Manifest .permission.CAMERA )
17646 }
17747}
0 commit comments