Add nullable and nonnull annotations everywhere

v2
Mattia Iavarone 6 years ago
parent 147f1676ca
commit bc5c9a41b4
  1. 7
      MIGRATION.md
  2. 6
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/CameraViewTest.java
  3. 22
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockCameraController.java
  4. 2
      cameraview/src/androidTest/java/com/otaliastudios/cameraview/MockCameraPreview.java
  5. 9
      cameraview/src/main/gles/com/otaliastudios/cameraview/AudioMediaEncoder.java
  6. 11
      cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoder.java
  7. 4
      cameraview/src/main/gles/com/otaliastudios/cameraview/MediaEncoderEngine.java
  8. 7
      cameraview/src/main/gles/com/otaliastudios/cameraview/TextureMediaEncoder.java
  9. 7
      cameraview/src/main/gles/com/otaliastudios/cameraview/VideoMediaEncoder.java
  10. 9
      cameraview/src/main/java/com/otaliastudios/cameraview/AspectRatio.java
  11. 50
      cameraview/src/main/java/com/otaliastudios/cameraview/Camera1.java
  12. 46
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraController.java
  13. 19
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraListener.java
  14. 22
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraOptions.java
  15. 21
      cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java
  16. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/Frame.java
  17. 13
      cameraview/src/main/java/com/otaliastudios/cameraview/FrameManager.java
  18. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/FullPictureRecorder.java
  19. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/FullVideoRecorder.java
  20. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/PictureRecorder.java
  21. 6
      cameraview/src/main/java/com/otaliastudios/cameraview/PictureResult.java
  22. 8
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotPictureRecorder.java
  23. 5
      cameraview/src/main/java/com/otaliastudios/cameraview/SnapshotVideoRecorder.java
  24. 3
      cameraview/src/main/java/com/otaliastudios/cameraview/VideoRecorder.java
  25. 5
      cameraview/src/main/java/com/otaliastudios/cameraview/VideoResult.java
  26. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Audio.java
  27. 5
      cameraview/src/main/options/com/otaliastudios/cameraview/Facing.java
  28. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Flash.java
  29. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/GestureAction.java
  30. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Grid.java
  31. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Hdr.java
  32. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Mode.java
  33. 3
      cameraview/src/main/options/com/otaliastudios/cameraview/Preview.java
  34. 4
      cameraview/src/main/options/com/otaliastudios/cameraview/VideoCodec.java
  35. 2
      cameraview/src/main/options/com/otaliastudios/cameraview/WhiteBalance.java
  36. 38
      cameraview/src/main/utils/com/otaliastudios/cameraview/CameraLogger.java
  37. 21
      cameraview/src/main/utils/com/otaliastudios/cameraview/CameraUtils.java
  38. 4
      cameraview/src/main/utils/com/otaliastudios/cameraview/CropHelper.java
  39. 5
      cameraview/src/main/utils/com/otaliastudios/cameraview/OrientationHelper.java
  40. 11
      cameraview/src/main/utils/com/otaliastudios/cameraview/RotationHelper.java
  41. 35
      cameraview/src/main/utils/com/otaliastudios/cameraview/SizeSelectors.java
  42. 13
      cameraview/src/main/utils/com/otaliastudios/cameraview/WorkerHandler.java
  43. 14
      cameraview/src/main/views/com/otaliastudios/cameraview/CameraPreview.java
  44. 9
      cameraview/src/main/views/com/otaliastudios/cameraview/GestureLayout.java
  45. 6
      cameraview/src/main/views/com/otaliastudios/cameraview/GlCameraPreview.java
  46. 6
      cameraview/src/main/views/com/otaliastudios/cameraview/GridLinesLayout.java
  47. 9
      cameraview/src/main/views/com/otaliastudios/cameraview/PinchGestureLayout.java
  48. 10
      cameraview/src/main/views/com/otaliastudios/cameraview/ScrollGestureLayout.java
  49. 7
      cameraview/src/main/views/com/otaliastudios/cameraview/SurfaceCameraPreview.java
  50. 19
      cameraview/src/main/views/com/otaliastudios/cameraview/TapGestureLayout.java
  51. 7
      cameraview/src/main/views/com/otaliastudios/cameraview/TextureCameraPreview.java
  52. 4
      cameraview/src/test/java/com/otaliastudios/cameraview/SizeSelectorsTest.java
  53. 6
      demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java

@ -124,13 +124,16 @@ The listener interface brings two breaking signature changes:
- `onVideoTaken()` now returns a `VideoResult`. Use `result.getFile()` to access the video file. - `onVideoTaken()` now returns a `VideoResult`. Use `result.getFile()` to access the video file.
The result class includes rich information about the video (or video snapshot) that was taken. The result class includes rich information about the video (or video snapshot) that was taken.
## Experimental mode
The v2 version introduces a `cameraExperimental` XML flag that you can use to enable experimental features.
Might be used in the future to speed up development.
## Other improvements ## Other improvements
- Added `@Nullable` and `@NonNull` annotations pretty much everywhere. This might **break** your Kotlin build.
- Added `setGridColor()` and `cameraGridColor` to control the grid color - Added `setGridColor()` and `cameraGridColor` to control the grid color
- Default `Facing` value is not `BACK` anymore but rather a value that guarantees that you have cameras (if possible). - Default `Facing` value is not `BACK` anymore but rather a value that guarantees that you have cameras (if possible).
If device has no `BACK` cameras, defaults to `FRONT`. If device has no `BACK` cameras, defaults to `FRONT`.
TODO: max size for video snapshot is naive
TODO: document cameraGridColor TODO: document cameraGridColor
TODO: document setVideoBitRate TODO: document setVideoBitRate
TODO: document setAudioBitRate TODO: document setAudioBitRate

@ -642,9 +642,9 @@ public class CameraViewTest extends BaseTest {
assertTrue(cameraView.mFrameProcessors.isEmpty()); assertTrue(cameraView.mFrameProcessors.isEmpty());
// Ensure this does not throw a ConcurrentModificationException // Ensure this does not throw a ConcurrentModificationException
cameraView.addFrameProcessor(new FrameProcessor() { public void process(Frame f) {} }); cameraView.addFrameProcessor(new FrameProcessor() { public void process(@NonNull Frame f) {} });
cameraView.addFrameProcessor(new FrameProcessor() { public void process(Frame f) {} }); cameraView.addFrameProcessor(new FrameProcessor() { public void process(@NonNull Frame f) {} });
cameraView.addFrameProcessor(new FrameProcessor() { public void process(Frame f) {} }); cameraView.addFrameProcessor(new FrameProcessor() { public void process(@NonNull Frame f) {} });
for (FrameProcessor test : cameraView.mFrameProcessors) { for (FrameProcessor test : cameraView.mFrameProcessors) {
cameraView.mFrameProcessors.remove(test); cameraView.mFrameProcessors.remove(test);
} }

@ -40,49 +40,49 @@ public class MockCameraController extends CameraController {
} }
@Override @Override
void setZoom(float zoom, PointF[] points, boolean notify) { void setZoom(float zoom, @Nullable PointF[] points, boolean notify) {
mZoomValue = zoom; mZoomValue = zoom;
mZoomChanged = true; mZoomChanged = true;
} }
@Override @Override
void setExposureCorrection(float EVvalue, float[] bounds, PointF[] points, boolean notify) { void setExposureCorrection(float EVvalue, @NonNull float[] bounds, @Nullable PointF[] points, boolean notify) {
mExposureCorrectionValue = EVvalue; mExposureCorrectionValue = EVvalue;
mExposureCorrectionChanged = true; mExposureCorrectionChanged = true;
} }
@Override @Override
void setFacing(Facing facing) { void setFacing(@NonNull Facing facing) {
mFacing = facing; mFacing = facing;
} }
@Override @Override
void setFlash(Flash flash) { void setFlash(@NonNull Flash flash) {
mFlash = flash; mFlash = flash;
} }
@Override @Override
void setWhiteBalance(WhiteBalance whiteBalance) { void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
mWhiteBalance = whiteBalance; mWhiteBalance = whiteBalance;
} }
@Override @Override
void setMode(Mode mode) { void setMode(@NonNull Mode mode) {
mMode = mode; mMode = mode;
} }
@Override @Override
void setHdr(Hdr hdr) { void setHdr(@NonNull Hdr hdr) {
mHdr = hdr; mHdr = hdr;
} }
@Override @Override
void setAudio(Audio audio) { void setAudio(@NonNull Audio audio) {
mAudio = audio; mAudio = audio;
} }
@Override @Override
void setLocation(Location location) { void setLocation(@Nullable Location location) {
mLocation = location; mLocation = location;
} }
@ -92,7 +92,7 @@ public class MockCameraController extends CameraController {
} }
@Override @Override
void takePictureSnapshot(AspectRatio viewAspectRatio) { void takePictureSnapshot(@NonNull AspectRatio viewAspectRatio) {
} }
@Override @Override
@ -127,7 +127,7 @@ public class MockCameraController extends CameraController {
} }
@Override @Override
public void onBufferAvailable(byte[] buffer) { public void onBufferAvailable(@NonNull byte[] buffer) {
} }
@Override @Override

@ -30,11 +30,13 @@ public class MockCameraPreview extends CameraPreview<View, Void> {
return new View(context); return new View(context);
} }
@NonNull
@Override @Override
Class<Void> getOutputClass() { Class<Void> getOutputClass() {
return null; return null;
} }
@NonNull
@Override @Override
Void getOutput() { Void getOutput() {
return null; return null;

@ -9,6 +9,7 @@ import android.media.MediaMuxer;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import java.io.IOException; import java.io.IOException;
@ -40,7 +41,7 @@ class AudioMediaEncoder extends MediaEncoder {
@EncoderThread @EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller, long maxLengthMillis) { void prepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) {
super.prepare(controller, maxLengthMillis); super.prepare(controller, maxLengthMillis);
final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1); final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
@ -65,7 +66,7 @@ class AudioMediaEncoder extends MediaEncoder {
@EncoderThread @EncoderThread
@Override @Override
void notify(String event, Object data) { } void notify(@NonNull String event, @Nullable Object data) { }
@EncoderThread @EncoderThread
@Override @Override
@ -74,7 +75,9 @@ class AudioMediaEncoder extends MediaEncoder {
synchronized (mLock) { synchronized (mLock) {
try { try {
mLock.wait(); mLock.wait();
} catch (InterruptedException e) {} } catch (InterruptedException e) {
// do nothing
}
} }
} }

@ -3,6 +3,8 @@ package com.otaliastudios.cameraview;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.util.Log; import android.util.Log;
@ -14,6 +16,7 @@ abstract class MediaEncoder {
private final static int TIMEOUT_USEC = 10000; // 10 msec private final static int TIMEOUT_USEC = 10000; // 10 msec
@SuppressWarnings("WeakerAccess")
protected MediaCodec mMediaCodec; protected MediaCodec mMediaCodec;
private MediaCodec.BufferInfo mBufferInfo; private MediaCodec.BufferInfo mBufferInfo;
@ -32,7 +35,7 @@ abstract class MediaEncoder {
* @param controller the muxer controller * @param controller the muxer controller
*/ */
@EncoderThread @EncoderThread
void prepare(MediaEncoderEngine.Controller controller, long maxLengthMillis) { void prepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) {
mController = controller; mController = controller;
mBufferInfo = new MediaCodec.BufferInfo(); mBufferInfo = new MediaCodec.BufferInfo();
mMaxLengthMillis = maxLengthMillis; mMaxLengthMillis = maxLengthMillis;
@ -53,7 +56,7 @@ abstract class MediaEncoder {
* @param data object * @param data object
*/ */
@EncoderThread @EncoderThread
abstract void notify(String event, Object data); abstract void notify(@NonNull String event, @Nullable Object data);
/** /**
* Stop recording. * Stop recording.
@ -77,7 +80,8 @@ abstract class MediaEncoder {
/** /**
* Encode data into the {@link #mMediaCodec}. * Encode data into the {@link #mMediaCodec}.
*/ */
protected void encode(final ByteBuffer buffer, final int length, final long presentationTimeUs) { @SuppressWarnings("WeakerAccess")
protected void encode(@Nullable final ByteBuffer buffer, final int length, final long presentationTimeUs) {
final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers(); final ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
while (true) { while (true) {
final int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_USEC); final int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_USEC);
@ -111,6 +115,7 @@ abstract class MediaEncoder {
* is set, we send EOS to the encoder, and then iterate until we see EOS on the output. * is set, we send EOS to the encoder, and then iterate until we see EOS on the output.
* Calling this with endOfStream set should be done once, right before stopping the muxer. * Calling this with endOfStream set should be done once, right before stopping the muxer.
*/ */
@SuppressWarnings("WeakerAccess")
protected void drain(boolean endOfStream) { protected void drain(boolean endOfStream) {
if (endOfStream) { if (endOfStream) {
mMediaCodec.signalEndOfInputStream(); mMediaCodec.signalEndOfInputStream();

@ -19,6 +19,7 @@ import java.util.List;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
class MediaEncoderEngine { class MediaEncoderEngine {
@SuppressWarnings("WeakerAccess")
final static int STOP_BY_USER = 0; final static int STOP_BY_USER = 0;
final static int STOP_BY_MAX_DURATION = 1; final static int STOP_BY_MAX_DURATION = 1;
final static int STOP_BY_MAX_SIZE = 2; final static int STOP_BY_MAX_SIZE = 2;
@ -56,13 +57,14 @@ class MediaEncoderEngine {
public void run() { public void run() {
// Trying to convert the size constraints to duration constraints, // Trying to convert the size constraints to duration constraints,
// because they are super easy to check. // because they are super easy to check.
// This is really naive & not accurate, but... // This is really naive & probably not accurate, but...
int bitRate = 0; int bitRate = 0;
for (MediaEncoder encoder : mEncoders) { for (MediaEncoder encoder : mEncoders) {
bitRate += encoder.getBitRate(); bitRate += encoder.getBitRate();
} }
int bytePerSecond = bitRate / 8; int bytePerSecond = bitRate / 8;
long sizeMaxDuration = (maxSize / bytePerSecond) * 1000L; long sizeMaxDuration = (maxSize / bytePerSecond) * 1000L;
long finalMaxDuration = Long.MAX_VALUE; long finalMaxDuration = Long.MAX_VALUE;
if (maxSize > 0 && maxDuration > 0) { if (maxSize > 0 && maxDuration > 0) {
mPossibleStopReason = sizeMaxDuration < maxDuration ? STOP_BY_MAX_SIZE : STOP_BY_MAX_DURATION; mPossibleStopReason = sizeMaxDuration < maxDuration ? STOP_BY_MAX_SIZE : STOP_BY_MAX_DURATION;

@ -9,6 +9,7 @@ import android.opengl.EGLContext;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
@ -46,13 +47,13 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
private EglWindowSurface mWindow; private EglWindowSurface mWindow;
private EglViewport mViewport; private EglViewport mViewport;
public TextureMediaEncoder(@NonNull Config config) { TextureMediaEncoder(@NonNull Config config) {
super(config); super(config);
} }
@EncoderThread @EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller, long maxLengthMillis) { void prepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) {
super.prepare(controller, maxLengthMillis); super.prepare(controller, maxLengthMillis);
mEglCore = new EglCore(mConfig.eglContext, EglCore.FLAG_RECORDABLE); mEglCore = new EglCore(mConfig.eglContext, EglCore.FLAG_RECORDABLE);
mWindow = new EglWindowSurface(mEglCore, mSurface, true); mWindow = new EglWindowSurface(mEglCore, mSurface, true);
@ -90,7 +91,7 @@ class TextureMediaEncoder extends VideoMediaEncoder<TextureMediaEncoder.Config>
@EncoderThread @EncoderThread
@Override @Override
void notify(String event, Object data) { void notify(@NonNull String event, @Nullable Object data) {
if (event.equals(FRAME_EVENT)) { if (event.equals(FRAME_EVENT)) {
Frame frame = (Frame) data; Frame frame = (Frame) data;

@ -22,8 +22,13 @@ import java.nio.ByteBuffer;
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends MediaEncoder { abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends MediaEncoder {
@SuppressWarnings("WeakerAccess")
protected C mConfig; protected C mConfig;
@SuppressWarnings("WeakerAccess")
protected Surface mSurface; protected Surface mSurface;
@SuppressWarnings("WeakerAccess")
protected int mFrameNum = -1; protected int mFrameNum = -1;
static class Config { static class Config {
@ -50,7 +55,7 @@ abstract class VideoMediaEncoder<C extends VideoMediaEncoder.Config> extends Med
@EncoderThread @EncoderThread
@Override @Override
void prepare(MediaEncoderEngine.Controller controller, long maxLengthMillis) { void prepare(@NonNull MediaEncoderEngine.Controller controller, long maxLengthMillis) {
super.prepare(controller, maxLengthMillis); super.prepare(controller, maxLengthMillis);
MediaFormat format = MediaFormat.createVideoFormat(mConfig.mimeType, mConfig.width, mConfig.height); MediaFormat format = MediaFormat.createVideoFormat(mConfig.mimeType, mConfig.width, mConfig.height);

@ -20,6 +20,7 @@ public class AspectRatio implements Comparable<AspectRatio> {
* @param size the size * @param size the size
* @return a (possibly cached) aspect ratio * @return a (possibly cached) aspect ratio
*/ */
@NonNull
public static AspectRatio of(Size size) { public static AspectRatio of(Size size) {
return AspectRatio.of(size.getWidth(), size.getHeight()); return AspectRatio.of(size.getWidth(), size.getHeight());
} }
@ -30,6 +31,7 @@ public class AspectRatio implements Comparable<AspectRatio> {
* @param y the height * @param y the height
* @return a (possibly cached) aspect ratio * @return a (possibly cached) aspect ratio
*/ */
@NonNull
public static AspectRatio of(int x, int y) { public static AspectRatio of(int x, int y) {
int gcd = gcd(x, y); int gcd = gcd(x, y);
x /= gcd; x /= gcd;
@ -50,6 +52,8 @@ public class AspectRatio implements Comparable<AspectRatio> {
* @param string a string of the format x:y where x and y are integers * @param string a string of the format x:y where x and y are integers
* @return a (possibly cached) aspect ratio * @return a (possibly cached) aspect ratio
*/ */
@NonNull
@SuppressWarnings("WeakerAccess")
public static AspectRatio parse(@NonNull String string) { public static AspectRatio parse(@NonNull String string) {
String[] parts = string.split(":"); String[] parts = string.split(":");
if (parts.length != 2) { if (parts.length != 2) {
@ -76,7 +80,8 @@ public class AspectRatio implements Comparable<AspectRatio> {
return mY; return mY;
} }
public boolean matches(Size size) { @SuppressWarnings("WeakerAccess")
public boolean matches(@NonNull Size size) {
int gcd = gcd(size.getWidth(), size.getHeight()); int gcd = gcd(size.getWidth(), size.getHeight());
int x = size.getWidth() / gcd; int x = size.getWidth() / gcd;
int y = size.getHeight() / gcd; int y = size.getHeight() / gcd;
@ -103,6 +108,7 @@ public class AspectRatio implements Comparable<AspectRatio> {
return mX + ":" + mY; return mX + ":" + mY;
} }
@SuppressWarnings("WeakerAccess")
public float toFloat() { public float toFloat() {
return (float) mX / mY; return (float) mX / mY;
} }
@ -123,6 +129,7 @@ public class AspectRatio implements Comparable<AspectRatio> {
} }
@SuppressWarnings("SuspiciousNameCombination") @SuppressWarnings("SuspiciousNameCombination")
@NonNull
public AspectRatio inverse() { public AspectRatio inverse() {
return AspectRatio.of(mY, mX); return AspectRatio.of(mY, mX);
} }

@ -47,7 +47,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
}; };
Camera1(CameraView.CameraCallbacks callback) { Camera1(@NonNull CameraView.CameraCallbacks callback) {
super(callback); super(callback);
mMapper = new Mapper1(); mMapper = new Mapper1();
} }
@ -298,7 +298,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
public void onBufferAvailable(byte[] buffer) { public void onBufferAvailable(@NonNull byte[] buffer) {
// TODO: sync with handler? // TODO: sync with handler?
if (isCameraAvailable()) { if (isCameraAvailable()) {
mCamera.addCallbackBuffer(buffer); mCamera.addCallbackBuffer(buffer);
@ -327,7 +327,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setMode(Mode mode) { void setMode(@NonNull Mode mode) {
if (mode != mMode) { if (mode != mMode) {
mMode = mode; mMode = mode;
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@ -340,7 +340,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setLocation(Location location) { void setLocation(@Nullable Location location) {
final Location oldLocation = mLocation; final Location oldLocation = mLocation;
mLocation = location; mLocation = location;
schedule(mLocationTask, true, new Runnable() { schedule(mLocationTask, true, new Runnable() {
@ -352,7 +352,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
}); });
} }
private boolean applyLocation(Camera.Parameters params, Location oldLocation) { private boolean applyLocation(@NonNull Camera.Parameters params, @Nullable Location oldLocation) {
if (mLocation != null) { if (mLocation != null) {
params.setGpsLatitude(mLocation.getLatitude()); params.setGpsLatitude(mLocation.getLatitude());
params.setGpsLongitude(mLocation.getLongitude()); params.setGpsLongitude(mLocation.getLongitude());
@ -364,7 +364,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setFacing(Facing facing) { void setFacing(@NonNull Facing facing) {
final Facing old = mFacing; final Facing old = mFacing;
if (facing != old) { if (facing != old) {
mFacing = facing; mFacing = facing;
@ -382,7 +382,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setWhiteBalance(WhiteBalance whiteBalance) { void setWhiteBalance(@NonNull WhiteBalance whiteBalance) {
final WhiteBalance old = mWhiteBalance; final WhiteBalance old = mWhiteBalance;
mWhiteBalance = whiteBalance; mWhiteBalance = whiteBalance;
schedule(mWhiteBalanceTask, true, new Runnable() { schedule(mWhiteBalanceTask, true, new Runnable() {
@ -394,7 +394,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
}); });
} }
private boolean applyWhiteBalance(Camera.Parameters params, WhiteBalance oldWhiteBalance) { private boolean applyWhiteBalance(@NonNull Camera.Parameters params, @NonNull WhiteBalance oldWhiteBalance) {
if (mCameraOptions.supports(mWhiteBalance)) { if (mCameraOptions.supports(mWhiteBalance)) {
params.setWhiteBalance((String) mMapper.map(mWhiteBalance)); params.setWhiteBalance((String) mMapper.map(mWhiteBalance));
return true; return true;
@ -404,7 +404,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setHdr(Hdr hdr) { void setHdr(@NonNull Hdr hdr) {
final Hdr old = mHdr; final Hdr old = mHdr;
mHdr = hdr; mHdr = hdr;
schedule(mHdrTask, true, new Runnable() { schedule(mHdrTask, true, new Runnable() {
@ -416,7 +416,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
}); });
} }
private boolean applyHdr(Camera.Parameters params, Hdr oldHdr) { private boolean applyHdr(@NonNull Camera.Parameters params, @NonNull Hdr oldHdr) {
if (mCameraOptions.supports(mHdr)) { if (mCameraOptions.supports(mHdr)) {
params.setSceneMode((String) mMapper.map(mHdr)); params.setSceneMode((String) mMapper.map(mHdr));
return true; return true;
@ -444,7 +444,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Override @Override
void setAudio(Audio audio) { void setAudio(@NonNull Audio audio) {
if (mAudio != audio) { if (mAudio != audio) {
if (isTakingVideo()) { if (isTakingVideo()) {
LOG.w("Audio setting was changed while recording. " + LOG.w("Audio setting was changed while recording. " +
@ -455,7 +455,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setFlash(Flash flash) { void setFlash(@NonNull Flash flash) {
final Flash old = mFlash; final Flash old = mFlash;
mFlash = flash; mFlash = flash;
schedule(mFlashTask, true, new Runnable() { schedule(mFlashTask, true, new Runnable() {
@ -468,7 +468,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
private boolean applyFlash(Camera.Parameters params, Flash oldFlash) { private boolean applyFlash(@NonNull Camera.Parameters params, @NonNull Flash oldFlash) {
if (mCameraOptions.supports(mFlash)) { if (mCameraOptions.supports(mFlash)) {
params.setFlashMode((String) mMapper.map(mFlash)); params.setFlashMode((String) mMapper.map(mFlash));
return true; return true;
@ -479,7 +479,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
// Choose the best default focus, based on session type. // Choose the best default focus, based on session type.
private void applyDefaultFocus(Camera.Parameters params) { private void applyDefaultFocus(@NonNull Camera.Parameters params) {
List<String> modes = params.getSupportedFocusModes(); List<String> modes = params.getSupportedFocusModes();
if (mMode == Mode.VIDEO && if (mMode == Mode.VIDEO &&
@ -500,6 +500,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
//noinspection UnnecessaryReturnStatement
return; return;
} }
} }
@ -552,7 +553,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Override @Override
void takePictureSnapshot(final AspectRatio viewAspectRatio) { void takePictureSnapshot(@NonNull final AspectRatio viewAspectRatio) {
LOG.v("takePictureSnapshot: scheduling"); LOG.v("takePictureSnapshot: scheduling");
schedule(null, true, new Runnable() { schedule(null, true, new Runnable() {
@Override @Override
@ -573,7 +574,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
public void onPreviewFrame(byte[] data, Camera camera) { public void onPreviewFrame(@NonNull byte[] data, Camera camera) {
Frame frame = mFrameManager.getFrame(data, Frame frame = mFrameManager.getFrame(data,
System.currentTimeMillis(), System.currentTimeMillis(),
offset(REF_SENSOR, REF_OUTPUT), offset(REF_SENSOR, REF_OUTPUT),
@ -782,7 +783,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Override @Override
void setZoom(final float zoom, final PointF[] points, final boolean notify) { void setZoom(final float zoom, @Nullable final PointF[] points, final boolean notify) {
schedule(mZoomTask, true, new Runnable() { schedule(mZoomTask, true, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -802,8 +803,8 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
@Override @Override
void setExposureCorrection(final float EVvalue, final float[] bounds, void setExposureCorrection(final float EVvalue, @NonNull final float[] bounds,
final PointF[] points, final boolean notify) { @Nullable final PointF[] points, final boolean notify) {
schedule(mExposureCorrectionTask, true, new Runnable() { schedule(mExposureCorrectionTask, true, new Runnable() {
@Override @Override
public void run() { public void run() {
@ -831,7 +832,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Override @Override
void startAutoFocus(@Nullable final Gesture gesture, final PointF point) { void startAutoFocus(@Nullable final Gesture gesture, @NonNull final PointF point) {
// Must get width and height from the UI thread. // Must get width and height from the UI thread.
int viewWidth = 0, viewHeight = 0; int viewWidth = 0, viewHeight = 0;
if (mPreview != null && mPreview.hasSurface()) { if (mPreview != null && mPreview.hasSurface()) {
@ -880,7 +881,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
}); });
} }
@NonNull
@WorkerThread @WorkerThread
private static List<Camera.Area> computeMeteringAreas(double viewClickX, double viewClickY, private static List<Camera.Area> computeMeteringAreas(double viewClickX, double viewClickY,
int viewWidth, int viewHeight, int viewWidth, int viewHeight,
@ -911,7 +912,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
return list; return list;
} }
@NonNull
private static Rect computeMeteringArea(double centerX, double centerY, double size) { private static Rect computeMeteringArea(double centerX, double centerY, double size) {
double delta = size / 2d; double delta = size / 2d;
int top = (int) Math.max(centerY - delta, -1000); int top = (int) Math.max(centerY - delta, -1000);
@ -928,7 +929,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
@Nullable @Nullable
private List<Size> sizesFromList(List<Camera.Size> sizes) { private List<Size> sizesFromList(@Nullable List<Camera.Size> sizes) {
if (sizes == null) return null; if (sizes == null) return null;
List<Size> result = new ArrayList<>(sizes.size()); List<Size> result = new ArrayList<>(sizes.size());
for (Camera.Size size : sizes) { for (Camera.Size size : sizes) {
@ -950,8 +951,5 @@ class Camera1 extends CameraController implements Camera.PreviewCallback, Camera
} }
}); });
} }
// -----------------
// Additional helper info
} }

@ -156,6 +156,7 @@ abstract class CameraController implements
//region Start&Stop //region Start&Stop
@NonNull
private String ss() { private String ss() {
switch (mState) { switch (mState) {
case STATE_STOPPING: return "STATE_STOPPING"; case STATE_STOPPING: return "STATE_STOPPING";
@ -273,11 +274,11 @@ abstract class CameraController implements
mDeviceOrientation = deviceOrientation; mDeviceOrientation = deviceOrientation;
} }
final void setPictureSizeSelector(SizeSelector selector) { final void setPictureSizeSelector(@NonNull SizeSelector selector) {
mPictureSizeSelector = selector; mPictureSizeSelector = selector;
} }
final void setVideoSizeSelector(SizeSelector selector) { final void setVideoSizeSelector(@NonNull SizeSelector selector) {
mVideoSizeSelector = selector; mVideoSizeSelector = selector;
} }
@ -289,7 +290,7 @@ abstract class CameraController implements
mVideoMaxDuration = videoMaxDurationMillis; mVideoMaxDuration = videoMaxDurationMillis;
} }
final void setVideoCodec(VideoCodec codec) { final void setVideoCodec(@NonNull VideoCodec codec) {
mVideoCodec = codec; mVideoCodec = codec;
} }
@ -306,35 +307,35 @@ abstract class CameraController implements
//region Abstract setters and APIs //region Abstract setters and APIs
// Should restart the session if active. // Should restart the session if active.
abstract void setMode(Mode mode); abstract void setMode(@NonNull Mode mode);
// Should restart the session if active. // Should restart the session if active.
abstract void setFacing(Facing facing); abstract void setFacing(@NonNull Facing facing);
// If closed, no-op. If opened, check supported and apply. // If closed, no-op. If opened, check supported and apply.
abstract void setZoom(float zoom, PointF[] points, boolean notify); abstract void setZoom(float zoom, @Nullable PointF[] points, boolean notify);
// If closed, no-op. If opened, check supported and apply. // If closed, no-op. If opened, check supported and apply.
abstract void setExposureCorrection(float EVvalue, float[] bounds, PointF[] points, boolean notify); abstract void setExposureCorrection(float EVvalue, @NonNull float[] bounds, @Nullable PointF[] points, boolean notify);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setFlash(Flash flash); abstract void setFlash(@NonNull Flash flash);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setWhiteBalance(WhiteBalance whiteBalance); abstract void setWhiteBalance(@NonNull WhiteBalance whiteBalance);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setHdr(Hdr hdr); abstract void setHdr(@NonNull Hdr hdr);
// If closed, keep. If opened, check supported and apply. // If closed, keep. If opened, check supported and apply.
abstract void setLocation(Location location); abstract void setLocation(@Nullable Location location);
// Just set. // Just set.
abstract void setAudio(Audio audio); abstract void setAudio(@NonNull Audio audio);
abstract void takePicture(); abstract void takePicture();
abstract void takePictureSnapshot(AspectRatio viewAspectRatio); abstract void takePictureSnapshot(@NonNull AspectRatio viewAspectRatio);
abstract void takeVideo(@NonNull File file); abstract void takeVideo(@NonNull File file);
@ -355,14 +356,17 @@ abstract class CameraController implements
return mCameraOptions; return mCameraOptions;
} }
@NonNull
final Facing getFacing() { final Facing getFacing() {
return mFacing; return mFacing;
} }
@NonNull
final Flash getFlash() { final Flash getFlash() {
return mFlash; return mFlash;
} }
@NonNull
final WhiteBalance getWhiteBalance() { final WhiteBalance getWhiteBalance() {
return mWhiteBalance; return mWhiteBalance;
} }
@ -383,18 +387,22 @@ abstract class CameraController implements
return mVideoMaxDuration; return mVideoMaxDuration;
} }
@NonNull
final Mode getMode() { final Mode getMode() {
return mMode; return mMode;
} }
@NonNull
final Hdr getHdr() { final Hdr getHdr() {
return mHdr; return mHdr;
} }
@Nullable
final Location getLocation() { final Location getLocation() {
return mLocation; return mLocation;
} }
@NonNull
final Audio getAudio() { final Audio getAudio() {
return mAudio; return mAudio;
} }
@ -403,10 +411,12 @@ abstract class CameraController implements
return mAudioBitRate; return mAudioBitRate;
} }
@NonNull
/* for tests */ final SizeSelector getPictureSizeSelector() { /* for tests */ final SizeSelector getPictureSizeSelector() {
return mPictureSizeSelector; return mPictureSizeSelector;
} }
@NonNull
/* for tests */ final SizeSelector getVideoSizeSelector() { /* for tests */ final SizeSelector getVideoSizeSelector() {
return mVideoSizeSelector; return mVideoSizeSelector;
} }
@ -469,12 +479,12 @@ abstract class CameraController implements
return offset(reference1, reference2) % 180 != 0; return offset(reference1, reference2) % 180 != 0;
} }
final Size getPictureSize(int reference) { final Size getPictureSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.VIDEO) return null; if (mCaptureSize == null || mMode == Mode.VIDEO) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize; return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
} }
final Size getVideoSize(int reference) { final Size getVideoSize(@SuppressWarnings("SameParameterValue") int reference) {
if (mCaptureSize == null || mMode == Mode.PICTURE) return null; if (mCaptureSize == null || mMode == Mode.PICTURE) return null;
return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize; return flip(REF_SENSOR, reference) ? mCaptureSize.flip() : mCaptureSize;
} }
@ -496,6 +506,8 @@ abstract class CameraController implements
* But when it does, the {@link CameraPreview.SurfaceCallback} should be called, * But when it does, the {@link CameraPreview.SurfaceCallback} should be called,
* and this should be refreshed. * and this should be refreshed.
*/ */
@NonNull
@SuppressWarnings("WeakerAccess")
protected final Size computeCaptureSize() { protected final Size computeCaptureSize() {
// We want to pass stuff into the REF_VIEW reference, not the sensor one. // We want to pass stuff into the REF_VIEW reference, not the sensor one.
// This is already managed by CameraOptions, so we just flip again at the end. // This is already managed by CameraOptions, so we just flip again at the end.
@ -517,7 +529,9 @@ abstract class CameraController implements
return result; return result;
} }
protected final Size computePreviewSize(List<Size> previewSizes) { @NonNull
@SuppressWarnings("WeakerAccess")
protected final Size computePreviewSize(@NonNull List<Size> previewSizes) {
// instead of flipping everything to REF_VIEW, we can just flip the // instead of flipping everything to REF_VIEW, we can just flip the
// surface size from REF_VIEW to REF_SENSOR, and reflip at the end. // surface size from REF_VIEW to REF_SENSOR, and reflip at the end.
AspectRatio targetRatio = AspectRatio.of(mCaptureSize.getWidth(), mCaptureSize.getHeight()); AspectRatio targetRatio = AspectRatio.of(mCaptureSize.getWidth(), mCaptureSize.getHeight());

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.graphics.PointF; import android.graphics.PointF;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
public abstract class CameraListener { public abstract class CameraListener {
@ -14,7 +15,7 @@ public abstract class CameraListener {
* @param options camera supported options * @param options camera supported options
*/ */
@UiThread @UiThread
public void onCameraOpened(CameraOptions options) { public void onCameraOpened(@NonNull CameraOptions options) {
} }
@ -57,7 +58,7 @@ public abstract class CameraListener {
* @param result captured picture * @param result captured picture
*/ */
@UiThread @UiThread
public void onPictureTaken(PictureResult result) { public void onPictureTaken(@NonNull PictureResult result) {
} }
@ -68,7 +69,7 @@ public abstract class CameraListener {
* @param result the video result * @param result the video result
*/ */
@UiThread @UiThread
public void onVideoTaken(VideoResult result) { public void onVideoTaken(@NonNull VideoResult result) {
} }
@ -97,7 +98,7 @@ public abstract class CameraListener {
* @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight() * @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight()
*/ */
@UiThread @UiThread
public void onFocusStart(PointF point) { public void onFocusStart(@NonNull PointF point) {
} }
@ -112,7 +113,7 @@ public abstract class CameraListener {
* @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight() * @param point coordinates with respect to CameraView.getWidth() and CameraView.getHeight()
*/ */
@UiThread @UiThread
public void onFocusEnd(boolean successful, PointF point) { public void onFocusEnd(boolean successful, @NonNull PointF point) {
} }
@ -123,10 +124,10 @@ public abstract class CameraListener {
* *
* @param newValue the new zoom value * @param newValue the new zoom value
* @param bounds min and max bounds for newValue (fixed to 0 ... 1) * @param bounds min and max bounds for newValue (fixed to 0 ... 1)
* @param fingers finger positions that caused the event * @param fingers finger positions that caused the event, null if not caused by touch
*/ */
@UiThread @UiThread
public void onZoomChanged(float newValue, float[] bounds, PointF[] fingers) { public void onZoomChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) {
} }
@ -137,10 +138,10 @@ public abstract class CameraListener {
* *
* @param newValue the new correction value * @param newValue the new correction value
* @param bounds min and max bounds for newValue, as returned by {@link CameraOptions} * @param bounds min and max bounds for newValue, as returned by {@link CameraOptions}
* @param fingers finger positions that caused the event * @param fingers finger positions that caused the event, null if not caused by touch
*/ */
@UiThread @UiThread
public void onExposureCorrectionChanged(float newValue, float[] bounds, PointF[] fingers) { public void onExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) {
} }

@ -36,7 +36,7 @@ public class CameraOptions {
// Camera1 constructor. // Camera1 constructor.
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
CameraOptions(Camera.Parameters params, boolean flipSizes) { CameraOptions(@NonNull Camera.Parameters params, boolean flipSizes) {
List<String> strings; List<String> strings;
Mapper mapper = new Mapper1(); Mapper mapper = new Mapper1();
@ -107,7 +107,7 @@ public class CameraOptions {
// Camera2 constructor. // Camera2 constructor.
@TargetApi(21) @TargetApi(21)
CameraOptions(CameraCharacteristics params) {} CameraOptions(@NonNull CameraCharacteristics params) {}
/** /**
@ -116,7 +116,7 @@ public class CameraOptions {
* @param control value to check * @param control value to check
* @return whether it's supported * @return whether it's supported
*/ */
public boolean supports(Control control) { public boolean supports(@NonNull Control control) {
return getSupportedControls(control.getClass()).contains(control); return getSupportedControls(control.getClass()).contains(control);
} }
@ -128,7 +128,7 @@ public class CameraOptions {
* @param action value to be checked * @param action value to be checked
* @return whether it's supported * @return whether it's supported
*/ */
public boolean supports(GestureAction action) { public boolean supports(@NonNull GestureAction action) {
switch (action) { switch (action) {
case FOCUS: case FOCUS:
case FOCUS_WITH_MARKER: case FOCUS_WITH_MARKER:
@ -146,6 +146,7 @@ public class CameraOptions {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@NonNull
public <T extends Control> Collection<T> getSupportedControls(@NonNull Class<T> controlClass) { public <T extends Control> Collection<T> getSupportedControls(@NonNull Class<T> controlClass) {
if (controlClass.equals(Audio.class)) { if (controlClass.equals(Audio.class)) {
return (Collection<T>) Arrays.asList(Audio.values()); return (Collection<T>) Arrays.asList(Audio.values());
@ -174,6 +175,7 @@ public class CameraOptions {
* *
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<Size> getSupportedPictureSizes() { public Collection<Size> getSupportedPictureSizes() {
return Collections.unmodifiableSet(supportedPictureSizes); return Collections.unmodifiableSet(supportedPictureSizes);
@ -185,6 +187,7 @@ public class CameraOptions {
* *
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<AspectRatio> getSupportedPictureAspectRatios() { public Collection<AspectRatio> getSupportedPictureAspectRatios() {
return Collections.unmodifiableSet(supportedPictureAspectRatio); return Collections.unmodifiableSet(supportedPictureAspectRatio);
@ -196,6 +199,7 @@ public class CameraOptions {
* *
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<Size> getSupportedVideoSizes() { public Collection<Size> getSupportedVideoSizes() {
return Collections.unmodifiableSet(supportedVideoSizes); return Collections.unmodifiableSet(supportedVideoSizes);
@ -207,6 +211,7 @@ public class CameraOptions {
* *
* @return a set of supported values. * @return a set of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<AspectRatio> getSupportedVideoAspectRatios() { public Collection<AspectRatio> getSupportedVideoAspectRatios() {
return Collections.unmodifiableSet(supportedVideoAspectRatio); return Collections.unmodifiableSet(supportedVideoAspectRatio);
@ -220,6 +225,7 @@ public class CameraOptions {
* @see Facing#FRONT * @see Facing#FRONT
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<Facing> getSupportedFacing() { public Collection<Facing> getSupportedFacing() {
return Collections.unmodifiableSet(supportedFacing); return Collections.unmodifiableSet(supportedFacing);
@ -235,6 +241,7 @@ public class CameraOptions {
* @see Flash#TORCH * @see Flash#TORCH
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<Flash> getSupportedFlash() { public Collection<Flash> getSupportedFlash() {
return Collections.unmodifiableSet(supportedFlash); return Collections.unmodifiableSet(supportedFlash);
@ -251,6 +258,7 @@ public class CameraOptions {
* @see WhiteBalance#CLOUDY * @see WhiteBalance#CLOUDY
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<WhiteBalance> getSupportedWhiteBalance() { public Collection<WhiteBalance> getSupportedWhiteBalance() {
return Collections.unmodifiableSet(supportedWhiteBalance); return Collections.unmodifiableSet(supportedWhiteBalance);
@ -264,6 +272,7 @@ public class CameraOptions {
* @see Hdr#ON * @see Hdr#ON
* @return a collection of supported values. * @return a collection of supported values.
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull @NonNull
public Collection<Hdr> getSupportedHdr() { public Collection<Hdr> getSupportedHdr() {
return Collections.unmodifiableSet(supportedHdr); return Collections.unmodifiableSet(supportedHdr);
@ -275,6 +284,7 @@ public class CameraOptions {
* *
* @return whether zoom is supported. * @return whether zoom is supported.
*/ */
@SuppressWarnings("WeakerAccess")
public boolean isZoomSupported() { public boolean isZoomSupported() {
return zoomSupported; return zoomSupported;
} }
@ -287,6 +297,7 @@ public class CameraOptions {
* *
* @return whether auto focus is supported. * @return whether auto focus is supported.
*/ */
@SuppressWarnings("WeakerAccess")
public boolean isAutoFocusSupported() { public boolean isAutoFocusSupported() {
return autoFocusSupported; return autoFocusSupported;
} }
@ -300,6 +311,7 @@ public class CameraOptions {
* @see #getExposureCorrectionMaxValue() * @see #getExposureCorrectionMaxValue()
* @return whether exposure correction is supported. * @return whether exposure correction is supported.
*/ */
@SuppressWarnings("WeakerAccess")
public boolean isExposureCorrectionSupported() { public boolean isExposureCorrectionSupported() {
return exposureCorrectionSupported; return exposureCorrectionSupported;
} }
@ -311,6 +323,7 @@ public class CameraOptions {
* *
* @return min EV value * @return min EV value
*/ */
@SuppressWarnings("WeakerAccess")
public float getExposureCorrectionMinValue() { public float getExposureCorrectionMinValue() {
return exposureCorrectionMinValue; return exposureCorrectionMinValue;
} }
@ -322,6 +335,7 @@ public class CameraOptions {
* *
* @return max EV value * @return max EV value
*/ */
@SuppressWarnings("WeakerAccess")
public float getExposureCorrectionMaxValue() { public float getExposureCorrectionMaxValue() {
return exposureCorrectionMaxValue; return exposureCorrectionMaxValue;
} }

@ -752,7 +752,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
float max = options.getExposureCorrectionMaxValue(); float max = options.getExposureCorrectionMaxValue();
if (EVvalue < min) EVvalue = min; if (EVvalue < min) EVvalue = min;
if (EVvalue > max) EVvalue = max; if (EVvalue > max) EVvalue = max;
mCameraController.setExposureCorrection(EVvalue, null, null, false); float[] bounds = new float[]{min, max};
mCameraController.setExposureCorrection(EVvalue, bounds, null, false);
} }
} }
@ -1561,10 +1562,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
void onShutter(boolean shouldPlaySound); void onShutter(boolean shouldPlaySound);
void dispatchOnVideoTaken(VideoResult result); void dispatchOnVideoTaken(VideoResult result);
void dispatchOnPictureTaken(PictureResult result); void dispatchOnPictureTaken(PictureResult result);
void dispatchOnFocusStart(@Nullable Gesture trigger, PointF where); void dispatchOnFocusStart(@Nullable Gesture trigger, @NonNull PointF where);
void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, PointF where); void dispatchOnFocusEnd(@Nullable Gesture trigger, boolean success, @NonNull PointF where);
void dispatchOnZoomChanged(final float newValue, final PointF[] fingers); void dispatchOnZoomChanged(final float newValue, @Nullable final PointF[] fingers);
void dispatchOnExposureCorrectionChanged(float newValue, float[] bounds, PointF[] fingers); void dispatchOnExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers);
void dispatchFrame(Frame frame); void dispatchFrame(Frame frame);
void dispatchError(CameraException exception); void dispatchError(CameraException exception);
} }
@ -1651,7 +1652,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@Override @Override
public void dispatchOnFocusStart(@Nullable final Gesture gesture, final PointF point) { public void dispatchOnFocusStart(@Nullable final Gesture gesture, @NonNull final PointF point) {
mLogger.i("dispatchOnFocusStart", gesture, point); mLogger.i("dispatchOnFocusStart", gesture, point);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
@ -1669,7 +1670,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override @Override
public void dispatchOnFocusEnd(@Nullable final Gesture gesture, final boolean success, public void dispatchOnFocusEnd(@Nullable final Gesture gesture, final boolean success,
final PointF point) { @NonNull final PointF point) {
mLogger.i("dispatchOnFocusEnd", gesture, success, point); mLogger.i("dispatchOnFocusEnd", gesture, success, point);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
@ -1707,7 +1708,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
@Override @Override
public void dispatchOnZoomChanged(final float newValue, final PointF[] fingers) { public void dispatchOnZoomChanged(final float newValue, @Nullable final PointF[] fingers) {
mLogger.i("dispatchOnZoomChanged", newValue); mLogger.i("dispatchOnZoomChanged", newValue);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override
@ -1721,8 +1722,8 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override @Override
public void dispatchOnExposureCorrectionChanged(final float newValue, public void dispatchOnExposureCorrectionChanged(final float newValue,
final float[] bounds, @NonNull final float[] bounds,
final PointF[] fingers) { @Nullable final PointF[] fingers) {
mLogger.i("dispatchOnExposureCorrectionChanged", newValue); mLogger.i("dispatchOnExposureCorrectionChanged", newValue);
mUiHandler.post(new Runnable() { mUiHandler.post(new Runnable() {
@Override @Override

@ -1,6 +1,7 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/** /**
* A preview frame to be processed by {@link FrameProcessor}s. * A preview frame to be processed by {@link FrameProcessor}s.
@ -19,7 +20,7 @@ public class Frame {
mManager = manager; mManager = manager;
} }
void set(byte[] data, long time, int rotation, Size size, int format) { void set(@NonNull byte[] data, long time, int rotation, @NonNull Size size, int format) {
this.mData = data; this.mData = data;
this.mTime = time; this.mTime = time;
this.mRotation = rotation; this.mRotation = rotation;
@ -40,6 +41,8 @@ public class Frame {
* *
* @return a frozen Frame * @return a frozen Frame
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public Frame freeze() { public Frame freeze() {
byte[] data = new byte[mData.length]; byte[] data = new byte[mData.length];
System.arraycopy(mData, 0, data, 0, mData.length); System.arraycopy(mData, 0, data, 0, mData.length);
@ -74,6 +77,7 @@ public class Frame {
* Returns the frame data. * Returns the frame data.
* @return the frame data * @return the frame data
*/ */
@NonNull
public byte[] getData() { public byte[] getData() {
return mData; return mData;
} }
@ -104,6 +108,7 @@ public class Frame {
* *
* @return frame size * @return frame size
*/ */
@NonNull
public Size getSize() { public Size getSize() {
return mSize; return mSize;
} }

@ -1,6 +1,9 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
/** /**
@ -21,7 +24,7 @@ import java.util.concurrent.LinkedBlockingQueue;
class FrameManager { class FrameManager {
interface BufferCallback { interface BufferCallback {
void onBufferAvailable(byte[] buffer); void onBufferAvailable(@NonNull byte[] buffer);
} }
private int mPoolSize; private int mPoolSize;
@ -29,7 +32,7 @@ class FrameManager {
private BufferCallback mCallback; private BufferCallback mCallback;
private LinkedBlockingQueue<Frame> mQueue; private LinkedBlockingQueue<Frame> mQueue;
FrameManager(int poolSize, BufferCallback callback) { FrameManager(int poolSize, @Nullable BufferCallback callback) {
mPoolSize = poolSize; mPoolSize = poolSize;
mCallback = callback; mCallback = callback;
mQueue = new LinkedBlockingQueue<>(mPoolSize); mQueue = new LinkedBlockingQueue<>(mPoolSize);
@ -71,14 +74,14 @@ class FrameManager {
* *
* @return a new frame * @return a new frame
*/ */
Frame getFrame(byte[] data, long time, int rotation, Size previewSize, int previewFormat) { Frame getFrame(@NonNull byte[] data, long time, int rotation, @NonNull Size previewSize, int previewFormat) {
Frame frame = mQueue.poll(); Frame frame = mQueue.poll();
if (frame == null) frame = new Frame(this); if (frame == null) frame = new Frame(this);
frame.set(data, time, rotation, previewSize, previewFormat); frame.set(data, time, rotation, previewSize, previewFormat);
return frame; return frame;
} }
int allocate(int bitsPerPixel, Size previewSize) { int allocate(int bitsPerPixel, @NonNull Size previewSize) {
mBufferSize = getBufferSize(bitsPerPixel, previewSize); mBufferSize = getBufferSize(bitsPerPixel, previewSize);
for (int i = 0; i < mPoolSize; i++) { for (int i = 0; i < mPoolSize; i++) {
mCallback.onBufferAvailable(new byte[mBufferSize]); mCallback.onBufferAvailable(new byte[mBufferSize]);
@ -86,7 +89,7 @@ class FrameManager {
return mBufferSize; return mBufferSize;
} }
private int getBufferSize(int bitsPerPixel, Size previewSize) { private int getBufferSize(int bitsPerPixel, @NonNull Size previewSize) {
long sizeInBits = previewSize.getHeight() * previewSize.getWidth() * bitsPerPixel; long sizeInBits = previewSize.getHeight() * previewSize.getWidth() * bitsPerPixel;
return (int) Math.ceil(sizeInBits / 8.0d); return (int) Math.ceil(sizeInBits / 8.0d);
} }

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.hardware.Camera; import android.hardware.Camera;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.media.ExifInterface; import android.support.media.ExifInterface;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -16,7 +18,7 @@ class FullPictureRecorder extends PictureRecorder {
private Camera mCamera; private Camera mCamera;
FullPictureRecorder(PictureResult stub, PictureResultListener listener, Camera camera) { FullPictureRecorder(@NonNull PictureResult stub, @Nullable PictureResultListener listener, @NonNull Camera camera) {
super(stub, listener); super(stub, listener);
mCamera = camera; mCamera = camera;

@ -3,6 +3,8 @@ package com.otaliastudios.cameraview;
import android.hardware.Camera; import android.hardware.Camera;
import android.media.CamcorderProfile; import android.media.CamcorderProfile;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/** /**
* A {@link VideoRecorder} that uses {@link android.media.MediaRecorder} APIs. * A {@link VideoRecorder} that uses {@link android.media.MediaRecorder} APIs.
@ -15,7 +17,7 @@ class FullVideoRecorder extends VideoRecorder {
private MediaRecorder mMediaRecorder; private MediaRecorder mMediaRecorder;
private CamcorderProfile mProfile; private CamcorderProfile mProfile;
FullVideoRecorder(VideoResult stub, VideoResultListener listener, Camera camera, int cameraId) { FullVideoRecorder(@NonNull VideoResult stub, @Nullable VideoResultListener listener, @NonNull Camera camera, int cameraId) {
super(stub, listener); super(stub, listener);
mMediaRecorder = new MediaRecorder(); mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(camera); mMediaRecorder.setCamera(camera);

@ -1,5 +1,6 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
/** /**
@ -12,13 +13,14 @@ abstract class PictureRecorder {
/* tests */ PictureResult mResult; /* tests */ PictureResult mResult;
/* tests */ PictureResultListener mListener; /* tests */ PictureResultListener mListener;
PictureRecorder(PictureResult stub, PictureResultListener listener) { PictureRecorder(@NonNull PictureResult stub, @Nullable PictureResultListener listener) {
mResult = stub; mResult = stub;
mListener = listener; mListener = listener;
} }
abstract void take(); abstract void take();
@SuppressWarnings("WeakerAccess")
protected void dispatchOnShutter(boolean didPlaySound) { protected void dispatchOnShutter(boolean didPlaySound) {
if (mListener != null) mListener.onPictureShutter(didPlaySound); if (mListener != null) mListener.onPictureShutter(didPlaySound);
} }

@ -93,7 +93,7 @@ public class PictureResult {
* @param maxHeight the max. height of final bitmap * @param maxHeight the max. height of final bitmap
* @param callback a callback to be notified of image decoding * @param callback a callback to be notified of image decoding
*/ */
public void asBitmap(int maxWidth, int maxHeight, BitmapCallback callback) { public void asBitmap(int maxWidth, int maxHeight, @NonNull BitmapCallback callback) {
CameraUtils.decodeBitmap(getData(), maxWidth, maxHeight, rotation, callback); CameraUtils.decodeBitmap(getData(), maxWidth, maxHeight, rotation, callback);
} }
@ -104,7 +104,9 @@ public class PictureResult {
* *
* @param callback a callback to be notified of image decoding * @param callback a callback to be notified of image decoding
*/ */
public void asBitmap(BitmapCallback callback) { public void asBitmap(@NonNull BitmapCallback callback) {
asBitmap(-1, -1, callback); asBitmap(-1, -1, callback);
} }
// TODO toFile
} }

@ -10,6 +10,7 @@ import android.hardware.Camera;
import android.opengl.EGL14; import android.opengl.EGL14;
import android.opengl.EGLContext; import android.opengl.EGLContext;
import android.opengl.Matrix; import android.opengl.Matrix;
import android.support.annotation.NonNull;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -28,7 +29,8 @@ class SnapshotPictureRecorder extends PictureRecorder {
private Size mSensorPreviewSize; private Size mSensorPreviewSize;
private int mFormat; private int mFormat;
SnapshotPictureRecorder(PictureResult stub, Camera1 controller, Camera camera, AspectRatio outputRatio) { SnapshotPictureRecorder(@NonNull PictureResult stub, @NonNull Camera1 controller,
@NonNull Camera camera, @NonNull AspectRatio outputRatio) {
super(stub, controller); super(stub, controller);
mController = controller; mController = controller;
mPreview = controller.mPreview; mPreview = controller.mPreview;
@ -48,7 +50,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
private void takeGl(final GlCameraPreview preview) { private void takeGl(@NonNull final GlCameraPreview preview) {
preview.addRendererFrameCallback(new GlCameraPreview.RendererFrameCallback() { preview.addRendererFrameCallback(new GlCameraPreview.RendererFrameCallback() {
int mTextureId; int mTextureId;
@ -145,7 +147,7 @@ class SnapshotPictureRecorder extends PictureRecorder {
private void takeLegacy() { private void takeLegacy() {
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override @Override
public void onPreviewFrame(final byte[] yuv, Camera camera) { public void onPreviewFrame(@NonNull final byte[] yuv, Camera camera) {
dispatchOnShutter(false); dispatchOnShutter(false);
// Got to rotate the preview frame, since byte[] data here does not include // Got to rotate the preview frame, since byte[] data here does not include

@ -4,6 +4,7 @@ import android.graphics.SurfaceTexture;
import android.opengl.EGL14; import android.opengl.EGL14;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
@ -31,7 +32,7 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren
private int mDesiredState = STATE_NOT_RECORDING; private int mDesiredState = STATE_NOT_RECORDING;
private int mTextureId = 0; private int mTextureId = 0;
SnapshotVideoRecorder(VideoResult stub, VideoResultListener listener, GlCameraPreview preview) { SnapshotVideoRecorder(@NonNull VideoResult stub, @Nullable VideoResultListener listener, @NonNull GlCameraPreview preview) {
super(stub, listener); super(stub, listener);
mPreview = preview; mPreview = preview;
mPreview.addRendererFrameCallback(this); mPreview.addRendererFrameCallback(this);
@ -55,7 +56,7 @@ class SnapshotVideoRecorder extends VideoRecorder implements GlCameraPreview.Ren
@RendererThread @RendererThread
@Override @Override
public void onRendererFrame(SurfaceTexture surfaceTexture, float scaleX, float scaleY) { public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, float scaleX, float scaleY) {
if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) { if (mCurrentState == STATE_NOT_RECORDING && mDesiredState == STATE_RECORDING) {
Size size = mResult.getSize(); Size size = mResult.getSize();
// Ensure width and height are divisible by 2, as I have read somewhere. // Ensure width and height are divisible by 2, as I have read somewhere.

@ -1,5 +1,6 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import java.io.File; import java.io.File;
@ -14,7 +15,7 @@ abstract class VideoRecorder {
/* tests */ VideoResult mResult; /* tests */ VideoResult mResult;
/* tests */ VideoResultListener mListener; /* tests */ VideoResultListener mListener;
VideoRecorder(VideoResult stub, VideoResultListener listener) { VideoRecorder(@NonNull VideoResult stub, @Nullable VideoResultListener listener) {
mResult = stub; mResult = stub;
mListener = listener; mListener = listener;
} }

@ -11,8 +11,13 @@ import java.io.File;
*/ */
public class VideoResult { public class VideoResult {
@SuppressWarnings({"WeakerAccess", "unused"})
public static final int REASON_USER = 0; public static final int REASON_USER = 0;
@SuppressWarnings("WeakerAccess")
public static final int REASON_MAX_SIZE_REACHED = 1; public static final int REASON_MAX_SIZE_REACHED = 1;
@SuppressWarnings("WeakerAccess")
public static final int REASON_MAX_DURATION_REACHED = 2; public static final int REASON_MAX_DURATION_REACHED = 2;
boolean isSnapshot; boolean isSnapshot;

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* Audio values indicate whether to record audio stream when record video. * Audio values indicate whether to record audio stream when record video.
* *
@ -30,6 +32,7 @@ public enum Audio implements Control {
return value; return value;
} }
@Nullable
static Audio fromValue(int value) { static Audio fromValue(int value) {
Audio[] list = Audio.values(); Audio[] list = Audio.values();
for (Audio action : list) { for (Audio action : list) {

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
/** /**
@ -21,7 +22,8 @@ public enum Facing implements Control {
*/ */
FRONT(1); FRONT(1);
final static Facing DEFAULT(@Nullable Context context) { @NonNull
static Facing DEFAULT(@Nullable Context context) {
if (context == null) { if (context == null) {
return BACK; return BACK;
} else if (CameraUtils.hasCameraFacing(context, BACK)) { } else if (CameraUtils.hasCameraFacing(context, BACK)) {
@ -45,6 +47,7 @@ public enum Facing implements Control {
return value; return value;
} }
@Nullable
static Facing fromValue(int value) { static Facing fromValue(int value) {
Facing[] list = Facing.values(); Facing[] list = Facing.values();
for (Facing action : list) { for (Facing action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* Flash value indicates the flash mode to be used. * Flash value indicates the flash mode to be used.
* *
@ -51,6 +53,7 @@ public enum Flash implements Control {
return value; return value;
} }
@Nullable
static Flash fromValue(int value) { static Flash fromValue(int value) {
Flash[] list = Flash.values(); Flash[] list = Flash.values();
for (Flash action : list) { for (Flash action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* Gestures actions are actions over camera controls that can be mapped to certain gestures over * Gestures actions are actions over camera controls that can be mapped to certain gestures over
* the screen, using XML attributes or {@link CameraView#mapGesture(Gesture, GestureAction)}. * the screen, using XML attributes or {@link CameraView#mapGesture(Gesture, GestureAction)}.
@ -81,6 +83,7 @@ public enum GestureAction {
return value; return value;
} }
@Nullable
static GestureAction fromValue(int value) { static GestureAction fromValue(int value) {
GestureAction[] list = GestureAction.values(); GestureAction[] list = GestureAction.values();
for (GestureAction action : list) { for (GestureAction action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* Grid values can be used to draw grid lines over the camera preview. * Grid values can be used to draw grid lines over the camera preview.
* *
@ -42,6 +44,7 @@ public enum Grid implements Control {
return value; return value;
} }
@Nullable
static Grid fromValue(int value) { static Grid fromValue(int value) {
Grid[] list = Grid.values(); Grid[] list = Grid.values();
for (Grid action : list) { for (Grid action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* Hdr values indicate whether to use high dynamic range techniques when capturing pictures. * Hdr values indicate whether to use high dynamic range techniques when capturing pictures.
* *
@ -30,6 +32,7 @@ public enum Hdr implements Control {
return value; return value;
} }
@Nullable
static Hdr fromValue(int value) { static Hdr fromValue(int value) {
Hdr[] list = Hdr.values(); Hdr[] list = Hdr.values();
for (Hdr action : list) { for (Hdr action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
import java.io.File; import java.io.File;
/** /**
@ -42,6 +44,7 @@ public enum Mode implements Control {
return value; return value;
} }
@Nullable
static Mode fromValue(int value) { static Mode fromValue(int value) {
Mode[] list = Mode.values(); Mode[] list = Mode.values();
for (Mode action : list) { for (Mode action : list) {

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* The preview engine to be used. * The preview engine to be used.
* *
@ -40,6 +42,7 @@ public enum Preview implements Control {
return value; return value;
} }
@Nullable
static Preview fromValue(int value) { static Preview fromValue(int value) {
Preview[] list = Preview.values(); Preview[] list = Preview.values();
for (Preview action : list) { for (Preview action : list) {

@ -1,6 +1,9 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
/** /**
* Constants for selecting the encoder of video recordings. * Constants for selecting the encoder of video recordings.
* https://developer.android.com/guide/topics/media/media-formats.html#video-formats * https://developer.android.com/guide/topics/media/media-formats.html#video-formats
@ -37,6 +40,7 @@ public enum VideoCodec implements Control {
return value; return value;
} }
@Nullable
static VideoCodec fromValue(int value) { static VideoCodec fromValue(int value) {
VideoCodec[] list = VideoCodec.values(); VideoCodec[] list = VideoCodec.values();
for (VideoCodec action : list) { for (VideoCodec action : list) {

@ -1,6 +1,7 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.Nullable;
/** /**
* White balance values control the white balance settings. * White balance values control the white balance settings.
@ -61,6 +62,7 @@ public enum WhiteBalance implements Control {
return value; return value;
} }
@Nullable
static WhiteBalance fromValue(int value) { static WhiteBalance fromValue(int value) {
WhiteBalance[] list = WhiteBalance.values(); WhiteBalance[] list = WhiteBalance.values();
for (WhiteBalance action : list) { for (WhiteBalance action : list) {

@ -1,6 +1,7 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
@ -45,7 +46,7 @@ public final class CameraLogger {
* @param message the log message * @param message the log message
* @param throwable an optional throwable * @param throwable an optional throwable
*/ */
void log(@LogLevel int level, String tag, String message, @Nullable Throwable throwable); void log(@LogLevel int level, @NonNull String tag, @NonNull String message, @Nullable Throwable throwable);
} }
static String lastMessage; static String lastMessage;
@ -59,7 +60,7 @@ public final class CameraLogger {
sLoggers = new ArrayList<>(); sLoggers = new ArrayList<>();
sLoggers.add(new Logger() { sLoggers.add(new Logger() {
@Override @Override
public void log(int level, String tag, String message, @Nullable Throwable throwable) { public void log(int level, @NonNull String tag, @NonNull String message, @Nullable Throwable throwable) {
switch (level) { switch (level) {
case LEVEL_VERBOSE: Log.v(tag, message, throwable); break; case LEVEL_VERBOSE: Log.v(tag, message, throwable); break;
case LEVEL_INFO: Log.i(tag, message, throwable); break; case LEVEL_INFO: Log.i(tag, message, throwable); break;
@ -70,7 +71,7 @@ public final class CameraLogger {
}); });
} }
static CameraLogger create(String tag) { static CameraLogger create(@NonNull String tag) {
return new CameraLogger(tag); return new CameraLogger(tag);
} }
@ -93,7 +94,8 @@ public final class CameraLogger {
* *
* @param logger logger to add * @param logger logger to add
*/ */
public static void registerLogger(Logger logger) { @SuppressWarnings("WeakerAccess")
public static void registerLogger(@NonNull Logger logger) {
sLoggers.add(logger); sLoggers.add(logger);
} }
@ -103,13 +105,15 @@ public final class CameraLogger {
* *
* @param logger logger to remove * @param logger logger to remove
*/ */
public static void unregisterLogger(Logger logger) { @SuppressWarnings("WeakerAccess")
public static void unregisterLogger(@NonNull Logger logger) {
sLoggers.remove(logger); sLoggers.remove(logger);
} }
@NonNull
private String mTag; private String mTag;
private CameraLogger(String tag) { private CameraLogger(@NonNull String tag) {
mTag = tag; mTag = tag;
} }
@ -117,41 +121,39 @@ public final class CameraLogger {
return sLevel <= messageLevel && sLoggers.size() > 0; return sLevel <= messageLevel && sLoggers.size() > 0;
} }
void v(Object... data) { void v(@NonNull Object... data) {
log(LEVEL_VERBOSE, data); log(LEVEL_VERBOSE, data);
} }
void i(Object... data) { void i(@NonNull Object... data) {
log(LEVEL_INFO, data); log(LEVEL_INFO, data);
} }
void w(Object... data) { void w(@NonNull Object... data) {
log(LEVEL_WARNING, data); log(LEVEL_WARNING, data);
} }
void e(Object... data) { void e(@NonNull Object... data) {
log(LEVEL_ERROR, data); log(LEVEL_ERROR, data);
} }
private void log(@LogLevel int level, Object... data) { private void log(@LogLevel int level, @NonNull Object... data) {
if (!should(level)) return; if (!should(level)) return;
String message = ""; StringBuilder message = new StringBuilder();
Throwable throwable = null; Throwable throwable = null;
final int size = data.length;
for (Object object : data) { for (Object object : data) {
if (object instanceof Throwable) { if (object instanceof Throwable) {
throwable = (Throwable) object; throwable = (Throwable) object;
} }
message += String.valueOf(object); message.append(String.valueOf(object));
message += " "; message.append(" ");
} }
message = message.trim();
for (Logger logger : sLoggers) { for (Logger logger : sLoggers) {
logger.log(level, mTag, message, throwable); logger.log(level, mTag, message.toString().trim(), throwable);
} }
lastMessage = message; lastMessage = message.toString();
lastTag = mTag; lastTag = mTag;
} }
} }

@ -30,7 +30,7 @@ public class CameraUtils {
* @return whether device has cameras * @return whether device has cameras
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static boolean hasCameras(Context context) { public static boolean hasCameras(@NonNull Context context) {
PackageManager manager = context.getPackageManager(); PackageManager manager = context.getPackageManager();
// There's also FEATURE_CAMERA_EXTERNAL , should we support it? // There's also FEATURE_CAMERA_EXTERNAL , should we support it?
return manager.hasSystemFeature(PackageManager.FEATURE_CAMERA) return manager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
@ -46,7 +46,7 @@ public class CameraUtils {
* @param facing either {@link Facing#BACK} or {@link Facing#FRONT} * @param facing either {@link Facing#BACK} or {@link Facing#FRONT}
* @return true if such sensor exists * @return true if such sensor exists
*/ */
public static boolean hasCameraFacing(Context context, Facing facing) { public static boolean hasCameraFacing(@NonNull Context context, @NonNull Facing facing) {
int internal = new Mapper1().map(facing); int internal = new Mapper1().map(facing);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
@ -66,7 +66,7 @@ public class CameraUtils {
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
@WorkerThread @WorkerThread
public static void decodeBitmap(final byte[] source) { public static void decodeBitmap(@NonNull final byte[] source) {
decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE); decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE);
} }
@ -80,7 +80,7 @@ public class CameraUtils {
* @param callback a callback to be notified * @param callback a callback to be notified
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static void decodeBitmap(final byte[] source, final BitmapCallback callback) { public static void decodeBitmap(@NonNull final byte[] source, @NonNull final BitmapCallback callback) {
decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE, callback); decodeBitmap(source, Integer.MAX_VALUE, Integer.MAX_VALUE, callback);
} }
@ -98,7 +98,7 @@ public class CameraUtils {
* @param callback a callback to be notified * @param callback a callback to be notified
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, final BitmapCallback callback) { public static void decodeBitmap(@NonNull final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapCallback callback) {
decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options(), callback); decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options(), callback);
} }
@ -117,12 +117,12 @@ public class CameraUtils {
* @param callback a callback to be notified * @param callback a callback to be notified
*/ */
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, final BitmapCallback callback) { public static void decodeBitmap(@NonNull final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, @NonNull final BitmapCallback callback) {
decodeBitmap(source, maxWidth, maxHeight, options, -1, callback); decodeBitmap(source, maxWidth, maxHeight, options, -1, callback);
} }
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
static void decodeBitmap(final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, final int rotation, final BitmapCallback callback) { static void decodeBitmap(@NonNull final byte[] source, final int maxWidth, final int maxHeight, @NonNull final BitmapFactory.Options options, final int rotation, @NonNull final BitmapCallback callback) {
final Handler ui = new Handler(); final Handler ui = new Handler();
WorkerHandler.run(new Runnable() { WorkerHandler.run(new Runnable() {
@Override @Override
@ -149,7 +149,7 @@ public class CameraUtils {
* @param maxWidth the max allowed width * @param maxWidth the max allowed width
* @param maxHeight the max allowed height * @param maxHeight the max allowed height
*/ */
static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight) { static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight) {
return decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options()); return decodeBitmap(source, maxWidth, maxHeight, new BitmapFactory.Options());
} }
@ -168,14 +168,14 @@ public class CameraUtils {
@SuppressWarnings({"SuspiciousNameCombination", "WeakerAccess"}) @SuppressWarnings({"SuspiciousNameCombination", "WeakerAccess"})
@Nullable @Nullable
@WorkerThread @WorkerThread
public static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options) { public static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options) {
return decodeBitmap(source, maxWidth, maxHeight, options, -1); return decodeBitmap(source, maxWidth, maxHeight, options, -1);
} }
// Null: got OOM // Null: got OOM
// TODO ignores flipping. but it should be super rare. // TODO ignores flipping. but it should be super rare.
@Nullable @Nullable
static Bitmap decodeBitmap(byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options, int rotation) { static Bitmap decodeBitmap(@NonNull byte[] source, int maxWidth, int maxHeight, @NonNull BitmapFactory.Options options, int rotation) {
if (maxWidth <= 0) maxWidth = Integer.MAX_VALUE; if (maxWidth <= 0) maxWidth = Integer.MAX_VALUE;
if (maxHeight <= 0) maxHeight = Integer.MAX_VALUE; if (maxHeight <= 0) maxHeight = Integer.MAX_VALUE;
int orientation; int orientation;
@ -220,6 +220,7 @@ public class CameraUtils {
if (orientation % 180 != 0) { if (orientation % 180 != 0) {
//noinspection SuspiciousNameCombination //noinspection SuspiciousNameCombination
outHeight = options.outWidth; outHeight = options.outWidth;
//noinspection SuspiciousNameCombination
outWidth = options.outHeight; outWidth = options.outHeight;
} }

@ -1,11 +1,13 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.graphics.Rect; import android.graphics.Rect;
import android.support.annotation.NonNull;
class CropHelper { class CropHelper {
// It's important that size and aspect ratio belong to the same reference. // It's important that size and aspect ratio belong to the same reference.
static Rect computeCrop(Size currentSize, AspectRatio targetRatio) { @NonNull
static Rect computeCrop(@NonNull Size currentSize, @NonNull AspectRatio targetRatio) {
int currentWidth = currentSize.getWidth(); int currentWidth = currentSize.getWidth();
int currentHeight = currentSize.getHeight(); int currentHeight = currentSize.getHeight();
if (targetRatio.matches(currentSize)) { if (targetRatio.matches(currentSize)) {

@ -20,10 +20,11 @@ class OrientationHelper {
void onDeviceOrientationChanged(int deviceOrientation); void onDeviceOrientationChanged(int deviceOrientation);
} }
OrientationHelper(Context context, @NonNull Callback callback) { OrientationHelper(@NonNull Context context, @NonNull Callback callback) {
mCallback = callback; mCallback = callback;
mListener = new OrientationEventListener(context.getApplicationContext(), SensorManager.SENSOR_DELAY_NORMAL) { mListener = new OrientationEventListener(context.getApplicationContext(), SensorManager.SENSOR_DELAY_NORMAL) {
@SuppressWarnings("ConstantConditions")
@Override @Override
public void onOrientationChanged(int orientation) { public void onOrientationChanged(int orientation) {
int or = 0; int or = 0;
@ -47,7 +48,7 @@ class OrientationHelper {
}; };
} }
void enable(Context context) { void enable(@NonNull Context context) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) { switch (display.getRotation()) {
case Surface.ROTATION_0: mDisplayOffset = 0; break; case Surface.ROTATION_0: mDisplayOffset = 0; break;

@ -1,10 +1,17 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.graphics.Rect; import android.graphics.Rect;
import android.support.annotation.NonNull;
/**
* This will only be used on low APIs or when GL surface is not available.
* This risks OOMs and was never a good tool.
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
class RotationHelper { class RotationHelper {
static byte[] rotate(final byte[] yuv, final Size size, final int rotation) { static byte[] rotate(@NonNull final byte[] yuv, @NonNull final Size size, final int rotation) {
if (rotation == 0) return yuv; if (rotation == 0) return yuv;
if (rotation % 90 != 0 || rotation < 0 || rotation > 270) { if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0"); throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");

@ -16,7 +16,7 @@ public class SizeSelectors {
* sizes in a list. * sizes in a list.
*/ */
public interface Filter { public interface Filter {
boolean accepts(Size size); boolean accepts(@NonNull Size size);
} }
/** /**
@ -26,6 +26,8 @@ public class SizeSelectors {
* @param filter a filter * @param filter a filter
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector withFilter(@NonNull Filter filter) { public static SizeSelector withFilter(@NonNull Filter filter) {
return new FilterSelector(filter); return new FilterSelector(filter);
} }
@ -37,10 +39,11 @@ public class SizeSelectors {
* @param width the max width * @param width the max width
* @return a new selector * @return a new selector
*/ */
@NonNull
public static SizeSelector maxWidth(final int width) { public static SizeSelector maxWidth(final int width) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getWidth() <= width; return size.getWidth() <= width;
} }
}); });
@ -53,10 +56,11 @@ public class SizeSelectors {
* @param width the min width * @param width the min width
* @return a new selector * @return a new selector
*/ */
@NonNull
public static SizeSelector minWidth(final int width) { public static SizeSelector minWidth(final int width) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getWidth() >= width; return size.getWidth() >= width;
} }
}); });
@ -69,10 +73,12 @@ public class SizeSelectors {
* @param height the max height * @param height the max height
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector maxHeight(final int height) { public static SizeSelector maxHeight(final int height) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getHeight() <= height; return size.getHeight() <= height;
} }
}); });
@ -85,10 +91,11 @@ public class SizeSelectors {
* @param height the min height * @param height the min height
* @return a new selector * @return a new selector
*/ */
@NonNull
public static SizeSelector minHeight(final int height) { public static SizeSelector minHeight(final int height) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getHeight() >= height; return size.getHeight() >= height;
} }
}); });
@ -103,11 +110,13 @@ public class SizeSelectors {
* @param delta a small tolerance value * @param delta a small tolerance value
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector aspectRatio(AspectRatio ratio, final float delta) { public static SizeSelector aspectRatio(AspectRatio ratio, final float delta) {
final float desired = ratio.toFloat(); final float desired = ratio.toFloat();
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
float candidate = AspectRatio.of(size.getWidth(), size.getHeight()).toFloat(); float candidate = AspectRatio.of(size.getWidth(), size.getHeight()).toFloat();
return candidate >= desired - delta && candidate <= desired + delta; return candidate >= desired - delta && candidate <= desired + delta;
} }
@ -120,6 +129,8 @@ public class SizeSelectors {
* *
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector biggest() { public static SizeSelector biggest() {
return new SizeSelector() { return new SizeSelector() {
@NonNull @NonNull
@ -138,6 +149,8 @@ public class SizeSelectors {
* *
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector smallest() { public static SizeSelector smallest() {
return new SizeSelector() { return new SizeSelector() {
@NonNull @NonNull
@ -156,10 +169,12 @@ public class SizeSelectors {
* @param area the max area * @param area the max area
* @return a new selector * @return a new selector
*/ */
@NonNull
@SuppressWarnings("WeakerAccess")
public static SizeSelector maxArea(final int area) { public static SizeSelector maxArea(final int area) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getHeight() * size.getWidth() <= area; return size.getHeight() * size.getWidth() <= area;
} }
}); });
@ -172,10 +187,12 @@ public class SizeSelectors {
* @param area the min area * @param area the min area
* @return a new selector * @return a new selector
*/ */
@SuppressWarnings("WeakerAccess")
@NonNull
public static SizeSelector minArea(final int area) { public static SizeSelector minArea(final int area) {
return withFilter(new Filter() { return withFilter(new Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getHeight() * size.getWidth() >= area; return size.getHeight() * size.getWidth() >= area;
} }
}); });
@ -191,6 +208,7 @@ public class SizeSelectors {
* @param selectors input selectors * @param selectors input selectors
* @return a new selector * @return a new selector
*/ */
@NonNull
public static SizeSelector and(SizeSelector... selectors) { public static SizeSelector and(SizeSelector... selectors) {
return new AndSelector(selectors); return new AndSelector(selectors);
} }
@ -203,6 +221,7 @@ public class SizeSelectors {
* @param selectors input selectors * @param selectors input selectors
* @return a new selector * @return a new selector
*/ */
@NonNull
public static SizeSelector or(SizeSelector... selectors) { public static SizeSelector or(SizeSelector... selectors) {
return new OrSelector(selectors); return new OrSelector(selectors);
} }

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.support.annotation.NonNull;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.WeakHashMap; import java.util.WeakHashMap;
@ -16,7 +17,8 @@ class WorkerHandler {
private final static CameraLogger LOG = CameraLogger.create(WorkerHandler.class.getSimpleName()); private final static CameraLogger LOG = CameraLogger.create(WorkerHandler.class.getSimpleName());
private final static ConcurrentHashMap<String, WeakReference<WorkerHandler>> sCache = new ConcurrentHashMap<>(4); private final static ConcurrentHashMap<String, WeakReference<WorkerHandler>> sCache = new ConcurrentHashMap<>(4);
public static WorkerHandler get(String name) { @NonNull
public static WorkerHandler get(@NonNull String name) {
if (sCache.containsKey(name)) { if (sCache.containsKey(name)) {
WorkerHandler cached = sCache.get(name).get(); WorkerHandler cached = sCache.get(name).get();
if (cached != null) { if (cached != null) {
@ -39,14 +41,14 @@ class WorkerHandler {
// Handy util to perform action in a fallback thread. // Handy util to perform action in a fallback thread.
// Not to be used for long-running operations since they will // Not to be used for long-running operations since they will
// block the fallback thread. // block the fallback thread.
public static void run(Runnable action) { public static void run(@NonNull Runnable action) {
get("FallbackCameraThread").post(action); get("FallbackCameraThread").post(action);
} }
private HandlerThread mThread; private HandlerThread mThread;
private Handler mHandler; private Handler mHandler;
private WorkerHandler(String name) { private WorkerHandler(@NonNull String name) {
mThread = new HandlerThread(name); mThread = new HandlerThread(name);
mThread.setDaemon(true); mThread.setDaemon(true);
mThread.start(); mThread.start();
@ -57,15 +59,16 @@ class WorkerHandler {
return mHandler; return mHandler;
} }
public void post(Runnable runnable) { public void post(@NonNull Runnable runnable) {
mHandler.post(runnable); mHandler.post(runnable);
} }
@NonNull
public Thread getThread() { public Thread getThread() {
return mThread; return mThread;
} }
public static void destroy() { static void destroy() {
for (String key : sCache.keySet()) { for (String key : sCache.keySet()) {
WeakReference<WorkerHandler> ref = sCache.get(key); WeakReference<WorkerHandler> ref = sCache.get(key);
WorkerHandler handler = ref.get(); WorkerHandler handler = ref.get();

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -33,21 +34,23 @@ abstract class CameraPreview<T extends View, Output> {
protected int mInputStreamHeight; protected int mInputStreamHeight;
protected boolean mInputFlipped; protected boolean mInputFlipped;
CameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { CameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
mView = onCreateView(context, parent); mView = onCreateView(context, parent);
mSurfaceCallback = callback; mSurfaceCallback = callback;
} }
@NonNull @NonNull
protected abstract T onCreateView(Context context, ViewGroup parent); protected abstract T onCreateView(@NonNull Context context, @NonNull ViewGroup parent);
@NonNull @NonNull
final T getView() { final T getView() {
return mView; return mView;
} }
@NonNull
abstract Class<Output> getOutputClass(); abstract Class<Output> getOutputClass();
@NonNull
abstract Output getOutput(); abstract Output getOutput();
// As far as I can see, these are the actual preview dimensions, as set in CameraParameters. // As far as I can see, these are the actual preview dimensions, as set in CameraParameters.
@ -63,15 +66,17 @@ abstract class CameraPreview<T extends View, Output> {
} }
} }
@NonNull
final Size getInputStreamSize() { final Size getInputStreamSize() {
return new Size(mInputStreamWidth, mInputStreamHeight); return new Size(mInputStreamWidth, mInputStreamHeight);
} }
@NonNull
final Size getOutputSurfaceSize() { final Size getOutputSurfaceSize() {
return new Size(mOutputSurfaceWidth, mOutputSurfaceHeight); return new Size(mOutputSurfaceWidth, mOutputSurfaceHeight);
} }
final void setSurfaceCallback(SurfaceCallback callback) { final void setSurfaceCallback(@NonNull SurfaceCallback callback) {
mSurfaceCallback = callback; mSurfaceCallback = callback;
// If surface already available, dispatch. // If surface already available, dispatch.
if (mOutputSurfaceWidth != 0 || mOutputSurfaceHeight != 0) { if (mOutputSurfaceWidth != 0 || mOutputSurfaceHeight != 0) {
@ -80,6 +85,7 @@ abstract class CameraPreview<T extends View, Output> {
} }
@SuppressWarnings("WeakerAccess")
protected final void dispatchOnOutputSurfaceAvailable(int width, int height) { protected final void dispatchOnOutputSurfaceAvailable(int width, int height) {
LOG.i("dispatchOnOutputSurfaceAvailable:", "w=", width, "h=", height); LOG.i("dispatchOnOutputSurfaceAvailable:", "w=", width, "h=", height);
mOutputSurfaceWidth = width; mOutputSurfaceWidth = width;
@ -93,6 +99,7 @@ abstract class CameraPreview<T extends View, Output> {
// As far as I can see, these are the view/surface dimensions. // As far as I can see, these are the view/surface dimensions.
// This is called by subclasses. // This is called by subclasses.
@SuppressWarnings("WeakerAccess")
protected final void dispatchOnOutputSurfaceSizeChanged(int width, int height) { protected final void dispatchOnOutputSurfaceSizeChanged(int width, int height) {
LOG.i("dispatchOnOutputSurfaceSizeChanged:", "w=", width, "h=", height); LOG.i("dispatchOnOutputSurfaceSizeChanged:", "w=", width, "h=", height);
if (width != mOutputSurfaceWidth || height != mOutputSurfaceHeight) { if (width != mOutputSurfaceWidth || height != mOutputSurfaceHeight) {
@ -105,6 +112,7 @@ abstract class CameraPreview<T extends View, Output> {
} }
} }
@SuppressWarnings("WeakerAccess")
protected final void dispatchOnOutputSurfaceDestroyed() { protected final void dispatchOnOutputSurfaceDestroyed() {
mOutputSurfaceWidth = 0; mOutputSurfaceWidth = 0;
mOutputSurfaceHeight = 0; mOutputSurfaceHeight = 0;

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.content.Context; import android.content.Context;
import android.graphics.PointF; import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -17,12 +18,12 @@ abstract class GestureLayout extends FrameLayout {
protected Gesture mType; protected Gesture mType;
protected PointF[] mPoints; protected PointF[] mPoints;
public GestureLayout(Context context) { public GestureLayout(@NonNull Context context) {
super(context); super(context);
onInitialize(context); onInitialize(context);
} }
protected void onInitialize(Context context) { protected void onInitialize(@NonNull Context context) {
} }
public void enable(boolean enable) { public void enable(boolean enable) {
@ -35,15 +36,17 @@ abstract class GestureLayout extends FrameLayout {
public abstract boolean onTouchEvent(MotionEvent event); public abstract boolean onTouchEvent(MotionEvent event);
@NonNull
public final Gesture getGestureType() { public final Gesture getGestureType() {
return mType; return mType;
} }
// For tests. // For tests.
void setGestureType(Gesture type) { void setGestureType(@NonNull Gesture type) {
mType = type; mType = type;
} }
@NonNull
public final PointF[] getPoints() { public final PointF[] getPoints() {
return mPoints; return mPoints;
} }

@ -71,7 +71,7 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
/* for tests */ float mScaleY = 1F; /* for tests */ float mScaleY = 1F;
private float[] mScaleXY = new float[] { mScaleX, mScaleY }; private float[] mScaleXY = new float[] { mScaleX, mScaleY };
GlCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { GlCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }
@ -103,7 +103,7 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
@NonNull @NonNull
@Override @Override
protected GLSurfaceView onCreateView(Context context, ViewGroup parent) { protected GLSurfaceView onCreateView(@NonNull Context context, @NonNull ViewGroup parent) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.cameraview_gl_view, parent, false); ViewGroup root = (ViewGroup) LayoutInflater.from(context).inflate(R.layout.cameraview_gl_view, parent, false);
GLSurfaceView glView = root.findViewById(R.id.gl_surface_view); GLSurfaceView glView = root.findViewById(R.id.gl_surface_view);
glView.setEGLContextClientVersion(2); glView.setEGLContextClientVersion(2);
@ -236,11 +236,13 @@ class GlCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple
} }
} }
@NonNull
@Override @Override
Class<SurfaceTexture> getOutputClass() { Class<SurfaceTexture> getOutputClass() {
return SurfaceTexture.class; return SurfaceTexture.class;
} }
@NonNull
@Override @Override
SurfaceTexture getOutput() { SurfaceTexture getOutput() {
return mInputSurfaceTexture; return mInputSurfaceTexture;

@ -26,7 +26,6 @@ class GridLinesLayout extends View {
Task<Integer> drawTask = new Task<>(); Task<Integer> drawTask = new Task<>();
public GridLinesLayout(@NonNull Context context) { public GridLinesLayout(@NonNull Context context) {
this(context, null); this(context, null);
} }
@ -45,11 +44,12 @@ class GridLinesLayout extends View {
vert.setBounds(0, top, (int) width, bottom); vert.setBounds(0, top, (int) width, bottom);
} }
@NonNull
public Grid getGridMode() { public Grid getGridMode() {
return gridMode; return gridMode;
} }
public void setGridMode(Grid gridMode) { public void setGridMode(@NonNull Grid gridMode) {
this.gridMode = gridMode; this.gridMode = gridMode;
postInvalidate(); postInvalidate();
} }
@ -89,7 +89,7 @@ class GridLinesLayout extends View {
} }
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
drawTask.start(); drawTask.start();
int count = getLineCount(); int count = getLineCount();

@ -1,8 +1,10 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PointF; import android.graphics.PointF;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector;
@ -14,14 +16,12 @@ class PinchGestureLayout extends GestureLayout {
private boolean mNotify; private boolean mNotify;
/* tests */ float mFactor = 0; /* tests */ float mFactor = 0;
public PinchGestureLayout(@NonNull Context context) {
public PinchGestureLayout(Context context) {
super(context); super(context);
} }
@Override @Override
protected void onInitialize(Context context) { protected void onInitialize(@NonNull Context context) {
super.onInitialize(context); super.onInitialize(context);
mPoints = new PointF[]{ new PointF(0, 0), new PointF(0, 0) }; mPoints = new PointF[]{ new PointF(0, 0), new PointF(0, 0) };
mDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { mDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@ -42,6 +42,7 @@ class PinchGestureLayout extends GestureLayout {
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
if (!mEnabled) return false; if (!mEnabled) return false;

@ -1,7 +1,9 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PointF; import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -14,13 +16,12 @@ class ScrollGestureLayout extends GestureLayout {
private boolean mNotify; private boolean mNotify;
/* tests */ float mFactor; /* tests */ float mFactor;
public ScrollGestureLayout(@NonNull Context context) {
public ScrollGestureLayout(Context context) {
super(context); super(context);
} }
@Override @Override
protected void onInitialize(Context context) { protected void onInitialize(@NonNull Context context) {
super.onInitialize(context); super.onInitialize(context);
mPoints = new PointF[]{ new PointF(0, 0), new PointF(0, 0) }; mPoints = new PointF[]{ new PointF(0, 0), new PointF(0, 0) };
mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@ -51,7 +52,7 @@ class ScrollGestureLayout extends GestureLayout {
mDetector.setIsLongpressEnabled(false); // Looks important. mDetector.setIsLongpressEnabled(false); // Looks important.
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
if (!mEnabled) return false; if (!mEnabled) return false;
@ -71,7 +72,6 @@ class ScrollGestureLayout extends GestureLayout {
return mNotify; return mNotify;
} }
@Override @Override
public float scaleValue(float currValue, float minValue, float maxValue) { public float scaleValue(float currValue, float minValue, float maxValue) {
float delta = mFactor; // -1 ... 1 float delta = mFactor; // -1 ... 1

@ -2,6 +2,7 @@ package com.otaliastudios.cameraview;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
@ -18,13 +19,13 @@ class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHolder> {
private boolean mDispatched; private boolean mDispatched;
SurfaceCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { SurfaceCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }
@NonNull @NonNull
@Override @Override
protected SurfaceView onCreateView(Context context, ViewGroup parent) { protected SurfaceView onCreateView(@NonNull Context context, @NonNull ViewGroup parent) {
View root = LayoutInflater.from(context).inflate(R.layout.cameraview_surface_view, parent, false); View root = LayoutInflater.from(context).inflate(R.layout.cameraview_surface_view, parent, false);
parent.addView(root, 0); parent.addView(root, 0);
SurfaceView surfaceView = root.findViewById(R.id.surface_view); SurfaceView surfaceView = root.findViewById(R.id.surface_view);
@ -59,11 +60,13 @@ class SurfaceCameraPreview extends CameraPreview<SurfaceView, SurfaceHolder> {
return surfaceView; return surfaceView;
} }
@NonNull
@Override @Override
SurfaceHolder getOutput() { SurfaceHolder getOutput() {
return getView().getHolder(); return getView().getHolder();
} }
@NonNull
@Override @Override
Class<SurfaceHolder> getOutputClass() { Class<SurfaceHolder> getOutputClass() {
return SurfaceHolder.class; return SurfaceHolder.class;

@ -2,8 +2,11 @@ package com.otaliastudios.cameraview;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.PointF; import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -13,20 +16,18 @@ import android.widget.ImageView;
class TapGestureLayout extends GestureLayout { class TapGestureLayout extends GestureLayout {
private GestureDetector mDetector; private GestureDetector mDetector;
private boolean mNotify; private boolean mNotify;
private FrameLayout mFocusMarkerContainer; private FrameLayout mFocusMarkerContainer;
private ImageView mFocusMarkerFill; private ImageView mFocusMarkerFill;
public TapGestureLayout(Context context) { public TapGestureLayout(@NonNull Context context) {
super(context); super(context);
} }
@Override @Override
protected void onInitialize(Context context) { protected void onInitialize(@NonNull Context context) {
super.onInitialize(context); super.onInitialize(context);
mPoints = new PointF[]{ new PointF(0, 0) }; mPoints = new PointF[]{ new PointF(0, 0) };
mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { mDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@ -62,7 +63,7 @@ class TapGestureLayout extends GestureLayout {
mFocusMarkerFill = findViewById(R.id.fill); mFocusMarkerFill = findViewById(R.id.fill);
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public boolean onTouchEvent(MotionEvent event) { public boolean onTouchEvent(MotionEvent event) {
if (!mEnabled) return false; if (!mEnabled) return false;
@ -100,7 +101,7 @@ class TapGestureLayout extends GestureLayout {
} }
}; };
public void onFocusStart(PointF point) { public void onFocusStart(@NonNull PointF point) {
removeCallbacks(mFocusMarkerHideRunnable); removeCallbacks(mFocusMarkerHideRunnable);
mFocusMarkerContainer.clearAnimation(); // animate().setListener(null).cancel(); mFocusMarkerContainer.clearAnimation(); // animate().setListener(null).cancel();
mFocusMarkerFill.clearAnimation(); // animate().setListener(null).cancel(); mFocusMarkerFill.clearAnimation(); // animate().setListener(null).cancel();
@ -128,7 +129,6 @@ class TapGestureLayout extends GestureLayout {
}); });
} }
public void onFocusEnd(boolean success) { public void onFocusEnd(boolean success) {
if (success) { if (success) {
animate(mFocusMarkerContainer, 1, 0, 500, 0, null); animate(mFocusMarkerContainer, 1, 0, 500, 0, null);
@ -145,9 +145,8 @@ class TapGestureLayout extends GestureLayout {
} }
} }
private static void animate(@NonNull View view, float scale, float alpha, long duration, long delay,
private static void animate(View view, float scale, float alpha, long duration, long delay, @Nullable Animator.AnimatorListener listener) {
Animator.AnimatorListener listener) {
view.animate().scaleX(scale).scaleY(scale) view.animate().scaleX(scale).scaleY(scale)
.alpha(alpha) .alpha(alpha)
.setDuration(duration) .setDuration(duration)

@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.TextureView; import android.view.TextureView;
import android.view.View; import android.view.View;
@ -11,13 +12,13 @@ import android.view.ViewGroup;
class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> { class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> {
TextureCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { TextureCameraPreview(@NonNull Context context, @NonNull ViewGroup parent, @Nullable SurfaceCallback callback) {
super(context, parent, callback); super(context, parent, callback);
} }
@NonNull @NonNull
@Override @Override
protected TextureView onCreateView(Context context, ViewGroup parent) { protected TextureView onCreateView(@NonNull Context context, @NonNull ViewGroup parent) {
View root = LayoutInflater.from(context).inflate(R.layout.cameraview_texture_view, parent, false); View root = LayoutInflater.from(context).inflate(R.layout.cameraview_texture_view, parent, false);
parent.addView(root, 0); parent.addView(root, 0);
TextureView texture = root.findViewById(R.id.texture_view); TextureView texture = root.findViewById(R.id.texture_view);
@ -46,11 +47,13 @@ class TextureCameraPreview extends CameraPreview<TextureView, SurfaceTexture> {
return texture; return texture;
} }
@NonNull
@Override @Override
Class<SurfaceTexture> getOutputClass() { Class<SurfaceTexture> getOutputClass() {
return SurfaceTexture.class; return SurfaceTexture.class;
} }
@NonNull
@Override @Override
SurfaceTexture getOutput() { SurfaceTexture getOutput() {
return getView().getSurfaceTexture(); return getView().getSurfaceTexture();

@ -1,6 +1,8 @@
package com.otaliastudios.cameraview; package com.otaliastudios.cameraview;
import android.support.annotation.NonNull;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -33,7 +35,7 @@ public class SizeSelectorsTest {
public void testWithFilter() { public void testWithFilter() {
SizeSelector selector = SizeSelectors.withFilter(new SizeSelectors.Filter() { SizeSelector selector = SizeSelectors.withFilter(new SizeSelectors.Filter() {
@Override @Override
public boolean accepts(Size size) { public boolean accepts(@NonNull Size size) {
return size.getWidth() == 600; return size.getWidth() == 600;
} }
}); });

@ -43,9 +43,9 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis
camera = findViewById(R.id.camera); camera = findViewById(R.id.camera);
camera.setLifecycleOwner(this); camera.setLifecycleOwner(this);
camera.addCameraListener(new CameraListener() { camera.addCameraListener(new CameraListener() {
public void onCameraOpened(CameraOptions options) { onOpened(options); } public void onCameraOpened(@NonNull CameraOptions options) { onOpened(options); }
public void onPictureTaken(PictureResult result) { onPicture(result); } public void onPictureTaken(@NonNull PictureResult result) { onPicture(result); }
public void onVideoTaken(VideoResult result) { onVideo(result); } public void onVideoTaken(@NonNull VideoResult result) { onVideo(result); }
public void onCameraError(@NonNull CameraException exception) { public void onCameraError(@NonNull CameraException exception) {
onError(exception); onError(exception);
} }

Loading…
Cancel
Save