Merge branch 'master' into master

pull/1/head
Dylan McIntyre 8 years ago committed by GitHub
commit 133fd134de
  1. 1
      build.gradle
  2. 5
      camerakit/build.gradle
  3. 17
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  4. 44
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  5. 5
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  6. 14
      camerakit/src/main/base/com/flurgle/camerakit/CameraProperties.java
  7. 121
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java

@ -15,6 +15,7 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
jcenter() jcenter()
maven { url 'https://maven.google.com' }
} }
} }

@ -33,6 +33,11 @@ android {
dependencies { dependencies {
compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.android.support:appcompat-v7:25.2.0'
compile "android.arch.lifecycle:runtime:1.0.0-alpha1"
compile "android.arch.lifecycle:extensions:1.0.0-alpha1"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"
} }
apply from: 'https://raw.githubusercontent.com/blundell/release-android-library/master/android-release-aar.gradle' apply from: 'https://raw.githubusercontent.com/blundell/release-android-library/master/android-release-aar.gradle'

@ -7,6 +7,7 @@ import android.media.CamcorderProfile;
import android.media.MediaRecorder; import android.media.MediaRecorder;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import android.support.annotation.Nullable;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.View; import android.view.View;
@ -39,6 +40,7 @@ public class Camera1 extends CameraImpl {
private int mCameraId; private int mCameraId;
private Camera mCamera; private Camera mCamera;
private Camera.Parameters mCameraParameters; private Camera.Parameters mCameraParameters;
private CameraProperties mCameraProperties;
private Camera.CameraInfo mCameraInfo; private Camera.CameraInfo mCameraInfo;
private Size mPreviewSize; private Size mPreviewSize;
private Size mCaptureSize; private Size mCaptureSize;
@ -212,7 +214,6 @@ public class Camera1 extends CameraImpl {
void captureImage() { void captureImage() {
switch (mMethod) { switch (mMethod) {
case METHOD_STANDARD: case METHOD_STANDARD:
// Null check required for camera here as is briefly null when View is detached // Null check required for camera here as is briefly null when View is detached
if (!capturingImage && mCamera != null) { if (!capturingImage && mCamera != null) {
@ -221,10 +222,8 @@ public class Camera1 extends CameraImpl {
mCamera.takePicture(null, null, null, mCamera.takePicture(null, null, null,
new Camera.PictureCallback() { new Camera.PictureCallback() {
@Override @Override
public void onPictureTaken(byte[] data, Camera camera) { public void onPictureTaken(byte[] data, Camera camera) {
mCameraListener.onPictureTaken(data); mCameraListener.onPictureTaken(data);
// Reset capturing state to allow photos to be taken // Reset capturing state to allow photos to be taken
@ -331,6 +330,12 @@ public class Camera1 extends CameraImpl {
return mCamera != null; return mCamera != null;
} }
@Nullable
@Override
CameraProperties getCameraProperties() {
return mCameraProperties;
}
// Internal: // Internal:
private void openCamera() { private void openCamera() {
@ -341,6 +346,7 @@ public class Camera1 extends CameraImpl {
mCamera = Camera.open(mCameraId); mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters(); mCameraParameters = mCamera.getParameters();
collectCameraProperties();
adjustCameraParameters(); adjustCameraParameters();
mCamera.setDisplayOrientation(calculatePreviewRotation()); mCamera.setDisplayOrientation(calculatePreviewRotation());
@ -413,6 +419,11 @@ public class Camera1 extends CameraImpl {
mCamera.setParameters(mCameraParameters); mCamera.setParameters(mCameraParameters);
} }
private void collectCameraProperties() {
mCameraProperties = new CameraProperties(mCameraParameters.getVerticalViewAngle(),
mCameraParameters.getHorizontalViewAngle());
}
private TreeSet<AspectRatio> findCommonAspectRatios(List<Camera.Size> previewSizes, List<Camera.Size> captureSizes) { private TreeSet<AspectRatio> findCommonAspectRatios(List<Camera.Size> previewSizes, List<Camera.Size> captureSizes) {
Set<AspectRatio> previewAspectRatios = new HashSet<>(); Set<AspectRatio> previewAspectRatios = new HashSet<>();
for (Camera.Size size : previewSizes) { for (Camera.Size size : previewSizes) {

@ -3,14 +3,18 @@ package com.flurgle.camerakit;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.graphics.ImageFormat; import android.graphics.ImageFormat;
import android.graphics.PointF;
import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.params.StreamConfigurationMap;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.SizeF;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.TreeSet; import java.util.TreeSet;
@ -28,6 +32,8 @@ class Camera2 extends CameraImpl {
private Size mCaptureSize; private Size mCaptureSize;
private Size mPreviewSize; private Size mPreviewSize;
private final HashMap<String, CameraProperties> mCameraPropertyMap = new HashMap<>();
Camera2(CameraListener callback, PreviewImpl preview, Context context) { Camera2(CameraListener callback, PreviewImpl preview, Context context) {
super(callback, preview); super(callback, preview);
preview.setCallback(new PreviewImpl.Callback() { preview.setCallback(new PreviewImpl.Callback() {
@ -38,6 +44,36 @@ class Camera2 extends CameraImpl {
}); });
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
// Get all view angles
try {
for (final String cameraId : mCameraManager.getCameraIdList()) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(cameraId);
@SuppressWarnings("ConstantConditions")
int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (orientation == CameraCharacteristics.LENS_FACING_BACK) {
float[] maxFocus = characteristics.get(
CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
if (maxFocus == null) {
continue;
}
SizeF size = characteristics.get(
CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);
if (size == null) {
continue;
}
float w = size.getWidth();
float h = size.getHeight();
mCameraPropertyMap.put(cameraId, new CameraProperties(
(float) Math.toDegrees(2*Math.atan(size.getWidth()/(maxFocus[0]*2))),
(float) Math.toDegrees(2*Math.atan(size.getHeight()/(maxFocus[0]*2)))
));
}
}
} catch (CameraAccessException e) {
throw new RuntimeException("Failed to get camera view angles", e);
}
} }
// CameraImpl: // CameraImpl:
@ -196,6 +232,14 @@ class Camera2 extends CameraImpl {
return mCamera != null; return mCamera != null;
} }
@Nullable
@Override
CameraProperties getCameraProperties() {
if (mCamera == null) {
return null;
}
return mCameraPropertyMap.get(mCamera.getId());
}
// Internal // Internal
private List<Size> getAvailableCaptureResolutions() { private List<Size> getAvailableCaptureResolutions() {

@ -1,5 +1,7 @@
package com.flurgle.camerakit; package com.flurgle.camerakit;
import android.support.annotation.Nullable;
abstract class CameraImpl { abstract class CameraImpl {
protected final CameraListener mCameraListener; protected final CameraListener mCameraListener;
@ -30,4 +32,7 @@ abstract class CameraImpl {
abstract Size getPreviewResolution(); abstract Size getPreviewResolution();
abstract boolean isCameraOpened(); abstract boolean isCameraOpened();
@Nullable
abstract CameraProperties getCameraProperties();
} }

@ -0,0 +1,14 @@
package com.flurgle.camerakit;
/**
* Simple pojo containing various camera properties.
*/
public class CameraProperties {
public final float verticalViewingAngle;
public final float horizontalViewingAngle;
public CameraProperties(float verticalViewingAngle, float horizontalViewingAngle) {
this.verticalViewingAngle = verticalViewingAngle;
this.horizontalViewingAngle = horizontalViewingAngle;
}
}

@ -2,12 +2,18 @@ package com.flurgle.camerakit;
import android.Manifest; import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.OnLifecycleEvent;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.YuvImage; import android.graphics.YuvImage;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
@ -35,7 +41,32 @@ import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_LAZY;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE; import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_STRICT; import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_STRICT;
public class CameraView extends FrameLayout { /**
* The CameraView implements the LifecycleObserver interface for ease of use. To take advantage of
* this, simply call the following from any LifecycleOwner:
* <pre>
* {@code
* protected void onCreate(@Nullable Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* setContentView(R.layout.my_view);
* ...
* getLifecycle().addObserver(mCameraView);
* }
* }
* </pre>
*/
public class CameraView extends FrameLayout implements LifecycleObserver {
private static Handler sWorkerHandler;
static {
// Initialize a single worker thread. This can be static since only a single camera
// reference can exist at a time.
HandlerThread workerThread = new HandlerThread("CameraViewWorker");
workerThread.setDaemon(true);
workerThread.start();
sWorkerHandler = new Handler(workerThread.getLooper());
}
@Facing @Facing
private int mFacing; private int mFacing;
@ -57,24 +88,33 @@ public class CameraView extends FrameLayout {
@VideoQuality @VideoQuality
private int mVideoQuality; private int mVideoQuality;
private int mJpegQuality; private int mJpegQuality;
private boolean mCropOutput; private boolean mCropOutput;
private boolean mAdjustViewBounds;
private boolean mAdjustViewBounds;
private CameraListenerMiddleWare mCameraListener; private CameraListenerMiddleWare mCameraListener;
private DisplayOrientationDetector mDisplayOrientationDetector;
private DisplayOrientationDetector mDisplayOrientationDetector;
private CameraImpl mCameraImpl; private CameraImpl mCameraImpl;
private PreviewImpl mPreviewImpl; private PreviewImpl mPreviewImpl;
private Lifecycle mLifecycle;
private boolean mIsStarted;
public CameraView(@NonNull Context context) { public CameraView(@NonNull Context context) {
super(context, null); super(context, null);
init(context, null);
} }
@SuppressWarnings("all") @SuppressWarnings("all")
public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) { public CameraView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init(context, attrs);
}
@SuppressWarnings("WrongConstant")
private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
if (attrs != null) { if (attrs != null) {
TypedArray a = context.getTheme().obtainStyledAttributes( TypedArray a = context.getTheme().obtainStyledAttributes(
attrs, attrs,
@ -102,6 +142,7 @@ public class CameraView extends FrameLayout {
mPreviewImpl = new TextureViewPreview(context, this); mPreviewImpl = new TextureViewPreview(context, this);
mCameraImpl = new Camera1(mCameraListener, mPreviewImpl); mCameraImpl = new Camera1(mCameraListener, mPreviewImpl);
mIsStarted = false;
setFacing(mFacing); setFacing(mFacing);
setFlash(mFlash); setFlash(mFlash);
setFocus(mFocus); setFocus(mFocus);
@ -118,7 +159,6 @@ public class CameraView extends FrameLayout {
mPreviewImpl.setDisplayOrientation(displayOrientation); mPreviewImpl.setDisplayOrientation(displayOrientation);
} }
}; };
}
final FocusMarkerLayout focusMarkerLayout = new FocusMarkerLayout(getContext()); final FocusMarkerLayout focusMarkerLayout = new FocusMarkerLayout(getContext());
addView(focusMarkerLayout); addView(focusMarkerLayout);
@ -135,11 +175,12 @@ public class CameraView extends FrameLayout {
} }
}); });
} }
mLifecycle = null;
}
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
if (!isInEditMode()) { if (!isInEditMode()) {
mDisplayOrientationDetector.enable( mDisplayOrientationDetector.enable(
ViewCompat.isAttachedToWindow(this) ViewCompat.isAttachedToWindow(this)
@ -152,7 +193,9 @@ public class CameraView extends FrameLayout {
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
if (!isInEditMode()) {
mDisplayOrientationDetector.disable(); mDisplayOrientationDetector.disable();
}
super.onDetachedFromWindow(); super.onDetachedFromWindow();
} }
@ -189,7 +232,42 @@ public class CameraView extends FrameLayout {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} }
public boolean isStarted() {
return mIsStarted;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (mLifecycle != null && mLifecycle.getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
// Potentially update the UI
if (enabled) {
start();
} else {
stop();
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume(LifecycleOwner owner) {
mLifecycle = owner.getLifecycle();
start();
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause(LifecycleOwner owner) {
mLifecycle = owner.getLifecycle();
stop();
}
public void start() { public void start() {
if (mIsStarted || !isEnabled()) {
// Already started, do nothing.
return;
}
mIsStarted = true;
int cameraCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA); int cameraCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA);
int audioCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.RECORD_AUDIO); int audioCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.RECORD_AUDIO);
@ -216,28 +294,42 @@ public class CameraView extends FrameLayout {
break; break;
} }
new Thread(new Runnable() { sWorkerHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mCameraImpl.start(); mCameraImpl.start();
} }
}).start(); });
} }
public void stop() { public void stop() {
if (!mIsStarted) {
// Already stopped, do nothing.
return;
}
mIsStarted = false;
mCameraImpl.stop(); mCameraImpl.stop();
} }
public void setFacing(@Facing @Nullable
final int facing) { public CameraProperties getCameraProperties() {
return mCameraImpl.getCameraProperties();
}
@Facing
public int getFacing() {
return mFacing;
}
public void setFacing(@Facing final int facing) {
this.mFacing = facing; this.mFacing = facing;
new Thread(new Runnable() { sWorkerHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
mCameraImpl.setFacing(facing); mCameraImpl.setFacing(facing);
} }
}).start(); });
} }
public void setFlash(@Flash int flash) { public void setFlash(@Flash int flash) {
@ -245,6 +337,11 @@ public class CameraView extends FrameLayout {
mCameraImpl.setFlash(flash); mCameraImpl.setFlash(flash);
} }
@Flash
public int getFlash() {
return mFlash;
}
public void setFocus(@Focus int focus) { public void setFocus(@Focus int focus) {
this.mFocus = focus; this.mFocus = focus;
if (this.mFocus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER) { if (this.mFocus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER) {

Loading…
Cancel
Save