From ddcea5e8a1d8b6130ea2d9a19d6a6e53987b3e6f Mon Sep 17 00:00:00 2001 From: Mike Wong Date: Wed, 27 Apr 2022 13:14:23 +0200 Subject: [PATCH] Expose several more APIs to the client --- .../qrscanner/scanner/CameraStateCallback.kt | 5 ++ .../ch/ubique/qrscanner/view/QrScannerView.kt | 61 ++++++++++++++----- 2 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 qrscanner-core/src/main/java/ch/ubique/qrscanner/scanner/CameraStateCallback.kt diff --git a/qrscanner-core/src/main/java/ch/ubique/qrscanner/scanner/CameraStateCallback.kt b/qrscanner-core/src/main/java/ch/ubique/qrscanner/scanner/CameraStateCallback.kt new file mode 100644 index 0000000..5acb3f0 --- /dev/null +++ b/qrscanner-core/src/main/java/ch/ubique/qrscanner/scanner/CameraStateCallback.kt @@ -0,0 +1,5 @@ +package ch.ubique.qrscanner.scanner + +fun interface CameraStateCallback { + fun onCameraStateChanged(isActive: Boolean) +} \ No newline at end of file diff --git a/qrscanner-core/src/main/java/ch/ubique/qrscanner/view/QrScannerView.kt b/qrscanner-core/src/main/java/ch/ubique/qrscanner/view/QrScannerView.kt index b94d252..36d2d9e 100644 --- a/qrscanner-core/src/main/java/ch/ubique/qrscanner/view/QrScannerView.kt +++ b/qrscanner-core/src/main/java/ch/ubique/qrscanner/view/QrScannerView.kt @@ -19,10 +19,7 @@ import androidx.core.view.GestureDetectorCompat import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.findViewTreeLifecycleOwner import androidx.lifecycle.lifecycleScope -import ch.ubique.qrscanner.scanner.ImageAnalyzer -import ch.ubique.qrscanner.scanner.ImageDecoder -import ch.ubique.qrscanner.scanner.QrScannerCallback -import ch.ubique.qrscanner.scanner.ScanningMode +import ch.ubique.qrscanner.scanner.* import ch.ubique.qrscanner.util.CameraUtil class QrScannerView @JvmOverloads constructor( @@ -57,12 +54,16 @@ class QrScannerView @JvmOverloads constructor( }) private var rotation = Surface.ROTATION_0 - private var isCameraActive = false private var isFocusOnTapEnabled = true + private var autoActivateOnAttach = true private var imageDecoders: List = emptyList() private var scannerCallback: QrScannerCallback? = null private var scanningMode = ScanningMode.PARALLEL + private var cameraStateCallback: CameraStateCallback? = null + + var isCameraActive = false + private set init { addView(previewView) @@ -88,7 +89,7 @@ class QrScannerView @JvmOverloads constructor( initializePreview() initializeAnalysis() - if (CameraUtil.hasCameraPermission(context)) { + if (CameraUtil.hasCameraPermission(context) && autoActivateOnAttach) { activateCamera() } } @@ -116,7 +117,7 @@ class QrScannerView @JvmOverloads constructor( .build() camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis) - isCameraActive = true + setCameraState(true) }, mainExecutor) } @@ -129,10 +130,26 @@ class QrScannerView @JvmOverloads constructor( cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() cameraProvider.unbindAll() - isCameraActive = false + setCameraState(false) }, mainExecutor) } + /** + * Add an option to disable the automatic camera activation when the view is attached to the window. + * This might be desirable if the client wants to control the (de-)activation of the camera preview themselves + */ + fun setAutoActivateOnAttach(autoActivateOnAttach: Boolean) { + this.autoActivateOnAttach = autoActivateOnAttach + } + + /** + * Set a callback for when the camera state changes due to calls to [activateCamera] and [deactivateCamera] + */ + fun setCameraStateCallback(callback: CameraStateCallback) { + this.cameraStateCallback = callback + callback.onCameraStateChanged(isCameraActive) + } + /** * Set any number of image decoders that should be used to analyze the incoming camera frames */ @@ -183,6 +200,24 @@ class QrScannerView @JvmOverloads constructor( } } + /** + * Start a focus and metering action for the given focus point. This is intended for regular autofocus intervals. + * If you need tap to focus behavior, use [setFocusOnTap] instead. + */ + fun startAutofocus(focusPointX: Float, focusPointY: Float) { + if (isCameraActive) { + val metricPointFactory = previewView.meteringPointFactory + val point = metricPointFactory.createPoint(focusPointX, focusPointY) + val action = FocusMeteringAction.Builder(point).build() + camera?.cameraControl?.startFocusAndMetering(action) + } + } + + /** + * @return The active camera's info or null if it is not yet initialized + */ + fun getCameraInfo() = camera?.cameraInfo + private fun initializePreview() { preview = Preview.Builder() .setTargetResolution(Size(720, 1280)) @@ -207,13 +242,9 @@ class QrScannerView @JvmOverloads constructor( .apply { setAnalyzer(mainExecutor, analyzer) } } - private fun startAutofocus(focusPointX: Float, focusPointY: Float) { - if (isCameraActive) { - val metricPointFactory = previewView.meteringPointFactory - val point = metricPointFactory.createPoint(focusPointX, focusPointY) - val action = FocusMeteringAction.Builder(point).build() - camera?.cameraControl?.startFocusAndMetering(action) - } + private fun setCameraState(isActive: Boolean) { + this.isCameraActive = isActive + cameraStateCallback?.onCameraStateChanged(isActive) } } \ No newline at end of file