Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kongzue committed Aug 28, 2021
0 parents commit c033471
Show file tree
Hide file tree
Showing 46 changed files with 1,216 additions and 0 deletions.
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions CameraXQRDecoder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
39 changes: 39 additions & 0 deletions CameraXQRDecoder/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
plugins {
id 'com.android.library'
}

android {
compileSdk 30

defaultConfig {
minSdk 21
targetSdk 30
versionCode 1
versionName "1.0"
consumerProguardFiles "consumer-rules.pro"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
compileOnly 'androidx.appcompat:appcompat:1.0.0+'
compileOnly 'com.google.android.material:material:1.0.0+'

def camerax_version = "1.0.0"
api "androidx.camera:camera-core:${camerax_version}"
api "androidx.camera:camera-camera2:${camerax_version}"
api "androidx.camera:camera-lifecycle:${camerax_version}"
api "androidx.camera:camera-view:1.0.0-alpha25"
api "androidx.camera:camera-extensions:1.0.0-alpha25"
api 'com.google.zxing:core:3.3.2'
}
Empty file.
21 changes: 21 additions & 0 deletions CameraXQRDecoder/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
7 changes: 7 additions & 0 deletions CameraXQRDecoder/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kongzue.cameraxqrdecoder">

<uses-permission android:name="android.permission.CAMERA" />

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package com.kongzue.cameraxqrdecoder;

import static androidx.camera.core.ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST;

import static com.kongzue.cameraxqrdecoder.util.Utils.isNull;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.Preview;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;

import com.google.common.util.concurrent.ListenableFuture;
import com.kongzue.cameraxqrdecoder.interfaces.OnWorkFinish;
import com.kongzue.cameraxqrdecoder.util.QRcodeAnalyzerImpl;
import com.kongzue.cameraxqrdecoder.util.QrDecoderPermissionUtil;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* @author: Kongzue
* @github: https://github.com/kongzue/
* @homepage: http://kongzue.com/
* @mail: myzcxhh@live.cn
* @createTime: 2021/8/28 9:32
*/
public class QrDecoderView extends FrameLayout {

public static boolean DEBUGMODE = true;
public static final String ERROR_NO_PERMISSION = "无法初始化:请检查权限,未获得权限:android.permission.CAMERA";

boolean isFlashOpen;
ExecutorService cameraExecutor;
boolean finish;
CameraInternal cameraInternal;
OnWorkFinish<String> onWorkFinish;
boolean keepScan;

public QrDecoderView(@NonNull Context context) {
super(context);
}

public QrDecoderView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

public QrDecoderView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public QrDecoderView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

public void start(OnWorkFinish<String> onWorkFinish) {
if (QrDecoderPermissionUtil.checkPermissions(getContext(), new String[]{"android.permission.CAMERA"})) {
this.onWorkFinish = onWorkFinish;
addScanQRView();
} else {
error(ERROR_NO_PERMISSION);
}
}

public boolean isFlashOpen() {
return isFlashOpen;
}

public QrDecoderView setFlashOpen(boolean flashOpen) {
isFlashOpen = flashOpen;
if (cameraInternal != null) {
cameraInternal.getCameraControl().enableTorch(isFlashOpen);
}
return this;
}

String oldResult;

private void addScanQRView() {
PreviewView viewFinder = new PreviewView(getContext());
addView(viewFinder, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

viewFinder.post(new Runnable() {
@Override
public void run() {
cameraExecutor = Executors.newSingleThreadExecutor();

CameraSelector.Builder builder = new CameraSelector.Builder();
builder.requireLensFacing(CameraSelector.LENS_FACING_BACK);
CameraSelector cameraSelector = builder.build();

ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(getContext());
DisplayMetrics metrics = new DisplayMetrics();
viewFinder.getDisplay().getRealMetrics(metrics);
int screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels); //屏幕纵横比
int rotation = viewFinder.getDisplay().getRotation();

cameraProviderFuture.addListener(new Runnable() {
@SuppressLint("RestrictedApi")
@Override
public void run() {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

Preview.Builder pBuilder = new Preview.Builder();
pBuilder.setTargetAspectRatio(screenAspectRatio);
pBuilder.setTargetRotation(rotation);
Preview preview = pBuilder.build();

preview.setSurfaceProvider(viewFinder.getSurfaceProvider());

ImageAnalysis.Builder iBuilder = new ImageAnalysis.Builder();
iBuilder.setBackpressureStrategy(STRATEGY_KEEP_ONLY_LATEST);
iBuilder.setTargetAspectRatio(screenAspectRatio);
iBuilder.setTargetRotation(rotation);

ImageAnalysis analysis = iBuilder.build();
analysis.setAnalyzer(cameraExecutor, new QRcodeAnalyzerImpl(new OnWorkFinish<String>() {
@Override
public void finish(String result) {
if (!finish && !isNull(result) && !Objects.equals(oldResult, result)) {
if (!keepScan) finish = true;
if (onWorkFinish != null) {
onWorkFinish.finish(result);
}
oldResult = result;
}
}
}));

cameraProvider.unbindAll();
cameraProvider.bindToLifecycle((AppCompatActivity) getContext(), cameraSelector, preview, analysis);

cameraInternal = preview.getCamera();
} catch (Exception e) {
if (DEBUGMODE) e.printStackTrace();
e.printStackTrace();
}
}
}, ContextCompat.getMainExecutor(getContext()));
}
});
}

double RATIO_4_3_VALUE = 4.0 / 3.0;
double RATIO_16_9_VALUE = 16.0 / 9.0;

private int aspectRatio(int width, int height) {
double previewRatio = Math.max(width, height) / Math.min(width, height);
if (Math.abs(previewRatio - RATIO_4_3_VALUE) <= Math.abs(previewRatio - RATIO_16_9_VALUE)) {
return AspectRatio.RATIO_4_3;
}
return AspectRatio.RATIO_16_9;
}

private void error(String errorNoPermission) {
if (DEBUGMODE) {
Log.e("QrDecoderView", errorNoPermission);
}
}

public boolean isKeepScan() {
return keepScan;
}

public QrDecoderView setKeepScan(boolean keepScan) {
this.keepScan = keepScan;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kongzue.cameraxqrdecoder.interfaces;

/**
* @author: Kongzue
* @github: https://github.com/kongzue/
* @homepage: http://kongzue.com/
* @mail: myzcxhh@live.cn
* @createTime: 2021/8/28 9:41
*/
public abstract class OnWorkFinish<D> {
public abstract void finish(D d);
public void failed(Object e){};
public void close(){};
}
Loading

0 comments on commit c033471

Please sign in to comment.