@@ -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 .getSupportedFocusModes ();
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,36 @@ public boolean setFlashMode(@FlashMode String mode) {
587
653
}
588
654
}
589
655
656
+ /**
657
+ * Checks whether a specific flash mode is supported.
658
+ * If the camera source is not initialized yet - then it will return false.
659
+ * @param mode
660
+ * @return true only if camera is initialized and mode is supported.
661
+ */
662
+ public boolean isFlashModeSupported (String mode ) {
663
+ if (mCamera != null ) {
664
+ Camera .Parameters parameters = mCamera .getParameters ();
665
+ final List <String > supportedModes = parameters .getSupportedFlashModes ();
666
+ return supportedModes != null && supportedModes .contains (mode );
667
+ }
668
+ return false ;
669
+ }
670
+
671
+ /**
672
+ * Checks whether a specific focus mode is supported.
673
+ * If the camera source is not initialized yet - then it will return false.
674
+ * @param mode
675
+ * @return true only if camera is initialized and mode is supported.
676
+ */
677
+ public boolean isFocusModeSupported (String mode ) {
678
+ if (mCamera != null ) {
679
+ Camera .Parameters parameters = mCamera .getParameters ();
680
+ final List <String > supportedModes = parameters .getSupportedFocusModes ();
681
+ return supportedModes != null && supportedModes .contains (mode );
682
+ }
683
+ return false ;
684
+ }
685
+
590
686
/**
591
687
* Starts camera auto-focus and registers a callback function to run when
592
688
* the camera is focused. This method is only valid when preview is active
@@ -600,7 +696,7 @@ public boolean setFlashMode(@FlashMode String mode) {
600
696
* <p/>
601
697
* <p>If the current flash mode is not
602
698
* {@link Camera.Parameters#FLASH_MODE_OFF}, flash may be
603
- * fired during auto-focus, depending on the driver and camera hardware.<p>
699
+ * fired during auto-focus, depending on the driver and camera hardware.</ p>
604
700
*
605
701
* @param cb the callback to run
606
702
* @see #cancelAutoFocus()
@@ -699,6 +795,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
699
795
synchronized (mCameraLock ) {
700
796
if (mCamera != null ) {
701
797
mCamera .startPreview ();
798
+ mCanTakePicture = true ;
702
799
}
703
800
}
704
801
}
@@ -740,11 +837,23 @@ public void onAutoFocusMoving(boolean start, Camera camera) {
740
837
*/
741
838
@ SuppressLint ("InlinedApi" )
742
839
private Camera createCamera () {
743
- int requestedCameraId = getIdForRequestedCamera (mFacing );
744
- if (requestedCameraId == -1 ) {
840
+ mRequestedCameraId = getIdForRequestedCamera (mFacing );
841
+
842
+ if (mRequestedCameraId == -1 && mCameraFallbackAllowed ) {
843
+ if (mFacing == CAMERA_FACING_BACK ) {
844
+ mFacing = CAMERA_FACING_FRONT ;
845
+ } else {
846
+ mFacing = CAMERA_FACING_BACK ;
847
+ }
848
+
849
+ mRequestedCameraId = getIdForRequestedCamera (mFacing );
850
+ }
851
+
852
+ if (mRequestedCameraId == -1 ) {
745
853
throw new RuntimeException ("Could not find requested camera." );
746
854
}
747
- Camera camera = Camera .open (requestedCameraId );
855
+
856
+ Camera camera = Camera .open (mRequestedCameraId );
748
857
749
858
SizePair sizePair = selectSizePair (camera , mRequestedPreviewWidth , mRequestedPreviewHeight );
750
859
if (sizePair == null ) {
@@ -770,11 +879,11 @@ private Camera createCamera() {
770
879
previewFpsRange [Camera .Parameters .PREVIEW_FPS_MAX_INDEX ]);
771
880
parameters .setPreviewFormat (ImageFormat .NV21 );
772
881
773
- setRotation (camera , parameters , requestedCameraId );
882
+ setRotation (camera , parameters , mRequestedCameraId );
774
883
775
884
if (mFocusMode != null ) {
776
- if ( parameters .getSupportedFocusModes (). contains (
777
- mFocusMode )) {
885
+ final List < String > supportedFocusModes = parameters .getSupportedFocusModes ();
886
+ if ( supportedFocusModes != null && supportedFocusModes . contains ( mFocusMode )) {
778
887
parameters .setFocusMode (mFocusMode );
779
888
} else {
780
889
Log .i (TAG , "Camera focus mode: " + mFocusMode + " is not supported on this device." );
@@ -785,13 +894,11 @@ private Camera createCamera() {
785
894
mFocusMode = parameters .getFocusMode ();
786
895
787
896
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
- }
897
+ final List <String > supportedFlashModes = parameters .getSupportedFlashModes ();
898
+ if (supportedFlashModes != null && supportedFlashModes .contains (mFlashMode )) {
899
+ parameters .setFlashMode (mFlashMode );
900
+ } else {
901
+ Log .i (TAG , "Camera flash mode: " + mFlashMode + " is not supported on this device." );
795
902
}
796
903
}
797
904
@@ -972,6 +1079,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
972
1079
return selectedFpsRange ;
973
1080
}
974
1081
1082
+ public void updateRotation () {
1083
+ if (mCamera != null ) {
1084
+ setRotation (mCamera , mCamera .getParameters (), mRequestedCameraId );
1085
+ }
1086
+ }
1087
+
975
1088
/**
976
1089
* Calculates the correct rotation for the given camera id and sets the rotation in the
977
1090
* parameters. It also sets the camera's display orientation and rotation.
@@ -1211,4 +1324,10 @@ public void run() {
1211
1324
}
1212
1325
}
1213
1326
}
1327
+
1328
+ public interface CameraSourceStateListener
1329
+ {
1330
+ void onCameraSourceStarted ();
1331
+ void onCameraSourceStopped ();
1332
+ }
1214
1333
}
0 commit comments