Skip to content

Commit 33c58f8

Browse files
committed
feat: Support focus depth/distance on android
1 parent 8e919c8 commit 33c58f8

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@ package com.mrousavy.camera.core
33
import android.Manifest
44
import android.content.Context
55
import android.content.pm.PackageManager
6+
import android.graphics.BitmapFactory
7+
import android.hardware.camera2.CameraMetadata
8+
import android.hardware.camera2.CaptureRequest
69
import android.media.AudioManager
710
import android.util.Log
811
import androidx.annotation.MainThread
12+
import androidx.annotation.OptIn
13+
import androidx.camera.camera2.interop.Camera2CameraControl
14+
import androidx.camera.camera2.interop.CaptureRequestOptions
15+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
916
import androidx.camera.core.Camera
1017
import androidx.camera.core.ImageAnalysis
1118
import androidx.camera.core.ImageCapture
@@ -211,6 +218,26 @@ class CameraSession(internal val context: Context, internal val callback: Callba
211218
// Frame Processor output will not receive a target rotation, user is responsible for rotating himself
212219
}
213220

221+
@ExperimentalCamera2Interop
222+
@SuppressLint("RestrictedApi")
223+
fun focusDepth(depth: Double) {
224+
val camera = camera ?: throw CameraNotReadyError()
225+
226+
try {
227+
Camera2CameraControl.from(camera.cameraControl).let {
228+
CaptureRequestOptions.Builder().apply {
229+
val distance = depth.toFloat()
230+
setCaptureRequestOption(CaptureRequest.LENS_FOCUS_DISTANCE, distance)
231+
setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_OFF)
232+
}.let { builder ->
233+
it.addCaptureRequestOptions(builder.build())
234+
}
235+
}
236+
} catch (e: CameraControl.OperationCanceledException) {
237+
throw FocusCanceledError()
238+
}
239+
}
240+
214241
interface Callback {
215242
fun onError(error: Throwable)
216243
fun onFrame(frame: Frame)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.mrousavy.camera.react
2+
3+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
4+
5+
@ExperimentalCamera2Interop
6+
fun CameraView.focusDepth(distance: Double) {
7+
cameraSession.focusDepth(distance)
8+
}

package/android/src/main/java/com/mrousavy/camera/react/CameraViewModule.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.mrousavy.camera.react
33
import android.Manifest
44
import android.content.pm.PackageManager
55
import android.util.Log
6+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop
67
import androidx.core.content.ContextCompat
78
import com.facebook.react.bridge.Callback
89
import com.facebook.react.bridge.Promise
@@ -188,6 +189,18 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
188189
}
189190
}
190191

192+
@ExperimentalCamera2Interop
193+
@ReactMethod
194+
fun focusDepth(viewTag: Int, distance: Double, promise: Promise) {
195+
backgroundCoroutineScope.launch {
196+
val view = findCameraView(viewTag)
197+
withPromise(promise) {
198+
view.focusDepth(distance)
199+
return@withPromise null
200+
}
201+
}
202+
}
203+
191204
private fun canRequestPermission(permission: String): Boolean {
192205
val activity = reactApplicationContext.currentActivity as? PermissionAwareActivity
193206
return activity?.shouldShowRequestPermissionRationale(permission) ?: false

package/src/Camera.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,27 @@ export class Camera extends React.PureComponent<CameraProps, CameraState> {
380380
throw tryParseNativeCameraError(e)
381381
}
382382
}
383+
384+
/**
385+
* Focus the camera to a specific distance.
386+
* @param {number} distance The distance to focus to. It should be lower than the minFocusDistance. Lower the value (closer to 0.001f), further the distance, higher the value (closer to the minFocusDistance), more macro the focus will be.
387+
*
388+
* Make sure the value doesn't exceed the device.minFocusDistance.
389+
*
390+
* @throws {@linkcode CameraRuntimeError} When any kind of error occured while focussing.
391+
* Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error
392+
* @example
393+
* ```ts
394+
* await camera.current.focusDepth(5)
395+
* ```
396+
*/
397+
public async focusDepth(distance: number): Promise<void> {
398+
try {
399+
return await CameraModule.focusDepth(this.handle, distance)
400+
} catch (e) {
401+
throw tryParseNativeCameraError(e)
402+
}
403+
}
383404
//#endregion
384405

385406
//#region Static Functions (NativeModule)

0 commit comments

Comments
 (0)