From 86b66ba89e8cf8db99ecb27d491b3600c3f13afd Mon Sep 17 00:00:00 2001 From: juho park Date: Thu, 14 Sep 2023 20:40:14 +0900 Subject: [PATCH 1/3] [Android] Fix handling manual code in CHIPTool --- .../setuppayloadscanner/BarcodeFragment.kt | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt index ece9f6ba0db511..4f3147cdaa892b 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt @@ -139,9 +139,9 @@ class BarcodeFragment : Fragment() { // workaround: can not use gms to scan the code in China, added a EditText to debug binding.manualCodeBtn.setOnClickListener { - val qrCode = binding.manualCodeEditText.text.toString() - Log.d(TAG, "Submit Code:$qrCode") - handleInputQrCode(qrCode) + val code = binding.manualCodeEditText.text.toString() + Log.d(TAG, "Submit Code:$code") + handleInputCode(code) } } @@ -178,24 +178,24 @@ class BarcodeFragment : Fragment() { } } - private fun handleInputQrCode(qrCode: String) { + private fun handleInputCode(code: String) { lateinit var payload: OnboardingPayload try { - payload = OnboardingPayloadParser().parseQrCode(qrCode) - } catch (ex: OnboardingPayloadException) { - try { - payload = OnboardingPayloadParser().parseManualPairingCode(qrCode) - } catch (ex: Exception) { - Log.e(TAG, "Unrecognized Manual Pairing Code", ex) - Toast.makeText(requireContext(), "Unrecognized Manual Pairing Code", Toast.LENGTH_SHORT) - .show() + payload = if(code.startsWith("MT:")){ + OnboardingPayloadParser().parseQrCode(code) + } else { + OnboardingPayloadParser().parseManualPairingCode(code) } + + FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) } catch (ex: UnrecognizedQrCodeException) { - Log.e(TAG, "Unrecognized QR Code", ex) + Log.e(TAG, "Unrecognized Code", ex) Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + } catch (ex: Exception) { + Log.e(TAG, "Exception, $ex") + Toast.makeText(requireContext(), "Occur Exception, $ex", Toast.LENGTH_SHORT).show() } - FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) - ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) } private fun handleScannedQrCode(barcode: Barcode) { From 039dcd018e447cf796be553a298e7486b52e9c58 Mon Sep 17 00:00:00 2001 From: juho park Date: Thu, 14 Sep 2023 20:40:14 +0900 Subject: [PATCH 2/3] [Android] Fix handling manual code in CHIPTool --- .../setuppayloadscanner/BarcodeFragment.kt | 358 +++++++++--------- 1 file changed, 180 insertions(+), 178 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt index ece9f6ba0db511..f0a2747e1110c1 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt @@ -55,212 +55,214 @@ import kotlin.math.min /** Launches the camera to scan for QR code. */ class BarcodeFragment : Fragment() { - private var _binding: BarcodeFragmentBinding? = null - private val binding - get() = _binding!! + private var _binding: BarcodeFragmentBinding? = null + private val binding + get() = _binding!! - private fun aspectRatio(width: Int, height: Int): Int { - val previewRatio = max(width, height).toDouble() / min(width, height) - if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) { - return AspectRatio.RATIO_4_3 + private fun aspectRatio(width: Int, height: Int): Int { + val previewRatio = max(width, height).toDouble() / min(width, height) + if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) { + return AspectRatio.RATIO_4_3 + } + return AspectRatio.RATIO_16_9 } - return AspectRatio.RATIO_16_9 - } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (!hasCameraPermission()) { - requestCameraPermission() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (!hasCameraPermission()) { + requestCameraPermission() + } } - } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = BarcodeFragmentBinding.inflate(inflater, container, false) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = BarcodeFragmentBinding.inflate(inflater, container, false) + + startCamera() + binding.inputAddressBtn.setOnClickListener { + FragmentUtil.getHost(this@BarcodeFragment, SelectActionFragment.Callback::class.java) + ?.onShowDeviceAddressInput() + } - startCamera() - binding.inputAddressBtn.setOnClickListener { - FragmentUtil.getHost(this@BarcodeFragment, SelectActionFragment.Callback::class.java) - ?.onShowDeviceAddressInput() + return binding.root } - return binding.root - } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + @SuppressLint("UnsafeOptInUsageError") + private fun startCamera() { + val cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity()) + cameraProviderFuture.addListener( + { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + val metrics = + DisplayMetrics().also { binding.cameraView.display?.getRealMetrics(it) } + val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels) + // Preview + val preview: Preview = + Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(binding.cameraView.display.rotation) + .build() + preview.setSurfaceProvider(binding.cameraView.surfaceProvider) - @SuppressLint("UnsafeOptInUsageError") - private fun startCamera() { - val cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity()) - cameraProviderFuture.addListener( - { - val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() - val metrics = DisplayMetrics().also { binding.cameraView.display?.getRealMetrics(it) } - val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels) - // Preview - val preview: Preview = - Preview.Builder() - .setTargetAspectRatio(screenAspectRatio) - .setTargetRotation(binding.cameraView.display.rotation) - .build() - preview.setSurfaceProvider(binding.cameraView.surfaceProvider) + // Setup barcode scanner + val imageAnalysis = + ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(binding.cameraView.display.rotation) + .build() + val cameraExecutor = Executors.newSingleThreadExecutor() + val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient() + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + processImageProxy(barcodeScanner, imageProxy) + } + // Select back camera as a default + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + try { + // Unbind use cases before rebinding + cameraProvider.unbindAll() - // Setup barcode scanner - val imageAnalysis = - ImageAnalysis.Builder() - .setTargetAspectRatio(screenAspectRatio) - .setTargetRotation(binding.cameraView.display.rotation) - .build() - val cameraExecutor = Executors.newSingleThreadExecutor() - val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient() - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - processImageProxy(barcodeScanner, imageProxy) - } - // Select back camera as a default - val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA - try { - // Unbind use cases before rebinding - cameraProvider.unbindAll() + // Bind use cases to camera + cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis) + } catch (exc: Exception) { + Log.e(TAG, "Use case binding failed", exc) + } + }, + ContextCompat.getMainExecutor(requireActivity()) + ) - // Bind use cases to camera - cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis) - } catch (exc: Exception) { - Log.e(TAG, "Use case binding failed", exc) + // workaround: can not use gms to scan the code in China, added a EditText to debug + binding.manualCodeBtn.setOnClickListener { + val code = binding.manualCodeEditText.text.toString() + Log.d(TAG, "Submit Code:$code") + handleInputCode(code) } - }, - ContextCompat.getMainExecutor(requireActivity()) - ) - - // workaround: can not use gms to scan the code in China, added a EditText to debug - binding.manualCodeBtn.setOnClickListener { - val qrCode = binding.manualCodeEditText.text.toString() - Log.d(TAG, "Submit Code:$qrCode") - handleInputQrCode(qrCode) } - } - @ExperimentalGetImage - private fun processImageProxy(barcodeScanner: BarcodeScanner, imageProxy: ImageProxy) { - val inputImage = - InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees) + @ExperimentalGetImage + private fun processImageProxy(barcodeScanner: BarcodeScanner, imageProxy: ImageProxy) { + val inputImage = + InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees) - barcodeScanner - .process(inputImage) - .addOnSuccessListener { barcodes -> barcodes.forEach { handleScannedQrCode(it) } } - .addOnFailureListener { Log.e(TAG, it.message ?: it.toString()) } - .addOnCompleteListener { - // When the image is from CameraX analysis use case, must call image.close() on - // received - // images when finished using them. Otherwise, new images may not be received or the - // camera - // may stall. - imageProxy.close() - } - } + barcodeScanner + .process(inputImage) + .addOnSuccessListener { barcodes -> barcodes.forEach { handleScannedQrCode(it) } } + .addOnFailureListener { Log.e(TAG, it.message ?: it.toString()) } + .addOnCompleteListener { + // When the image is from CameraX analysis use case, must call image.close() on + // received + // images when finished using them. Otherwise, new images may not be received or the + // camera + // may stall. + imageProxy.close() + } + } - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) { - if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_DENIED) { - showCameraPermissionAlert() - } - } else { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) { + if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_DENIED) { + showCameraPermissionAlert() + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + } } - } - private fun handleInputQrCode(qrCode: String) { - lateinit var payload: OnboardingPayload - try { - payload = OnboardingPayloadParser().parseQrCode(qrCode) - } catch (ex: OnboardingPayloadException) { - try { - payload = OnboardingPayloadParser().parseManualPairingCode(qrCode) - } catch (ex: Exception) { - Log.e(TAG, "Unrecognized Manual Pairing Code", ex) - Toast.makeText(requireContext(), "Unrecognized Manual Pairing Code", Toast.LENGTH_SHORT) - .show() - } - } catch (ex: UnrecognizedQrCodeException) { - Log.e(TAG, "Unrecognized QR Code", ex) - Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + private fun handleInputCode(code: String) { + try { + val payload = if (code.startsWith("MT:")) { + OnboardingPayloadParser().parseQrCode(code) + } else { + OnboardingPayloadParser().parseManualPairingCode(code) + } + + FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) + } catch (ex: UnrecognizedQrCodeException) { + Log.e(TAG, "Unrecognized Code", ex) + Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + } catch (ex: Exception) { + Log.e(TAG, "Exception, $ex") + Toast.makeText(requireContext(), "Occur Exception, $ex", Toast.LENGTH_SHORT).show() + } } - FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) - ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) - } - private fun handleScannedQrCode(barcode: Barcode) { - Handler(Looper.getMainLooper()).post { - lateinit var payload: OnboardingPayload - try { - payload = - barcode.displayValue?.let { OnboardingPayloadParser().parseQrCode(it) } ?: return@post - } catch (ex: UnrecognizedQrCodeException) { - Log.e(TAG, "Unrecognized QR Code", ex) - Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() - return@post - } - FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) - ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) + private fun handleScannedQrCode(barcode: Barcode) { + Handler(Looper.getMainLooper()).post { + try { + val payload = + barcode.displayValue?.let { OnboardingPayloadParser().parseQrCode(it) } + ?: return@post + + FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) + } catch (ex: UnrecognizedQrCodeException) { + Log.e(TAG, "Unrecognized QR Code", ex) + Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + return@post + } + } } - } - private fun showCameraPermissionAlert() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.camera_permission_missing_alert_title) - .setMessage(R.string.camera_permission_missing_alert_subtitle) - .setPositiveButton(R.string.camera_permission_missing_alert_try_again) { _, _ -> - requestCameraPermission() - } - .setCancelable(false) - .create() - .show() - } + private fun showCameraPermissionAlert() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.camera_permission_missing_alert_title) + .setMessage(R.string.camera_permission_missing_alert_subtitle) + .setPositiveButton(R.string.camera_permission_missing_alert_try_again) { _, _ -> + requestCameraPermission() + } + .setCancelable(false) + .create() + .show() + } - private fun showCameraUnavailableAlert() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.camera_unavailable_alert_title) - .setMessage(R.string.camera_unavailable_alert_subtitle) - .setPositiveButton(R.string.camera_unavailable_alert_exit) { _, _ -> - requireActivity().finish() - } - .setCancelable(false) - .create() - .show() - } + private fun showCameraUnavailableAlert() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.camera_unavailable_alert_title) + .setMessage(R.string.camera_unavailable_alert_subtitle) + .setPositiveButton(R.string.camera_unavailable_alert_exit) { _, _ -> + requireActivity().finish() + } + .setCancelable(false) + .create() + .show() + } - private fun hasCameraPermission(): Boolean { - return (PackageManager.PERMISSION_GRANTED == - checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) - } + private fun hasCameraPermission(): Boolean { + return (PackageManager.PERMISSION_GRANTED == + checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) + } - private fun requestCameraPermission() { - val permissions = arrayOf(Manifest.permission.CAMERA) - requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSION) - } + private fun requestCameraPermission() { + val permissions = arrayOf(Manifest.permission.CAMERA) + requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSION) + } - /** Interface for notifying the host. */ - interface Callback { - /** Notifies host of the [CHIPDeviceInfo] from the scanned QR code. */ - fun onCHIPDeviceInfoReceived(deviceInfo: CHIPDeviceInfo) - } + /** Interface for notifying the host. */ + interface Callback { + /** Notifies host of the [CHIPDeviceInfo] from the scanned QR code. */ + fun onCHIPDeviceInfoReceived(deviceInfo: CHIPDeviceInfo) + } - companion object { - private const val TAG = "BarcodeFragment" - private const val REQUEST_CODE_CAMERA_PERMISSION = 100 + companion object { + private const val TAG = "BarcodeFragment" + private const val REQUEST_CODE_CAMERA_PERMISSION = 100 - @JvmStatic fun newInstance() = BarcodeFragment() + @JvmStatic + fun newInstance() = BarcodeFragment() - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } + private const val RATIO_4_3_VALUE = 4.0 / 3.0 + private const val RATIO_16_9_VALUE = 16.0 / 9.0 + } } From c7c2ed2a47c9e1575230d37ece2c8162d17464ce Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Fri, 22 Sep 2023 11:07:53 -0400 Subject: [PATCH 3/3] Re-run kotlin formatter via scriptsd/helpers/kotlin-format.sh --- .../setuppayloadscanner/BarcodeFragment.kt | 354 +++++++++--------- 1 file changed, 175 insertions(+), 179 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt index f0a2747e1110c1..9a9b5a3322eb11 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/setuppayloadscanner/BarcodeFragment.kt @@ -36,8 +36,6 @@ import androidx.camera.lifecycle.ProcessCameraProvider import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.checkSelfPermission import androidx.fragment.app.Fragment -import chip.onboardingpayload.OnboardingPayload -import chip.onboardingpayload.OnboardingPayloadException import chip.onboardingpayload.OnboardingPayloadParser import chip.onboardingpayload.UnrecognizedQrCodeException import com.google.chip.chiptool.R @@ -55,214 +53,212 @@ import kotlin.math.min /** Launches the camera to scan for QR code. */ class BarcodeFragment : Fragment() { - private var _binding: BarcodeFragmentBinding? = null - private val binding - get() = _binding!! + private var _binding: BarcodeFragmentBinding? = null + private val binding + get() = _binding!! - private fun aspectRatio(width: Int, height: Int): Int { - val previewRatio = max(width, height).toDouble() / min(width, height) - if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) { - return AspectRatio.RATIO_4_3 - } - return AspectRatio.RATIO_16_9 + private fun aspectRatio(width: Int, height: Int): Int { + val previewRatio = max(width, height).toDouble() / min(width, height) + if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) { + return AspectRatio.RATIO_4_3 } + return AspectRatio.RATIO_16_9 + } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (!hasCameraPermission()) { - requestCameraPermission() - } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (!hasCameraPermission()) { + requestCameraPermission() } + } - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = BarcodeFragmentBinding.inflate(inflater, container, false) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = BarcodeFragmentBinding.inflate(inflater, container, false) - startCamera() - binding.inputAddressBtn.setOnClickListener { - FragmentUtil.getHost(this@BarcodeFragment, SelectActionFragment.Callback::class.java) - ?.onShowDeviceAddressInput() - } - - return binding.root + startCamera() + binding.inputAddressBtn.setOnClickListener { + FragmentUtil.getHost(this@BarcodeFragment, SelectActionFragment.Callback::class.java) + ?.onShowDeviceAddressInput() } - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + return binding.root + } - @SuppressLint("UnsafeOptInUsageError") - private fun startCamera() { - val cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity()) - cameraProviderFuture.addListener( - { - val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() - val metrics = - DisplayMetrics().also { binding.cameraView.display?.getRealMetrics(it) } - val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels) - // Preview - val preview: Preview = - Preview.Builder() - .setTargetAspectRatio(screenAspectRatio) - .setTargetRotation(binding.cameraView.display.rotation) - .build() - preview.setSurfaceProvider(binding.cameraView.surfaceProvider) + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } - // Setup barcode scanner - val imageAnalysis = - ImageAnalysis.Builder() - .setTargetAspectRatio(screenAspectRatio) - .setTargetRotation(binding.cameraView.display.rotation) - .build() - val cameraExecutor = Executors.newSingleThreadExecutor() - val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient() - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - processImageProxy(barcodeScanner, imageProxy) - } - // Select back camera as a default - val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA - try { - // Unbind use cases before rebinding - cameraProvider.unbindAll() + @SuppressLint("UnsafeOptInUsageError") + private fun startCamera() { + val cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity()) + cameraProviderFuture.addListener( + { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + val metrics = DisplayMetrics().also { binding.cameraView.display?.getRealMetrics(it) } + val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels) + // Preview + val preview: Preview = + Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(binding.cameraView.display.rotation) + .build() + preview.setSurfaceProvider(binding.cameraView.surfaceProvider) - // Bind use cases to camera - cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis) - } catch (exc: Exception) { - Log.e(TAG, "Use case binding failed", exc) - } - }, - ContextCompat.getMainExecutor(requireActivity()) - ) + // Setup barcode scanner + val imageAnalysis = + ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(binding.cameraView.display.rotation) + .build() + val cameraExecutor = Executors.newSingleThreadExecutor() + val barcodeScanner: BarcodeScanner = BarcodeScanning.getClient() + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + processImageProxy(barcodeScanner, imageProxy) + } + // Select back camera as a default + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + try { + // Unbind use cases before rebinding + cameraProvider.unbindAll() - // workaround: can not use gms to scan the code in China, added a EditText to debug - binding.manualCodeBtn.setOnClickListener { - val code = binding.manualCodeEditText.text.toString() - Log.d(TAG, "Submit Code:$code") - handleInputCode(code) + // Bind use cases to camera + cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis) + } catch (exc: Exception) { + Log.e(TAG, "Use case binding failed", exc) } + }, + ContextCompat.getMainExecutor(requireActivity()) + ) + + // workaround: can not use gms to scan the code in China, added a EditText to debug + binding.manualCodeBtn.setOnClickListener { + val code = binding.manualCodeEditText.text.toString() + Log.d(TAG, "Submit Code:$code") + handleInputCode(code) } + } - @ExperimentalGetImage - private fun processImageProxy(barcodeScanner: BarcodeScanner, imageProxy: ImageProxy) { - val inputImage = - InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees) + @ExperimentalGetImage + private fun processImageProxy(barcodeScanner: BarcodeScanner, imageProxy: ImageProxy) { + val inputImage = + InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees) - barcodeScanner - .process(inputImage) - .addOnSuccessListener { barcodes -> barcodes.forEach { handleScannedQrCode(it) } } - .addOnFailureListener { Log.e(TAG, it.message ?: it.toString()) } - .addOnCompleteListener { - // When the image is from CameraX analysis use case, must call image.close() on - // received - // images when finished using them. Otherwise, new images may not be received or the - // camera - // may stall. - imageProxy.close() - } + barcodeScanner + .process(inputImage) + .addOnSuccessListener { barcodes -> barcodes.forEach { handleScannedQrCode(it) } } + .addOnFailureListener { Log.e(TAG, it.message ?: it.toString()) } + .addOnCompleteListener { + // When the image is from CameraX analysis use case, must call image.close() on + // received + // images when finished using them. Otherwise, new images may not be received or the + // camera + // may stall. + imageProxy.close() + } + } + + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) { + if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_DENIED) { + showCameraPermissionAlert() + } + } else { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) } + } - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) { - if (grantResults.size == 1 && grantResults[0] == PackageManager.PERMISSION_DENIED) { - showCameraPermissionAlert() - } + private fun handleInputCode(code: String) { + try { + val payload = + if (code.startsWith("MT:")) { + OnboardingPayloadParser().parseQrCode(code) } else { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) + OnboardingPayloadParser().parseManualPairingCode(code) } - } - private fun handleInputCode(code: String) { - try { - val payload = if (code.startsWith("MT:")) { - OnboardingPayloadParser().parseQrCode(code) - } else { - OnboardingPayloadParser().parseManualPairingCode(code) - } - - FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) - ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) - } catch (ex: UnrecognizedQrCodeException) { - Log.e(TAG, "Unrecognized Code", ex) - Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() - } catch (ex: Exception) { - Log.e(TAG, "Exception, $ex") - Toast.makeText(requireContext(), "Occur Exception, $ex", Toast.LENGTH_SHORT).show() - } + FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) + } catch (ex: UnrecognizedQrCodeException) { + Log.e(TAG, "Unrecognized Code", ex) + Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + } catch (ex: Exception) { + Log.e(TAG, "Exception, $ex") + Toast.makeText(requireContext(), "Occur Exception, $ex", Toast.LENGTH_SHORT).show() } + } - private fun handleScannedQrCode(barcode: Barcode) { - Handler(Looper.getMainLooper()).post { - try { - val payload = - barcode.displayValue?.let { OnboardingPayloadParser().parseQrCode(it) } - ?: return@post + private fun handleScannedQrCode(barcode: Barcode) { + Handler(Looper.getMainLooper()).post { + try { + val payload = + barcode.displayValue?.let { OnboardingPayloadParser().parseQrCode(it) } ?: return@post - FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) - ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) - } catch (ex: UnrecognizedQrCodeException) { - Log.e(TAG, "Unrecognized QR Code", ex) - Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() - return@post - } - } + FragmentUtil.getHost(this@BarcodeFragment, Callback::class.java) + ?.onCHIPDeviceInfoReceived(CHIPDeviceInfo.fromSetupPayload(payload)) + } catch (ex: UnrecognizedQrCodeException) { + Log.e(TAG, "Unrecognized QR Code", ex) + Toast.makeText(requireContext(), "Unrecognized QR Code", Toast.LENGTH_SHORT).show() + return@post + } } + } - private fun showCameraPermissionAlert() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.camera_permission_missing_alert_title) - .setMessage(R.string.camera_permission_missing_alert_subtitle) - .setPositiveButton(R.string.camera_permission_missing_alert_try_again) { _, _ -> - requestCameraPermission() - } - .setCancelable(false) - .create() - .show() - } + private fun showCameraPermissionAlert() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.camera_permission_missing_alert_title) + .setMessage(R.string.camera_permission_missing_alert_subtitle) + .setPositiveButton(R.string.camera_permission_missing_alert_try_again) { _, _ -> + requestCameraPermission() + } + .setCancelable(false) + .create() + .show() + } - private fun showCameraUnavailableAlert() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.camera_unavailable_alert_title) - .setMessage(R.string.camera_unavailable_alert_subtitle) - .setPositiveButton(R.string.camera_unavailable_alert_exit) { _, _ -> - requireActivity().finish() - } - .setCancelable(false) - .create() - .show() - } + private fun showCameraUnavailableAlert() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.camera_unavailable_alert_title) + .setMessage(R.string.camera_unavailable_alert_subtitle) + .setPositiveButton(R.string.camera_unavailable_alert_exit) { _, _ -> + requireActivity().finish() + } + .setCancelable(false) + .create() + .show() + } - private fun hasCameraPermission(): Boolean { - return (PackageManager.PERMISSION_GRANTED == - checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) - } + private fun hasCameraPermission(): Boolean { + return (PackageManager.PERMISSION_GRANTED == + checkSelfPermission(requireContext(), Manifest.permission.CAMERA)) + } - private fun requestCameraPermission() { - val permissions = arrayOf(Manifest.permission.CAMERA) - requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSION) - } + private fun requestCameraPermission() { + val permissions = arrayOf(Manifest.permission.CAMERA) + requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSION) + } - /** Interface for notifying the host. */ - interface Callback { - /** Notifies host of the [CHIPDeviceInfo] from the scanned QR code. */ - fun onCHIPDeviceInfoReceived(deviceInfo: CHIPDeviceInfo) - } + /** Interface for notifying the host. */ + interface Callback { + /** Notifies host of the [CHIPDeviceInfo] from the scanned QR code. */ + fun onCHIPDeviceInfoReceived(deviceInfo: CHIPDeviceInfo) + } - companion object { - private const val TAG = "BarcodeFragment" - private const val REQUEST_CODE_CAMERA_PERMISSION = 100 + companion object { + private const val TAG = "BarcodeFragment" + private const val REQUEST_CODE_CAMERA_PERMISSION = 100 - @JvmStatic - fun newInstance() = BarcodeFragment() + @JvmStatic fun newInstance() = BarcodeFragment() - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } + private const val RATIO_4_3_VALUE = 4.0 / 3.0 + private const val RATIO_16_9_VALUE = 16.0 / 9.0 + } }