Skip to content

Commit

Permalink
Init ExtensionsManager and ProcessCameraProvider before checking Exte…
Browse files Browse the repository at this point in the history
…nsion availability (#48)

* Init ExtensionsManager and ProcessCameraProvider before checking Extension availability

* Remove withSuspendablePromise

* Async init ProcessCameraProvider

* Remove that unnecessary Future caching again

* Post `update` on previewView

Fixes "previewView.display must not be null!" error
  • Loading branch information
mrousavy authored Mar 12, 2021
1 parent c4d7d81 commit d85126d
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 180 deletions.
70 changes: 39 additions & 31 deletions android/src/main/java/com/mrousavy/camera/CameraView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
private val reactContext: ReactContext
get() = context as ReactContext

@Suppress("JoinDeclarationAndAssignment")
internal val previewView: PreviewView
private val cameraExecutor = Executors.newSingleThreadExecutor()
internal val takePhotoExecutor = Executors.newSingleThreadExecutor()
Expand Down Expand Up @@ -192,30 +193,35 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
/**
* Invalidate all React Props and reconfigure the device
*/
fun update(changedProps: ArrayList<String>) = GlobalScope.launch(Dispatchers.Main) {
try {
val shouldReconfigureSession = changedProps.containsAny(propsThatRequireSessionReconfiguration)
val shouldReconfigureZoom = shouldReconfigureSession || changedProps.contains("zoom")
val shouldReconfigureTorch = shouldReconfigureSession || changedProps.contains("torch")

if (changedProps.contains("isActive")) {
updateLifecycleState()
}
if (shouldReconfigureSession) {
configureSession()
}
if (shouldReconfigureZoom) {
val scaled = (zoom.toFloat() * (maxZoom - minZoom)) + minZoom
camera!!.cameraControl.setZoomRatio(scaled)
}
if (shouldReconfigureTorch) {
camera!!.cameraControl.enableTorch(torch == "on")
}
if (changedProps.contains("enableZoomGesture")) {
setOnTouchListener(if (enableZoomGesture) touchEventListener else null)
fun update(changedProps: ArrayList<String>) = previewView.post {
// TODO: Does this introduce too much overhead?
// I need to .post on the previewView because it might've not been initialized yet
// I need to use GlobalScope.launch because of the suspend fun [configureSession]
GlobalScope.launch(Dispatchers.Main) {
try {
val shouldReconfigureSession = changedProps.containsAny(propsThatRequireSessionReconfiguration)
val shouldReconfigureZoom = shouldReconfigureSession || changedProps.contains("zoom")
val shouldReconfigureTorch = shouldReconfigureSession || changedProps.contains("torch")

if (changedProps.contains("isActive")) {
updateLifecycleState()
}
if (shouldReconfigureSession) {
configureSession()
}
if (shouldReconfigureZoom) {
val scaled = (zoom.toFloat() * (maxZoom - minZoom)) + minZoom
camera!!.cameraControl.setZoomRatio(scaled)
}
if (shouldReconfigureTorch) {
camera!!.cameraControl.enableTorch(torch == "on")
}
if (changedProps.contains("enableZoomGesture")) {
setOnTouchListener(if (enableZoomGesture) touchEventListener else null)
}
} catch (e: CameraError) {
invokeOnError(e)
}
} catch (e: CameraError) {
invokeOnError(e)
}
}

Expand All @@ -225,7 +231,8 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
@SuppressLint("UnsafeExperimentalUsageError", "RestrictedApi")
private suspend fun configureSession() {
try {
Log.d(REACT_CLASS, "Configuring session...")
val startTime = System.currentTimeMillis()
Log.i(REACT_CLASS, "Configuring session...")
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
throw MicrophonePermissionError()
}
Expand All @@ -236,12 +243,12 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
throw NoCameraDeviceError()
}
if (format != null)
Log.d(REACT_CLASS, "Configuring session with Camera ID $cameraId and custom format...")
Log.i(REACT_CLASS, "Configuring session with Camera ID $cameraId and custom format...")
else
Log.d(REACT_CLASS, "Configuring session with Camera ID $cameraId and default format options...")
Log.i(REACT_CLASS, "Configuring session with Camera ID $cameraId and default format options...")

// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider = ProcessCameraProvider.getInstance(context).await()
val cameraProvider = ProcessCameraProvider.getInstance(reactContext).await()

val cameraSelector = CameraSelector.Builder().byID(cameraId!!).build()

Expand All @@ -257,15 +264,15 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {

if (format == null) {
// let CameraX automatically find best resolution for the target aspect ratio
Log.d(REACT_CLASS, "No custom format has been set, CameraX will automatically determine best configuration...")
Log.i(REACT_CLASS, "No custom format has been set, CameraX will automatically determine best configuration...")
val aspectRatio = aspectRatio(previewView.width, previewView.height)
previewBuilder.setTargetAspectRatio(aspectRatio)
imageCaptureBuilder.setTargetAspectRatio(aspectRatio)
videoCaptureBuilder.setTargetAspectRatio(aspectRatio)
} else {
// User has selected a custom format={}. Use that
val format = DeviceFormat(format!!)
Log.d(REACT_CLASS, "Using custom format - photo: ${format.photoSize}, video: ${format.videoSize} @ $fps FPS")
Log.i(REACT_CLASS, "Using custom format - photo: ${format.photoSize}, video: ${format.videoSize} @ $fps FPS")
previewBuilder.setDefaultResolution(format.photoSize)
imageCaptureBuilder.setDefaultResolution(format.photoSize)
videoCaptureBuilder.setDefaultResolution(format.photoSize)
Expand All @@ -275,7 +282,7 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
// Camera supports the given FPS (frame rate range)
val frameDuration = (1.0 / fps.toDouble()).toLong() * 1_000_000_000

Log.d(REACT_CLASS, "Setting AE_TARGET_FPS_RANGE to $fps-$fps, and SENSOR_FRAME_DURATION to $frameDuration")
Log.i(REACT_CLASS, "Setting AE_TARGET_FPS_RANGE to $fps-$fps, and SENSOR_FRAME_DURATION to $frameDuration")
Camera2Interop.Extender(previewBuilder)
.setCaptureRequestOption(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(fps, fps))
.setCaptureRequestOption(CaptureRequest.SENSOR_FRAME_DURATION, frameDuration)
Expand Down Expand Up @@ -333,7 +340,8 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
minZoom = camera!!.cameraInfo.zoomState.value?.minZoomRatio ?: 1f
maxZoom = camera!!.cameraInfo.zoomState.value?.maxZoomRatio ?: 1f

Log.d(REACT_CLASS, "Session configured! Camera: ${camera!!}")
val duration = System.currentTimeMillis() - startTime
Log.i(REACT_CLASS, "Session configured in $duration ms! Camera: ${camera!!}")
invokeOnInitialized()
} catch (exc: Throwable) {
throw when (exc) {
Expand Down
Loading

0 comments on commit d85126d

Please sign in to comment.