* 内置手电筒按钮,当光线太暗时,自动显示手电筒 fix(#58)

*  生成二维码时Logo支持自定义大小 fix(#62)
This commit is contained in:
jenly1314
2019-11-15 17:29:37 +08:00
parent 004bd683a1
commit b830b89b5f
31 changed files with 411 additions and 151 deletions

View File

@@ -54,21 +54,21 @@ ZXingLite for Android 是ZXing的精简版基于ZXing库优化扫码和生成
<dependency> <dependency>
<groupId>com.king.zxing</groupId> <groupId>com.king.zxing</groupId>
<artifactId>zxing-lite</artifactId> <artifactId>zxing-lite</artifactId>
<version>1.1.3</version> <version>1.1.4</version>
<type>pom</type> <type>pom</type>
</dependency> </dependency>
``` ```
### Gradle: ### Gradle:
```gradle ```gradle
//AndroidX 版本 //AndroidX 版本
implementation 'com.king.zxing:zxing-lite:1.1.3-androidx' implementation 'com.king.zxing:zxing-lite:1.1.4-androidx'
//Android 版本 //Android 版本
implementation 'com.king.zxing:zxing-lite:1.1.3' implementation 'com.king.zxing:zxing-lite:1.1.4'
``` ```
### Lvy: ### Lvy:
```lvy ```lvy
<dependency org='com.king.zxing' name='zxing-lite' rev='1.1.3'> <dependency org='com.king.zxing' name='zxing-lite' rev='1.1.4'>
<artifact name='$AID' ext='pom'></artifact> <artifact name='$AID' ext='pom'></artifact>
</dependency> </dependency>
``` ```
@@ -95,7 +95,10 @@ api 'com.google.zxing:core:3.3.3'
## 示例 ## 示例
布局示例 可自定义布局布局内至少要保证有SurfaceView和ViewfinderView控件id可根据重写CaptureActivity 的 getPreviewViewId 和 getViewFinderViewId方法自定义 布局示例
> 可自定义布局布局内至少要保证有SurfaceView和ViewfinderView控件id可根据重写CaptureActivity 的 getSurfaceViewId 和 getViewfinderViewId方法自定义
> ivTorch为 v1.1.4版本新增的手电筒按钮如果想改ID可通过CaptureActivity中的getIvTorchId自定义ID
```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"
@@ -109,10 +112,22 @@ api 'com.google.zxing:core:3.3.3'
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
android:id="@+id/ivTorch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/zxl_torch_selector"
android:layout_marginTop="@dimen/torchMarginTop" />
</FrameLayout> </FrameLayout>
``` ```
或在你的布局中添加
```Xml
<include layout="@layout/zxl_capture"/>
```
代码示例 (二维码/条形码) 代码示例 (二维码/条形码)
```Java ```Java
//跳转的默认扫码界面 //跳转的默认扫码界面
@@ -128,7 +143,8 @@ api 'com.google.zxing:core:3.3.3'
```Xml ```Xml
<activity <activity
android:name="com.king.zxing.CaptureActivity" android:name="com.king.zxing.CaptureActivity"
android:screenOrientation="portrait"/> android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
``` ```
### 快速实现扫码有以下几种方式: ### 快速实现扫码有以下几种方式:
@@ -146,6 +162,10 @@ api 'com.google.zxing:core:3.3.3'
## 版本记录 ## 版本记录
#### v1.1.42019-11-15
* 内置手电筒按钮,当光线太暗时,自动显示手电筒 fix(#58)
* 生成二维码时Logo支持自定义大小 fix(#62)
#### v1.1.32019-9-24 #### v1.1.32019-9-24
* 支持真实识别区域比例和识别区域偏移量可配置 * 支持真实识别区域比例和识别区域偏移量可配置
* 对外暴露更多可配置参数 * 对外暴露更多可配置参数

Binary file not shown.

View File

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

View File

@@ -23,21 +23,26 @@
</activity> </activity>
<activity <activity
android:name="com.king.zxing.CaptureActivity" android:name="com.king.zxing.CaptureActivity"
android:screenOrientation="portrait"/> android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
<activity <activity
android:name=".EasyCaptureActivity" android:name=".EasyCaptureActivity"
android:screenOrientation="portrait"/> android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
<activity <activity
android:name=".CustomCaptureActivity"/> android:name=".CustomCaptureActivity"
android:theme="@style/CaptureTheme"/>
<activity <activity
android:name=".CaptureFragmentActivity" android:name=".CaptureFragmentActivity"
android:screenOrientation="portrait"/> android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
<activity <activity
android:name=".CustomActivity" android:name=".CustomActivity"
android:screenOrientation="portrait"/> android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
<activity <activity
android:name=".CodeActivity" android:name=".CodeActivity"

View File

@@ -57,11 +57,16 @@ public class CodeActivity extends AppCompatActivity {
* @param content * @param content
*/ */
private void createQRCode(String content){ private void createQRCode(String content){
//生成二维码最好放子线程生成防止阻塞UI这里只是演示 new Thread(() -> {
Bitmap logo = BitmapFactory.decodeResource(getResources(),R.drawable.logo); //生成二维码相关放在子线程里面
Bitmap bitmap = CodeUtils.createQRCode(content,600,logo); Bitmap logo = BitmapFactory.decodeResource(getResources(),R.drawable.logo);
//显示二维码 Bitmap bitmap = CodeUtils.createQRCode(content,600,logo);
ivCode.setImageBitmap(bitmap); runOnUiThread(()->{
//显示二维码
ivCode.setImageBitmap(bitmap);
});
}).start();
} }
/** /**
@@ -69,13 +74,18 @@ public class CodeActivity extends AppCompatActivity {
* @param content * @param content
*/ */
private void createBarCode(String content){ private void createBarCode(String content){
//生成条形码最好放子线程生成防止阻塞UI这里只是演示 new Thread(() -> {
Bitmap bitmap = CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200,null,true); //生成条形码相关放在子线程里面
//显示条形码 Bitmap bitmap = CodeUtils.createBarCode(content, BarcodeFormat.CODE_128,800,200,null,true);
ivCode.setImageBitmap(bitmap); runOnUiThread(()->{
//显示条形码
ivCode.setImageBitmap(bitmap);
});
}).start();
} }
public void onClick(View v){ public void onClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.ivLeft: case R.id.ivLeft:

View File

@@ -1,8 +1,7 @@
package com.king.zxing.app; package com.king.zxing.app;
import android.hardware.Camera;
import android.os.Bundle;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View; import android.view.View;
@@ -33,6 +32,8 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
private ViewfinderView viewfinderView; private ViewfinderView viewfinderView;
private View ivTorch;
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
@@ -52,10 +53,12 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
surfaceView = findViewById(R.id.surfaceView); surfaceView = findViewById(R.id.surfaceView);
viewfinderView = findViewById(R.id.viewfinderView); viewfinderView = findViewById(R.id.viewfinderView);
ivTorch = findViewById(R.id.ivFlash);
ivTorch.setVisibility(View.INVISIBLE);
isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false); isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false);
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView); mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
mCaptureHelper.setOnCaptureCallback(this); mCaptureHelper.setOnCaptureCallback(this);
mCaptureHelper.onCreate(); mCaptureHelper.onCreate();
mCaptureHelper.vibrate(true) mCaptureHelper.vibrate(true)
@@ -89,26 +92,6 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
return super.onTouchEvent(event); return super.onTouchEvent(event);
} }
/**
* 关闭闪光灯(手电筒)
*/
private void offFlash(){
Camera camera = mCaptureHelper.getCameraManager().getOpenCamera().getCamera();
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
}
/**
* 开启闪光灯(手电筒)
*/
public void openFlash(){
Camera camera = mCaptureHelper.getCameraManager().getOpenCamera().getCamera();
Camera.Parameters parameters = camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
}
/** /**
* 扫码结果回调 * 扫码结果回调
@@ -124,25 +107,12 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
} }
private void clickFlash(View v){
if(v.isSelected()){
offFlash();
v.setSelected(false);
}else{
openFlash();
v.setSelected(true);
}
}
public void onClick(View v){ public void onClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.ivLeft: case R.id.ivLeft:
onBackPressed(); onBackPressed();
break; break;
case R.id.ivFlash:
clickFlash(v);
break;
} }
} }
} }

View File

@@ -15,17 +15,14 @@
*/ */
package com.king.zxing.app; package com.king.zxing.app;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.king.zxing.CaptureActivity; import com.king.zxing.CaptureActivity;
import com.king.zxing.app.util.StatusBarUtils; import com.king.zxing.app.util.StatusBarUtils;
import com.king.zxing.camera.CameraConfigurationUtils; import com.king.zxing.camera.FrontLightMode;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
@@ -35,8 +32,6 @@ import androidx.appcompat.widget.Toolbar;
*/ */
public class CustomCaptureActivity extends CaptureActivity { public class CustomCaptureActivity extends CaptureActivity {
private ImageView ivFlash;
private boolean isContinuousScan; private boolean isContinuousScan;
@Override @Override
public int getLayoutId() { public int getLayoutId() {
@@ -52,12 +47,6 @@ public class CustomCaptureActivity extends CaptureActivity {
TextView tvTitle = findViewById(R.id.tvTitle); TextView tvTitle = findViewById(R.id.tvTitle);
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE)); tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
ivFlash = findViewById(R.id.ivFlash);
if(!hasTorch()){
ivFlash.setVisibility(View.GONE);
}
isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false); isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false);
//获取CaptureHelper里面有扫码相关的配置设置 //获取CaptureHelper里面有扫码相关的配置设置
getCaptureHelper().playBeep(false)//播放音效 getCaptureHelper().playBeep(false)//播放音效
@@ -67,28 +56,12 @@ public class CustomCaptureActivity extends CaptureActivity {
// .framingRectRatio(0.9f)//设置识别区域比例范围建议在0.625 ~ 1.0之间。非全屏识别时才有效 // .framingRectRatio(0.9f)//设置识别区域比例范围建议在0.625 ~ 1.0之间。非全屏识别时才有效
// .framingRectVerticalOffset(0)//设置识别区域垂直方向偏移量,非全屏识别时才有效 // .framingRectVerticalOffset(0)//设置识别区域垂直方向偏移量,非全屏识别时才有效
// .framingRectHorizontalOffset(0)//设置识别区域水平方向偏移量,非全屏识别时才有效 // .framingRectHorizontalOffset(0)//设置识别区域水平方向偏移量,非全屏识别时才有效
.frontLightMode(FrontLightMode.AUTO)//设置闪光灯模式
.tooDarkLux(45f)//设置光线太暗时,自动触发开启闪光灯的照度值
.brightEnoughLux(450f)//设置光线足够明亮时,自动触发关闭闪光灯的照度值
.continuousScan(isContinuousScan);//是否连扫 .continuousScan(isContinuousScan);//是否连扫
} }
/**
* 开启或关闭闪光灯(手电筒)
* @param on {@code true}表示开启,{@code false}表示关闭
*/
public void setTorch(boolean on){
Camera camera = getCameraManager().getOpenCamera().getCamera();
Camera.Parameters parameters = camera.getParameters();
CameraConfigurationUtils.setTorch(parameters,on);
camera.setParameters(parameters);
}
/**
* 检测是否支持闪光灯(手电筒)
* @return
*/
public boolean hasTorch(){
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
}
/** /**
* 扫码结果回调 * 扫码结果回调
@@ -104,21 +77,11 @@ public class CustomCaptureActivity extends CaptureActivity {
return super.onResultCallback(result); return super.onResultCallback(result);
} }
private void clickFlash(View v){
boolean isSelected = v.isSelected();
setTorch(!isSelected);
v.setSelected(!isSelected);
}
public void onClick(View v){ public void onClick(View v){
switch (v.getId()){ switch (v.getId()){
case R.id.ivLeft: case R.id.ivLeft:
onBackPressed(); onBackPressed();
break; break;
case R.id.ivFlash:
clickFlash(v);
break;
} }
} }
} }

View File

@@ -94,7 +94,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
} }
private void parsePhoto(Intent data){ private void parsePhoto(Intent data){
final String path = UriUtils.INSTANCE.getImagePath(this,data); final String path = UriUtils.getImagePath(this,data);
Log.d("Jenly","path:" + path); Log.d("Jenly","path:" + path);
if(TextUtils.isEmpty(path)){ if(TextUtils.isEmpty(path)){
return; return;

View File

@@ -33,8 +33,11 @@ import androidx.appcompat.widget.Toolbar;
/** /**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public enum StatusBarUtils { public final class StatusBarUtils {
INSTANCE;
private StatusBarUtils(){
throw new AssertionError();
}
public static void immersiveStatusBar(Activity activity, Toolbar toolbar) { public static void immersiveStatusBar(Activity activity, Toolbar toolbar) {
immersiveStatusBar(activity,toolbar,0.0f); immersiveStatusBar(activity,toolbar,0.0f);

View File

@@ -1,6 +1,5 @@
package com.king.zxing.app.util; package com.king.zxing.app.util;
import android.annotation.TargetApi;
import android.content.ContentUris; import android.content.ContentUris;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -14,13 +13,16 @@ import android.util.Log;
/** /**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public enum UriUtils { public final class UriUtils {
INSTANCE;
private UriUtils(){
throw new AssertionError();
}
/** /**
* 获取图片 * 获取图片
*/ */
public String getImagePath(Context context,Intent data) { public static String getImagePath(Context context,Intent data) {
String imagePath = null; String imagePath = null;
Uri uri = data.getData(); Uri uri = data.getData();
//获取系統版本 //获取系統版本
@@ -54,7 +56,7 @@ public enum UriUtils {
/** /**
* 通过uri和selection来获取真实的图片路径,从相册获取图片时要用 * 通过uri和selection来获取真实的图片路径,从相册获取图片时要用
*/ */
private String getImagePath(Context context,Uri uri, String selection) { private static String getImagePath(Context context,Uri uri, String selection) {
String path = null; String path = null;
Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null); Cursor cursor = context.getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) { if (cursor != null) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -31,7 +31,6 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="160dp" android:layout_marginTop="160dp" />
style="@style/OnClick"/>
<include layout="@layout/toolbar_capture"/> <include layout="@layout/toolbar_capture"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -22,7 +22,7 @@
app:labelTextLocation="bottom" app:labelTextLocation="bottom"
app:laserStyle="grid"/> app:laserStyle="grid"/>
<ImageView <ImageView
android:id="@+id/ivFlash" android:id="@+id/ivTorch"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/flash_selected_selector" android:src="@drawable/flash_selected_selector"
@@ -30,7 +30,6 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="160dp" android:layout_marginTop="160dp" />
style="@style/OnClick"/>
<include layout="@layout/toolbar_capture"/> <include layout="@layout/toolbar_capture"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -36,8 +36,17 @@ import com.king.zxing.camera.FrontLightMode;
*/ */
final class AmbientLightManager implements SensorEventListener { final class AmbientLightManager implements SensorEventListener {
private static final float TOO_DARK_LUX = 45.0f; protected static final float TOO_DARK_LUX = 45.0f;
private static final float BRIGHT_ENOUGH_LUX = 450.0f; protected static final float BRIGHT_ENOUGH_LUX = 100.0f;
/**
* 光线太暗时默认照度45 lux
*/
private float tooDarkLux = TOO_DARK_LUX;
/**
* 光线足够亮时默认照度450 lux
*/
private float brightEnoughLux = BRIGHT_ENOUGH_LUX;
private final Context context; private final Context context;
private CameraManager cameraManager; private CameraManager cameraManager;
@@ -72,14 +81,22 @@ final class AmbientLightManager implements SensorEventListener {
public void onSensorChanged(SensorEvent sensorEvent) { public void onSensorChanged(SensorEvent sensorEvent) {
float ambientLightLux = sensorEvent.values[0]; float ambientLightLux = sensorEvent.values[0];
if (cameraManager != null) { if (cameraManager != null) {
if (ambientLightLux <= TOO_DARK_LUX) { if (ambientLightLux <= tooDarkLux) {
cameraManager.setTorch(true); cameraManager.sensorChanged(true,ambientLightLux);
} else if (ambientLightLux >= BRIGHT_ENOUGH_LUX) { } else if (ambientLightLux >= brightEnoughLux) {
cameraManager.setTorch(false); cameraManager.sensorChanged(false,ambientLightLux);
} }
} }
} }
public void setTooDarkLux(float tooDarkLux){
this.tooDarkLux = tooDarkLux;
}
public void setBrightEnoughLux(float brightEnoughLux){
this.brightEnoughLux = brightEnoughLux;
}
@Override @Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do nothing // do nothing

View File

@@ -19,6 +19,7 @@ import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View;
import com.king.zxing.camera.CameraManager; import com.king.zxing.camera.CameraManager;
@@ -32,6 +33,7 @@ public class CaptureActivity extends Activity implements OnCaptureCallback{
private SurfaceView surfaceView; private SurfaceView surfaceView;
private ViewfinderView viewfinderView; private ViewfinderView viewfinderView;
private View ivTorch;
private CaptureHelper mCaptureHelper; private CaptureHelper mCaptureHelper;
@@ -51,7 +53,12 @@ public class CaptureActivity extends Activity implements OnCaptureCallback{
public void initUI(){ public void initUI(){
surfaceView = findViewById(getSurfaceViewId()); surfaceView = findViewById(getSurfaceViewId());
viewfinderView = findViewById(getViewfinderViewId()); viewfinderView = findViewById(getViewfinderViewId());
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView); int ivTorchId = getIvTorchId();
if(ivTorchId != 0){
ivTorch = findViewById(ivTorchId);
ivTorch.setVisibility(View.INVISIBLE);
}
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
mCaptureHelper.setOnCaptureCallback(this); mCaptureHelper.setOnCaptureCallback(this);
mCaptureHelper.onCreate(); mCaptureHelper.onCreate();
} }
@@ -74,7 +81,7 @@ public class CaptureActivity extends Activity implements OnCaptureCallback{
} }
/** /**
* {@link ViewfinderView} 的 id * {@link #viewfinderView} 的 ID
* @return * @return
*/ */
public int getViewfinderViewId(){ public int getViewfinderViewId(){
@@ -83,13 +90,21 @@ public class CaptureActivity extends Activity implements OnCaptureCallback{
/** /**
* 预览界面{@link #surfaceView} 的id * 预览界面{@link #surfaceView} 的ID
* @return * @return
*/ */
public int getSurfaceViewId(){ public int getSurfaceViewId(){
return R.id.surfaceView; return R.id.surfaceView;
} }
/**
* 获取 {@link #ivTorch} 的ID
* @return 默认返回{@code R.id.ivTorch}, 如果不需要手电筒按钮可以返回0
*/
public int getIvTorchId(){
return R.id.ivTorch;
}
/** /**
* Get {@link CaptureHelper} * Get {@link CaptureHelper}
* @return {@link #mCaptureHelper} * @return {@link #mCaptureHelper}

View File

@@ -38,6 +38,7 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
private SurfaceView surfaceView; private SurfaceView surfaceView;
private ViewfinderView viewfinderView; private ViewfinderView viewfinderView;
private View ivTorch;
private CaptureHelper mCaptureHelper; private CaptureHelper mCaptureHelper;
@@ -67,7 +68,12 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
public void initUI(){ public void initUI(){
surfaceView = mRootView.findViewById(getSurfaceViewId()); surfaceView = mRootView.findViewById(getSurfaceViewId());
viewfinderView = mRootView.findViewById(getViewfinderViewId()); viewfinderView = mRootView.findViewById(getViewfinderViewId());
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView); int ivTorchId = getIvTorchId();
if(ivTorchId != 0){
ivTorch = mRootView.findViewById(ivTorchId);
ivTorch.setVisibility(View.INVISIBLE);
}
mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
mCaptureHelper.setOnCaptureCallback(this); mCaptureHelper.setOnCaptureCallback(this);
} }
@@ -96,7 +102,6 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
return R.id.viewfinderView; return R.id.viewfinderView;
} }
/** /**
* 预览界面{@link #surfaceView} 的id * 预览界面{@link #surfaceView} 的id
* @return * @return
@@ -105,6 +110,14 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
return R.id.surfaceView; return R.id.surfaceView;
} }
/**
* 获取 {@link #ivTorch} 的ID
* @return 默认返回{@code R.id.ivTorch}, 如果不需要手电筒按钮可以返回0
*/
public int getIvTorchId(){
return R.id.ivTorch;
}
/** /**
* Get {@link CaptureHelper} * Get {@link CaptureHelper}
* @return {@link #mCaptureHelper} * @return {@link #mCaptureHelper}

View File

@@ -17,6 +17,7 @@ package com.king.zxing;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.hardware.Camera; import android.hardware.Camera;
@@ -24,11 +25,13 @@ import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType; import com.google.zxing.DecodeHintType;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.king.zxing.camera.CameraManager; import com.king.zxing.camera.CameraManager;
import com.king.zxing.camera.FrontLightMode;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -62,6 +65,7 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
private ViewfinderView viewfinderView; private ViewfinderView viewfinderView;
private SurfaceHolder surfaceHolder; private SurfaceHolder surfaceHolder;
private SurfaceHolder.Callback callback; private SurfaceHolder.Callback callback;
private View ivTorch;
private Collection<BarcodeFormat> decodeFormats; private Collection<BarcodeFormat> decodeFormats;
private Map<DecodeHintType,Object> decodeHints; private Map<DecodeHintType,Object> decodeHints;
@@ -127,21 +131,58 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
* 识别区域水平方向偏移量 * 识别区域水平方向偏移量
*/ */
private int framingRectHorizontalOffset; private int framingRectHorizontalOffset;
/**
* 光线太暗,当光线亮度太暗,亮度低于此值时,显示手电筒按钮
*/
private float tooDarkLux = AmbientLightManager.TOO_DARK_LUX;
/**
* 光线足够明亮,当光线亮度足够明亮,亮度高于此值时,隐藏手电筒按钮
*/
private float brightEnoughLux = AmbientLightManager.BRIGHT_ENOUGH_LUX;
/**
* 扫码回调
*/
private OnCaptureCallback onCaptureCallback; private OnCaptureCallback onCaptureCallback;
/**
* use {@link #CaptureHelper(Fragment, SurfaceView, ViewfinderView, View)}
* @param fragment
* @param surfaceView
* @param viewfinderView
*/
@Deprecated
public CaptureHelper(Fragment fragment, SurfaceView surfaceView, ViewfinderView viewfinderView){ public CaptureHelper(Fragment fragment, SurfaceView surfaceView, ViewfinderView viewfinderView){
this(fragment.getActivity(),surfaceView,viewfinderView); this(fragment,surfaceView,viewfinderView,null);
} }
public CaptureHelper(Fragment fragment, SurfaceView surfaceView, ViewfinderView viewfinderView,View ivTorch){
this(fragment.getActivity(),surfaceView,viewfinderView,ivTorch);
}
/**
* use {@link #CaptureHelper(Activity, SurfaceView, ViewfinderView, View)}
* @param activity
* @param surfaceView
* @param viewfinderView
*/
@Deprecated
public CaptureHelper(Activity activity,SurfaceView surfaceView,ViewfinderView viewfinderView){ public CaptureHelper(Activity activity,SurfaceView surfaceView,ViewfinderView viewfinderView){
this(activity,surfaceView,viewfinderView,null);
}
/**
*
* @param activity
* @param surfaceView
* @param viewfinderView
* @param ivTorch
*/
public CaptureHelper(Activity activity,SurfaceView surfaceView,ViewfinderView viewfinderView,View ivTorch){
this.activity = activity; this.activity = activity;
this.viewfinderView = viewfinderView; this.viewfinderView = viewfinderView;
this.ivTorch = ivTorch;
surfaceHolder = surfaceView.getHolder(); surfaceHolder = surfaceView.getHolder();
hasSurface = false; hasSurface = false;
} }
@@ -156,6 +197,22 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
cameraManager.setFramingRectRatio(framingRectRatio); cameraManager.setFramingRectRatio(framingRectRatio);
cameraManager.setFramingRectVerticalOffset(framingRectVerticalOffset); cameraManager.setFramingRectVerticalOffset(framingRectVerticalOffset);
cameraManager.setFramingRectHorizontalOffset(framingRectHorizontalOffset); cameraManager.setFramingRectHorizontalOffset(framingRectHorizontalOffset);
if(ivTorch !=null && activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
ivTorch.setOnClickListener(v -> cameraManager.setTorch(!ivTorch.isSelected()));
cameraManager.setOnSensorListener((torch, tooDark, ambientLightLux) -> {
if(tooDark){
if(ivTorch.getVisibility() != View.VISIBLE){
ivTorch.setVisibility(View.VISIBLE);
}
}else if(!torch){
if(ivTorch.getVisibility() == View.VISIBLE){
ivTorch.setVisibility(View.INVISIBLE);
}
}
});
cameraManager.setOnTorchListener(torch -> ivTorch.setSelected(torch));
}
callback = new SurfaceHolder.Callback() { callback = new SurfaceHolder.Callback() {
@Override @Override
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
@@ -187,6 +244,11 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
//设置是否播放音效和震动 //设置是否播放音效和震动
beepManager.setPlayBeep(isPlayBeep); beepManager.setPlayBeep(isPlayBeep);
beepManager.setVibrate(isVibrate); beepManager.setVibrate(isVibrate);
//设置闪光灯的太暗时和足够亮时的照度值
ambientLightManager.setTooDarkLux(tooDarkLux);
ambientLightManager.setBrightEnoughLux(brightEnoughLux);
} }
@@ -566,6 +628,49 @@ public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,Capture
return this; return this;
} }
/**
* 设置闪光灯模式。当设置模式为:{@link FrontLightMode#AUTO}时,如果满意默认的照度值范围,
* 可通过{@link #tooDarkLux(float)}和{@link #brightEnoughLux(float)}来自定义照度范围,
* 控制自动触发开启和关闭闪光灯。
* 当设置模式非{@link FrontLightMode#AUTO}时,传感器不会检测,则不使用手电筒
*
* @param mode 默认:{@link FrontLightMode#AUTO}
* @return
*/
public CaptureHelper frontLightMode(FrontLightMode mode) {
FrontLightMode.put(activity,mode);
if(ivTorch!=null && mode != FrontLightMode.AUTO){
ivTorch.setVisibility(View.INVISIBLE);
}
return this;
}
/**
* 设置光线太暗时,自动显示手电筒按钮
* @param tooDarkLux 默认:{@link AmbientLightManager#TOO_DARK_LUX}
* @return
*/
public CaptureHelper tooDarkLux(float tooDarkLux) {
this.tooDarkLux = tooDarkLux;
if(ambientLightManager != null){
ambientLightManager.setTooDarkLux(tooDarkLux);
}
return this;
}
/**
* 设置光线足够明亮时,自动隐藏手电筒按钮
* @param brightEnoughLux 默认:{@link AmbientLightManager#BRIGHT_ENOUGH_LUX}
* @return
*/
public CaptureHelper brightEnoughLux(float brightEnoughLux) {
this.brightEnoughLux = brightEnoughLux;
if(ambientLightManager != null){
ambientLightManager.setTooDarkLux(tooDarkLux);
}
return this;
}
/** /**
* 设置返回扫码原图 * 设置返回扫码原图
* @param returnBitmap 默认为false当返回true表示扫码就结果会返回扫码原图相应的会增加性能消耗。 * @param returnBitmap 默认为false当返回true表示扫码就结果会返回扫码原图相应的会增加性能消耗。

View File

@@ -73,6 +73,11 @@ public final class CameraManager {
*/ */
private final PreviewCallback previewCallback; private final PreviewCallback previewCallback;
private OnTorchListener onTorchListener;
private OnSensorListener onSensorListener;
private boolean isTorch;
public CameraManager(Context context) { public CameraManager(Context context) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.configManager = new CameraConfigurationManager(context); this.configManager = new CameraConfigurationManager(context);
@@ -193,14 +198,22 @@ public final class CameraManager {
autoFocusManager.stop(); autoFocusManager.stop();
autoFocusManager = null; autoFocusManager = null;
} }
this.isTorch = newSetting;
configManager.setTorch(theCamera.getCamera(), newSetting); configManager.setTorch(theCamera.getCamera(), newSetting);
if (wasAutoFocusManager) { if (wasAutoFocusManager) {
autoFocusManager = new AutoFocusManager(context, theCamera.getCamera()); autoFocusManager = new AutoFocusManager(context, theCamera.getCamera());
autoFocusManager.start(); autoFocusManager.start();
} }
if(onTorchListener!=null){
onTorchListener.onTorchChanged(newSetting);
}
} }
} }
/** /**
* A single preview frame will be returned to the handler supplied. The data will arrive as byte[] * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
* in the message.obj field, with width and height encoded as message.arg1 and message.arg2, * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
@@ -377,4 +390,49 @@ public final class CameraManager {
size, size, false); size, size, false);
} }
/**
* 提供闪光灯监听
* @param listener
*/
public void setOnTorchListener(OnTorchListener listener){
this.onTorchListener = listener;
}
/**
* 传感器光线照度监听
* @param listener
*/
public void setOnSensorListener(OnSensorListener listener){
this.onSensorListener = listener;
}
public void sensorChanged(boolean tooDark,float ambientLightLux){
if(onSensorListener!=null){
onSensorListener.onSensorChanged(isTorch,tooDark,ambientLightLux);
}
}
public interface OnTorchListener{
/**
* 当闪光灯状态改变时触发
* @param torch true表示开启、false表示关闭
*/
void onTorchChanged(boolean torch);
}
/**
* 传感器灯光亮度监听
*/
public interface OnSensorListener{
/**
*
* @param torch 闪光灯是否开启
* @param tooDark 传感器检测到的光线亮度,是否太暗
* @param ambientLightLux 光线照度
*/
void onSensorChanged(boolean torch,boolean tooDark,float ambientLightLux);
}
} }

View File

@@ -16,7 +16,9 @@ package com.king.zxing.camera;
*/ */
import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.king.zxing.Preferences; import com.king.zxing.Preferences;
@@ -33,11 +35,16 @@ public enum FrontLightMode {
OFF; OFF;
private static FrontLightMode parse(String modeString) { private static FrontLightMode parse(String modeString) {
return modeString == null ? OFF : valueOf(modeString); return modeString == null ? AUTO : valueOf(modeString);
} }
public static FrontLightMode readPref(SharedPreferences sharedPrefs) { public static FrontLightMode readPref(SharedPreferences sharedPrefs) {
return parse(sharedPrefs.getString(Preferences.KEY_FRONT_LIGHT_MODE, OFF.toString())); return parse(sharedPrefs.getString(Preferences.KEY_FRONT_LIGHT_MODE, AUTO.toString()));
}
public static void put(Context context, FrontLightMode mode) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString(Preferences.KEY_FRONT_LIGHT_MODE, mode.toString()).commit();
} }
} }

View File

@@ -46,13 +46,14 @@ import java.util.Map;
import java.util.Vector; import java.util.Vector;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
/** /**
* @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a> * @author Jenly <a href="mailto:jenly1314@gmail.com">Jenly</a>
*/ */
public class CodeUtils { public final class CodeUtils {
private CodeUtils(){ private CodeUtils(){
throw new AssertionError(); throw new AssertionError();
@@ -60,8 +61,8 @@ public class CodeUtils {
/** /**
* 生成二维码 * 生成二维码
* @param content * @param content 二维码的内容
* @param heightPix * @param heightPix 二维码的高
* @return * @return
*/ */
public static Bitmap createQRCode(String content, int heightPix) { public static Bitmap createQRCode(String content, int heightPix) {
@@ -69,13 +70,25 @@ public class CodeUtils {
} }
/** /**
* 生成二维码 * 生成二维码
* @param content * @param content 二维码的内容
* @param heightPix * @param heightPix 二维码的高
* @param logo * @param logo logo大小默认占二维码的20%
* @return * @return
*/ */
public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) { public static Bitmap createQRCode(String content, int heightPix, Bitmap logo) {
return createQRCode(content,heightPix,logo,0.2f);
}
/**
* 生成二维码
* @param content 二维码的内容
* @param heightPix 二维码的高
* @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) {
//配置参数 //配置参数
Map<EncodeHintType, Object> hints = new HashMap<>(); Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put( EncodeHintType.CHARACTER_SET, "utf-8"); hints.put( EncodeHintType.CHARACTER_SET, "utf-8");
@@ -83,18 +96,19 @@ public class CodeUtils {
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度 //设置空白边距的宽度
hints.put(EncodeHintType.MARGIN, 1); //default is 4 hints.put(EncodeHintType.MARGIN, 1); //default is 4
return createQRCode(content,heightPix,logo,hints); return createQRCode(content,heightPix,logo,ratio,hints);
} }
/** /**
* 生成二维码 * 生成二维码
* @param content * @param content 二维码的内容
* @param heightPix * @param heightPix 二维码的高
* @param logo * @param logo 二维码中间的logo
* @param ratio logo所占比例 因为二维码的最大容错率为30%所以建议ratio的范围小于0.3
* @param hints * @param hints
* @return * @return
*/ */
public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,Map<EncodeHintType,?> hints) { public static Bitmap createQRCode(String content, int heightPix, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f)float ratio,Map<EncodeHintType,?> hints) {
try { try {
// 图像数据转换,使用了矩阵转换 // 图像数据转换,使用了矩阵转换
@@ -117,7 +131,7 @@ public class CodeUtils {
bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix); bitmap.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix);
if (logo != null) { if (logo != null) {
bitmap = addLogo(bitmap, logo); bitmap = addLogo(bitmap, logo,ratio);
} }
return bitmap; return bitmap;
@@ -130,8 +144,12 @@ public class CodeUtils {
/** /**
* 在二维码中间添加Logo图案 * 在二维码中间添加Logo图案
* @param src
* @param logo
* @param ratio logo所占比例 因为二维码的最大容错率为30%所以建议ratio的范围小于0.3
* @return
*/ */
private static Bitmap addLogo(Bitmap src, Bitmap logo) { private static Bitmap addLogo(Bitmap src, Bitmap logo,@FloatRange(from = 0.0f,to = 1.0f) float ratio) {
if (src == null) { if (src == null) {
return null; return null;
} }
@@ -154,8 +172,8 @@ public class CodeUtils {
return src; return src;
} }
//logo大小为二维码整体大小的1/6 //logo大小为二维码整体大小
float scaleFactor = srcWidth * 1.0f / 6 / logoWidth; float scaleFactor = srcWidth * ratio / logoWidth;
Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
try { try {
Canvas canvas = new Canvas(bitmap); Canvas canvas = new Canvas(bitmap);
@@ -256,7 +274,7 @@ public class CodeUtils {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try { try {
result = reader.decodeWithState(bitmap); result = reader.decodeWithState(bitmap);
} catch (Exception e) {//解析失败则通过GlobalHistogramBinarizer 再试一次 } catch (Exception e) {//解析失败则通过GlobalHistogramBinarizer 再试一次
BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source)); BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source));
try { try {
result = reader.decodeWithState(bitmap1); result = reader.decodeWithState(bitmap1);
@@ -291,7 +309,7 @@ public class CodeUtils {
int h = newOpts.outHeight; int h = newOpts.outHeight;
float width = 800f; float width = 800f;
float height = 480f; float height = 480f;
// 缩放比由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 // 缩放比由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;// be=1表示不缩放 int be = 1;// be=1表示不缩放
if (w > h && w > width) {// 如果宽度大的话根据宽度固定大小缩放 if (w > h && w > width) {// 如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / width); be = (int) (newOpts.outWidth / width);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

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

View File

@@ -23,5 +23,11 @@
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
android:id="@+id/ivTorch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/zxl_torch_selector"
android:layout_marginTop="@dimen/torchMarginTop" />
</FrameLayout> </FrameLayout>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CaptureTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="colorPrimary">@android:color/black</item>
<item name="colorPrimaryDark">@android:color/black</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CaptureTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="colorPrimary">@android:color/black</item>
<item name="colorPrimaryDark">@android:color/black</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@color/capture_status_bar_color</item>
<item name="android:navigationBarColor">@color/capture_navigation_bar_color</item>
</style>
</resources>

View File

@@ -8,4 +8,7 @@
<color name="viewfinder_result_point_color">#C0FFBD21</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="capture_navigation_bar_color">#00000000</color>
</resources> </resources>

View File

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

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CaptureTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="colorPrimary">@android:color/black</item>
<item name="colorPrimaryDark">@android:color/black</item>
</style>
</resources>

View File

@@ -1,7 +1,7 @@
//App //App
def app_version = [:] def app_version = [:]
app_version.versionCode = 14 app_version.versionCode = 16
app_version.versionName = "1.1.3-androidx" app_version.versionName = "1.1.4-androidx"
ext.app_version = app_version ext.app_version = app_version
//build version //build version