4.5 KiB
This guide covers implementing low-light features using Night mode extensions and Low Light Boost (LLB).
Choosing the right tool
| Feature | Used for | Implementation | UX impact |
|---|---|---|---|
| Night mode | High-quality stills | ExtensionsManager |
Possibly requires user to hold still for several seconds. |
| LLB, AE mode | Real-time preview or video | Camera2Interop, CameraX utility |
Hardware drops the frame rate to increase brightness. |
| LLB, Play services | Real-time preview and video | SurfaceProcessor |
Software-based brightening; maintains a higher frame rate. |
Night mode extension
CameraX Extensions provide access to the device's built-in computational photography pipeline.
Basic setup
To set up the extension, initialize the extension manager:
// Use ListenableFuture.await() extension function for coroutine support
val extensionsManager = ExtensionsManager.getInstanceAsync(context, cameraProvider).await()
if (extensionsManager.isExtensionAvailable(cameraSelector, ExtensionMode.NIGHT)) {
val nightSelector = extensionsManager.getExtensionEnabledCameraSelector(
cameraSelector, ExtensionMode.NIGHT
)
cameraProvider.bindToLifecycle(lifecycleOwner, nightSelector, imageCapture, preview)
}
Comprehensive features
-
Image postview : Display a low-resolution image immediately while the multi-frame processing occurs.
val imageCapture = ImageCapture.Builder() .setPostviewEnabled(true) .build() -
Extension strength : Let users control the intensity of the night effect.
// Set the strength of the active extension (e.g. NIGHT mode intensity) val extensionsManager = ExtensionsManager.getInstanceAsync(context, cameraProvider).await() val extensionsControl = extensionsManager.getCameraExtensionsControl(camera.cameraControl) extensionsControl?.setExtensionStrength(strength) -
Capture progress : Show a UI progress bar for long exposures.
// Use the suspend extension function for takePicture to avoid callback boilerplate try { val result = imageCapture.takePicture(outputOptions) // Use result.savedUri or other fields } catch (e: ImageCaptureException) { // Handle capture failure }
Low-light boost
LLB is designed for preview and video streams where you prefer high frame rates.
AE mode
The built-in CameraX way to prioritize brightness. It modifies the hardware's auto-exposure algorithm.
-
Activation : Use
CameraControl.enableLowLightBoostAsync. -
Implementation :
// Enable Low Light Boost (LLB) natively in CameraX 1.4+ camera.cameraControl.enableLowLightBoostAsync(true) -
Monitoring : Observe
CameraInfo.lowLightBoostStateto track when the hardware actively applies the enhancement.
Google Play services LLB
It's a multi-step implementation that uses a session-based SurfaceProcessor.
Dependency : com.google.android.gms:play-services-camera-low-light-boost
To implement Google Play services LLB, follow these core steps:
-
Initialize client :
val client = LowLightBoost.getClient. -
Implement
SurfaceProcessor:- Manage session : Call
client.createSession. - Forward required metadata : Observe the camera's
TotalCaptureResultstream and forward every result to the session:session.processCaptureResult. - Provide surface : Get the input surface from the session,
session.getCameraSurface, and provide it to the camera'sSurfaceRequest. - Lifecycle : Release the session,
session.release, when the processor is closed or theSurfaceRequestcompletes.
- Manage session : Call
-
Wire using
CameraEffect:val effect = SimpleCameraEffect( CameraEffect.PREVIEW or CameraEffect.VIDEO_CAPTURE, executor, llbSurfaceProcessor ) { throw it } // Add to UseCaseGroup val useCaseGroup = UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(videoCapture) .addEffect(effect) .build() -
Scene detection : Use
session.setSceneDetectorCallbackto receiveboostStrengthupdates for real-time UI indicators.
Implementation notes
- Thread safety : Always handle
ExtensionsManagerandLowLightBoostClientinitialization asynchronously. - FPS trade-offs: AE mode LLB often drops the frame rate significantly to increase brightness.
- Compatibility : Extensions, Night Mode, possibly conflict with
ConcurrentCamera. Always verify support before binding.