1
+ // Copyright 2019 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
1
5
package io .flutter .plugins .camera ;
2
6
3
7
import static android .view .OrientationEventListener .ORIENTATION_UNKNOWN ;
47
51
import io .flutter .plugins .camera .media .MediaRecorderBuilder ;
48
52
import io .flutter .plugins .camera .types .ExposureMode ;
49
53
import io .flutter .plugins .camera .types .FlashMode ;
54
+ import io .flutter .plugins .camera .types .FocusMode ;
50
55
import io .flutter .plugins .camera .types .ResolutionPreset ;
51
56
import io .flutter .view .TextureRegistry .SurfaceTextureEntry ;
52
57
import java .io .File ;
@@ -95,6 +100,7 @@ public class Camera {
95
100
private int currentOrientation = ORIENTATION_UNKNOWN ;
96
101
private FlashMode flashMode ;
97
102
private ExposureMode exposureMode ;
103
+ private FocusMode focusMode ;
98
104
private PictureCaptureRequest pictureCaptureRequest ;
99
105
private CameraRegions cameraRegions ;
100
106
private int exposureOffset ;
@@ -128,6 +134,7 @@ public Camera(
128
134
this .applicationContext = activity .getApplicationContext ();
129
135
this .flashMode = FlashMode .auto ;
130
136
this .exposureMode = ExposureMode .auto ;
137
+ this .focusMode = FocusMode .auto ;
131
138
this .exposureOffset = 0 ;
132
139
orientationEventListener =
133
140
new OrientationEventListener (activity .getApplicationContext ()) {
@@ -168,7 +175,7 @@ private void initFps(CameraCharacteristics cameraCharacteristics) {
168
175
int upper = range .getUpper ();
169
176
Log .i ("Camera" , "[FPS Range Available] is:" + range );
170
177
if (upper >= 10 ) {
171
- if (fpsRange == null || upper < fpsRange .getUpper ()) {
178
+ if (fpsRange == null || upper > fpsRange .getUpper ()) {
172
179
fpsRange = range ;
173
180
}
174
181
}
@@ -221,7 +228,9 @@ public void onOpened(@NonNull CameraDevice device) {
221
228
previewSize .getWidth (),
222
229
previewSize .getHeight (),
223
230
exposureMode ,
224
- isExposurePointSupported ());
231
+ focusMode ,
232
+ isExposurePointSupported (),
233
+ isFocusPointSupported ());
225
234
} catch (CameraAccessException e ) {
226
235
dartMessenger .sendCameraErrorEvent (e .getMessage ());
227
236
close ();
@@ -309,7 +318,7 @@ public void onConfigured(@NonNull CameraCaptureSession session) {
309
318
cameraCaptureSession = session ;
310
319
311
320
updateFpsRange ();
312
- updateAutoFocus ( );
321
+ updateFocus ( focusMode );
313
322
updateFlash (flashMode );
314
323
updateExposure (exposureMode );
315
324
@@ -510,7 +519,7 @@ private void runPictureAutoFocus() {
510
519
assert (pictureCaptureRequest != null );
511
520
512
521
pictureCaptureRequest .setState (PictureCaptureRequest .State .focusing );
513
- lockAutoFocus ();
522
+ lockAutoFocus (pictureCaptureCallback );
514
523
}
515
524
516
525
private void runPicturePreCapture () {
@@ -570,7 +579,7 @@ public void onCaptureCompleted(
570
579
}
571
580
}
572
581
573
- private void lockAutoFocus () {
582
+ private void lockAutoFocus (CaptureCallback callback ) {
574
583
captureRequestBuilder .set (
575
584
CaptureRequest .CONTROL_AF_TRIGGER , CaptureRequest .CONTROL_AF_TRIGGER_START );
576
585
@@ -581,7 +590,7 @@ private void lockAutoFocus() {
581
590
private void unlockAutoFocus () {
582
591
captureRequestBuilder .set (
583
592
CaptureRequest .CONTROL_AF_TRIGGER , CameraMetadata .CONTROL_AF_TRIGGER_CANCEL );
584
- updateAutoFocus ( );
593
+ updateFocus ( focusMode );
585
594
try {
586
595
cameraCaptureSession .capture (captureRequestBuilder .build (), null , null );
587
596
} catch (CameraAccessException ignored ) {
@@ -764,25 +773,72 @@ public void setExposurePoint(@NonNull final Result result, Double x, Double y)
764
773
"setExposurePointFailed" , "Device does not have exposure point capabilities" , null );
765
774
return ;
766
775
}
767
- // Check if we are doing a reset or not
768
- if (x == null || y == null ) {
769
- x = 0.5 ;
770
- y = 0.5 ;
771
- }
772
- // Get the current region boundaries.
773
- Size maxBoundaries = getRegionBoundaries ();
774
- if (maxBoundaries == null ) {
776
+ // Check if the current region boundaries are known
777
+ if (cameraRegions .getMaxBoundaries () == null ) {
775
778
result .error ("setExposurePointFailed" , "Could not determine max region boundaries" , null );
776
779
return ;
777
780
}
778
781
// Set the metering rectangle
779
- cameraRegions .setAutoExposureMeteringRectangleFromPoint (x , y );
782
+ if (x == null || y == null ) cameraRegions .resetAutoExposureMeteringRectangle ();
783
+ else cameraRegions .setAutoExposureMeteringRectangleFromPoint (x , y );
780
784
// Apply it
781
785
updateExposure (exposureMode );
782
786
refreshPreviewCaptureSession (
783
787
() -> result .success (null ), (code , message ) -> result .error ("CameraAccess" , message , null ));
784
788
}
785
789
790
+ public void setFocusMode (@ NonNull final Result result , FocusMode mode )
791
+ throws CameraAccessException {
792
+ this .focusMode = mode ;
793
+
794
+ updateFocus (mode );
795
+
796
+ switch (mode ) {
797
+ case auto :
798
+ refreshPreviewCaptureSession (
799
+ null , (code , message ) -> result .error ("setFocusMode" , message , null ));
800
+ break ;
801
+ case locked :
802
+ lockAutoFocus (
803
+ new CaptureCallback () {
804
+ @ Override
805
+ public void onCaptureCompleted (
806
+ @ NonNull CameraCaptureSession session ,
807
+ @ NonNull CaptureRequest request ,
808
+ @ NonNull TotalCaptureResult result ) {
809
+ unlockAutoFocus ();
810
+ }
811
+ });
812
+ break ;
813
+ }
814
+ result .success (null );
815
+ }
816
+
817
+ public void setFocusPoint (@ NonNull final Result result , Double x , Double y )
818
+ throws CameraAccessException {
819
+ // Check if focus point functionality is available.
820
+ if (!isFocusPointSupported ()) {
821
+ result .error ("setFocusPointFailed" , "Device does not have focus point capabilities" , null );
822
+ return ;
823
+ }
824
+
825
+ // Check if the current region boundaries are known
826
+ if (cameraRegions .getMaxBoundaries () == null ) {
827
+ result .error ("setFocusPointFailed" , "Could not determine max region boundaries" , null );
828
+ return ;
829
+ }
830
+
831
+ // Set the metering rectangle
832
+ if (x == null || y == null ) {
833
+ cameraRegions .resetAutoFocusMeteringRectangle ();
834
+ } else {
835
+ cameraRegions .setAutoFocusMeteringRectangleFromPoint (x , y );
836
+ }
837
+
838
+ // Apply the new metering rectangle
839
+ setFocusMode (result , focusMode );
840
+ }
841
+
786
842
@ TargetApi (VERSION_CODES .P )
787
843
private boolean supportsDistortionCorrection () throws CameraAccessException {
788
844
int [] availableDistortionCorrectionModes =
@@ -832,6 +888,14 @@ private boolean isExposurePointSupported() throws CameraAccessException {
832
888
return supportedRegions != null && supportedRegions > 0 ;
833
889
}
834
890
891
+ private boolean isFocusPointSupported () throws CameraAccessException {
892
+ Integer supportedRegions =
893
+ cameraManager
894
+ .getCameraCharacteristics (cameraDevice .getId ())
895
+ .get (CameraCharacteristics .CONTROL_MAX_REGIONS_AF );
896
+ return supportedRegions != null && supportedRegions > 0 ;
897
+ }
898
+
835
899
public double getMinExposureOffset () throws CameraAccessException {
836
900
Range <Integer > range =
837
901
cameraManager
@@ -912,7 +976,7 @@ private void updateFpsRange() {
912
976
captureRequestBuilder .set (CaptureRequest .CONTROL_AE_TARGET_FPS_RANGE , fpsRange );
913
977
}
914
978
915
- private void updateAutoFocus ( ) {
979
+ private void updateFocus ( FocusMode mode ) {
916
980
if (useAutoFocus ) {
917
981
int [] modes = cameraCharacteristics .get (CameraCharacteristics .CONTROL_AF_AVAILABLE_MODES );
918
982
// Auto focus is not supported
@@ -923,8 +987,25 @@ private void updateAutoFocus() {
923
987
captureRequestBuilder .set (
924
988
CaptureRequest .CONTROL_AF_MODE , CaptureRequest .CONTROL_AF_MODE_OFF );
925
989
} else {
990
+ // Applying auto focus
991
+ switch (mode ) {
992
+ case locked :
993
+ captureRequestBuilder .set (
994
+ CaptureRequest .CONTROL_AF_MODE , CaptureRequest .CONTROL_AF_MODE_AUTO );
995
+ break ;
996
+ case auto :
997
+ captureRequestBuilder .set (
998
+ CaptureRequest .CONTROL_AF_MODE ,
999
+ recordingVideo
1000
+ ? CaptureRequest .CONTROL_AF_MODE_CONTINUOUS_VIDEO
1001
+ : CaptureRequest .CONTROL_AF_MODE_CONTINUOUS_PICTURE );
1002
+ default :
1003
+ break ;
1004
+ }
1005
+ MeteringRectangle afRect = cameraRegions .getAFMeteringRectangle ();
926
1006
captureRequestBuilder .set (
927
- CaptureRequest .CONTROL_AF_MODE , CaptureRequest .CONTROL_AF_MODE_CONTINUOUS_PICTURE );
1007
+ CaptureRequest .CONTROL_AF_REGIONS ,
1008
+ afRect == null ? null : new MeteringRectangle [] {afRect });
928
1009
}
929
1010
} else {
930
1011
captureRequestBuilder .set (CaptureRequest .CONTROL_AF_MODE , CaptureRequest .CONTROL_AF_MODE_OFF );
0 commit comments