-
-
Save hoangchungk53qx1/78fa1912248fefec72746960d2670360 to your computer and use it in GitHub Desktop.
ScanQrcodeFragment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.doancnpm.edoctor2.ui.main.history | |
| import android.Manifest | |
| import android.annotation.SuppressLint | |
| import android.content.pm.PackageManager.PERMISSION_GRANTED | |
| import android.os.Build | |
| import android.os.Bundle | |
| import android.os.VibrationEffect | |
| import android.os.Vibrator | |
| import android.util.Size | |
| import android.view.View | |
| import androidx.activity.result.ActivityResultLauncher | |
| import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions | |
| import androidx.camera.core.CameraSelector | |
| import androidx.camera.core.ImageAnalysis | |
| import androidx.camera.core.ImageProxy | |
| import androidx.camera.core.Preview | |
| import androidx.camera.lifecycle.ProcessCameraProvider | |
| import androidx.core.content.ContextCompat | |
| import androidx.core.os.bundleOf | |
| import androidx.fragment.app.setFragmentResult | |
| import androidx.lifecycle.lifecycleScope | |
| import androidx.navigation.fragment.findNavController | |
| import androidx.navigation.fragment.navArgs | |
| import com.doancnpm.edoctor2.R | |
| import com.doancnpm.edoctor2.core.BaseFragment | |
| import com.doancnpm.edoctor2.databinding.FragmentScanQrcodeBinding | |
| import com.doancnpm.edoctor2.domain.dispatchers.AppSchedulers | |
| import com.doancnpm.edoctor2.utils.exhaustMap | |
| import com.doancnpm.edoctor2.utils.toast | |
| import com.doancnpm.edoctor2.utils.viewBinding | |
| import com.google.mlkit.vision.barcode.Barcode | |
| import com.google.mlkit.vision.barcode.BarcodeScanning | |
| import com.google.mlkit.vision.common.InputImage | |
| import com.jakewharton.rxrelay3.PublishRelay | |
| import io.reactivex.rxjava3.core.Observable | |
| import io.reactivex.rxjava3.kotlin.addTo | |
| import io.reactivex.rxjava3.kotlin.subscribeBy | |
| import kotlinx.coroutines.ExperimentalCoroutinesApi | |
| import kotlinx.coroutines.launch | |
| import kotlinx.coroutines.rx3.rxObservable | |
| import kotlinx.coroutines.suspendCancellableCoroutine | |
| import kotlinx.coroutines.tasks.await | |
| import org.koin.android.ext.android.inject | |
| import timber.log.Timber | |
| import java.util.concurrent.Executors | |
| import kotlin.coroutines.resume | |
| @ExperimentalCoroutinesApi | |
| class ScanQrcodeFragment : BaseFragment(R.layout.fragment_scan_qrcode) { | |
| private val binding by viewBinding<FragmentScanQrcodeBinding>() | |
| private val navArgs by navArgs<ScanQrcodeFragmentArgs>() | |
| private val schedulers by inject<AppSchedulers>() | |
| private val scanner by lazy { BarcodeScanning.getClient() } | |
| private val imageProxyS = PublishRelay.create<ImageProxy>() | |
| @SuppressLint("UnsafeExperimentalUsageError") | |
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | |
| super.onViewCreated(view, savedInstanceState) | |
| imageProxyS | |
| .exhaustMap { proxy -> | |
| Observable.using( | |
| { proxy }, | |
| { imageProxy -> | |
| rxObservable { | |
| Timber.d("Analyze: $imageProxy") | |
| val mediaImage = imageProxy.image ?: return@rxObservable | |
| val image = InputImage.fromMediaImage( | |
| mediaImage, | |
| imageProxy.imageInfo.rotationDegrees | |
| ) | |
| val qrCode = scanner | |
| .process(image) | |
| .await() | |
| .firstOrNull { it.valueType == Barcode.TYPE_TEXT } | |
| ?.displayValue | |
| ?: return@rxObservable | |
| send(qrCode) | |
| } | |
| }, | |
| ImageProxy::close, | |
| ) | |
| } | |
| .take(1) | |
| .observeOn(schedulers.main) | |
| .subscribeBy { code -> | |
| val vibrator = ContextCompat.getSystemService( | |
| requireContext(), | |
| Vibrator::class.java, | |
| )!! | |
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| vibrator.vibrate( | |
| VibrationEffect.createOneShot( | |
| 500, | |
| VibrationEffect.DEFAULT_AMPLITUDE, | |
| ) | |
| ) | |
| } else { | |
| @Suppress("DEPRECATION") | |
| vibrator.vibrate(500) | |
| } | |
| requireContext().toast("Code: $code") | |
| setFragmentResult( | |
| requestKey = REQUEST_KEY, | |
| result = bundleOf( | |
| QR_CODE_KEY to code, | |
| ORDER_ID_KEY to navArgs.orderId, | |
| ) | |
| ) | |
| findNavController().popBackStack() | |
| } | |
| .addTo(compositeDisposable) | |
| // Request camera permissions | |
| if (allPermissionsGranted()) { | |
| startCamera() | |
| } else { | |
| viewLifecycleOwner.lifecycleScope.launch { | |
| suspendCancellableCoroutine<Unit> { continuation -> | |
| var launcher: ActivityResultLauncher<Array<String>>? = null | |
| launcher = registerForActivityResult(RequestMultiplePermissions()) { | |
| launcher?.unregister() | |
| continuation.resume(Unit) | |
| } | |
| continuation.invokeOnCancellation { launcher.unregister() } | |
| launcher.launch(REQUIRED_PERMISSIONS) | |
| } | |
| if (allPermissionsGranted()) { | |
| startCamera() | |
| } else { | |
| requireContext().toast("Permissions not granted by the user.") | |
| findNavController().popBackStack() | |
| } | |
| } | |
| } | |
| } | |
| private fun startCamera() { | |
| val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext()) | |
| cameraProviderFuture.addListener( | |
| Runnable { | |
| // Used to bind the lifecycle of cameras to the lifecycle owner | |
| val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() | |
| // Preview | |
| val preview = Preview.Builder() | |
| .setTargetResolution(Size(480, 480)) | |
| .build() | |
| // Select back camera | |
| val cameraSelector = CameraSelector | |
| .Builder() | |
| .requireLensFacing(CameraSelector.LENS_FACING_BACK) | |
| .build() | |
| val imageAnalyzer = ImageAnalysis.Builder() | |
| .setTargetResolution(Size(480, 480)) | |
| .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) | |
| .build() | |
| .also { analysis -> | |
| analysis.setAnalyzer( | |
| Executors.newSingleThreadExecutor(), | |
| ImageAnalysis.Analyzer(imageProxyS::accept) | |
| ) | |
| } | |
| try { | |
| // Unbind use cases before rebinding | |
| cameraProvider.unbindAll() | |
| // Bind use cases to camera | |
| cameraProvider.bindToLifecycle( | |
| this, | |
| cameraSelector, | |
| preview, | |
| imageAnalyzer, | |
| ) | |
| preview.setSurfaceProvider(binding.viewFinder.createSurfaceProvider()) | |
| } catch (e: Exception) { | |
| Timber.d(e, "Use case binding failed: ${e.message}") | |
| } | |
| }, | |
| ContextCompat.getMainExecutor(requireContext()), | |
| ) | |
| } | |
| private fun allPermissionsGranted(): Boolean { | |
| return REQUIRED_PERMISSIONS.all { | |
| ContextCompat.checkSelfPermission( | |
| requireContext(), | |
| it | |
| ) == PERMISSION_GRANTED | |
| } | |
| } | |
| companion object { | |
| private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA) | |
| val REQUEST_KEY = ScanQrcodeFragment::class.java.name + ".request_key" | |
| val QR_CODE_KEY = ScanQrcodeFragment::class.java.name + ".qr_code_key" | |
| val ORDER_ID_KEY = ScanQrcodeFragment::class.java.name + ".order_id_key" | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment