重构v2.0

This commit is contained in:
Jenly
2020-12-24 17:50:42 +08:00
parent 5eb7511ed9
commit a6a529f130
31 changed files with 639 additions and 331 deletions

144
README.md
View File

@@ -27,13 +27,11 @@ ZXingLite for Android 是ZXing的精简版基于ZXing库优化扫码和生成
| frameColor | color |<font color=#1FB3E2>#7F1FB3E2</font>| 扫描区边框的颜色 | | frameColor | color |<font color=#1FB3E2>#7F1FB3E2</font>| 扫描区边框的颜色 |
| cornerColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区边角的颜色 | | cornerColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区边角的颜色 |
| laserColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区激光线的颜色 | | laserColor | color |<font color=#1FB3E2>#FF1FB3E2</font>| 扫描区激光线的颜色 |
| resultPointColor | color |<font color=#EFBD21>#C0EFBD21</font>| 扫描区结果点的颜色 |
| labelText | string | | 扫描提示文本信息 | | labelText | string | | 扫描提示文本信息 |
| labelTextColor | color |<font color=#C0C0C0>#FFC0C0C0</font>| 提示文本字体颜色 | | labelTextColor | color |<font color=#C0C0C0>#FFC0C0C0</font>| 提示文本字体颜色 |
| labelTextSize | dimension |14sp| 提示文本字体大小 | | labelTextSize | dimension |14sp| 提示文本字体大小 |
| labelTextPadding | dimension |24dp| 提示文本距离扫描区的间距 | | labelTextPadding | dimension |24dp| 提示文本距离扫描区的间距 |
| labelTextLocation | enum |bottom| 提示文本显示位置 | | labelTextLocation | enum |bottom| 提示文本显示位置 |
| showResultPoint | boolean | false | 是否显示合适的扫码结果点 |
| frameWidth | dimension | | 扫码框宽度 | | frameWidth | dimension | | 扫码框宽度 |
| frameHeight | dimension | | 扫码框高度 | | frameHeight | dimension | | 扫码框高度 |
| laserStyle | enum | line | 扫描激光的样式 | | laserStyle | enum | line | 扫描激光的样式 |
@@ -50,33 +48,28 @@ ZXingLite for Android 是ZXing的精简版基于ZXing库优化扫码和生成
| framePaddingTop | dimension | 0 | 扫码框上边的内间距 | | framePaddingTop | dimension | 0 | 扫码框上边的内间距 |
| framePaddingRight | dimension | 0 | 扫码框右边的内间距 | | framePaddingRight | dimension | 0 | 扫码框右边的内间距 |
| framePaddingBottom | dimension | 0 | 扫码框下边的内间距 | | framePaddingBottom | dimension | 0 | 扫码框下边的内间距 |
| frameGravity | enum | center | 扫码框对齐方式 |
## 引入 ## 引入
### Maven 最新版本
```maven
<dependency>
<groupId>com.king.zxing</groupId>
<artifactId>zxing-lite</artifactId>
<version>1.1.9</version>
<type>pom</type>
</dependency>
```
### Gradle: ### Gradle:
```gradle ```gradle
//AndroidX 版本 //AndroidX 版本
implementation 'com.king.zxing:zxing-lite:2.0.0'
```
以前 **v1.x** 旧版本
```gradle
//AndroidX 版本
implementation 'com.king.zxing:zxing-lite:1.1.9-androidx' implementation 'com.king.zxing:zxing-lite:1.1.9-androidx'
//Android 版本 //Android 版本
implementation 'com.king.zxing:zxing-lite:1.1.9' implementation 'com.king.zxing:zxing-lite:1.1.9'
``` ```
### Lvy:
```lvy
<dependency org='com.king.zxing' name='zxing-lite' rev='1.1.9'>
<artifact name='$AID' ext='pom'></artifact>
</dependency>
```
###### 如果Gradle出现compile失败的情况可以在Project的build.gradle里面添加如下也可以使用上面的JitPack来compile ###### 如果Gradle出现compile失败的情况可以在Project的build.gradle里面添加如下也可以使用上面的JitPack来compile
```gradle ```gradle
@@ -88,47 +81,50 @@ allprojects {
} }
``` ```
## 引入的库: ## 版本说明
```gradle
//AndroidX
api 'androidx.appcompat:appcompat:1.1.0'
api 'com.google.zxing:core:3.3.3'
//Android #### v2.x 相对于 v1.x 的优势
api 'com.android.support:appcompat-v7:28.0.0' * v2.x基于CameraX抽象整体流程可扩展性更高。
api 'com.google.zxing:core:3.3.3' * v2.x基于CameraX通过预览裁剪的方式确保预览界面不变形无需铺满屏幕就能适配v1.x通过遍历Camera支持预览的尺寸找到与屏幕最接近的比例减少变形的可能性需铺满屏幕才能适配)
``` * v2.x如果您是通过继承CaptureActivity或CaptureFragment实现扫码功能那么动态权限申请相关都已经在CaptureActivity或CaptureFragment处理好了无需您格外申请。
(【v1.1.9】)[https://github.com/jenly1314/ZXingLite/tree/androidx] 如果您正在使用 **1.x** 版本请调转,当前 **2.x** 版本已经基于 **Camerx** 进行重构,不支持升级,请在新项目中使用。
下面的示例和相关说明都是针对于当前最新版本如果您使用的是v1.x旧版本(请戳此处查看分支)[https://github.com/jenly1314/ZXingLite/tree/androidx]。
## 示例 ## 示例
布局示例 布局示例
> 可自定义布局覆写getLayoutId方法布局内至少要保证有SurfaceView和ViewfinderView控件id可根据覆写CaptureActivity 的 getSurfaceViewId 和 getViewfinderViewId方法自定义 > 可自定义布局覆写getLayoutId方法布局内至少要保证有PreviewView。
> ivTorch为 v1.1.4版本新增的手电筒按钮如果想改ID可通过CaptureActivity中的getIvTorchId自定义ID > PreviewView 用来预览布局内至少要保证有PreviewView如果是继承CaptureActivity或CaptureFragment控件id可覆写getPreviewViewId方法自定义
> ViewfinderView 用来渲染扫码视图给用户起到一个视觉效果本身扫码识别本身没有关系如果是继承CaptureActivity或CaptureFragment控件id可复写getViewfinderViewId方法自定义默认为previewView返回0表示无需ViewfinderView
> ivFlashlight 用来内置手电筒如果是继承CaptureActivity或CaptureFragment控件id可复写getFlashlightId方法自定义默认为ivFlashlight。返回0表示无需内置手电筒。您也可以自己去定义
> 如果是从v1.1.4以前版本升级至v1.1.4以上版本请参考如下布局示例新增ivTorch也可忽略内置手电筒功能可直接将CaptureActivity中的getIvTorchId方法返回0
```Xml ```Xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<SurfaceView <androidx.camera.view.PreviewView
android:id="@+id/surfaceView" android:id="@+id/previewView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<com.king.zxing.ViewfinderView <com.king.zxing.ViewfinderView
android:id="@+id/viewfinderView" android:id="@+id/viewfinderView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<ImageView <ImageView
android:id="@+id/ivTorch" android:id="@+id/ivFlashlight"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@drawable/zxl_torch_selector" android:src="@drawable/zxl_flashlight_selector"
android:layout_marginTop="@dimen/torchMarginTop" /> android:layout_marginTop="@dimen/zxl_flashlight_margin_top" />
</FrameLayout> </FrameLayout>
``` ```
或在你的布局中添加 或在你的布局中添加
@@ -152,6 +148,44 @@ api 'com.google.zxing:core:3.3.3'
CodeUtils.parseQRCode(bitmapPath); CodeUtils.parseQRCode(bitmapPath);
``` ```
CameraScan配置示例
```java
//获取CameraScan扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
getCameraScan().setPlayBeep(true)//设置是否播放音效默认为false
.setVibrate(true)//设置是否震动默认为false
.setCameraConfig(new CameraConfig())//设置相机配置信息CameraConfig可覆写options方法自定义配置
.setNeedAutoZoom(false)//二维码太小时可自动缩放默认为false
.setNeedTouchZoom(true)//支持多指触摸捏合缩放默认为true
.setDarkLightLux(45f)//设置光线足够暗的阈值单位lux需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
.setBrightLightLux(100f)//设置光线足够明亮的阈值单位lux需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
.bindFlashlightView(ivFlashlight)//绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒按钮
.setOnScanResultCallback(this)//设置扫码结果回调,需要自己处理或者需要连扫时,可设置回调,自己去处理相关逻辑
.setAnalyzer(new MultiFormatAnalyzer(new DecodeConfig()))//设置分析器,DecodeConfig可以配置一些解码时的配置信息如果内置的不满足您的需求你也可以自定义实现
.setAnalyzeImage(true)//设置是否分析图片默认为true。如果设置为false相当于关闭了扫码识别功能
.startCamera();//启动预览
//设置闪光灯(手电筒)是否开启,需在startCamera之后调用才有效
getCameraScan().enableTorch(torch);
```
CameraScan配置示例只需识别二维码的配置示例
```java
//初始化解码配置
DecodeConfig decodeConfig = new DecodeConfig();
decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高
.setFullAreaScan(false)//设置是否全区域识别默认true
.setAreaRectRatio(0.9f)//设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
.setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量默认为0为0表示居中可以为负数
.setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量默认为0为0表示居中可以为负数
//在启动预览之前,设置分析器,只识别二维码
getCameraScan()
.setVibrate(true)//设置是否震动默认为false
.setAnalyzer(new MultiFormatAnalyzer(decodeConfig));//设置分析器,如果内置实现的一些分析器不满足您的需求,你也可以自定义去实现
```
如果直接使用CaptureActivity需在您项目的AndroidManifest中添加如下配置 如果直接使用CaptureActivity需在您项目的AndroidManifest中添加如下配置
```Xml ```Xml
<activity <activity
@@ -166,9 +200,9 @@ api 'com.google.zxing:core:3.3.3'
> 2、通过继承CaptureActivity或者CaptureFragment并自定义布局。适用于大多场景并无需关心扫码相关逻辑自定义布局时需覆写getLayoutId方法 > 2、通过继承CaptureActivity或者CaptureFragment并自定义布局。适用于大多场景并无需关心扫码相关逻辑自定义布局时需覆写getLayoutId方法
> 3、在你项目的Activity或者Fragment中创建一个CaptureHelper并在相应的生命周期中调用CaptureHelper的周期适用于想在扫码界面写交互逻辑又因为项目架构或其它原因无法直接或间接继承CaptureActivity或CaptureFragment时使用 > 3、在你项目的Activity或者Fragment中实例化一个CameraScan即可适用于想在扫码界面写交互逻辑又因为项目架构或其它原因无法直接或间接继承CaptureActivity或CaptureFragment时使用
> 4、参照CaptureHelper写一个自定义的扫码帮助类其它步骤同方式3。扩展高级用法谨慎使用 > 4、继承CameraScan自己实现一个可参照默认实现类DefaultCameraScan其它步骤同方式3。扩展高级用法谨慎使用
### 其他 ### 其他
@@ -186,6 +220,12 @@ compileOptions {
## 版本记录 ## 版本记录
#### v2.0.02020-12-24
* 基于CameraX进行重构
* 抽象整体流程,可扩展性更高
* 从2.x开始只支持AndroidX
* minSdk要求从 **16+** 改为 **21+**
#### v1.1.92020-4-28 #### v1.1.92020-4-28
* 修复1.1.8版本优化细节时不小心改出个Bug(fix #86) * 修复1.1.8版本优化细节时不小心改出个Bug(fix #86)
@@ -199,7 +239,7 @@ compileOptions {
#### v1.1.62019-12-27 #### v1.1.62019-12-27
* 生成条形码/二维码时支持自定义配置颜色 * 生成条形码/二维码时支持自定义配置颜色
* 支持识别反色码增强识别率默认不支持需通过CaptureHelper.supportLuminanceInvert(true)开启) * 支持识别反色码增强识别率默认不支持需通过CameraScan.supportLuminanceInvert(true)开启)
#### v1.1.52019-12-16 #### v1.1.52019-12-16
* 优化Camera初始化相关策略减少出现卡顿的可能性 * 优化Camera初始化相关策略减少出现卡顿的可能性
@@ -218,7 +258,7 @@ compileOptions {
#### v1.1.12019-5-20 #### v1.1.12019-5-20
* 支持扫二维码过小时,自动缩放 * 支持扫二维码过小时,自动缩放
* 支持识别垂直条形码增强条形码识别默认不支持需通过CaptureHelper.supportVerticalCode(true)开启) * 支持识别垂直条形码增强条形码识别默认不支持需通过CameraScan.supportVerticalCode(true)开启)
#### v1.1.02019-4-19 #### v1.1.02019-4-19
* 将扫码相关逻辑与界面分离ZXingLite使用更容易扩展 * 将扫码相关逻辑与界面分离ZXingLite使用更容易扩展

Binary file not shown.

View File

@@ -1 +0,0 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":26,"versionName":"1.1.9-androidx","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}]

View File

@@ -2,8 +2,6 @@ package com.king.zxing.app;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@@ -11,7 +9,6 @@ import android.widget.Toast;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.CameraScan; import com.king.zxing.CameraScan;
import com.king.zxing.DefaultCameraScan; import com.king.zxing.DefaultCameraScan;
import com.king.zxing.ICameraScan;
import com.king.zxing.ViewfinderView; import com.king.zxing.ViewfinderView;
import com.king.zxing.app.util.StatusBarUtils; import com.king.zxing.app.util.StatusBarUtils;
@@ -63,9 +60,9 @@ public class CustomActivity extends AppCompatActivity implements CameraScan.OnSc
isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false); isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false);
mCameraScan = new DefaultCameraScan(this,previewView); mCameraScan = new DefaultCameraScan(this,previewView);
mCameraScan.setOnScanResultCallback(this); mCameraScan.setOnScanResultCallback(this)
.setVibrate(true)
mCameraScan.startCamera(); .startCamera();
} }

View File

@@ -21,7 +21,11 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.CameraConfig;
import com.king.zxing.CaptureActivity; import com.king.zxing.CaptureActivity;
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.app.util.StatusBarUtils;
@@ -58,9 +62,27 @@ public class CustomCaptureActivity extends CaptureActivity {
@Override @Override
public void initCameraScan() { public void initCameraScan() {
super.initCameraScan(); super.initCameraScan();
//获取CaptureHelper里面有扫码相关的配置设 //初始化解码配
getCameraScan().setPlayBeep(false)//播放音效 DecodeConfig decodeConfig = new DecodeConfig();
.setVibrate(true);//震动 decodeConfig.setHints(DecodeFormatManager.DEFAULT_HINTS)////设置解码
// .setAreaRectRatio(0.9f)//设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
// .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量默认为0为0表示居中可以为负数
// .setAreaRectHorizontalOffset(0)//设置识别区域水平方向偏移量默认为0为0表示居中可以为负数
.setFullAreaScan(true);//设置是否全区域识别默认true
//获取CameraScan里面有扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
getCameraScan().setPlayBeep(true)//设置是否播放音效默认为false
.setVibrate(true)//设置是否震动默认为false
.setCameraConfig(new CameraConfig())//设置相机配置信息CameraConfig可覆写options方法自定义配置
.setNeedAutoZoom(false)//二维码太小时可自动缩放默认为false
.setNeedTouchZoom(true)//支持多指触摸捏合缩放默认为true
.setDarkLightLux(45f)//设置光线足够暗的阈值单位lux需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
.setBrightLightLux(100f)//设置光线足够明亮的阈值单位lux需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
.bindFlashlightView(ivFlashlight)//绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒按钮
.setOnScanResultCallback(this)//设置扫码结果回调,需要自己处理或者需要连扫时,可设置回调,自己去处理相关逻辑
.setAnalyzer(new MultiFormatAnalyzer(decodeConfig))//设置分析器,DecodeConfig可以配置一些解码时的配置信息如果内置的不满足您的需求你也可以自定义实现
.setAnalyzeImage(true)//设置是否分析图片默认为true。如果设置为false相当于关闭了扫码识别功能
.startCamera();//启动预览
} }
/** /**

View File

@@ -5,6 +5,7 @@ import android.widget.TextView;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.CaptureActivity; import com.king.zxing.CaptureActivity;
import com.king.zxing.DecodeConfig;
import com.king.zxing.DecodeFormatManager; import com.king.zxing.DecodeFormatManager;
import com.king.zxing.analyze.MultiFormatAnalyzer; import com.king.zxing.analyze.MultiFormatAnalyzer;
import com.king.zxing.app.util.StatusBarUtils; import com.king.zxing.app.util.StatusBarUtils;
@@ -36,10 +37,20 @@ public class QRCodeActivity extends CaptureActivity {
@Override @Override
public void initCameraScan() { public void initCameraScan() {
super.initCameraScan(); super.initCameraScan();
//在启动预览之前,设置分析器,只识别二维码,如果只有识别二维码的需求,这样效率更多高
//初始化解码配置
DecodeConfig decodeConfig = new DecodeConfig();
decodeConfig.setHints(DecodeFormatManager.QR_CODE_HINTS)//如果只有识别二维码的需求,这样设置效率会更高
.setFullAreaScan(false)//设置是否全区域识别默认true
.setAreaRectRatio(0.9f)//设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
.setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量默认为0为0表示居中可以为负数
.setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量默认为0为0表示居中可以为负数
//在启动预览之前,设置分析器,只识别二维码
getCameraScan() getCameraScan()
.setVibrate(true) .setVibrate(true)//设置是否震动默认为false
.setAnalyzer(new MultiFormatAnalyzer(DecodeFormatManager.QR_CODE_HINTS)); .setNeedAutoZoom(true)//二维码太小时可自动缩放默认为false
.setAnalyzer(new MultiFormatAnalyzer(decodeConfig));//设置分析器,如果内置实现的一些分析器不满足您的需求,你也可以自定义去实现
} }
@Override @Override

View File

@@ -18,7 +18,6 @@
app:laserColor="@color/colorAccent" app:laserColor="@color/colorAccent"
app:frameColor="@color/colorPrimary" app:frameColor="@color/colorPrimary"
app:cornerColor="@color/colorPrimary" app:cornerColor="@color/colorPrimary"
app:resultPointColor="@color/colorAccent"
app:labelTextLocation="bottom" app:labelTextLocation="bottom"
app:laserStyle="grid" app:laserStyle="grid"
app:gridHeight="0dp"/> app:gridHeight="0dp"/>

View File

@@ -18,10 +18,8 @@
app:laserColor="@color/colorAccent" app:laserColor="@color/colorAccent"
app:frameColor="@color/colorPrimary" app:frameColor="@color/colorPrimary"
app:cornerColor="@color/colorPrimary" app:cornerColor="@color/colorPrimary"
app:resultPointColor="@color/colorAccent"
app:labelTextLocation="bottom" app:labelTextLocation="bottom"
app:laserStyle="grid" app:laserStyle="grid" />
app:showResultPoint="true"/>
<ImageView <ImageView
android:id="@+id/ivFlashlight" android:id="@+id/ivFlashlight"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -18,10 +18,8 @@
app:laserColor="@color/colorAccent" app:laserColor="@color/colorAccent"
app:frameColor="@color/colorPrimary" app:frameColor="@color/colorPrimary"
app:cornerColor="@color/colorPrimary" app:cornerColor="@color/colorPrimary"
app:resultPointColor="@color/colorAccent"
app:labelTextLocation="bottom" app:labelTextLocation="bottom"
app:laserStyle="grid" app:laserStyle="grid" />
app:showResultPoint="true"/>
<ImageView <ImageView
android:id="@+id/ivFlashlight" android:id="@+id/ivFlashlight"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -6,6 +6,7 @@ import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview; import androidx.camera.core.Preview;
/** /**
* 相机配置:主要用于提供相机预览时可自定义一些配置,便于扩展
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public class CameraConfig { public class CameraConfig {

View File

@@ -1,27 +1,23 @@
package com.king.zxing; package com.king.zxing;
import android.content.Intent; import android.content.Intent;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.google.zxing.qrcode.QRCodeReader;
import com.king.zxing.analyze.Analyzer; import com.king.zxing.analyze.Analyzer;
import com.king.zxing.util.LogUtils; import com.king.zxing.analyze.AreaRectAnalyzer;
import com.king.zxing.analyze.BarcodeFormatAnalyzer;
import com.king.zxing.analyze.ImageAnalyzer;
import com.king.zxing.analyze.MultiFormatAnalyzer;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.camera.core.CameraSelector; import androidx.camera.core.CameraSelector;
import static com.king.zxing.CameraScan.*;
/** /**
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public abstract class CameraScan implements ICameraScan { public abstract class CameraScan implements ICamera,ICameraControl {
/**
* 默认触控误差值
*/
private static final int DEVIATION = 6;
public static String SCAN_RESULT = "SCAN_RESULT"; public static String SCAN_RESULT = "SCAN_RESULT";
@@ -34,14 +30,20 @@ public abstract class CameraScan implements ICameraScan {
/** /**
* 是否需要支持自动缩放 * 是否需要支持自动缩放
*/ */
private boolean isNeedAutoZoom = true; private boolean isNeedAutoZoom = false;
/** /**
* 是否需要支持触摸缩放 * 是否需要支持触摸缩放
*/ */
private boolean isNeedTouchZoom = true; private boolean isNeedTouchZoom = true;
private float mOldDistance; /**
* 是否需要支持触摸缩放
* @return
*/
protected boolean isNeedTouchZoom() {
return isNeedTouchZoom;
}
/** /**
@@ -72,46 +74,6 @@ public abstract class CameraScan implements ICameraScan {
return this; return this;
} }
protected boolean onTouchEvent(MotionEvent event) {
if(getCamera() != null && isNeedTouchZoom){
LogUtils.d("action:" + (event.getAction() & MotionEvent.ACTION_MASK));
if(event.getPointerCount() > 1) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {//多点触控
case MotionEvent.ACTION_POINTER_DOWN:
mOldDistance = calcFingerSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
float newDistance = calcFingerSpacing(event);
if (newDistance > mOldDistance + DEVIATION) {
zoomIn();
} else if (newDistance < mOldDistance - DEVIATION) {
zoomOut();
}
mOldDistance = newDistance;
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
return false;
}
}
return true;
}
return false;
}
/**
* 计算两指间距离
* @param event
* @return
*/
private float calcFingerSpacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
/** /**
* 设置相机配置,请在{@link #startCamera()}之前调用 * 设置相机配置,请在{@link #startCamera()}之前调用
* @param cameraConfig * @param cameraConfig
@@ -125,29 +87,18 @@ public abstract class CameraScan implements ICameraScan {
public abstract CameraScan setAnalyzeImage(boolean analyze); public abstract CameraScan setAnalyzeImage(boolean analyze);
/** /**
* 设置分析器 * 设置分析器,内置了一些{@link Analyzer}的实现类如下
* @see {@link MultiFormatAnalyzer}
* @see {@link AreaRectAnalyzer}
* @see {@link ImageAnalyzer}
*
* @see {@link BarcodeFormatAnalyzer}
* @see {@link QRCodeReader}
*
* @param analyzer * @param analyzer
*/ */
public abstract CameraScan setAnalyzer(Analyzer analyzer); public abstract CameraScan setAnalyzer(Analyzer analyzer);
/**
* 设置手电筒是否开启
* @param torch
*/
public abstract CameraScan enableTorch(boolean torch);
/**
* 手电筒是否开启
* @return
*/
public abstract boolean isTorchEnabled();
/**
* 是否支持闪光灯
* @return
*/
public abstract boolean hasFlashUnit();
/** /**
* 设置是否震动 * 设置是否震动
* @param vibrate * @param vibrate
@@ -172,6 +123,17 @@ public abstract class CameraScan implements ICameraScan {
*/ */
public abstract CameraScan bindFlashlightView(@Nullable View 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{
boolean onScanResultCallback(Result result); boolean onScanResultCallback(Result result);

View File

@@ -15,23 +15,26 @@
*/ */
package com.king.zxing; package com.king.zxing;
import android.Manifest;
import android.os.Bundle; import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.util.LogUtils;
import com.king.zxing.util.PermissionUtils;
import androidx.annotation.LayoutRes; import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.view.PreviewView; import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
/** /**
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
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;
protected PreviewView previewView; protected PreviewView previewView;
protected ViewfinderView viewfinderView; protected ViewfinderView viewfinderView;
@@ -62,32 +65,50 @@ public class CaptureActivity extends AppCompatActivity implements CameraScan.OnS
if(ivFlashlightId != 0){ if(ivFlashlightId != 0){
ivFlashlight = findViewById(ivFlashlightId); ivFlashlight = findViewById(ivFlashlightId);
if(ivFlashlight != null){ if(ivFlashlight != null){
ivFlashlight.setOnClickListener(v -> toggleTorch()); ivFlashlight.setOnClickListener(v -> toggleTorchState());
} }
} }
initCameraScan(); initCameraScan();
startCamera(); startCamera();
} }
/**
* 初始化CameraScan
*/
public void initCameraScan(){ public void initCameraScan(){
mCameraScan = new DefaultCameraScan(this,previewView); mCameraScan = new DefaultCameraScan(this,previewView);
mCameraScan.setOnScanResultCallback(this); mCameraScan.setOnScanResultCallback(this);
} }
/**
* 启动相机预览
*/
public void startCamera(){ public void startCamera(){
if(mCameraScan != null){ if(mCameraScan != null){
mCameraScan.startCamera(); if(PermissionUtils.checkPermission(this,Manifest.permission.CAMERA)){
mCameraScan.startCamera();
}else{
LogUtils.d("checkPermissionResult != PERMISSION_GRANTED");
PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE);
}
} }
} }
/**
* 释放相机
*/
private void releaseCamera(){ private void releaseCamera(){
if(mCameraScan != null){ if(mCameraScan != null){
mCameraScan.release(); mCameraScan.release();
} }
} }
protected void toggleTorch(){ /**
* 切换闪光灯状态(开启/关闭)
*/
protected void toggleTorchState(){
if(mCameraScan != null){ if(mCameraScan != null){
boolean isTorch = mCameraScan.isTorchEnabled(); boolean isTorch = mCameraScan.isTorchEnabled();
mCameraScan.enableTorch(!isTorch); mCameraScan.enableTorch(!isTorch);
@@ -97,6 +118,27 @@ 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);
}
}
/**
* 请求Camera权限回调结果
* @param permissions
* @param grantResults
*/
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){
if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){
startCamera();
}else{
finish();
}
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
releaseCamera(); releaseCamera();

View File

@@ -15,12 +15,15 @@
*/ */
package com.king.zxing; package com.king.zxing;
import android.Manifest;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.util.LogUtils;
import com.king.zxing.util.PermissionUtils;
import androidx.annotation.LayoutRes; import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -32,6 +35,8 @@ import androidx.fragment.app.Fragment;
*/ */
public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback { public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback {
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0X86;
private View mRootView; private View mRootView;
protected PreviewView previewView; protected PreviewView previewView;
@@ -73,31 +78,48 @@ public class CaptureFragment extends Fragment implements CameraScan.OnScanResult
if(ivFlashlightId != 0){ if(ivFlashlightId != 0){
ivFlashlight = mRootView.findViewById(ivFlashlightId); ivFlashlight = mRootView.findViewById(ivFlashlightId);
if(ivFlashlight != null){ if(ivFlashlight != null){
ivFlashlight.setOnClickListener(v -> toggleTorch()); ivFlashlight.setOnClickListener(v -> toggleTorchState());
} }
} }
initCameraScan(); initCameraScan();
startCamera(); startCamera();
} }
/**
* 初始化CameraScan
*/
public void initCameraScan(){ public void initCameraScan(){
mCameraScan = new DefaultCameraScan(this,previewView); mCameraScan = new DefaultCameraScan(this,previewView);
mCameraScan.setOnScanResultCallback(this); mCameraScan.setOnScanResultCallback(this);
} }
/**
* 启动相机预览
*/
public void startCamera(){ public void startCamera(){
if(mCameraScan != null){ if(mCameraScan != null){
mCameraScan.startCamera(); if(PermissionUtils.checkPermission(getContext(), Manifest.permission.CAMERA)){
mCameraScan.startCamera();
}else{
LogUtils.d("checkPermissionResult != PERMISSION_GRANTED");
PermissionUtils.requestPermission(this,Manifest.permission.CAMERA,CAMERA_PERMISSION_REQUEST_CODE);
}
} }
} }
/**
* 释放相机
*/
private void releaseCamera(){ private void releaseCamera(){
if(mCameraScan != null){ if(mCameraScan != null){
mCameraScan.release(); mCameraScan.release();
} }
} }
protected void toggleTorch(){ /**
* 切换闪光灯状态(开启/关闭)
*/
protected void toggleTorchState(){
if(mCameraScan != null){ if(mCameraScan != null){
boolean isTorch = mCameraScan.isTorchEnabled(); boolean isTorch = mCameraScan.isTorchEnabled();
mCameraScan.enableTorch(!isTorch); mCameraScan.enableTorch(!isTorch);
@@ -107,6 +129,27 @@ 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);
}
}
/**
* 请求Camera权限回调结果
* @param permissions
* @param grantResults
*/
public void requestCameraPermissionResult(@NonNull String[] permissions, @NonNull int[] grantResults){
if(PermissionUtils.requestPermissionsResult(Manifest.permission.CAMERA,permissions,grantResults)){
startCamera();
}else{
getActivity().finish();
}
}
@Override @Override
public void onDestroy() { public void onDestroy() {
releaseCamera(); releaseCamera();

View File

@@ -2,6 +2,7 @@ package com.king.zxing;
import android.graphics.Rect; import android.graphics.Rect;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType; import com.google.zxing.DecodeHintType;
import com.google.zxing.common.GlobalHistogramBinarizer; import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer; import com.google.zxing.common.HybridBinarizer;
@@ -12,6 +13,30 @@ import androidx.annotation.FloatRange;
/** /**
* 解码配置:主要用于在扫码识别时,提供一些配置,便于扩展。通过配置可决定内置分析器的能力,从而间接的控制并简化扫码识别的流程
* <p></>
* 设置解码 {@link #setHints(Map)}内置的一些解码可参见如下:
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
* @see {@link DecodeFormatManager#ALL_HINTS}
* @see {@link DecodeFormatManager#CODE_128_HINTS}
* @see {@link DecodeFormatManager#QR_CODE_HINTS}
* @see {@link DecodeFormatManager#ONE_DIMENSIONAL_HINTS}
* @see {@link DecodeFormatManager#TWO_DIMENSIONAL_HINTS}
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
*
* 如果不满足您也可以通过{@link DecodeFormatManager#createDecodeHints(BarcodeFormat...)}自己配置支持的格式
*
* <p></>
* 识别区域可设置的方式有如下几种:
* {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高
* {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效
* {@link #setAreaRectRatio(float)} 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低
*
* 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的所以这里的区域并不是用户所能预览到的区域而是指Camera预览的真实区域
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
* <p></>
* *
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
@@ -75,6 +100,18 @@ public class DecodeConfig {
/** /**
* 设置解码 * 设置解码
* @param hints {@link DecodeFormatManager} * @param hints {@link DecodeFormatManager}
*
* 内置的一些解码可参见如下:
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
* @see {@link DecodeFormatManager#ALL_HINTS}
* @see {@link DecodeFormatManager#CODE_128_HINTS}
* @see {@link DecodeFormatManager#QR_CODE_HINTS}
* @see {@link DecodeFormatManager#ONE_DIMENSIONAL_HINTS}
* @see {@link DecodeFormatManager#TWO_DIMENSIONAL_HINTS}
* @see {@link DecodeFormatManager#DEFAULT_HINTS}
*
* 如果不满足您也可以通过{@link DecodeFormatManager#createDecodeHints(BarcodeFormat...)}自己配置支持的格式
*
* @return * @return
*/ */
public DecodeConfig setHints(Map<DecodeHintType, Object> hints) { public DecodeConfig setHints(Map<DecodeHintType, Object> hints) {
@@ -184,8 +221,19 @@ public class DecodeConfig {
} }
/** /**
* 设置需要分析识别区域,当设置了指定的分析区域时,识别区域比例和识别区域相关参数都将无效 * 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效
* @param analyzeAreaRect * @param analyzeAreaRect
*
* 识别区域可设置的方式有如下几种:
* {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高
* {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效
* {@link #setAreaRectRatio(float)} 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低
*
* 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的所以这里的区域并不是用户所能预览到的区域而是指Camera预览的真实区域
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
*
* @return * @return
*/ */
public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) { public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) {
@@ -202,8 +250,18 @@ public class DecodeConfig {
} }
/** /**
* 设置是否支持全区域扫码识别,优先级比识别区域比例 * 设置是否支持全区域扫码识别,优先级比识别区域高
* @param fullAreaScan 默认为{@code true} * @param fullAreaScan 默认为{@code true}
*
* 识别区域可设置的方式有如下几种:
* {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高
* {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效
* {@link #setAreaRectRatio(float)} 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低
*
* 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的所以这里的区域并不是用户所能预览到的区域而是指Camera预览的真实区域
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
* @return * @return
*/ */
public DecodeConfig setFullAreaScan(boolean fullAreaScan) { public DecodeConfig setFullAreaScan(boolean fullAreaScan) {
@@ -220,8 +278,19 @@ public class DecodeConfig {
} }
/** /**
* 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别 * 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低
* @param areaRectRatio * @param areaRectRatio
*
* 识别区域可设置的方式有如下几种:
* {@link #setFullAreaScan(boolean)} 设置是否支持全区域扫码识别,优先级比识别区域高
* {@link #setAnalyzeAreaRect(Rect)} 设置需要分析识别区域,优先级比识别区域比例高,当设置了指定的分析区域时,识别区域比例和识别区域偏移量相关参数都将无效
* {@link #setAreaRectRatio(float)} 设置识别区域比例默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别,优先级最低
*
* 因为{@link androidx.camera.view.PreviewView}的预览区域是经过裁剪的所以这里的区域并不是用户所能预览到的区域而是指Camera预览的真实区域
* 您还可以通过{@link CameraScan#setCameraConfig(CameraConfig)}去自定义配置{@link CameraConfig}的配置信息控制预览相关配置信息
*
* 即判定区域分析的优先级顺序为:{@link #setFullAreaScan(boolean)} -> {@link #setAnalyzeAreaRect(Rect)} -> {@link #setAreaRectRatio(float)}
*
* @return * @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) {

View File

@@ -4,7 +4,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.MotionEvent; import android.view.ScaleGestureDetector;
import android.view.View; import android.view.View;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@@ -24,6 +24,7 @@ import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis; import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview; import androidx.camera.core.Preview;
import androidx.camera.core.TorchState; import androidx.camera.core.TorchState;
import androidx.camera.core.ZoomState;
import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView; import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@@ -87,18 +88,38 @@ public class DefaultCameraScan extends CameraScan {
initData(); initData();
} }
private ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener(){
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
if(mCamera != null){
float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio();
zoomTo(ratio * scale);
}
return true;
}
};
private void initData(){ private void initData(){
mResultLiveData = new MutableLiveData<>(); mResultLiveData = new MutableLiveData<>();
mResultLiveData.observe(mLifecycleOwner, result -> { mResultLiveData.observe(mLifecycleOwner, result -> {
handleAnalyzeResult(result); handleAnalyzeResult(result);
}); });
ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
mPreviewView.setOnClickListener(new View.OnClickListener() { mPreviewView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
LogUtils.d("click"); LogUtils.d("click");
} }
}); });
mPreviewView.setOnTouchListener((v, event) -> onTouchEvent(event)); mPreviewView.setOnTouchListener((v, event) -> {
if(isNeedTouchZoom()){
return scaleGestureDetector.onTouchEvent(event);
}
return false;
});
DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
mScreenWidth = displayMetrics.widthPixels; mScreenWidth = displayMetrics.widthPixels;
@@ -109,14 +130,16 @@ public class DefaultCameraScan extends CameraScan {
mAmbientLightManager.register(); mAmbientLightManager.register();
mAmbientLightManager.setOnLightSensorEventListener((dark, lightLux) -> { mAmbientLightManager.setOnLightSensorEventListener((dark, lightLux) -> {
if(flashlightView != null){ if(flashlightView != null){
flashlightView.setSelected(!dark);
if(dark){ if(dark){
if(flashlightView.getVisibility() != View.VISIBLE){ if(flashlightView.getVisibility() != View.VISIBLE){
flashlightView.setVisibility(View.VISIBLE); flashlightView.setVisibility(View.VISIBLE);
flashlightView.setSelected(isTorchEnabled());
} }
}else if(flashlightView.getVisibility() == View.VISIBLE){ }else if(flashlightView.getVisibility() == View.VISIBLE && !isTorchEnabled()){
flashlightView.setVisibility(View.INVISIBLE); flashlightView.setVisibility(View.INVISIBLE);
flashlightView.setSelected(false);
} }
} }
}); });
} }
@@ -131,7 +154,6 @@ public class DefaultCameraScan extends CameraScan {
} }
} }
@Override @Override
public CameraScan setCameraConfig(CameraConfig cameraConfig) { public CameraScan setCameraConfig(CameraConfig cameraConfig) {
if(cameraConfig != null){ if(cameraConfig != null){
@@ -288,10 +310,15 @@ public class DefaultCameraScan extends CameraScan {
} }
} }
@Override @Override
public void zoomTo(float ratio) { public void zoomTo(float ratio) {
if(mCamera != null){ if(mCamera != null){
mCamera.getCameraControl().setZoomRatio(ratio); ZoomState zoomState = mCamera.getCameraInfo().getZoomState().getValue();
float maxRatio = zoomState.getMaxZoomRatio();
float minRatio = zoomState.getMinZoomRatio();
float zoom = Math.max(Math.min(ratio,maxRatio),minRatio);
mCamera.getCameraControl().setZoomRatio(zoom);
} }
} }
@@ -323,11 +350,10 @@ public class DefaultCameraScan extends CameraScan {
} }
@Override @Override
public CameraScan enableTorch(boolean torch) { public void enableTorch(boolean torch) {
if(mCamera != null && hasFlashUnit()){ if(mCamera != null && hasFlashUnit()){
mCamera.getCameraControl().enableTorch(torch); mCamera.getCameraControl().enableTorch(torch);
} }
return this;
} }
@Override @Override
@@ -401,4 +427,18 @@ public class DefaultCameraScan extends CameraScan {
return this; return this;
} }
public CameraScan setDarkLightLux(float lightLux){
if(mAmbientLightManager != null){
mAmbientLightManager.setDarkLightLux(lightLux);
}
return this;
}
public CameraScan setBrightLightLux(float lightLux){
if(mAmbientLightManager != null){
mAmbientLightManager.setBrightLightLux(lightLux);
}
return this;
}
} }

View File

@@ -0,0 +1,33 @@
package com.king.zxing;
import androidx.annotation.Nullable;
import androidx.camera.core.Camera;
/**
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public interface ICamera {
/**
* 启动相机预览
*/
void startCamera();
/**
* 停止相机预览
*/
void stopCamera();
/**
* 获取{@link Camera}
* @return
*/
@Nullable Camera getCamera();
/**
* 释放
*/
void release();
}

View File

@@ -1,29 +1,11 @@
package com.king.zxing; package com.king.zxing;
import android.view.MotionEvent;
import com.google.zxing.Result;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
import androidx.camera.core.Camera;
/** /**
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public interface ICameraScan { public interface ICameraControl {
/**
* 启动相机预览
*/
void startCamera();
/**
* 停止相机预览
*/
void stopCamera();
/** /**
* 放大 * 放大
@@ -42,12 +24,12 @@ public interface ICameraScan {
void zoomTo(float ratio); void zoomTo(float ratio);
/** /**
* 放大 * 线性放大
*/ */
void lineZoomIn(); void lineZoomIn();
/** /**
* 缩小 * 线性缩小
*/ */
void lineZoomOut(); void lineZoomOut();
@@ -57,13 +39,21 @@ public interface ICameraScan {
*/ */
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);
/** /**
* 获取{@link Camera} * 闪光灯手电筒是否开启
* @return * @return
*/ */
@Nullable Camera getCamera(); boolean isTorchEnabled();
void release();
/**
* 是否支持闪光灯
* @return
*/
boolean hasFlashUnit();
} }

View File

@@ -42,6 +42,8 @@ import androidx.annotation.ColorRes;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; 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 * 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. * transparency outside it, as well as the laser scanner animation and result points.
@@ -79,10 +81,10 @@ public class ViewfinderView extends View {
* 扫码框四角颜色 * 扫码框四角颜色
*/ */
private int cornerColor; private int cornerColor;
/** // /**
* 结果点颜色 // * 结果点颜色
*/ // */
private int resultPointColor; // private int resultPointColor;
/** /**
* 提示文本与扫码框的边距 * 提示文本与扫码框的边距
@@ -118,14 +120,6 @@ public class ViewfinderView extends View {
*/ */
private boolean isShowResultPoint; private boolean isShowResultPoint;
/**
* 屏幕宽
*/
private int screenWidth;
/**
* 屏幕高
*/
private int screenHeight;
/** /**
* 扫码框宽 * 扫码框宽
*/ */
@@ -185,13 +179,17 @@ public class ViewfinderView extends View {
*/ */
private float frameRatio; private float frameRatio;
/**
* 扫码框内间距
*/
private float framePaddingLeft; private float framePaddingLeft;
private float framePaddingTop; private float framePaddingTop;
private float framePaddingRight; private float framePaddingRight;
private float framePaddingBottom; private float framePaddingBottom;
/**
private List<ResultPoint> possibleResultPoints; * 扫码框对齐方式
private List<ResultPoint> lastPossibleResultPoints; */
private FrameGravity frameGravity;
public enum LaserStyle{ public enum LaserStyle{
NONE(0),LINE(1),GRID(2); NONE(0),LINE(1),GRID(2);
@@ -201,13 +199,11 @@ public class ViewfinderView extends View {
} }
private static LaserStyle getFromInt(int value){ private static LaserStyle getFromInt(int value){
for(LaserStyle style : LaserStyle.values()){ for(LaserStyle style : LaserStyle.values()){
if(style.mValue == value){ if(style.mValue == value){
return style; return style;
} }
} }
return LaserStyle.LINE; return LaserStyle.LINE;
} }
} }
@@ -222,17 +218,33 @@ public class ViewfinderView extends View {
} }
private static TextLocation getFromInt(int value){ private static TextLocation getFromInt(int value){
for(TextLocation location : TextLocation.values()){ for(TextLocation location : TextLocation.values()){
if(location.mValue == value){ if(location.mValue == value){
return location; return location;
} }
} }
return TextLocation.TOP; return TextLocation.TOP;
} }
}
public enum FrameGravity {
CENTER(0), LEFT(1), TOP(2), RIGHT(3), BOTTOM(4);
private int mValue;
FrameGravity(int value) {
mValue = value;
}
private static FrameGravity getFromInt(int value) {
for (FrameGravity gravity : values()) {
if (gravity.mValue == value) {
return gravity;
}
}
return CENTER;
}
} }
public ViewfinderView(Context context) { public ViewfinderView(Context context) {
@@ -256,7 +268,7 @@ public class ViewfinderView extends View {
frameColor = array.getColor(R.styleable.ViewfinderView_frameColor, ContextCompat.getColor(context,R.color.viewfinder_frame)); 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)); 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)); laserColor = array.getColor(R.styleable.ViewfinderView_laserColor, ContextCompat.getColor(context,R.color.viewfinder_laser));
resultPointColor = array.getColor(R.styleable.ViewfinderView_resultPointColor, ContextCompat.getColor(context,R.color.viewfinder_result_point_color)); // resultPointColor = array.getColor(R.styleable.ViewfinderView_resultPointColor, ContextCompat.getColor(context,R.color.viewfinder_result_point_color));
labelText = array.getString(R.styleable.ViewfinderView_labelText); labelText = array.getString(R.styleable.ViewfinderView_labelText);
labelTextColor = array.getColor(R.styleable.ViewfinderView_labelTextColor, ContextCompat.getColor(context,R.color.viewfinder_text_color)); labelTextColor = array.getColor(R.styleable.ViewfinderView_labelTextColor, ContextCompat.getColor(context,R.color.viewfinder_text_color));
@@ -264,7 +276,7 @@ public class ViewfinderView extends View {
labelTextPadding = array.getDimension(R.styleable.ViewfinderView_labelTextPadding,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics())); labelTextPadding = array.getDimension(R.styleable.ViewfinderView_labelTextPadding,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,24,getResources().getDisplayMetrics()));
labelTextLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_labelTextLocation,0)); labelTextLocation = TextLocation.getFromInt(array.getInt(R.styleable.ViewfinderView_labelTextLocation,0));
isShowResultPoint = array.getBoolean(R.styleable.ViewfinderView_showResultPoint,false); // isShowResultPoint = array.getBoolean(R.styleable.ViewfinderView_showResultPoint,false);
frameWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameWidth,0); frameWidth = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameWidth,0);
frameHeight = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameHeight,0); frameHeight = array.getDimensionPixelSize(R.styleable.ViewfinderView_frameHeight,0);
@@ -284,27 +296,12 @@ public class ViewfinderView extends View {
framePaddingTop = array.getDimension(R.styleable.ViewfinderView_framePaddingTop,0); framePaddingTop = array.getDimension(R.styleable.ViewfinderView_framePaddingTop,0);
framePaddingRight = array.getDimension(R.styleable.ViewfinderView_framePaddingRight,0); framePaddingRight = array.getDimension(R.styleable.ViewfinderView_framePaddingRight,0);
framePaddingBottom = array.getDimension(R.styleable.ViewfinderView_framePaddingBottom,0); framePaddingBottom = array.getDimension(R.styleable.ViewfinderView_framePaddingBottom,0);
frameGravity = FrameGravity.getFromInt(array.getInt(R.styleable.ViewfinderView_frameGravity, CENTER.mValue));
array.recycle(); array.recycle();
paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = null;
screenWidth = getDisplayMetrics().widthPixels;
screenHeight = getDisplayMetrics().heightPixels;
int size = (int)(Math.min(screenWidth,screenHeight) * frameRatio);
if(frameWidth<=0 || frameWidth > screenWidth){
frameWidth = size;
}
if(frameHeight<=0 || frameHeight > screenHeight){
frameHeight = size;
}
} }
private DisplayMetrics getDisplayMetrics(){ private DisplayMetrics getDisplayMetrics(){
@@ -327,13 +324,43 @@ public class ViewfinderView extends View {
this.labelTextSize = textSize; this.labelTextSize = textSize;
} }
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onSizeChanged(w, h, oldw, oldh);
//扫码框默认居中,支持利用内距偏移扫码框 initFrame(w,h);
int leftOffset = (int)((screenWidth - frameWidth) / 2 + framePaddingLeft - framePaddingRight); }
int topOffset = (int)((screenHeight - frameHeight) / 2 + framePaddingTop - framePaddingBottom);
frame = new Rect(leftOffset, topOffset, leftOffset + frameWidth, topOffset + frameHeight); private void initFrame(int width,int height){
int size = (int)(Math.min(width,height) * frameRatio);
if(frameWidth <= 0 || frameWidth > width){
frameWidth = size;
}
if(frameHeight <= 0 || frameHeight > height){
frameHeight = size;
}
float leftOffsets = (width - frameWidth) / 2 + framePaddingLeft - framePaddingRight;
float topOffsets = (height - frameHeight) / 2 + framePaddingTop - framePaddingBottom;
switch (frameGravity){
case LEFT:
leftOffsets = framePaddingLeft;
break;
case TOP:
topOffsets = framePaddingTop;
break;
case RIGHT:
leftOffsets = width - frameWidth + framePaddingRight;
break;
case BOTTOM:
topOffsets = height - frameHeight + framePaddingBottom;
break;
}
frame = new Rect((int)leftOffsets, (int)topOffsets, (int)leftOffsets + frameWidth, (int)topOffsets + frameHeight);
} }
@Override @Override
@@ -361,8 +388,6 @@ public class ViewfinderView extends View {
drawCorner(canvas, frame); drawCorner(canvas, frame);
//绘制提示信息 //绘制提示信息
drawTextInfo(canvas, frame); drawTextInfo(canvas, frame);
//绘制扫码结果点
drawResultPoint(canvas,frame);
// Request another update at the animation interval, but only repaint the laser line, // Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask. // not the entire viewfinder mask.
postInvalidateDelayed(scannerAnimationDelay, postInvalidateDelayed(scannerAnimationDelay,
@@ -385,11 +410,10 @@ public class ViewfinderView extends View {
StaticLayout staticLayout = new StaticLayout(labelText,textPaint,canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL,1.0f,0.0f,true); StaticLayout staticLayout = new StaticLayout(labelText,textPaint,canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL,1.0f,0.0f,true);
if(labelTextLocation == TextLocation.BOTTOM){ if(labelTextLocation == TextLocation.BOTTOM){
canvas.translate(frame.left + frame.width() / 2,frame.bottom + labelTextPadding); canvas.translate(frame.left + frame.width() / 2,frame.bottom + labelTextPadding);
staticLayout.draw(canvas);
}else{ }else{
canvas.translate(frame.left + frame.width() / 2,frame.top - labelTextPadding - staticLayout.getHeight()); canvas.translate(frame.left + frame.width() / 2,frame.top - labelTextPadding - staticLayout.getHeight());
staticLayout.draw(canvas);
} }
staticLayout.draw(canvas);
} }
} }
@@ -529,53 +553,16 @@ public class ViewfinderView extends View {
* @param height * @param height
*/ */
private void drawExterior(Canvas canvas, Rect frame, int width, int height) { private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
paint.setColor(maskColor); if(maskColor != 0){
canvas.drawRect(0, 0, width, frame.top, paint); paint.setColor(maskColor);
canvas.drawRect(0, frame.top, frame.left, frame.bottom, paint); canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(frame.right, frame.top, width, frame.bottom, paint); canvas.drawRect(0, frame.top, frame.left, frame.bottom, paint);
canvas.drawRect(0, frame.bottom, width, height, paint); canvas.drawRect(frame.right, frame.top, width, frame.bottom, paint);
} canvas.drawRect(0, frame.bottom, width, height, paint);
/**
* 绘制扫码结果点
* @param canvas
* @param frame
*/
private void drawResultPoint(Canvas canvas,Rect frame){
if(!isShowResultPoint){
return;
}
List<ResultPoint> currentPossible = possibleResultPoints;
List<ResultPoint> currentLast = lastPossibleResultPoints;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
synchronized (currentPossible) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentPossible) {
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
}
}
}
if (currentLast != null) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
synchronized (currentLast) {
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentLast) {
canvas.drawCircle( point.getX(),point.getY(), radius, paint);
}
}
} }
} }
public void drawViewfinder() { public void drawViewfinder() {
invalidate(); invalidate();
} }
@@ -597,21 +584,5 @@ public class ViewfinderView extends View {
} }
public void addPossibleResultPoint(ResultPoint point) {
if(isShowResultPoint){
List<ResultPoint> points = possibleResultPoints;
synchronized (points) {
points.add(point);
int size = points.size();
if (size > MAX_RESULT_POINTS) {
// trim it
points.subList(0, size - MAX_RESULT_POINTS / 2).clear();
}
}
}
}
} }

View File

@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.graphics.ImageFormat; import android.graphics.ImageFormat;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.util.LogUtils;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -35,6 +36,7 @@ public abstract class ImageAnalyzer implements Analyzer {
buffer.get(data); buffer.get(data);
return analyze(data,image.getWidth(),image.getHeight()); return analyze(data,image.getWidth(),image.getHeight());
} }
LogUtils.w("imageFormat: " + image.getFormat());
return null; return null;
} }

View File

@@ -0,0 +1,111 @@
package com.king.zxing.util;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
/**
* @author <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/
public class 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;
}
/**
* 请求权限
* @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);
}
/**
* 请求权限
* @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);
}
/**
* 请求权限
* @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);
}
/**
* 请求权限
* @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);
}
/**
* 请求权限结果
* @param requestPermission 请求的权限
* @param permissions
* @param grantResults
* @return 返回{@code true} 表示已授权,{@code false}表示未授权
*/
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){
return true;
}
}
}
return false;
}
/**
* 请求权限结果
* @param requestPermissions 请求的权限
* @param permissions
* @param grantResults
* @return 返回{@code true} 表示全部已授权,{@code false}表示未全部授权
*/
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){
return false;
}
}
}
}
return true;
}
}

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/zxl_torch_on"/> <item android:state_selected="true" android:drawable="@drawable/zxl_flashlight_on"/>
<item android:drawable="@drawable/zxl_torch_off"/> <item android:drawable="@drawable/zxl_flashlight_off"/>
</selector> </selector>

View File

@@ -1,16 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@@ -28,6 +16,6 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@drawable/zxl_torch_selector" android:src="@drawable/zxl_flashlight_selector"
android:layout_marginTop="@dimen/torchMarginTop" /> android:layout_marginTop="@dimen/zxl_flashlight_margin_top" />
</FrameLayout> </FrameLayout>

View File

@@ -4,7 +4,6 @@
<attr name="frameColor" format="color" /> <attr name="frameColor" format="color" />
<attr name="cornerColor" format="color"/> <attr name="cornerColor" format="color"/>
<attr name="laserColor" format="color"/> <attr name="laserColor" format="color"/>
<attr name="resultPointColor" format="color"/>
<attr name="labelText" format="string"/> <attr name="labelText" format="string"/>
<attr name="labelTextColor" format="color"/> <attr name="labelTextColor" format="color"/>
<attr name="labelTextSize" format="dimension"/> <attr name="labelTextSize" format="dimension"/>
@@ -13,7 +12,6 @@
<enum name="top" value="0"/> <enum name="top" value="0"/>
<enum name="bottom" value="1"/> <enum name="bottom" value="1"/>
</attr> </attr>
<attr name="showResultPoint" format="boolean"/>
<attr name="frameWidth" format="dimension"/> <attr name="frameWidth" format="dimension"/>
<attr name="frameHeight" format="dimension"/> <attr name="frameHeight" format="dimension"/>
<attr name="gridColumn" format="integer"/> <attr name="gridColumn" format="integer"/>
@@ -34,6 +32,13 @@
<attr name="framePaddingTop" format="dimension"/> <attr name="framePaddingTop" format="dimension"/>
<attr name="framePaddingRight" format="dimension"/> <attr name="framePaddingRight" format="dimension"/>
<attr name="framePaddingBottom" format="dimension"/> <attr name="framePaddingBottom" format="dimension"/>
<attr name="frameGravity" format="enum">
<enum name="center" value="0"/>
<enum name="left" value="1"/>
<enum name="top" value="2"/>
<enum name="right" value="3"/>
<enum name="bottom" value="4"/>
</attr>
</declare-styleable> </declare-styleable>

View File

@@ -5,10 +5,9 @@
<color name="viewfinder_frame">#7F1FB3E2</color> <color name="viewfinder_frame">#7F1FB3E2</color>
<color name="viewfinder_corner">#FF1FB3E2</color> <color name="viewfinder_corner">#FF1FB3E2</color>
<color name="viewfinder_laser">#FF1FB3E2</color> <color name="viewfinder_laser">#FF1FB3E2</color>
<color name="viewfinder_result_point_color">#C0FFBD21</color>
<color name="viewfinder_text_color">#FFC0C0C0</color> <color name="viewfinder_text_color">#FFC0C0C0</color>
<color name="capture_status_bar_color">#00000000</color> <color name="zxl_capture_status_bar_color">#00000000</color>
<color name="capture_navigation_bar_color">#00000000</color> <color name="zxl_capture_navigation_bar_color">#00000000</color>
</resources> </resources>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<dimen name="torchMarginTop">80dp</dimen> <dimen name="zxl_flashlight_margin_top">80dp</dimen>
</resources> </resources>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="decode"/>
<item type="id" name="decode_failed"/>
<item type="id" name="decode_succeeded"/>
<item type="id" name="launch_product_query"/>
<item type="id" name="quit"/>
<item type="id" name="restart_preview"/>
<item type="id" name="return_scan_result"/>
</resources>

View File

@@ -1,2 +0,0 @@
<resources>
</resources>

View File

@@ -8,8 +8,8 @@
<item name="colorPrimaryDark">@android:color/black</item> <item name="colorPrimaryDark">@android:color/black</item>
<item name="android:windowTranslucentStatus">true</item> <item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item> <item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@color/capture_status_bar_color</item> <item name="android:statusBarColor">@color/zxl_capture_status_bar_color</item>
<item name="android:navigationBarColor">@color/capture_navigation_bar_color</item> <item name="android:navigationBarColor">@color/zxl_capture_navigation_bar_color</item>
</style> </style>
</resources> </resources>

View File

@@ -1,7 +1,7 @@
//App //App
def app_version = [:] def app_version = [:]
app_version.versionCode = 27 app_version.versionCode = 27
app_version.versionName = "2.0.0-beta1" app_version.versionName = "2.0.0"
ext.app_version = app_version ext.app_version = app_version
//build version //build version