diff --git a/README.md b/README.md
index 7cfc830..0c837c5 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,10 @@ ZXingLite for Android 是ZXing的精简版,基于ZXing库优化扫码和生成
| frameLineWidth | dimension | 1dp | 边框线宽度 |
| scannerAnimationDelay | integer | 20 | 扫描动画延迟间隔时间,单位:毫秒 |
| frameRatio | float | 0.625f | 扫码框与屏幕占比 |
+| framePaddingLeft | dimension | 0 | 扫码框左边的内间距 |
+| framePaddingTop | dimension | 0 | 扫码框上边的内间距 |
+| framePaddingRight | dimension | 0 | 扫码框右边的内间距 |
+| framePaddingBottom | dimension | 0 | 扫码框下边的内间距 |
## 引入
diff --git a/app/build.gradle b/app/build.gradle
index e68691a..822d281 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,6 @@
apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion build_versions.compileSdk
@@ -22,10 +24,15 @@ android {
abortOnError false
}
+
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
}
dependencies {
@@ -33,11 +40,14 @@ dependencies {
testImplementation deps.test.junit
androidTestImplementation deps.test.runner
androidTestImplementation deps.test.espresso
- //support
+
implementation deps.support.design
implementation deps.support.appcompat
implementation deps.support.constraintlayout
+ implementation deps.kotlin
+ implementation deps.corektx
+
implementation deps.easypermissions
implementation project(':lib')
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7cc0f0d..51d4581 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,9 +46,16 @@
android:screenOrientation="portrait"
android:theme="@style/CaptureTheme"/>
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/king/zxing/app/CustomActivity.java b/app/src/main/java/com/king/zxing/app/CustomActivity.java
index 3cd2059..99754be 100644
--- a/app/src/main/java/com/king/zxing/app/CustomActivity.java
+++ b/app/src/main/java/com/king/zxing/app/CustomActivity.java
@@ -9,31 +9,33 @@ import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.Result;
-import com.king.zxing.CaptureHelper;
-import com.king.zxing.OnCaptureCallback;
+import com.king.zxing.CameraScan;
+import com.king.zxing.DefaultCameraScan;
+import com.king.zxing.ICameraScan;
import com.king.zxing.ViewfinderView;
import com.king.zxing.app.util.StatusBarUtils;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
+import androidx.camera.view.PreviewView;
import androidx.fragment.app.Fragment;
/**
* 自定义扫码:当直接使用CaptureActivity
- * 自定义扫码,切记自定义扫码需在{@link Activity}或者{@link Fragment}相对应的生命周期里面调用{@link #mCaptureHelper}对应的生命周期
+ * 自定义扫码,切记自定义扫码需在{@link Activity}或者{@link Fragment}相对应的生命周期里面调用{@link #mCameraScan}对应的生命周期
* @author Jenly
*/
-public class CustomActivity extends AppCompatActivity implements OnCaptureCallback {
+public class CustomActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback {
private boolean isContinuousScan;
- private CaptureHelper mCaptureHelper;
+ private CameraScan mCameraScan;
- private SurfaceView surfaceView;
+ private PreviewView previewView;
private ViewfinderView viewfinderView;
- private View ivTorch;
+ private View ivFlash;
private Toast toast;
@@ -53,60 +55,38 @@ public class CustomActivity extends AppCompatActivity implements OnCaptureCallba
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
- surfaceView = findViewById(R.id.surfaceView);
+ previewView = findViewById(R.id.previewView);
viewfinderView = findViewById(R.id.viewfinderView);
- ivTorch = findViewById(R.id.ivFlash);
- ivTorch.setVisibility(View.INVISIBLE);
+ ivFlash = findViewById(R.id.ivFlash);
+ ivFlash.setVisibility(View.INVISIBLE);
isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false);
- mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
- mCaptureHelper.setOnCaptureCallback(this);
- mCaptureHelper.onCreate();
- mCaptureHelper.vibrate(true)
- .fullScreenScan(true)//全屏扫码
- .supportVerticalCode(true)//支持扫垂直条码,建议有此需求时才使用。
- .supportLuminanceInvert(true)//是否支持识别反色码(黑白反色的码),增加识别率
- .continuousScan(isContinuousScan);
+ mCameraScan = new DefaultCameraScan(this,previewView);
+ mCameraScan.setOnScanResultCallback(this);
- }
+ mCameraScan.startCamera();
- @Override
- protected void onResume() {
- super.onResume();
- mCaptureHelper.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mCaptureHelper.onPause();
}
@Override
protected void onDestroy() {
+ mCameraScan.release();
super.onDestroy();
- mCaptureHelper.onDestroy();
}
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mCaptureHelper.onTouchEvent(event);
- return super.onTouchEvent(event);
- }
-
-
/**
* 扫码结果回调
* @param result 扫码结果
* @return
*/
@Override
- public boolean onResultCallback(Result result) {
+ public boolean onScanResultCallback(Result result) {
if(isContinuousScan){
showToast(result.getText());
}
- return false;
+ //如果需支持连扫,返回true即可
+ return isContinuousScan;
}
private void showToast(String text){
diff --git a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java
index c606ee2..bb7a594 100644
--- a/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java
+++ b/app/src/main/java/com/king/zxing/app/CustomCaptureActivity.java
@@ -52,21 +52,16 @@ public class CustomCaptureActivity extends CaptureActivity {
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
isContinuousScan = getIntent().getBooleanExtra(MainActivity.KEY_IS_CONTINUOUS,false);
- //获取CaptureHelper,里面有扫码相关的配置设置
- getCaptureHelper().playBeep(false)//播放音效
- .vibrate(true)//震动
- .fullScreenScan(true)
- .supportVerticalCode(true)//支持扫垂直条码,建议有此需求时才使用。
-// .decodeFormats(DecodeFormatManager.QR_CODE_FORMATS)//设置只识别二维码会提升速度
-// .framingRectRatio(0.9f)//设置识别区域比例,范围建议在0.625 ~ 1.0之间。非全屏识别时才有效
-// .framingRectVerticalOffset(0)//设置识别区域垂直方向偏移量,非全屏识别时才有效
-// .framingRectHorizontalOffset(0)//设置识别区域水平方向偏移量,非全屏识别时才有效
- .tooDarkLux(45f)//设置光线太暗时,自动触发开启闪光灯的照度值
- .brightEnoughLux(100f)//设置光线足够明亮时,自动触发关闭闪光灯的照度值
- .continuousScan(isContinuousScan)//是否连扫
- .supportLuminanceInvert(true);//是否支持识别反色码(黑白反色的码),增加识别率
+
}
+ @Override
+ public void initCameraScan() {
+ super.initCameraScan();
+ //获取CaptureHelper,里面有扫码相关的配置设置
+ getCameraScan().setPlayBeep(false)//播放音效
+ .setVibrate(true);//震动
+ }
/**
* 扫码结果回调
@@ -74,12 +69,12 @@ public class CustomCaptureActivity extends CaptureActivity {
* @return
*/
@Override
- public boolean onResultCallback(Result result) {
- if(isContinuousScan){//连续扫码时,直接弹出结果
+ public boolean onScanResultCallback(Result result) {
+ if(isContinuousScan){
showToast(result.getText());
}
-
- return super.onResultCallback(result);
+ //如果支持连扫,返回true即可
+ return isContinuousScan;
}
private void showToast(String text){
diff --git a/app/src/main/java/com/king/zxing/app/EasyCaptureActivity.java b/app/src/main/java/com/king/zxing/app/EasyCaptureActivity.java
index 8efa631..ac546f2 100644
--- a/app/src/main/java/com/king/zxing/app/EasyCaptureActivity.java
+++ b/app/src/main/java/com/king/zxing/app/EasyCaptureActivity.java
@@ -42,10 +42,15 @@ public class EasyCaptureActivity extends CaptureActivity {
StatusBarUtils.immersiveStatusBar(this,toolbar,0.2f);
TextView tvTitle = findViewById(R.id.tvTitle);
tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
- getCaptureHelper()
-// .decodeFormats(DecodeFormatManager.QR_CODE_FORMATS)//设置只识别二维码会提升速度
- .playBeep(true)
- .vibrate(true);
+
+ }
+
+ @Override
+ public void initCameraScan() {
+ super.initCameraScan();
+ getCameraScan()
+ .setPlayBeep(true)
+ .setVibrate(true);
}
public void onClick(View v){
diff --git a/app/src/main/java/com/king/zxing/app/MainActivity.java b/app/src/main/java/com/king/zxing/app/MainActivity.java
index f6cb14c..91f2516 100644
--- a/app/src/main/java/com/king/zxing/app/MainActivity.java
+++ b/app/src/main/java/com/king/zxing/app/MainActivity.java
@@ -26,12 +26,12 @@ import android.view.View;
import android.widget.Button;
import android.widget.Toast;
+import com.king.zxing.CameraScan;
import com.king.zxing.CaptureActivity;
-import com.king.zxing.Intents;
import com.king.zxing.app.util.UriUtils;
import com.king.zxing.util.CodeUtils;
+import com.king.zxing.util.LogUtils;
-import org.w3c.dom.Text;
import java.util.List;
@@ -78,6 +78,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+
}
@Override
@@ -86,7 +87,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
if(resultCode == RESULT_OK && data!=null){
switch (requestCode){
case REQUEST_CODE_SCAN:
- String result = data.getStringExtra(Intents.Scan.RESULT);
+ String result = CameraScan.parseScanResult(data);
showToast(result);
break;
case REQUEST_CODE_PHOTO:
@@ -109,7 +110,7 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
private void parsePhoto(Intent data){
final String path = UriUtils.getImagePath(this,data);
- Log.d("Jenly","path:" + path);
+ LogUtils.d("path:" + path);
if(TextUtils.isEmpty(path)){
return;
}
@@ -254,6 +255,11 @@ public class MainActivity extends AppCompatActivity implements EasyPermissions.P
case R.id.btn7:
checkExternalStoragePermissions();
break;
+ case R.id.btn8:
+ this.cls = QRCodeActivity.class;
+ this.title = ((Button)v).getText().toString();
+ checkCameraPermissions();
+ break;
}
}
diff --git a/app/src/main/java/com/king/zxing/app/QRCodeActivity.java b/app/src/main/java/com/king/zxing/app/QRCodeActivity.java
new file mode 100644
index 0000000..8ebd4c1
--- /dev/null
+++ b/app/src/main/java/com/king/zxing/app/QRCodeActivity.java
@@ -0,0 +1,49 @@
+package com.king.zxing.app;
+
+import android.os.Bundle;
+import android.widget.TextView;
+
+import com.google.zxing.Result;
+import com.king.zxing.CaptureActivity;
+import com.king.zxing.DecodeFormatManager;
+import com.king.zxing.analyze.MultiFormatAnalyzer;
+import com.king.zxing.app.util.StatusBarUtils;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+
+/**
+ * @author Jenly
+ */
+public class QRCodeActivity extends CaptureActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ StatusBarUtils.immersiveStatusBar(this,toolbar,0.2f);
+ TextView tvTitle = findViewById(R.id.tvTitle);
+ tvTitle.setText(getIntent().getStringExtra(MainActivity.KEY_TITLE));
+ }
+
+
+ @Override
+ public int getLayoutId() {
+ return R.layout.qr_code_activity;
+ }
+
+ @Override
+ public void initCameraScan() {
+ super.initCameraScan();
+ //在启动预览之前,设置分析器,只识别二维码,如果只有识别二维码的需求,这样效率更多高
+ getCameraScan()
+ .setVibrate(true)
+ .setAnalyzer(new MultiFormatAnalyzer(DecodeFormatManager.QR_CODE_HINTS));
+ }
+
+ @Override
+ public boolean onScanResultCallback(Result result) {
+ return super.onScanResultCallback(result);
+ }
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index a557909..e905d87 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -131,4 +131,17 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn6"
style="@style/OnClick"/>
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/custom_activity.xml b/app/src/main/res/layout/custom_activity.xml
index 7822dbd..7d751f3 100644
--- a/app/src/main/res/layout/custom_activity.xml
+++ b/app/src/main/res/layout/custom_activity.xml
@@ -5,8 +5,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 379587a..2acaa0a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,9 +6,9 @@ buildscript {
addRepos(repositories)
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
- classpath 'com.novoda:bintray-release:0.9'
-
+ classpath "com.android.tools.build:gradle:$versions.gralde"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlin"
+ classpath "com.novoda:bintray-release:$versions.bintray_release"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4f698fe..9b554bc 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
diff --git a/lib/build.gradle b/lib/build.gradle
index 18d3f9e..a1d708b 100644
--- a/lib/build.gradle
+++ b/lib/build.gradle
@@ -44,4 +44,8 @@ dependencies {
api deps.support.appcompat
api deps.zxing
+ api deps.camera_core
+ api deps.camera_camera2
+ api deps.camera_lifecycle
+ api deps.camera_view
}
diff --git a/lib/src/main/AndroidManifest.xml b/lib/src/main/AndroidManifest.xml
index bd901ed..1aa341d 100644
--- a/lib/src/main/AndroidManifest.xml
+++ b/lib/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
diff --git a/lib/src/main/java/com/king/zxing/AmbientLightManager.java b/lib/src/main/java/com/king/zxing/AmbientLightManager.java
index fc5f07e..1c904b3 100644
--- a/lib/src/main/java/com/king/zxing/AmbientLightManager.java
+++ b/lib/src/main/java/com/king/zxing/AmbientLightManager.java
@@ -23,82 +23,88 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import com.king.zxing.camera.CameraManager;
-
/**
- * Detects ambient light and switches on the front light when very dark, and off again when sufficiently light.
- *
- * @author Sean Owen
- * @author Nikolaus Huber
+ * @author Jenly
*/
-final class AmbientLightManager implements SensorEventListener {
+public class AmbientLightManager implements SensorEventListener {
private static final int INTERVAL_TIME = 200;
- protected static final float TOO_DARK_LUX = 45.0f;
- protected static final float BRIGHT_ENOUGH_LUX = 100.0f;
+ protected static final float DARK_LUX = 45.0f;
+ protected static final float BRIGHT_LUX = 100.0f;
/**
* 光线太暗时,默认:照度45 lux
*/
- private float tooDarkLux = TOO_DARK_LUX;
+ private float darkLightLux = DARK_LUX;
/**
* 光线足够亮时,默认:照度450 lux
*/
- private float brightEnoughLux = BRIGHT_ENOUGH_LUX;
+ private float brightLightLux = BRIGHT_LUX;
- private final Context context;
- private CameraManager cameraManager;
+ private SensorManager sensorManager;
private Sensor lightSensor;
private long lastTime;
+ private boolean isLightSensorEnabled;
+
+ private OnLightSensorEventListener mOnLightSensorEventListener;
+
AmbientLightManager(Context context) {
- this.context = context;
+ sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ isLightSensorEnabled = true;
}
- void start(CameraManager cameraManager) {
- this.cameraManager = cameraManager;
- SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
- lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
- if (lightSensor != null) {
+ public void register() {
+ if (sensorManager != null && lightSensor != null) {
sensorManager.registerListener(this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
- void stop() {
- if (lightSensor != null) {
- SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ public void unregister() {
+ if (sensorManager != null && lightSensor != null) {
sensorManager.unregisterListener(this);
- cameraManager = null;
- lightSensor = null;
}
}
+
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
- long currentTime = System.currentTimeMillis();
- if(currentTime - lastTime < INTERVAL_TIME){//降低频率
- return;
- }
- lastTime = currentTime;
+ if(isLightSensorEnabled){
+ long currentTime = System.currentTimeMillis();
+ if(currentTime - lastTime < INTERVAL_TIME){//降低频率
+ return;
+ }
+ lastTime = currentTime;
- float ambientLightLux = sensorEvent.values[0];
- if (cameraManager != null) {
- if (ambientLightLux <= tooDarkLux) {
- cameraManager.sensorChanged(true,ambientLightLux);
- } else if (ambientLightLux >= brightEnoughLux) {
- cameraManager.sensorChanged(false,ambientLightLux);
+ if (mOnLightSensorEventListener != null) {
+ float lightLux = sensorEvent.values[0];
+ mOnLightSensorEventListener.onSensorChanged(lightLux);
+ if (lightLux <= darkLightLux) {
+ mOnLightSensorEventListener.onSensorChanged(true,darkLightLux);
+ } else if (lightLux >= brightLightLux) {
+ mOnLightSensorEventListener.onSensorChanged(false,darkLightLux);
+ }
}
}
}
- public void setTooDarkLux(float tooDarkLux){
- this.tooDarkLux = tooDarkLux;
+ /**
+ * 设置光线足够暗的阈值(单位:lux)
+ * @param lightLux
+ */
+ public void setDarkLightLux(float lightLux){
+ this.darkLightLux = lightLux;
}
- public void setBrightEnoughLux(float brightEnoughLux){
- this.brightEnoughLux = brightEnoughLux;
+ /**
+ * 设置光线足够明亮的阈值(单位:lux)
+ * @param lightLux
+ */
+ public void setBrightLightLux(float lightLux){
+ this.darkLightLux = lightLux;
}
@Override
@@ -106,4 +112,40 @@ final class AmbientLightManager implements SensorEventListener {
// do nothing
}
+ public boolean isLightSensorEnabled() {
+ return isLightSensorEnabled;
+ }
+
+ /**
+ * 设置是否启用光线亮度传感器
+ * @param lightSensorEnabled
+ */
+ public void setLightSensorEnabled(boolean lightSensorEnabled) {
+ isLightSensorEnabled = lightSensorEnabled;
+ }
+
+ /**
+ * 设置光线亮度传感器监听器,只有在 {@link #isLightSensorEnabled} 为{@code true} 才有效
+ * @param listener
+ */
+ public void setOnLightSensorEventListener(OnLightSensorEventListener listener){
+ mOnLightSensorEventListener = listener;
+ }
+
+ public interface OnLightSensorEventListener{
+ /**
+ *
+ * @param lightLux 当前检测到的光线照度值
+ */
+ default void onSensorChanged(float lightLux){
+
+ }
+
+ /**
+ * 传感器改变事件
+ * @param dark 是否太暗了,当检测到的光线照度值小于{@link #darkLightLux}时,为{@code true}
+ * @param lightLux 当前检测到的光线照度值
+ */
+ void onSensorChanged(boolean dark,float lightLux);
+ }
}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/BeepManager.java b/lib/src/main/java/com/king/zxing/BeepManager.java
index ffba77c..68aefb6 100644
--- a/lib/src/main/java/com/king/zxing/BeepManager.java
+++ b/lib/src/main/java/com/king/zxing/BeepManager.java
@@ -16,9 +16,7 @@ package com.king.zxing;
*/
-import android.app.Activity;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
@@ -27,23 +25,22 @@ import android.os.Vibrator;
import com.king.zxing.util.LogUtils;
import java.io.Closeable;
-import java.io.IOException;
/**
- * Manages beeps and vibrations for {@link Activity}.
+ * @author Jenly
*/
public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable {
-// private static final float BEEP_VOLUME = 0.10f;
private static final long VIBRATE_DURATION = 200L;
- private final Activity activity;
+ private final Context context;
private MediaPlayer mediaPlayer;
+ private Vibrator vibrator;
private boolean playBeep;
private boolean vibrate;
- BeepManager(Activity activity) {
- this.activity = activity;
+ BeepManager(Context context) {
+ this.context = context;
this.mediaPlayer = null;
updatePrefs();
}
@@ -56,53 +53,36 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable
this.playBeep = playBeep;
}
- synchronized void updatePrefs() {
-// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
-// shouldBeep(prefs, activity);
-// vibrate = prefs.getBoolean(Preferences.KEY_VIBRATE, false);
- if (playBeep && mediaPlayer == null) {
- // The volume on STREAM_SYSTEM is not adjustable, and users found it too loud,
- // so we now play on the music stream.
- activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
- mediaPlayer = buildMediaPlayer(activity);
+ private synchronized void updatePrefs() {
+ if (mediaPlayer == null) {
+ mediaPlayer = buildMediaPlayer(context);
+ }
+ if(vibrator == null){
+ vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
}
}
- synchronized void playBeepSoundAndVibrate() {
+ public synchronized void playBeepSoundAndVibrate() {
if (playBeep && mediaPlayer != null) {
mediaPlayer.start();
}
- LogUtils.d("vibrate:" + vibrate);
if (vibrate) {
- Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(VIBRATE_DURATION);
}
}
- private static boolean shouldBeep(SharedPreferences prefs, Context activity) {
- boolean shouldPlayBeep = prefs.getBoolean(Preferences.KEY_PLAY_BEEP, false);
- if (shouldPlayBeep) {
- // See if sound settings overrides this
- AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
- if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
- shouldPlayBeep = false;
- }
- }
- return shouldPlayBeep;
- }
-
- private MediaPlayer buildMediaPlayer(Context activity) {
+ private MediaPlayer buildMediaPlayer(Context context) {
MediaPlayer mediaPlayer = new MediaPlayer();
- try (AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.zxl_beep)) {
+ try {
+ AssetFileDescriptor file = context.getResources().openRawResourceFd(R.raw.zxl_beep);
mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(false);
-// mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
mediaPlayer.prepare();
return mediaPlayer;
- } catch (IOException ioe) {
- LogUtils.w(ioe);
+ } catch (Exception e) {
+ LogUtils.w(e);
mediaPlayer.release();
return null;
}
@@ -110,22 +90,20 @@ public final class BeepManager implements MediaPlayer.OnErrorListener, Closeable
@Override
public synchronized boolean onError(MediaPlayer mp, int what, int extra) {
- if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
- // we are finished, so put up an appropriate error toast if required and finish
- activity.finish();
- } else {
- // possibly media player error, so release and recreate
- close();
- updatePrefs();
- }
+ close();
+ updatePrefs();
return true;
}
@Override
public synchronized void close() {
- if (mediaPlayer != null) {
- mediaPlayer.release();
- mediaPlayer = null;
+ try{
+ if (mediaPlayer != null) {
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }catch (Exception e){
+ LogUtils.e(e);
}
}
diff --git a/lib/src/main/java/com/king/zxing/CameraConfig.java b/lib/src/main/java/com/king/zxing/CameraConfig.java
new file mode 100644
index 0000000..68ae44d
--- /dev/null
+++ b/lib/src/main/java/com/king/zxing/CameraConfig.java
@@ -0,0 +1,32 @@
+package com.king.zxing;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.Preview;
+
+/**
+ * @author Jenly
+ */
+public class CameraConfig {
+
+ public CameraConfig(){
+
+ }
+
+ @NonNull
+ public Preview options(@NonNull Preview.Builder builder){
+ return builder.build();
+ }
+
+ @NonNull
+ public CameraSelector options(@NonNull CameraSelector.Builder builder){
+ return builder.build();
+ }
+
+ @NonNull
+ public ImageAnalysis options(@NonNull ImageAnalysis.Builder builder){
+ return builder.build();
+ }
+
+}
diff --git a/lib/src/main/java/com/king/zxing/CameraScan.java b/lib/src/main/java/com/king/zxing/CameraScan.java
new file mode 100644
index 0000000..2069446
--- /dev/null
+++ b/lib/src/main/java/com/king/zxing/CameraScan.java
@@ -0,0 +1,189 @@
+package com.king.zxing;
+
+import android.content.Intent;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.google.zxing.Result;
+import com.king.zxing.analyze.Analyzer;
+import com.king.zxing.util.LogUtils;
+
+import androidx.annotation.Nullable;
+import androidx.camera.core.CameraSelector;
+
+import static com.king.zxing.CameraScan.*;
+
+/**
+ * @author Jenly
+ */
+public abstract class CameraScan implements ICameraScan {
+
+ /**
+ * 默认触控误差值
+ */
+ private static final int DEVIATION = 6;
+
+ public static String SCAN_RESULT = "SCAN_RESULT";
+
+ /** A camera on the device facing the same direction as the device's screen. */
+ public static int LENS_FACING_FRONT = CameraSelector.LENS_FACING_FRONT;
+ /** A camera on the device facing the opposite direction as the device's screen. */
+ public static int LENS_FACING_BACK = CameraSelector.LENS_FACING_BACK;
+
+
+ /**
+ * 是否需要支持自动缩放
+ */
+ private boolean isNeedAutoZoom = true;
+
+ /**
+ * 是否需要支持触摸缩放
+ */
+ private boolean isNeedTouchZoom = true;
+
+ private float mOldDistance;
+
+
+ /**
+ * 设置是否需要支持触摸缩放
+ * @param needTouchZoom
+ * @return
+ */
+ public CameraScan setNeedTouchZoom(boolean needTouchZoom) {
+ isNeedTouchZoom = needTouchZoom;
+ return this;
+ }
+
+ /**
+ * 是否需要支持自动缩放
+ * @return
+ */
+ protected boolean isNeedAutoZoom() {
+ return isNeedAutoZoom;
+ }
+
+ /**
+ * 设置是否需要支持自动缩放
+ * @param needAutoZoom
+ * @return
+ */
+ public CameraScan setNeedAutoZoom(boolean needAutoZoom) {
+ isNeedAutoZoom = needAutoZoom;
+ 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()}之前调用
+ * @param cameraConfig
+ */
+ public abstract CameraScan setCameraConfig(CameraConfig cameraConfig);
+
+ /**
+ * 设置是否分析图像
+ * @param analyze
+ */
+ public abstract CameraScan setAnalyzeImage(boolean analyze);
+
+ /**
+ * 设置分析器
+ * @param 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
+ */
+ public abstract CameraScan setVibrate(boolean vibrate);
+
+ /**
+ * 设置是否播放提示音
+ * @param playBeep
+ */
+ public abstract CameraScan setPlayBeep(boolean playBeep);
+
+ /**
+ * 设置扫码结果回调
+ * @param callback
+ */
+ public abstract CameraScan setOnScanResultCallback(OnScanResultCallback callback);
+
+ /**
+ * 绑定手电筒,绑定后可根据光线传感器,动态显示或隐藏手电筒
+ * @param v
+ */
+ public abstract CameraScan bindFlashlightView(@Nullable View v);
+
+
+ public interface OnScanResultCallback{
+ boolean onScanResultCallback(Result result);
+ }
+
+
+ @Nullable
+ public static String parseScanResult(Intent data){
+ if(data != null){
+ return data.getStringExtra(SCAN_RESULT);
+ }
+ return null;
+ }
+
+}
diff --git a/lib/src/main/java/com/king/zxing/CaptureActivity.java b/lib/src/main/java/com/king/zxing/CaptureActivity.java
index f92e430..e539722 100644
--- a/lib/src/main/java/com/king/zxing/CaptureActivity.java
+++ b/lib/src/main/java/com/king/zxing/CaptureActivity.java
@@ -17,28 +17,27 @@ package com.king.zxing;
import android.os.Bundle;
import android.view.MotionEvent;
-import android.view.SurfaceView;
import android.view.View;
import com.google.zxing.Result;
-import com.king.zxing.camera.CameraManager;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.view.PreviewView;
+import androidx.core.app.ActivityCompat;
/**
* @author Jenly
*/
-public class CaptureActivity extends AppCompatActivity implements OnCaptureCallback{
+public class CaptureActivity extends AppCompatActivity implements CameraScan.OnScanResultCallback{
- public static final String KEY_RESULT = Intents.Scan.RESULT;
- private SurfaceView surfaceView;
- private ViewfinderView viewfinderView;
- private View ivTorch;
+ protected PreviewView previewView;
+ protected ViewfinderView viewfinderView;
+ protected View ivFlashlight;
- private CaptureHelper mCaptureHelper;
+ private CameraScan mCameraScan;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -48,28 +47,60 @@ public class CaptureActivity extends AppCompatActivity implements OnCaptureCallb
setContentView(layoutId);
}
initUI();
- mCaptureHelper.onCreate();
}
/**
* 初始化
*/
public void initUI(){
- surfaceView = findViewById(getSurfaceViewId());
+ previewView = findViewById(getPreviewViewId());
int viewfinderViewId = getViewfinderViewId();
if(viewfinderViewId != 0){
viewfinderView = findViewById(viewfinderViewId);
}
- int ivTorchId = getIvTorchId();
- if(ivTorchId != 0){
- ivTorch = findViewById(ivTorchId);
+ int ivFlashlightId = getFlashlightId();
+ if(ivFlashlightId != 0){
+ ivFlashlight = findViewById(ivFlashlightId);
+ if(ivFlashlight != null){
+ ivFlashlight.setOnClickListener(v -> toggleTorch());
+ }
}
- initCaptureHelper();
+ initCameraScan();
+ startCamera();
}
- public void initCaptureHelper(){
- mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
- mCaptureHelper.setOnCaptureCallback(this);
+ public void initCameraScan(){
+ mCameraScan = new DefaultCameraScan(this,previewView);
+ mCameraScan.setOnScanResultCallback(this);
+ }
+
+
+ public void startCamera(){
+ if(mCameraScan != null){
+ mCameraScan.startCamera();
+ }
+ }
+
+ private void releaseCamera(){
+ if(mCameraScan != null){
+ mCameraScan.release();
+ }
+ }
+
+ protected void toggleTorch(){
+ if(mCameraScan != null){
+ boolean isTorch = mCameraScan.isTorchEnabled();
+ mCameraScan.enableTorch(!isTorch);
+ if(ivFlashlight != null){
+ ivFlashlight.setSelected(!isTorch);
+ }
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ releaseCamera();
+ super.onDestroy();
}
/**
@@ -99,60 +130,27 @@ public class CaptureActivity extends AppCompatActivity implements OnCaptureCallb
/**
- * 预览界面{@link #surfaceView} 的ID
+ * 预览界面{@link #previewView} 的ID
* @return
*/
- public int getSurfaceViewId(){
- return R.id.surfaceView;
+ public int getPreviewViewId(){
+ return R.id.previewView;
}
/**
- * 获取 {@link #ivTorch} 的ID
- * @return 默认返回{@code R.id.ivTorch}, 如果不需要手电筒按钮可以返回0
+ * 获取 {@link #ivFlashlight} 的ID
+ * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0
*/
- public int getIvTorchId(){
- return R.id.ivTorch;
+ public int getFlashlightId(){
+ return R.id.ivFlashlight;
}
/**
- * Get {@link CaptureHelper}
- * @return {@link #mCaptureHelper}
+ * Get {@link CameraScan}
+ * @return {@link #mCameraScan}
*/
- public CaptureHelper getCaptureHelper(){
- return mCaptureHelper;
- }
-
- /**
- * Get {@link CameraManager} use {@link #getCaptureHelper()#getCameraManager()}
- * @return {@link #mCaptureHelper#getCameraManager()}
- */
- @Deprecated
- public CameraManager getCameraManager(){
- return mCaptureHelper.getCameraManager();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mCaptureHelper.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mCaptureHelper.onPause();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mCaptureHelper.onDestroy();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mCaptureHelper.onTouchEvent(event);
- return super.onTouchEvent(event);
+ public CameraScan getCameraScan(){
+ return mCameraScan;
}
/**
@@ -161,7 +159,7 @@ public class CaptureActivity extends AppCompatActivity implements OnCaptureCallb
* @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截
*/
@Override
- public boolean onResultCallback(Result result) {
+ public boolean onScanResultCallback(Result result) {
return false;
}
}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/CaptureFragment.java b/lib/src/main/java/com/king/zxing/CaptureFragment.java
index bc40409..bf5ce96 100644
--- a/lib/src/main/java/com/king/zxing/CaptureFragment.java
+++ b/lib/src/main/java/com/king/zxing/CaptureFragment.java
@@ -17,31 +17,28 @@ package com.king.zxing;
import android.os.Bundle;
import android.view.LayoutInflater;
-import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import com.google.zxing.Result;
-import com.king.zxing.camera.CameraManager;
import androidx.annotation.LayoutRes;
-import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.camera.view.PreviewView;
import androidx.fragment.app.Fragment;
/**
* @author Jenly
*/
-public class CaptureFragment extends Fragment implements OnCaptureCallback {
-
- public static final String KEY_RESULT = Intents.Scan.RESULT;
+public class CaptureFragment extends Fragment implements CameraScan.OnScanResultCallback {
private View mRootView;
- private SurfaceView surfaceView;
- private ViewfinderView viewfinderView;
- private View ivTorch;
+ protected PreviewView previewView;
+ protected ViewfinderView viewfinderView;
+ protected View ivFlashlight;
- private CaptureHelper mCaptureHelper;
+ private CameraScan mCameraScan;
public static CaptureFragment newInstance() {
@@ -57,7 +54,7 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int layoutId = getLayoutId();
if(isContentView(layoutId)){
- mRootView = inflater.inflate(getLayoutId(),container,false);
+ mRootView = createRootView(inflater,container);
}
initUI();
return mRootView;
@@ -67,25 +64,57 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
* 初始化
*/
public void initUI(){
- surfaceView = mRootView.findViewById(getSurfaceViewId());
+ previewView = mRootView.findViewById(getPreviewViewId());
int viewfinderViewId = getViewfinderViewId();
if(viewfinderViewId != 0){
viewfinderView = mRootView.findViewById(viewfinderViewId);
}
- int ivTorchId = getIvTorchId();
- if(ivTorchId != 0){
- ivTorch = mRootView.findViewById(ivTorchId);
+ int ivFlashlightId = getFlashlightId();
+ if(ivFlashlightId != 0){
+ ivFlashlight = mRootView.findViewById(ivFlashlightId);
+ if(ivFlashlight != null){
+ ivFlashlight.setOnClickListener(v -> toggleTorch());
+ }
}
- initCaptureHelper();
+ initCameraScan();
+ startCamera();
}
- public void initCaptureHelper(){
- mCaptureHelper = new CaptureHelper(this,surfaceView,viewfinderView,ivTorch);
- mCaptureHelper.setOnCaptureCallback(this);
+ public void initCameraScan(){
+ mCameraScan = new DefaultCameraScan(this,previewView);
+ mCameraScan.setOnScanResultCallback(this);
+ }
+
+ public void startCamera(){
+ if(mCameraScan != null){
+ mCameraScan.startCamera();
+ }
+ }
+
+ private void releaseCamera(){
+ if(mCameraScan != null){
+ mCameraScan.release();
+ }
+ }
+
+ protected void toggleTorch(){
+ if(mCameraScan != null){
+ boolean isTorch = mCameraScan.isTorchEnabled();
+ mCameraScan.enableTorch(!isTorch);
+ if(ivFlashlight != null){
+ ivFlashlight.setSelected(!isTorch);
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ releaseCamera();
+ super.onDestroy();
}
/**
- * 返回true时会自动初始化{@link #mRootView},返回为false时需自己去通过{@link #setRootView(View)}初始化{@link #mRootView}
+ * 返回true时会自动初始化{@link #createRootView(LayoutInflater, ViewGroup)},返回为false是需自己去初始化{@link #createRootView(LayoutInflater, ViewGroup)}
* @param layoutId
* @return 默认返回true
*/
@@ -93,6 +122,17 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
return true;
}
+ /**
+ * 创建{@link #mRootView}
+ * @param inflater
+ * @param container
+ * @return
+ */
+ @NonNull
+ public View createRootView(LayoutInflater inflater, ViewGroup container){
+ return inflater.inflate(getLayoutId(),container,false);
+ }
+
/**
* 布局id
* @return
@@ -102,81 +142,36 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
}
/**
- * {@link ViewfinderView} 的 id
+ * {@link #viewfinderView} 的 ID
* @return 默认返回{@code R.id.viewfinderView}, 如果不需要扫码框可以返回0
*/
public int getViewfinderViewId(){
return R.id.viewfinderView;
}
+
/**
- * 预览界面{@link #surfaceView} 的id
+ * 预览界面{@link #previewView} 的ID
* @return
*/
- public int getSurfaceViewId(){
- return R.id.surfaceView;
+ public int getPreviewViewId(){
+ return R.id.previewView;
}
/**
- * 获取 {@link #ivTorch} 的ID
- * @return 默认返回{@code R.id.ivTorch}, 如果不需要手电筒按钮可以返回0
+ * 获取 {@link #ivFlashlight} 的ID
+ * @return 默认返回{@code R.id.ivFlashlight}, 如果不需要手电筒按钮可以返回0
*/
- public int getIvTorchId(){
- return R.id.ivTorch;
+ public int getFlashlightId(){
+ return R.id.ivFlashlight;
}
/**
- * Get {@link CaptureHelper}
- * @return {@link #mCaptureHelper}
+ * Get {@link CameraScan}
+ * @return {@link #mCameraScan}
*/
- public CaptureHelper getCaptureHelper(){
- return mCaptureHelper;
- }
-
- /**
- * Get {@link CameraManager} use {@link #getCaptureHelper()#getCameraManager()}
- * @return {@link #mCaptureHelper#getCameraManager()}
- */
- @Deprecated
- public CameraManager getCameraManager(){
- return mCaptureHelper.getCameraManager();
- }
-
- //--------------------------------------------
-
- public View getRootView() {
- return mRootView;
- }
-
- public void setRootView(View rootView) {
- this.mRootView = rootView;
- }
-
-
- //--------------------------------------------
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- mCaptureHelper.onCreate();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mCaptureHelper.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mCaptureHelper.onPause();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- mCaptureHelper.onDestroy();
+ public CameraScan getCameraScan(){
+ return mCameraScan;
}
/**
@@ -185,8 +180,15 @@ public class CaptureFragment extends Fragment implements OnCaptureCallback {
* @return 返回true表示拦截,将不自动执行后续逻辑,为false表示不拦截,默认不拦截
*/
@Override
- public boolean onResultCallback(Result result) {
+ public boolean onScanResultCallback(Result result) {
return false;
}
+ //--------------------------------------------
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+
}
diff --git a/lib/src/main/java/com/king/zxing/CaptureHandler.java b/lib/src/main/java/com/king/zxing/CaptureHandler.java
deleted file mode 100644
index b54f998..0000000
--- a/lib/src/main/java/com/king/zxing/CaptureHandler.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package com.king.zxing;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Point;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.Display;
-import android.view.WindowManager;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.Result;
-import com.google.zxing.ResultPoint;
-import com.google.zxing.ResultPointCallback;
-import com.king.zxing.camera.CameraManager;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * @author Jenly
- */
-public class CaptureHandler extends Handler implements ResultPointCallback {
-
-
- private final OnCaptureListener onCaptureListener;
- private final DecodeThread decodeThread;
- private State state;
- private final CameraManager cameraManager;
- private final ViewfinderView viewfinderView;
- /**
- * 是否支持垂直的条形码
- */
- private boolean isSupportVerticalCode;
-
- /**
- * 是否返回扫码原图
- */
- private boolean isReturnBitmap;
-
- /**
- * 是否支持自动缩放
- */
- private boolean isSupportAutoZoom;
-
- /**
- *
- */
- private boolean isSupportLuminanceInvert;
-
-
- private enum State {
- PREVIEW,
- SUCCESS,
- DONE
- }
-
- CaptureHandler(Activity activity,ViewfinderView viewfinderView,OnCaptureListener onCaptureListener,
- Collection decodeFormats,
- Map baseHints,
- String characterSet,
- CameraManager cameraManager) {
- this.viewfinderView = viewfinderView;
- this.onCaptureListener = onCaptureListener;
- decodeThread = new DecodeThread(activity,cameraManager,this, decodeFormats, baseHints, characterSet, this);
- decodeThread.start();
- state = State.SUCCESS;
-
- // Start ourselves capturing previews and decoding.
- this.cameraManager = cameraManager;
- cameraManager.startPreview();
- restartPreviewAndDecode();
- }
-
- @Override
- public void handleMessage(Message message) {
- if (message.what == R.id.restart_preview) {
- restartPreviewAndDecode();
-
- } else if (message.what == R.id.decode_succeeded) {
- state = State.SUCCESS;
- Bundle bundle = message.getData();
- Bitmap barcode = null;
- float scaleFactor = 1.0f;
- if (bundle != null) {
- byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
- if (compressedBitmap != null) {
- barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
- // Mutable copy:
- barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
- }
- scaleFactor = bundle.getFloat(DecodeThread.BARCODE_SCALED_FACTOR);
- }
- onCaptureListener.onHandleDecode((Result) message.obj, barcode, scaleFactor);
-
-
- } else if (message.what == R.id.decode_failed) {// We're decoding as fast as possible, so when one decode fails, start another.
- state = State.PREVIEW;
- cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
-
- }
- }
-
- public void quitSynchronously() {
- state = State.DONE;
- cameraManager.stopPreview();
- Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
- quit.sendToTarget();
- try {
- // Wait at most half a second; should be enough time, and onPause() will timeout quickly
- decodeThread.join(100L);
- } catch (InterruptedException e) {
- // continue
- }
-
- // Be absolutely sure we don't send any queued up messages
- removeMessages(R.id.decode_succeeded);
- removeMessages(R.id.decode_failed);
- }
-
- public void restartPreviewAndDecode() {
- if (state == State.SUCCESS) {
- state = State.PREVIEW;
- cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
- if(viewfinderView!= null){
- viewfinderView.drawViewfinder();
- }
- }
- }
-
- @Override
- public void foundPossibleResultPoint(ResultPoint point) {
- if(viewfinderView!=null){
- ResultPoint resultPoint = transform(point);
- viewfinderView.addPossibleResultPoint(resultPoint);
- }
- }
-
- private boolean isScreenPortrait(Context context){
- WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = manager.getDefaultDisplay();
- Point screenResolution = new Point();
- display.getSize(screenResolution);
- return screenResolution.x < screenResolution.y;
- }
-
- /**
- *
- * @return
- */
- private ResultPoint transform(ResultPoint originPoint) {
- Point screenPoint = cameraManager.getScreenResolution();
- Point previewPoint = cameraManager.getPreviewSizeOnScreen();
-
- float scaleX = 1.0f * screenPoint.x / previewPoint.x;
- float scaleY = 1.0f * screenPoint.y / previewPoint.y;
-
- float x = originPoint.getX() * scaleX - Math.min(screenPoint.y,previewPoint.y)/2;
- float y = originPoint.getY() * scaleY - Math.max(screenPoint.x,previewPoint.x)/2;
-
- return new ResultPoint(x,y);
- }
-
- public boolean isSupportVerticalCode() {
- return isSupportVerticalCode;
- }
-
- public void setSupportVerticalCode(boolean supportVerticalCode) {
- isSupportVerticalCode = supportVerticalCode;
- }
-
- public boolean isReturnBitmap() {
- return isReturnBitmap;
- }
-
- public void setReturnBitmap(boolean returnBitmap) {
- isReturnBitmap = returnBitmap;
- }
-
- public boolean isSupportAutoZoom() {
- return isSupportAutoZoom;
- }
-
- public void setSupportAutoZoom(boolean supportAutoZoom) {
- isSupportAutoZoom = supportAutoZoom;
- }
-
- public boolean isSupportLuminanceInvert() {
- return isSupportLuminanceInvert;
- }
-
- public void setSupportLuminanceInvert(boolean supportLuminanceInvert) {
- isSupportLuminanceInvert = supportLuminanceInvert;
- }
-}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/CaptureHelper.java b/lib/src/main/java/com/king/zxing/CaptureHelper.java
deleted file mode 100644
index 9ddcbfc..0000000
--- a/lib/src/main/java/com/king/zxing/CaptureHelper.java
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * Copyright (C) 2019 Jenly Yu
- *
- * 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.
- */
-package com.king.zxing;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.hardware.Camera;
-import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.Result;
-import com.king.zxing.camera.CameraManager;
-import com.king.zxing.util.LogUtils;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-
-import androidx.annotation.FloatRange;
-import androidx.fragment.app.Fragment;
-
-/**
- * @author Jenly
- */
-/**
- * @author Jenly
- */
-public class CaptureHelper implements CaptureLifecycle,CaptureTouchEvent,CaptureManager, SurfaceHolder.Callback {
-
- private Activity activity;
-
- private CaptureHandler captureHandler;
- private OnCaptureListener onCaptureListener;
-
- private CameraManager cameraManager;
-
- private InactivityTimer inactivityTimer;
- private BeepManager beepManager;
- private AmbientLightManager ambientLightManager;
-
-
- private SurfaceView surfaceView;
- private ViewfinderView viewfinderView;
- private SurfaceHolder surfaceHolder;
- private View ivTorch;
-
- private Collection decodeFormats;
- private Map decodeHints;
- private String characterSet;
-
- private boolean hasSurface;
- /**
- * 默认触控误差值
- */
- private static final int DEVIATION = 6;
- /**
- * 是否支持缩放(变焦),默认支持
- */
- private boolean isSupportZoom = true;
- private float oldDistance;
-
- /**
- * 是否支持自动缩放(变焦),默认支持
- */
- private boolean isSupportAutoZoom = true;
-
- /**
- * 是否支持识别颜色反转色的码,黑白颜色反转,默认不支持
- */
- private boolean isSupportLuminanceInvert = false;
-
- /**
- * 是否支持连扫,默认不支持
- */
- private boolean isContinuousScan = false;
- /**
- * 连扫时,是否自动重置预览和解码器,默认自动重置
- */
- private boolean isAutoRestartPreviewAndDecode = true;
- /**
- * 是否播放音效
- */
- private boolean isPlayBeep;
- /**
- * 是否震动
- */
- private boolean isVibrate;
-
- /**
- * 是否支持垂直的条形码
- */
- private boolean isSupportVerticalCode;
-
- /**
- * 是否返回扫码原图
- */
- private boolean isReturnBitmap;
-
- /**
- * 是否支持全屏扫码识别
- */
- private boolean isFullScreenScan;
-
- /**
- * 识别区域比例,范围建议在0.625 ~ 1.0之间,默认0.9
- */
- private float framingRectRatio = 0.9f;
- /**
- * 识别区域垂直方向偏移量
- */
- private int framingRectVerticalOffset;
- /**
- * 识别区域水平方向偏移量
- */
- private int framingRectHorizontalOffset;
- /**
- * 光线太暗,当光线亮度太暗,亮度低于此值时,显示手电筒按钮
- */
- private float tooDarkLux = AmbientLightManager.TOO_DARK_LUX;
- /**
- * 光线足够明亮,当光线亮度足够明亮,亮度高于此值时,隐藏手电筒按钮
- */
- private float brightEnoughLux = AmbientLightManager.BRIGHT_ENOUGH_LUX;
- /**
- * 扫码回调
- */
- private OnCaptureCallback onCaptureCallback;
-
- private boolean hasCameraFlash;
-
- /**
- * 是否启用光线传感器
- */
- private boolean isAmbientLightEnabled = true;
-
- /**
- * use {@link #CaptureHelper(Fragment, SurfaceView, ViewfinderView, View)}
- * @param fragment
- * @param surfaceView
- * @param viewfinderView
- */
- @Deprecated
- public CaptureHelper(Fragment fragment, SurfaceView surfaceView, ViewfinderView 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){
- 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.surfaceView = surfaceView;
- this.viewfinderView = viewfinderView;
- this.ivTorch = ivTorch;
- }
-
-
- @Override
- public void onCreate(){
- surfaceHolder = surfaceView.getHolder();
- hasSurface = false;
- inactivityTimer = new InactivityTimer(activity);
- beepManager = new BeepManager(activity);
- ambientLightManager = new AmbientLightManager(activity);
-
- hasCameraFlash = activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
- initCameraManager();
-
- onCaptureListener = (result, barcode, scaleFactor) -> {
- inactivityTimer.onActivity();
- beepManager.playBeepSoundAndVibrate();
- onResult(result,barcode,scaleFactor);
- };
- //设置是否播放音效和震动
- beepManager.setPlayBeep(isPlayBeep);
- beepManager.setVibrate(isVibrate);
-
- //设置闪光灯的太暗时和足够亮时的照度值
- ambientLightManager.setTooDarkLux(tooDarkLux);
- ambientLightManager.setBrightEnoughLux(brightEnoughLux);
-
- }
-
-
-
- @Override
- public void onResume(){
- beepManager.updatePrefs();
-
- inactivityTimer.onResume();
-
- if (hasSurface) {
- initCamera(surfaceHolder);
- } else {
- surfaceHolder.addCallback(this);
- }
- if(isAmbientLightEnabled){
- ambientLightManager.start(cameraManager);
- }
-
- }
-
-
- @Override
- public void onPause(){
- if (captureHandler != null) {
- captureHandler.quitSynchronously();
- captureHandler = null;
- }
- inactivityTimer.onPause();
- if(isAmbientLightEnabled) {
- ambientLightManager.stop();
- }
- beepManager.close();
- cameraManager.closeDriver();
- if (!hasSurface) {
- surfaceHolder.removeCallback(this);
- }
- if(ivTorch != null && ivTorch.getVisibility() == View.VISIBLE){
- ivTorch.setSelected(false);
- ivTorch.setVisibility(View.INVISIBLE);
- }
- }
-
-
- @Override
- public void onDestroy(){
- inactivityTimer.shutdown();
- }
-
- /**
- * 支持缩放时,须在{@link Activity#onTouchEvent(MotionEvent)}调用此方法
- * @param event
- */
- @Override
- public boolean onTouchEvent(MotionEvent event){
- if(isSupportZoom && cameraManager.isOpen()){
- Camera camera = cameraManager.getOpenCamera().getCamera();
- if(camera ==null){
- return false;
- }
- if(event.getPointerCount() > 1) {
- switch (event.getAction() & MotionEvent.ACTION_MASK) {//多点触控
- case MotionEvent.ACTION_POINTER_DOWN:
- oldDistance = calcFingerSpacing(event);
- break;
- case MotionEvent.ACTION_MOVE:
- float newDistance = calcFingerSpacing(event);
-
- if (newDistance > oldDistance + DEVIATION) {//
- handleZoom(true, camera);
- } else if (newDistance < oldDistance - DEVIATION) {
- handleZoom(false, camera);
- }
- oldDistance = newDistance;
- break;
- }
-
- return true;
- }
- }
-
- return false;
- }
-
- private void initCameraManager(){
- cameraManager = new CameraManager(activity);
- cameraManager.setFullScreenScan(isFullScreenScan);
- cameraManager.setFramingRectRatio(framingRectRatio);
- cameraManager.setFramingRectVerticalOffset(framingRectVerticalOffset);
- cameraManager.setFramingRectHorizontalOffset(framingRectHorizontalOffset);
- if(ivTorch !=null && hasCameraFlash){
- ivTorch.setOnClickListener(v -> {
- if(cameraManager!=null){
- 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));
-
- }
- }
-
-
- /**
- * 初始化Camera
- * @param surfaceHolder
- */
- private void initCamera(SurfaceHolder surfaceHolder) {
- if (surfaceHolder == null) {
- throw new IllegalStateException("No SurfaceHolder provided");
- }
- if (cameraManager.isOpen()) {
- LogUtils.w("initCamera() while already open -- late SurfaceView callback?");
- return;
- }
- try {
- cameraManager.openDriver(surfaceHolder);
- // Creating the handler starts the preview, which can also throw a RuntimeException.
- if (captureHandler == null) {
- captureHandler = new CaptureHandler(activity,viewfinderView,onCaptureListener, decodeFormats, decodeHints, characterSet, cameraManager);
- captureHandler.setSupportVerticalCode(isSupportVerticalCode);
- captureHandler.setReturnBitmap(isReturnBitmap);
- captureHandler.setSupportAutoZoom(isSupportAutoZoom);
- captureHandler.setSupportLuminanceInvert(isSupportLuminanceInvert);
- }
- } catch (IOException ioe) {
- LogUtils.w(ioe);
- } catch (RuntimeException e) {
- // Barcode Scanner has seen crashes in the wild of this variety:
- // java.?lang.?RuntimeException: Fail to connect to camera service
- LogUtils.w( "Unexpected error initializing camera", e);
- }
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- if (holder == null) {
- LogUtils.w( "*** WARNING *** surfaceCreated() gave us a null surface!");
- }
- if (!hasSurface) {
- hasSurface = true;
- initCamera(holder);
- }
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- hasSurface = false;
- }
-
- /**
- * 处理变焦缩放
- * @param isZoomIn
- * @param camera
- */
- private void handleZoom(boolean isZoomIn, Camera camera) {
- Camera.Parameters params = camera.getParameters();
- if (params.isZoomSupported()) {
- int maxZoom = params.getMaxZoom();
- int zoom = params.getZoom();
- if (isZoomIn && zoom < maxZoom) {
- zoom++;
- } else if (zoom > 0) {
- zoom--;
- }
- params.setZoom(zoom);
- camera.setParameters(params);
- } else {
- LogUtils.i( "zoom not supported");
- }
- }
-
- /**
- * 聚焦
- * @param event
- * @param camera
- */
- @Deprecated
- private void focusOnTouch(MotionEvent event,Camera camera) {
-
- Camera.Parameters params = camera.getParameters();
- Camera.Size previewSize = params.getPreviewSize();
-
- Rect focusRect = calcTapArea(event.getRawX(), event.getRawY(), 1f,previewSize);
- Rect meteringRect = calcTapArea(event.getRawX(), event.getRawY(), 1.5f,previewSize);
- Camera.Parameters parameters = camera.getParameters();
- if (parameters.getMaxNumFocusAreas() > 0) {
- List focusAreas = new ArrayList<>();
- focusAreas.add(new Camera.Area(focusRect, 600));
- parameters.setFocusAreas(focusAreas);
- }
-
- if (parameters.getMaxNumMeteringAreas() > 0) {
- List meteringAreas = new ArrayList<>();
- meteringAreas.add(new Camera.Area(meteringRect, 600));
- parameters.setMeteringAreas(meteringAreas);
- }
- final String currentFocusMode = params.getFocusMode();
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
- camera.setParameters(params);
-
- camera.autoFocus((success, camera1) -> {
- Camera.Parameters params1 = camera1.getParameters();
- params1.setFocusMode(currentFocusMode);
- camera1.setParameters(params1);
- });
-
- }
-
-
- /**
- * 计算两指间距离
- * @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);
- }
-
- /**
- * 计算对焦区域
- * @param x
- * @param y
- * @param coefficient
- * @param previewSize
- * @return
- */
- private Rect calcTapArea(float x, float y, float coefficient, Camera.Size previewSize) {
- float focusAreaSize = 200;
- int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
- int centerX = (int) ((x / previewSize.width) * 2000 - 1000);
- int centerY = (int) ((y / previewSize.height) * 2000 - 1000);
- int left = clamp(centerX - (areaSize / 2), -1000, 1000);
- int top = clamp(centerY - (areaSize / 2), -1000, 1000);
- RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
- return new Rect(Math.round(rectF.left), Math.round(rectF.top),
- Math.round(rectF.right), Math.round(rectF.bottom));
- }
-
- /**
- * 根据范围限定值
- * @param x
- * @param min 范围最小值
- * @param max 范围最大值
- * @return
- */
- private int clamp(int x, int min, int max) {
- if (x > max) {
- return max;
- }
- if (x < min) {
- return min;
- }
- return x;
- }
-
-
- /**
- * 重新启动扫码和解码器
- */
- public void restartPreviewAndDecode(){
- if(captureHandler != null){
- captureHandler.restartPreviewAndDecode();
- }
- }
-
- /**
- * 接收扫码结果
- * @param result
- * @param barcode
- * @param scaleFactor
- */
- public void onResult(Result result, Bitmap barcode, float scaleFactor){
- onResult(result);
- }
-
- /**';, mnb
- *
- * 接收扫码结果,想支持连扫时,可将{@link #continuousScan(boolean)}设置为{@code true}
- * 如果{@link #isContinuousScan}支持连扫,则默认重启扫码和解码器;当连扫逻辑太复杂时,
- * 请将{@link #autoRestartPreviewAndDecode(boolean)}设置为{@code false},并手动调用{@link #restartPreviewAndDecode()}
- * @param result 扫码结果
- */
- public void onResult(Result result){
- final String text = result.getText();
- if(isContinuousScan){
- if(onCaptureCallback!=null){
- onCaptureCallback.onResultCallback(result);
- }
- if(isAutoRestartPreviewAndDecode){
- restartPreviewAndDecode();
- }
- return;
- }
-
- if(isPlayBeep && captureHandler != null){//如果播放音效,则稍微延迟一点,给予播放音效时间
- captureHandler.postDelayed(() -> {
- //如果设置了回调,并且onCallback返回为true,则表示拦截
- if(onCaptureCallback!=null && onCaptureCallback.onResultCallback(result)){
- return;
- }
- Intent intent = new Intent();
- intent.putExtra(Intents.Scan.RESULT,text);
- activity.setResult(Activity.RESULT_OK,intent);
- activity.finish();
- },100);
-
- return;
- }
-
- //如果设置了回调,并且onCallback返回为true,则表示拦截
- if(onCaptureCallback!=null && onCaptureCallback.onResultCallback(result)){
- return;
- }
- Intent intent = new Intent();
- intent.putExtra(Intents.Scan.RESULT,text);
- activity.setResult(Activity.RESULT_OK,intent);
- activity.finish();
- }
-
-
- /**
- * 设置是否连续扫码,如果想支持连续扫码,则将此方法返回{@code true}并重写{@link #onResult(Result)}
- */
- public CaptureHelper continuousScan(boolean isContinuousScan){
- this.isContinuousScan = isContinuousScan;
- return this;
- }
-
-
- /**
- * 设置是否自动重启扫码和解码器,当支持连扫时才起作用。
- * @return 默认返回 true
- */
- public CaptureHelper autoRestartPreviewAndDecode(boolean isAutoRestartPreviewAndDecode){
- this.isAutoRestartPreviewAndDecode = isAutoRestartPreviewAndDecode;
- return this;
- }
-
-
- /**
- * 设置是否播放音效
- * @return
- */
- public CaptureHelper playBeep(boolean playBeep){
- this.isPlayBeep = playBeep;
- if(beepManager!=null){
- beepManager.setPlayBeep(playBeep);
- }
- return this;
- }
-
- /**
- * 设置是否震动
- * @return
- */
- public CaptureHelper vibrate(boolean vibrate){
- this.isVibrate = vibrate;
- if(beepManager!=null){
- beepManager.setVibrate(vibrate);
- }
- return this;
- }
-
-
- /**
- * 设置是否支持缩放
- * @param supportZoom
- * @return
- */
- public CaptureHelper supportZoom(boolean supportZoom) {
- isSupportZoom = supportZoom;
- return this;
- }
-
- /**
- * 设置支持的解码一/二维码格式,默认常规的码都支持
- * @param decodeFormats 可参见{@link DecodeFormatManager}
- * @return
- */
- public CaptureHelper decodeFormats(Collection decodeFormats) {
- this.decodeFormats = decodeFormats;
- return this;
- }
-
- /**
- * {@link DecodeHintType}
- * @param decodeHints
- * @return
- */
- public CaptureHelper decodeHints(Map decodeHints) {
- this.decodeHints = decodeHints;
- return this;
- }
-
- /**
- * {@link DecodeHintType}
- * @param key {@link DecodeHintType}
- * @param value {@link }
- * @return
- */
- public CaptureHelper decodeHint(DecodeHintType key,Object value){
- if(decodeHints == null){
- decodeHints = new EnumMap<>(DecodeHintType.class);
- }
- decodeHints.put(key,value);
- return this;
- }
-
- /**
- * 设置解码时编码字符集
- * @param characterSet
- * @return
- */
- public CaptureHelper characterSet(String characterSet) {
- this.characterSet = characterSet;
- return this;
- }
-
- /**
- * 设置是否支持扫垂直的条码
- * @param supportVerticalCode 默认为false,想要增强扫条码识别度时可使用,相应的会增加性能消耗。
- * @return
- */
- public CaptureHelper supportVerticalCode(boolean supportVerticalCode) {
- this.isSupportVerticalCode = supportVerticalCode;
- if(captureHandler!=null){
- captureHandler.setSupportVerticalCode(isSupportVerticalCode);
- }
- 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表示扫码就结果会返回扫码原图,相应的会增加性能消耗。
- * @return
- */
- public CaptureHelper returnBitmap(boolean returnBitmap) {
- isReturnBitmap = returnBitmap;
- if(captureHandler!=null){
- captureHandler.setReturnBitmap(isReturnBitmap);
- }
- return this;
- }
-
-
- /**
- * 设置是否支持自动缩放
- * @param supportAutoZoom
- * @return
- */
- public CaptureHelper supportAutoZoom(boolean supportAutoZoom) {
- isSupportAutoZoom = supportAutoZoom;
- if(captureHandler!=null){
- captureHandler.setSupportAutoZoom(isSupportAutoZoom);
- }
- return this;
- }
-
- /**
- * 是否支持识别反色码,黑白颜色反转
- * @param supportLuminanceInvert 默认为false,当返回true时表示支持,会增加识别率,但相应的也会增加性能消耗。
- * @return
- */
- public CaptureHelper supportLuminanceInvert(boolean supportLuminanceInvert) {
- isSupportLuminanceInvert = supportLuminanceInvert;
- if(captureHandler!=null){
- captureHandler.setSupportLuminanceInvert(isSupportLuminanceInvert);
- }
- return this;
- }
-
- /**
- * 设置是否支持全屏扫码识别
- * @param fullScreenScan 默认为false
- * @return
- */
- public CaptureHelper fullScreenScan(boolean fullScreenScan) {
- isFullScreenScan = fullScreenScan;
- if(cameraManager!=null){
- cameraManager.setFullScreenScan(isFullScreenScan);
- }
- return this;
- }
-
- /**
- * 设置识别区域比例,范围建议在0.625 ~ 1.0之间。非全屏识别时才有效
- * 0.625 即与默认推荐显示区域一致,1.0表示与宽度一致
- * @param framingRectRatio 默认0.9
- * @return
- */
- public CaptureHelper framingRectRatio(@FloatRange(from = 0.0f ,to = 1.0f) float framingRectRatio) {
- this.framingRectRatio = framingRectRatio;
- if(cameraManager!=null){
- cameraManager.setFramingRectRatio(framingRectRatio);
- }
- return this;
- }
-
- /**
- * 设置识别区域垂直方向偏移量,非全屏识别时才有效
- * @param framingRectVerticalOffset 默认0,表示不偏移
- * @return
- */
- public CaptureHelper framingRectVerticalOffset(int framingRectVerticalOffset) {
- this.framingRectVerticalOffset = framingRectVerticalOffset;
- if(cameraManager!=null){
- cameraManager.setFramingRectVerticalOffset(framingRectVerticalOffset);
- }
- return this;
- }
-
- /**
- * 设置识别区域水平方向偏移量,非全屏识别时才有效
- * @param framingRectHorizontalOffset 默认0,表示不偏移
- * @return
- */
- public CaptureHelper framingRectHorizontalOffset(int framingRectHorizontalOffset) {
- this.framingRectHorizontalOffset = framingRectHorizontalOffset;
- if(cameraManager!=null){
- cameraManager.setFramingRectHorizontalOffset(framingRectHorizontalOffset);
- }
- return this;
- }
-
- /**
- * 是否启用光线传感器
- * @param isAmbientLightEnabled
- * @return
- */
- public CaptureHelper ambientLightEnabled(boolean isAmbientLightEnabled){
- this.isAmbientLightEnabled = isAmbientLightEnabled;
- return this;
- }
-
-
- /**
- * 设置扫码回调
- * @param callback
- * @return
- */
- public CaptureHelper setOnCaptureCallback(OnCaptureCallback callback) {
- this.onCaptureCallback = callback;
- return this;
- }
-
- /**
- * {@link CameraManager}
- * @return {@link #cameraManager}
- */
- @Override
- public CameraManager getCameraManager() {
- return cameraManager;
- }
-
- /**
- * {@link BeepManager}
- * @return {@link #beepManager}
- */
- @Override
- public BeepManager getBeepManager() {
- return beepManager;
- }
-
- /**
- * {@link AmbientLightManager}
- * @return {@link #ambientLightManager}
- */
- @Override
- public AmbientLightManager getAmbientLightManager() {
- return ambientLightManager;
- }
-
- /**
- * {@link InactivityTimer}
- * @return {@link #inactivityTimer}
- */
- @Override
- public InactivityTimer getInactivityTimer() {
- return inactivityTimer;
- }
-}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/CaptureLifecycle.java b/lib/src/main/java/com/king/zxing/CaptureLifecycle.java
deleted file mode 100644
index 5e990ee..0000000
--- a/lib/src/main/java/com/king/zxing/CaptureLifecycle.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2019 Jenly Yu
- *
- * 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.
- */
-package com.king.zxing;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * @author Jenly
- */
-public interface CaptureLifecycle {
-
- /**
- * {@link Activity#onCreate(Bundle)}
- */
- void onCreate();
- /**
- * {@link Activity#onResume()}
- */
- void onResume();
-
- /**
- * {@link Activity#onPause()}
- */
- void onPause();
-
- /**
- * {@link Activity#onDestroy()}
- */
- void onDestroy();
-
-}
diff --git a/lib/src/main/java/com/king/zxing/CaptureManager.java b/lib/src/main/java/com/king/zxing/CaptureManager.java
deleted file mode 100644
index 0d4e0c1..0000000
--- a/lib/src/main/java/com/king/zxing/CaptureManager.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2019 Jenly Yu
- *
- * 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.
- */
-package com.king.zxing;
-
-import com.king.zxing.camera.CameraManager;
-
-/**
- * @author Jenly
- */
-public interface CaptureManager {
-
- /**
- * Get {@link CameraManager}
- * @return {@link CameraManager}
- */
- CameraManager getCameraManager();
-
- /**
- * Get {@link BeepManager}
- * @return {@link BeepManager}
- */
- BeepManager getBeepManager();
-
- /**
- * Get {@link AmbientLightManager}
- * @return {@link AmbientLightManager}
- */
- AmbientLightManager getAmbientLightManager();
-
- /**
- * Get {@link InactivityTimer}
- * @return {@link InactivityTimer}
- */
- InactivityTimer getInactivityTimer();
-}
diff --git a/lib/src/main/java/com/king/zxing/CaptureTouchEvent.java b/lib/src/main/java/com/king/zxing/CaptureTouchEvent.java
deleted file mode 100644
index 884f1a5..0000000
--- a/lib/src/main/java/com/king/zxing/CaptureTouchEvent.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2019 Jenly Yu
- *
- * 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.
- */
-package com.king.zxing;
-
-import android.view.MotionEvent;
-
-/**
- * @author Jenly
- */
-public interface CaptureTouchEvent {
-
- /**
- * {@link android.app.Activity#onTouchEvent(MotionEvent)}
- */
- boolean onTouchEvent(MotionEvent event);
-}
diff --git a/lib/src/main/java/com/king/zxing/DecodeConfig.java b/lib/src/main/java/com/king/zxing/DecodeConfig.java
new file mode 100644
index 0000000..02c638b
--- /dev/null
+++ b/lib/src/main/java/com/king/zxing/DecodeConfig.java
@@ -0,0 +1,284 @@
+package com.king.zxing;
+
+import android.graphics.Rect;
+
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.common.GlobalHistogramBinarizer;
+import com.google.zxing.common.HybridBinarizer;
+
+import java.util.Map;
+
+import androidx.annotation.FloatRange;
+
+
+/**
+ *
+ * @author Jenly
+ */
+public class DecodeConfig {
+
+ private Map hints = DecodeFormatManager.DEFAULT_HINTS;
+
+ /**
+ * 是否支持使用多解码
+ */
+ private boolean isMultiDecode = true;
+
+ /**
+ * 是否支持识别反色码(条码黑白颜色反转的码)
+ */
+ private boolean isSupportLuminanceInvert;
+ /**
+ * 是否支持识别反色码(条码黑白颜色反转的码)使用多解码
+ */
+ private boolean isSupportLuminanceInvertMultiDecode;
+ /**
+ * 是否支持垂直的条码
+ */
+ private boolean isSupportVerticalCode;
+ /**
+ * 是否支持垂直的条码,使用多解码
+ */
+ private boolean isSupportVerticalCodeMultiDecode;
+
+ /**
+ * 需要分析识别区域
+ */
+ private Rect analyzeAreaRect;
+
+ /**
+ * 是否支持全区域扫码识别
+ */
+ private boolean isFullAreaScan = true;
+
+ /**
+ * 识别区域比例,默认0.9
+ */
+ private float areaRectRatio = 0.9f;
+ /**
+ * 识别区域垂直方向偏移量
+ */
+ private int areaRectVerticalOffset;
+ /**
+ * 识别区域水平方向偏移量
+ */
+ private int areaRectHorizontalOffset;
+
+ public DecodeConfig(){
+
+ }
+
+ public Map getHints() {
+ return hints;
+ }
+
+ /**
+ * 设置解码
+ * @param hints {@link DecodeFormatManager}
+ * @return
+ */
+ public DecodeConfig setHints(Map hints) {
+ this.hints = hints;
+ return this;
+ }
+
+ /**
+ * 是否支持识别反色码,黑白颜色反转
+ * @return
+ */
+ public boolean isSupportLuminanceInvert() {
+ return isSupportLuminanceInvert;
+ }
+
+ /**
+ * 设置是否支持识别反色码,黑白颜色反转
+ * @param supportLuminanceInvert 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
+ * @return
+ */
+ public DecodeConfig setSupportLuminanceInvert(boolean supportLuminanceInvert) {
+ isSupportLuminanceInvert = supportLuminanceInvert;
+ return this;
+ }
+
+ /**
+ * 是否支持扫垂直的条码
+ * @return
+ */
+ public boolean isSupportVerticalCode() {
+ return isSupportVerticalCode;
+ }
+
+ /**
+ * 设置是否支持扫垂直的条码
+ * @param supportVerticalCode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
+ * @return
+ */
+ public DecodeConfig setSupportVerticalCode(boolean supportVerticalCode) {
+ isSupportVerticalCode = supportVerticalCode;
+ return this;
+ }
+
+ /**
+ * 是否支持使用多解码
+ * @return
+ */
+ public boolean isMultiDecode() {
+ return isMultiDecode;
+ }
+
+ /**
+ * 是否支持使用多解码
+ * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
+ * @param multiDecode 默认为{@code true}
+ * @return
+ */
+ public DecodeConfig setMultiDecode(boolean multiDecode) {
+ isMultiDecode = multiDecode;
+ return this;
+ }
+
+ /**
+ * 是否支持识别反色码(条码黑白颜色反转的码)使用多解码
+ * @return
+ */
+ public boolean isSupportLuminanceInvertMultiDecode() {
+ return isSupportLuminanceInvertMultiDecode;
+ }
+
+ /**
+ * 设置是否支持识别反色码(条码黑白颜色反转的码)使用多解码
+ * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
+ * @param supportLuminanceInvertMultiDecode 默认为{@code false},想要增强支持扫码识别反色码时可使用,相应的也会增加性能消耗。
+ * @return
+ */
+ public DecodeConfig setSupportLuminanceInvertMultiDecode(boolean supportLuminanceInvertMultiDecode) {
+ isSupportLuminanceInvertMultiDecode = supportLuminanceInvertMultiDecode;
+ return this;
+ }
+
+ /**
+ * 是否支持垂直的条码,使用多解码
+ * @return
+ */
+ public boolean isSupportVerticalCodeMultiDecode() {
+ return isSupportVerticalCodeMultiDecode;
+ }
+
+ /**
+ * 设置是否支持垂直的条码,使用多解码
+ * @see {@link HybridBinarizer} , {@link GlobalHistogramBinarizer}
+ * @param supportVerticalCodeMultiDecode 默认为{@code false},想要增强支持扫码识别垂直的条码时可使用,相应的也会增加性能消耗。
+ * @return
+ */
+ public DecodeConfig setSupportVerticalCodeMultiDecode(boolean supportVerticalCodeMultiDecode) {
+ isSupportVerticalCodeMultiDecode = supportVerticalCodeMultiDecode;
+ return this;
+ }
+
+ /**
+ * 需要分析识别区域
+ * @return
+ */
+ public Rect getAnalyzeAreaRect() {
+ return analyzeAreaRect;
+ }
+
+ /**
+ * 设置需要分析识别区域,当设置了指定的分析区域时,识别区域比例和识别区域相关参数都将无效
+ * @param analyzeAreaRect
+ * @return
+ */
+ public DecodeConfig setAnalyzeAreaRect(Rect analyzeAreaRect) {
+ this.analyzeAreaRect = analyzeAreaRect;
+ return this;
+ }
+
+ /**
+ * 是否支持全区域扫码识别
+ * @return
+ */
+ public boolean isFullAreaScan() {
+ return isFullAreaScan;
+ }
+
+ /**
+ * 设置是否支持全区域扫码识别,优先级比识别区域比例高
+ * @param fullAreaScan 默认为{@code true}
+ * @return
+ */
+ public DecodeConfig setFullAreaScan(boolean fullAreaScan) {
+ isFullAreaScan = fullAreaScan;
+ return this;
+ }
+
+ /**
+ * 识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
+ * @return
+ */
+ public float getAreaRectRatio() {
+ return areaRectRatio;
+ }
+
+ /**
+ * 设置识别区域比例,默认0.9,设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
+ * @param areaRectRatio
+ * @return
+ */
+ public DecodeConfig setAreaRectRatio(@FloatRange(from = 0.5,to = 1.0) float areaRectRatio) {
+ this.areaRectRatio = areaRectRatio;
+ return this;
+ }
+
+ /**
+ * 识别区域垂直方向偏移量
+ * @return
+ */
+ public int getAreaRectVerticalOffset() {
+ return areaRectVerticalOffset;
+ }
+
+ /**
+ * 设置识别区域垂直方向偏移量
+ * @param areaRectVerticalOffset
+ * @return
+ */
+ public DecodeConfig setAreaRectVerticalOffset(int areaRectVerticalOffset) {
+ this.areaRectVerticalOffset = areaRectVerticalOffset;
+ return this;
+ }
+
+ /**
+ * 识别区域水平方向偏移量
+ * @return
+ */
+ public int getAreaRectHorizontalOffset() {
+ return areaRectHorizontalOffset;
+ }
+
+ /**
+ * 设置识别区域水平方向偏移量
+ * @param areaRectHorizontalOffset
+ * @return
+ */
+ public DecodeConfig setAreaRectHorizontalOffset(int areaRectHorizontalOffset) {
+ this.areaRectHorizontalOffset = areaRectHorizontalOffset;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "DecodeConfig{" +
+ "hints=" + hints +
+ ", isMultiDecode=" + isMultiDecode +
+ ", isSupportLuminanceInvert=" + isSupportLuminanceInvert +
+ ", isSupportLuminanceInvertMultiDecode=" + isSupportLuminanceInvertMultiDecode +
+ ", isSupportVerticalCode=" + isSupportVerticalCode +
+ ", isSupportVerticalCodeMultiDecode=" + isSupportVerticalCodeMultiDecode +
+ ", analyzeAreaRect=" + analyzeAreaRect +
+ ", isFullAreaScan=" + isFullAreaScan +
+ ", areaRectRatio=" + areaRectRatio +
+ ", areaRectVerticalOffset=" + areaRectVerticalOffset +
+ ", areaRectHorizontalOffset=" + areaRectHorizontalOffset +
+ '}';
+ }
+}
diff --git a/lib/src/main/java/com/king/zxing/DecodeFormatManager.java b/lib/src/main/java/com/king/zxing/DecodeFormatManager.java
index 4223fcb..a0eef3b 100644
--- a/lib/src/main/java/com/king/zxing/DecodeFormatManager.java
+++ b/lib/src/main/java/com/king/zxing/DecodeFormatManager.java
@@ -1,105 +1,195 @@
-package com.king.zxing;
-/*
- * Copyright (C) 2010 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.content.Intent;
-import android.net.Uri;
-import com.google.zxing.BarcodeFormat;
-
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-public final class DecodeFormatManager {
-
- private static final Pattern COMMA_PATTERN = Pattern.compile(",");
-
- public static final Set PRODUCT_FORMATS;
- public static final Set INDUSTRIAL_FORMATS;
- public static final Set ONE_D_FORMATS;
- public static final Set QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE);
- public static final Set DATA_MATRIX_FORMATS = EnumSet.of(BarcodeFormat.DATA_MATRIX);
- public static final Set AZTEC_FORMATS = EnumSet.of(BarcodeFormat.AZTEC);
- public static final Set PDF417_FORMATS = EnumSet.of(BarcodeFormat.PDF_417);
- static {
- PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A,
- BarcodeFormat.UPC_E,
- BarcodeFormat.EAN_13,
- BarcodeFormat.EAN_8,
- BarcodeFormat.RSS_14,
- BarcodeFormat.RSS_EXPANDED);
- INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39,
- BarcodeFormat.CODE_93,
- BarcodeFormat.CODE_128,
- BarcodeFormat.ITF,
- BarcodeFormat.CODABAR);
- ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS);
- ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS);
- }
- private static final Map> FORMATS_FOR_MODE;
- static {
- FORMATS_FOR_MODE = new HashMap<>();
- FORMATS_FOR_MODE.put(Intents.Scan.ONE_D_MODE, ONE_D_FORMATS);
- FORMATS_FOR_MODE.put(Intents.Scan.PRODUCT_MODE, PRODUCT_FORMATS);
- FORMATS_FOR_MODE.put(Intents.Scan.QR_CODE_MODE, QR_CODE_FORMATS);
- FORMATS_FOR_MODE.put(Intents.Scan.DATA_MATRIX_MODE, DATA_MATRIX_FORMATS);
- FORMATS_FOR_MODE.put(Intents.Scan.AZTEC_MODE, AZTEC_FORMATS);
- FORMATS_FOR_MODE.put(Intents.Scan.PDF417_MODE, PDF417_FORMATS);
- }
-
- private DecodeFormatManager() {}
-
- static Set parseDecodeFormats(Intent intent) {
- Iterable scanFormats = null;
- CharSequence scanFormatsString = intent.getStringExtra(Intents.Scan.FORMATS);
- if (scanFormatsString != null) {
- scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
- }
- return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
- }
-
- static Set parseDecodeFormats(Uri inputUri) {
- List formats = inputUri.getQueryParameters(Intents.Scan.FORMATS);
- if (formats != null && formats.size() == 1 && formats.get(0) != null) {
- formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
- }
- return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
- }
-
- private static Set parseDecodeFormats(Iterable scanFormats, String decodeMode) {
- if (scanFormats != null) {
- Set formats = EnumSet.noneOf(BarcodeFormat.class);
- try {
- for (String format : scanFormats) {
- formats.add(BarcodeFormat.valueOf(format));
- }
- return formats;
- } catch (IllegalArgumentException iae) {
- // ignore it then
- }
- }
- if (decodeMode != null) {
- return FORMATS_FOR_MODE.get(decodeMode);
- }
- return null;
- }
-
-}
\ No newline at end of file
+package com.king.zxing;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.DecodeHintType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+import androidx.annotation.NonNull;
+
+/**
+ * @author Jenly
+ */
+public final class DecodeFormatManager {
+
+ /**
+ * 所有的
+ */
+ public static final Map ALL_HINTS = new EnumMap<>(DecodeHintType.class);
+ /**
+ * CODE_128 (最常用的一维码)
+ */
+ public static final Map CODE_128_HINTS = createDecodeHint(BarcodeFormat.CODE_128);
+ /**
+ * QR_CODE (最常用的二维码)
+ */
+ public static final Map QR_CODE_HINTS = createDecodeHint(BarcodeFormat.QR_CODE);
+ /**
+ * 一维码
+ */
+ public static final Map ONE_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class);
+ /**
+ * 二维码
+ */
+ public static final Map TWO_DIMENSIONAL_HINTS = new EnumMap<>(DecodeHintType.class);
+
+ /**
+ * 默认
+ */
+ public static final Map DEFAULT_HINTS = new EnumMap<>(DecodeHintType.class);
+
+ static {
+ //all hints
+ addDecodeHintTypes(ALL_HINTS,getAllFormats());
+ //one dimension
+ addDecodeHintTypes(ONE_DIMENSIONAL_HINTS,getOneDimensionalFormats());
+ //Two dimension
+ addDecodeHintTypes(TWO_DIMENSIONAL_HINTS,getTwoDimensionalFormats());
+ //default hints
+ addDecodeHintTypes(DEFAULT_HINTS,getDefaultFormats());
+ }
+
+ /**
+ * 所有支持的{@link BarcodeFormat}
+ * @return
+ */
+ private static List getAllFormats(){
+ List list = new ArrayList<>();
+ list.add(BarcodeFormat.AZTEC);
+ list.add(BarcodeFormat.CODABAR);
+ list.add(BarcodeFormat.CODE_39);
+ list.add(BarcodeFormat.CODE_93);
+ list.add(BarcodeFormat.CODE_128);
+ list.add(BarcodeFormat.DATA_MATRIX);
+ list.add(BarcodeFormat.EAN_8);
+ list.add(BarcodeFormat.EAN_13);
+ list.add(BarcodeFormat.ITF);
+ list.add(BarcodeFormat.MAXICODE);
+ list.add(BarcodeFormat.PDF_417);
+ list.add(BarcodeFormat.QR_CODE);
+ list.add(BarcodeFormat.RSS_14);
+ list.add(BarcodeFormat.RSS_EXPANDED);
+ list.add(BarcodeFormat.UPC_A);
+ list.add(BarcodeFormat.UPC_E);
+ list.add(BarcodeFormat.UPC_EAN_EXTENSION);
+ return list;
+ }
+
+ /**
+ * 二维码
+ * 包括如下几种格式:
+ * {@link BarcodeFormat#CODABAR}
+ * {@link BarcodeFormat#CODE_39}
+ * {@link BarcodeFormat#CODE_93}
+ * {@link BarcodeFormat#CODE_128}
+ * {@link BarcodeFormat#EAN_8}
+ * {@link BarcodeFormat#EAN_13}
+ * {@link BarcodeFormat#ITF}
+ * {@link BarcodeFormat#RSS_14}
+ * {@link BarcodeFormat#RSS_EXPANDED}
+ * {@link BarcodeFormat#UPC_A}
+ * {@link BarcodeFormat#UPC_E}
+ * {@link BarcodeFormat#UPC_EAN_EXTENSION}
+ * @return
+ */
+ private static List getOneDimensionalFormats(){
+ List list = new ArrayList<>();
+ list.add(BarcodeFormat.CODABAR);
+ list.add(BarcodeFormat.CODE_39);
+ list.add(BarcodeFormat.CODE_93);
+ list.add(BarcodeFormat.CODE_128);
+ list.add(BarcodeFormat.EAN_8);
+ list.add(BarcodeFormat.EAN_13);
+ list.add(BarcodeFormat.ITF);
+ list.add(BarcodeFormat.RSS_14);
+ list.add(BarcodeFormat.RSS_EXPANDED);
+ list.add(BarcodeFormat.UPC_A);
+ list.add(BarcodeFormat.UPC_E);
+ list.add(BarcodeFormat.UPC_EAN_EXTENSION);
+ return list;
+ }
+
+ /**
+ * 二维码
+ * 包括如下几种格式:
+ * {@link BarcodeFormat#AZTEC}
+ * {@link BarcodeFormat#DATA_MATRIX}
+ * {@link BarcodeFormat#MAXICODE}
+ * {@link BarcodeFormat#PDF_417}
+ * {@link BarcodeFormat#QR_CODE}
+ * @return
+ */
+ private static List getTwoDimensionalFormats(){
+ List list = new ArrayList<>();
+ list.add(BarcodeFormat.AZTEC);
+ list.add(BarcodeFormat.DATA_MATRIX);
+ list.add(BarcodeFormat.MAXICODE);
+ list.add(BarcodeFormat.PDF_417);
+ list.add(BarcodeFormat.QR_CODE);
+ return list;
+ }
+
+ /**
+ * 默认支持的格式
+ * 包括如下几种格式:
+ * {@link BarcodeFormat#QR_CODE}
+ * {@link BarcodeFormat#UPC_A}
+ * {@link BarcodeFormat#EAN_13}
+ * {@link BarcodeFormat#CODE_128}
+ * @return
+ */
+ private static List getDefaultFormats(){
+ List list = new ArrayList<>();
+ list.add(BarcodeFormat.QR_CODE);
+ list.add(BarcodeFormat.UPC_A);
+ list.add(BarcodeFormat.EAN_13);
+ list.add(BarcodeFormat.CODE_128);
+ return list;
+ }
+
+ private static List singletonList(T o){
+ return Collections.singletonList(o);
+ }
+
+ /**
+ * 支持解码的格式
+ * @param barcodeFormats {@link BarcodeFormat}
+ * @return
+ */
+ public static Map createDecodeHints(@NonNull BarcodeFormat... barcodeFormats){
+ Map hints = new EnumMap<>(DecodeHintType.class);
+ addDecodeHintTypes(hints, Arrays.asList(barcodeFormats));
+ return hints;
+ }
+
+ /**
+ * 支持解码的格式
+ * @param barcodeFormat {@link BarcodeFormat}
+ * @return
+ */
+ public static Map createDecodeHint(@NonNull BarcodeFormat barcodeFormat){
+ Map hints = new EnumMap<>(DecodeHintType.class);
+ addDecodeHintTypes(hints,singletonList(barcodeFormat));
+ return hints;
+ }
+
+ /**
+ *
+ * @param hints
+ * @param formats
+ */
+ private static void addDecodeHintTypes(Map hints,List formats){
+ // Image is known to be of one of a few possible formats.
+ hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
+ // Spend more time to try to find a barcode; optimize for accuracy, not speed.
+ hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
+ // Specifies what character encoding to use when decoding, where applicable (type String)
+ hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
+ }
+
+}
diff --git a/lib/src/main/java/com/king/zxing/DecodeHandler.java b/lib/src/main/java/com/king/zxing/DecodeHandler.java
deleted file mode 100644
index cf43606..0000000
--- a/lib/src/main/java/com/king/zxing/DecodeHandler.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package com.king.zxing;
-/*
- * Copyright (C) 2010 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.hardware.Camera;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.view.Display;
-import android.view.WindowManager;
-
-import com.google.zxing.BinaryBitmap;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.PlanarYUVLuminanceSource;
-import com.google.zxing.Result;
-import com.google.zxing.ResultPoint;
-import com.google.zxing.common.GlobalHistogramBinarizer;
-import com.google.zxing.common.HybridBinarizer;
-import com.king.zxing.camera.CameraManager;
-import com.king.zxing.util.LogUtils;
-
-import java.io.ByteArrayOutputStream;
-import java.util.Map;
-
-final class DecodeHandler extends Handler {
-
- private final Context context;
- private final CameraManager cameraManager;
- private final CaptureHandler handler;
- private final MultiFormatReader multiFormatReader;
- private boolean running = true;
-
- private long lastZoomTime;
-
- DecodeHandler(Context context, CameraManager cameraManager,CaptureHandler handler, Map hints) {
- multiFormatReader = new MultiFormatReader();
- multiFormatReader.setHints(hints);
- this.context = context;
- this.cameraManager = cameraManager;
- this.handler = handler;
- }
-
- @Override
- public void handleMessage(Message message) {
- if (message == null || !running) {
- return;
- }
- if (message.what == R.id.decode) {
- decode((byte[]) message.obj, message.arg1, message.arg2,isScreenPortrait(),handler.isSupportVerticalCode());
-
- } else if (message.what == R.id.quit) {
- running = false;
- Looper.myLooper().quit();
-
- }
- }
-
- private boolean isScreenPortrait(){
- WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = manager.getDefaultDisplay();
- Point screenResolution = new Point();
- display.getSize(screenResolution);
- return screenResolution.x < screenResolution.y;
- }
-
- /**
- * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
- * reuse the same reader objects from one decode to the next.
- *
- * @param data The YUV preview frame.
- * @param width The width of the preview frame.
- * @param height The height of the preview frame.
- */
- private void decode(byte[] data, int width, int height,boolean isScreenPortrait,boolean isSupportVerticalCode) {
- long start = System.currentTimeMillis();
- Result rawResult = null;
- PlanarYUVLuminanceSource source = buildPlanarYUVLuminanceSource(data,width,height,isScreenPortrait);
-
- if (source != null) {
-
- boolean isReDecode;
- try {
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- rawResult = multiFormatReader.decodeWithState(bitmap);
- isReDecode = false;
- } catch (Exception e) {
- isReDecode = true;
- }
-
- if(isReDecode && handler.isSupportLuminanceInvert()){
- try {
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source.invert()));
- rawResult = multiFormatReader.decodeWithState(bitmap);
- isReDecode = false;
- } catch (Exception e) {
- isReDecode = true;
- }
- }
-
- if(isReDecode){
- try{
- BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
- rawResult = multiFormatReader.decodeWithState(bitmap);
- isReDecode = false;
- }catch (Exception e){
- isReDecode = true;
- }
- }
-
- if(isReDecode && isSupportVerticalCode){
- source = buildPlanarYUVLuminanceSource(data,width,height,!isScreenPortrait);
- if(source!=null){
- try{
- BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
- rawResult = multiFormatReader.decodeWithState(bitmap);
- }catch (Exception e){
-
- }
- }
-
- }
-
- multiFormatReader.reset();
- }
-
- if (rawResult != null) {
- // Don't log the barcode contents for security.
- long end = System.currentTimeMillis();
- LogUtils.d("Found barcode in " + (end - start) + " ms");
-
- if(handler.isSupportAutoZoom()){//是否支持自动放大
- ResultPoint[] resultPoints = rawResult.getResultPoints();
- LogUtils.d("resultPoints:" +resultPoints.length);
-
- final int length = resultPoints.length;
- if(length >= 2){//超过两个点则计算距离
- int ratio = 6;
- int maxDistance = (int)ResultPoint.distance(resultPoints[0],resultPoints[1]);
- if(length >= 3){
- float distance2 = ResultPoint.distance(resultPoints[1],resultPoints[2]);
- float distance3 = ResultPoint.distance(resultPoints[0],resultPoints[2]);
- maxDistance = (int)Math.max(Math.max(maxDistance,distance2),distance3);
- ratio = 5;
- }
-
- if(handleAutoZoom(maxDistance,width,ratio)){//根据点之间的最大距离
- Message message = Message.obtain();
- message.what = R.id.decode_succeeded;
- message.obj = rawResult;
- if(handler.isReturnBitmap()){
- Bundle bundle = new Bundle();
- bundleThumbnail(source, bundle);
- message.setData(bundle);
- }
- handler.sendMessageDelayed(message,300);
- return;
- }
- }
- }
-
- Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult);
- if(handler.isReturnBitmap()){
- Bundle bundle = new Bundle();
- bundleThumbnail(source, bundle);
- message.setData(bundle);
- }
- message.sendToTarget();
-
- } else {
- Message message = Message.obtain(handler, R.id.decode_failed);
- message.sendToTarget();
- }
- }
-
- private PlanarYUVLuminanceSource buildPlanarYUVLuminanceSource(byte[] data, int width, int height,boolean isRotate){
- PlanarYUVLuminanceSource source;
- if(isRotate){
- byte[] rotatedData = new byte[data.length];
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++)
- rotatedData[x * height + height - y - 1] = data[x + y * width];
- }
- int tmp = width;
- width = height;
- height = tmp;
- source = cameraManager.buildLuminanceSource(rotatedData, width, height);
- }else{
- source = cameraManager.buildLuminanceSource(data, width, height);
- }
- return source;
- }
-
- private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) {
- int[] pixels = source.renderThumbnail();
- int width = source.getThumbnailWidth();
- int height = source.getThumbnailHeight();
- Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
- bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray());
- bundle.putFloat(DecodeThread.BARCODE_SCALED_FACTOR, (float) width / source.getWidth());
- }
-
- private boolean handleAutoZoom(int length,int width,int ratio){
- if(lastZoomTime > System.currentTimeMillis() - 1000){
- return false;
- }
-
- if(length < width / ratio){
-
- Camera camera = cameraManager.getOpenCamera().getCamera();
- if(camera!=null){
- Camera.Parameters params = camera.getParameters();
- if (params.isZoomSupported()) {
- int maxZoom = params.getMaxZoom();
- int zoom = params.getZoom();
- params.setZoom(Math.min(zoom + maxZoom/5,maxZoom));
- camera.setParameters(params);
- lastZoomTime = System.currentTimeMillis();
- return true;
- } else {
- LogUtils.d("Zoom not supported");
- }
- }
-
- }
-
- return false;
- }
-
-}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/DecodeThread.java b/lib/src/main/java/com/king/zxing/DecodeThread.java
deleted file mode 100644
index 4a4b5b8..0000000
--- a/lib/src/main/java/com/king/zxing/DecodeThread.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.king.zxing;
-
-/*
- * Copyright (C) 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.DecodeHintType;
-import com.google.zxing.ResultPointCallback;
-import com.king.zxing.camera.CameraManager;
-import com.king.zxing.util.LogUtils;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.os.Handler;
-import android.os.Looper;
-import android.preference.PreferenceManager;
-
-import java.util.Collection;
-import java.util.EnumMap;
-import java.util.EnumSet;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-
-/**
- * This thread does all the heavy lifting of decoding the images.
- *
- * @author dswitkin@google.com (Daniel Switkin)
- */
-final class DecodeThread extends Thread {
-
- public static final String BARCODE_BITMAP = "barcode_bitmap";
- public static final String BARCODE_SCALED_FACTOR = "barcode_scaled_factor";
-
- private final Context context;
- private final CameraManager cameraManager;
- private final Map hints;
- private Handler handler;
- private CaptureHandler captureHandler;
- private final CountDownLatch handlerInitLatch;
-
- DecodeThread(Context context,CameraManager cameraManager,
- CaptureHandler captureHandler,
- Collection decodeFormats,
- Map baseHints,
- String characterSet,
- ResultPointCallback resultPointCallback) {
-
- this.context = context;
- this.cameraManager = cameraManager;
- this.captureHandler = captureHandler;
- handlerInitLatch = new CountDownLatch(1);
-
- hints = new EnumMap<>(DecodeHintType.class);
- if (baseHints != null) {
- hints.putAll(baseHints);
- }
-
- // The prefs can't change while the thread is running, so pick them up once here.
- if (decodeFormats == null || decodeFormats.isEmpty()) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- decodeFormats = EnumSet.noneOf(BarcodeFormat.class);
- if (prefs.getBoolean(Preferences.KEY_DECODE_1D_PRODUCT, true)) {
- decodeFormats.addAll(DecodeFormatManager.PRODUCT_FORMATS);
- }
- if (prefs.getBoolean(Preferences.KEY_DECODE_1D_INDUSTRIAL, true)) {
- decodeFormats.addAll(DecodeFormatManager.INDUSTRIAL_FORMATS);
- }
- if (prefs.getBoolean(Preferences.KEY_DECODE_QR, true)) {
- decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
- }
- if (prefs.getBoolean(Preferences.KEY_DECODE_DATA_MATRIX, true)) {
- decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
- }
- if (prefs.getBoolean(Preferences.KEY_DECODE_AZTEC, false)) {
- decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS);
- }
- if (prefs.getBoolean(Preferences.KEY_DECODE_PDF417, false)) {
- decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS);
- }
- }
- hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
-
- if (characterSet != null) {
- hints.put(DecodeHintType.CHARACTER_SET, characterSet);
- }
- hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
- LogUtils.i("Hints: " + hints);
- }
-
- Handler getHandler() {
- try {
- handlerInitLatch.await();
- } catch (InterruptedException ie) {
- // continue?
- }
- return handler;
- }
-
- @Override
- public void run() {
- Looper.prepare();
- handler = new DecodeHandler(context,cameraManager,captureHandler, hints);
- handlerInitLatch.countDown();
- Looper.loop();
- }
-
-}
\ No newline at end of file
diff --git a/lib/src/main/java/com/king/zxing/DefaultCameraScan.java b/lib/src/main/java/com/king/zxing/DefaultCameraScan.java
new file mode 100644
index 0000000..cab3584
--- /dev/null
+++ b/lib/src/main/java/com/king/zxing/DefaultCameraScan.java
@@ -0,0 +1,404 @@
+package com.king.zxing;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.Result;
+import com.google.zxing.ResultPoint;
+import com.king.zxing.analyze.Analyzer;
+import com.king.zxing.analyze.MultiFormatAnalyzer;
+import com.king.zxing.util.LogUtils;
+
+import java.util.concurrent.Executors;
+
+import androidx.annotation.FloatRange;
+import androidx.annotation.Nullable;
+import androidx.camera.core.Camera;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.Preview;
+import androidx.camera.core.TorchState;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.view.PreviewView;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.MutableLiveData;
+
+/**
+ * @author Jenly
+ */
+public class DefaultCameraScan extends CameraScan {
+
+ private FragmentActivity mFragmentActivity;
+ private Context mContext;
+ private LifecycleOwner mLifecycleOwner;
+ private PreviewView mPreviewView;
+
+ private ListenableFuture mCameraProviderFuture;
+ private Camera mCamera;
+
+ private CameraConfig mCameraConfig;
+ private Analyzer mAnalyzer;
+
+ /**
+ * 是否分析
+ */
+ private volatile boolean isAnalyze = true;
+
+ /**
+ * 是否已经分析出结果
+ */
+ private volatile boolean isAnalyzeResult;
+
+ private View flashlightView;
+
+ private MutableLiveData mResultLiveData;
+
+ private OnScanResultCallback mOnScanResultCallback;
+
+ private BeepManager mBeepManager;
+ private AmbientLightManager mAmbientLightManager;
+
+ private int mScreenWidth;
+ private int mScreenHeight;
+ private long mLastAutoZoomTime;
+
+ public DefaultCameraScan(FragmentActivity activity, PreviewView previewView){
+ this.mFragmentActivity = activity;
+ this.mLifecycleOwner = activity;
+ this.mContext = activity;
+ this.mPreviewView = previewView;
+ initData();
+ }
+
+ public DefaultCameraScan(Fragment fragment, PreviewView previewView){
+ this.mFragmentActivity = fragment.getActivity();
+ this.mLifecycleOwner = fragment;
+ this.mContext = fragment.getContext();
+ this.mPreviewView = previewView;
+ initData();
+ }
+
+ private void initData(){
+ mResultLiveData = new MutableLiveData<>();
+ mResultLiveData.observe(mLifecycleOwner, result -> {
+ handleAnalyzeResult(result);
+ });
+ mPreviewView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ LogUtils.d("click");
+ }
+ });
+ mPreviewView.setOnTouchListener((v, event) -> onTouchEvent(event));
+
+ DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ mScreenWidth = displayMetrics.widthPixels;
+ mScreenHeight = displayMetrics.heightPixels;
+ mBeepManager = new BeepManager(mContext);
+ mAmbientLightManager = new AmbientLightManager(mContext);
+ if(mAmbientLightManager != null){
+ mAmbientLightManager.register();
+ mAmbientLightManager.setOnLightSensorEventListener((dark, lightLux) -> {
+ if(flashlightView != null){
+ flashlightView.setSelected(!dark);
+ if(dark){
+ if(flashlightView.getVisibility() != View.VISIBLE){
+ flashlightView.setVisibility(View.VISIBLE);
+ }
+ }else if(flashlightView.getVisibility() == View.VISIBLE){
+ flashlightView.setVisibility(View.INVISIBLE);
+ }
+ }
+ });
+ }
+ }
+
+ private void initConfig(){
+ if(mCameraConfig == null){
+ mCameraConfig = new CameraConfig();
+ }
+ if(mAnalyzer == null){
+ mAnalyzer = new MultiFormatAnalyzer();
+ }
+ }
+
+
+ @Override
+ public CameraScan setCameraConfig(CameraConfig cameraConfig) {
+ if(cameraConfig != null){
+ this.mCameraConfig = cameraConfig;
+ }
+ return this;
+ }
+
+ @Override
+ public void startCamera(){
+ initConfig();
+ mCameraProviderFuture = ProcessCameraProvider.getInstance(mContext);
+ mCameraProviderFuture.addListener(() -> {
+
+ try{
+ Preview preview = mCameraConfig.options(new Preview.Builder());
+
+ //相机选择器
+ CameraSelector cameraSelector = mCameraConfig.options(new CameraSelector.Builder()
+ .requireLensFacing(LENS_FACING_BACK));
+ //设置SurfaceProvider
+ preview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
+
+ //图像分析
+ ImageAnalysis imageAnalysis = mCameraConfig.options(new ImageAnalysis.Builder()
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST));
+ imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor(), image -> {
+ if(isAnalyze && !isAnalyzeResult && mAnalyzer != null){
+ Result result = mAnalyzer.analyze(image);
+ if(result != null){
+ mResultLiveData.postValue(result);
+ }
+ }
+ image.close();
+ });
+ if(mCamera != null){
+ mCameraProviderFuture.get().unbindAll();
+ }
+ //绑定到生命周期
+ mCamera = mCameraProviderFuture.get().bindToLifecycle(mLifecycleOwner, cameraSelector, preview, imageAnalysis);
+ }catch (Exception e){
+ LogUtils.e(e);
+ }
+
+ },ContextCompat.getMainExecutor(mContext));
+ }
+
+ /**
+ * 处理分析结果
+ * @param result
+ */
+ private synchronized void handleAnalyzeResult(Result result){
+ if(isAnalyzeResult || !isAnalyze){
+ return;
+ }
+ isAnalyzeResult = true;
+ if(mBeepManager != null){
+ mBeepManager.playBeepSoundAndVibrate();
+ }
+
+ if(result.getBarcodeFormat() == BarcodeFormat.QR_CODE && isNeedAutoZoom() && mLastAutoZoomTime + 100 < System.currentTimeMillis()){
+ ResultPoint[] points = result.getResultPoints();
+ if(points != null && points.length >= 2){
+ float distance1 = ResultPoint.distance(points[0],points[1]);
+ float maxDistance = distance1;
+ if(points.length >= 3){
+ float distance2 = ResultPoint.distance(points[1],points[2]);
+ float distance3 = ResultPoint.distance(points[0],points[2]);
+ maxDistance = Math.max(Math.max(distance1,distance2),distance3);
+ }
+ if(handleAutoZoom((int)maxDistance,result)){
+ return;
+ }
+ }
+ }
+
+ scanResultCallback(result);
+ }
+
+ private boolean handleAutoZoom(int distance,Result result){
+ int size = Math.min(mScreenWidth,mScreenHeight);
+ if(distance * 4 < size){
+ mLastAutoZoomTime = System.currentTimeMillis();
+ zoomIn();
+ scanResultCallback(result);
+ return true;
+ }
+ return false;
+ }
+
+ private void scanResultCallback(Result result){
+ if(mOnScanResultCallback != null && mOnScanResultCallback.onScanResultCallback(result)){
+ //如果拦截了结果,则重置分析结果状态,直接可以连扫
+ isAnalyzeResult = false;
+ return;
+ }
+
+ if(mFragmentActivity != null){
+ Intent intent = new Intent();
+ intent.putExtra(SCAN_RESULT,result.getText());
+ mFragmentActivity.setResult(Activity.RESULT_OK,intent);
+ mFragmentActivity.finish();
+ }
+ }
+
+
+ @Override
+ public void stopCamera(){
+ if(mCameraProviderFuture != null){
+ try {
+ mCameraProviderFuture.get().unbindAll();
+ }catch (Exception e){
+ LogUtils.e(e);
+ }
+ }
+ }
+
+ @Override
+ public CameraScan setAnalyzeImage(boolean analyze) {
+ isAnalyze = analyze;
+ return this;
+ }
+
+ /**
+ * 设置分析器,如果内置的一些分析器不满足您的需求,你也可以自定义{@link Analyzer},
+ * 自定义时,切记需在{@link #startCamera()}之前调用才有效
+ * @param analyzer
+ */
+ @Override
+ public CameraScan setAnalyzer(Analyzer analyzer) {
+ mAnalyzer = analyzer;
+ return this;
+ }
+
+ @Override
+ public void zoomIn(){
+ if(mCamera != null){
+ float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio() + 0.1f;
+ float maxRatio = mCamera.getCameraInfo().getZoomState().getValue().getMaxZoomRatio();
+ if(ratio <= maxRatio){
+ mCamera.getCameraControl().setZoomRatio(ratio);
+ }
+ }
+ }
+
+ @Override
+ public void zoomOut(){
+ if(mCamera != null){
+ float ratio = mCamera.getCameraInfo().getZoomState().getValue().getZoomRatio() - 0.1f;
+ float minRatio = mCamera.getCameraInfo().getZoomState().getValue().getMinZoomRatio();
+ if(ratio >= minRatio){
+ mCamera.getCameraControl().setZoomRatio(ratio);
+ }
+ }
+ }
+
+ @Override
+ public void zoomTo(float ratio) {
+ if(mCamera != null){
+ mCamera.getCameraControl().setZoomRatio(ratio);
+ }
+ }
+
+ @Override
+ public void lineZoomIn() {
+ if(mCamera != null){
+ float zoom = mCamera.getCameraInfo().getZoomState().getValue().getLinearZoom() + 0.1f;
+ if(zoom <= 1f){
+ mCamera.getCameraControl().setLinearZoom(zoom);
+ }
+ }
+ }
+
+ @Override
+ public void lineZoomOut() {
+ if(mCamera != null){
+ float zoom = mCamera.getCameraInfo().getZoomState().getValue().getLinearZoom() - 0.1f;
+ if(zoom >= 0f){
+ mCamera.getCameraControl().setLinearZoom(zoom);
+ }
+ }
+ }
+
+ @Override
+ public void lineZoomTo(@FloatRange(from = 0.0,to = 1.0) float linearZoom) {
+ if(mCamera != null){
+ mCamera.getCameraControl().setLinearZoom(linearZoom);
+ }
+ }
+
+ @Override
+ public CameraScan enableTorch(boolean torch) {
+ if(mCamera != null && hasFlashUnit()){
+ mCamera.getCameraControl().enableTorch(torch);
+ }
+ return this;
+ }
+
+ @Override
+ public boolean isTorchEnabled() {
+ if(mCamera != null){
+ return mCamera.getCameraInfo().getTorchState().getValue() == TorchState.ON;
+ }
+ return false;
+ }
+
+ /**
+ * 是否支持闪光灯
+ * @return
+ */
+ @Override
+ public boolean hasFlashUnit(){
+ if(mCamera != null){
+ return mCamera.getCameraInfo().hasFlashUnit();
+ }
+ return false;
+ }
+
+ @Override
+ public CameraScan setVibrate(boolean vibrate) {
+ if(mBeepManager != null){
+ mBeepManager.setVibrate(vibrate);
+ }
+ return this;
+ }
+
+ @Override
+ public CameraScan setPlayBeep(boolean playBeep) {
+ if(mBeepManager != null){
+ mBeepManager.setPlayBeep(playBeep);
+ }
+ return this;
+ }
+
+ @Override
+ public CameraScan setOnScanResultCallback(OnScanResultCallback callback) {
+ this.mOnScanResultCallback = callback;
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public Camera getCamera(){
+ return mCamera;
+ }
+
+
+ @Override
+ public void release() {
+ isAnalyze = false;
+ flashlightView = null;
+ if(mAmbientLightManager != null){
+ mAmbientLightManager.unregister();
+ }
+ if(mBeepManager != null){
+ mBeepManager.close();
+ }
+ stopCamera();
+ }
+
+ @Override
+ public CameraScan bindFlashlightView(@Nullable View v) {
+ flashlightView = v;
+ if(mAmbientLightManager != null){
+ mAmbientLightManager.setLightSensorEnabled(v != null);
+ }
+ return this;
+ }
+
+}
diff --git a/lib/src/main/java/com/king/zxing/ICameraScan.java b/lib/src/main/java/com/king/zxing/ICameraScan.java
new file mode 100644
index 0000000..9433233
--- /dev/null
+++ b/lib/src/main/java/com/king/zxing/ICameraScan.java
@@ -0,0 +1,69 @@
+package com.king.zxing;
+
+
+import android.view.MotionEvent;
+
+import com.google.zxing.Result;
+
+import androidx.annotation.FloatRange;
+import androidx.annotation.Nullable;
+import androidx.camera.core.Camera;
+
+/**
+ * @author Jenly
+ */
+public interface ICameraScan {
+
+ /**
+ * 启动相机预览
+ */
+ void startCamera();
+
+ /**
+ * 停止相机预览
+ */
+ void stopCamera();
+
+
+ /**
+ * 放大
+ */
+ void zoomIn();
+
+ /**
+ * 缩小
+ */
+ void zoomOut();
+
+ /**
+ * 缩放到指定比例
+ * @param ratio
+ */
+ void zoomTo(float ratio);
+
+ /**
+ * 放大
+ */
+ void lineZoomIn();
+
+ /**
+ * 缩小
+ */
+ void lineZoomOut();
+
+ /**
+ * 线性缩放到指定比例
+ * @param linearZoom
+ */
+ void lineZoomTo(@FloatRange(from = 0.0,to = 1.0) float linearZoom);
+
+
+ /**
+ * 获取{@link Camera}
+ * @return
+ */
+ @Nullable Camera getCamera();
+
+ void release();
+
+}
diff --git a/lib/src/main/java/com/king/zxing/InactivityTimer.java b/lib/src/main/java/com/king/zxing/InactivityTimer.java
deleted file mode 100644
index 45a505a..0000000
--- a/lib/src/main/java/com/king/zxing/InactivityTimer.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.king.zxing;
-
-/*
- * Copyright (C) 2010 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.AsyncTask;
-import android.os.BatteryManager;
-
-import com.king.zxing.util.LogUtils;
-
-import java.lang.ref.WeakReference;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- * Finishes an activity after a period of inactivity if the device is on battery power.
- */
-final class InactivityTimer {
-
- private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L;
-
- private final Activity activity;
- private final BroadcastReceiver powerStatusReceiver;
- private boolean registered;
- private AsyncTask