diff --git a/README.md b/README.md index 64f5c81..d11a4d8 100644 --- a/README.md +++ b/README.md @@ -24,35 +24,44 @@ ZXingLite for Android 是ZXing的精简极速版,基于ZXing库优化扫码和 ## ViewfinderView属性说明 -| 属性 | 值类型 | 默认值 | 说明 | -| :------| :------ | :------ | :------ | -| maskColor | color |#60000000| 扫描区外遮罩的颜色 | -| frameColor | color |#7F1FB3E2| 扫描区边框的颜色 | -| cornerColor | color |#FF1FB3E2| 扫描区边角的颜色 | -| laserColor | color |#FF1FB3E2| 扫描区激光线的颜色 | -| labelText | string | | 扫描提示文本信息 | -| labelTextColor | color |#FFC0C0C0| 提示文本字体颜色 | + +| 属性 | 属性类型 | 默认值 | 属性说明 | +| :------|:----------| :------ | :------ | +| maskColor | color |#60000000| 扫描区外遮罩的颜色 | +| frameColor | color |#7F1FB3E2| 扫描区边框的颜色 | +| cornerColor | color |#FF1FB3E2| 扫描区边角的颜色 | +| laserColor | color |#FF1FB3E2| 扫描区激光线的颜色 | +| labelText | string | | 扫描提示文本信息 | +| labelTextColor | color |#FFC0C0C0| 提示文本字体颜色 | | labelTextSize | dimension |14sp| 提示文本字体大小 | | labelTextPadding | dimension |24dp| 提示文本距离扫描区的间距 | | labelTextWidth | dimension | | 提示文本的宽度,默认为View的宽度 | -| labelTextLocation | enum |bottom| 提示文本显示位置 | +| labelTextLocation | enum |bottom| 提示文本显示位置 | | frameWidth | dimension | | 扫码框宽度 | | frameHeight | dimension | | 扫码框高度 | -| laserStyle | enum | line | 扫描激光的样式 | -| gridColumn | integer | 20 | 网格扫描激光列数 | -| gridHeight | integer | 40dp | 网格扫描激光高度,为0dp时,表示动态铺满 | +| laserStyle | enum | line | 扫描激光的样式 | +| gridColumn | integer | 20 | 网格扫描激光列数 | +| gridHeight | integer | 40dp | 网格扫描激光高度,为0dp时,表示动态铺满 | | cornerRectWidth | dimension | 4dp | 扫描区边角的宽 | | cornerRectHeight | dimension | 16dp | 扫描区边角的高 | | scannerLineMoveDistance | dimension | 2dp | 扫描线每次移动距离 | | scannerLineHeight | dimension | 5dp | 扫描线高度 | | frameLineWidth | dimension | 1dp | 边框线宽度 | -| scannerAnimationDelay | integer | 20 | 扫描动画延迟间隔时间,单位:毫秒 | -| frameRatio | float | 0.625f | 扫码框与屏幕占比 | +| scannerAnimationDelay | integer | 20 | 扫描动画延迟间隔时间,单位:毫秒 | +| frameRatio | float | 0.625f | 扫码框与屏幕占比 | | framePaddingLeft | dimension | 0 | 扫码框左边的内间距 | | framePaddingTop | dimension | 0 | 扫码框上边的内间距 | | framePaddingRight | dimension | 0 | 扫码框右边的内间距 | | framePaddingBottom | dimension | 0 | 扫码框下边的内间距 | -| frameGravity | enum | center | 扫码框对齐方式 | +| frameGravity | enum | center | 扫码框对齐方式 | +| pointColor | color | #FF1FB3E2 | 结果点的颜色 | +| pointStrokeColor | color | #FFFFFFFF | 结果点描边的颜色 | +| pointRadius | dimension | 15dp | 结果点的半径 | +| pointStrokeRatio | float | 1.2 | 结果点描边半径与结果点半径的比例 | +| pointDrawable | reference | | 结果点自定义图片 | +| showPointAnim | boolean | true | 是否显示结果点的动画 | +| laserDrawable | reference | | 扫描激光自定义图片 | +| viewfinderStyle | enum | classic | 取景框样式;支持:classic:经典样式(带扫码框那种)、popular:流行样式(不带扫码框) | ## 引入 @@ -73,8 +82,8 @@ allprojects { 2. 在Module的 **build.gradle** 里面添加引入依赖项 ```gradle -//AndroidX 版本 -implementation 'com.github.jenly1314:zxing-lite:2.3.0' +// AndroidX 版本 +implementation 'com.github.jenly1314:zxing-lite:2.3.1' ``` @@ -89,81 +98,75 @@ implementation 'com.github.jenly1314:zxing-lite:2.3.0' **v1.x** 旧版本 [v1.1.9](https://github.com/jenly1314/ZXingLite/tree/androidx) ```gradle -//AndroidX 版本 +// AndroidX 版本 implementation 'com.king.zxing:zxing-lite:1.1.9-androidx' -//Android Support 版本 +// Android Support 版本 implementation 'com.king.zxing:zxing-lite:1.1.9' ``` +## 使用说明 -### 快速实现扫码有以下几种方式: +### 快速实现扫码识别有以下几种方式: -> 1、直接使用CaptureActivity或者CaptureFragment。(纯洁的扫码,无任何添加剂) +> 1、直接使用CaptureActivity或者CaptureFragment。(默认的扫码实现) > 2、通过继承CaptureActivity或者CaptureFragment并自定义布局。(适用于大多场景,并无需关心扫码相关逻辑,自定义布局时需覆写getLayoutId方法)实现示例:[CustomCaptureActivity](app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java) 和 [QRCodeActivity](app/src/main/java/com/king/zxing/app/QRCodeActivity.java) -> 3、在你项目的Activity或者Fragment中实例化一个CameraScan即可。(适用于想在扫码界面写交互逻辑,又因为项目架构或其它原因,无法直接或间接继承CaptureActivity或CaptureFragment时使用)实现示例:[CustomActivity](app/src/main/java/com/king/zxing/app/CustomActivity.java) +> 3、在你项目的Activity或者Fragment中实例化一个CameraScan即可。(适用于想在扫码界面写交互逻辑,又因为项目架构或其它原因,无法直接或间接继承CaptureActivity或CaptureFragment时使用)实现示例:[CustomFullScanActivity](app/src/main/java/com/king/zxing/app/CustomFullScanActivity.java) > 4、继承CameraScan自己实现一个,可参照默认实现类DefaultCameraScan,其它步骤同方式3。(扩展高级用法,谨慎使用) +### 关于 CameraScan -## 示例 +**CameraScan** 作为相机扫描的(核心)基类;所有与相机扫描相关的都是基于此类来直接或间接进行控制的。 -布局示例 -> 可自定义布局(覆写getLayoutId方法),布局内至少要保证有PreviewView。 +### 关于 CameraConfig -> PreviewView 用来预览,布局内至少要保证有PreviewView,如果是继承CaptureActivity或CaptureFragment,控件id可覆写getPreviewViewId方法自定义 +主要是相机相关的配置;如:摄像头的前置后置、相机预览相关、图像分析相关等配置。 -> ViewfinderView 用来渲染扫码视图,给用户起到一个视觉效果,本身扫码识别本身没有关系,如果是继承CaptureActivity或CaptureFragment,控件id可复写getViewfinderViewId方法自定义,默认为previewView,返回0表示无需ViewfinderView +> 你可以直接库中内置实现的相机配置: **CameraConfig** 、**AspectRatioCameraConfig** 和 **ResolutionCameraConfig**。 -> ivFlashlight 用来内置手电筒,如果是继承CaptureActivity或CaptureFragment,控件id可复写getFlashlightId方法自定义,默认为ivFlashlight。返回0表示无需内置手电筒。您也可以自己去定义 +#### 这里简单说下各自的特点: +* **CameraConfig**:默认的相机配置。 +* **AspectRatioCameraConfig**:根据纵横比配置相机,使输出分析的图像尽可能的接近屏幕的比例 +* **ResolutionCameraConfig**:根据尺寸配置相机的目标图像大小,使输出分析的图像的分辨率尽可能的接近屏幕尺寸 -```Xml - - - - - -``` +> 你也可以自定义或覆写 **CameraConfig** 中的 **options** 方法,根据需要定制配置。 -或在你的布局中添加 +这里特别温馨提示:默认配置在未配置相机的目标分析图像大小时,会优先使用:横屏:640 * 480 竖屏:480 * 640; -```Xml - -``` +根据这个图像质量顺便说下默认配置的优缺点: -代码示例 (二维码/条形码) -```Java - //跳转的默认扫码界面 - startActivityForResult(new Intent(context,CaptureActivity.class),requestCode); +* 优点:因为图像质量不高,所以在低配置的设备上使用也能hold住,这样就能尽可能的适应各种设备; +* 缺点:正是由于图像质量不高,从而可能会对检测识别率略有影响,比如在某些机型上体验欠佳。 +* 结论:在适配、性能与体验之间得有所取舍,找到平衡点。 - //生成二维码 - CodeUtils.createQRCode(content,600,logo); - //生成条形码 - CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200); - //解析条形码/二维码 - CodeUtils.parseCode(bitmap); - //解析二维码 - CodeUtils.parseQRCode(bitmap); -``` +> 当使用默认的 **CameraConfig** 在某些机型上体验欠佳时,你可以尝试使用 **AspectRatioCameraConfig** 或 +**ResolutionCameraConfig** 会有意想不到奇效。 + +### 关于 **Analyzer** + +**Analyzer** 为定义的分析器接口;主要用于分析相机预览的帧数据;通过实现 **Analyzer** 可以自定义分析过程。 + +### 关于 **CaptureActivity** 和 **CaptureFragment** + +**CaptureActivity** 和 **CaptureFragment** 作为扫描预览界面的基类,主要目的是便于快速实现扫码识别。 + +> 扫描预览界面内部持有 **CameraScan**,并处理了 **CameraScan** 的初始化(如:相机权限、相机预览、生命周期等细节) + +## 使用示例 + +### CameraScan配置示例 + +**CameraScan** 里面包含部分支持链式调用的方法,即调用返回是 **CameraScan** 本身的一些配置建议在调用 **startCamera()** 方法之前调用。 + +> 如果是通过继承 **CaptureActivity** 或者 **CaptureFragment** 或其子类实现的相机扫描,可以在 +**initCameraScan()** 方法中获取 **CameraScan** ,然后根据需要修改相关配置。 + +示例1: -CameraScan配置示例 ```java //获取CameraScan,扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法,即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。 getCameraScan().setPlayBeep(true)//设置是否播放音效,默认为false @@ -176,16 +179,17 @@ CameraScan配置示例 .bindFlashlightView(ivFlashlight)//绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒按钮 .setOnScanResultCallback(this)//设置扫码结果回调,需要自己处理或者需要连扫时,可设置回调,自己去处理相关逻辑 .setAnalyzer(new MultiFormatAnalyzer(new DecodeConfig()))//设置分析器,DecodeConfig可以配置一些解码时的配置信息,如果内置的不满足您的需求,你也可以自定义实现, - .setAnalyzeImage(true)//设置是否分析图片,默认为true。如果设置为false,相当于关闭了扫码识别功能 - .startCamera();//启动预览(如果是通过继承CaptureActivity或CaptureFragment实现扫码无需调用这句startCamera) + .setAnalyzeImage(true);//设置是否分析图片,默认为true。如果设置为false,相当于关闭了扫码识别功能 + + // 启动预览(如果是通过继承CaptureActivity或CaptureFragment实现的则无需调用startCamera) + getCameraScan().startCamera(); - - //设置闪光灯(手电筒)是否开启,需在startCamera之后调用才有效 + // 设置闪光灯(手电筒)是否开启,需在startCamera之后调用才有效 getCameraScan().enableTorch(torch); ``` -CameraScan配置示例(只需识别二维码的配置示例) +示例2:(只需识别二维码的配置示例) ```java //初始化解码配置 DecodeConfig decodeConfig = new DecodeConfig(); @@ -201,7 +205,65 @@ CameraScan配置示例(只需识别二维码的配置示例) .setAnalyzer(new MultiFormatAnalyzer(decodeConfig));//设置分析器,如果内置实现的一些分析器不满足您的需求,你也可以自定义去实现 ``` -通过继承CaptureActivity实现扫二维码完整示例 +### 布局示例 + +**PreviewView** 用来预览,布局内至少要保证有 **PreviewView**,如果是继承 **CaptureActivity** 或 **CaptureFragment**,控件id可覆写`getPreviewViewId`方法自定义 + +**ViewfinderView** 用来渲染扫码视图,给用户起到一个视觉效果,本身扫码识别本身没有关系,如果是继承 **CaptureActivity** 或 **CaptureFragment**,控件ID可复写`getViewfinderViewId`方法自定义,默认为 **previewView**,返回0表示无需 **ViewfinderView** + +**ivFlashlight** 是布局内置的手电筒,如果是继承 **CaptureActivity** 或 **CaptureFragment**,控件id可复写`getFlashlightId`方法自定义,默认为 **ivFlashlight**。返回0表示无需内置手电筒。您也可以自己去定义 + +> 可自定义布局(覆写`getLayoutId方法`),布局内至少要保证有 **PreviewView**。 + +```Xml + + + + + + + + +``` + +或在你的布局中添加 + +```Xml + +``` + +### 代码示例 + +**工具类CodeUtils的使用示例(二维码/条形码)** +```Java + + // 生成二维码 + CodeUtils.createQRCode(content,600,logo); + // 生成条形码 + CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200); + // 解析条形码/二维码 + CodeUtils.parseCode(bitmap); + // 解析二维码 + CodeUtils.parseQRCode(bitmap); +``` + +**通过继承CaptureActivity实现扫二维码完整示例** + ```java public class QRCodeActivity extends CaptureActivity { @@ -259,16 +321,19 @@ public class QRCodeActivity extends CaptureActivity { ``` -如果直接使用CaptureActivity需在您项目的AndroidManifest中添加如下配置 + +### 其他 + +#### AndroidManifest + +如果你直接使用了默认 **CaptureActivity** ,则需在你项目的AndroidManifest中注册 **CaptureActivity**,配置如下 ```Xml ``` - - -### 其他 +#### JDK版本 需使用JDK8+编译,在你项目中的build.gradle的android{}中添加配置: @@ -290,7 +355,7 @@ compileOptions { ## 版本说明 -### v2.x 基于CameraX重构震撼发布 +### v2.x 基于CameraX进行了重构 #### v2.x 相对于 v1.x 的优势 @@ -304,7 +369,7 @@ compileOptions { #### v1.x 说明 -[【v1.1.9】](https://github.com/jenly1314/ZXingLite/tree/androidx) 如果您正在使用 **1.x** 版本请点击下面的链接查看分支版本,当前 **2.x** 版本已经基于 **CameraX** 进行重构,不支持升级,请在新项目中使用。 +[【v1.1.9】](https://github.com/jenly1314/ZXingLite/tree/androidx) 如果您正在使用 **1.x** 版本请点击下面的链接查看分支版本,当前 **2.x** 版本已经基于 **CameraX** 进行重构,API变化较大,谨慎升级。 查看AndroidX版 **1.x** 分支 [请戳此处](https://github.com/jenly1314/ZXingLite/tree/androidx) @@ -314,6 +379,11 @@ compileOptions { ## 版本记录 +#### v2.3.1:2023-3-4 +* 更新CameraX至v1.2.1 +* 更新Gradle至v7.5 +* 优化细节 + #### v2.3.0:2022-12-11 * 更新CameraX至v1.2.0 * 更新zxing至v3.5.1 diff --git a/app/build.gradle b/app/build.gradle index 0e355f0..20e0d52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,8 +26,8 @@ android { compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } // kotlinOptions { diff --git a/app/release/app-release.apk b/app/release/app-release.apk index fabd9cf..a2a3f8e 100644 Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 5b47a73..962452f 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,8 +11,8 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 35, - "versionName": "2.3.0", + "versionCode": 36, + "versionName": "2.3.1", "outputFile": "app-release.apk" } ], diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 211a7fc..bf02d13 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -44,7 +44,7 @@ android:theme="@style/CaptureTheme"/> 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 17c8e1d..9744cce 100644 --- a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java +++ b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java @@ -22,7 +22,6 @@ import android.widget.Toast; import com.google.zxing.Result; import com.king.zxing.CameraScan; -import com.king.zxing.config.CameraConfig; import com.king.zxing.CaptureActivity; import com.king.zxing.DecodeConfig; import com.king.zxing.DecodeFormatManager; @@ -121,8 +120,8 @@ public class CustomCaptureActivity extends CaptureActivity { if(toast == null){ toast = Toast.makeText(this,text,Toast.LENGTH_SHORT); }else{ - toast.setDuration(Toast.LENGTH_SHORT); toast.setText(text); + toast.setDuration(Toast.LENGTH_SHORT); } toast.show(); } diff --git a/app/src/main/java/com/king/zxing/app/CustomActivity.java b/app/src/main/java/com/king/zxing/app/CustomFullScanActivity.java similarity index 77% rename from app/src/main/java/com/king/zxing/app/CustomActivity.java rename to app/src/main/java/com/king/zxing/app/CustomFullScanActivity.java index 85d5753..dd77a50 100644 --- a/app/src/main/java/com/king/zxing/app/CustomActivity.java +++ b/app/src/main/java/com/king/zxing/app/CustomFullScanActivity.java @@ -8,9 +8,13 @@ import android.widget.Toast; import com.google.zxing.Result; import com.king.zxing.CameraScan; +import com.king.zxing.DecodeConfig; +import com.king.zxing.DecodeFormatManager; import com.king.zxing.DefaultCameraScan; import com.king.zxing.ViewfinderView; +import com.king.zxing.analyze.MultiFormatAnalyzer; import com.king.zxing.app.util.StatusBarUtils; +import com.king.zxing.config.ResolutionCameraConfig; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; @@ -22,7 +26,7 @@ import androidx.fragment.app.Fragment; * 自定义扫码,切记自定义扫码需在{@link Activity}或者{@link Fragment}相对应的生命周期里面调用{@link #mCameraScan}对应的生命周期 * @author Jenly */ -public class CustomActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback { +public class CustomFullScanActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback { private boolean isContinuousScan; @@ -59,9 +63,16 @@ public class CustomActivity extends AppCompatActivity implements CameraScan.OnSc isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false); + //初始化解码配置 + DecodeConfig decodeConfig = new DecodeConfig(); + decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高,不设置默认为DecodeFormatManager.DEFAULT_HINTS + .setFullAreaScan(true);//设置是否全区域识别,默认false + mCameraScan = new DefaultCameraScan(this,previewView); mCameraScan.setOnScanResultCallback(this) + .setAnalyzer(new MultiFormatAnalyzer(decodeConfig)) .setVibrate(true) + .setCameraConfig(new ResolutionCameraConfig(this, ResolutionCameraConfig.IMAGE_QUALITY_720P)) .startCamera(); } diff --git a/app/src/main/java/com/king/zxing/app/MainActivity.java b/app/src/main/java/com/king/zxing/app/MainActivity.java index 93efcf6..6ffdeae 100644 --- a/app/src/main/java/com/king/zxing/app/MainActivity.java +++ b/app/src/main/java/com/king/zxing/app/MainActivity.java @@ -31,7 +31,6 @@ import com.king.zxing.util.CodeUtils; import com.king.zxing.util.LogUtils; -import java.io.IOException; import java.util.List; import androidx.appcompat.app.AppCompatActivity; @@ -43,9 +42,9 @@ import pub.devrel.easypermissions.EasyPermissions; /** * 扫码Demo示例说明 * - * 快速实现扫码有以下几种方式: + * 快速实现扫码识别有以下几种方式: * - * 1、直接使用CaptureActivity或者CaptureFragment。(纯洁的扫码,无任何添加剂) + * 1、直接使用CaptureActivity或者CaptureFragment。(默认的扫码实现) * * 2、通过继承CaptureActivity或者CaptureFragment并自定义布局。(适用于大多场景,并无需关心扫码相关逻辑,自定义布局时需覆写getLayoutId方法) * @@ -108,13 +107,6 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P } private void parsePhoto(Intent data){ - -// final String path = UriUtils.getImagePath(this,data); -// LogUtils.d("path:" + path); -// if(TextUtils.isEmpty(path)){ -// return; -// } - try { Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),data.getData()); //异步解析 @@ -243,7 +235,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P checkCameraPermissions(); break; case R.id.btn4: - this.cls = CustomActivity.class; + this.cls = CustomFullScanActivity.class; this.title = ((Button)v).getText().toString(); checkCameraPermissions(); break; 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 18ce0be..7643f6c 100644 --- a/app/src/main/java/com/king/zxing/app/QRCodeActivity.java +++ b/app/src/main/java/com/king/zxing/app/QRCodeActivity.java @@ -11,6 +11,7 @@ import com.king.zxing.DecodeConfig; import com.king.zxing.DecodeFormatManager; import com.king.zxing.analyze.MultiFormatAnalyzer; import com.king.zxing.app.util.StatusBarUtils; +import com.king.zxing.config.AspectRatioCameraConfig; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; @@ -50,8 +51,8 @@ public class QRCodeActivity extends CaptureActivity { //在启动预览之前,设置分析器,只识别二维码 getCameraScan() + .setCameraConfig(new AspectRatioCameraConfig(this))//设置相机配置,使用 AspectRatioCameraConfig .setVibrate(true)//设置是否震动,默认为false - .setNeedAutoZoom(true)//二维码太小时可自动缩放,默认为false .setAnalyzer(new MultiFormatAnalyzer(decodeConfig));//设置分析器,如果内置实现的一些分析器不满足您的需求,你也可以自定义去实现 } diff --git a/app/src/main/res/drawable-xxhdpi/flash_off.png b/app/src/main/res/drawable-xxhdpi/flash_off.png deleted file mode 100644 index 0aa92fe..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/flash_off.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/flash_on.png b/app/src/main/res/drawable-xxhdpi/flash_on.png deleted file mode 100644 index bc321fe..0000000 Binary files a/app/src/main/res/drawable-xxhdpi/flash_on.png and /dev/null differ diff --git a/app/src/main/res/drawable/flash_selected_selector.xml b/app/src/main/res/drawable/flash_selected_selector.xml deleted file mode 100644 index 45f9caf..0000000 --- a/app/src/main/res/drawable/flash_selected_selector.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index e905d87..e60378b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -87,7 +87,7 @@ android:layout_marginRight="20dp" android:layout_marginTop="6dp" android:layout_marginBottom="6dp" - android:text="自定义扫码" + android:text="自定义全屏扫二维码" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/btn3" diff --git a/app/src/main/res/layout/custom_activity.xml b/app/src/main/res/layout/custom_activity.xml index 771b958..abad373 100644 --- a/app/src/main/res/layout/custom_activity.xml +++ b/app/src/main/res/layout/custom_activity.xml @@ -13,24 +13,16 @@ android:id="@+id/viewfinderView" android:layout_width="match_parent" android:layout_height="match_parent" - app:labelTextWidth="180dp" - app:labelText="@string/tips_scan_code" - app:labelTextSize="@dimen/size_14sp" - app:laserColor="@color/colorAccent" - app:frameColor="@color/colorPrimary" - app:cornerColor="@color/colorPrimary" - app:labelTextLocation="bottom" - app:laserStyle="grid" - app:gridHeight="0dp"/> + app:viewfinderStyle="popular"/> + android:layout_marginTop="170dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/custom_capture_activity.xml b/app/src/main/res/layout/custom_capture_activity.xml index 75aa57d..e3d4d28 100644 --- a/app/src/main/res/layout/custom_capture_activity.xml +++ b/app/src/main/res/layout/custom_capture_activity.xml @@ -24,11 +24,11 @@ android:id="@+id/ivFlashlight" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/flash_selected_selector" + android:src="@drawable/zxl_flashlight_selector" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginTop="160dp" /> + android:layout_marginTop="170dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/qr_code_activity.xml b/app/src/main/res/layout/qr_code_activity.xml index ea0af26..3d4d8d8 100644 --- a/app/src/main/res/layout/qr_code_activity.xml +++ b/app/src/main/res/layout/qr_code_activity.xml @@ -24,11 +24,11 @@ android:id="@+id/ivFlashlight" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@drawable/flash_selected_selector" + android:src="@drawable/zxl_flashlight_selector" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginTop="160dp" /> + android:layout_marginTop="170dp" /> \ No newline at end of file diff --git a/app/src/main/res/values-v19/dimens.xml b/app/src/main/res/values-v19/dimens.xml deleted file mode 100644 index 554c79e..0000000 --- a/app/src/main/res/values-v19/dimens.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 25dp - \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8678a22..3eca2a5 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,6 +1,6 @@ - 0dp + 25dp 50dp diff --git a/build.gradle b/build.gradle index fd7429c..7b0e6f4 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,6 @@ buildscript { repositories { google() - maven { url 'https://maven.aliyun.com/repository/public/' } mavenCentral() } @@ -24,9 +23,7 @@ buildscript { allprojects { repositories { google() - maven { url 'https://maven.aliyun.com/repository/public/' } mavenCentral() -// jcenter() // Warning: this repository is going to shut down soon } } diff --git a/change_log.md b/change_log.md index 08583d7..ffb6bf2 100644 --- a/change_log.md +++ b/change_log.md @@ -1,5 +1,10 @@ ## 版本记录 +#### v2.3.1:2023-3-4 +* 更新CameraX至v1.2.1 +* 更新Gradle至v7.5 +* 优化细节 + #### v2.3.0:2022-12-11 * 更新CameraX至v1.2.0 * 更新zxing至v3.5.1 @@ -20,6 +25,7 @@ #### v2.1.0:2021-6-30 (从v2.1.0开始不再发布至JCenter) * 更新CameraX至v1.0.0 * 优化细节 +* 发布至MavenCentral #### v2.0.3:2021-3-26 * 更新CameraX至v1.0.0-rc03 diff --git a/gradle.properties b/gradle.properties index 7abbfc5..00ba57b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,8 +14,8 @@ org.gradle.jvmargs = -Xmx1536m android.useAndroidX=true android.enableJetifier=true -VERSION_NAME=2.3.0 -VERSION_CODE=35 +VERSION_NAME=2.3.1 +VERSION_CODE=36 GROUP=com.github.jenly1314 POM_DESCRIPTION=ZXingLite for Android @@ -43,3 +43,5 @@ RELEASE_SIGNING_ENABLED=false + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6e7a18d..4fc80b3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip diff --git a/versions.gradle b/versions.gradle index 7c06ec6..a373438 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,7 +1,7 @@ //App def app_version = [:] -app_version.versionCode = 35 -app_version.versionName = "2.3.0" +app_version.versionCode = 36 +app_version.versionName = "2.3.1" ext.app_version = app_version //build version @@ -29,14 +29,14 @@ versions.espresso = "3.2.0" versions.bintray_release = "0.9.2" versions.mavenPublish = '0.18.0' -versions.gralde = "7.1.1" +versions.gralde = "7.4.1" versions.kotlin = "1.6.0" versions.coreKtx = "1.6.0" //zxing versions.zxing = "3.5.1" -versions.camerax = "1.2.0" +versions.camerax = "1.2.1" versions.easypermissions = "3.0.0" diff --git a/zxing-lite/build.gradle b/zxing-lite/build.gradle index beeedb8..199c004 100644 --- a/zxing-lite/build.gradle +++ b/zxing-lite/build.gradle @@ -27,8 +27,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } } diff --git a/zxing-lite/src/main/java/com/king/zxing/CameraScan.java b/zxing-lite/src/main/java/com/king/zxing/CameraScan.java index bd6e3ae..a1c616d 100644 --- a/zxing-lite/src/main/java/com/king/zxing/CameraScan.java +++ b/zxing-lite/src/main/java/com/king/zxing/CameraScan.java @@ -16,18 +16,36 @@ import androidx.annotation.Nullable; import androidx.camera.core.CameraSelector; /** + * 相机扫描基类定义;内置的默认实现见:{@link DefaultCameraScan} + *

+ * 快速实现扫描识别主要有以下几种方式: + *

+ * 1、通过继承 {@link CaptureActivity}或者{@link CaptureFragment}或其子类,可快速实现扫描识别。 + * (适用于大多数场景,自定义布局时需覆写getLayoutId方法) + *

+ * 2、在你项目的Activity或者Fragment中实例化一个{@link DefaultCameraScan}。(适用于想在扫码界面写交互逻辑,又因为项目 + * 架构或其它原因,无法直接或间接继承{@link CaptureActivity}或{@link CaptureFragment}时使用) + *

+ * 3、继承{@link CameraScan}自己实现一个,可参照默认实现类{@link DefaultCameraScan},其他步骤同方式2。(高级用法,谨慎使用) + * * @author Jenly */ -public abstract class CameraScan implements ICamera,ICameraControl { +public abstract class CameraScan implements ICamera, ICameraControl { + /** + * 扫描返回结果的key;解析方式可参见:{@link #parseScanResult(Intent)} + */ public static String SCAN_RESULT = "SCAN_RESULT"; - /** A camera on the device facing the same direction as the device's screen. */ + /** + * A camera on the device facing the same direction as the device's screen. + */ public static int LENS_FACING_FRONT = CameraSelector.LENS_FACING_FRONT; - /** A camera on the device facing the opposite direction as the device's screen. */ + /** + * A camera on the device facing the opposite direction as the device's screen. + */ public static int LENS_FACING_BACK = CameraSelector.LENS_FACING_BACK; - /** * 是否需要支持自动缩放 */ @@ -40,15 +58,16 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 是否需要支持触摸缩放 + * * @return */ protected boolean isNeedTouchZoom() { return isNeedTouchZoom; } - /** * 设置是否需要支持触摸缩放 + * * @param needTouchZoom * @return */ @@ -59,6 +78,7 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 是否需要支持自动缩放 + * * @return */ protected boolean isNeedAutoZoom() { @@ -67,6 +87,7 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 设置是否需要支持自动缩放 + * * @param needAutoZoom * @return */ @@ -77,19 +98,21 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 设置相机配置,请在{@link #startCamera()}之前调用 + * * @param cameraConfig */ public abstract CameraScan setCameraConfig(CameraConfig cameraConfig); /** * 设置是否分析图像,通过此方法可以动态控制是否分析图像,常用于中断扫码识别。如:连扫时,扫到结果,然后停止分析图像 - * + *

* 1. 因为分析图像默认为true,如果想支持连扫,在{@link OnScanResultCallback#onScanResultCallback(Result)}返回true拦截即可。 * 当连扫的处理逻辑比较复杂时,请在处理逻辑前通过调用setAnalyzeImage(false)来停止分析图像, * 等逻辑处理完后再调用getCameraScan().setAnalyzeImage(true)来继续分析图像。 - * + *

* 2. 如果只是想拦截扫码结果回调自己处理逻辑,但并不想继续分析图像(即不想连扫),可通过 * 调用getCameraScan().setAnalyzeImage(false)来停止分析图像。 + * * @param analyze */ public abstract CameraScan setAnalyzeImage(boolean analyze); @@ -97,72 +120,77 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 设置分析器,如果内置的一些分析器不满足您的需求,你也可以自定义{@link Analyzer}, * 自定义时,切记需在{@link #startCamera()}之前调用才有效。 - * + *

* 内置了一些{@link Analyzer}的实现类如下: + * + * @param analyzer * @see {@link MultiFormatAnalyzer} * @see {@link AreaRectAnalyzer} * @see {@link ImageAnalyzer} - * * @see {@link BarcodeFormatAnalyzer} * @see {@link QRCodeReader} - * - * @param analyzer */ public abstract CameraScan setAnalyzer(Analyzer analyzer); /** * 设置是否震动 + * * @param vibrate */ public abstract CameraScan setVibrate(boolean vibrate); /** * 设置是否播放提示音 + * * @param playBeep */ public abstract CameraScan setPlayBeep(boolean playBeep); /** * 设置扫码结果回调 + * * @param callback */ public abstract CameraScan setOnScanResultCallback(OnScanResultCallback callback); /** * 绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒 + * * @param v */ public abstract CameraScan bindFlashlightView(@Nullable View v); /** * 设置光线足够暗的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效 + * * @param lightLux */ public abstract CameraScan setDarkLightLux(float lightLux); /** * 设置光线足够明亮的阈值(单位:lux),需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效 + * * @param lightLux */ public abstract CameraScan setBrightLightLux(float lightLux); - public interface OnScanResultCallback{ + public interface OnScanResultCallback { /** * 扫码结果回调 + * * @param result * @return 返回false表示不拦截,将关闭扫码界面并将结果返回给调用界面; - * 返回true表示拦截,需自己处理逻辑。当isAnalyze为true时,默认会继续分析图像(也就是连扫)。 - * 如果只是想拦截扫码结果回调,并不想继续分析图像(不想连扫),请在拦截扫码逻辑处通过调 - * 用{@link CameraScan#setAnalyzeImage(boolean)}, - * 因为{@link CameraScan#setAnalyzeImage(boolean)}方法能动态控制是否继续分析图像。 - * + * 返回true表示拦截,需自己处理逻辑。当isAnalyze为true时,默认会继续分析图像(也就是连扫)。 + * 如果只是想拦截扫码结果回调,并不想继续分析图像(不想连扫),请在拦截扫码逻辑处通过调 + * 用{@link CameraScan#setAnalyzeImage(boolean)}, + * 因为{@link CameraScan#setAnalyzeImage(boolean)}方法能动态控制是否继续分析图像。 */ boolean onScanResultCallback(Result result); /** * 扫码结果识别失败时触发此回调方法 */ - default void onScanResultFailure(){ + default void onScanResultFailure() { } @@ -170,12 +198,13 @@ public abstract class CameraScan implements ICamera,ICameraControl { /** * 解析扫码结果 + * * @param data * @return */ @Nullable - public static String parseScanResult(Intent data){ - if(data != null){ + public static String parseScanResult(Intent data) { + if (data != null) { return data.getStringExtra(SCAN_RESULT); } return null; diff --git a/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java b/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java index 9c413d1..99bb782 100644 --- a/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java +++ b/zxing-lite/src/main/java/com/king/zxing/CaptureActivity.java @@ -29,9 +29,21 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.camera.view.PreviewView; /** + * 相机扫描基类;{@link CaptureActivity} 内部持有{@link CameraScan},便于快速实现扫描识别。 + *

+ * 快速实现扫描识别主要有以下几种方式: + *

+ * 1、通过继承 {@link CaptureActivity}或者{@link CaptureFragment}或其子类,可快速实现扫描识别。 + * (适用于大多数场景,自定义布局时需覆写getLayoutId方法) + *

+ * 2、在你项目的Activity或者Fragment中实例化一个{@link DefaultCameraScan}。(适用于想在扫码界面写交互逻辑,又因为项目 + * 架构或其它原因,无法直接或间接继承{@link CaptureActivity}或{@link CaptureFragment}时使用) + *

+ * 3、继承{@link CameraScan}自己实现一个,可参照默认实现类{@link DefaultCameraScan},其他步骤同方式2。(高级用法,谨慎使用) + * * @author Jenly */ -public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback{ +public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback { private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86; @@ -44,7 +56,7 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if(isContentView()){ + if (isContentView()) { setContentView(getLayoutId()); } initUI(); @@ -53,16 +65,16 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS /** * 初始化 */ - public void initUI(){ + public void initUI() { previewView = findViewById(getPreviewViewId()); int viewfinderViewId = getViewfinderViewId(); - if(viewfinderViewId != 0){ + if (viewfinderViewId != 0) { viewfinderView = findViewById(viewfinderViewId); } int ivFlashlightId = getFlashlightId(); - if(ivFlashlightId != 0){ + if (ivFlashlightId != 0) { ivFlashlight = findViewById(ivFlashlightId); - if(ivFlashlight != null){ + if (ivFlashlight != null) { ivFlashlight.setOnClickListener(v -> onClickFlashlight()); } } @@ -73,39 +85,37 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS /** * 点击手电筒 */ - protected void onClickFlashlight(){ + protected void onClickFlashlight() { toggleTorchState(); } /** * 初始化CameraScan */ - public void initCameraScan(){ - mCameraScan = new DefaultCameraScan(this,previewView); + public void initCameraScan() { + mCameraScan = new DefaultCameraScan(this, previewView); mCameraScan.setOnScanResultCallback(this); } - /** * 启动相机预览 */ - public void startCamera(){ - if(mCameraScan != null){ - if(PermissionUtils.checkPermission(this,Manifest.permission.CAMERA)){ + public void startCamera() { + if (mCameraScan != null) { + if (PermissionUtils.checkPermission(this, Manifest.permission.CAMERA)) { mCameraScan.startCamera(); - }else{ + } else { LogUtils.d("checkPermissionResult != PERMISSION_GRANTED"); - PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE); + PermissionUtils.requestPermission(this, Manifest.permission.CAMERA, CAMERA_PERMISSION_REQUEST_CODE); } } } - /** * 释放相机 */ - private void releaseCamera(){ - if(mCameraScan != null){ + private void releaseCamera() { + if (mCameraScan != null) { mCameraScan.release(); } } @@ -113,11 +123,11 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS /** * 切换闪光灯状态(开启/关闭) */ - protected void toggleTorchState(){ - if(mCameraScan != null){ + protected void toggleTorchState() { + if (mCameraScan != null) { boolean isTorch = mCameraScan.isTorchEnabled(); mCameraScan.enableTorch(!isTorch); - if(ivFlashlight != null){ + if (ivFlashlight != null) { ivFlashlight.setSelected(!isTorch); } } @@ -126,20 +136,21 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if(requestCode == CAMERA_PERMISSION_REQUEST_CODE){ - requestCameraPermissionResult(permissions,grantResults); + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { + requestCameraPermissionResult(permissions, grantResults); } } /** * 请求Camera权限回调结果 + * * @param permissions * @param grantResults */ - public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){ - if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){ + public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) { + if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) { startCamera(); - }else{ + } else { finish(); } } @@ -152,55 +163,62 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS /** * 返回true时会自动初始化{@link #setContentView(int)},返回为false是需自己去初始化{@link #setContentView(int)} + * * @return 默认返回true */ - public boolean isContentView(){ + public boolean isContentView() { return true; } /** - * 布局id + * 布局ID;通过覆写此方法可以自定义布局 + * * @return */ - public int getLayoutId(){ + public int getLayoutId() { return R.layout.zxl_capture; } /** * {@link #viewfinderView} 的 ID + * * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回0 */ - public int getViewfinderViewId(){ + public int getViewfinderViewId() { return R.id.viewfinderView; } /** * 预览界面{@link #previewView} 的ID + * * @return */ - public int getPreviewViewId(){ + public int getPreviewViewId() { return R.id.previewView; } /** * 获取 {@link #ivFlashlight} 的ID - * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 + * + * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 */ - public int getFlashlightId(){ + public int getFlashlightId() { return R.id.ivFlashlight; } /** * Get {@link CameraScan} + * * @return {@link #mCameraScan} */ - public CameraScan getCameraScan(){ + public CameraScan getCameraScan() { return mCameraScan; } /** * 接收扫码结果回调 + * * @param result 扫码结果 * @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截 */ diff --git a/zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java b/zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java index 5eaa9c9..462fb97 100644 --- a/zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java +++ b/zxing-lite/src/main/java/com/king/zxing/CaptureFragment.java @@ -30,6 +30,18 @@ import androidx.camera.view.PreviewView; import androidx.fragment.app.Fragment; /** + * 相机扫描基类;{@link CaptureFragment} 内部持有{@link CameraScan},便于快速实现扫描识别。 + *

+ * 快速实现扫描识别主要有以下几种方式: + *

+ * 1、通过继承 {@link CaptureActivity}或者{@link CaptureFragment}或其子类,可快速实现扫描识别。 + * (适用于大多数场景,自定义布局时需覆写getLayoutId方法) + *

+ * 2、在你项目的Activity或者Fragment中实例化一个{@link DefaultCameraScan}。(适用于想在扫码界面写交互逻辑,又因为项目 + * 架构或其它原因,无法直接或间接继承{@link CaptureActivity}或{@link CaptureFragment}时使用) + *

+ * 3、继承{@link CameraScan}自己实现一个,可参照默认实现类{@link DefaultCameraScan},其他步骤同方式2。(高级用法,谨慎使用) + * * @author Jenly */ public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback { @@ -53,11 +65,10 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult return fragment; } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if(isContentView()){ - mRootView = createRootView(inflater,container); + if (isContentView()) { + mRootView = createRootView(inflater, container); } initUI(); return mRootView; @@ -66,16 +77,16 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult /** * 初始化 */ - public void initUI(){ + public void initUI() { previewView = mRootView.findViewById(getPreviewViewId()); int viewfinderViewId = getViewfinderViewId(); - if(viewfinderViewId != 0){ + if (viewfinderViewId != 0) { viewfinderView = mRootView.findViewById(viewfinderViewId); } int ivFlashlightId = getFlashlightId(); - if(ivFlashlightId != 0){ + if (ivFlashlightId != 0) { ivFlashlight = mRootView.findViewById(ivFlashlightId); - if(ivFlashlight != null){ + if (ivFlashlight != null) { ivFlashlight.setOnClickListener(v -> onClickFlashlight()); } } @@ -86,28 +97,28 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult /** * 点击手电筒 */ - protected void onClickFlashlight(){ + protected void onClickFlashlight() { toggleTorchState(); } /** * 初始化CameraScan */ - public void initCameraScan(){ - mCameraScan = new DefaultCameraScan(this,previewView); + public void initCameraScan() { + mCameraScan = new DefaultCameraScan(this, previewView); mCameraScan.setOnScanResultCallback(this); } /** * 启动相机预览 */ - public void startCamera(){ - if(mCameraScan != null){ - if(PermissionUtils.checkPermission(getContext(), Manifest.permission.CAMERA)){ + public void startCamera() { + if (mCameraScan != null) { + if (PermissionUtils.checkPermission(getContext(), Manifest.permission.CAMERA)) { mCameraScan.startCamera(); - }else{ + } else { LogUtils.d("checkPermissionResult != PERMISSION_GRANTED"); - PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE); + PermissionUtils.requestPermission(this, Manifest.permission.CAMERA, CAMERA_PERMISSION_REQUEST_CODE); } } } @@ -115,8 +126,8 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult /** * 释放相机 */ - private void releaseCamera(){ - if(mCameraScan != null){ + private void releaseCamera() { + if (mCameraScan != null) { mCameraScan.release(); } } @@ -124,11 +135,11 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult /** * 切换闪光灯状态(开启/关闭) */ - protected void toggleTorchState(){ - if(mCameraScan != null){ + protected void toggleTorchState() { + if (mCameraScan != null) { boolean isTorch = mCameraScan.isTorchEnabled(); mCameraScan.enableTorch(!isTorch); - if(ivFlashlight != null){ + if (ivFlashlight != null) { ivFlashlight.setSelected(!isTorch); } } @@ -137,20 +148,21 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if(requestCode == CAMERA_PERMISSION_REQUEST_CODE){ - requestCameraPermissionResult(permissions,grantResults); + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { + requestCameraPermissionResult(permissions, grantResults); } } /** * 请求Camera权限回调结果 + * * @param permissions * @param grantResults */ - public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){ - if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){ + public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults) { + if (PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA, permissions, grantResults)) { startCamera(); - }else{ + } else { getActivity().finish(); } } @@ -163,66 +175,73 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult /** * 返回true时会自动初始化{@link #createRootView(LayoutInflater, ViewGroup)},返回为false是需自己去初始化{@link #createRootView(LayoutInflater, ViewGroup)} + * * @return 默认返回true */ - public boolean isContentView(){ + public boolean isContentView() { return true; } /** * 创建{@link #mRootView} + * * @param inflater * @param container * @return */ @NonNull - public View createRootView(LayoutInflater inflater, ViewGroup container){ - return inflater.inflate(getLayoutId(),container,false); + public View createRootView(LayoutInflater inflater, ViewGroup container) { + return inflater.inflate(getLayoutId(), container, false); } /** - * 布局id + * 布局ID;通过覆写此方法可以自定义布局 + * * @return */ - public int getLayoutId(){ + public int getLayoutId() { return R.layout.zxl_capture; } /** * {@link #viewfinderView} 的 ID + * * @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回0 */ - public int getViewfinderViewId(){ + public int getViewfinderViewId() { return R.id.viewfinderView; } - /** * 预览界面{@link #previewView} 的ID + * * @return */ - public int getPreviewViewId(){ + public int getPreviewViewId() { return R.id.previewView; } /** * 获取 {@link #ivFlashlight} 的ID - * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 + * + * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0 */ - public int getFlashlightId(){ + public int getFlashlightId() { return R.id.ivFlashlight; } /** * Get {@link CameraScan} + * * @return {@link #mCameraScan} */ - public CameraScan getCameraScan(){ + public CameraScan getCameraScan() { return mCameraScan; } /** * 接收扫码结果回调 + * * @param result 扫码结果 * @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截 */ @@ -237,5 +256,4 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult return mRootView; } - } diff --git a/zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java b/zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java index 0cdc18b..308d89f 100644 --- a/zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java +++ b/zxing-lite/src/main/java/com/king/zxing/DecodeConfig.java @@ -12,11 +12,12 @@ import java.util.Map; import androidx.annotation.FloatRange; - /** * 解码配置:主要用于在扫码识别时,提供一些配置,便于扩展。通过配置可决定内置分析器的能力,从而间接的控制并简化扫码识别的流程 *

* 设置解码 {@link #setHints(Map)}内置的一些解码可参见如下: + * + * @author Jenly * @see {@link DecodeFormatManager#DEFAULT_HINTS} * @see {@link DecodeFormatManager#ALL_HINTS} * @see {@link DecodeFormatManager#CODE_128_HINTS} @@ -24,7 +25,7 @@ import androidx.annotation.FloatRange; * @see {@link DecodeFormatManager#ONE_DIMENSIONAL_HINTS} * @see {@link DecodeFormatManager#TWO_DIMENSIONAL_HINTS} * @see {@link DecodeFormatManager#DEFAULT_HINTS} - * + *

* 如果不满足您也可以通过{@link DecodeFormatManager#createDecodeHints(BarcodeFormat...)}自己配置支持的格式 * *

@@ -32,18 +33,16 @@ import androidx.annotation.FloatRange; * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 - * + *

* 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 - * + *

* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} *

- * - * @author Jenly */ public class DecodeConfig { - private Map hints = DecodeFormatManager.DEFAULT_HINTS; + private Map hints = DecodeFormatManager.DEFAULT_HINTS; public static final float DEFAULT_AREA_RECT_RATIO = 0.8f; @@ -92,7 +91,7 @@ public class DecodeConfig { */ private int areaRectHorizontalOffset; - public DecodeConfig(){ + public DecodeConfig() { } @@ -102,9 +101,11 @@ public class DecodeConfig { /** * 设置解码 - * @param hints {@link DecodeFormatManager} * - * 内置的一些解码可参见如下: + * @param hints {@link DecodeFormatManager} + *

+ * 内置的一些解码可参见如下: + * @return * @see {@link DecodeFormatManager#DEFAULT_HINTS} * @see {@link DecodeFormatManager#ALL_HINTS} * @see {@link DecodeFormatManager#CODE_128_HINTS} @@ -112,10 +113,8 @@ public class DecodeConfig { * @see {@link DecodeFormatManager#ONE_DIMENSIONAL_HINTS} * @see {@link DecodeFormatManager#TWO_DIMENSIONAL_HINTS} * @see {@link DecodeFormatManager#DEFAULT_HINTS} - * + *

* 如果不满足您也可以通过{@link DecodeFormatManager#createDecodeHints(BarcodeFormat...)}自己配置支持的格式 - * - * @return */ public DecodeConfig setHints(Map hints) { this.hints = hints; @@ -124,6 +123,7 @@ public class DecodeConfig { /** * 是否支持识别反色码,黑白颜色反转 + * * @return */ public boolean isSupportLuminanceInvert() { @@ -132,6 +132,7 @@ public class DecodeConfig { /** * 设置是否支持识别反色码,黑白颜色反转 + * * @param supportLuminanceInvert 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。 * @return */ @@ -142,6 +143,7 @@ public class DecodeConfig { /** * 是否支持扫垂直的条码 + * * @return */ public boolean isSupportVerticalCode() { @@ -150,6 +152,7 @@ public class DecodeConfig { /** * 设置是否支持扫垂直的条码 + * * @param supportVerticalCode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。 * @return */ @@ -160,6 +163,7 @@ public class DecodeConfig { /** * 是否支持使用多解码 + * * @return */ public boolean isMultiDecode() { @@ -168,9 +172,10 @@ public class DecodeConfig { /** * 是否支持使用多解码 - * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} + * * @param multiDecode 默认为{@code true} * @return + * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} */ public DecodeConfig setMultiDecode(boolean multiDecode) { isMultiDecode = multiDecode; @@ -178,7 +183,8 @@ public class DecodeConfig { } /** - * 是否支持识别反色码(条码黑白颜色反转的码)使用多解码 + * 是否支持识别反色码(条码黑白颜色反转的码)使用多解码 + * * @return */ public boolean isSupportLuminanceInvertMultiDecode() { @@ -187,9 +193,10 @@ public class DecodeConfig { /** * 设置是否支持识别反色码(条码黑白颜色反转的码)使用多解码 - * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} - * @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。 + * + * @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。 * @return + * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} */ public DecodeConfig setSupportLuminanceInvertMultiDecode(boolean supportLuminanceInvertMultiDecode) { isSupportLuminanceInvertMultiDecode = supportLuminanceInvertMultiDecode; @@ -198,6 +205,7 @@ public class DecodeConfig { /** * 是否支持垂直的条码,使用多解码 + * * @return */ public boolean isSupportVerticalCodeMultiDecode() { @@ -205,8 +213,8 @@ public class DecodeConfig { } /** - * 设置是否支持垂直的条码,使用多解码 - * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} + * 设置是否支持垂直的条码,使用多解码;解码时,对应的二值化的实现: {@link HybridBinarizer} , {@link GlobalHistogramBinarizer} + * * @param supportVerticalCodeMultiDecode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。 * @return */ @@ -217,6 +225,7 @@ public class DecodeConfig { /** * 需要分析识别区域 + * * @return */ public Rect getAnalyzeAreaRect() { @@ -225,18 +234,16 @@ public class DecodeConfig { /** * 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 - * @param analyzeAreaRect - * - * 识别区域可设置的方式有如下几种: - * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 - * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 - * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 - * - * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, - * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 - * - * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} * + * @param analyzeAreaRect 识别区域可设置的方式有如下几种: + * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 + * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 + * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 + *

+ * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, + * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 + *

+ * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} * @return */ public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) { @@ -246,6 +253,7 @@ public class DecodeConfig { /** * 是否支持全区域扫码识别 + * * @return */ public boolean isFullAreaScan() { @@ -254,17 +262,18 @@ public class DecodeConfig { /** * 设置是否支持全区域扫码识别,优先级比识别区域高 + * * @param fullAreaScan 默认为{@code true} - * - * 识别区域可设置的方式有如下几种: - * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 - * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 - * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 - * - * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, - * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 - * - * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} + *

+ * 识别区域可设置的方式有如下几种: + * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 + * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 + * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 + *

+ * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, + * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 + *

+ * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} * @return */ public DecodeConfig setFullAreaScan(boolean fullAreaScan) { @@ -274,6 +283,7 @@ public class DecodeConfig { /** * 识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 + * * @return */ public float getAreaRectRatio() { @@ -282,27 +292,26 @@ public class DecodeConfig { /** * 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 - * @param areaRectRatio - * - * 识别区域可设置的方式有如下几种: - * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 - * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 - * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 - * - * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, - * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 - * - * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} * + * @param areaRectRatio 识别区域可设置的方式有如下几种: + * {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高 + * {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效 + * {@link #setAreaRectRatio(float)} 设置识别区域比例,默认{@link #DEFAULT_AREA_RECT_RATIO},设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低 + *

+ * 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的,所以这里的区域并不是用户所能预览到的区域,而是指Camera预览的真实区域, + * 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息 + *

+ * 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)} * @return */ - public DecodeConfig setAreaRectRatio(@FloatRange(from = 0.5,to = 1.0) float areaRectRatio) { + public DecodeConfig setAreaRectRatio(@FloatRange(from = 0.5, to = 1.0) float areaRectRatio) { this.areaRectRatio = areaRectRatio; return this; } /** * 识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移 + * * @return */ public int getAreaRectVerticalOffset() { @@ -311,6 +320,7 @@ public class DecodeConfig { /** * 设置识别区域垂直方向偏移量,支持负数,大于0时,居中心向下偏移,小于0时,居中心向上偏移 + * * @param areaRectVerticalOffset * @return */ @@ -321,6 +331,7 @@ public class DecodeConfig { /** * 识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移 + * * @return */ public int getAreaRectHorizontalOffset() { @@ -329,6 +340,7 @@ public class DecodeConfig { /** * 设置识别区域水平方向偏移量,支持负数,大于0时,居中心向右偏移,小于0时,居中心向左偏移 + * * @param areaRectHorizontalOffset * @return */ diff --git a/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java b/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java index a0eef3b..0a08c42 100644 --- a/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java +++ b/zxing-lite/src/main/java/com/king/zxing/DecodeFormatManager.java @@ -13,6 +13,10 @@ import java.util.Map; import androidx.annotation.NonNull; /** + * 解码格式管理器 + *

+ * 将常见的一些解码配置已根据条形码类型进行了几大划分,可根据需要找到符合的划分配置类型直接使用。 + * * @author Jenly */ public final class DecodeFormatManager { @@ -20,45 +24,46 @@ public final class DecodeFormatManager { /** * 所有的 */ - public static final Map ALL_HINTS = new EnumMap<>(DecodeHintType.class); + public static final Map ALL_HINTS = new EnumMap<>(DecodeHintType.class); /** * CODE_128 (最常用的一维码) */ - public static final Map CODE_128_HINTS = createDecodeHint(BarcodeFormat.CODE_128); + public static final Map CODE_128_HINTS = createDecodeHint(BarcodeFormat.CODE_128); /** * QR_CODE (最常用的二维码) */ - public static final Map QR_CODE_HINTS = createDecodeHint(BarcodeFormat.QR_CODE); + public static final Map QR_CODE_HINTS = createDecodeHint(BarcodeFormat.QR_CODE); /** * 一维码 */ - public static final Map ONE_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class); + public static final Map ONE_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class); /** * 二维码 */ - public static final Map TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class); + public static final Map TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class); /** * 默认 */ - public static final Map DEFAULT_HINTS = new EnumMap<>(DecodeHintType.class); + public static final Map DEFAULT_HINTS = new EnumMap<>(DecodeHintType.class); static { //all hints - addDecodeHintTypes(ALL_HINTS,getAllFormats()); + addDecodeHintTypes(ALL_HINTS, getAllFormats()); //one dimension - addDecodeHintTypes(ONE_DIMENSIONAL_HINTS,getOneDimensionalFormats()); + addDecodeHintTypes(ONE_DIMENSIONAL_HINTS, getOneDimensionalFormats()); //Two dimension - addDecodeHintTypes(TWO_DIMENSIONAL_HINTS,getTwoDimensionalFormats()); + addDecodeHintTypes(TWO_DIMENSIONAL_HINTS, getTwoDimensionalFormats()); //default hints - addDecodeHintTypes(DEFAULT_HINTS,getDefaultFormats()); + addDecodeHintTypes(DEFAULT_HINTS, getDefaultFormats()); } /** * 所有支持的{@link BarcodeFormat} + * * @return */ - private static List getAllFormats(){ + private static List getAllFormats() { List list = new ArrayList<>(); list.add(BarcodeFormat.AZTEC); list.add(BarcodeFormat.CODABAR); @@ -83,21 +88,22 @@ public final class DecodeFormatManager { /** * 二维码 * 包括如下几种格式: - * {@link BarcodeFormat#CODABAR} - * {@link BarcodeFormat#CODE_39} - * {@link BarcodeFormat#CODE_93} - * {@link BarcodeFormat#CODE_128} - * {@link BarcodeFormat#EAN_8} - * {@link BarcodeFormat#EAN_13} - * {@link BarcodeFormat#ITF} - * {@link BarcodeFormat#RSS_14} - * {@link BarcodeFormat#RSS_EXPANDED} - * {@link BarcodeFormat#UPC_A} - * {@link BarcodeFormat#UPC_E} - * {@link BarcodeFormat#UPC_EAN_EXTENSION} + * {@link BarcodeFormat#CODABAR} + * {@link BarcodeFormat#CODE_39} + * {@link BarcodeFormat#CODE_93} + * {@link BarcodeFormat#CODE_128} + * {@link BarcodeFormat#EAN_8} + * {@link BarcodeFormat#EAN_13} + * {@link BarcodeFormat#ITF} + * {@link BarcodeFormat#RSS_14} + * {@link BarcodeFormat#RSS_EXPANDED} + * {@link BarcodeFormat#UPC_A} + * {@link BarcodeFormat#UPC_E} + * {@link BarcodeFormat#UPC_EAN_EXTENSION} + * * @return */ - private static List getOneDimensionalFormats(){ + private static List getOneDimensionalFormats() { List list = new ArrayList<>(); list.add(BarcodeFormat.CODABAR); list.add(BarcodeFormat.CODE_39); @@ -117,14 +123,15 @@ public final class DecodeFormatManager { /** * 二维码 * 包括如下几种格式: - * {@link BarcodeFormat#AZTEC} - * {@link BarcodeFormat#DATA_MATRIX} - * {@link BarcodeFormat#MAXICODE} - * {@link BarcodeFormat#PDF_417} - * {@link BarcodeFormat#QR_CODE} + * {@link BarcodeFormat#AZTEC} + * {@link BarcodeFormat#DATA_MATRIX} + * {@link BarcodeFormat#MAXICODE} + * {@link BarcodeFormat#PDF_417} + * {@link BarcodeFormat#QR_CODE} + * * @return */ - private static List getTwoDimensionalFormats(){ + private static List getTwoDimensionalFormats() { List list = new ArrayList<>(); list.add(BarcodeFormat.AZTEC); list.add(BarcodeFormat.DATA_MATRIX); @@ -137,13 +144,14 @@ public final class DecodeFormatManager { /** * 默认支持的格式 * 包括如下几种格式: - * {@link BarcodeFormat#QR_CODE} - * {@link BarcodeFormat#UPC_A} - * {@link BarcodeFormat#EAN_13} - * {@link BarcodeFormat#CODE_128} + * {@link BarcodeFormat#QR_CODE} + * {@link BarcodeFormat#UPC_A} + * {@link BarcodeFormat#EAN_13} + * {@link BarcodeFormat#CODE_128} + * * @return */ - private static List getDefaultFormats(){ + private static List getDefaultFormats() { List list = new ArrayList<>(); list.add(BarcodeFormat.QR_CODE); list.add(BarcodeFormat.UPC_A); @@ -152,38 +160,35 @@ public final class DecodeFormatManager { return list; } - private static List singletonList(T o){ - return Collections.singletonList(o); - } - /** * 支持解码的格式 + * * @param barcodeFormats {@link BarcodeFormat} * @return */ - public static Map createDecodeHints(@NonNull BarcodeFormat... barcodeFormats){ - Map hints = new EnumMap<>(DecodeHintType.class); + public static Map createDecodeHints(@NonNull BarcodeFormat... barcodeFormats) { + Map hints = new EnumMap<>(DecodeHintType.class); addDecodeHintTypes(hints, Arrays.asList(barcodeFormats)); return hints; } /** * 支持解码的格式 + * * @param barcodeFormat {@link BarcodeFormat} * @return */ - public static Map createDecodeHint(@NonNull BarcodeFormat barcodeFormat){ - Map hints = new EnumMap<>(DecodeHintType.class); - addDecodeHintTypes(hints,singletonList(barcodeFormat)); + public static Map createDecodeHint(@NonNull BarcodeFormat barcodeFormat) { + Map hints = new EnumMap<>(DecodeHintType.class); + addDecodeHintTypes(hints, Collections.singletonList(barcodeFormat)); return hints; } /** - * * @param hints * @param formats */ - private static void addDecodeHintTypes(Map hints,List formats){ + private static void addDecodeHintTypes(Map hints, List formats) { // Image is known to be of one of a few possible formats. hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); // Spend more time to try to find a barcode; optimize for accuracy, not speed. diff --git a/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java index f0a75a2..a62777e 100644 --- a/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java +++ b/zxing-lite/src/main/java/com/king/zxing/DefaultCameraScan.java @@ -1,5 +1,6 @@ package com.king.zxing; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -27,6 +28,7 @@ import androidx.annotation.FloatRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.camera.core.Camera; +import androidx.camera.core.CameraInfo; import androidx.camera.core.CameraSelector; import androidx.camera.core.FocusMeteringAction; import androidx.camera.core.ImageAnalysis; @@ -43,6 +45,18 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.MutableLiveData; /** + * 相机扫描基类;{@link DefaultCameraScan} 为 {@link CameraScan} 的默认实现 + *

+ * 快速实现扫描识别主要有以下几种方式: + *

+ * 1、通过继承 {@link CaptureActivity}或者{@link CaptureFragment}或其子类,可快速实现扫描识别。 + * (适用于大多数场景,自定义布局时需覆写getLayoutId方法) + *

+ * 2、在你项目的Activity或者Fragment中实例化一个{@link DefaultCameraScan}。(适用于想在扫码界面写交互逻辑,又因为项目 + * 架构或其它原因,无法直接或间接继承{@link CaptureActivity}或{@link CaptureFragment}时使用) + *

+ * 3、继承{@link CameraScan}自己实现一个,可参照默认实现类{@link DefaultCameraScan},其他步骤同方式2。(高级用法,谨慎使用) + * * @author Jenly */ public class DefaultCameraScan extends CameraScan { @@ -61,6 +75,11 @@ public class DefaultCameraScan extends CameraScan { */ private static final int HOVER_TAP_SLOP = 20; + /** + * 每次缩放改变的步长 + */ + private static final float ZOOM_STEP_SIZE = 0.1F; + private FragmentActivity mFragmentActivity; private Context mContext; private LifecycleOwner mLifecycleOwner; @@ -92,15 +111,15 @@ public class DefaultCameraScan extends CameraScan { private AmbientLightManager mAmbientLightManager; private int mOrientation; - private int mScreenWidth; - private int mScreenHeight; + private int mImageWidth; + private int mImageHeight; private long mLastAutoZoomTime; private long mLastHoveTapTime; private boolean isClickTap; private float mDownX; private float mDownY; - public DefaultCameraScan(@NonNull FragmentActivity activity,@NonNull PreviewView previewView){ + public DefaultCameraScan(@NonNull FragmentActivity activity, @NonNull PreviewView previewView) { this.mFragmentActivity = activity; this.mLifecycleOwner = activity; this.mContext = activity; @@ -108,7 +127,7 @@ public class DefaultCameraScan extends CameraScan { initData(); } - public DefaultCameraScan(@NonNull Fragment fragment,@NonNull PreviewView previewView){ + public DefaultCameraScan(@NonNull Fragment fragment, @NonNull PreviewView previewView) { this.mFragmentActivity = fragment.getActivity(); this.mLifecycleOwner = fragment; this.mContext = fragment.getContext(); @@ -116,25 +135,34 @@ public class DefaultCameraScan extends CameraScan { initData(); } - private ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener(){ + /** + * 缩放手势检测 + */ + private ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { float scale = detector.getScaleFactor(); - if(mCamera != null){ + if (mCamera != null) { float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio(); + // 根据缩放的手势和当前比例进行缩放 zoomTo(ratio * scale); + return true; } - return true; + return false; } }; - private void initData(){ + /** + * 初始化 + */ + @SuppressLint("ClickableViewAccessibility") + private void initData() { mResultLiveData = new MutableLiveData<>(); mResultLiveData.observe(mLifecycleOwner, result -> { - if(result != null){ + if (result != null) { handleAnalyzeResult(result); - }else if(mOnScanResultCallback != null){ + } else if (mOnScanResultCallback != null) { mOnScanResultCallback.onScanResultFailure(); } }); @@ -144,42 +172,38 @@ public class DefaultCameraScan extends CameraScan { ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener); mPreviewView.setOnTouchListener((v, event) -> { handlePreviewViewClickTap(event); - if(isNeedTouchZoom()){ + if (isNeedTouchZoom()) { return scaleGestureDetector.onTouchEvent(event); } return false; }); - DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); - mScreenWidth = displayMetrics.widthPixels; - mScreenHeight = displayMetrics.heightPixels; - - LogUtils.d(String.format("displayMetrics:%dx%d",mScreenWidth,mScreenHeight)); - mBeepManager = new BeepManager(mContext); mAmbientLightManager = new AmbientLightManager(mContext); - if(mAmbientLightManager != null){ - mAmbientLightManager.register(); - mAmbientLightManager.setOnLightSensorEventListener((dark, lightLux) -> { - if(flashlightView != null){ - if(dark){ - if(flashlightView.getVisibility() != View.VISIBLE){ - flashlightView.setVisibility(View.VISIBLE); - flashlightView.setSelected(isTorchEnabled()); - } - }else if(flashlightView.getVisibility() == View.VISIBLE && !isTorchEnabled()){ - flashlightView.setVisibility(View.INVISIBLE); - flashlightView.setSelected(false); + mAmbientLightManager.register(); + mAmbientLightManager.setOnLightSensorEventListener((dark, lightLux) -> { + if (flashlightView != null) { + if (dark) { + if (flashlightView.getVisibility() != View.VISIBLE) { + flashlightView.setVisibility(View.VISIBLE); + flashlightView.setSelected(isTorchEnabled()); } - + } else if (flashlightView.getVisibility() == View.VISIBLE && !isTorchEnabled()) { + flashlightView.setVisibility(View.INVISIBLE); + flashlightView.setSelected(false); } - }); - } + } + }); } - private void handlePreviewViewClickTap(MotionEvent event){ - if(event.getPointerCount() == 1){ - switch (event.getAction()){ + /** + * 处理预览视图点击事件;如果触发的点击事件被判定对焦操作,则开始自动对焦 + * + * @param event + */ + private void handlePreviewViewClickTap(MotionEvent event) { + if (event.getPointerCount() == 1) { + switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isClickTap = true; mDownX = event.getX(); @@ -187,35 +211,43 @@ public class DefaultCameraScan extends CameraScan { mLastHoveTapTime = System.currentTimeMillis(); break; case MotionEvent.ACTION_MOVE: - isClickTap = MathUtils.distance(mDownX,mDownY,event.getX(),event.getY()) < HOVER_TAP_SLOP; + 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()); + if (isClickTap && mLastHoveTapTime + HOVER_TAP_TIMEOUT > System.currentTimeMillis()) { + // 开始对焦和测光 + startFocusAndMetering(event.getX(), event.getY()); } break; } } } - private void startFocusAndMetering(float x, float y){ - if(mCamera != null){ - MeteringPoint point = mPreviewView.getMeteringPointFactory().createPoint(x,y); + /** + * 开始对焦和测光 + * + * @param x + * @param y + */ + private void startFocusAndMetering(float x, float y) { + if (mCamera != null) { + MeteringPoint point = mPreviewView.getMeteringPointFactory().createPoint(x, y); FocusMeteringAction focusMeteringAction = new FocusMeteringAction.Builder(point).build(); - if(mCamera.getCameraInfo().isFocusMeteringSupported(focusMeteringAction)){ + if (mCamera.getCameraInfo().isFocusMeteringSupported(focusMeteringAction)) { mCamera.getCameraControl().startFocusAndMetering(focusMeteringAction); LogUtils.d("startFocusAndMetering:" + x + "," + y); } } } - - - private void initConfig(){ - if(mCameraConfig == null){ + /** + * 初始化配置 + */ + private void initConfig() { + if (mCameraConfig == null) { mCameraConfig = new CameraConfig(); } - if(mAnalyzer == null){ + if (mAnalyzer == null) { mAnalyzer = new MultiFormatAnalyzer(); } } @@ -223,19 +255,19 @@ public class DefaultCameraScan extends CameraScan { @Override public CameraScan setCameraConfig(CameraConfig cameraConfig) { - if(cameraConfig != null){ + if (cameraConfig != null) { this.mCameraConfig = cameraConfig; } return this; } @Override - public void startCamera(){ + public void startCamera() { initConfig(); mCameraProviderFuture = ProcessCameraProvider.getInstance(mContext); mCameraProviderFuture.addListener(() -> { - try{ + try { Preview preview = mCameraConfig.options(new Preview.Builder()); //相机选择器 @@ -248,49 +280,52 @@ public class DefaultCameraScan extends CameraScan { .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)); imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), image -> { - if(isAnalyze && !isAnalyzeResult && mAnalyzer != null){ - Result result = mAnalyzer.analyze(image,mOrientation); + mImageWidth = image.getWidth(); + mImageHeight = image.getHeight(); + if (isAnalyze && !isAnalyzeResult && mAnalyzer != null) { + Result result = mAnalyzer.analyze(image, mOrientation); mResultLiveData.postValue(result); } image.close(); }); - if(mCamera != null){ + if (mCamera != null) { mCameraProviderFuture.get().unbindAll(); } - //绑定到生命周期 + // 绑定到生命周期 mCamera = mCameraProviderFuture.get().bindToLifecycle(mLifecycleOwner, cameraSelector, preview, imageAnalysis); - }catch (Exception e){ + } catch (Exception e) { LogUtils.e(e); } - },ContextCompat.getMainExecutor(mContext)); + }, ContextCompat.getMainExecutor(mContext)); } /** * 处理分析结果 + * * @param result */ - private synchronized void handleAnalyzeResult(Result result){ + private synchronized void handleAnalyzeResult(Result result) { - if(isAnalyzeResult || !isAnalyze){ + if (isAnalyzeResult || !isAnalyze) { return; } isAnalyzeResult = true; - if(mBeepManager != null){ + if (mBeepManager != null) { mBeepManager.playBeepSoundAndVibrate(); } - if(result.getBarcodeFormat() == BarcodeFormat.QR_CODE && isNeedAutoZoom() && mLastAutoZoomTime + 100 < System.currentTimeMillis()){ + if (result.getBarcodeFormat() == BarcodeFormat.QR_CODE && isNeedAutoZoom() && mLastAutoZoomTime + 100 < System.currentTimeMillis()) { ResultPoint[] points = result.getResultPoints(); - if(points != null && points.length >= 2){ - float distance1 = ResultPoint.distance(points[0],points[1]); + if (points != null && points.length >= 2) { + float distance1 = ResultPoint.distance(points[0], points[1]); float maxDistance = distance1; - if(points.length >= 3){ - float distance2 = ResultPoint.distance(points[1],points[2]); - float distance3 = ResultPoint.distance(points[0],points[2]); - maxDistance = Math.max(Math.max(distance1,distance2),distance3); + if (points.length >= 3) { + float distance2 = ResultPoint.distance(points[1], points[2]); + float distance3 = ResultPoint.distance(points[0], points[2]); + maxDistance = Math.max(Math.max(distance1, distance2), distance3); } - if(handleAutoZoom((int)maxDistance,result)){ + if (handleAutoZoom((int) maxDistance, result)) { return; } } @@ -299,9 +334,15 @@ public class DefaultCameraScan extends CameraScan { scanResultCallback(result); } - private boolean handleAutoZoom(int distance,Result result){ - int size = Math.min(mScreenWidth,mScreenHeight); - if(distance * 4 < size){ + /** + * 处理自动缩放 + * @param distance + * @param result + * @return + */ + private boolean handleAutoZoom(int distance, Result result) { + int size = Math.min(mImageWidth, mImageHeight); + if (distance * 4 < size) { mLastAutoZoomTime = System.currentTimeMillis(); zoomIn(); scanResultCallback(result); @@ -310,8 +351,12 @@ public class DefaultCameraScan extends CameraScan { return false; } - private void scanResultCallback(Result result){ - if(mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)){ + /** + * 扫描结果回调 + * @param result + */ + private void scanResultCallback(Result result) { + if (mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)) { /* * 如果拦截了结果,则重置分析结果状态,并当isAnalyze为true时,默认会继续分析图像(也就是连扫)。 * 如果只是想拦截扫码结果回调,并不想继续分析图像(不想连扫),请在拦截扫码逻辑处通过调用 @@ -321,21 +366,20 @@ public class DefaultCameraScan extends CameraScan { return; } - if(mFragmentActivity != null){ + if (mFragmentActivity != null) { Intent intent = new Intent(); - intent.putExtra(SCAN_RESULT,result.getText()); - mFragmentActivity.setResult(Activity.RESULT_OK,intent); + intent.putExtra(SCAN_RESULT, result.getText()); + mFragmentActivity.setResult(Activity.RESULT_OK, intent); mFragmentActivity.finish(); } } - @Override - public void stopCamera(){ - if(mCameraProviderFuture != null){ + public void stopCamera() { + if (mCameraProviderFuture != null) { try { mCameraProviderFuture.get().unbindAll(); - }catch (Exception e){ + } catch (Exception e) { LogUtils.e(e); } } @@ -353,45 +397,45 @@ public class DefaultCameraScan extends CameraScan { return this; } + @Override - public void zoomIn(){ - if(mCamera != null){ - float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio() + 0.1f; - float maxRatio = mCamera.getCameraInfo().getZoomState().getValue().getMaxZoomRatio(); - if(ratio <= maxRatio){ + public void zoomIn() { + if (mCamera != null) { + float ratio = getCameraInfo().getZoomState().getValue().getZoomRatio() + ZOOM_STEP_SIZE; + float maxRatio = getCameraInfo().getZoomState().getValue().getMaxZoomRatio(); + if (ratio <= maxRatio) { mCamera.getCameraControl().setZoomRatio(ratio); } } } @Override - public void zoomOut(){ - if(mCamera != null){ - float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio() - 0.1f; - float minRatio = mCamera.getCameraInfo().getZoomState().getValue().getMinZoomRatio(); - if(ratio >= minRatio){ + public void zoomOut() { + if (mCamera != null) { + float ratio = getCameraInfo().getZoomState().getValue().getZoomRatio() - ZOOM_STEP_SIZE; + float minRatio = getCameraInfo().getZoomState().getValue().getMinZoomRatio(); + if (ratio >= minRatio) { mCamera.getCameraControl().setZoomRatio(ratio); } } } - @Override public void zoomTo(float ratio) { - if(mCamera != null){ - ZoomState zoomState = mCamera.getCameraInfo().getZoomState().getValue(); + if (mCamera != null) { + ZoomState zoomState = getCameraInfo().getZoomState().getValue(); float maxRatio = zoomState.getMaxZoomRatio(); float minRatio = zoomState.getMinZoomRatio(); - float zoom = Math.max(Math.min(ratio,maxRatio),minRatio); + float zoom = Math.max(Math.min(ratio, maxRatio), minRatio); mCamera.getCameraControl().setZoomRatio(zoom); } } @Override public void lineZoomIn() { - if(mCamera != null){ - float zoom = mCamera.getCameraInfo().getZoomState().getValue().getLinearZoom() + 0.1f; - if(zoom <= 1f){ + if (mCamera != null) { + float zoom = getCameraInfo().getZoomState().getValue().getLinearZoom() + ZOOM_STEP_SIZE; + if (zoom <= 1f) { mCamera.getCameraControl().setLinearZoom(zoom); } } @@ -399,31 +443,31 @@ public class DefaultCameraScan extends CameraScan { @Override public void lineZoomOut() { - if(mCamera != null){ - float zoom = mCamera.getCameraInfo().getZoomState().getValue().getLinearZoom() - 0.1f; - if(zoom >= 0f){ + if (mCamera != null) { + float zoom = getCameraInfo().getZoomState().getValue().getLinearZoom() - ZOOM_STEP_SIZE; + if (zoom >= 0f) { mCamera.getCameraControl().setLinearZoom(zoom); } } } @Override - public void lineZoomTo(@FloatRange(from = 0.0,to = 1.0) float linearZoom) { - if(mCamera != null){ + public void lineZoomTo(@FloatRange(from = 0.0, to = 1.0) float linearZoom) { + if (mCamera != null) { mCamera.getCameraControl().setLinearZoom(linearZoom); } } @Override public void enableTorch(boolean torch) { - if(mCamera != null && hasFlashUnit()){ + if (mCamera != null && hasFlashUnit()) { mCamera.getCameraControl().enableTorch(torch); } } @Override public boolean isTorchEnabled() { - if(mCamera != null){ + if (mCamera != null) { return mCamera.getCameraInfo().getTorchState().getValue() == TorchState.ON; } return false; @@ -431,11 +475,12 @@ public class DefaultCameraScan extends CameraScan { /** * 是否支持闪光灯 + * * @return */ @Override - public boolean hasFlashUnit(){ - if(mCamera != null){ + public boolean hasFlashUnit() { + if (mCamera != null) { return mCamera.getCameraInfo().hasFlashUnit(); } return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); @@ -443,7 +488,7 @@ public class DefaultCameraScan extends CameraScan { @Override public CameraScan setVibrate(boolean vibrate) { - if(mBeepManager != null){ + if (mBeepManager != null) { mBeepManager.setVibrate(vibrate); } return this; @@ -451,7 +496,7 @@ public class DefaultCameraScan extends CameraScan { @Override public CameraScan setPlayBeep(boolean playBeep) { - if(mBeepManager != null){ + if (mBeepManager != null) { mBeepManager.setPlayBeep(playBeep); } return this; @@ -465,19 +510,27 @@ public class DefaultCameraScan extends CameraScan { @Nullable @Override - public Camera getCamera(){ + public Camera getCamera() { return mCamera; } + /** + * CameraInfo + * + * @return {@link CameraInfo} + */ + private CameraInfo getCameraInfo() { + return mCamera.getCameraInfo(); + } @Override public void release() { isAnalyze = false; flashlightView = null; - if(mAmbientLightManager != null){ + if (mAmbientLightManager != null) { mAmbientLightManager.unregister(); } - if(mBeepManager != null){ + if (mBeepManager != null) { mBeepManager.close(); } stopCamera(); @@ -486,23 +539,23 @@ public class DefaultCameraScan extends CameraScan { @Override public CameraScan bindFlashlightView(@Nullable View v) { flashlightView = v; - if(mAmbientLightManager != null){ + if (mAmbientLightManager != null) { mAmbientLightManager.setLightSensorEnabled(v != null); } return this; } @Override - public CameraScan setDarkLightLux(float lightLux){ - if(mAmbientLightManager != null){ + public CameraScan setDarkLightLux(float lightLux) { + if (mAmbientLightManager != null) { mAmbientLightManager.setDarkLightLux(lightLux); } return this; } @Override - public CameraScan setBrightLightLux(float lightLux){ - if(mAmbientLightManager != null){ + public CameraScan setBrightLightLux(float lightLux) { + if (mAmbientLightManager != null) { mAmbientLightManager.setBrightLightLux(lightLux); } return this; diff --git a/zxing-lite/src/main/java/com/king/zxing/ICamera.java b/zxing-lite/src/main/java/com/king/zxing/ICamera.java index df4ddf1..b8543c2 100644 --- a/zxing-lite/src/main/java/com/king/zxing/ICamera.java +++ b/zxing-lite/src/main/java/com/king/zxing/ICamera.java @@ -1,10 +1,11 @@ package com.king.zxing; - import androidx.annotation.Nullable; import androidx.camera.core.Camera; /** + * 相机定义 + * * @author Jenly */ public interface ICamera { @@ -21,9 +22,11 @@ public interface ICamera { /** * 获取{@link Camera} + * * @return */ - @Nullable Camera getCamera(); + @Nullable + Camera getCamera(); /** * 释放 diff --git a/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java b/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java index 5bdbf96..2dfa9c8 100644 --- a/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java +++ b/zxing-lite/src/main/java/com/king/zxing/ICameraControl.java @@ -3,6 +3,8 @@ package com.king.zxing; import androidx.annotation.FloatRange; /** + * 相机控制:主要包括调节焦距和闪光灯控制 + * * @author Jenly */ public interface ICameraControl { @@ -19,6 +21,7 @@ public interface ICameraControl { /** * 缩放到指定比例 + * * @param ratio */ void zoomTo(float ratio); @@ -35,24 +38,28 @@ public interface ICameraControl { /** * 线性缩放到指定比例 + * * @param linearZoom */ - void lineZoomTo(@FloatRange(from = 0.0,to = 1.0) float linearZoom); + void lineZoomTo(@FloatRange(from = 0.0, to = 1.0) float linearZoom); /** * 设置闪光灯(手电筒)是否开启 + * * @param torch */ void enableTorch(boolean torch); /** * 闪光灯(手电筒)是否开启 + * * @return */ boolean isTorchEnabled(); /** * 是否支持闪光灯 + * * @return */ boolean hasFlashUnit(); diff --git a/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java index f43fb2e..4e3af5b 100644 --- a/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java +++ b/zxing-lite/src/main/java/com/king/zxing/ViewfinderView.java @@ -1,30 +1,20 @@ package com.king.zxing; -/* - * Copyright (C) 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; +import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Shader; +import android.graphics.drawable.Drawable; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; @@ -32,28 +22,37 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; +import android.view.GestureDetector; +import android.view.MotionEvent; import android.view.View; import com.king.zxing.util.LogUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import static com.king.zxing.ViewfinderView.FrameGravity.*; - /** - * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial - * transparency outside it, as well as the laser scanner animation and result points. + * 取景视图:主要用于渲染扫描效果 * - * @author dswitkin@google.com (Daniel Switkin) + * @author Jenly */ public class ViewfinderView extends View { - private static final int CURRENT_POINT_OPACITY = 0xA0; - private static final int MAX_RESULT_POINTS = 20; - private static final int POINT_SIZE = 30; + /** + * 默认范围比例,之所以默认为 1.2 是因为内切圆半径和外切圆半径之和的二分之一(即:(1 + √2) / 2 ≈ 1.2) + */ + private final float DEFAULT_RANGE_RATIO = 1.2F; + + private final float MAX_ZOOM_RATIO = 1.2F; /** * 画笔 @@ -186,25 +185,78 @@ public class ViewfinderView extends View { */ private FrameGravity frameGravity; - - private Point point; private int pointColor; private int pointStrokeColor; + private Bitmap pointBitmap; + private boolean isShowPointAnim = true; private float pointRadius; - private float pointStrokeRatio = 1.2f; + private float pointStrokeRatio; + private float pointStrokeRadius; + /** + * 当前缩放比例 + */ + private float currentZoomRatio = 1.0f; + /** + * 最后一次缩放比例(即上一次缩放比例) + */ + private float lastZoomRatio; + /** + * 缩放速度 + */ + private float zoomSpeed = 0.02f; - public enum LaserStyle{ - NONE(0),LINE(1),GRID(2); + private int zoomCount; + + /** + * 结果点有效点击范围半径 + */ + private float pointRangeRadius; + + private Bitmap laserBitmap; + + private int viewfinderStyle = ViewfinderStyle.CLASSIC; + + private List pointList; + + private boolean isShowPoints = false; + + private OnItemClickListener onItemClickListener; + + private GestureDetector gestureDetector; + + /** + * 取景框样式 + */ + @IntDef({ViewfinderStyle.CLASSIC, ViewfinderStyle.POPULAR}) + @Retention(RetentionPolicy.SOURCE) + public @interface ViewfinderStyle { + /** + * 经典样式:经典的扫码风格(带扫码框) + */ + int CLASSIC = 0; + /** + * 流行样式:类似于新版的微信全屏扫码(不带扫码框) + */ + int POPULAR = 1; + + } + + /** + * 扫描线样式 + */ + public enum LaserStyle { + NONE(0), LINE(1), GRID(2), IMAGE(3); private int mValue; - LaserStyle(int value){ + + LaserStyle(int value) { mValue = value; } - private static LaserStyle getFromInt(int value){ - for(LaserStyle style : LaserStyle.values()){ - if(style.mValue == value){ + private static LaserStyle getFromInt(int value) { + for (LaserStyle style : LaserStyle.values()) { + if (style.mValue == value) { return style; } } @@ -212,18 +264,21 @@ public class ViewfinderView extends View { } } + /** + * 文字位置 + */ public enum TextLocation { - TOP(0),BOTTOM(1); + TOP(0), BOTTOM(1); private int mValue; - TextLocation(int value){ + TextLocation(int value) { mValue = value; } - private static TextLocation getFromInt(int value){ - for(TextLocation location : TextLocation.values()){ - if(location.mValue == value){ + private static TextLocation getFromInt(int value) { + for (TextLocation location : TextLocation.values()) { + if (location.mValue == value) { return location; } } @@ -231,7 +286,9 @@ public class ViewfinderView extends View { } } - + /** + * 扫码框对齐方式 + */ public enum FrameGravity { CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4); @@ -252,65 +309,107 @@ public class ViewfinderView extends View { } public ViewfinderView(Context context) { - this(context,null); + this(context, null); } public ViewfinderView(Context context, @Nullable AttributeSet attrs) { - this(context, attrs,0); + this(context, attrs, 0); } public ViewfinderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - init(context,attrs); + init(context, attrs); } - + /** + * 初始化 + * + * @param context + * @param attrs + */ private void init(Context context, AttributeSet attrs) { - //初始化自定义属性信息 + // 初始化自定义属性信息 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView); - maskColor = array.getColor(R.styleable.ViewfinderView_maskColor, ContextCompat.getColor(context,R.color.viewfinder_mask)); - frameColor = array.getColor(R.styleable.ViewfinderView_frameColor, ContextCompat.getColor(context,R.color.viewfinder_frame)); - cornerColor = array.getColor(R.styleable.ViewfinderView_cornerColor, ContextCompat.getColor(context,R.color.viewfinder_corner)); - laserColor = array.getColor(R.styleable.ViewfinderView_laserColor, ContextCompat.getColor(context,R.color.viewfinder_laser)); + maskColor = array.getColor(R.styleable.ViewfinderView_maskColor, ContextCompat.getColor(context, R.color.viewfinder_mask)); + frameColor = array.getColor(R.styleable.ViewfinderView_frameColor, ContextCompat.getColor(context, R.color.viewfinder_frame)); + cornerColor = array.getColor(R.styleable.ViewfinderView_cornerColor, ContextCompat.getColor(context, R.color.viewfinder_corner)); + laserColor = array.getColor(R.styleable.ViewfinderView_laserColor, ContextCompat.getColor(context, R.color.viewfinder_laser)); labelText = array.getString(R.styleable.ViewfinderView_labelText); - labelTextColor = array.getColor(R.styleable.ViewfinderView_labelTextColor, ContextCompat.getColor(context,R.color.viewfinder_text_color)); - labelTextSize = array.getDimension(R.styleable.ViewfinderView_labelTextSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,14f,getResources().getDisplayMetrics())); - labelTextPadding = array.getDimension(R.styleable.ViewfinderView_labelTextPadding,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics())); - labelTextWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_labelTextWidth,0); - labelTextLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_labelTextLocation,0)); + labelTextColor = array.getColor(R.styleable.ViewfinderView_labelTextColor, ContextCompat.getColor(context, R.color.viewfinder_text_color)); + labelTextSize = array.getDimension(R.styleable.ViewfinderView_labelTextSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14f, getResources().getDisplayMetrics())); + labelTextPadding = array.getDimension(R.styleable.ViewfinderView_labelTextPadding, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics())); + labelTextWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_labelTextWidth, 0); + labelTextLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_labelTextLocation, 0)); - frameWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameWidth,0); - frameHeight = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameHeight,0); + frameWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameWidth, 0); + frameHeight = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameHeight, 0); - laserStyle = LaserStyle.getFromInt(array.getInt(R.styleable.ViewfinderView_laserStyle,LaserStyle.LINE.mValue)); - gridColumn = array.getInt(R.styleable.ViewfinderView_gridColumn,20); - gridHeight = (int)array.getDimension(R.styleable.ViewfinderView_gridHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40,getResources().getDisplayMetrics())); + laserStyle = LaserStyle.getFromInt(array.getInt(R.styleable.ViewfinderView_laserStyle, LaserStyle.LINE.mValue)); + gridColumn = array.getInt(R.styleable.ViewfinderView_gridColumn, 20); + gridHeight = (int) array.getDimension(R.styleable.ViewfinderView_gridHeight, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics())); + + cornerRectWidth = (int) array.getDimension(R.styleable.ViewfinderView_cornerRectWidth, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics())); + cornerRectHeight = (int) array.getDimension(R.styleable.ViewfinderView_cornerRectHeight, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics())); + scannerLineMoveDistance = (int) array.getDimension(R.styleable.ViewfinderView_scannerLineMoveDistance, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics())); + scannerLineHeight = (int) array.getDimension(R.styleable.ViewfinderView_scannerLineHeight, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics())); + frameLineWidth = (int) array.getDimension(R.styleable.ViewfinderView_frameLineWidth, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics())); + scannerAnimationDelay = array.getInteger(R.styleable.ViewfinderView_scannerAnimationDelay, 20); + frameRatio = array.getFloat(R.styleable.ViewfinderView_frameRatio, 0.625f); + framePaddingLeft = array.getDimension(R.styleable.ViewfinderView_framePaddingLeft, 0); + framePaddingTop = array.getDimension(R.styleable.ViewfinderView_framePaddingTop, 0); + framePaddingRight = array.getDimension(R.styleable.ViewfinderView_framePaddingRight, 0); + framePaddingBottom = array.getDimension(R.styleable.ViewfinderView_framePaddingBottom, 0); + frameGravity = FrameGravity.getFromInt(array.getInt(R.styleable.ViewfinderView_frameGravity, FrameGravity.CENTER.mValue)); + + pointColor = array.getColor(R.styleable.ViewfinderView_pointColor, ContextCompat.getColor(context, R.color.viewfinder_point)); + pointStrokeColor = array.getColor(R.styleable.ViewfinderView_pointStrokeColor, Color.WHITE); + pointRadius = array.getDimension(R.styleable.ViewfinderView_pointRadius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics())); + pointStrokeRatio = array.getFloat(R.styleable.ViewfinderView_pointStrokeRatio, DEFAULT_RANGE_RATIO); + isShowPointAnim = array.getBoolean(R.styleable.ViewfinderView_showPointAnim, true); + Drawable pointDrawable = array.getDrawable(R.styleable.ViewfinderView_pointDrawable); + Drawable laserDrawable = array.getDrawable(R.styleable.ViewfinderView_laserDrawable); + viewfinderStyle = array.getInt(R.styleable.ViewfinderView_viewfinderStyle, ViewfinderStyle.CLASSIC); - cornerRectWidth = (int)array.getDimension(R.styleable.ViewfinderView_cornerRectWidth,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,4,getResources().getDisplayMetrics())); - cornerRectHeight = (int)array.getDimension(R.styleable.ViewfinderView_cornerRectHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,16,getResources().getDisplayMetrics())); - scannerLineMoveDistance = (int)array.getDimension(R.styleable.ViewfinderView_scannerLineMoveDistance,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,2,getResources().getDisplayMetrics())); - scannerLineHeight = (int)array.getDimension(R.styleable.ViewfinderView_scannerLineHeight,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,5,getResources().getDisplayMetrics())); - frameLineWidth = (int)array.getDimension(R.styleable.ViewfinderView_frameLineWidth,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,1,getResources().getDisplayMetrics())); - scannerAnimationDelay = array.getInteger(R.styleable.ViewfinderView_scannerAnimationDelay,20); - frameRatio = array.getFloat(R.styleable.ViewfinderView_frameRatio,0.625f); - framePaddingLeft = array.getDimension(R.styleable.ViewfinderView_framePaddingLeft,0); - framePaddingTop = array.getDimension(R.styleable.ViewfinderView_framePaddingTop,0); - framePaddingRight = array.getDimension(R.styleable.ViewfinderView_framePaddingRight,0); - framePaddingBottom = array.getDimension(R.styleable.ViewfinderView_framePaddingBottom,0); - frameGravity = FrameGravity.getFromInt(array.getInt(R.styleable.ViewfinderView_frameGravity, CENTER.mValue)); array.recycle(); - pointColor = laserColor; - pointStrokeColor = Color.WHITE; + if (pointDrawable != null) { + pointBitmap = getBitmapFormDrawable(pointDrawable); + pointRangeRadius = (pointBitmap.getWidth() + pointBitmap.getHeight()) / 4 * DEFAULT_RANGE_RATIO; + } else { + pointStrokeRadius = pointRadius * pointStrokeRatio; + pointRangeRadius = pointStrokeRadius * DEFAULT_RANGE_RATIO; + } + + if (laserDrawable != null) { + laserBitmap = getBitmapFormDrawable(laserDrawable); + } - pointRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getResources().getDisplayMetrics()); paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setAntiAlias(true); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (isShowPoints && checkSingleTap(e.getX(), e.getY())) { + return true; + } + return super.onSingleTapUp(e); + } + }); + } - private DisplayMetrics getDisplayMetrics(){ + private Bitmap getBitmapFormDrawable(@NonNull Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + private DisplayMetrics getDisplayMetrics() { return getResources().getDisplayMetrics(); } @@ -322,48 +421,52 @@ public class ViewfinderView extends View { this.labelTextColor = color; } - public void setLabelTextColorResource(@ColorRes int id){ - this.labelTextColor = ContextCompat.getColor(getContext(),id); + public void setLabelTextColorResource(@ColorRes int id) { + this.labelTextColor = ContextCompat.getColor(getContext(), id); } public void setLabelTextSize(float textSize) { this.labelTextSize = textSize; } + public void setLaserStyle(LaserStyle laserStyle) { + this.laserStyle = laserStyle; + } + + public void setPointImageResource(@DrawableRes int drawable) { + setPointBitmap(BitmapFactory.decodeResource(getResources(), drawable)); + } + + public void setPointBitmap(Bitmap bitmap) { + pointBitmap = bitmap; + pointRangeRadius = (pointBitmap.getWidth() + pointBitmap.getHeight()) / 4 * DEFAULT_RANGE_RATIO; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - LogUtils.d("onLayout" + getWidth() + "," + getHeight()); initFrame(getWidth(),getHeight()); } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - LogUtils.d("onSizeChanged" + w + "," + h); + private void initFrame(int width, int height) { - } + int size = (int) (Math.min(width, height) * frameRatio); - - private void initFrame(int width,int height){ - - int size = (int)(Math.min(width,height) * frameRatio); - - if(frameWidth <= 0 || frameWidth > width){ + if (frameWidth <= 0 || frameWidth > width) { frameWidth = size; } - if(frameHeight <= 0 || frameHeight > height){ + if (frameHeight <= 0 || frameHeight > height) { frameHeight = size; } - if(labelTextWidth <= 0){ + if (labelTextWidth <= 0) { labelTextWidth = width - getPaddingLeft() - getPaddingRight(); } float leftOffsets = (width - frameWidth) / 2 + framePaddingLeft - framePaddingRight; float topOffsets = (height - frameHeight) / 2 + framePaddingTop - framePaddingBottom; - switch (frameGravity){ + switch (frameGravity) { case LEFT: leftOffsets = framePaddingLeft; break; @@ -374,57 +477,74 @@ public class ViewfinderView extends View { leftOffsets = width - frameWidth + framePaddingRight; break; case BOTTOM: - topOffsets = height - frameHeight + framePaddingBottom; + topOffsets = height - frameHeight + framePaddingBottom; break; } - frame = new Rect((int)leftOffsets, (int)topOffsets, (int)leftOffsets + frameWidth, (int)topOffsets + frameHeight); + frame = new Rect((int) leftOffsets, (int) topOffsets, (int) leftOffsets + frameWidth, (int) topOffsets + frameHeight); } @Override public void onDraw(Canvas canvas) { + if (isShowPoints) { + // 显示结果点 + drawMask(canvas, getWidth(), getHeight()); + drawResultPoints(canvas, pointList); + if (isShowPointAnim && pointBitmap == null) { + // 显示动画并且结果点标记的图片为空时,支持缩放动画 + calcZoomPointAnim(); + } + return; + } + if (frame == null) { return; } - if(scannerStart == 0 || scannerEnd == 0) { + if (scannerStart == 0 || scannerEnd == 0) { scannerStart = frame.top; scannerEnd = frame.bottom - scannerLineHeight; } - int width = canvas.getWidth(); - int height = canvas.getHeight(); + if (viewfinderStyle == ViewfinderStyle.CLASSIC) {// CLASSIC样式:经典样式(带扫码框) + // 绘制模糊区域 + drawExterior(canvas, frame, getWidth(), getHeight()); + // 绘制扫描动画 + drawLaserScanner(canvas, frame); + // 绘制取景区域框 + drawFrame(canvas, frame); + // 绘制取景区域边角 + drawCorner(canvas, frame); + // 绘制提示信息 + drawTextInfo(canvas, frame); + // 间隔更新取景区域 + postInvalidateDelayed(scannerAnimationDelay, frame.left, frame.top, frame.right, frame.bottom); + } else if (viewfinderStyle == ViewfinderStyle.POPULAR) {// POPULAR样式:类似于新版的微信全屏扫码(不带扫码框) + // 绘制扫描动画 + drawLaserScanner(canvas, frame); + postInvalidateDelayed(scannerAnimationDelay); + } - // 绘制模糊区域 - drawExterior(canvas,frame,width,height); - // 绘制扫描动画 - drawLaserScanner(canvas,frame); - // 绘制取景区域框 - drawFrame(canvas, frame); - // 绘制取景区域边角 - drawCorner(canvas, frame); - //绘制提示信息 - drawTextInfo(canvas, frame); - // 间隔更新取景区域 - postInvalidateDelayed(scannerAnimationDelay, frame.left, frame.top, frame.right, frame.bottom); } /** * 绘制文本 + * * @param canvas * @param frame */ private void drawTextInfo(Canvas canvas, Rect frame) { - if(!TextUtils.isEmpty(labelText)){ + if (!TextUtils.isEmpty(labelText)) { textPaint.setColor(labelTextColor); textPaint.setTextSize(labelTextSize); textPaint.setTextAlign(Paint.Align.CENTER); - StaticLayout staticLayout = new StaticLayout(labelText,textPaint,labelTextWidth, Layout.Alignment.ALIGN_NORMAL,1.2f,0.0f,true); - if(labelTextLocation == TextLocation.BOTTOM){ - canvas.translate(frame.left + frame.width() / 2,frame.bottom + labelTextPadding); - }else{ - canvas.translate(frame.left + frame.width() / 2,frame.top - labelTextPadding - staticLayout.getHeight()); + + StaticLayout staticLayout = new StaticLayout(labelText, textPaint, labelTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.2f, 0.0f, true); + if (labelTextLocation == TextLocation.BOTTOM) { + canvas.translate(frame.left + frame.width() / 2, frame.bottom + labelTextPadding); + } else { + canvas.translate(frame.left + frame.width() / 2, frame.top - labelTextPadding - staticLayout.getHeight()); } staticLayout.draw(canvas); } @@ -433,39 +553,65 @@ public class ViewfinderView extends View { /** * 绘制边角 + * * @param canvas * @param frame */ private void drawCorner(Canvas canvas, Rect frame) { paint.setColor(cornerColor); - //左上 + // 左上 canvas.drawRect(frame.left, frame.top, frame.left + cornerRectWidth, frame.top + cornerRectHeight, paint); canvas.drawRect(frame.left, frame.top, frame.left + cornerRectHeight, frame.top + cornerRectWidth, paint); - //右上 + // 右上 canvas.drawRect(frame.right - cornerRectWidth, frame.top, frame.right, frame.top + cornerRectHeight, paint); canvas.drawRect(frame.right - cornerRectHeight, frame.top, frame.right, frame.top + cornerRectWidth, paint); - //左下 + // 左下 canvas.drawRect(frame.left, frame.bottom - cornerRectWidth, frame.left + cornerRectHeight, frame.bottom, paint); canvas.drawRect(frame.left, frame.bottom - cornerRectHeight, frame.left + cornerRectWidth, frame.bottom, paint); - //右下 + // 右下 canvas.drawRect(frame.right - cornerRectWidth, frame.bottom - cornerRectHeight, frame.right, frame.bottom, paint); canvas.drawRect(frame.right - cornerRectHeight, frame.bottom - cornerRectWidth, frame.right, frame.bottom, paint); } + /** + * 绘制扫码动画 + * + * @param canvas + * @param frame + */ + private void drawImageScanner(Canvas canvas, Rect frame) { + if (laserBitmap != null) { + paint.setColor(Color.WHITE); + canvas.drawBitmap(laserBitmap, frame.left, scannerStart, paint); + if (scannerStart < scannerEnd) { + scannerStart += scannerLineMoveDistance; + } else { + scannerStart = frame.top; + } + } else { + drawLineScanner(canvas, frame); + } + + } + /** * 绘制激光扫描线 + * * @param canvas * @param frame */ private void drawLaserScanner(Canvas canvas, Rect frame) { - if(laserStyle != null){ + if (laserStyle != null) { paint.setColor(laserColor); - switch (laserStyle){ - case LINE://线 - drawLineScanner(canvas,frame); + switch (laserStyle) { + case LINE:// 线 + drawLineScanner(canvas, frame); break; - case GRID://网格 - drawGridScanner(canvas,frame); + case GRID:// 网格 + drawGridScanner(canvas, frame); + break; + case IMAGE:// 图片 + drawImageScanner(canvas, frame); break; } paint.setShader(null); @@ -474,11 +620,12 @@ public class ViewfinderView extends View { /** * 绘制线性式扫描 + * * @param canvas * @param frame */ - private void drawLineScanner(Canvas canvas,Rect frame){ - //线性渐变 + private void drawLineScanner(Canvas canvas, Rect frame) { + // 线性渐变 LinearGradient linearGradient = new LinearGradient( frame.left, scannerStart, frame.left, scannerStart + scannerLineHeight, @@ -487,8 +634,8 @@ public class ViewfinderView extends View { Shader.TileMode.MIRROR); paint.setShader(linearGradient); - if(scannerStart <= scannerEnd) { - //椭圆 + if (scannerStart < scannerEnd) { + // 椭圆 RectF rectF = new RectF(frame.left + 2 * scannerLineHeight, scannerStart, frame.right - 2 * scannerLineHeight, scannerStart + scannerLineHeight); canvas.drawOval(rectF, paint); scannerStart += scannerLineMoveDistance; @@ -499,34 +646,35 @@ public class ViewfinderView extends View { /** * 绘制网格式扫描 + * * @param canvas * @param frame */ - private void drawGridScanner(Canvas canvas,Rect frame){ + private void drawGridScanner(Canvas canvas, Rect frame) { int stroke = 2; paint.setStrokeWidth(stroke); - //计算Y轴开始位置 + // 计算Y轴开始位置 int startY = gridHeight > 0 && scannerStart - frame.top > gridHeight ? scannerStart - gridHeight : frame.top; - LinearGradient linearGradient = new LinearGradient(frame.left + frame.width()/2, startY, frame.left + frame.width()/2, scannerStart, new int[]{shadeColor(laserColor), laserColor}, new float[]{0,1f}, LinearGradient.TileMode.CLAMP); - //给画笔设置着色器 + LinearGradient linearGradient = new LinearGradient(frame.left + frame.width() / 2, startY, frame.left + frame.width() / 2, scannerStart, new int[]{shadeColor(laserColor), laserColor}, new float[]{0, 1f}, LinearGradient.TileMode.CLAMP); + // 给画笔设置着色器 paint.setShader(linearGradient); - float wUnit = frame.width() * 1.0f/ gridColumn; + float wUnit = frame.width() * 1.0f / gridColumn; float hUnit = wUnit; - //遍历绘制网格纵线 + // 遍历绘制网格纵线 for (int i = 1; i < gridColumn; i++) { - canvas.drawLine(frame.left + i * wUnit, startY,frame.left + i * wUnit, scannerStart,paint); + canvas.drawLine(frame.left + i * wUnit, startY, frame.left + i * wUnit, scannerStart, paint); } int height = gridHeight > 0 && scannerStart - frame.top > gridHeight ? gridHeight : scannerStart - frame.top; - //遍历绘制网格横线 - for (int i = 0; i <= height/hUnit; i++) { - canvas.drawLine(frame.left, scannerStart - i * hUnit,frame.right, scannerStart - i * hUnit,paint); + // 遍历绘制网格横线 + for (int i = 0; i <= height / hUnit; i++) { + canvas.drawLine(frame.left, scannerStart - i * hUnit, frame.right, scannerStart - i * hUnit, paint); } - if(scannerStart points) { + paint.setColor(Color.WHITE); + if (points != null) { + for (Point point : points) { + drawResultPoint(canvas, point, currentZoomRatio); + } + } + } + + /** + * 计算点的缩放动画 + */ + private void calcZoomPointAnim() { + if (currentZoomRatio <= 1F) { + lastZoomRatio = currentZoomRatio; + currentZoomRatio += zoomSpeed; + + if (zoomCount < 2) { + // 记住缩放回合次数 + zoomCount++; + } else { + zoomCount = 0; + } + } else if (currentZoomRatio >= MAX_ZOOM_RATIO) { + lastZoomRatio = currentZoomRatio; + currentZoomRatio -= zoomSpeed; + } else { + if (lastZoomRatio > currentZoomRatio) { + lastZoomRatio = currentZoomRatio; + currentZoomRatio -= zoomSpeed; + } else { + lastZoomRatio = currentZoomRatio; + currentZoomRatio += zoomSpeed; + } + } + + // 每间隔3秒触发一套缩放动画,一套动画缩放三个回合(即:每次zoomCount累加到2后重置为0时) + postInvalidateDelayed(zoomCount == 0 && lastZoomRatio == 1f ? 3000 : scannerAnimationDelay * 2); + + } + + /** + * 绘制结果点 + * + * @param canvas + * @param point + */ + private void drawResultPoint(Canvas canvas, Point point, float currentZoomRatio) { + if (pointBitmap != null) { + float left = point.x - pointBitmap.getWidth() / 2.0f; + float top = point.y - pointBitmap.getHeight() / 2.0f; + canvas.drawBitmap(pointBitmap, left, top, paint); + } else { + paint.setColor(pointStrokeColor); + canvas.drawCircle(point.x, point.y, pointStrokeRadius * currentZoomRatio, paint); + + paint.setColor(pointColor); + canvas.drawCircle(point.x, point.y, pointRadius * currentZoomRatio, paint); + } + + + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + if (isShowPoints) { + gestureDetector.onTouchEvent(event); + } + return isShowPoints || super.onTouchEvent(event); + } + + private boolean checkSingleTap(float x, float y) { + if (pointList != null) { + for (int i = 0; i < pointList.size(); i++) { + Point point = pointList.get(i); + float distance = getDistance(x, y, point.x, point.y); + if (distance <= pointRangeRadius) { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(i); + } + return true; + } + } + } + + return true; + } + + /** + * 获取两点之间的距离 + * + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @return + */ + private float getDistance(float x1, float y1, float x2, float y2) { + return (float) Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); + } + + /** + * 是否显示结果点 + * + * @return + */ + public boolean isShowPoints() { + return isShowPoints; + } + + /** + * 显示扫码动画 + */ + public void showScanner() { + isShowPoints = false; invalidate(); } - public void setLaserStyle(LaserStyle laserStyle) { - this.laserStyle = laserStyle; + /** + * 显示结果点 + * + * @param points + */ + public void showResultPoints(List points) { + pointList = points; + isShowPoints = true; + zoomCount = 0; + lastZoomRatio = 0; + currentZoomRatio = 1; + invalidate(); } + /** + * 设置点击Item监听 + * + * @param listener + */ + public void setOnItemClickListener(OnItemClickListener listener) { + onItemClickListener = listener; + } - + /** + * Item点击监听 + */ + public interface OnItemClickListener { + void onItemClick(int position); + } } \ No newline at end of file diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/Analyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/Analyzer.java index 69c9484..59b579c 100644 --- a/zxing-lite/src/main/java/com/king/zxing/analyze/Analyzer.java +++ b/zxing-lite/src/main/java/com/king/zxing/analyze/Analyzer.java @@ -1,24 +1,27 @@ package com.king.zxing.analyze; +import android.content.res.Configuration; + import com.google.zxing.Result; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.camera.core.ImageProxy; -import android.content.res.Configuration; /** * 分析器 + * * @author Jenly */ public interface Analyzer { /** * Analyzes an image to produce a result. - * @param image The image to analyze + * + * @param image The image to analyze * @param orientation {@link Configuration#ORIENTATION_LANDSCAPE}, {@link Configuration#ORIENTATION_PORTRAIT}. * @return */ @Nullable - Result analyze(@NonNull ImageProxy image,int orientation); + Result analyze(@NonNull ImageProxy image, int orientation); } diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java index 9370b44..af49679 100644 --- a/zxing-lite/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java +++ b/zxing-lite/src/main/java/com/king/zxing/analyze/AreaRectAnalyzer.java @@ -13,26 +13,28 @@ import java.util.Map; import androidx.annotation.Nullable; /** + * 矩阵区域分析器:主要用于锁定具体的识别区域 + * * @author Jenly */ public abstract class AreaRectAnalyzer extends ImageAnalyzer { DecodeConfig mDecodeConfig; - Map mHints; + 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){ + public AreaRectAnalyzer(@Nullable DecodeConfig config) { this.mDecodeConfig = config; - if(config != null){ + if (config != null) { mHints = config.getHints(); isMultiDecode = config.isMultiDecode(); mAreaRectRatio = config.getAreaRectRatio(); mAreaRectHorizontalOffset = config.getAreaRectHorizontalOffset(); mAreaRectVerticalOffset = config.getAreaRectVerticalOffset(); - }else{ + } else { mHints = DecodeFormatManager.DEFAULT_HINTS; } @@ -41,28 +43,28 @@ public abstract class AreaRectAnalyzer extends ImageAnalyzer { @Nullable @Override public Result analyze(byte[] data, int width, int height) { - if(mDecodeConfig != null){ - if(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()); + if (rect != null) {// 如果分析区域不为空,则使用指定的区域进行扫码识别 + return analyze(data, width, height, rect.left, rect.top, rect.width(), rect.height()); } } - //如果分析区域为空,则通过识别区域比例和相关的偏移量计算出最终的区域进行扫码识别 - int size = (int)(Math.min(width,height) * mAreaRectRatio); - int left = (width-size)/2 + mAreaRectHorizontalOffset; - int top = (height-size)/2 + mAreaRectVerticalOffset; + // 如果分析区域为空,则通过识别区域比例和相关的偏移量计算出最终的区域进行扫码识别 + 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); + return analyze(data, width, height, left, top, size, size); } @Nullable - public abstract Result analyze(byte[] data, int dataWidth, int dataHeight,int left,int top,int width,int height); + public abstract Result analyze(byte[] data, int dataWidth, int dataHeight, int left, int top, int width, int height); } diff --git a/zxing-lite/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java b/zxing-lite/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java index a4a792e..1583e1f 100644 --- a/zxing-lite/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java +++ b/zxing-lite/src/main/java/com/king/zxing/analyze/MultiFormatAnalyzer.java @@ -11,23 +11,24 @@ import com.google.zxing.common.HybridBinarizer; import com.king.zxing.DecodeConfig; import com.king.zxing.util.LogUtils; - import java.util.Map; import androidx.annotation.Nullable; /** + * 多格式分析器:主要用于分析识别条形码/二维码 + * * @author Jenly */ public class MultiFormatAnalyzer extends AreaRectAnalyzer { MultiFormatReader mReader; - public MultiFormatAnalyzer(){ - this((DecodeConfig)null); + public MultiFormatAnalyzer() { + this((DecodeConfig) null); } - public MultiFormatAnalyzer(@Nullable Map hints){ + public MultiFormatAnalyzer(@Nullable Map hints) { this(new DecodeConfig().setHints(hints)); } @@ -36,62 +37,62 @@ public class MultiFormatAnalyzer extends AreaRectAnalyzer { initReader(); } - private void initReader(){ + private void initReader() { mReader = new MultiFormatReader(); } @Nullable @Override - public Result analyze(byte[] data, int dataWidth, int dataHeight,int left,int top,int width,int height) { + public Result analyze(byte[] data, int dataWidth, int dataHeight, int left, int top, int width, int height) { Result rawResult = null; try { long start = System.currentTimeMillis(); mReader.setHints(mHints); - PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data,dataWidth,dataHeight,left,top,width,height,false); - rawResult = decodeInternal(source,isMultiDecode); + PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, dataWidth, dataHeight, left, top, width, height, false); + rawResult = decodeInternal(source, isMultiDecode); - if(rawResult == null && mDecodeConfig != null){ - if(rawResult == null && mDecodeConfig.isSupportVerticalCode()){ + if (rawResult == null && mDecodeConfig != null) { + 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()); + rawResult = decodeInternal(new PlanarYUVLuminanceSource(rotatedData, dataHeight, dataWidth, top, left, height, width, false), mDecodeConfig.isSupportVerticalCodeMultiDecode()); } - if(rawResult == null && mDecodeConfig.isSupportLuminanceInvert()){ - rawResult = decodeInternal(source.invert(),mDecodeConfig.isSupportLuminanceInvertMultiDecode()); + if (rawResult == null && mDecodeConfig.isSupportLuminanceInvert()) { + rawResult = decodeInternal(source.invert(), mDecodeConfig.isSupportLuminanceInvertMultiDecode()); } } - if(rawResult != null){ + if (rawResult != null) { long end = System.currentTimeMillis(); LogUtils.d("Found barcode in " + (end - start) + " ms"); } } catch (Exception e) { - }finally { + } finally { mReader.reset(); } return rawResult; } - private Result decodeInternal(LuminanceSource source,boolean isMultiDecode){ + private Result decodeInternal(LuminanceSource source, boolean isMultiDecode) { Result result = null; - try{ - try{ - //采用HybridBinarizer解析 + try { + try { + // 采用HybridBinarizer解析 result = mReader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source))); - }catch (Exception e){ + } catch (Exception e) { } - if(isMultiDecode && result == null){ - //如果没有解析成功,再采用GlobalHistogramBinarizer解析一次 + if (isMultiDecode && result == null) { + // 如果没有解析成功,再采用GlobalHistogramBinarizer解析一次 result = mReader.decodeWithState(new BinaryBitmap(new GlobalHistogramBinarizer(source))); } - }catch (Exception e){ + } catch (Exception e) { } return result; diff --git a/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java index 269716e..a12030d 100644 --- a/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java +++ b/zxing-lite/src/main/java/com/king/zxing/config/AspectRatioCameraConfig.java @@ -3,7 +3,6 @@ package com.king.zxing.config; import android.content.Context; import android.util.DisplayMetrics; - import com.king.zxing.util.LogUtils; import androidx.annotation.NonNull; @@ -13,7 +12,8 @@ import androidx.camera.core.ImageAnalysis; import androidx.camera.core.Preview; /** - * 相机配置:根据纵横比配置相机,使输出分析的图像尽可能的接近屏幕比例 + * 相机配置:根据纵横比配置相机,使输出分析的图像尽可能的接近屏幕的比例 + * * @author Jenly */ public final class AspectRatioCameraConfig extends CameraConfig { @@ -22,22 +22,26 @@ public final class AspectRatioCameraConfig extends CameraConfig { public AspectRatioCameraConfig(Context context) { super(); + initTargetAspectRatio(context); + } + /** + * 初始化 {@link #mAspectRatio} + * + * @param context + */ + private void initTargetAspectRatio(Context context) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); int width = displayMetrics.widthPixels; int height = displayMetrics.heightPixels; - mAspectRatio = aspectRatio(width, height); - LogUtils.d("aspectRatio:" + mAspectRatio); - - } - - private int aspectRatio(float width, float height){ float ratio = Math.max(width, height) / Math.min(width, height); - if (Math.abs(ratio - 4.0f / 3.0f) < Math.abs(ratio - 16.0f / 9.0f)) { - return AspectRatio.RATIO_4_3; + if (Math.abs(ratio - 4.0F / 3.0F) < Math.abs(ratio - 16.0F / 9.0F)) { + mAspectRatio = AspectRatio.RATIO_4_3; + } else { + mAspectRatio = AspectRatio.RATIO_16_9; } - return AspectRatio.RATIO_16_9; + LogUtils.d("aspectRatio:" + mAspectRatio); } @NonNull @@ -59,3 +63,4 @@ public final class AspectRatioCameraConfig extends CameraConfig { return super.options(builder); } } + diff --git a/zxing-lite/src/main/java/com/king/zxing/config/CameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/config/CameraConfig.java index 8a36749..769db4e 100644 --- a/zxing-lite/src/main/java/com/king/zxing/config/CameraConfig.java +++ b/zxing-lite/src/main/java/com/king/zxing/config/CameraConfig.java @@ -6,28 +6,75 @@ import androidx.camera.core.ImageAnalysis; import androidx.camera.core.Preview; /** - * 相机配置:主要用于提供相机预览时可自定义一些配置,便于扩展 + * 相机配置:主要用于提供相机预览时可自定义一些配置,便于拓展; + *

+ * 库中内置实现{@link CameraConfig}的有{@link AspectRatioCameraConfig}和{@link ResolutionCameraConfig}; + *

+ * 这里简单说下各自的特点: + *

+ * {@link CameraConfig} - 默认的相机配置 + *

+ * {@link AspectRatioCameraConfig} - 根据纵横比配置相机,使输出分析的图像尽可能的接近屏幕的比例 + *

+ * {@link ResolutionCameraConfig} - 根据尺寸配置相机的目标图像大小,使输出分析的图像的分辨率尽可能的接近屏幕尺寸 + *

+ * 当使用默认的 {@link CameraConfig}在某些机型上体验欠佳时,你可以尝试使用{@link AspectRatioCameraConfig}或 + * {@link ResolutionCameraConfig}会有意想不到奇效。 + *

+ * 你也可以自定义或覆写 {@link CameraConfig} 中的 {@link #options} 方法,根据需要定制配置。 + * * @author Jenly */ public class CameraConfig { - public CameraConfig(){ + public CameraConfig() { } + /** + * 配置 {@link Preview.Builder};可参考:{@link AspectRatioCameraConfig} 或 {@link ResolutionCameraConfig} + *

+ * 如配置目标旋转角度为90度:{@code builder.setTargetRotation(Surface.ROTATION_90)} + *

+ * 切记,外部请勿直接调用 {@link #options(Preview.Builder)} + * + * @param builder + * @return + */ @NonNull - public Preview options(@NonNull Preview.Builder builder){ + public Preview options(@NonNull Preview.Builder builder) { return builder.build(); } + /** + * 配置 {@link CameraSelector.Builder};可参考:{@link AspectRatioCameraConfig} 或 {@link ResolutionCameraConfig} + *

+ * 如配置前置摄像头:{@code builder.requireLensFacing(CameraSelector.LENS_FACING_FRONT)} + *

+ * 切记,外部请勿直接调用 {@link #options(CameraSelector.Builder)} + * + * @param builder + * @return + */ @NonNull - public CameraSelector options(@NonNull CameraSelector.Builder builder){ + public CameraSelector options(@NonNull CameraSelector.Builder builder) { return builder.build(); } + /** + * 配置 {@link ImageAnalysis.Builder};可参考:{@link AspectRatioCameraConfig} 或 {@link ResolutionCameraConfig} + *

+ * 如配置目标旋转角度为90度:{@code builder.setTargetRotation(Surface.ROTATION_90)} + *

+ * 切记,外部请勿直接调用 {@link #options(ImageAnalysis.Builder)} + * + * @param builder + * @return + */ @NonNull - public ImageAnalysis options(@NonNull ImageAnalysis.Builder builder){ + public ImageAnalysis options(@NonNull ImageAnalysis.Builder builder) { return builder.build(); } } + diff --git a/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java b/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java index b783641..5239679 100644 --- a/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java +++ b/zxing-lite/src/main/java/com/king/zxing/config/ResolutionCameraConfig.java @@ -4,53 +4,89 @@ import android.content.Context; import android.util.DisplayMetrics; import android.util.Size; - import com.king.zxing.util.LogUtils; +import java.util.Locale; + import androidx.annotation.NonNull; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageAnalysis; import androidx.camera.core.Preview; /** - * 相机配置:根据尺寸配置相机的目标图像,使输出分析的图像尽可能的接近屏幕尺寸 + * 相机配置:根据尺寸配置相机的目标图像大小,使输出分析的图像的分辨率尽可能的接近屏幕尺寸 + * * @author Jenly */ public class ResolutionCameraConfig extends CameraConfig { - private Size mTargetSize; - - public ResolutionCameraConfig(Context context) { - super(); + /** + * 1080P + */ + public static final int IMAGE_QUALITY_1080P = 1080; + /** + * 720P + */ + public static final int IMAGE_QUALITY_720P = 720; + + private Size mTargetSize; + + /** + * 构造 + * + * @param context 上下文 + */ + public ResolutionCameraConfig(Context context) { + this(context, IMAGE_QUALITY_1080P); + } + + /** + * 构造 + * + * @param context 上下文 + * @param imageQuality 图像质量;此参数只是期望的图像质量,最终以实际计算结果为准 + */ + public ResolutionCameraConfig(Context context, int imageQuality) { + super(); + initTargetResolutionSize(context, imageQuality); + } + + /** + * 初始化 {@link #mTargetSize} + * + * @param context 上下文 + * @param imageQuality 图像质量;此参数只是期望的图像质量,最终以实际计算结果为准 + */ + private void initTargetResolutionSize(Context context, int imageQuality) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); int width = displayMetrics.widthPixels; int height = displayMetrics.heightPixels; - LogUtils.d(String.format("displayMetrics:%d x %d",width,height)); - //因为为了保持流畅性和性能,限制在1080p,在此前提下尽可能的找到屏幕接近的分辨率 - if(width < height){ - int size = Math.min(width, 1080); - float ratio = width / (float)height; - if(ratio > 0.7){//一般应用于平板 - mTargetSize = new Size(size, (int)(size / 3.0f * 4.0f)); - }else{ - mTargetSize = new Size(size, (int)(size / 9.0f * 16.0f)); + LogUtils.d(String.format(Locale.getDefault(), "displayMetrics:%d x %d", width, height)); + // 因为为了保持流畅性和性能,尽可能的限制在imageQuality(默认:1080p),在此前提下尽可能的找到屏幕接近的分辨率 + if (width < height) { + int size = Math.min(width, imageQuality); + float ratio = width / (float) height; + if (ratio > 0.7F) { + // 一般应用于平板 + mTargetSize = new Size(size, (int) (size / 3.0F * 4.0F)); + } else { + mTargetSize = new Size(size, (int) (size / 9.0F * 16.0F)); } - }else{ - int size = Math.min(height, 1080); - float ratio = height / (float)width; - if(ratio > 0.7){//一般应用于平板 - mTargetSize = new Size((int)(size / 3.0f * 4.0f), size); - }else{ - mTargetSize = new Size((int)(size / 9.0f * 16.0), size); + } else { + int size = Math.min(height, imageQuality); + float ratio = height / (float) width; + if (ratio > 0.7F) { + // 一般应用于平板 + mTargetSize = new Size((int) (size / 3.0F * 4.0F), size); + } else { + mTargetSize = new Size((int) (size / 9.0F * 16.0F), size); } } LogUtils.d("targetSize:" + mTargetSize); } - - @NonNull @Override public Preview options(@NonNull Preview.Builder builder) { diff --git a/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java b/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java index 919a6e8..8db276c 100644 --- a/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java +++ b/zxing-lite/src/main/java/com/king/zxing/manager/AmbientLightManager.java @@ -1,22 +1,5 @@ package com.king.zxing.manager; -/* - * Copyright (C) 2012 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; @@ -30,8 +13,8 @@ public class AmbientLightManager implements SensorEventListener { private static final int INTERVAL_TIME = 200; - protected static final float DARK_LUX = 45.0f; - protected static final float BRIGHT_LUX = 100.0f; + protected static final float DARK_LUX = 45.0F; + protected static final float BRIGHT_LUX = 100.0F; /** * 光线太暗时,默认:照度45 lux @@ -72,9 +55,10 @@ public class AmbientLightManager implements SensorEventListener { @Override public void onSensorChanged(SensorEvent sensorEvent) { - if(isLightSensorEnabled){ + if (isLightSensorEnabled) { long currentTime = System.currentTimeMillis(); - if(currentTime - lastTime < INTERVAL_TIME){//降低频率 + if (currentTime - lastTime < INTERVAL_TIME) { + // 降低频率 return; } lastTime = currentTime; @@ -83,9 +67,9 @@ public class AmbientLightManager implements SensorEventListener { float lightLux = sensorEvent.values[0]; mOnLightSensorEventListener.onSensorChanged(lightLux); if (lightLux <= darkLightLux) { - mOnLightSensorEventListener.onSensorChanged(true,lightLux); + mOnLightSensorEventListener.onSensorChanged(true, lightLux); } else if (lightLux >= brightLightLux) { - mOnLightSensorEventListener.onSensorChanged(false,lightLux); + mOnLightSensorEventListener.onSensorChanged(false, lightLux); } } } @@ -93,17 +77,19 @@ public class AmbientLightManager implements SensorEventListener { /** * 设置光线足够暗的阈值(单位:lux) + * * @param lightLux */ - public void setDarkLightLux(float lightLux){ + public void setDarkLightLux(float lightLux) { this.darkLightLux = lightLux; } /** * 设置光线足够明亮的阈值(单位:lux) + * * @param lightLux */ - public void setBrightLightLux(float lightLux){ + public void setBrightLightLux(float lightLux) { this.brightLightLux = lightLux; } @@ -118,6 +104,7 @@ public class AmbientLightManager implements SensorEventListener { /** * 设置是否启用光线亮度传感器 + * * @param lightSensorEnabled */ public void setLightSensorEnabled(boolean lightSensorEnabled) { @@ -126,26 +113,27 @@ public class AmbientLightManager implements SensorEventListener { /** * 设置光线亮度传感器监听器,只有在 {@link #isLightSensorEnabled} 为{@code true} 才有效 + * * @param listener */ - public void setOnLightSensorEventListener(OnLightSensorEventListener listener){ + public void setOnLightSensorEventListener(OnLightSensorEventListener listener) { mOnLightSensorEventListener = listener; } - public interface OnLightSensorEventListener{ + public interface OnLightSensorEventListener { /** - * * @param lightLux 当前检测到的光线照度值 */ - default void onSensorChanged(float lightLux){ + default void onSensorChanged(float lightLux) { } /** * 传感器改变事件 - * @param dark 是否太暗了,当检测到的光线照度值小于{@link #darkLightLux}时,为{@code true} + * + * @param dark 是否太暗了,当检测到的光线照度值小于{@link #darkLightLux}时,为{@code true} * @param lightLux 当前检测到的光线照度值 */ - void onSensorChanged(boolean dark,float lightLux); + void onSensorChanged(boolean dark, float lightLux); } -} +} \ No newline at end of file diff --git a/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java index dc2b892..b9dd88c 100644 --- a/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java +++ b/zxing-lite/src/main/java/com/king/zxing/manager/BeepManager.java @@ -1,24 +1,7 @@ package com.king.zxing.manager; -/* - * Copyright (C) 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - import android.content.Context; import android.content.res.AssetFileDescriptor; -import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Build; import android.os.VibrationEffect; @@ -28,7 +11,6 @@ import com.king.zxing.R; import com.king.zxing.util.LogUtils; import java.io.Closeable; -import java.lang.annotation.ElementType; /** * @author Jenly @@ -49,11 +31,11 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable updatePrefs(); } - public void setVibrate(boolean vibrate){ + public void setVibrate(boolean vibrate) { this.vibrate = vibrate; } - public void setPlayBeep(boolean playBeep){ + public void setPlayBeep(boolean playBeep) { this.playBeep = playBeep; } @@ -61,8 +43,8 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable if (mediaPlayer == null) { mediaPlayer = buildMediaPlayer(context); } - if(vibrator == null){ - vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); + if (vibrator == null) { + vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } } @@ -85,7 +67,6 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable AssetFileDescriptor file = context.getResources().openRawResourceFd(R.raw.zxl_beep); mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); mediaPlayer.setOnErrorListener(this); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setLooping(false); mediaPlayer.prepare(); return mediaPlayer; @@ -105,12 +86,12 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable @Override public synchronized void close() { - try{ + try { if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } - }catch (Exception e){ + } catch (Exception e) { LogUtils.e(e); } } diff --git a/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java index 513b21a..7d9be52 100644 --- a/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java +++ b/zxing-lite/src/main/java/com/king/zxing/util/CodeUtils.java @@ -48,8 +48,9 @@ import com.king.zxing.DecodeFormatManager; import java.util.HashMap; import java.util.Map; - /** + * 二维码/条形码工具类:主要包括二维码/条形码的解析与生成 + * * @author Jenly Jenly */ public final class CodeUtils { @@ -57,108 +58,115 @@ public final class CodeUtils { public static final int DEFAULT_REQ_WIDTH = 480; public static final int DEFAULT_REQ_HEIGHT = 640; - private CodeUtils(){ + private CodeUtils() { throw new AssertionError(); } /** * 生成二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 * @return */ public static Bitmap createQRCode(String content, int heightPix) { - return createQRCode(content,heightPix,null); + return createQRCode(content, heightPix, null); } /** * 生成二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 * @param codeColor 二维码的颜色 * @return */ - public static Bitmap createQRCode(String content, int heightPix,int codeColor) { - return createQRCode(content,heightPix,null,codeColor); + public static Bitmap createQRCode(String content, int heightPix, int codeColor) { + return createQRCode(content, heightPix, null, codeColor); } /** * 生成我二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 - * @param logo logo大小默认占二维码的20% + * @param logo logo大小默认占二维码的20% * @return */ public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) { - return createQRCode(content,heightPix,logo,Color.BLACK); + return createQRCode(content, heightPix, logo, Color.BLACK); } /** * 生成我二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 - * @param logo logo大小默认占二维码的20% + * @param logo logo大小默认占二维码的20% * @param codeColor 二维码的颜色 * @return */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,int codeColor) { - return createQRCode(content,heightPix,logo,0.2f,codeColor); + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo, int codeColor) { + return createQRCode(content, heightPix, logo, 0.2f, codeColor); } /** * 生成二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @return */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio) { + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo, @FloatRange(from = 0.0f, to = 1.0f) float ratio) { //配置参数 Map hints = new HashMap<>(); - hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //容错级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //设置空白边距的宽度 hints.put(EncodeHintType.MARGIN, 1); //default is 4 - return createQRCode(content,heightPix,logo,ratio,hints); + return createQRCode(content, heightPix, logo, ratio, hints); } /** * 生成二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @param codeColor 二维码的颜色 * @return */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,int codeColor) { + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo, @FloatRange(from = 0.0f, to = 1.0f) float ratio, int codeColor) { //配置参数 Map hints = new HashMap<>(); - hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); //容错级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //设置空白边距的宽度 hints.put(EncodeHintType.MARGIN, 1); //default is 1 - return createQRCode(content,heightPix,logo,ratio,hints,codeColor); + return createQRCode(content, heightPix, logo, ratio, hints, codeColor); } - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints) { - return createQRCode(content,heightPix,logo,ratio,hints,Color.BLACK); + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo, @FloatRange(from = 0.0f, to = 1.0f) float ratio, Map hints) { + return createQRCode(content, heightPix, logo, ratio, hints, Color.BLACK); } /** * 生成二维码 - * @param content 二维码的内容 + * + * @param content 二维码的内容 * @param heightPix 二维码的高 - * @param logo 二维码中间的logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param logo 二维码中间的logo + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @param hints * @param codeColor 二维码的颜色 * @return */ - public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map hints,int codeColor) { + public static Bitmap createQRCode(String content, int heightPix, Bitmap logo, @FloatRange(from = 0.0f, to = 1.0f) float ratio, Map hints, int codeColor) { try { // 图像数据转换,使用了矩阵转换 @@ -181,7 +189,7 @@ public final class CodeUtils { bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); if (logo != null) { - bitmap = addLogo(bitmap, logo,ratio); + bitmap = addLogo(bitmap, logo, ratio); } return bitmap; @@ -194,12 +202,13 @@ public final class CodeUtils { /** * 在二维码中间添加Logo图案 + * * @param src * @param logo - * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 + * @param ratio logo所占比例 因为二维码的最大容错率为30%,所以建议ratio的范围小于0.3 * @return */ - private static Bitmap addLogo(Bitmap src, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f) float ratio) { + private static Bitmap addLogo(Bitmap src, Bitmap logo, @FloatRange(from = 0.0f, to = 1.0f) float ratio) { if (src == null) { return null; } @@ -243,12 +252,13 @@ public final class CodeUtils { /** * 解析二维码图片 + * * @param bitmapPath 需要解析的图片路径 * @return */ - public static String parseQRCode(String bitmapPath){ + public static String parseQRCode(String bitmapPath) { Result result = parseQRCodeResult(bitmapPath); - if(result != null){ + if (result != null) { return result.getText(); } return null; @@ -256,42 +266,46 @@ public final class CodeUtils { /** * 解析二维码图片 + * * @param bitmapPath 需要解析的图片路径 * @return */ - public static Result parseQRCodeResult(String bitmapPath){ - return parseQRCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT); + public static Result parseQRCodeResult(String bitmapPath) { + return parseQRCodeResult(bitmapPath, DEFAULT_REQ_WIDTH, DEFAULT_REQ_HEIGHT); } /** * 解析二维码图片 + * * @param bitmapPath 需要解析的图片路径 - * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 * @return */ - public static Result parseQRCodeResult(String bitmapPath,int reqWidth,int reqHeight){ - return parseCodeResult(bitmapPath,reqWidth,reqHeight, DecodeFormatManager.QR_CODE_HINTS); + public static Result parseQRCodeResult(String bitmapPath, int reqWidth, int reqHeight) { + return parseCodeResult(bitmapPath, reqWidth, reqHeight, DecodeFormatManager.QR_CODE_HINTS); } /** * 解析一维码/二维码图片 + * * @param bitmapPath 需要解析的图片路径 * @return */ - public static String parseCode(String bitmapPath){ + public static String parseCode(String bitmapPath) { return parseCode(bitmapPath, DecodeFormatManager.ALL_HINTS); } /** * 解析一维码/二维码图片 + * * @param bitmapPath 需要解析的图片路径 - * @param hints 解析编码类型 + * @param hints 解析编码类型 * @return */ - public static String parseCode(String bitmapPath, Map hints){ - Result result = parseCodeResult(bitmapPath,hints); - if(result != null){ + public static String parseCode(String bitmapPath, Map hints) { + Result result = parseCodeResult(bitmapPath, hints); + if (result != null) { return result.getText(); } return null; @@ -299,31 +313,34 @@ public final class CodeUtils { /** * 解析二维码图片 + * * @param bitmap 解析的图片 * @return */ - public static String parseQRCode(Bitmap bitmap){ - return parseCode(bitmap,DecodeFormatManager.QR_CODE_HINTS); + public static String parseQRCode(Bitmap bitmap) { + return parseCode(bitmap, DecodeFormatManager.QR_CODE_HINTS); } /** * 解析一维码/二维码图片 + * * @param bitmap 解析的图片 * @return */ - public static String parseCode(Bitmap bitmap){ - return parseCode(bitmap,DecodeFormatManager.ALL_HINTS); + public static String parseCode(Bitmap bitmap) { + return parseCode(bitmap, DecodeFormatManager.ALL_HINTS); } /** * 解析一维码/二维码图片 + * * @param bitmap 解析的图片 - * @param hints 解析编码类型 + * @param hints 解析编码类型 * @return */ - public static String parseCode(Bitmap bitmap,Map hints){ - Result result = parseCodeResult(bitmap,hints); - if(result != null){ + public static String parseCode(Bitmap bitmap, Map hints) { + Result result = parseCodeResult(bitmap, hints); + if (result != null) { return result.getText(); } return null; @@ -331,103 +348,108 @@ public final class CodeUtils { /** * 解析一维码/二维码图片 + * * @param bitmapPath - * @param hints 解析编码类型 + * @param hints 解析编码类型 * @return */ - public static Result parseCodeResult(String bitmapPath, Map hints){ - return parseCodeResult(bitmapPath,DEFAULT_REQ_WIDTH,DEFAULT_REQ_HEIGHT,hints); + public static Result parseCodeResult(String bitmapPath, Map hints) { + return parseCodeResult(bitmapPath, DEFAULT_REQ_WIDTH, DEFAULT_REQ_HEIGHT, hints); } /** * 解析一维码/二维码图片 + * * @param bitmapPath 需要解析的图片路径 - * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 - * @param hints 解析编码类型 + * @param reqWidth 请求目标宽度,如果实际图片宽度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param reqHeight 请求目标高度,如果实际图片高度大于此值,会自动进行压缩处理,当 reqWidth 和 reqHeight都小于或等于0时,则不进行压缩处理 + * @param hints 解析编码类型 * @return */ - public static Result parseCodeResult(String bitmapPath,int reqWidth,int reqHeight, Map hints){ - return parseCodeResult(compressBitmap(bitmapPath,reqWidth,reqHeight),hints); + public static Result parseCodeResult(String bitmapPath, int reqWidth, int reqHeight, Map hints) { + return parseCodeResult(compressBitmap(bitmapPath, reqWidth, reqHeight), hints); } /** * 解析一维码/二维码图片 + * * @param bitmap 解析的图片 * @return */ - public static Result parseCodeResult(Bitmap bitmap){ - return parseCodeResult(getRGBLuminanceSource(bitmap),DecodeFormatManager.ALL_HINTS); + public static Result parseCodeResult(Bitmap bitmap) { + return parseCodeResult(getRGBLuminanceSource(bitmap), DecodeFormatManager.ALL_HINTS); } /** * 解析一维码/二维码图片 + * * @param bitmap 解析的图片 - * @param hints 解析编码类型 + * @param hints 解析编码类型 * @return */ - public static Result parseCodeResult(Bitmap bitmap,Map hints){ - return parseCodeResult(getRGBLuminanceSource(bitmap),hints); + public static Result parseCodeResult(Bitmap bitmap, Map hints) { + return parseCodeResult(getRGBLuminanceSource(bitmap), hints); } /** * 解析一维码/二维码图片 + * * @param source * @param hints * @return */ - public static Result parseCodeResult(LuminanceSource source, Map hints){ + public static Result parseCodeResult(LuminanceSource source, Map hints) { Result result = null; MultiFormatReader reader = new MultiFormatReader(); - try{ + try { reader.setHints(hints); if (source != null) { - result = decodeInternal(reader,source); - if(result == null){ - result = decodeInternal(reader,source.invert()); + result = decodeInternal(reader, source); + if (result == null) { + result = decodeInternal(reader, source.invert()); } - if(result == null && source.isRotateSupported()){ - result = decodeInternal(reader,source.rotateCounterClockwise()); + if (result == null && source.isRotateSupported()) { + result = decodeInternal(reader, source.rotateCounterClockwise()); } } - }catch (Exception e){ + } catch (Exception e) { LogUtils.w(e.getMessage()); - }finally { + } finally { reader.reset(); } return result; } - private static Result decodeInternal(MultiFormatReader reader,LuminanceSource source){ + private static Result decodeInternal(MultiFormatReader reader, LuminanceSource source) { Result result = null; - try{ - try{ + try { + try { //采用HybridBinarizer解析 result = reader.decodeWithState(new BinaryBitmap(new HybridBinarizer(source))); - }catch (Exception e){ + } catch (Exception e) { } - if(result == null){ + if (result == null) { //如果没有解析成功,再采用GlobalHistogramBinarizer解析一次 result = reader.decodeWithState(new BinaryBitmap(new GlobalHistogramBinarizer(source))); } - }catch (Exception e){ + } catch (Exception e) { } return result; } - /** * 压缩图片 + * * @param path * @return */ - private static Bitmap compressBitmap(String path,int reqWidth,int reqHeight){ - if(reqWidth > 0 && reqHeight > 0){//都大于进行判断是否压缩 + private static Bitmap compressBitmap(String path, int reqWidth, int reqHeight) { + if (reqWidth > 0 && reqHeight > 0) {//都大于进行判断是否压缩 BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 开始读入图片,此时把options.inJustDecodeBounds 设回true了 @@ -444,7 +466,7 @@ public final class CodeUtils { if (height > reqHeight) {// 如果高度高的话根据宽度固定大小缩放 hSize = (int) (height / reqHeight); } - int size = Math.max(wSize,hSize); + int size = Math.max(wSize, hSize); if (size <= 0) size = 1; newOpts.inSampleSize = size;// 设置缩放比例 @@ -461,10 +483,11 @@ public final class CodeUtils { /** * 获取RGBLuminanceSource + * * @param bitmap * @return */ - private static RGBLuminanceSource getRGBLuminanceSource(@NonNull Bitmap bitmap){ + private static RGBLuminanceSource getRGBLuminanceSource(@NonNull Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); @@ -476,33 +499,36 @@ public final class CodeUtils { /** * 生成条形码 + * * @param content * @param desiredWidth * @param desiredHeight * @return */ public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null); + return createBarCode(content, BarcodeFormat.CODE_128, desiredWidth, desiredHeight, null); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth * @param desiredHeight * @return */ - public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight) { - return createBarCode(content,format,desiredWidth,desiredHeight,null); + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight) { + return createBarCode(content, format, desiredWidth, desiredHeight, null); } public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,Color.BLACK); + return createBarCode(content, BarcodeFormat.CODE_128, desiredWidth, desiredHeight, null, isShowText, 40, Color.BLACK); } /** * 生成条形码 + * * @param content * @param desiredWidth * @param desiredHeight @@ -510,12 +536,13 @@ public final class CodeUtils { * @param codeColor * @return */ - public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,BarcodeFormat.CODE_128,desiredWidth,desiredHeight,null,isShowText,40,codeColor); + public static Bitmap createBarCode(String content, int desiredWidth, int desiredHeight, boolean isShowText, @ColorInt int codeColor) { + return createBarCode(content, BarcodeFormat.CODE_128, desiredWidth, desiredHeight, null, isShowText, 40, codeColor); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth @@ -523,12 +550,13 @@ public final class CodeUtils { * @param hints * @return */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,false,40,Color.BLACK); + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints) { + return createBarCode(content, format, desiredWidth, desiredHeight, hints, false, 40, Color.BLACK); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth @@ -537,12 +565,13 @@ public final class CodeUtils { * @param isShowText * @return */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,Color.BLACK); + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText) { + return createBarCode(content, format, desiredWidth, desiredHeight, hints, isShowText, 40, Color.BLACK); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth @@ -551,12 +580,13 @@ public final class CodeUtils { * @param codeColor * @return */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,format,desiredWidth,desiredHeight,null,isShowText,40,codeColor); + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, boolean isShowText, @ColorInt int codeColor) { + return createBarCode(content, format, desiredWidth, desiredHeight, null, isShowText, 40, codeColor); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth @@ -565,12 +595,13 @@ public final class CodeUtils { * @param isShowText * @return */ - public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText,@ColorInt int codeColor) { - return createBarCode(content,format,desiredWidth,desiredHeight,hints,isShowText,40,codeColor); + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText, @ColorInt int codeColor) { + return createBarCode(content, format, desiredWidth, desiredHeight, hints, isShowText, 40, codeColor); } /** * 生成条形码 + * * @param content * @param format * @param desiredWidth @@ -581,8 +612,8 @@ public final class CodeUtils { * @param codeColor * @return */ - public static Bitmap createBarCode(String content,BarcodeFormat format, int desiredWidth, int desiredHeight,Map hints,boolean isShowText,int textSize,@ColorInt int codeColor) { - if(TextUtils.isEmpty(content)){ + public static Bitmap createBarCode(String content, BarcodeFormat format, int desiredWidth, int desiredHeight, Map hints, boolean isShowText, int textSize, @ColorInt int codeColor) { + if (TextUtils.isEmpty(content)) { return null; } final int WHITE = Color.WHITE; @@ -606,8 +637,8 @@ public final class CodeUtils { Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); - if(isShowText){ - return addCode(bitmap,content,textSize,codeColor,textSize/2); + if (isShowText) { + return addCode(bitmap, content, textSize, codeColor, textSize / 2); } return bitmap; } catch (WriterException e) { @@ -618,6 +649,7 @@ public final class CodeUtils { /** * 条形码下面添加文本信息 + * * @param src * @param code * @param textSize @@ -650,7 +682,7 @@ public final class CodeUtils { paint.setTextSize(textSize); paint.setColor(textColor); paint.setTextAlign(Paint.Align.CENTER); - canvas.drawText(code,srcWidth/2,srcHeight + textSize /2 + offset,paint); + canvas.drawText(code, srcWidth / 2, srcHeight + textSize / 2 + offset, paint); canvas.save(); canvas.restore(); } catch (Exception e) { @@ -662,5 +694,4 @@ public final class CodeUtils { } - } \ No newline at end of file diff --git a/zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java index cb49719..3007af9 100644 --- a/zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java +++ b/zxing-lite/src/main/java/com/king/zxing/util/LogUtils.java @@ -16,9 +16,10 @@ */ package com.king.zxing.util; - import android.util.Log; +import java.util.Locale; + /** * @author Jenly Jenly */ @@ -28,10 +29,14 @@ public class LogUtils { public static final String VERTICAL = "|"; - /** 是否显示Log日志 */ + /** + * 是否显示Log日志 + */ private static boolean isShowLog = true; - /** Log日志优先权 */ + /** + * Log日志优先权 + */ private static int priority = 1; /** @@ -71,7 +76,7 @@ public class LogUtils { public static final String TAG_FORMAT = "%s.%s(%s:%d)"; - private LogUtils(){ + private LogUtils() { throw new AssertionError(); } @@ -97,24 +102,25 @@ public class LogUtils { /** * 根据堆栈生成TAG + * * @return TAG|className.methodName(fileName:lineNumber) */ private static String generateTag(StackTraceElement caller) { String tag = TAG_FORMAT; String callerClazzName = caller.getClassName(); callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1); - tag = String.format(tag,callerClazzName, caller.getMethodName(),caller.getFileName(),caller.getLineNumber()); + tag = String.format(Locale.getDefault(), tag, callerClazzName, caller.getMethodName(), caller.getFileName(), caller.getLineNumber()); return new StringBuilder().append(TAG).append(VERTICAL).append(tag).toString(); } /** * 获取堆栈 - * @param n - * n=0 VMStack - * n=1 Thread - * n=3 CurrentStack - * n=4 CallerStack - * ... + * + * @param n n=0 VMStack + * n=1 Thread + * n=3 CurrentStack + * n=4 CallerStack + * ... * @return */ public static StackTraceElement getStackTraceElement(int n) { @@ -123,18 +129,18 @@ public class LogUtils { /** * 获取调用方的堆栈TAG + * * @return */ - private static String getCallerStackLogTag(){ + private static String getCallerStackLogTag() { return generateTag(getStackTraceElement(5)); } /** - * * @param t * @return */ - private static String getStackTraceString(Throwable t){ + private static String getStackTraceString(Throwable t) { return Log.getStackTraceString(t); } @@ -142,6 +148,7 @@ public class LogUtils { /** * Log.v + * * @param msg */ public static void v(String msg) { @@ -155,7 +162,7 @@ public class LogUtils { Log.v(getCallerStackLogTag(), getStackTraceString(t)); } - public static void v(String msg,Throwable t) { + public static void v(String msg, Throwable t) { if (isShowLog && priority <= VERBOSE) Log.v(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -164,6 +171,7 @@ public class LogUtils { /** * Log.d + * * @param msg */ public static void d(String msg) { @@ -176,7 +184,7 @@ public class LogUtils { Log.d(getCallerStackLogTag(), getStackTraceString(t)); } - public static void d(String msg,Throwable t) { + public static void d(String msg, Throwable t) { if (isShowLog && priority <= DEBUG) Log.d(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -185,6 +193,7 @@ public class LogUtils { /** * Log.i + * * @param msg */ public static void i(String msg) { @@ -197,7 +206,7 @@ public class LogUtils { Log.i(getCallerStackLogTag(), getStackTraceString(t)); } - public static void i(String msg,Throwable t) { + public static void i(String msg, Throwable t) { if (isShowLog && priority <= INFO) Log.i(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -206,6 +215,7 @@ public class LogUtils { /** * Log.w + * * @param msg */ public static void w(String msg) { @@ -218,7 +228,7 @@ public class LogUtils { Log.w(getCallerStackLogTag(), getStackTraceString(t)); } - public static void w(String msg,Throwable t) { + public static void w(String msg, Throwable t) { if (isShowLog && priority <= WARN) Log.w(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -227,6 +237,7 @@ public class LogUtils { /** * Log.e + * * @param msg */ public static void e(String msg) { @@ -239,7 +250,7 @@ public class LogUtils { Log.e(getCallerStackLogTag(), getStackTraceString(t)); } - public static void e(String msg,Throwable t) { + public static void e(String msg, Throwable t) { if (isShowLog && priority <= ERROR) Log.e(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -248,6 +259,7 @@ public class LogUtils { /** * Log.wtf + * * @param msg */ public static void wtf(String msg) { @@ -260,7 +272,7 @@ public class LogUtils { Log.wtf(getCallerStackLogTag(), getStackTraceString(t)); } - public static void wtf(String msg,Throwable t) { + public static void wtf(String msg, Throwable t) { if (isShowLog && priority <= ASSERT) Log.wtf(getCallerStackLogTag(), String.valueOf(msg), t); } @@ -312,3 +324,4 @@ public class LogUtils { } } + diff --git a/zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java b/zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java index cb880dd..88b406f 100644 --- a/zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java +++ b/zxing-lite/src/main/java/com/king/zxing/util/PermissionUtils.java @@ -14,72 +14,78 @@ import androidx.fragment.app.Fragment; */ public class PermissionUtils { - private PermissionUtils(){ + private PermissionUtils() { throw new AssertionError(); } /** * 检测是否授权 + * * @param context * @param permission * @return 返回{@code true} 表示已授权,{@code false}表示未授权 */ - public static boolean checkPermission(@NonNull Context context, @NonNull String permission){ - return ActivityCompat.checkSelfPermission(context,permission) == PackageManager.PERMISSION_GRANTED; + public static boolean checkPermission(@NonNull Context context, @NonNull String permission) { + return ActivityCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; } /** * 请求权限 + * * @param activity * @param permission * @param requestCode */ - public static void requestPermission(@NonNull Activity activity,@NonNull String permission, @IntRange(from = 0) int requestCode){ - requestPermissions(activity,new String[]{permission},requestCode); + public static void requestPermission(@NonNull Activity activity, @NonNull String permission, @IntRange(from = 0) int requestCode) { + requestPermissions(activity, new String[]{permission}, requestCode); } /** * 请求权限 + * * @param fragment * @param permission * @param requestCode */ - public static void requestPermission(@NonNull Fragment fragment, @NonNull String permission, @IntRange(from = 0) int requestCode){ - requestPermissions(fragment,new String[]{permission},requestCode); + public static void requestPermission(@NonNull Fragment fragment, @NonNull String permission, @IntRange(from = 0) int requestCode) { + requestPermissions(fragment, new String[]{permission}, requestCode); } /** * 请求权限 + * * @param activity * @param permissions * @param requestCode */ - public static void requestPermissions(@NonNull Activity activity,@NonNull String[] permissions, @IntRange(from = 0) int requestCode){ - ActivityCompat.requestPermissions(activity,permissions,requestCode); + public static void requestPermissions(@NonNull Activity activity, @NonNull String[] permissions, @IntRange(from = 0) int requestCode) { + ActivityCompat.requestPermissions(activity, permissions, requestCode); } /** * 请求权限 + * * @param fragment * @param permissions * @param requestCode */ - public static void requestPermissions(@NonNull Fragment fragment,@NonNull String[] permissions, @IntRange(from = 0) int requestCode){ - fragment.requestPermissions(permissions,requestCode); + public static void requestPermissions(@NonNull Fragment fragment, @NonNull String[] permissions, @IntRange(from = 0) int requestCode) { + fragment.requestPermissions(permissions, requestCode); } /** * 请求权限结果 + * * @param requestPermission 请求的权限 * @param permissions * @param grantResults * @return 返回{@code true} 表示已授权,{@code false}表示未授权 */ - public static boolean requestPermissionsResult(@NonNull String requestPermission, @NonNull String[] permissions, @NonNull int[] grantResults){ + public static boolean requestPermissionsResult(@NonNull String requestPermission, @NonNull String[] permissions, @NonNull int[] grantResults) { int length = permissions.length; - for(int i = 0; i < length; i++){ - if(requestPermission.equals(permissions[i])){ - if(grantResults[i] == PackageManager.PERMISSION_GRANTED){ + for (int i = 0; i < length; i++) { + if (requestPermission.equals(permissions[i])) { + if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { return true; } } @@ -89,17 +95,18 @@ public class PermissionUtils { /** * 请求权限结果 + * * @param requestPermissions 请求的权限 * @param permissions * @param grantResults * @return 返回{@code true} 表示全部已授权,{@code false}表示未全部授权 */ - public static boolean requestPermissionsResult(@NonNull String[] requestPermissions, @NonNull String[] permissions, @NonNull int[] grantResults){ + public static boolean requestPermissionsResult(@NonNull String[] requestPermissions, @NonNull String[] permissions, @NonNull int[] grantResults) { int length = permissions.length; - for(int i = 0; i < length; i++){ - for(int j = 0; j < requestPermissions.length; j++){ - if(requestPermissions[j].equals(permissions[i])){ - if(grantResults[i] != PackageManager.PERMISSION_GRANTED){ + for (int i = 0; i < length; i++) { + for (int j = 0; j < requestPermissions.length; j++) { + if (requestPermissions[j].equals(permissions[i])) { + if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { return false; } } diff --git a/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png b/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png deleted file mode 100644 index 0aa92fe..0000000 Binary files a/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_off.png and /dev/null differ diff --git a/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png b/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png deleted file mode 100644 index bc321fe..0000000 Binary files a/zxing-lite/src/main/res/drawable-xxhdpi/zxl_flashlight_on.png and /dev/null differ diff --git a/zxing-lite/src/main/res/drawable/zxl_flashlight_off.xml b/zxing-lite/src/main/res/drawable/zxl_flashlight_off.xml new file mode 100644 index 0000000..938acbd --- /dev/null +++ b/zxing-lite/src/main/res/drawable/zxl_flashlight_off.xml @@ -0,0 +1,12 @@ + + + + diff --git a/zxing-lite/src/main/res/drawable/zxl_flashlight_on.xml b/zxing-lite/src/main/res/drawable/zxl_flashlight_on.xml new file mode 100644 index 0000000..d754a42 --- /dev/null +++ b/zxing-lite/src/main/res/drawable/zxl_flashlight_on.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml b/zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml index 8a1e4a7..f8f56cc 100644 --- a/zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml +++ b/zxing-lite/src/main/res/drawable/zxl_flashlight_selector.xml @@ -1,5 +1,5 @@ - - + + \ No newline at end of file diff --git a/zxing-lite/src/main/res/layout/zxl_capture.xml b/zxing-lite/src/main/res/layout/zxl_capture.xml index e8b9b67..73574c5 100644 --- a/zxing-lite/src/main/res/layout/zxl_capture.xml +++ b/zxing-lite/src/main/res/layout/zxl_capture.xml @@ -6,16 +6,19 @@ + android:layout_height="match_parent" /> + + android:layout_height="match_parent" /> + + android:layout_marginTop="@dimen/zxl_flashlight_margin_top" + android:contentDescription="@null" + android:src="@drawable/zxl_flashlight_selector" /> \ No newline at end of file diff --git a/zxing-lite/src/main/res/values/attrs.xml b/zxing-lite/src/main/res/values/attrs.xml index b73f114..7840283 100644 --- a/zxing-lite/src/main/res/values/attrs.xml +++ b/zxing-lite/src/main/res/values/attrs.xml @@ -40,6 +40,17 @@ + + + + + + + + + + + diff --git a/zxing-lite/src/main/res/values/colors.xml b/zxing-lite/src/main/res/values/colors.xml index 62348b6..b2d9f48 100644 --- a/zxing-lite/src/main/res/values/colors.xml +++ b/zxing-lite/src/main/res/values/colors.xml @@ -5,6 +5,7 @@ #7F1FB3E2 #FF1FB3E2 #FF1FB3E2 + #FF1FB3E2 #FFC0C0C0 #00000000 diff --git a/zxing-lite/src/main/res/values/dimens.xml b/zxing-lite/src/main/res/values/dimens.xml index edc5b93..e6aeb0d 100644 --- a/zxing-lite/src/main/res/values/dimens.xml +++ b/zxing-lite/src/main/res/values/dimens.xml @@ -1,4 +1,4 @@ - 80dp + 90dp \ No newline at end of file