bookmark_border【Kotlin】Camera2 プレビューのSurfaceViewタップでフォーカスを固定する

プレビューしているSurfaceViewがタップされた座標に応じてフォーカス固定したかったけども、まとまった情報がなかったので個人的なメモ。
例外のハンドリングやCameraCaptureSessionのnullチェックなどは割愛しているので注意。

// Activityの中
private var cameraDevice: CameraDevice? = null
private var cameraSession: CameraCaptureSession? = null
private var previewRequestBuilder: CaptureRequest.Builder? = null
// Activityの中
private var cameraDevice: CameraDevice? = null
private var cameraSession: CameraCaptureSession? = null
private var previewRequestBuilder: CaptureRequest.Builder? = null
// 前提:
// ActivityCompat.requestPermissionsで、カメラ使用の許可をユーザから得ている
// カメラがすでにオープンしている。
//   onResume()とかで、上記のpreviewRequestBuilder, cameraDevice, cameraSessionにすでに参照を入れている。
//   CameraCaptureSession.StateCallback#onConfiguredまで行っていて、プレビューが始まっている。
// surfaceViewはプレビュー用のView
surfaceView.setOnTouchListener { _: View, motionEvent: MotionEvent ->
    if (motionEvent.action == MotionEvent.ACTION_DOWN) {
        // タップされた場所から20pxの範囲に対してフォーカスさせる
        // 画面のorientationに応じて別途座標の反転などが必要
        val rectangle = MeteringRectangle(motionEvent.x.toInt(), motionEvent.y.toInt(),
            20, 20, MeteringRectangle.METERING_WEIGHT_MAX)
        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, arrayOf(rectangle))
        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)
        // 露出の調整やフラッシュが必要なときは適宜previewRequestBuilder#setする
        // builder.set(CaptureRequest.CONTROL_AE_REGIONS, arrayOf(rectangle))
        // builder.set(CaptureRequest.CONTROL_AE_XXXXXXX, XXXXXXX)
        cameraSession!!.setRepeatingRequest(previewRequestBuilder.build(), null, null)
        // CallbackやHandlerを指定する場合
        /*
        cameraSession!!.setRepeatingRequest(previewRequestBuilder.build(), object :     CameraCaptureSession.CaptureCallback() {
            // コールバックが必要ならここに処理を記述
        }, handler)
        */
    }
    true
}