Fix QR processing resolution and allow front camera use for device linking.

This commit is contained in:
Cody Henthorne
2022-10-13 09:57:44 -04:00
committed by Alex Hart
parent 3d14c05114
commit ea9bf0ccd5
11 changed files with 215 additions and 52 deletions

View File

@@ -67,7 +67,7 @@ class QrProcessor {
companion object {
private val TAG = Log.tag(QrProcessor::class.java)
/** For debugging only */
var listener: ((LuminanceSource) -> Unit)? = null
}
}

View File

@@ -57,6 +57,11 @@ class QrScannerView @JvmOverloads constructor(
})
}
fun toggleCamera() {
Log.d(TAG, "Toggling camera")
scannerView?.toggleCamera()
}
companion object {
private val TAG = Log.tag(QrScannerView::class.java)
}

View File

@@ -7,4 +7,5 @@ import androidx.lifecycle.LifecycleOwner
*/
interface ScannerView {
fun start(lifecycleOwner: LifecycleOwner)
fun toggleCamera()
}

View File

@@ -18,8 +18,27 @@ internal class ScannerView19 constructor(
private val scanListener: ScanListener
) : FrameLayout(context), ScannerView {
private var lifecycleOwner: LifecycleOwner? = null
private var scanningThread: ScanningThread? = null
private val cameraView: QrCameraView
private lateinit var cameraView: QrCameraView
private val lifecycleObserver = object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
val scanningThread = ScanningThread()
scanningThread.setScanListener(scanListener)
cameraView.onResume()
cameraView.setPreviewCallback(scanningThread)
scanningThread.start()
this@ScannerView19.scanningThread = scanningThread
}
override fun onPause(owner: LifecycleOwner) {
cameraView.onPause()
scanningThread?.stopScanning()
scanningThread = null
}
}
init {
cameraView = QrCameraView(context)
@@ -28,22 +47,16 @@ internal class ScannerView19 constructor(
}
override fun start(lifecycleOwner: LifecycleOwner) {
lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
val scanningThread = ScanningThread()
scanningThread.setScanListener(scanListener)
cameraView.onResume()
cameraView.setPreviewCallback(scanningThread)
scanningThread.start()
this.lifecycleOwner?.lifecycle?.removeObserver(lifecycleObserver)
this.lifecycleOwner = lifecycleOwner
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}
this@ScannerView19.scanningThread = scanningThread
}
override fun onPause(owner: LifecycleOwner) {
cameraView.onPause()
scanningThread?.stopScanning()
scanningThread = null
}
})
override fun toggleCamera() {
cameraView.toggleCamera()
lifecycleOwner?.let {
lifecycleObserver.onPause(it)
lifecycleObserver.onResume(it)
}
}
}

View File

@@ -2,9 +2,9 @@ package org.signal.qr
import android.annotation.SuppressLint
import android.content.Context
import android.util.Size
import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
@@ -28,19 +28,42 @@ internal class ScannerView21 constructor(
private val listener: ScanListener
) : FrameLayout(context), ScannerView {
private var lifecyleOwner: LifecycleOwner? = null
private val analyzerExecutor = Executors.newSingleThreadExecutor()
private var cameraProvider: ProcessCameraProvider? = null
private var cameraSelector: CameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
private var camera: Camera? = null
private var previewView: PreviewView
private val qrProcessor = QrProcessor()
private val lifecycleObserver: DefaultLifecycleObserver = object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
cameraProvider = null
camera = null
analyzerExecutor.shutdown()
}
}
init {
previewView = PreviewView(context)
previewView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
addView(previewView)
}
override fun toggleCamera() {
cameraSelector = if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
CameraSelector.DEFAULT_FRONT_CAMERA
} else {
CameraSelector.DEFAULT_BACK_CAMERA
}
lifecyleOwner?.let { start(it) }
}
override fun start(lifecycleOwner: LifecycleOwner) {
this.lifecyleOwner?.lifecycle?.removeObserver(lifecycleObserver)
this.lifecyleOwner = lifecycleOwner
previewView.post {
Log.i(TAG, "Starting")
ProcessCameraProvider.getInstance(context).apply {
@@ -54,13 +77,7 @@ internal class ScannerView21 constructor(
}
}
lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
cameraProvider = null
camera = null
analyzerExecutor.shutdown()
}
})
lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
}
private fun onCameraProvider(lifecycle: LifecycleOwner, cameraProvider: ProcessCameraProvider?) {
@@ -71,10 +88,14 @@ internal class ScannerView21 constructor(
Log.i(TAG, "Initializing use cases")
val preview = Preview.Builder().build()
val resolution = Size(480, 640)
val preview = Preview.Builder()
.setTargetResolution(resolution)
.build()
val imageAnalysis = ImageAnalysis.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_4_3)
.setTargetResolution(resolution)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
@@ -88,10 +109,13 @@ internal class ScannerView21 constructor(
}
cameraProvider.unbindAll()
camera = cameraProvider.bindToLifecycle(lifecycle, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageAnalysis)
camera = cameraProvider.bindToLifecycle(lifecycle, cameraSelector, preview, imageAnalysis)
preview.setSurfaceProvider(previewView.surfaceProvider)
Log.d(TAG, "Preview: ${preview.resolutionInfo}")
Log.d(TAG, "Analysis: ${imageAnalysis.resolutionInfo}")
this.cameraProvider = cameraProvider
}

View File

@@ -47,7 +47,7 @@ public class QrCameraView extends ViewGroup {
private final OnOrientationChange onOrientationChange;
private volatile Optional<Camera> camera = Optional.empty();
private final int cameraId = CameraInfo.CAMERA_FACING_BACK;
private volatile int cameraId = CameraInfo.CAMERA_FACING_BACK;
private volatile int displayOrientation = -1;
private @NonNull State state = State.PAUSED;
@@ -161,6 +161,14 @@ public class QrCameraView extends ViewGroup {
return state != State.PAUSED;
}
public void toggleCamera() {
if (cameraId == CameraInfo.CAMERA_FACING_BACK) {
cameraId = CameraInfo.CAMERA_FACING_FRONT;
} else {
cameraId = CameraInfo.CAMERA_FACING_BACK;
}
}
@SuppressWarnings("SuspiciousNameCombination")
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {