diff --git a/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java b/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java index 430fd746..6ececb63 100644 --- a/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java +++ b/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java @@ -122,11 +122,14 @@ public class CameraSource { private int mFacing = CAMERA_FACING_BACK; + private boolean mCameraFallbackAllowed = true; + /** * Rotation of the device, and thus the associated preview images captured from the device. * See {@link Frame.Metadata#getRotation()}. */ private int mRotation; + private int mRequestedCameraId; private Size mPreviewSize; @@ -143,7 +146,9 @@ public class CameraSource { // These instances need to be held onto to avoid GC of their underlying resources. Even though // these aren't used outside of the method that creates them, they still must have hard // references maintained to them. + @SuppressWarnings("FieldCanBeLocal") private SurfaceView mDummySurfaceView; + @SuppressWarnings("FieldCanBeLocal") private SurfaceTexture mDummySurfaceTexture; /** @@ -153,6 +158,8 @@ public class CameraSource { private Thread mProcessingThread; private FrameProcessingRunnable mFrameProcessor; + private boolean mCanTakePicture = false; + /** * Map to convert between a byte array, received from the camera, and its associated byte * 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) { return this; } + /** + * Sets whether fallback from front to back or vice versa is allowed. + * Used in case the requested camera was not available. + * Default: true. + */ + public Builder setCameraFallbackAllowed(boolean allowed) { + mCameraSource.mCameraFallbackAllowed = allowed; + return this; + } + /** * Creates an instance of the camera source. */ @@ -376,6 +393,8 @@ public CameraSource start(SurfaceHolder surfaceHolder) throws IOException { mCamera = createCamera(); mCamera.setPreviewDisplay(surfaceHolder); mCamera.startPreview(); + + mCanTakePicture = true; mProcessingThread = new Thread(mFrameProcessor); mFrameProcessor.setActive(true); @@ -410,6 +429,8 @@ public void stop() { // clear the buffer to prevent oom exceptions mBytesToByteBuffer.clear(); + + mCanTakePicture = false; if (mCamera != null) { mCamera.stopPreview(); @@ -450,6 +471,22 @@ public int getCameraFacing() { return mFacing; } + /** + * Sets whether fallback from front to back or vice versa is allowed. + * Used in case the requested camera was not available. + */ + public boolean isCameraFallbackAllowed() { + return mCameraFallbackAllowed; + } + + public boolean isCameraFacingBackAvailable() { + return getIdForRequestedCamera(CAMERA_FACING_BACK) != -1; + } + + public boolean isCameraFacingFrontAvailable() { + return getIdForRequestedCamera(CAMERA_FACING_FRONT) != -1; + } + public int doZoom(float scale) { synchronized (mCameraLock) { if (mCamera == null) { @@ -494,7 +531,10 @@ public int doZoom(float scale) { */ public void takePicture(ShutterCallback shutter, PictureCallback jpeg) { synchronized (mCameraLock) { - if (mCamera != null) { + if (mCamera != null && mCanTakePicture) { + + mCanTakePicture = false; // Preview is suspended until we're done + PictureStartCallback startCallback = new PictureStartCallback(); startCallback.mDelegate = shutter; PictureDoneCallback doneCallback = new PictureDoneCallback(); @@ -535,7 +575,8 @@ public boolean setFocusMode(@FocusMode String mode) { synchronized (mCameraLock) { if (mCamera != null && mode != null) { Camera.Parameters parameters = mCamera.getParameters(); - if (parameters.getSupportedFocusModes().contains(mode)) { + final List supportedFlashModes = parameters.getSupportedFlashModes(); + if (supportedFlashModes != null && supportedFlashModes.contains(mode)) { parameters.setFocusMode(mode); mCamera.setParameters(parameters); mFocusMode = mode; @@ -575,7 +616,8 @@ public boolean setFlashMode(@FlashMode String mode) { synchronized (mCameraLock) { if (mCamera != null && mode != null) { Camera.Parameters parameters = mCamera.getParameters(); - if (parameters.getSupportedFlashModes().contains(mode)) { + final List supportedFlashModes = parameters.getSupportedFlashModes(); + if (supportedFlashModes != null && supportedFlashModes.contains(mode)) { parameters.setFlashMode(mode); mCamera.setParameters(parameters); mFlashMode = mode; @@ -600,7 +642,7 @@ public boolean setFlashMode(@FlashMode String mode) { *

*

If the current flash mode is not * {@link Camera.Parameters#FLASH_MODE_OFF}, flash may be - * fired during auto-focus, depending on the driver and camera hardware.

+ * fired during auto-focus, depending on the driver and camera hardware.

* * @param cb the callback to run * @see #cancelAutoFocus() @@ -699,6 +741,7 @@ public void onPictureTaken(byte[] data, Camera camera) { synchronized (mCameraLock) { if (mCamera != null) { mCamera.startPreview(); + mCanTakePicture = true; } } } @@ -740,11 +783,23 @@ public void onAutoFocusMoving(boolean start, Camera camera) { */ @SuppressLint("InlinedApi") private Camera createCamera() { - int requestedCameraId = getIdForRequestedCamera(mFacing); - if (requestedCameraId == -1) { + mRequestedCameraId = getIdForRequestedCamera(mFacing); + + if (mRequestedCameraId == -1 && mCameraFallbackAllowed) { + if (mFacing == CAMERA_FACING_BACK) { + mFacing = CAMERA_FACING_FRONT; + } else { + mFacing = CAMERA_FACING_BACK; + } + + mRequestedCameraId = getIdForRequestedCamera(mFacing); + } + + if (mRequestedCameraId == -1) { throw new RuntimeException("Could not find requested camera."); } - Camera camera = Camera.open(requestedCameraId); + + Camera camera = Camera.open(mRequestedCameraId); SizePair sizePair = selectSizePair(camera, mRequestedPreviewWidth, mRequestedPreviewHeight); if (sizePair == null) { @@ -770,11 +825,11 @@ private Camera createCamera() { previewFpsRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); parameters.setPreviewFormat(ImageFormat.NV21); - setRotation(camera, parameters, requestedCameraId); + setRotation(camera, parameters, mRequestedCameraId); if (mFocusMode != null) { - if (parameters.getSupportedFocusModes().contains( - mFocusMode)) { + final List supportedFlashModes = parameters.getSupportedFlashModes(); + if (supportedFlashModes != null && supportedFlashModes.contains(mFocusMode)) { parameters.setFocusMode(mFocusMode); } else { Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device."); @@ -785,13 +840,11 @@ private Camera createCamera() { mFocusMode = parameters.getFocusMode(); if (mFlashMode != null) { - if (parameters.getSupportedFlashModes() != null) { - if (parameters.getSupportedFlashModes().contains( - mFlashMode)) { - parameters.setFlashMode(mFlashMode); - } else { - Log.i(TAG, "Camera flash mode: " + mFlashMode + " is not supported on this device."); - } + final List supportedFlashModes = parameters.getSupportedFlashModes(); + if (supportedFlashModes != null && supportedFlashModes.contains(mFlashMode)) { + parameters.setFlashMode(mFlashMode); + } else { + Log.i(TAG, "Camera flash mode: " + mFlashMode + " is not supported on this device."); } } @@ -972,6 +1025,12 @@ private int[] selectPreviewFpsRange(Camera camera, float desiredPreviewFps) { return selectedFpsRange; } + public void updateRotation() { + if (mCamera != null) { + setRotation(mCamera, mCamera.getParameters(), mRequestedCameraId); + } + } + /** * Calculates the correct rotation for the given camera id and sets the rotation in the * parameters. It also sets the camera's display orientation and rotation.