Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make things safer #222

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ public class CameraSource {
*/
private static final float ASPECT_RATIO_TOLERANCE = 0.01f;

public CameraSourceStateListener getStateListener() {
return mStateListener;
}

public void setStateListener(CameraSourceStateListener stateListener) {
this.mStateListener = stateListener;
}

@StringDef({
Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
Expand Down Expand Up @@ -122,11 +130,16 @@ public class CameraSource {

private int mFacing = CAMERA_FACING_BACK;

private boolean mCameraFallbackAllowed = true;

private CameraSourceStateListener mStateListener = null;

/**
* 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;

Expand All @@ -143,7 +156,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;

/**
Expand All @@ -153,6 +168,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
Expand Down Expand Up @@ -240,6 +257,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.
*/
Expand Down Expand Up @@ -356,6 +383,11 @@ public CameraSource start() throws IOException {
mFrameProcessor.setActive(true);
mProcessingThread.start();
}

if (mStateListener != null) {
mStateListener.onCameraSourceStarted();
}

return this;
}

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

mCanTakePicture = true;

mProcessingThread = new Thread(mFrameProcessor);
mFrameProcessor.setActive(true);
mProcessingThread.start();
}

if (mStateListener != null) {
mStateListener.onCameraSourceStarted();
}

return this;
}

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

mCanTakePicture = false;

if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallbackWithBuffer(null);
Expand All @@ -433,6 +474,10 @@ public void stop() {
mCamera = null;
}
}

if (mStateListener != null) {
mStateListener.onCameraSourceStopped();
}
}

/**
Expand All @@ -450,6 +495,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) {
Expand Down Expand Up @@ -494,7 +555,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();
Expand Down Expand Up @@ -535,7 +599,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<String> supportedFocusModes = parameters.getSupportedFocusModes();
if (supportedFocusModes != null && supportedFocusModes.contains(mode)) {
parameters.setFocusMode(mode);
mCamera.setParameters(parameters);
mFocusMode = mode;
Expand Down Expand Up @@ -575,7 +640,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<String> supportedFlashModes = parameters.getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(mode)) {
parameters.setFlashMode(mode);
mCamera.setParameters(parameters);
mFlashMode = mode;
Expand All @@ -587,6 +653,36 @@ public boolean setFlashMode(@FlashMode String mode) {
}
}

/**
* Checks whether a specific flash mode is supported.
* If the camera source is not initialized yet - then it will return false.
* @param mode
* @return true only if camera is initialized and mode is supported.
*/
public boolean isFlashModeSupported(String mode) {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
final List<String> supportedModes = parameters.getSupportedFlashModes();
return supportedModes != null && supportedModes.contains(mode);
}
return false;
}

/**
* Checks whether a specific focus mode is supported.
* If the camera source is not initialized yet - then it will return false.
* @param mode
* @return true only if camera is initialized and mode is supported.
*/
public boolean isFocusModeSupported(String mode) {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
final List<String> supportedModes = parameters.getSupportedFocusModes();
return supportedModes != null && supportedModes.contains(mode);
}
return false;
}

/**
* Starts camera auto-focus and registers a callback function to run when
* the camera is focused. This method is only valid when preview is active
Expand All @@ -600,7 +696,7 @@ public boolean setFlashMode(@FlashMode String mode) {
* <p/>
* <p>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.<p>
* fired during auto-focus, depending on the driver and camera hardware.</p>
*
* @param cb the callback to run
* @see #cancelAutoFocus()
Expand Down Expand Up @@ -699,6 +795,7 @@ public void onPictureTaken(byte[] data, Camera camera) {
synchronized (mCameraLock) {
if (mCamera != null) {
mCamera.startPreview();
mCanTakePicture = true;
}
}
}
Expand Down Expand Up @@ -740,11 +837,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) {
Expand All @@ -770,11 +879,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<String> supportedFocusModes = parameters.getSupportedFocusModes();
if (supportedFocusModes != null && supportedFocusModes.contains(mFocusMode)) {
parameters.setFocusMode(mFocusMode);
} else {
Log.i(TAG, "Camera focus mode: " + mFocusMode + " is not supported on this device.");
Expand All @@ -785,13 +894,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<String> 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.");
}
}

Expand Down Expand Up @@ -972,6 +1079,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.
Expand Down Expand Up @@ -1211,4 +1324,10 @@ public void run() {
}
}
}

public interface CameraSourceStateListener
{
void onCameraSourceStarted();
void onCameraSourceStopped();
}
}