Skip to content

Instantly share code, notes, and snippets.

<application>
<component name="StudioFlags">
<option name="data">
<map>
<!-- This flag enables experimental automotive templates -->
<entry key="npw.templates.automotive" value="true" />
</map>
</option>
</component>
</application>
val cameraSession: CameraCaptureSession = ...
// Use still capture template to build our capture request
val captureRequest = cameraSession.device.createCaptureRequest(
CameraDevice.TEMPLATE_STILL_CAPTURE)
// Determine if this device supports distortion correction
val characteristics: CameraCharacteristics = ...
val supportsDistortionCorrection = characteristics.get(
CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES)?.contains(
val cameraManager: CameraManager = ...
// Get the two output targets from the activity / fragment
val surface1 = ... // from SurfaceView
val surface2 = ... // from SurfaceView
val dualCamera = findShortLongCameraPair(manager)!!
val outputTargets = DualCameraOutputs(
null, mutableListOf(surface1), mutableListOf(surface2))
fun findShortLongCameraPair(manager: CameraManager, facing: Int? = null): DualCamera? {
return findDualCameras(manager, facing).map {
val characteristics1 = manager.getCameraCharacteristics(it.physicalId1)
val characteristics2 = manager.getCameraCharacteristics(it.physicalId2)
// Query the focal lengths advertised by each physical camera
val focalLengths1 = characteristics1.get(
CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS) ?: floatArrayOf(0F)
val focalLengths2 = characteristics2.get(
/**
* Helper type definition that encapsulates 3 sets of output targets:
*
* 1. Logical camera
* 2. First physical camera
* 3. Second physical camera
*/
typealias DualCameraOutputs =
Triple<MutableList<Surface>?, MutableList<Surface>?, MutableList<Surface>?>
fun openDualCamera(cameraManager: CameraManager,
dualCamera: DualCamera,
executor: Executor = AsyncTask.SERIAL_EXECUTOR,
callback: (CameraDevice) -> Unit) {
cameraManager.openCamera(
dualCamera.logicalId, executor, object : CameraDevice.StateCallback() {
override fun onOpened(device: CameraDevice) = callback(device)
// Omitting for brevity...
override fun onError(device: CameraDevice, error: Int) = onDisconnected(device)
/**
* Helper class used to encapsulate a logical camera and two underlying
* physical cameras
*/
data class DualCamera(val logicalId: String, val physicalId1: String, val physicalId2: String)
fun findDualCameras(manager: CameraManager, facing: Int? = null): Array<DualCamera> {
val dualCameras = ArrayList<DualCamera>()
// Iterate over all the available camera characteristics
imageReader.setOnImageAvailableListener({
val frame = it.acquireNextImage()
// Do something with `frame` here
it.close()
}, null)
val frameBufferCount = 3 // just an example, depends on your usage of ImageReader
val imageReader = ImageReader.newInstance(
imageReaderSize.width, imageReaderSize.height, ImageFormat.YUV_420_888
frameBufferCount)
val surfaceView = findViewById<SurfaceView>(...)
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
// We do not need to specify image format, and it will be considered of type PRIV
// Surface is now ready and we could use it as an output target for CameraSession
}
...
})