mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 08:23:00 +01:00
Only bind camera use cases that the device supports.
The new camera implementation always bound all four CameraX use cases (preview, image capture, video capture, and image analysis) regardless of device capabilities. On devices with LEGACY camera hardware level, this causes image capture to fail with "Capture request failed with reason ERROR" because the hardware cannot handle that many simultaneous use cases. This change makes video capture and QR scanning use case binding conditional based on CameraXModePolicy, which already determines device capabilities. Video capture is only bound when the device supports mixed mode (image + video simultaneously). QR scanning analysis is only bound when explicitly requested.
This commit is contained in:
committed by
Cody Henthorne
parent
a2057e20d2
commit
c37bb96aab
@@ -76,6 +76,8 @@ fun CameraScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
roundCorners: Boolean = true,
|
||||
contentAlignment: Alignment = Alignment.Center,
|
||||
enableVideoCapture: Boolean = true,
|
||||
enableQrScanning: Boolean = false,
|
||||
content: @Composable BoxScope.() -> Unit = {}
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
@@ -103,7 +105,9 @@ fun CameraScreen(
|
||||
lifecycleOwner = lifecycleOwner,
|
||||
cameraProvider = cameraProvider,
|
||||
surfaceProvider = surfaceProvider,
|
||||
context = context
|
||||
context = context,
|
||||
enableVideoCapture = enableVideoCapture,
|
||||
enableQrScanning = enableQrScanning
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import androidx.lifecycle.LifecycleOwner
|
||||
|
||||
sealed interface CameraScreenEvents {
|
||||
|
||||
/** Binds a camera to a sruface provider. */
|
||||
/** Binds a camera to a surface provider. */
|
||||
data class BindCamera(
|
||||
val lifecycleOwner: LifecycleOwner,
|
||||
val cameraProvider: ProcessCameraProvider,
|
||||
val surfaceProvider: Preview.SurfaceProvider,
|
||||
val context: Context
|
||||
val context: Context,
|
||||
val enableVideoCapture: Boolean = true,
|
||||
val enableQrScanning: Boolean = false
|
||||
) : CameraScreenEvents
|
||||
|
||||
/** Focuses the camera on a point. */
|
||||
|
||||
@@ -344,27 +344,35 @@ class CameraScreenViewModel : ViewModel() {
|
||||
.setResolutionSelector(resolutionSelector)
|
||||
.build()
|
||||
|
||||
// Video capture (16:9 is default for video)
|
||||
val recorder = Recorder.Builder()
|
||||
.setAspectRatio(AspectRatio.RATIO_16_9)
|
||||
.setQualitySelector(
|
||||
androidx.camera.video.QualitySelector.from(
|
||||
androidx.camera.video.Quality.HIGHEST,
|
||||
androidx.camera.video.FallbackStrategy.higherQualityOrLowerThan(androidx.camera.video.Quality.HD)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
val videoCaptureUseCase = VideoCapture.withOutput(recorder)
|
||||
// Build the list of use cases based on device capabilities
|
||||
val useCases = mutableListOf<androidx.camera.core.UseCase>(preview, imageCaptureUseCase)
|
||||
|
||||
// Image analysis for QR code detection
|
||||
val imageAnalysisUseCase = ImageAnalysis.Builder()
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build()
|
||||
.also {
|
||||
it.setAnalyzer(imageAnalysisExecutor) { imageProxy ->
|
||||
processImageForQrCode(imageProxy)
|
||||
var videoCaptureUseCase: VideoCapture<Recorder>? = null
|
||||
if (event.enableVideoCapture) {
|
||||
val recorder = Recorder.Builder()
|
||||
.setAspectRatio(AspectRatio.RATIO_16_9)
|
||||
.setQualitySelector(
|
||||
androidx.camera.video.QualitySelector.from(
|
||||
androidx.camera.video.Quality.HIGHEST,
|
||||
androidx.camera.video.FallbackStrategy.higherQualityOrLowerThan(androidx.camera.video.Quality.HD)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
videoCaptureUseCase = VideoCapture.withOutput(recorder)
|
||||
useCases += videoCaptureUseCase
|
||||
}
|
||||
|
||||
if (event.enableQrScanning) {
|
||||
val imageAnalysisUseCase = ImageAnalysis.Builder()
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build()
|
||||
.also {
|
||||
it.setAnalyzer(imageAnalysisExecutor) { imageProxy ->
|
||||
processImageForQrCode(imageProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
useCases += imageAnalysisUseCase
|
||||
}
|
||||
|
||||
// Select camera based on lensFacing
|
||||
val cameraSelector = CameraSelector.Builder()
|
||||
@@ -379,10 +387,7 @@ class CameraScreenViewModel : ViewModel() {
|
||||
camera = event.cameraProvider.bindToLifecycle(
|
||||
event.lifecycleOwner,
|
||||
cameraSelector,
|
||||
preview,
|
||||
imageCaptureUseCase,
|
||||
videoCaptureUseCase,
|
||||
imageAnalysisUseCase
|
||||
*useCases.toTypedArray()
|
||||
)
|
||||
|
||||
lifecycleOwner = event.lifecycleOwner
|
||||
|
||||
Reference in New Issue
Block a user