Existing 3-function callback to Kotlin Coroutines

In this particular case you can use a general approach to convert a callback-based API to a suspending function via suspendCoroutine function:

suspend fun CameraManager.openCamera(cameraId: String): CameraDevice? =
    suspendCoroutine { cont ->
        val callback = object : CameraDevice.StateCallback() {
            override fun onOpened(camera: CameraDevice) {
                cont.resume(camera)
            }

            override fun onDisconnected(camera: CameraDevice) {
                cont.resume(null)
            }

            override fun onError(camera: CameraDevice, error: Int) {
                // assuming that we don't care about the error in this example
                cont.resume(null) 
            }
        }
        openCamera(cameraId, callback, null)
    }

Now, in your application code you can just do manager.openCamera(cameraId) and get a reference to CameraDevice if it was opened successfully or null if it was not.


Use suspendCancellableCoroutine instead of suspendCoroutine with proper exception handling

suspend fun CameraManager.openCamera(cameraId: String): CameraDevice? =
        suspendCancellableCoroutine { cont ->
             val callback = object : CameraDevice.StateCallback() {
                 override fun onOpened(camera: CameraDevice) {
                   cont.resume(camera)
               }

               override fun onDisconnected(camera: CameraDevice) {
                   cont.resume(null)
               }

               override fun onError(camera: CameraDevice, error: Int) {
                   // Resume the coroutine by throwing an exception or resume with null
                   cont.resumeWithException(/* Insert a custom exception */) 
               }
        }
        openCamera(cameraId, callback, null)
    }

It is preferable to always choose suspendCancellableCoroutine to handle cancellation of the coroutine scope, or to propagate cancellation from the underlying API. Source with other great examples