@@ -91,6 +91,14 @@ public class CameraSource {
91
91
*/
92
92
private static final float ASPECT_RATIO_TOLERANCE = 0.01f ;
93
93
94
+ public CameraSourceStateListener getStateListener () {
95
+ return mStateListener ;
96
+ }
97
+
98
+ public void setStateListener (CameraSourceStateListener stateListener ) {
99
+ this .mStateListener = stateListener ;
100
+ }
101
+
94
102
@ StringDef ({
95
103
Camera .Parameters .FOCUS_MODE_CONTINUOUS_PICTURE ,
96
104
Camera .Parameters .FOCUS_MODE_CONTINUOUS_VIDEO ,
@@ -122,11 +130,16 @@ public class CameraSource {
122
130
123
131
private int mFacing = CAMERA_FACING_BACK ;
124
132
133
+ private boolean mCameraFallbackAllowed = true ;
134
+
135
+ private CameraSourceStateListener mStateListener = null ;
136
+
125
137
/**
126
138
* Rotation of the device, and thus the associated preview images captured from the device.
127
139
* See {@link Frame.Metadata#getRotation()}.
128
140
*/
129
141
private int mRotation ;
142
+ private int mRequestedCameraId ;
130
143
131
144
private Size mPreviewSize ;
132
145
@@ -143,7 +156,9 @@ public class CameraSource {
143
156
// These instances need to be held onto to avoid GC of their underlying resources. Even though
144
157
// these aren't used outside of the method that creates them, they still must have hard
145
158
// references maintained to them.
159
+ @ SuppressWarnings ("FieldCanBeLocal" )
146
160
private SurfaceView mDummySurfaceView ;
161
+ @ SuppressWarnings ("FieldCanBeLocal" )
147
162
private SurfaceTexture mDummySurfaceTexture ;
148
163
149
164
/**
@@ -153,6 +168,8 @@ public class CameraSource {
153
168
private Thread mProcessingThread ;
154
169
private FrameProcessingRunnable mFrameProcessor ;
155
170
171
+ private boolean mCanTakePicture = false ;
172
+
156
173
/**
157
174
* Map to convert between a byte array, received from the camera, and its associated byte
158
175
* buffer. We use byte buffers internally because this is a more efficient way to call into
@@ -240,6 +257,16 @@ public Builder setFacing(int facing) {
240
257
return this ;
241
258
}
242
259
260
+ /**
261
+ * Sets whether fallback from front to back or vice versa is allowed.
262
+ * Used in case the requested camera was not available.
263
+ * Default: true.
264
+ */
265
+ public Builder setCameraFallbackAllowed (boolean allowed ) {
266
+ mCameraSource .mCameraFallbackAllowed = allowed ;
267
+ return this ;
268
+ }
269
+
243
270
/**
244
271
* Creates an instance of the camera source.
245
272
*/
@@ -356,6 +383,11 @@ public CameraSource start() throws IOException {
356
383
mFrameProcessor .setActive (true );
357
384
mProcessingThread .start ();
358
385
}
386
+
387
+ if (mStateListener != null ) {
388
+ mStateListener .onCameraSourceStarted ();
389
+ }
390
+
359
391
return this ;
360
392
}
361
393
@@ -377,10 +409,17 @@ public CameraSource start(SurfaceHolder surfaceHolder) throws IOException {
377
409
mCamera .setPreviewDisplay (surfaceHolder );
378
410
mCamera .startPreview ();
379
411
412
+ mCanTakePicture = true ;
413
+
380
414
mProcessingThread = new Thread (mFrameProcessor );
381
415
mFrameProcessor .setActive (true );
382
416
mProcessingThread .start ();
383
417
}
418
+
419
+ if (mStateListener != null ) {
420
+ mStateListener .onCameraSourceStarted ();
421
+ }
422
+
384
423
return this ;
385
424
}
386
425
@@ -411,6 +450,8 @@ public void stop() {
411
450
// clear the buffer to prevent oom exceptions
412
451
mBytesToByteBuffer .clear ();
413
452
453
+ mCanTakePicture = false ;
454
+
414
455
if (mCamera != null ) {
415
456
mCamera .stopPreview ();
416
457
mCamera .setPreviewCallbackWithBuffer (null );
@@ -433,6 +474,10 @@ public void stop() {
433
474
mCamera = null ;
434
475
}
435
476
}
477
+
478
+ if (mStateListener != null ) {
479
+ mStateListener .onCameraSourceStopped ();
480
+ }
436
481
}
437
482
438
483
/**
@@ -450,6 +495,22 @@ public int getCameraFacing() {
450
495
return mFacing ;
451
496
}
452
497
498
+ /**
499
+ * Sets whether fallback from front to back or vice versa is allowed.
500
+ * Used in case the requested camera was not available.
501
+ */
502
+ public boolean isCameraFallbackAllowed () {
503
+ return mCameraFallbackAllowed ;
504
+ }
505
+
506
+ public boolean isCameraFacingBackAvailable () {
507
+ return getIdForRequestedCamera (CAMERA_FACING_BACK ) != -1 ;
508
+ }
509
+
510
+ public boolean isCameraFacingFrontAvailable () {
511
+ return getIdForRequestedCamera (CAMERA_FACING_FRONT ) != -1 ;
512
+ }
513
+
453
514
public int doZoom (float scale ) {
454
515
synchronized (mCameraLock ) {
455
516
if (mCamera == null ) {
@@ -494,7 +555,10 @@ public int doZoom(float scale) {
494
555
*/
495
556
public void takePicture (ShutterCallback shutter , PictureCallback jpeg ) {
496
557
synchronized (mCameraLock ) {
497
- if (mCamera != null ) {
558
+ if (mCamera != null && mCanTakePicture ) {
559
+
560
+ mCanTakePicture = false ; // Preview is suspended until we're done
561
+
498
562
PictureStartCallback startCallback = new PictureStartCallback ();
499
563
startCallback .mDelegate = shutter ;
500
564
PictureDoneCallback doneCallback = new PictureDoneCallback ();
@@ -535,7 +599,8 @@ public boolean setFocusMode(@FocusMode String mode) {
535
599
synchronized (mCameraLock ) {
536
600
if (mCamera != null && mode != null ) {
537
601
Camera .Parameters parameters = mCamera .getParameters ();
538
- if (parameters .getSupportedFocusModes ().contains (mode )) {
602
+ final List <String > supportedFocusModes = parameters .getSupportedFlashModes ();
603
+ if (supportedFocusModes != null && supportedFocusModes .contains (mode )) {
539
604
parameters .setFocusMode (mode );
540
605
mCamera .setParameters (parameters );
541
606
mFocusMode = mode ;
@@ -575,7 +640,8 @@ public boolean setFlashMode(@FlashMode String mode) {
575
640
synchronized (mCameraLock ) {
576
641
if (mCamera != null && mode != null ) {
577
642
Camera .Parameters parameters = mCamera .getParameters ();
578
- if (parameters .getSupportedFlashModes ().contains (mode )) {
643
+ final List <String > supportedFlashModes = parameters .getSupportedFlashModes ();
644
+ if (supportedFlashModes != null && supportedFlashModes .contains (mode )) {
579
645
parameters .setFlashMode (mode );
580
646
mCamera .setParameters (parameters );
581
647
mFlashMode = mode ;
@@ -587,6 +653,15 @@ public boolean setFlashMode(@FlashMode String mode) {
587
653
}
588
654
}
589
655
656
+ public boolean isModeSupported (String mode ) {
657
+ if (mCamera != null ) {
658
+ Camera .Parameters parameters = mCamera .getParameters ();
659
+ final List <String > supportedModes = parameters .getSupportedFlashModes ();
660
+ return supportedModes != null && supportedModes .contains (mode );
661
+ }
662
+ return false ;
663
+ }
664
+
590
665
/**
591
666
* Starts camera auto-focus and registers a callback function to run when
592
667
* the camera is focused. This method is only valid when preview is active
@@ -600,7 +675,7 @@ public boolean setFlashMode(@FlashMode String mode) {
600
675
* <p/>
601
676
* <p>If the current flash mode is not
602
677
* {@link Camera.Parameters#FLASH_MODE_OFF}, flash may be
603
- * fired during auto-focus, depending on the driver and camera hardware.<p>
678
+ * fired during auto-focus, depending on the driver and camera hardware.</ p>
604
679
*
605
680
* @param cb the callback to run
606
681
* @see #cancelAutoFocus()
@@ -699,6 +774,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
699
774
synchronized (mCameraLock ) {
700
775
if (mCamera != null ) {
701
776
mCamera .startPreview ();
777
+ mCanTakePicture = true ;
702
778
}
703
779
}
704
780
}
@@ -740,11 +816,23 @@ public void onAutoFocusMoving(boolean start, Camera camera) {
740
816
*/
741
817
@ SuppressLint ("InlinedApi" )
742
818
private Camera createCamera () {
743
- int requestedCameraId = getIdForRequestedCamera (mFacing );
744
- if (requestedCameraId == -1 ) {
819
+ mRequestedCameraId = getIdForRequestedCamera (mFacing );
820
+
821
+ if (mRequestedCameraId == -1 && mCameraFallbackAllowed ) {
822
+ if (mFacing == CAMERA_FACING_BACK ) {
823
+ mFacing = CAMERA_FACING_FRONT ;
824
+ } else {
825
+ mFacing = CAMERA_FACING_BACK ;
826
+ }
827
+
828
+ mRequestedCameraId = getIdForRequestedCamera (mFacing );
829
+ }
830
+
831
+ if (mRequestedCameraId == -1 ) {
745
832
throw new RuntimeException ("Could not find requested camera." );
746
833
}
747
- Camera camera = Camera .open (requestedCameraId );
834
+
835
+ Camera camera = Camera .open (mRequestedCameraId );
748
836
749
837
SizePair sizePair = selectSizePair (camera , mRequestedPreviewWidth , mRequestedPreviewHeight );
750
838
if (sizePair == null ) {
@@ -770,11 +858,11 @@ private Camera createCamera() {
770
858
previewFpsRange [Camera .Parameters .PREVIEW_FPS_MAX_INDEX ]);
771
859
parameters .setPreviewFormat (ImageFormat .NV21 );
772
860
773
- setRotation (camera , parameters , requestedCameraId );
861
+ setRotation (camera , parameters , mRequestedCameraId );
774
862
775
863
if (mFocusMode != null ) {
776
- if ( parameters .getSupportedFocusModes (). contains (
777
- mFocusMode )) {
864
+ final List < String > supportedFocusModes = parameters .getSupportedFlashModes ();
865
+ if ( supportedFocusModes != null && supportedFocusModes . contains ( mFocusMode )) {
778
866
parameters .setFocusMode (mFocusMode );
779
867
} else {
780
868
Log .i (TAG , "Camera focus mode: " + mFocusMode + " is not supported on this device." );
@@ -785,13 +873,11 @@ private Camera createCamera() {
785
873
mFocusMode = parameters .getFocusMode ();
786
874
787
875
if (mFlashMode != null ) {
788
- if (parameters .getSupportedFlashModes () != null ) {
789
- if (parameters .getSupportedFlashModes ().contains (
790
- mFlashMode )) {
791
- parameters .setFlashMode (mFlashMode );
792
- } else {
793
- Log .i (TAG , "Camera flash mode: " + mFlashMode + " is not supported on this device." );
794
- }
876
+ final List <String > supportedFlashModes = parameters .getSupportedFlashModes ();
877
+ if (supportedFlashModes != null && supportedFlashModes .contains (mFlashMode )) {
878
+ parameters .setFlashMode (mFlashMode );
879
+ } else {
880
+ Log .i (TAG , "Camera flash mode: " + mFlashMode + " is not supported on this device." );
795
881
}
796
882
}
797
883
@@ -972,6 +1058,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
972
1058
return selectedFpsRange ;
973
1059
}
974
1060
1061
+ public void updateRotation () {
1062
+ if (mCamera != null ) {
1063
+ setRotation (mCamera , mCamera .getParameters (), mRequestedCameraId );
1064
+ }
1065
+ }
1066
+
975
1067
/**
976
1068
* Calculates the correct rotation for the given camera id and sets the rotation in the
977
1069
* parameters. It also sets the camera's display orientation and rotation.
@@ -1211,4 +1303,10 @@ public void run() {
1211
1303
}
1212
1304
}
1213
1305
}
1306
+
1307
+ public interface CameraSourceStateListener
1308
+ {
1309
+ void onCameraSourceStarted ();
1310
+ void onCameraSourceStopped ();
1311
+ }
1214
1312
}
0 commit comments