Fixed serious bugs. Option to have WRAP_CONTENT to both dimensions

pull/1/head
Mattia Iavarone 7 years ago
parent c5e38fca19
commit b8628d4c2d
  1. 15
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 5
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  3. 1
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  4. 29
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  5. 4
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  6. 64
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java

@ -48,6 +48,7 @@ class Camera1 extends CameraImpl {
private int mDisplayOffset;
private int mDeviceOrientation;
private int mSensorOffset;
@Facing private int mFacing;
@Flash private int mFlash;
@ -130,6 +131,7 @@ class Camera1 extends CameraImpl {
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, mCameraInfo);
if (mCameraInfo.facing == internalFacing) {
mSensorOffset = mCameraInfo.orientation;
mCameraId = i;
mFacing = facing;
break;
@ -291,6 +293,11 @@ class Camera1 extends CameraImpl {
return mPreviewSize;
}
@Override
boolean shouldFlipSizes() {
return mSensorOffset % 180 != 0;
}
@Override
boolean isCameraOpened() {
return mCamera != null;
@ -337,9 +344,9 @@ class Camera1 extends CameraImpl {
private int computeCameraToDisplayOffset() {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
// or: (360 - ((info.orientation + displayOrientation) % 360)) % 360;
return ((mCameraInfo.orientation - mDisplayOffset) + 360 + 180) % 360;
return ((mSensorOffset - mDisplayOffset) + 360 + 180) % 360;
} else {
return (mCameraInfo.orientation - mDisplayOffset + 360) % 360;
return (mSensorOffset - mDisplayOffset + 360) % 360;
}
}
@ -348,7 +355,7 @@ class Camera1 extends CameraImpl {
* the camera APIs as long as you call {@link Camera.Parameters#setRotation(int)}.
*/
private int computeExifOrientation() {
return (mDeviceOrientation + mCameraInfo.orientation) % 360;
return (mDeviceOrientation + mSensorOffset) % 360;
}
private int calculateCaptureRotation() {
@ -388,7 +395,7 @@ class Camera1 extends CameraImpl {
private void adjustCameraParameters() {
boolean invertPreviewSizes = mDisplayOffset % 180 != 0;
boolean invertPreviewSizes = shouldFlipSizes(); // mDisplayOffset % 180 != 0;
mPreview.setDesiredSize(
invertPreviewSizes ? getPreviewSize().getHeight() : getPreviewSize().getWidth(),
invertPreviewSizes ? getPreviewSize().getWidth() : getPreviewSize().getHeight()

@ -231,6 +231,11 @@ class Camera2 extends CameraImpl {
return mPreviewSize;
}
@Override
boolean shouldFlipSizes() {
return false;
}
@Override
boolean isCameraOpened() {
return mCamera != null;

@ -31,6 +31,7 @@ abstract class CameraImpl {
abstract Size getCaptureSize();
abstract Size getPreviewSize();
abstract boolean shouldFlipSizes(); // Wheter the Sizes should be flipped to match the view orientation.
abstract boolean isCameraOpened();
@Nullable

@ -1,6 +1,7 @@
package com.flurgle.camerakit;
import android.graphics.SurfaceTexture;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
@ -14,6 +15,7 @@ abstract class PreviewImpl {
private OnSurfaceChangedCallback mOnSurfaceChangedCallback;
// As far as I can see, these are the view/surface dimensions.
// This live in the 'View' orientation.
private int mSurfaceWidth;
private int mSurfaceHeight;
@ -49,7 +51,8 @@ abstract class PreviewImpl {
}
// As far as I can see, these are the view/surface dimensions.
// This is called by subclasses.
// This is called by subclasses. 1080, 1794 -- 1080, 1440
protected void setSurfaceSize(int width, int height) {
this.mSurfaceWidth = width;
this.mSurfaceHeight = height;
@ -57,7 +60,7 @@ abstract class PreviewImpl {
}
// As far as I can see, these are the actual preview dimensions, as set in CameraParameters.
// This is called by the CameraImpl.
// This is called by the CameraImpl. 1200, 1600
void setDesiredSize(int width, int height) {
this.mDesiredWidth = width;
this.mDesiredHeight = height;
@ -73,26 +76,24 @@ abstract class PreviewImpl {
* to match the desired aspect ratio.
* This means that the external part of the surface will be cropped by the outer view.
*/
protected void refreshScale() {
private void refreshScale() {
getView().post(new Runnable() {
@Override
public void run() {
if (mDesiredWidth != 0 && mDesiredHeight != 0) {
AspectRatio aspectRatio = AspectRatio.of(mDesiredWidth, mDesiredHeight);
int targetHeight = (int) (getView().getWidth() * aspectRatio.toFloat());
float scaleY;
if (getView().getHeight() > 0) {
scaleY = (float) targetHeight / (float) getView().getHeight();
} else {
scaleY = 1;
float targetHeight = (float) mSurfaceWidth / aspectRatio.toFloat();
float scale = 1;
if (mSurfaceHeight > 0) {
scale = targetHeight / (float) mSurfaceHeight;
}
if (scaleY > 1) {
getView().setScaleX(1);
getView().setScaleY(scaleY);
if (scale > 1) {
getView().setScaleX(1f);
getView().setScaleY(scale);
} else {
getView().setScaleX(1 / scaleY);
getView().setScaleY(1);
getView().setScaleX(1f / scale);
getView().setScaleY(1f);
}
}
}

@ -14,7 +14,7 @@ class TextureViewPreview extends PreviewImpl {
private final TextureView mTextureView;
TextureViewPreview(Context context, ViewGroup parent) {
final View view = View.inflate(context, R.layout.texture_view, parent);
final View view = View.inflate(context, R.layout.texture_view, parent); // MATCH_PARENT
mTextureView = (TextureView) view.findViewById(R.id.texture_view);
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@ -28,7 +28,7 @@ class TextureViewPreview extends PreviewImpl {
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
setSurfaceSize(width, height);
dispatchSurfaceChanged();
refreshScale();
// refreshScale();
}
@Override

@ -11,8 +11,10 @@ import android.content.ContextWrapper;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
@ -24,6 +26,7 @@ import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
@ -174,9 +177,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Log.e(TAG, "onAttachedToWindow");
if (!isInEditMode()) {
Log.e(TAG, "onAttachedToWindow: enabling orientation detector.");
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
mOrientationHelper.enable(display);
@ -185,9 +186,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override
protected void onDetachedFromWindow() {
Log.e(TAG, "onDetachedFromWindow");
if (!isInEditMode()) {
Log.e(TAG, "onDetachedFromWindow: disabling orientation detector.");
mOrientationHelper.disable();
}
super.onDetachedFromWindow();
@ -215,20 +214,55 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
Size previewSize = getPreviewSize();
if (previewSize == null) {
// Early measure.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
if (getLayoutParams().width == LayoutParams.WRAP_CONTENT) {
int height = MeasureSpec.getSize(heightMeasureSpec);
float ratio = (float) height / (float) previewSize.getWidth();
int width = (int) (previewSize.getHeight() * ratio);
boolean wwc = getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT;
boolean hwc = getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
boolean flip = mCameraImpl.shouldFlipSizes();
float previewWidth = flip ? previewSize.getHeight() : previewSize.getWidth();
float previewHeight = flip ? previewSize.getWidth() : previewSize.getHeight();
if (wwc && hwc) {
// If both dimensions are WRAP_CONTENT, let's try to fit the preview size perfectly
// without cropping.
// TODO: This should actually be a flag, like scaleMode, that replaces cropOutput and adjustViewBounds.
// This is like a fitCenter.
// preview: 1600x1200
// parent: 1080x1794
float parentHeight = MeasureSpec.getSize(heightMeasureSpec); // 1794.
float parentWidth = MeasureSpec.getSize(widthMeasureSpec); // 1080. mode = AT_MOST
float targetRatio = previewHeight / previewWidth;
float currentRatio = parentHeight / parentWidth;
Log.e(TAG, "parentHeight="+parentHeight+", parentWidth="+parentWidth);
Log.e(TAG, "previewHeight="+previewHeight+", previewWidth="+previewWidth);
if (currentRatio > targetRatio) {
// View is too tall. Must reduce height.
int newHeight = (int) (parentWidth * targetRatio);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
} else {
// View is too wide. Must reduce width.
int newWidth = (int) (parentHeight / targetRatio);
super.onMeasure(MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
}
} else if (wwc) {
// Legacy behavior, with just a WC dimension. This is dangerous because the final size
// might be bigger than the available size, resulting in part of the surface getting cropped.
// Think for example of a 4:3 preview in a 16:9 screen, with width=MP and height=WC.
// This is like a cropCenter.
float height = MeasureSpec.getSize(heightMeasureSpec);
float ratio = height / previewWidth;
int width = (int) (previewHeight * ratio);
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightMeasureSpec);
} else if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
int width = MeasureSpec.getSize(widthMeasureSpec);
float ratio = (float) width / (float) previewSize.getHeight();
int height = (int) (previewSize.getWidth() * ratio);
} else if (hwc) {
float width = MeasureSpec.getSize(widthMeasureSpec);
float ratio = width / previewHeight;
int height = (int) (previewWidth * ratio);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
} else {
@ -446,12 +480,18 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/**
* Returns the size used for the preview,
* or null if it hasn't been computed (for example if the surface is not ready).
* @return a Size
*/
@Nullable
public Size getPreviewSize() {
return mCameraImpl != null ? mCameraImpl.getPreviewSize() : null;
}
/**
* Returns the size used for the capture,
* or null if it hasn't been computed yet (for example if the surface is not ready).
* @return a Size
*/
@Nullable
public Size getCaptureSize() {
return mCameraImpl != null ? mCameraImpl.getCaptureSize() : null;

Loading…
Cancel
Save