Import source from https://github.com/dm77/barcodescanner
This commit is contained in:
parent
69680a9856
commit
e9f9decf00
|
@ -239,7 +239,6 @@ ext.groups = [
|
|||
regex: [
|
||||
],
|
||||
group: [
|
||||
'me.dm7.barcodescanner',
|
||||
]
|
||||
]
|
||||
]
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace "me.dm7.barcodescanner.core"
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.annotation:annotation-jvm:1.6.0'
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.findAll { it.name.startsWith("lint") }.each {
|
||||
it.enabled = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
public abstract class BarcodeScannerView extends FrameLayout implements Camera.PreviewCallback {
|
||||
|
||||
private CameraWrapper mCameraWrapper;
|
||||
private CameraPreview mPreview;
|
||||
private IViewFinder mViewFinderView;
|
||||
private Rect mFramingRectInPreview;
|
||||
private CameraHandlerThread mCameraHandlerThread;
|
||||
private Boolean mFlashState;
|
||||
private boolean mAutofocusState = true;
|
||||
private boolean mShouldScaleToFill = true;
|
||||
|
||||
private boolean mIsLaserEnabled = true;
|
||||
@ColorInt private int mLaserColor = getResources().getColor(R.color.viewfinder_laser);
|
||||
@ColorInt private int mBorderColor = getResources().getColor(R.color.viewfinder_border);
|
||||
private int mMaskColor = getResources().getColor(R.color.viewfinder_mask);
|
||||
private int mBorderWidth = getResources().getInteger(R.integer.viewfinder_border_width);
|
||||
private int mBorderLength = getResources().getInteger(R.integer.viewfinder_border_length);
|
||||
private boolean mRoundedCorner = false;
|
||||
private int mCornerRadius = 0;
|
||||
private boolean mSquaredFinder = false;
|
||||
private float mBorderAlpha = 1.0f;
|
||||
private int mViewFinderOffset = 0;
|
||||
private float mAspectTolerance = 0.1f;
|
||||
|
||||
public BarcodeScannerView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BarcodeScannerView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(
|
||||
attributeSet,
|
||||
R.styleable.BarcodeScannerView,
|
||||
0, 0);
|
||||
|
||||
try {
|
||||
setShouldScaleToFill(a.getBoolean(R.styleable.BarcodeScannerView_shouldScaleToFill, true));
|
||||
mIsLaserEnabled = a.getBoolean(R.styleable.BarcodeScannerView_laserEnabled, mIsLaserEnabled);
|
||||
mLaserColor = a.getColor(R.styleable.BarcodeScannerView_laserColor, mLaserColor);
|
||||
mBorderColor = a.getColor(R.styleable.BarcodeScannerView_borderColor, mBorderColor);
|
||||
mMaskColor = a.getColor(R.styleable.BarcodeScannerView_maskColor, mMaskColor);
|
||||
mBorderWidth = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_borderWidth, mBorderWidth);
|
||||
mBorderLength = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_borderLength, mBorderLength);
|
||||
|
||||
mRoundedCorner = a.getBoolean(R.styleable.BarcodeScannerView_roundedCorner, mRoundedCorner);
|
||||
mCornerRadius = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_cornerRadius, mCornerRadius);
|
||||
mSquaredFinder = a.getBoolean(R.styleable.BarcodeScannerView_squaredFinder, mSquaredFinder);
|
||||
mBorderAlpha = a.getFloat(R.styleable.BarcodeScannerView_borderAlpha, mBorderAlpha);
|
||||
mViewFinderOffset = a.getDimensionPixelSize(R.styleable.BarcodeScannerView_finderOffset, mViewFinderOffset);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mViewFinderView = createViewFinderView(getContext());
|
||||
}
|
||||
|
||||
public final void setupLayout(CameraWrapper cameraWrapper) {
|
||||
removeAllViews();
|
||||
|
||||
mPreview = new CameraPreview(getContext(), cameraWrapper, this);
|
||||
mPreview.setAspectTolerance(mAspectTolerance);
|
||||
mPreview.setShouldScaleToFill(mShouldScaleToFill);
|
||||
if (!mShouldScaleToFill) {
|
||||
RelativeLayout relativeLayout = new RelativeLayout(getContext());
|
||||
relativeLayout.setGravity(Gravity.CENTER);
|
||||
relativeLayout.setBackgroundColor(Color.BLACK);
|
||||
relativeLayout.addView(mPreview);
|
||||
addView(relativeLayout);
|
||||
} else {
|
||||
addView(mPreview);
|
||||
}
|
||||
|
||||
if (mViewFinderView instanceof View) {
|
||||
addView((View) mViewFinderView);
|
||||
} else {
|
||||
throw new IllegalArgumentException("IViewFinder object returned by " +
|
||||
"'createViewFinderView()' should be instance of android.view.View");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Method that creates view that represents visual appearance of a barcode scanner</p>
|
||||
* <p>Override it to provide your own view for visual appearance of a barcode scanner</p>
|
||||
*
|
||||
* @param context {@link Context}
|
||||
* @return {@link android.view.View} that implements {@link ViewFinderView}
|
||||
*/
|
||||
protected IViewFinder createViewFinderView(Context context) {
|
||||
ViewFinderView viewFinderView = new ViewFinderView(context);
|
||||
viewFinderView.setBorderColor(mBorderColor);
|
||||
viewFinderView.setLaserColor(mLaserColor);
|
||||
viewFinderView.setLaserEnabled(mIsLaserEnabled);
|
||||
viewFinderView.setBorderStrokeWidth(mBorderWidth);
|
||||
viewFinderView.setBorderLineLength(mBorderLength);
|
||||
viewFinderView.setMaskColor(mMaskColor);
|
||||
|
||||
viewFinderView.setBorderCornerRounded(mRoundedCorner);
|
||||
viewFinderView.setBorderCornerRadius(mCornerRadius);
|
||||
viewFinderView.setSquareViewFinder(mSquaredFinder);
|
||||
viewFinderView.setViewFinderOffset(mViewFinderOffset);
|
||||
return viewFinderView;
|
||||
}
|
||||
|
||||
public void setLaserColor(int laserColor) {
|
||||
mLaserColor = laserColor;
|
||||
mViewFinderView.setLaserColor(mLaserColor);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setMaskColor(int maskColor) {
|
||||
mMaskColor = maskColor;
|
||||
mViewFinderView.setMaskColor(mMaskColor);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setBorderColor(int borderColor) {
|
||||
mBorderColor = borderColor;
|
||||
mViewFinderView.setBorderColor(mBorderColor);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setBorderStrokeWidth(int borderStrokeWidth) {
|
||||
mBorderWidth = borderStrokeWidth;
|
||||
mViewFinderView.setBorderStrokeWidth(mBorderWidth);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setBorderLineLength(int borderLineLength) {
|
||||
mBorderLength = borderLineLength;
|
||||
mViewFinderView.setBorderLineLength(mBorderLength);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setLaserEnabled(boolean isLaserEnabled) {
|
||||
mIsLaserEnabled = isLaserEnabled;
|
||||
mViewFinderView.setLaserEnabled(mIsLaserEnabled);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setIsBorderCornerRounded(boolean isBorderCornerRounded) {
|
||||
mRoundedCorner = isBorderCornerRounded;
|
||||
mViewFinderView.setBorderCornerRounded(mRoundedCorner);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setBorderCornerRadius(int borderCornerRadius) {
|
||||
mCornerRadius = borderCornerRadius;
|
||||
mViewFinderView.setBorderCornerRadius(mCornerRadius);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setSquareViewFinder(boolean isSquareViewFinder) {
|
||||
mSquaredFinder = isSquareViewFinder;
|
||||
mViewFinderView.setSquareViewFinder(mSquaredFinder);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
public void setBorderAlpha(float borderAlpha) {
|
||||
mBorderAlpha = borderAlpha;
|
||||
mViewFinderView.setBorderAlpha(mBorderAlpha);
|
||||
mViewFinderView.setupViewFinder();
|
||||
}
|
||||
|
||||
public void startCamera(int cameraId) {
|
||||
if(mCameraHandlerThread == null) {
|
||||
mCameraHandlerThread = new CameraHandlerThread(this);
|
||||
}
|
||||
mCameraHandlerThread.startCamera(cameraId);
|
||||
}
|
||||
|
||||
public void setupCameraPreview(CameraWrapper cameraWrapper) {
|
||||
mCameraWrapper = cameraWrapper;
|
||||
if(mCameraWrapper != null) {
|
||||
setupLayout(mCameraWrapper);
|
||||
mViewFinderView.setupViewFinder();
|
||||
if(mFlashState != null) {
|
||||
setFlash(mFlashState);
|
||||
}
|
||||
setAutoFocus(mAutofocusState);
|
||||
}
|
||||
}
|
||||
|
||||
public void startCamera() {
|
||||
startCamera(CameraUtils.getDefaultCameraId());
|
||||
}
|
||||
|
||||
public void stopCamera() {
|
||||
if(mCameraWrapper != null) {
|
||||
mPreview.stopCameraPreview();
|
||||
mPreview.setCamera(null, null);
|
||||
mCameraWrapper.mCamera.release();
|
||||
mCameraWrapper = null;
|
||||
}
|
||||
if(mCameraHandlerThread != null) {
|
||||
mCameraHandlerThread.quit();
|
||||
mCameraHandlerThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void stopCameraPreview() {
|
||||
if(mPreview != null) {
|
||||
mPreview.stopCameraPreview();
|
||||
}
|
||||
}
|
||||
|
||||
protected void resumeCameraPreview() {
|
||||
if(mPreview != null) {
|
||||
mPreview.showCameraPreview();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Rect getFramingRectInPreview(int previewWidth, int previewHeight) {
|
||||
if (mFramingRectInPreview == null) {
|
||||
Rect framingRect = mViewFinderView.getFramingRect();
|
||||
int viewFinderViewWidth = mViewFinderView.getWidth();
|
||||
int viewFinderViewHeight = mViewFinderView.getHeight();
|
||||
if (framingRect == null || viewFinderViewWidth == 0 || viewFinderViewHeight == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Rect rect = new Rect(framingRect);
|
||||
|
||||
if(previewWidth < viewFinderViewWidth) {
|
||||
rect.left = rect.left * previewWidth / viewFinderViewWidth;
|
||||
rect.right = rect.right * previewWidth / viewFinderViewWidth;
|
||||
}
|
||||
|
||||
if(previewHeight < viewFinderViewHeight) {
|
||||
rect.top = rect.top * previewHeight / viewFinderViewHeight;
|
||||
rect.bottom = rect.bottom * previewHeight / viewFinderViewHeight;
|
||||
}
|
||||
|
||||
mFramingRectInPreview = rect;
|
||||
}
|
||||
return mFramingRectInPreview;
|
||||
}
|
||||
|
||||
public void setFlash(boolean flag) {
|
||||
mFlashState = flag;
|
||||
if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) {
|
||||
|
||||
Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters();
|
||||
if(flag) {
|
||||
if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) {
|
||||
return;
|
||||
}
|
||||
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
|
||||
} else {
|
||||
if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_OFF)) {
|
||||
return;
|
||||
}
|
||||
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
|
||||
}
|
||||
mCameraWrapper.mCamera.setParameters(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getFlash() {
|
||||
if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) {
|
||||
Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters();
|
||||
if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void toggleFlash() {
|
||||
if(mCameraWrapper != null && CameraUtils.isFlashSupported(mCameraWrapper.mCamera)) {
|
||||
Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters();
|
||||
if(parameters.getFlashMode().equals(Camera.Parameters.FLASH_MODE_TORCH)) {
|
||||
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
|
||||
} else {
|
||||
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
|
||||
}
|
||||
mCameraWrapper.mCamera.setParameters(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoFocus(boolean state) {
|
||||
mAutofocusState = state;
|
||||
if(mPreview != null) {
|
||||
mPreview.setAutoFocus(state);
|
||||
}
|
||||
}
|
||||
|
||||
public void setShouldScaleToFill(boolean shouldScaleToFill) {
|
||||
mShouldScaleToFill = shouldScaleToFill;
|
||||
}
|
||||
|
||||
public void setAspectTolerance(float aspectTolerance) {
|
||||
mAspectTolerance = aspectTolerance;
|
||||
}
|
||||
|
||||
public byte[] getRotatedData(byte[] data, Camera camera) {
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
Camera.Size size = parameters.getPreviewSize();
|
||||
int width = size.width;
|
||||
int height = size.height;
|
||||
|
||||
int rotationCount = getRotationCount();
|
||||
|
||||
if(rotationCount == 1 || rotationCount == 3) {
|
||||
for (int i = 0; i < rotationCount; i++) {
|
||||
byte[] rotatedData = new byte[data.length];
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
rotatedData[x * height + height - y - 1] = data[x + y * width];
|
||||
}
|
||||
data = rotatedData;
|
||||
int tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public int getRotationCount() {
|
||||
int displayOrientation = mPreview.getDisplayOrientation();
|
||||
return displayOrientation / 90;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
|
||||
import android.hardware.Camera;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
|
||||
// This code is mostly based on the top answer here: http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes
|
||||
public class CameraHandlerThread extends HandlerThread {
|
||||
private static final String LOG_TAG = "CameraHandlerThread";
|
||||
|
||||
private BarcodeScannerView mScannerView;
|
||||
|
||||
public CameraHandlerThread(BarcodeScannerView scannerView) {
|
||||
super("CameraHandlerThread");
|
||||
mScannerView = scannerView;
|
||||
start();
|
||||
}
|
||||
|
||||
public void startCamera(final int cameraId) {
|
||||
Handler localHandler = new Handler(getLooper());
|
||||
localHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Camera camera = CameraUtils.getCameraInstance(cameraId);
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mScannerView.setupCameraPreview(CameraWrapper.getWrapper(camera, cameraId));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
312
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraPreview.java
vendored
Normal file
312
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraPreview.java
vendored
Normal file
|
@ -0,0 +1,312 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.Camera;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
|
||||
private static final String TAG = "CameraPreview";
|
||||
|
||||
private CameraWrapper mCameraWrapper;
|
||||
private Handler mAutoFocusHandler;
|
||||
private boolean mPreviewing = true;
|
||||
private boolean mAutoFocus = true;
|
||||
private boolean mSurfaceCreated = false;
|
||||
private boolean mShouldScaleToFill = true;
|
||||
private Camera.PreviewCallback mPreviewCallback;
|
||||
private float mAspectTolerance = 0.1f;
|
||||
|
||||
public CameraPreview(Context context, CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) {
|
||||
super(context);
|
||||
init(cameraWrapper, previewCallback);
|
||||
}
|
||||
|
||||
public CameraPreview(Context context, AttributeSet attrs, CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) {
|
||||
super(context, attrs);
|
||||
init(cameraWrapper, previewCallback);
|
||||
}
|
||||
|
||||
public void init(CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) {
|
||||
setCamera(cameraWrapper, previewCallback);
|
||||
mAutoFocusHandler = new Handler();
|
||||
getHolder().addCallback(this);
|
||||
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
}
|
||||
|
||||
public void setCamera(CameraWrapper cameraWrapper, Camera.PreviewCallback previewCallback) {
|
||||
mCameraWrapper = cameraWrapper;
|
||||
mPreviewCallback = previewCallback;
|
||||
}
|
||||
|
||||
public void setShouldScaleToFill(boolean scaleToFill) {
|
||||
mShouldScaleToFill = scaleToFill;
|
||||
}
|
||||
|
||||
public void setAspectTolerance(float aspectTolerance) {
|
||||
mAspectTolerance = aspectTolerance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder surfaceHolder) {
|
||||
mSurfaceCreated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
|
||||
if(surfaceHolder.getSurface() == null) {
|
||||
return;
|
||||
}
|
||||
stopCameraPreview();
|
||||
showCameraPreview();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
|
||||
mSurfaceCreated = false;
|
||||
stopCameraPreview();
|
||||
}
|
||||
|
||||
public void showCameraPreview() {
|
||||
if(mCameraWrapper != null) {
|
||||
try {
|
||||
getHolder().addCallback(this);
|
||||
mPreviewing = true;
|
||||
setupCameraParameters();
|
||||
mCameraWrapper.mCamera.setPreviewDisplay(getHolder());
|
||||
mCameraWrapper.mCamera.setDisplayOrientation(getDisplayOrientation());
|
||||
mCameraWrapper.mCamera.setOneShotPreviewCallback(mPreviewCallback);
|
||||
mCameraWrapper.mCamera.startPreview();
|
||||
if(mAutoFocus) {
|
||||
if (mSurfaceCreated) { // check if surface created before using autofocus
|
||||
safeAutoFocus();
|
||||
} else {
|
||||
scheduleAutoFocus(); // wait 1 sec and then do check again
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void safeAutoFocus() {
|
||||
try {
|
||||
mCameraWrapper.mCamera.autoFocus(autoFocusCB);
|
||||
} catch (RuntimeException re) {
|
||||
// Horrible hack to deal with autofocus errors on Sony devices
|
||||
// See https://github.com/dm77/barcodescanner/issues/7 for example
|
||||
scheduleAutoFocus(); // wait 1 sec and then do check again
|
||||
}
|
||||
}
|
||||
|
||||
public void stopCameraPreview() {
|
||||
if(mCameraWrapper != null) {
|
||||
try {
|
||||
mPreviewing = false;
|
||||
getHolder().removeCallback(this);
|
||||
mCameraWrapper.mCamera.cancelAutoFocus();
|
||||
mCameraWrapper.mCamera.setOneShotPreviewCallback(null);
|
||||
mCameraWrapper.mCamera.stopPreview();
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, e.toString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setupCameraParameters() {
|
||||
Camera.Size optimalSize = getOptimalPreviewSize();
|
||||
Camera.Parameters parameters = mCameraWrapper.mCamera.getParameters();
|
||||
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
|
||||
mCameraWrapper.mCamera.setParameters(parameters);
|
||||
adjustViewSize(optimalSize);
|
||||
}
|
||||
|
||||
private void adjustViewSize(Camera.Size cameraSize) {
|
||||
Point previewSize = convertSizeToLandscapeOrientation(new Point(getWidth(), getHeight()));
|
||||
float cameraRatio = ((float) cameraSize.width) / cameraSize.height;
|
||||
float screenRatio = ((float) previewSize.x) / previewSize.y;
|
||||
|
||||
if (screenRatio > cameraRatio) {
|
||||
setViewSize((int) (previewSize.y * cameraRatio), previewSize.y);
|
||||
} else {
|
||||
setViewSize(previewSize.x, (int) (previewSize.x / cameraRatio));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
private Point convertSizeToLandscapeOrientation(Point size) {
|
||||
if (getDisplayOrientation() % 180 == 0) {
|
||||
return size;
|
||||
} else {
|
||||
return new Point(size.y, size.x);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
private void setViewSize(int width, int height) {
|
||||
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
int tmpWidth;
|
||||
int tmpHeight;
|
||||
if (getDisplayOrientation() % 180 == 0) {
|
||||
tmpWidth = width;
|
||||
tmpHeight = height;
|
||||
} else {
|
||||
tmpWidth = height;
|
||||
tmpHeight = width;
|
||||
}
|
||||
|
||||
if (mShouldScaleToFill) {
|
||||
int parentWidth = ((View) getParent()).getWidth();
|
||||
int parentHeight = ((View) getParent()).getHeight();
|
||||
float ratioWidth = (float) parentWidth / (float) tmpWidth;
|
||||
float ratioHeight = (float) parentHeight / (float) tmpHeight;
|
||||
|
||||
float compensation;
|
||||
|
||||
if (ratioWidth > ratioHeight) {
|
||||
compensation = ratioWidth;
|
||||
} else {
|
||||
compensation = ratioHeight;
|
||||
}
|
||||
|
||||
tmpWidth = Math.round(tmpWidth * compensation);
|
||||
tmpHeight = Math.round(tmpHeight * compensation);
|
||||
}
|
||||
|
||||
layoutParams.width = tmpWidth;
|
||||
layoutParams.height = tmpHeight;
|
||||
setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
public int getDisplayOrientation() {
|
||||
if (mCameraWrapper == null) {
|
||||
//If we don't have a camera set there is no orientation so return dummy value
|
||||
return 0;
|
||||
}
|
||||
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
if(mCameraWrapper.mCameraId == -1) {
|
||||
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
|
||||
} else {
|
||||
Camera.getCameraInfo(mCameraWrapper.mCameraId, info);
|
||||
}
|
||||
|
||||
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
|
||||
int rotation = display.getRotation();
|
||||
int degrees = 0;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0: degrees = 0; break;
|
||||
case Surface.ROTATION_90: degrees = 90; break;
|
||||
case Surface.ROTATION_180: degrees = 180; break;
|
||||
case Surface.ROTATION_270: degrees = 270; break;
|
||||
}
|
||||
|
||||
int result;
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
result = (info.orientation + degrees) % 360;
|
||||
result = (360 - result) % 360; // compensate the mirror
|
||||
} else { // back-facing
|
||||
result = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Camera.Size getOptimalPreviewSize() {
|
||||
if(mCameraWrapper == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Camera.Size> sizes = mCameraWrapper.mCamera.getParameters().getSupportedPreviewSizes();
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
if (DisplayUtils.getScreenOrientation(getContext()) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
int portraitWidth = h;
|
||||
h = w;
|
||||
w = portraitWidth;
|
||||
}
|
||||
|
||||
double targetRatio = (double) w / h;
|
||||
if (sizes == null) return null;
|
||||
|
||||
Camera.Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
|
||||
int targetHeight = h;
|
||||
|
||||
// Try to find an size match aspect ratio and size
|
||||
for (Camera.Size size : sizes) {
|
||||
double ratio = (double) size.width / size.height;
|
||||
if (Math.abs(ratio - targetRatio) > mAspectTolerance) continue;
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot find the one match the aspect ratio, ignore the requirement
|
||||
if (optimalSize == null) {
|
||||
minDiff = Double.MAX_VALUE;
|
||||
for (Camera.Size size : sizes) {
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
return optimalSize;
|
||||
}
|
||||
|
||||
public void setAutoFocus(boolean state) {
|
||||
if(mCameraWrapper != null && mPreviewing) {
|
||||
if(state == mAutoFocus) {
|
||||
return;
|
||||
}
|
||||
mAutoFocus = state;
|
||||
if(mAutoFocus) {
|
||||
if (mSurfaceCreated) { // check if surface created before using autofocus
|
||||
Log.v(TAG, "Starting autofocus");
|
||||
safeAutoFocus();
|
||||
} else {
|
||||
scheduleAutoFocus(); // wait 1 sec and then do check again
|
||||
}
|
||||
} else {
|
||||
Log.v(TAG, "Cancelling autofocus");
|
||||
mCameraWrapper.mCamera.cancelAutoFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable doAutoFocus = new Runnable() {
|
||||
public void run() {
|
||||
if(mCameraWrapper != null && mPreviewing && mAutoFocus && mSurfaceCreated) {
|
||||
safeAutoFocus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Mimic continuous auto-focusing
|
||||
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
|
||||
public void onAutoFocus(boolean success, Camera camera) {
|
||||
scheduleAutoFocus();
|
||||
}
|
||||
};
|
||||
|
||||
private void scheduleAutoFocus() {
|
||||
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
|
||||
}
|
||||
}
|
63
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraUtils.java
vendored
Normal file
63
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraUtils.java
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CameraUtils {
|
||||
/** A safe way to get an instance of the Camera object. */
|
||||
public static Camera getCameraInstance() {
|
||||
return getCameraInstance(getDefaultCameraId());
|
||||
}
|
||||
|
||||
/** Favor back-facing camera by default. If none exists, fallback to whatever camera is available **/
|
||||
public static int getDefaultCameraId() {
|
||||
int numberOfCameras = Camera.getNumberOfCameras();
|
||||
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
||||
int defaultCameraId = -1;
|
||||
for (int i = 0; i < numberOfCameras; i++) {
|
||||
defaultCameraId = i;
|
||||
Camera.getCameraInfo(i, cameraInfo);
|
||||
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return defaultCameraId;
|
||||
}
|
||||
|
||||
/** A safe way to get an instance of the Camera object. */
|
||||
public static Camera getCameraInstance(int cameraId) {
|
||||
Camera c = null;
|
||||
try {
|
||||
if(cameraId == -1) {
|
||||
c = Camera.open(); // attempt to get a Camera instance
|
||||
} else {
|
||||
c = Camera.open(cameraId); // attempt to get a Camera instance
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Camera is not available (in use or does not exist)
|
||||
}
|
||||
return c; // returns null if camera is unavailable
|
||||
}
|
||||
|
||||
public static boolean isFlashSupported(Camera camera) {
|
||||
/* Credits: Top answer at http://stackoverflow.com/a/19599365/868173 */
|
||||
if (camera != null) {
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
|
||||
if (parameters.getFlashMode() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> supportedFlashModes = parameters.getSupportedFlashModes();
|
||||
if (supportedFlashModes == null || supportedFlashModes.isEmpty() || supportedFlashModes.size() == 1 && supportedFlashModes.get(0).equals(Camera.Parameters.FLASH_MODE_OFF)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
23
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java
vendored
Normal file
23
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.hardware.Camera;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class CameraWrapper {
|
||||
public final Camera mCamera;
|
||||
public final int mCameraId;
|
||||
|
||||
private CameraWrapper(@NonNull Camera camera, int cameraId) {
|
||||
this.mCamera = camera;
|
||||
this.mCameraId = cameraId;
|
||||
}
|
||||
|
||||
public static CameraWrapper getWrapper(Camera camera, int cameraId) {
|
||||
if (camera == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new CameraWrapper(camera, cameraId);
|
||||
}
|
||||
}
|
||||
}
|
41
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/DisplayUtils.java
vendored
Normal file
41
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/DisplayUtils.java
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
public class DisplayUtils {
|
||||
public static Point getScreenResolution(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
Point screenResolution = new Point();
|
||||
if (android.os.Build.VERSION.SDK_INT >= 13) {
|
||||
display.getSize(screenResolution);
|
||||
} else {
|
||||
screenResolution.set(display.getWidth(), display.getHeight());
|
||||
}
|
||||
|
||||
return screenResolution;
|
||||
}
|
||||
|
||||
public static int getScreenOrientation(Context context)
|
||||
{
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
|
||||
int orientation = Configuration.ORIENTATION_UNDEFINED;
|
||||
if(display.getWidth()==display.getHeight()){
|
||||
orientation = Configuration.ORIENTATION_SQUARE;
|
||||
} else{
|
||||
if(display.getWidth() < display.getHeight()){
|
||||
orientation = Configuration.ORIENTATION_PORTRAIT;
|
||||
}else {
|
||||
orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
}
|
||||
return orientation;
|
||||
}
|
||||
|
||||
}
|
53
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/IViewFinder.java
vendored
Normal file
53
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/IViewFinder.java
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
public interface IViewFinder {
|
||||
|
||||
void setLaserColor(int laserColor);
|
||||
void setMaskColor(int maskColor);
|
||||
void setBorderColor(int borderColor);
|
||||
void setBorderStrokeWidth(int borderStrokeWidth);
|
||||
void setBorderLineLength(int borderLineLength);
|
||||
void setLaserEnabled(boolean isLaserEnabled);
|
||||
|
||||
void setBorderCornerRounded(boolean isBorderCornersRounded);
|
||||
void setBorderAlpha(float alpha);
|
||||
void setBorderCornerRadius(int borderCornersRadius);
|
||||
void setViewFinderOffset(int offset);
|
||||
void setSquareViewFinder(boolean isSquareViewFinder);
|
||||
/**
|
||||
* Method that executes when Camera preview is starting.
|
||||
* It is recommended to update framing rect here and invalidate view after that. <br/>
|
||||
* For example see: {@link ViewFinderView#setupViewFinder()}
|
||||
*/
|
||||
void setupViewFinder();
|
||||
|
||||
/**
|
||||
* Provides {@link Rect} that identifies area where barcode scanner can detect visual codes
|
||||
* <p>Note: This rect is a area representation in absolute pixel values. <br/>
|
||||
* For example: <br/>
|
||||
* If View's size is 1024x800 so framing rect might be 500x400</p>
|
||||
*
|
||||
* @return {@link Rect} that identifies barcode scanner area
|
||||
*/
|
||||
Rect getFramingRect();
|
||||
|
||||
/**
|
||||
* Width of a {@link android.view.View} that implements this interface
|
||||
* <p>Note: this is already implemented in {@link android.view.View},
|
||||
* so you don't need to override method and provide your implementation</p>
|
||||
*
|
||||
* @return width of a view
|
||||
*/
|
||||
int getWidth();
|
||||
|
||||
/**
|
||||
* Height of a {@link android.view.View} that implements this interface
|
||||
* <p>Note: this is already implemented in {@link android.view.View},
|
||||
* so you don't need to override method and provide your implementation</p>
|
||||
*
|
||||
* @return height of a view
|
||||
*/
|
||||
int getHeight();
|
||||
}
|
259
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/ViewFinderView.java
vendored
Normal file
259
library/external/barcodescanner/core/src/main/java/me/dm7/barcodescanner/core/ViewFinderView.java
vendored
Normal file
|
@ -0,0 +1,259 @@
|
|||
package me.dm7.barcodescanner.core;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.CornerPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
public class ViewFinderView extends View implements IViewFinder {
|
||||
private static final String TAG = "ViewFinderView";
|
||||
|
||||
private Rect mFramingRect;
|
||||
|
||||
private static final float PORTRAIT_WIDTH_RATIO = 6f/8;
|
||||
private static final float PORTRAIT_WIDTH_HEIGHT_RATIO = 0.75f;
|
||||
|
||||
private static final float LANDSCAPE_HEIGHT_RATIO = 5f/8;
|
||||
private static final float LANDSCAPE_WIDTH_HEIGHT_RATIO = 1.4f;
|
||||
private static final int MIN_DIMENSION_DIFF = 50;
|
||||
|
||||
private static final float DEFAULT_SQUARE_DIMENSION_RATIO = 5f / 8;
|
||||
|
||||
private static final int[] SCANNER_ALPHA = {0, 64, 128, 192, 255, 192, 128, 64};
|
||||
private int scannerAlpha;
|
||||
private static final int POINT_SIZE = 10;
|
||||
private static final long ANIMATION_DELAY = 80l;
|
||||
|
||||
private final int mDefaultLaserColor = getResources().getColor(R.color.viewfinder_laser);
|
||||
private final int mDefaultMaskColor = getResources().getColor(R.color.viewfinder_mask);
|
||||
private final int mDefaultBorderColor = getResources().getColor(R.color.viewfinder_border);
|
||||
private final int mDefaultBorderStrokeWidth = getResources().getInteger(R.integer.viewfinder_border_width);
|
||||
private final int mDefaultBorderLineLength = getResources().getInteger(R.integer.viewfinder_border_length);
|
||||
|
||||
protected Paint mLaserPaint;
|
||||
protected Paint mFinderMaskPaint;
|
||||
protected Paint mBorderPaint;
|
||||
protected int mBorderLineLength;
|
||||
protected boolean mSquareViewFinder;
|
||||
private boolean mIsLaserEnabled;
|
||||
private float mBordersAlpha;
|
||||
private int mViewFinderOffset = 0;
|
||||
|
||||
public ViewFinderView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public ViewFinderView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
//set up laser paint
|
||||
mLaserPaint = new Paint();
|
||||
mLaserPaint.setColor(mDefaultLaserColor);
|
||||
mLaserPaint.setStyle(Paint.Style.FILL);
|
||||
|
||||
//finder mask paint
|
||||
mFinderMaskPaint = new Paint();
|
||||
mFinderMaskPaint.setColor(mDefaultMaskColor);
|
||||
|
||||
//border paint
|
||||
mBorderPaint = new Paint();
|
||||
mBorderPaint.setColor(mDefaultBorderColor);
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
mBorderPaint.setStrokeWidth(mDefaultBorderStrokeWidth);
|
||||
mBorderPaint.setAntiAlias(true);
|
||||
|
||||
mBorderLineLength = mDefaultBorderLineLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLaserColor(int laserColor) {
|
||||
mLaserPaint.setColor(laserColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaskColor(int maskColor) {
|
||||
mFinderMaskPaint.setColor(maskColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderColor(int borderColor) {
|
||||
mBorderPaint.setColor(borderColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderStrokeWidth(int borderStrokeWidth) {
|
||||
mBorderPaint.setStrokeWidth(borderStrokeWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderLineLength(int borderLineLength) {
|
||||
mBorderLineLength = borderLineLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLaserEnabled(boolean isLaserEnabled) { mIsLaserEnabled = isLaserEnabled; }
|
||||
|
||||
@Override
|
||||
public void setBorderCornerRounded(boolean isBorderCornersRounded) {
|
||||
if (isBorderCornersRounded) {
|
||||
mBorderPaint.setStrokeJoin(Paint.Join.ROUND);
|
||||
} else {
|
||||
mBorderPaint.setStrokeJoin(Paint.Join.BEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderAlpha(float alpha) {
|
||||
int colorAlpha = (int) (255 * alpha);
|
||||
mBordersAlpha = alpha;
|
||||
mBorderPaint.setAlpha(colorAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBorderCornerRadius(int borderCornersRadius) {
|
||||
mBorderPaint.setPathEffect(new CornerPathEffect(borderCornersRadius));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setViewFinderOffset(int offset) {
|
||||
mViewFinderOffset = offset;
|
||||
}
|
||||
|
||||
// TODO: Need a better way to configure this. Revisit when working on 2.0
|
||||
@Override
|
||||
public void setSquareViewFinder(boolean set) {
|
||||
mSquareViewFinder = set;
|
||||
}
|
||||
|
||||
public void setupViewFinder() {
|
||||
updateFramingRect();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public Rect getFramingRect() {
|
||||
return mFramingRect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
if(getFramingRect() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawViewFinderMask(canvas);
|
||||
drawViewFinderBorder(canvas);
|
||||
|
||||
if (mIsLaserEnabled) {
|
||||
drawLaser(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawViewFinderMask(Canvas canvas) {
|
||||
int width = canvas.getWidth();
|
||||
int height = canvas.getHeight();
|
||||
Rect framingRect = getFramingRect();
|
||||
|
||||
canvas.drawRect(0, 0, width, framingRect.top, mFinderMaskPaint);
|
||||
canvas.drawRect(0, framingRect.top, framingRect.left, framingRect.bottom + 1, mFinderMaskPaint);
|
||||
canvas.drawRect(framingRect.right + 1, framingRect.top, width, framingRect.bottom + 1, mFinderMaskPaint);
|
||||
canvas.drawRect(0, framingRect.bottom + 1, width, height, mFinderMaskPaint);
|
||||
}
|
||||
|
||||
public void drawViewFinderBorder(Canvas canvas) {
|
||||
Rect framingRect = getFramingRect();
|
||||
|
||||
// Top-left corner
|
||||
Path path = new Path();
|
||||
path.moveTo(framingRect.left, framingRect.top + mBorderLineLength);
|
||||
path.lineTo(framingRect.left, framingRect.top);
|
||||
path.lineTo(framingRect.left + mBorderLineLength, framingRect.top);
|
||||
canvas.drawPath(path, mBorderPaint);
|
||||
|
||||
// Top-right corner
|
||||
path.moveTo(framingRect.right, framingRect.top + mBorderLineLength);
|
||||
path.lineTo(framingRect.right, framingRect.top);
|
||||
path.lineTo(framingRect.right - mBorderLineLength, framingRect.top);
|
||||
canvas.drawPath(path, mBorderPaint);
|
||||
|
||||
// Bottom-right corner
|
||||
path.moveTo(framingRect.right, framingRect.bottom - mBorderLineLength);
|
||||
path.lineTo(framingRect.right, framingRect.bottom);
|
||||
path.lineTo(framingRect.right - mBorderLineLength, framingRect.bottom);
|
||||
canvas.drawPath(path, mBorderPaint);
|
||||
|
||||
// Bottom-left corner
|
||||
path.moveTo(framingRect.left, framingRect.bottom - mBorderLineLength);
|
||||
path.lineTo(framingRect.left, framingRect.bottom);
|
||||
path.lineTo(framingRect.left + mBorderLineLength, framingRect.bottom);
|
||||
canvas.drawPath(path, mBorderPaint);
|
||||
}
|
||||
|
||||
public void drawLaser(Canvas canvas) {
|
||||
Rect framingRect = getFramingRect();
|
||||
|
||||
// Draw a red "laser scanner" line through the middle to show decoding is active
|
||||
mLaserPaint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
|
||||
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
|
||||
int middle = framingRect.height() / 2 + framingRect.top;
|
||||
canvas.drawRect(framingRect.left + 2, middle - 1, framingRect.right - 1, middle + 2, mLaserPaint);
|
||||
|
||||
postInvalidateDelayed(ANIMATION_DELAY,
|
||||
framingRect.left - POINT_SIZE,
|
||||
framingRect.top - POINT_SIZE,
|
||||
framingRect.right + POINT_SIZE,
|
||||
framingRect.bottom + POINT_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
|
||||
updateFramingRect();
|
||||
}
|
||||
|
||||
public synchronized void updateFramingRect() {
|
||||
Point viewResolution = new Point(getWidth(), getHeight());
|
||||
int width;
|
||||
int height;
|
||||
int orientation = DisplayUtils.getScreenOrientation(getContext());
|
||||
|
||||
if(mSquareViewFinder) {
|
||||
if(orientation != Configuration.ORIENTATION_PORTRAIT) {
|
||||
height = (int) (getHeight() * DEFAULT_SQUARE_DIMENSION_RATIO);
|
||||
width = height;
|
||||
} else {
|
||||
width = (int) (getWidth() * DEFAULT_SQUARE_DIMENSION_RATIO);
|
||||
height = width;
|
||||
}
|
||||
} else {
|
||||
if(orientation != Configuration.ORIENTATION_PORTRAIT) {
|
||||
height = (int) (getHeight() * LANDSCAPE_HEIGHT_RATIO);
|
||||
width = (int) (LANDSCAPE_WIDTH_HEIGHT_RATIO * height);
|
||||
} else {
|
||||
width = (int) (getWidth() * PORTRAIT_WIDTH_RATIO);
|
||||
height = (int) (PORTRAIT_WIDTH_HEIGHT_RATIO * width);
|
||||
}
|
||||
}
|
||||
|
||||
if(width > getWidth()) {
|
||||
width = getWidth() - MIN_DIMENSION_DIFF;
|
||||
}
|
||||
|
||||
if(height > getHeight()) {
|
||||
height = getHeight() - MIN_DIMENSION_DIFF;
|
||||
}
|
||||
|
||||
int leftOffset = (viewResolution.x - width) / 2;
|
||||
int topOffset = (viewResolution.y - height) / 2;
|
||||
mFramingRect = new Rect(leftOffset + mViewFinderOffset, topOffset + mViewFinderOffset, leftOffset + width - mViewFinderOffset, topOffset + height - mViewFinderOffset);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="viewfinder_border_width">4</integer>
|
||||
<integer name="viewfinder_border_length">60</integer>
|
||||
</resources>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="viewfinder_border_width">5</integer>
|
||||
<integer name="viewfinder_border_length">80</integer>
|
||||
</resources>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="viewfinder_border_width">6</integer>
|
||||
<integer name="viewfinder_border_length">100</integer>
|
||||
</resources>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="BarcodeScannerView">
|
||||
<attr name="shouldScaleToFill" format="boolean" />
|
||||
<attr name="laserEnabled" format="boolean" />
|
||||
<attr name="laserColor" format="color" />
|
||||
<attr name="borderColor" format="color" />
|
||||
<attr name="maskColor" format="color" />
|
||||
<attr name="borderWidth" format="dimension" />
|
||||
<attr name="borderLength" format="dimension" />
|
||||
<attr name="roundedCorner" format="boolean" />
|
||||
<attr name="cornerRadius" format="dimension" />
|
||||
<attr name="squaredFinder" format="boolean" />
|
||||
<attr name="borderAlpha" format="float" />
|
||||
<attr name="finderOffset" format="dimension" />
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="viewfinder_mask">#60000000</color>
|
||||
<color name="viewfinder_laser">#ffcc0000</color>
|
||||
<color name="viewfinder_border">#ffafed44</color>
|
||||
</resources>
|
|
@ -0,0 +1,4 @@
|
|||
<resources>
|
||||
<integer name="viewfinder_border_width">4</integer>
|
||||
<integer name="viewfinder_border_length">60</integer>
|
||||
</resources>
|
|
@ -0,0 +1,29 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
namespace "me.dm7.barcodescanner.zxing"
|
||||
|
||||
compileSdk versions.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdk versions.minSdk
|
||||
targetSdk versions.targetSdk
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility versions.sourceCompat
|
||||
targetCompatibility versions.targetCompat
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(":library:external:barcodescanner:core")
|
||||
// Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170
|
||||
api 'com.google.zxing:core:3.3.3'
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.findAll { it.name.startsWith("lint") }.each {
|
||||
it.enabled = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
package me.dm7.barcodescanner.zxing;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.Camera;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.BinaryBitmap;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.LuminanceSource;
|
||||
import com.google.zxing.MultiFormatReader;
|
||||
import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.PlanarYUVLuminanceSource;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import me.dm7.barcodescanner.core.BarcodeScannerView;
|
||||
import me.dm7.barcodescanner.core.DisplayUtils;
|
||||
|
||||
public class ZXingScannerView extends BarcodeScannerView {
|
||||
private static final String TAG = "ZXingScannerView";
|
||||
|
||||
public interface ResultHandler {
|
||||
void handleResult(Result rawResult);
|
||||
}
|
||||
|
||||
private MultiFormatReader mMultiFormatReader;
|
||||
public static final List<BarcodeFormat> ALL_FORMATS = new ArrayList<>();
|
||||
private List<BarcodeFormat> mFormats;
|
||||
private ResultHandler mResultHandler;
|
||||
|
||||
static {
|
||||
ALL_FORMATS.add(BarcodeFormat.AZTEC);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODABAR);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_39);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_93);
|
||||
ALL_FORMATS.add(BarcodeFormat.CODE_128);
|
||||
ALL_FORMATS.add(BarcodeFormat.DATA_MATRIX);
|
||||
ALL_FORMATS.add(BarcodeFormat.EAN_8);
|
||||
ALL_FORMATS.add(BarcodeFormat.EAN_13);
|
||||
ALL_FORMATS.add(BarcodeFormat.ITF);
|
||||
ALL_FORMATS.add(BarcodeFormat.MAXICODE);
|
||||
ALL_FORMATS.add(BarcodeFormat.PDF_417);
|
||||
ALL_FORMATS.add(BarcodeFormat.QR_CODE);
|
||||
ALL_FORMATS.add(BarcodeFormat.RSS_14);
|
||||
ALL_FORMATS.add(BarcodeFormat.RSS_EXPANDED);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_A);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_E);
|
||||
ALL_FORMATS.add(BarcodeFormat.UPC_EAN_EXTENSION);
|
||||
}
|
||||
|
||||
public ZXingScannerView(Context context) {
|
||||
super(context);
|
||||
initMultiFormatReader();
|
||||
}
|
||||
|
||||
public ZXingScannerView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
initMultiFormatReader();
|
||||
}
|
||||
|
||||
public void setFormats(List<BarcodeFormat> formats) {
|
||||
mFormats = formats;
|
||||
initMultiFormatReader();
|
||||
}
|
||||
|
||||
public void setResultHandler(ResultHandler resultHandler) {
|
||||
mResultHandler = resultHandler;
|
||||
}
|
||||
|
||||
public Collection<BarcodeFormat> getFormats() {
|
||||
if(mFormats == null) {
|
||||
return ALL_FORMATS;
|
||||
}
|
||||
return mFormats;
|
||||
}
|
||||
|
||||
private void initMultiFormatReader() {
|
||||
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, getFormats());
|
||||
mMultiFormatReader = new MultiFormatReader();
|
||||
mMultiFormatReader.setHints(hints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPreviewFrame(byte[] data, Camera camera) {
|
||||
if(mResultHandler == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
Camera.Size size = parameters.getPreviewSize();
|
||||
int width = size.width;
|
||||
int height = size.height;
|
||||
|
||||
if (DisplayUtils.getScreenOrientation(getContext()) == Configuration.ORIENTATION_PORTRAIT) {
|
||||
int rotationCount = getRotationCount();
|
||||
if (rotationCount == 1 || rotationCount == 3) {
|
||||
int tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
data = getRotatedData(data, camera);
|
||||
}
|
||||
|
||||
Result rawResult = null;
|
||||
PlanarYUVLuminanceSource source = buildLuminanceSource(data, width, height);
|
||||
|
||||
if (source != null) {
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
try {
|
||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
||||
} catch (ReaderException re) {
|
||||
// continue
|
||||
} catch (NullPointerException npe) {
|
||||
// This is terrible
|
||||
} catch (ArrayIndexOutOfBoundsException aoe) {
|
||||
|
||||
} finally {
|
||||
mMultiFormatReader.reset();
|
||||
}
|
||||
|
||||
if (rawResult == null) {
|
||||
LuminanceSource invertedSource = source.invert();
|
||||
bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource));
|
||||
try {
|
||||
rawResult = mMultiFormatReader.decodeWithState(bitmap);
|
||||
} catch (NotFoundException e) {
|
||||
// continue
|
||||
} finally {
|
||||
mMultiFormatReader.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Result finalRawResult = rawResult;
|
||||
|
||||
if (finalRawResult != null) {
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Stopping the preview can take a little long.
|
||||
// So we want to set result handler to null to discard subsequent calls to
|
||||
// onPreviewFrame.
|
||||
ResultHandler tmpResultHandler = mResultHandler;
|
||||
mResultHandler = null;
|
||||
|
||||
stopCameraPreview();
|
||||
if (tmpResultHandler != null) {
|
||||
tmpResultHandler.handleResult(finalRawResult);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
camera.setOneShotPreviewCallback(this);
|
||||
}
|
||||
} catch(RuntimeException e) {
|
||||
// TODO: Terrible hack. It is possible that this method is invoked after camera is released.
|
||||
Log.e(TAG, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void resumeCameraPreview(ResultHandler resultHandler) {
|
||||
mResultHandler = resultHandler;
|
||||
super.resumeCameraPreview();
|
||||
}
|
||||
|
||||
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
|
||||
Rect rect = getFramingRectInPreview(width, height);
|
||||
if (rect == null) {
|
||||
return null;
|
||||
}
|
||||
// Go ahead and assume it's YUV rather than die.
|
||||
PlanarYUVLuminanceSource source = null;
|
||||
|
||||
try {
|
||||
source = new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
|
||||
rect.width(), rect.height(), false);
|
||||
} catch(Exception e) {
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@ include ':library:external:textdrawable'
|
|||
include ':library:external:autocomplete'
|
||||
include ':library:external:realmfieldnameshelper'
|
||||
include ':library:external:span'
|
||||
include ':library:external:barcodescanner:core'
|
||||
include ':library:external:barcodescanner:zxing'
|
||||
|
||||
include ':library:rustCrypto'
|
||||
include ':matrix-sdk-android'
|
||||
|
|
|
@ -263,11 +263,7 @@ dependencies {
|
|||
// Stick to 3.3.3 because of https://github.com/zxing/zxing/issues/1170
|
||||
implementation 'com.google.zxing:core:3.3.3'
|
||||
|
||||
// Excludes the legacy support library annotation usages
|
||||
// https://github.com/dm77/barcodescanner/blob/d036996c8a6f36a68843ffe539c834c28944b2d5/core/src/main/java/me/dm7/barcodescanner/core/CameraWrapper.java#L4
|
||||
implementation ('me.dm7.barcodescanner:zxing:1.9.13') {
|
||||
exclude group: 'com.android.support', module: 'support-v4'
|
||||
}
|
||||
implementation project(":library:external:barcodescanner:zxing")
|
||||
|
||||
// Emoji Keyboard
|
||||
api libs.vanniktech.emojiMaterial
|
||||
|
|
Loading…
Reference in New Issue