@@ -99,6 +99,8 @@ class Camera2ApiManager(context: Context) {
9999 private set
100100 var isAutoWhiteBalanceEnabled: Boolean = true
101101 private set
102+ var isWhiteBalanceLockEnabled: Boolean = false
103+ private set
102104 var isRunning: Boolean = false
103105 private set
104106 private var fps = 30
@@ -409,6 +411,11 @@ class Camera2ApiManager(context: Context) {
409411 val builderInputSurface = this .builderInputSurface ? : return false
410412 val modes = characteristics.secureGet(CameraCharacteristics .CONTROL_AWB_AVAILABLE_MODES ) ? : return false
411413 if (! modes.contains(mode)) return false
414+ val maxRegionsAwb = characteristics.secureGet(CameraCharacteristics .CONTROL_MAX_REGIONS_AWB ) ? : 0
415+ if (maxRegionsAwb > 0 ) {
416+ val clearRect = MeteringRectangle (0 , 0 , 0 , 0 , MeteringRectangle .METERING_WEIGHT_DONT_CARE )
417+ builderInputSurface.set(CaptureRequest .CONTROL_AWB_REGIONS , arrayOf(clearRect))
418+ }
412419 builderInputSurface.set(CaptureRequest .CONTROL_AWB_MODE , mode)
413420 isAutoWhiteBalanceEnabled = applyRequest(builderInputSurface)
414421 return isAutoWhiteBalanceEnabled
@@ -453,6 +460,11 @@ class Camera2ApiManager(context: Context) {
453460 val builderInputSurface = this .builderInputSurface ? : return false
454461 val modes = characteristics.secureGet(CameraCharacteristics .CONTROL_AE_AVAILABLE_MODES ) ? : return false
455462 if (! modes.contains(CaptureRequest .CONTROL_AE_MODE_ON )) return false
463+ val maxRegionsAe = characteristics.secureGet(CameraCharacteristics .CONTROL_MAX_REGIONS_AE ) ? : 0
464+ if (maxRegionsAe > 0 ) {
465+ val clearRect = MeteringRectangle (0 , 0 , 0 , 0 , MeteringRectangle .METERING_WEIGHT_DONT_CARE )
466+ builderInputSurface.set(CaptureRequest .CONTROL_AE_REGIONS , arrayOf(clearRect))
467+ }
456468 builderInputSurface.set(CaptureRequest .CONTROL_AE_MODE , CaptureRequest .CONTROL_AE_MODE_ON )
457469 isAutoExposureEnabled = applyRequest(builderInputSurface)
458470 return isAutoExposureEnabled
@@ -492,6 +504,30 @@ class Camera2ApiManager(context: Context) {
492504 isExposureLockEnabled = false
493505 }
494506
507+ /* *
508+ * Lock auto white balance to the current value. The camera will stop adjusting white balance
509+ * automatically (useful to avoid color shifts from lighting changes).
510+ * @return true if success, false if fail (not supported or called before start camera)
511+ */
512+ fun enableWhiteBalanceLock (): Boolean {
513+ val characteristics = cameraCharacteristics ? : return false
514+ val builderInputSurface = this .builderInputSurface ? : return false
515+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
516+ val available = characteristics.secureGet(CameraCharacteristics .CONTROL_AWB_LOCK_AVAILABLE ) ? : return false
517+ if (! available) return false
518+ }
519+ builderInputSurface.set(CaptureRequest .CONTROL_AWB_LOCK , true )
520+ isWhiteBalanceLockEnabled = applyRequest(builderInputSurface)
521+ return isWhiteBalanceLockEnabled
522+ }
523+
524+ fun disableWhiteBalanceLock () {
525+ val builderInputSurface = this .builderInputSurface ? : return
526+ builderInputSurface.set(CaptureRequest .CONTROL_AWB_LOCK , false )
527+ applyRequest(builderInputSurface)
528+ isWhiteBalanceLockEnabled = false
529+ }
530+
495531 fun enableVideoStabilization (): Boolean {
496532 val characteristics = cameraCharacteristics ? : return false
497533 val builderInputSurface = this .builderInputSurface ? : return false
@@ -569,24 +605,30 @@ class Camera2ApiManager(context: Context) {
569605 return supportedExposure
570606 }
571607
572- fun tapToFocus (view : View , event : MotionEvent ): Boolean {
573- val builderInputSurface = this .builderInputSurface ? : return false
574- val characteristics = cameraCharacteristics ? : return false
575- val session = cameraCaptureSession ? : return false
576- if (characteristics.get(CameraCharacteristics .CONTROL_MAX_REGIONS_AF ) == 0 ) return false
577- val focusTag = " focus"
578- val sensorArraySize = characteristics.get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE ) ? : return false
608+ private fun getTapRect (view : View , event : MotionEvent ): MeteringRectangle ? {
609+ val characteristics = cameraCharacteristics ? : return null
610+ val sensorArraySize = characteristics.secureGet(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE ) ? : return null
611+
579612 val x = event.x
580613 val y = event.y
581614 val focusX = (x / view.width.toFloat()) * sensorArraySize.width()
582615 val focusY = (y / view.height.toFloat()) * sensorArraySize.height()
583- val focusRect = MeteringRectangle (
616+ return MeteringRectangle (
584617 (focusX - 100 ).toInt().coerceIn(0 , sensorArraySize.width()),
585618 (focusY - 100 ).toInt().coerceIn(0 , sensorArraySize.height()),
586619 (100 * 2 ).coerceIn(0 , sensorArraySize.width()),
587620 (100 * 2 ).coerceIn(0 , sensorArraySize.height()),
588621 MeteringRectangle .METERING_WEIGHT_MAX
589622 )
623+ }
624+
625+ fun tapToFocus (view : View , event : MotionEvent ): Boolean {
626+ val builderInputSurface = this .builderInputSurface ? : return false
627+ val session = cameraCaptureSession ? : return false
628+ val characteristics = cameraCharacteristics ? : return false
629+ if ((characteristics.secureGet(CameraCharacteristics .CONTROL_MAX_REGIONS_AF ) ? : 0 ) == 0 ) return false
630+ val focusRect = getTapRect(view, event) ? : return false
631+ val focusTag = " focus"
590632
591633 val captureCallbackHandler: CameraCaptureSession .CaptureCallback =
592634 object : CameraCaptureSession .CaptureCallback () {
@@ -621,6 +663,56 @@ class Camera2ApiManager(context: Context) {
621663 }
622664 }
623665
666+ /* *
667+ * Tap to meter exposure at a specific point.
668+ *
669+ * @param view The view where the touch event occurred
670+ * @param event The touch event containing coordinates
671+ * @return true if successful, false otherwise
672+ */
673+ fun tapToMeterExposure (view : View , event : MotionEvent ): Boolean {
674+ if (isExposureLockEnabled) return false
675+ val builderInputSurface = this .builderInputSurface ? : return false
676+ val characteristics = cameraCharacteristics ? : return false
677+ if ((characteristics.secureGet(CameraCharacteristics .CONTROL_MAX_REGIONS_AE ) ? : 0 ) == 0 ) return false
678+ val aeRect = getTapRect(view, event) ? : return false
679+
680+ return try {
681+ builderInputSurface.set(CaptureRequest .CONTROL_AE_REGIONS , arrayOf(aeRect))
682+ builderInputSurface.set(CaptureRequest .CONTROL_AE_MODE , CameraMetadata .CONTROL_AE_MODE_ON )
683+ isAutoExposureEnabled = applyRequest(builderInputSurface)
684+ isAutoExposureEnabled
685+ } catch (e: Exception ) {
686+ Log .e(TAG , " Error setting AE region" , e)
687+ false
688+ }
689+ }
690+
691+ /* *
692+ * Tap to meter white balance at a specific point.
693+ *
694+ * @param view The view where the touch event occurred
695+ * @param event The touch event containing coordinates
696+ * @return true if successful, false otherwise
697+ */
698+ fun tapToMeterWhiteBalance (view : View , event : MotionEvent ): Boolean {
699+ if (isWhiteBalanceLockEnabled) return false
700+ val builderInputSurface = this .builderInputSurface ? : return false
701+ val characteristics = cameraCharacteristics ? : return false
702+ if ((characteristics.secureGet(CameraCharacteristics .CONTROL_MAX_REGIONS_AWB ) ? : 0 ) == 0 ) return false
703+ val awbRect = getTapRect(view, event) ? : return false
704+
705+ return try {
706+ builderInputSurface.set(CaptureRequest .CONTROL_AWB_REGIONS , arrayOf(awbRect))
707+ builderInputSurface.set(CaptureRequest .CONTROL_AWB_MODE , CameraMetadata .CONTROL_AWB_MODE_AUTO )
708+ isAutoWhiteBalanceEnabled = applyRequest(builderInputSurface)
709+ isAutoWhiteBalanceEnabled
710+ } catch (e: Exception ) {
711+ Log .e(TAG , " Error setting AWB region" , e)
712+ false
713+ }
714+ }
715+
624716 /* *
625717 * Select camera facing
626718 *
@@ -961,6 +1053,8 @@ class Camera2ApiManager(context: Context) {
9611053
9621054 @JvmOverloads
9631055 fun closeCamera (resetSurface : Boolean = true) {
1056+ isExposureLockEnabled = false
1057+ isWhiteBalanceLockEnabled = false
9641058 isLanternEnabled = false
9651059 zoomLevel = 1.0f
9661060 cameraCaptureSession?.close()
0 commit comments