diff --git a/README.md b/README.md index 3b49346..caed2c6 100644 --- a/README.md +++ b/README.md @@ -194,8 +194,8 @@ CameraScan配置示例(只需识别二维码的配置示例) //初始化解码配置 DecodeConfig decodeConfig = new DecodeConfig(); decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高 - .setFullAreaScan(false)//设置是否全区域识别,默认true - .setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 + .setFullAreaScan(false)//设置是否全区域识别,默认false + .setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数 .setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数 @@ -239,6 +239,12 @@ compileOptions { ## 版本记录 +#### v2.0.1:2020-12-30 +* 更新CameraX至v1.0.0-rc01 +* 新增支持点击预览区域对焦目标 +* 修改一些默认配置 +* 优化细节 + #### v2.0.0:2020-12-24 * 基于CameraX进行重构 * 抽象整体流程,可扩展性更高 diff --git a/app/build.gradle b/app/build.gradle index 822d281..24f9be7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,9 +41,9 @@ dependencies { androidTestImplementation deps.test.runner androidTestImplementation deps.test.espresso - implementation deps.support.design - implementation deps.support.appcompat - implementation deps.support.constraintlayout + implementation deps.androidx.design + implementation deps.androidx.appcompat + implementation deps.androidx.constraintlayout implementation deps.kotlin implementation deps.corektx diff --git a/app/release/app-release.apk b/app/release/app-release.apk index 21911c6..dae458d 100644 Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ diff --git a/app/release/output.json b/app/release/output.json index a60f71c..9b59f61 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":27,"versionName":"2.0.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file +[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":28,"versionName":"2.0.1","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file diff --git a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java index c8ed883..4782e37 100644 --- a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java +++ b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java @@ -67,10 +67,10 @@ public class CustomCaptureActivity extends CaptureActivity { decodeConfig.setHints(DecodeFormatManager.ALL_HINTS)////设置解码 .setSupportVerticalCode(true)//设置是否支持扫垂直的条码 (增强识别率,相应的也会增加性能消耗) .setSupportLuminanceInvert(true)//设置是否支持识别反色码,黑白颜色反转(增强识别率,相应的也会增加性能消耗) -// .setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 + .setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 // .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数 // .setAreaRectHorizontalOffset(0)//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数 - .setFullAreaScan(true);//设置是否全区域识别,默认true + .setFullAreaScan(false);//设置是否全区域识别,默认false //获取CameraScan,里面有扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法,即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。 getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false diff --git a/app/src/main/java/com/king/zxing/app/QRCodeActivity.java b/app/src/main/java/com/king/zxing/app/QRCodeActivity.java index 221b14e..a60ab00 100644 --- a/app/src/main/java/com/king/zxing/app/QRCodeActivity.java +++ b/app/src/main/java/com/king/zxing/app/QRCodeActivity.java @@ -41,8 +41,8 @@ public class QRCodeActivity extends CaptureActivity { //初始化解码配置 DecodeConfig decodeConfig = new DecodeConfig(); decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高 - .setFullAreaScan(false)//设置是否全区域识别,默认true - .setAreaRectRatio(0.9f)//设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 + .setFullAreaScan(false)//设置是否全区域识别,默认false + .setAreaRectRatio(0.8f)//设置识别区域比例,默认0.8,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量,默认为0,为0表示居中,可以为负数 .setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量,默认为0,为0表示居中,可以为负数 diff --git a/lib/build.gradle b/lib/build.gradle index a1d708b..35ff9d9 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -42,7 +42,7 @@ dependencies { androidTestImplementation deps.test.runner androidTestImplementation deps.test.espresso - api deps.support.appcompat + compileOnly deps.androidx.appcompat api deps.zxing api deps.camera_core api deps.camera_camera2 diff --git a/lib/src/main/java/com/king/zxing/DecodeConfig.java b/lib/src/main/java/com/king/zxing/DecodeConfig.java index 9f5094e..e714839 100644 --- a/lib/src/main/java/com/king/zxing/DecodeConfig.java +++ b/lib/src/main/java/com/king/zxing/DecodeConfig.java @@ -44,6 +44,8 @@ public class DecodeConfig { private Map hints = DecodeFormatManager.DEFAULT_HINTS; + public static final float DEFAULT_AREA_RECT_RATIO = 0.8f; + /** * 是否支持使用多解码 */ @@ -74,12 +76,12 @@ public class DecodeConfig { /** * 是否支持全区域扫码识别 */ - private boolean isFullAreaScan = true; + private boolean isFullAreaScan = false; /** - * 识别区域比例,默认0.9 + * 识别区域比例,默认0.8 */ - private float areaRectRatio = 0.9f; + private float areaRectRatio = DEFAULT_AREA_RECT_RATIO; /** * 识别区域垂直方向偏移量 */ diff --git a/lib/src/main/java/com/king/zxing/DefaultCameraScan.java b/lib/src/main/java/com/king/zxing/DefaultCameraScan.java index 7f702ed..973ea79 100644 --- a/lib/src/main/java/com/king/zxing/DefaultCameraScan.java +++ b/lib/src/main/java/com/king/zxing/DefaultCameraScan.java @@ -1,16 +1,21 @@ package com.king.zxing; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.util.DisplayMetrics; +import android.util.Size; +import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; +import android.view.ViewConfiguration; import com.google.common.util.concurrent.ListenableFuture; import com.google.zxing.BarcodeFormat; import com.google.zxing.Result; import com.google.zxing.ResultPoint; +import com.google.zxing.common.detector.MathUtils; import com.king.zxing.analyze.Analyzer; import com.king.zxing.analyze.MultiFormatAnalyzer; import com.king.zxing.util.LogUtils; @@ -21,7 +26,9 @@ import androidx.annotation.FloatRange; import androidx.annotation.Nullable; import androidx.camera.core.Camera; import androidx.camera.core.CameraSelector; +import androidx.camera.core.FocusMeteringAction; import androidx.camera.core.ImageAnalysis; +import androidx.camera.core.MeteringPoint; import androidx.camera.core.Preview; import androidx.camera.core.TorchState; import androidx.camera.core.ZoomState; @@ -38,6 +45,20 @@ import androidx.lifecycle.MutableLiveData; */ public class DefaultCameraScan extends CameraScan { + /** + * Defines the maximum duration in milliseconds between a touch pad + * touch and release for a given touch to be considered a tap (click) as + * opposed to a hover movement gesture. + */ + private static final int HOVER_TAP_TIMEOUT = 150; + + /** + * Defines the maximum distance in pixels that a touch pad touch can move + * before being released for it to be considered a tap (click) as opposed + * to a hover movement gesture. + */ + private static final int HOVER_TAP_SLOP = 20; + private FragmentActivity mFragmentActivity; private Context mContext; private LifecycleOwner mLifecycleOwner; @@ -68,9 +89,14 @@ public class DefaultCameraScan extends CameraScan { private BeepManager mBeepManager; private AmbientLightManager mAmbientLightManager; + private int mOrientation; private int mScreenWidth; private int mScreenHeight; private long mLastAutoZoomTime; + private long mLastHoveTapTime; + private boolean isClickTap; + private float mDownX; + private float mDownY; public DefaultCameraScan(FragmentActivity activity, PreviewView previewView){ this.mFragmentActivity = activity; @@ -107,8 +133,10 @@ public class DefaultCameraScan extends CameraScan { handleAnalyzeResult(result); }); + mOrientation = mContext.getResources().getConfiguration().orientation; ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener); mPreviewView.setOnTouchListener((v, event) -> { + handlePreviewViewClickTap(event); if(isNeedTouchZoom()){ return scaleGestureDetector.onTouchEvent(event); } @@ -139,6 +167,37 @@ public class DefaultCameraScan extends CameraScan { } } + private void handlePreviewViewClickTap(MotionEvent event){ + if(event.getPointerCount() == 1){ + switch (event.getAction()){ + case MotionEvent.ACTION_DOWN: + isClickTap = true; + mDownX = event.getX(); + mDownY = event.getY(); + mLastHoveTapTime = System.currentTimeMillis(); + break; + case MotionEvent.ACTION_MOVE: + isClickTap = MathUtils.distance(mDownX,mDownY,event.getX(),event.getY()) < HOVER_TAP_SLOP; + break; + case MotionEvent.ACTION_UP: + if(isClickTap && mLastHoveTapTime + HOVER_TAP_TIMEOUT > System.currentTimeMillis()){ + startFocusAndMetering(event.getX(),event.getY()); + } + break; + } + } + } + + private void startFocusAndMetering(float x, float y){ + if(mCamera != null){ + LogUtils.d("startFocusAndMetering:" + x + "," + y); + MeteringPoint point = mPreviewView.getMeteringPointFactory().createPoint(x,y); + mCamera.getCameraControl().startFocusAndMetering(new FocusMeteringAction.Builder(point).build()); + } + } + + + private void initConfig(){ if(mCameraConfig == null){ mCameraConfig = new CameraConfig(); @@ -148,6 +207,7 @@ public class DefaultCameraScan extends CameraScan { } } + @Override public CameraScan setCameraConfig(CameraConfig cameraConfig) { if(cameraConfig != null){ @@ -176,7 +236,7 @@ public class DefaultCameraScan extends CameraScan { .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)); imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), image -> { if(isAnalyze && !isAnalyzeResult && mAnalyzer != null){ - Result result = mAnalyzer.analyze(image); + Result result = mAnalyzer.analyze(image,mOrientation); if(result != null){ mResultLiveData.postValue(result); } diff --git a/lib/src/main/java/com/king/zxing/analyze/Analyzer.java b/lib/src/main/java/com/king/zxing/analyze/Analyzer.java index 57490bd..69c9484 100644 --- a/lib/src/main/java/com/king/zxing/analyze/Analyzer.java +++ b/lib/src/main/java/com/king/zxing/analyze/Analyzer.java @@ -5,6 +5,7 @@ import com.google.zxing.Result; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.camera.core.ImageProxy; +import android.content.res.Configuration; /** * 分析器 @@ -12,6 +13,12 @@ import androidx.camera.core.ImageProxy; */ public interface Analyzer { + /** + * Analyzes an image to produce a result. + * @param image The image to analyze + * @param orientation {@link Configuration#ORIENTATION_LANDSCAPE}, {@link Configuration#ORIENTATION_PORTRAIT}. + * @return + */ @Nullable - Result analyze(@NonNull ImageProxy image); + Result analyze(@NonNull ImageProxy image,int orientation); } diff --git a/lib/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java b/lib/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java index 1c4a57a..8a6e0ff 100644 --- a/lib/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java +++ b/lib/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java @@ -19,12 +19,18 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer { DecodeConfig mDecodeConfig; Map mHints; boolean isMultiDecode = true; + private float mAreaRectRatio = DecodeConfig.DEFAULT_AREA_RECT_RATIO; + private int mAreaRectHorizontalOffset = 0; + private int mAreaRectVerticalOffset = 0; public AreaRectAnalyzer(@Nullable DecodeConfig config){ this.mDecodeConfig = config; if(config != null){ mHints = config.getHints(); isMultiDecode = config.isMultiDecode(); + mAreaRectRatio = config.getAreaRectRatio(); + mAreaRectHorizontalOffset = config.getAreaRectHorizontalOffset(); + mAreaRectVerticalOffset = config.getAreaRectVerticalOffset(); }else{ mHints = DecodeFormatManager.DEFAULT_HINTS; } @@ -34,19 +40,22 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer { @Nullable @Override public Result analyze(byte[] data, int width, int height) { - if(mDecodeConfig == null || mDecodeConfig.isFullAreaScan()){ - //mDecodeConfig为空或者支持全区域扫码识别时,直接使用全区域进行扫码识别 - return analyze(data,width,height,0,0,width,height); + if(mDecodeConfig != null){ + if(mDecodeConfig.isFullAreaScan()){ + //mDecodeConfig为空或者支持全区域扫码识别时,直接使用全区域进行扫码识别 + return analyze(data,width,height,0,0,width,height); + } + + Rect rect = mDecodeConfig.getAnalyzeAreaRect(); + if(rect != null){//如果分析区域不为空,则使用指定的区域进行扫码识别 + return analyze(data,width,height,rect.left,rect.top,rect.width(),rect.height()); + } } - Rect rect = mDecodeConfig.getAnalyzeAreaRect(); - if(rect != null){//如果分析区域不为空,则使用指定的区域进行扫码识别 - return analyze(data,width,height,rect.left,rect.top,rect.width(),rect.height()); - } //如果分析区域为空,则通过识别区域比例和相关的偏移量计算出最终的区域进行扫码识别 - int size = (int)(Math.min(width,height) * mDecodeConfig.getAreaRectRatio()); - int left = (width-size)/2 + mDecodeConfig.getAreaRectHorizontalOffset(); - int top = (height-size)/2 + mDecodeConfig.getAreaRectVerticalOffset(); + int size = (int)(Math.min(width,height) * mAreaRectRatio); + int left = (width-size)/2 + mAreaRectHorizontalOffset; + int top = (height-size)/2 + mAreaRectVerticalOffset; return analyze(data,width,height,left,top,size,size); diff --git a/lib/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java b/lib/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java index a269eb6..4d9c521 100644 --- a/lib/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java +++ b/lib/src/main/java/com/king/zxing/analyze/BarcodeFormatAnalyzer.java @@ -48,9 +48,10 @@ public abstract class BarcodeFormatAnalyzer extends AreaRectAnalyzer { if(rawResult == null && mDecodeConfig != null){ if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){ 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]; + for (int y = 0; y < dataHeight; y++) { + for (int x = 0; x < dataWidth; x++){ + rotatedData[x * dataHeight + dataHeight - y - 1] = data[x + y * dataWidth]; + } } rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData,dataHeight,dataWidth,top,left,height,width,false),mDecodeConfig.isSupportVerticalCodeMultiDecode()); } diff --git a/lib/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java b/lib/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java index 76ff570..e57f2e0 100644 --- a/lib/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java +++ b/lib/src/main/java/com/king/zxing/analyze/ImageAnalyzer.java @@ -1,6 +1,7 @@ package com.king.zxing.analyze; import android.annotation.SuppressLint; +import android.content.res.Configuration; import android.graphics.ImageFormat; import com.google.zxing.Result; @@ -28,13 +29,24 @@ public abstract class ImageAnalyzer implements Analyzer { public abstract Result analyze(byte[] data, int width, int height); @Override - public Result analyze(@NonNull ImageProxy image) { + public Result analyze(@NonNull ImageProxy image,int orientation) { if(image.getFormat() == ImageFormat.YUV_420_888){ @SuppressLint("UnsafeExperimentalUsageError") ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); - return analyze(data,image.getWidth(),image.getHeight()); + int width = image.getWidth(); + int height = image.getHeight(); + if(orientation == Configuration.ORIENTATION_PORTRAIT){ + 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]; + } + } + return analyze(rotatedData,height,width); + } + return analyze(data,width,height); } LogUtils.w("imageFormat: " + image.getFormat()); return null; diff --git a/lib/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java b/lib/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java index 567f18b..a4a792e 100644 --- a/lib/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java +++ b/lib/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java @@ -54,8 +54,9 @@ public class MultiFormatAnalyzer extends AreaRectAnalyzer { if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){ byte[] rotatedData = new byte[data.length]; for (int y = 0; y < dataHeight; y++) { - for (int x = 0; x < dataWidth; x++) + for (int x = 0; x < dataWidth; x++){ rotatedData[x * dataHeight + dataHeight - y - 1] = data[x + y * dataWidth]; + } } rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData,dataHeight,dataWidth,top,left,height,width,false),mDecodeConfig.isSupportVerticalCodeMultiDecode()); } diff --git a/versions.gradle b/versions.gradle index df9f18c..98fcd97 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,7 +1,7 @@ //App def app_version = [:] -app_version.versionCode = 27 -app_version.versionName = "2.0.0" +app_version.versionCode = 28 +app_version.versionName = "2.0.1" ext.app_version = app_version //build version @@ -35,18 +35,18 @@ versions.coreKtx = "1.3.2" //zxing versions.zxing = "3.3.0" -versions.camerax = "1.0.0-beta12" +versions.camerax = "1.0.0-rc01" versions.easypermissions = "3.0.0" ext.versions = versions -//support -def support = [:] -support.design = "com.google.android.material:material:$versions.material" -support.appcompat = "androidx.appcompat:appcompat:$versions.appcompat" -support.constraintlayout = "androidx.constraintlayout:constraintlayout:$versions.constraintLayout" -deps.support = support +//androidx +def androidx = [:] +androidx.design = "com.google.android.material:material:$versions.material" +androidx.appcompat = "androidx.appcompat:appcompat:$versions.appcompat" +androidx.constraintlayout = "androidx.constraintlayout:constraintlayout:$versions.constraintLayout" +deps.androidx = androidx //test def test = [:]