Skip to content

Commit cef27f5

Browse files
committed
Make things safer
1. Fallback for requested camera 2. Not crashing when taking pictures at the wrong time 3. Callback for state changes - to be able to take actions only when actually ready 4. Query for modes, like is flash available?
1 parent a558930 commit cef27f5

File tree

1 file changed

+136
-17
lines changed
  • visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera

1 file changed

+136
-17
lines changed

visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java

+136-17
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ public class CameraSource {
9191
*/
9292
private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
9393

94+
public CameraSourceStateListener getStateListener() {
95+
return mStateListener;
96+
}
97+
98+
public void setStateListener(CameraSourceStateListener stateListener) {
99+
this.mStateListener = stateListener;
100+
}
101+
94102
@StringDef({
95103
Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
96104
Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
@@ -122,11 +130,16 @@ public class CameraSource {
122130

123131
private int mFacing = CAMERA_FACING_BACK;
124132

133+
private boolean mCameraFallbackAllowed = true;
134+
135+
private CameraSourceStateListener mStateListener = null;
136+
125137
/**
126138
* Rotation of the device, and thus the associated preview images captured from the device.
127139
* See {@link Frame.Metadata#getRotation()}.
128140
*/
129141
private int mRotation;
142+
private int mRequestedCameraId;
130143

131144
private Size mPreviewSize;
132145

@@ -143,7 +156,9 @@ public class CameraSource {
143156
// These instances need to be held onto to avoid GC of their underlying resources. Even though
144157
// these aren't used outside of the method that creates them, they still must have hard
145158
// references maintained to them.
159+
@SuppressWarnings("FieldCanBeLocal")
146160
private SurfaceView mDummySurfaceView;
161+
@SuppressWarnings("FieldCanBeLocal")
147162
private SurfaceTexture mDummySurfaceTexture;
148163

149164
/**
@@ -153,6 +168,8 @@ public class CameraSource {
153168
private Thread mProcessingThread;
154169
private FrameProcessingRunnable mFrameProcessor;
155170

171+
private boolean mCanTakePicture = false;
172+
156173
/**
157174
* Map to convert between a byte array, received from the camera, and its associated byte
158175
* 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) {
240257
return this;
241258
}
242259

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+
243270
/**
244271
* Creates an instance of the camera source.
245272
*/
@@ -356,6 +383,11 @@ public CameraSource start() throws IOException {
356383
mFrameProcessor.setActive(true);
357384
mProcessingThread.start();
358385
}
386+
387+
if (mStateListener != null) {
388+
mStateListener.onCameraSourceStarted();
389+
}
390+
359391
return this;
360392
}
361393

@@ -377,10 +409,17 @@ public CameraSource start(SurfaceHolder surfaceHolder) throws IOException {
377409
mCamera.setPreviewDisplay(surfaceHolder);
378410
mCamera.startPreview();
379411

412+
mCanTakePicture = true;
413+
380414
mProcessingThread = new Thread(mFrameProcessor);
381415
mFrameProcessor.setActive(true);
382416
mProcessingThread.start();
383417
}
418+
419+
if (mStateListener != null) {
420+
mStateListener.onCameraSourceStarted();
421+
}
422+
384423
return this;
385424
}
386425

@@ -411,6 +450,8 @@ public void stop() {
411450
// clear the buffer to prevent oom exceptions
412451
mBytesToByteBuffer.clear();
413452

453+
mCanTakePicture = false;
454+
414455
if (mCamera != null) {
415456
mCamera.stopPreview();
416457
mCamera.setPreviewCallbackWithBuffer(null);
@@ -433,6 +474,10 @@ public void stop() {
433474
mCamera = null;
434475
}
435476
}
477+
478+
if (mStateListener != null) {
479+
mStateListener.onCameraSourceStopped();
480+
}
436481
}
437482

438483
/**
@@ -450,6 +495,22 @@ public int getCameraFacing() {
450495
return mFacing;
451496
}
452497

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+
453514
public int doZoom(float scale) {
454515
synchronized (mCameraLock) {
455516
if (mCamera == null) {
@@ -494,7 +555,10 @@ public int doZoom(float scale) {
494555
*/
495556
public void takePicture(ShutterCallback shutter, PictureCallback jpeg) {
496557
synchronized (mCameraLock) {
497-
if (mCamera != null) {
558+
if (mCamera != null && mCanTakePicture) {
559+
560+
mCanTakePicture = false; // Preview is suspended until we're done
561+
498562
PictureStartCallback startCallback = new PictureStartCallback();
499563
startCallback.mDelegate = shutter;
500564
PictureDoneCallback doneCallback = new PictureDoneCallback();
@@ -535,7 +599,8 @@ public boolean setFocusMode(@FocusMode String mode) {
535599
synchronized (mCameraLock) {
536600
if (mCamera != null && mode != null) {
537601
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)) {
539604
parameters.setFocusMode(mode);
540605
mCamera.setParameters(parameters);
541606
mFocusMode = mode;
@@ -575,7 +640,8 @@ public boolean setFlashMode(@FlashMode String mode) {
575640
synchronized (mCameraLock) {
576641
if (mCamera != null && mode != null) {
577642
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)) {
579645
parameters.setFlashMode(mode);
580646
mCamera.setParameters(parameters);
581647
mFlashMode = mode;
@@ -587,6 +653,36 @@ public boolean setFlashMode(@FlashMode String mode) {
587653
}
588654
}
589655

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+
590686
/**
591687
* Starts camera auto-focus and registers a callback function to run when
592688
* the camera is focused. This method is only valid when preview is active
@@ -600,7 +696,7 @@ public boolean setFlashMode(@FlashMode String mode) {
600696
* <p/>
601697
* <p>If the current flash mode is not
602698
* {@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>
604700
*
605701
* @param cb the callback to run
606702
* @see #cancelAutoFocus()
@@ -699,6 +795,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
699795
synchronized (mCameraLock) {
700796
if (mCamera != null) {
701797
mCamera.startPreview();
798+
mCanTakePicture = true;
702799
}
703800
}
704801
}
@@ -740,11 +837,23 @@ public void onAutoFocusMoving(boolean start, Camera camera) {
740837
*/
741838
@SuppressLint("InlinedApi")
742839
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) {
745853
throw new RuntimeException("Could not find requested camera.");
746854
}
747-
Camera camera = Camera.open(requestedCameraId);
855+
856+
Camera camera = Camera.open(mRequestedCameraId);
748857

749858
SizePair sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight);
750859
if (sizePair == null) {
@@ -770,11 +879,11 @@ private Camera createCamera() {
770879
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
771880
parameters.setPreviewFormat(ImageFormat.NV21);
772881

773-
setRotation(camera, parameters, requestedCameraId);
882+
setRotation(camera, parameters, mRequestedCameraId);
774883

775884
if (mFocusMode != null) {
776-
if (parameters.getSupportedFocusModes().contains(
777-
mFocusMode)) {
885+
final List<String> supportedFocusModes = parameters.getSupportedFocusModes();
886+
if (supportedFocusModes != null && supportedFocusModes.contains(mFocusMode)) {
778887
parameters.setFocusMode(mFocusMode);
779888
} else {
780889
Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device.");
@@ -785,13 +894,11 @@ private Camera createCamera() {
785894
mFocusMode = parameters.getFocusMode();
786895

787896
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.");
795902
}
796903
}
797904

@@ -972,6 +1079,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
9721079
return selectedFpsRange;
9731080
}
9741081

1082+
public void updateRotation() {
1083+
if (mCamera != null) {
1084+
setRotation(mCamera, mCamera.getParameters(), mRequestedCameraId);
1085+
}
1086+
}
1087+
9751088
/**
9761089
* Calculates the correct rotation for the given camera id and sets the rotation in the
9771090
* parameters. It also sets the camera's display orientation and rotation.
@@ -1211,4 +1324,10 @@ public void run() {
12111324
}
12121325
}
12131326
}
1327+
1328+
public interface CameraSourceStateListener
1329+
{
1330+
void onCameraSourceStarted();
1331+
void onCameraSourceStopped();
1332+
}
12141333
}

0 commit comments

Comments
 (0)