Skip to content

Commit 713538e

Browse files
authored
Make things safer
Fallback for requested camera, not crashing when taking pictures at the wrong time
1 parent a558930 commit 713538e

File tree

1 file changed

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

1 file changed

+76
-17
lines changed

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

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,14 @@ public class CameraSource {
122122

123123
private int mFacing = CAMERA_FACING_BACK;
124124

125+
private boolean mCameraFallbackAllowed = true;
126+
125127
/**
126128
* Rotation of the device, and thus the associated preview images captured from the device.
127129
* See {@link Frame.Metadata#getRotation()}.
128130
*/
129131
private int mRotation;
132+
private int mRequestedCameraId;
130133

131134
private Size mPreviewSize;
132135

@@ -143,7 +146,9 @@ public class CameraSource {
143146
// These instances need to be held onto to avoid GC of their underlying resources. Even though
144147
// these aren't used outside of the method that creates them, they still must have hard
145148
// references maintained to them.
149+
@SuppressWarnings("FieldCanBeLocal")
146150
private SurfaceView mDummySurfaceView;
151+
@SuppressWarnings("FieldCanBeLocal")
147152
private SurfaceTexture mDummySurfaceTexture;
148153

149154
/**
@@ -153,6 +158,8 @@ public class CameraSource {
153158
private Thread mProcessingThread;
154159
private FrameProcessingRunnable mFrameProcessor;
155160

161+
private boolean mCanTakePicture = false;
162+
156163
/**
157164
* Map to convert between a byte array, received from the camera, and its associated byte
158165
* buffer. We use byte buffers internally because this is a more efficient way to call into
@@ -240,6 +247,16 @@ public Builder setFacing(int facing) {
240247
return this;
241248
}
242249

250+
/**
251+
* Sets whether fallback from front to back or vice versa is allowed.
252+
* Used in case the requested camera was not available.
253+
* Default: true.
254+
*/
255+
public Builder setCameraFallbackAllowed(boolean allowed) {
256+
mCameraSource.mCameraFallbackAllowed = allowed;
257+
return this;
258+
}
259+
243260
/**
244261
* Creates an instance of the camera source.
245262
*/
@@ -376,6 +393,8 @@ public CameraSource start(SurfaceHolder surfaceHolder) throws IOException {
376393
mCamera = createCamera();
377394
mCamera.setPreviewDisplay(surfaceHolder);
378395
mCamera.startPreview();
396+
397+
mCanTakePicture = true;
379398

380399
mProcessingThread = new Thread(mFrameProcessor);
381400
mFrameProcessor.setActive(true);
@@ -410,6 +429,8 @@ public void stop() {
410429

411430
// clear the buffer to prevent oom exceptions
412431
mBytesToByteBuffer.clear();
432+
433+
mCanTakePicture = false;
413434

414435
if (mCamera != null) {
415436
mCamera.stopPreview();
@@ -450,6 +471,22 @@ public int getCameraFacing() {
450471
return mFacing;
451472
}
452473

474+
/**
475+
* Sets whether fallback from front to back or vice versa is allowed.
476+
* Used in case the requested camera was not available.
477+
*/
478+
public boolean isCameraFallbackAllowed() {
479+
return mCameraFallbackAllowed;
480+
}
481+
482+
public boolean isCameraFacingBackAvailable() {
483+
return getIdForRequestedCamera(CAMERA_FACING_BACK) != -1;
484+
}
485+
486+
public boolean isCameraFacingFrontAvailable() {
487+
return getIdForRequestedCamera(CAMERA_FACING_FRONT) != -1;
488+
}
489+
453490
public int doZoom(float scale) {
454491
synchronized (mCameraLock) {
455492
if (mCamera == null) {
@@ -494,7 +531,10 @@ public int doZoom(float scale) {
494531
*/
495532
public void takePicture(ShutterCallback shutter, PictureCallback jpeg) {
496533
synchronized (mCameraLock) {
497-
if (mCamera != null) {
534+
if (mCamera != null && mCanTakePicture) {
535+
536+
mCanTakePicture = false; // Preview is suspended until we're done
537+
498538
PictureStartCallback startCallback = new PictureStartCallback();
499539
startCallback.mDelegate = shutter;
500540
PictureDoneCallback doneCallback = new PictureDoneCallback();
@@ -535,7 +575,8 @@ public boolean setFocusMode(@FocusMode String mode) {
535575
synchronized (mCameraLock) {
536576
if (mCamera != null && mode != null) {
537577
Camera.Parameters parameters = mCamera.getParameters();
538-
if (parameters.getSupportedFocusModes().contains(mode)) {
578+
final List<String> supportedFlashModes = parameters.getSupportedFlashModes();
579+
if (supportedFlashModes != null && supportedFlashModes.contains(mode)) {
539580
parameters.setFocusMode(mode);
540581
mCamera.setParameters(parameters);
541582
mFocusMode = mode;
@@ -575,7 +616,8 @@ public boolean setFlashMode(@FlashMode String mode) {
575616
synchronized (mCameraLock) {
576617
if (mCamera != null && mode != null) {
577618
Camera.Parameters parameters = mCamera.getParameters();
578-
if (parameters.getSupportedFlashModes().contains(mode)) {
619+
final List<String> supportedFlashModes = parameters.getSupportedFlashModes();
620+
if (supportedFlashModes != null && supportedFlashModes.contains(mode)) {
579621
parameters.setFlashMode(mode);
580622
mCamera.setParameters(parameters);
581623
mFlashMode = mode;
@@ -600,7 +642,7 @@ public boolean setFlashMode(@FlashMode String mode) {
600642
* <p/>
601643
* <p>If the current flash mode is not
602644
* {@link Camera.Parameters#FLASH_MODE_OFF}, flash may be
603-
* fired during auto-focus, depending on the driver and camera hardware.<p>
645+
* fired during auto-focus, depending on the driver and camera hardware.</p>
604646
*
605647
* @param cb the callback to run
606648
* @see #cancelAutoFocus()
@@ -699,6 +741,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
699741
synchronized (mCameraLock) {
700742
if (mCamera != null) {
701743
mCamera.startPreview();
744+
mCanTakePicture = true;
702745
}
703746
}
704747
}
@@ -740,11 +783,23 @@ public void onAutoFocusMoving(boolean start, Camera camera) {
740783
*/
741784
@SuppressLint("InlinedApi")
742785
private Camera createCamera() {
743-
int requestedCameraId = getIdForRequestedCamera(mFacing);
744-
if (requestedCameraId == -1) {
786+
mRequestedCameraId = getIdForRequestedCamera(mFacing);
787+
788+
if (mRequestedCameraId == -1 && mCameraFallbackAllowed) {
789+
if (mFacing == CAMERA_FACING_BACK) {
790+
mFacing = CAMERA_FACING_FRONT;
791+
} else {
792+
mFacing = CAMERA_FACING_BACK;
793+
}
794+
795+
mRequestedCameraId = getIdForRequestedCamera(mFacing);
796+
}
797+
798+
if (mRequestedCameraId == -1) {
745799
throw new RuntimeException("Could not find requested camera.");
746800
}
747-
Camera camera = Camera.open(requestedCameraId);
801+
802+
Camera camera = Camera.open(mRequestedCameraId);
748803

749804
SizePair sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight);
750805
if (sizePair == null) {
@@ -770,11 +825,11 @@ private Camera createCamera() {
770825
previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
771826
parameters.setPreviewFormat(ImageFormat.NV21);
772827

773-
setRotation(camera, parameters, requestedCameraId);
828+
setRotation(camera, parameters, mRequestedCameraId);
774829

775830
if (mFocusMode != null) {
776-
if (parameters.getSupportedFocusModes().contains(
777-
mFocusMode)) {
831+
final List<String> supportedFlashModes = parameters.getSupportedFlashModes();
832+
if (supportedFlashModes != null && supportedFlashModes.contains(mFocusMode)) {
778833
parameters.setFocusMode(mFocusMode);
779834
} else {
780835
Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device.");
@@ -785,13 +840,11 @@ private Camera createCamera() {
785840
mFocusMode = parameters.getFocusMode();
786841

787842
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-
}
843+
final List<String> supportedFlashModes = parameters.getSupportedFlashModes();
844+
if (supportedFlashModes != null && supportedFlashModes.contains(mFlashMode)) {
845+
parameters.setFlashMode(mFlashMode);
846+
} else {
847+
Log.i(TAG, "Camera flash mode: " + mFlashMode + " is not supported on this device.");
795848
}
796849
}
797850

@@ -972,6 +1025,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) {
9721025
return selectedFpsRange;
9731026
}
9741027

1028+
public void updateRotation() {
1029+
if (mCamera != null) {
1030+
setRotation(mCamera, mCamera.getParameters(), mRequestedCameraId);
1031+
}
1032+
}
1033+
9751034
/**
9761035
* Calculates the correct rotation for the given camera id and sets the rotation in the
9771036
* parameters. It also sets the camera's display orientation and rotation.

0 commit comments

Comments
 (0)