This commit is contained in:
2025-11-18 15:25:59 +08:00
parent 790f719050
commit 69f2eaf336
1227 changed files with 89317 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.bertsir.zbar"
>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
>
<provider
android:name=".utils.QrFileProvider"
android:authorities="${applicationId}.zbar.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/qr_file_paths"/>
</provider>
<activity android:name="cn.bertsir.zbar.QRActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
/>
<activity
android:name=".utils.PermissionUtils$PermissionActivity"
android:theme="@style/ActivityTranslucent"
/>
<activity android:name="com.soundcloud.android.crop.CropImageActivity" />
</application>
</manifest>
@@ -0,0 +1,211 @@
/*
* Copyright © Yan Zhenjie
*
* 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 cn.bertsir.zbar;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
/**
* <p>Camera config.</p>
*/
public final class CameraConfiguration {
private static final String TAG = "CameraConfiguration";
private static final int MIN_PREVIEW_PIXELS = 480 * 320;
private static final double MAX_ASPECT_DISTORTION = 0.15;
private final Context context;
private Point screenResolution;
private Point cameraResolution;
public CameraConfiguration(Context context) {
this.context = context;
}
@SuppressWarnings("SuspiciousNameCombination")
public void initFromCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
screenResolution = getDisplaySize(display);
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// Convert to vertical screen.
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
}
cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera);
}
private Point getDisplaySize(final Display display) {
final Point point = new Point();
if (Build.VERSION.SDK_INT >= 13)
display.getSize(point);
else {
point.set(display.getWidth(), display.getHeight());
}
return point;
}
public void setDesiredCameraParameters(Camera camera, boolean safeMode) {
Camera.Parameters parameters = camera.getParameters();
if (parameters == null) {
Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration.");
return;
}
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
camera.setParameters(parameters);
Camera.Parameters afterParameters = camera.getParameters();
Camera.Size afterSize = afterParameters.getPreviewSize();
if (afterSize != null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize.height)) {
cameraResolution.x = afterSize.width;
cameraResolution.y = afterSize.height;
}
camera.setDisplayOrientation(90);
}
/**
* Camera resolution.
*
* @return {@link Point}.
*/
public Point getCameraResolution() {
return cameraResolution;
}
/**
* Screen resolution.
*
* @return {@link Point}.
*/
public Point getScreenResolution() {
return screenResolution;
}
/**
* Calculate the preview interface size.
*
* @param parameters camera params.
* @param screenResolution screen resolution.
* @return {@link Point}.
*/
private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes();
if (rawSupportedSizes == null) {
Log.w(TAG, "Device returned no supported preview sizes; using default");
Camera.Size defaultSize = parameters.getPreviewSize();
return new Point(defaultSize.width, defaultSize.height);
}
// Sort by size, descending
List<Camera.Size> supportedPreviewSizes = new ArrayList<>(rawSupportedSizes);
Collections.sort(supportedPreviewSizes, new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size a, Camera.Size b) {
int aPixels = a.height * a.width;
int bPixels = b.height * b.width;
if (bPixels < aPixels) {
return -1;
}
if (bPixels > aPixels) {
return 1;
}
return 0;
}
});
if (Log.isLoggable(TAG, Log.INFO)) {
StringBuilder previewSizesString = new StringBuilder();
for (Camera.Size supportedPreviewSize : supportedPreviewSizes) {
previewSizesString.append(supportedPreviewSize.width)
.append('x')
.append(supportedPreviewSize.height)
.append(' ');
}
Log.i(TAG, "Supported preview sizes: " + previewSizesString);
}
double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
// Remove sizes that are unsuitable
Iterator<Camera.Size> it = supportedPreviewSizes.iterator();
while (it.hasNext()) {
Camera.Size supportedPreviewSize = it.next();
int realWidth = supportedPreviewSize.width;
int realHeight = supportedPreviewSize.height;
if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
it.remove();
continue;
}
boolean isCandidatePortrait = realWidth < realHeight;
int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth;
int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight;
double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
double distortion = Math.abs(aspectRatio - screenAspectRatio);
if (distortion > MAX_ASPECT_DISTORTION) {
it.remove();
continue;
}
if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
Point exactPoint = new Point(realWidth, realHeight);
Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
return exactPoint;
}
}
// If no exact match, use largest preview size. This was not a great
// idea on older devices because
// of the additional computation needed. We're likely to get here on
// newer Android 4+ devices, where
// the CPU is much more powerful.
if (!supportedPreviewSizes.isEmpty()) {
Camera.Size largestPreview = supportedPreviewSizes.get(0);
Point largestSize = new Point(largestPreview.width, largestPreview.height);
Log.i(TAG, "Using largest suitable preview size: " + largestSize);
return largestSize;
}
// If there is nothing at all suitable, return current preview size
Camera.Size defaultPreview = parameters.getPreviewSize();
Point defaultSize = new Point(defaultPreview.width, defaultPreview.height);
Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize);
return defaultSize;
}
}
@@ -0,0 +1,238 @@
/*
* Copyright © Yan Zhenjie
*
* 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 cn.bertsir.zbar;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import java.io.IOException;
import cn.bertsir.zbar.utils.QRUtils;
/**
* <p>Camera manager.</p>
*/
public final class CameraManager {
private static final String TAG = "CameraManager";
private final CameraConfiguration mConfiguration;
private Context context;
private Camera mCamera;
public CameraManager(Context context) {
this.context = context;
this.mConfiguration = new CameraConfiguration(context);
}
/**
* Opens the mCamera driver and initializes the hardware parameters.
*
* @throws Exception ICamera open failed, occupied or abnormal.
*/
public synchronized void openDriver() throws Exception {
if (mCamera != null) return;
mCamera = Camera.open();
if (mCamera == null) throw new IOException("The camera is occupied.");
mConfiguration.initFromCameraParameters(mCamera);
Camera.Parameters parameters = mCamera.getParameters();
String parametersFlattened = parameters == null ? null : parameters.flatten();
try {
mConfiguration.setDesiredCameraParameters(mCamera, false);
} catch (RuntimeException re) {
if (parametersFlattened != null) {
parameters = mCamera.getParameters();
parameters.unflatten(parametersFlattened);
try {
mCamera.setParameters(parameters);
mConfiguration.setDesiredCameraParameters(mCamera, true);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
}
/**
* Closes the camera driver if still in use.
*/
public synchronized void closeDriver() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
/**
* Camera is opened.
*
* @return true, other wise false.
*/
public boolean isOpen() {
return mCamera != null;
}
/**
* Get camera configuration.
*
* @return {@link CameraConfiguration}.
*/
public CameraConfiguration getConfiguration() {
return mConfiguration;
}
/**
* Camera start preview.
*
* @param holder {@link SurfaceHolder}.
* @param previewCallback {@link Camera.PreviewCallback}.
* @throws IOException if the method fails (for example, if the surface is unavailable or unsuitable).
*/
public void startPreview(SurfaceHolder holder, Camera.PreviewCallback previewCallback) throws IOException {
if (mCamera != null) {
//解决nexus5x扫码倒立的情况
if(android.os.Build.MANUFACTURER.equals("LGE") &&
android.os.Build.MODEL.equals("Nexus 5X")) {
mCamera.setDisplayOrientation(QRUtils.getInstance().isScreenOriatationPortrait(context) ? 270 : 180);
}else {
mCamera.setDisplayOrientation(QRUtils.getInstance().isScreenOriatationPortrait(context) ? 90 : 0);
}
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
}
}
/**
* Camera stop preview.
*/
public void stopPreview() {
if (mCamera != null) {
try {
mCamera.stopPreview();
} catch (Exception ignored) {
// nothing.
}
try {
mCamera.setPreviewDisplay(null);
} catch (IOException ignored) {
// nothing.
}
}
}
/**
* Focus on, make a scan action.
*
* @param callback {@link Camera.AutoFocusCallback}.
*/
public void autoFocus(Camera.AutoFocusCallback callback) {
if (mCamera != null)
try {
mCamera.autoFocus(callback);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* set Camera Flash
*/
public void setFlash(){
if(mCamera != null){
Camera.Parameters parameters = mCamera.getParameters();
if(parameters.getFlashMode() == null) {
return;
}
if(parameters.getFlashMode().endsWith(Camera.Parameters.FLASH_MODE_TORCH)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}else {
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
mCamera.setParameters(parameters);
}
}
/**
* set Camera Flash
*/
public void setFlash(boolean open){
if(mCamera != null){
Camera.Parameters parameters = mCamera.getParameters();
if(parameters.getFlashMode() == null) {
return;
}
if(!open){
if(parameters.getFlashMode().endsWith(Camera.Parameters.FLASH_MODE_TORCH)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
}else {
if(parameters.getFlashMode().endsWith(Camera.Parameters.FLASH_MODE_OFF)){
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
}
mCamera.setParameters(parameters);
}
}
/**
* 相机设置焦距
*/
public void setCameraZoom(float ratio){
if(mCamera != null){
Camera.Parameters parameters = mCamera.getParameters();
if(!parameters.isZoomSupported()){
return;
}
int maxZoom = parameters.getMaxZoom();
if(maxZoom == 0){
return;
}
int zoom = (int) (maxZoom * ratio);
parameters.setZoom(zoom);
mCamera.setParameters(parameters);
}
}
public void handleZoom(boolean isZoomIn) {
if(mCamera != null){
Camera.Parameters params = mCamera.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);
mCamera.setParameters(params);
} else {
Log.i(TAG, "zoom not supported");
}
}
}
}
@@ -0,0 +1,168 @@
/*
* Copyright © Yan Zhenjie
*
* 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 cn.bertsir.zbar;
import android.content.Context;
import android.hardware.Camera;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;
/**
* <p>QRCode Camera preview, include QRCode recognition.</p>
*/
public class CameraPreview extends FrameLayout implements SurfaceHolder.Callback {
private CameraManager mCameraManager;
private CameraScanAnalysis mPreviewCallback;
private SurfaceView mSurfaceView;
private boolean isPreviewStart = false;
public CameraPreview(Context context) {
this(context, null);
}
public CameraPreview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCameraManager = new CameraManager(context);
mPreviewCallback = new CameraScanAnalysis(context);
}
/**
* Set Scan results callback.
*
* @param callback {@link ScanCallback}.
*/
public void setScanCallback(ScanCallback callback) {
mPreviewCallback.setScanCallback(callback);
}
/**
* Camera start preview.
*/
public boolean start() {
try {
mCameraManager.openDriver();
} catch (Exception e) {
Toast.makeText(getContext(), "摄像头权限被拒绝!", Toast.LENGTH_SHORT).show();
return false;
}
mPreviewCallback.onStart();
if (mSurfaceView == null) {
mSurfaceView = new SurfaceView(getContext());
addView(mSurfaceView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
SurfaceHolder holder = mSurfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
startCameraPreview(mSurfaceView.getHolder());
return true;
}
/**
* Camera stop preview.
*/
public void stop() {
removeCallbacks(mAutoFocusTask);
mPreviewCallback.onStop();
mCameraManager.stopPreview();
mCameraManager.closeDriver();
}
private void startCameraPreview(SurfaceHolder holder) {
try {
mCameraManager.startPreview(holder, mPreviewCallback);
mCameraManager.autoFocus(mFocusCallback);
isPreviewStart = true;
} catch (Exception e) {
e.printStackTrace();
//如果异常延迟200ms再试
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mCameraManager.autoFocus(mFocusCallback);
}
}, 200);
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (holder.getSurface() == null) {
return;
}
mCameraManager.stopPreview();
startCameraPreview(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
private Camera.AutoFocusCallback mFocusCallback = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
postDelayed(mAutoFocusTask, 500);
}
};
private Runnable mAutoFocusTask = new Runnable() {
public void run() {
mCameraManager.autoFocus(mFocusCallback);
}
};
@Override
protected void onDetachedFromWindow() {
stop();
super.onDetachedFromWindow();
}
public void setFlash() {
mCameraManager.setFlash();
}
public void setFlash(boolean open) {
mCameraManager.setFlash(open);
}
public void setZoom(float zoom){
mCameraManager.setCameraZoom(zoom);
}
public void handleZoom(boolean isZoomIn){
mCameraManager.handleZoom(isZoomIn);
}
public boolean isPreviewStart(){
return this.isPreviewStart;
}
}
@@ -0,0 +1,316 @@
/*
* Copyright © Yan Zhenjie
*
* 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 cn.bertsir.zbar;
import android.content.Context;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.DetectorResult;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.datamatrix.detector.Detector;
import com.google.zxing.qrcode.QRCodeReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import cn.bertsir.zbar.Qr.Config;
import cn.bertsir.zbar.Qr.Image;
import cn.bertsir.zbar.Qr.ImageScanner;
import cn.bertsir.zbar.Qr.ScanResult;
import cn.bertsir.zbar.Qr.Symbol;
import cn.bertsir.zbar.Qr.SymbolSet;
import cn.bertsir.zbar.utils.QRUtils;
/**
*/
class CameraScanAnalysis implements Camera.PreviewCallback {
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private ImageScanner mImageScanner;
private Handler mHandler;
private ScanCallback mCallback;
private static final String TAG = "CameraScanAnalysis";
private boolean allowAnalysis = true;
private Image barcode;
private int cropWidth;
private int cropHeight;
private Camera.Size size;
private byte[] data;
private Camera camera;
private Context context;
private long lastResultTime = 0;
private MultiFormatReader multiFormatReader = new MultiFormatReader();
CameraScanAnalysis(Context context) {
this.context = context;
mImageScanner = new ImageScanner();
if (Symbol.scanType == QrConfig.TYPE_QRCODE) {
mImageScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
mImageScanner.setConfig(Symbol.QRCODE, Config.ENABLE, 1);
} else if (Symbol.scanType == QrConfig.TYPE_BARCODE) {
mImageScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
mImageScanner.setConfig(Symbol.CODE128, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.CODE39, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.EAN13, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.EAN8, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.UPCA, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.UPCE, Config.ENABLE, 1);
mImageScanner.setConfig(Symbol.UPCE, Config.ENABLE, 1);
} else if (Symbol.scanType == QrConfig.TYPE_ALL) {
mImageScanner.setConfig(Symbol.NONE, Config.X_DENSITY, 3);
mImageScanner.setConfig(Symbol.NONE, Config.Y_DENSITY, 3);
} else if (Symbol.scanType == QrConfig.TYPE_CUSTOM) {
mImageScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
mImageScanner.setConfig(Symbol.scanFormat, Config.ENABLE, 1);
} else {
mImageScanner.setConfig(Symbol.NONE, Config.X_DENSITY, 3);
mImageScanner.setConfig(Symbol.NONE, Config.Y_DENSITY, 3);
}
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (mCallback != null) mCallback.onScanResult((ScanResult) msg.obj);
}
};
}
void setScanCallback(ScanCallback callback) {
this.mCallback = callback;
}
void onStop() {
this.allowAnalysis = false;
}
void onStart() {
this.allowAnalysis = true;
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (allowAnalysis) {
allowAnalysis = false;
this.data = data;
this.camera = camera;
size = camera.getParameters().getPreviewSize();
barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
if (Symbol.is_only_scan_center) {
//用于框中的自动拉伸和对识别数据的裁剪
cropWidth = (int) (Symbol.cropWidth * (size.height / (float) Symbol.screenWidth));
cropHeight = (int) (Symbol.cropHeight * (size.width / (float) Symbol.screenHeight));
Symbol.cropX = size.width / 2 - cropHeight / 2;
Symbol.cropY = size.height / 2 - cropWidth / 2;
barcode.setCrop(Symbol.cropX, Symbol.cropY, cropHeight, cropWidth);
}else {
//用于全屏幕的自动拉升
Symbol.cropX =0;
Symbol.cropY = 0;
cropWidth = size.width;
cropHeight = size.height;
}
if(Symbol.looperScan && (System.currentTimeMillis() - lastResultTime < Symbol.looperWaitTime)){
allowAnalysis = true;
return;
}
executorService.execute(mAnalysisTask);
}
}
/**
* 相机设置焦距
*/
public void cameraZoom(Camera mCamera) {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
if (!parameters.isZoomSupported()) {
return;
}
int maxZoom = parameters.getMaxZoom();
if (maxZoom == 0) {
return;
}
if (parameters.getZoom() + 10 > parameters.getMaxZoom()) {
return;
}
parameters.setZoom(parameters.getZoom() + 10);
mCamera.setParameters(parameters);
}
}
private Runnable mAnalysisTask = new Runnable() {
@Override
public void run() {
if (Symbol.is_auto_zoom && Symbol.scanType == QrConfig.TYPE_QRCODE
&& QRUtils.getInstance().isScreenOriatationPortrait(context)) {
if(Symbol.is_only_scan_center){
if (Symbol.cropX == 0 || Symbol.cropY == 0 || cropWidth == 0 || cropHeight == 0) {
return;
}
}
LuminanceSource source = new PlanarYUVLuminanceSource(data, size.width,
size.height, Symbol.cropX, Symbol.cropY, cropWidth, cropHeight, true);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
DetectorResult detectorResult = null;
try {
detectorResult = new Detector(bitmap.getBlackMatrix()).detect();
ResultPoint[] p = detectorResult.getPoints();
//计算扫描框中的二维码的宽度,两点间距离公式
float point1X = p[0].getX();
float point1Y = p[0].getY();
float point2X = p[1].getX();
float point2Y = p[1].getY();
int len = (int) Math.sqrt(Math.abs(point1X - point2X) * Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y) * Math.abs(point1Y - point2Y));
int minZoomLen = 10;
if (len < cropWidth / 4 && len > minZoomLen) {
cameraZoom(camera);
}
} catch (NotFoundException e) {
e.printStackTrace();
}
}
}
int result = mImageScanner.scanImage(barcode);
String resultStr = null;
int resultType = -1;
if (result != 0) {
SymbolSet symSet = mImageScanner.getResults();
for (Symbol sym : symSet){
resultStr = sym.getData();
resultType= sym.getType();
}
}
if (!TextUtils.isEmpty(resultStr)) {
ScanResult scanResult = new ScanResult();
scanResult.setContent(resultStr);
scanResult.setType(resultType == Symbol.QRCODE ? ScanResult.CODE_QR : ScanResult.CODE_BAR);
Message message = mHandler.obtainMessage();
message.obj = scanResult;
message.sendToTarget();
lastResultTime = System.currentTimeMillis();
if (Symbol.looperScan) {
allowAnalysis = true;
}
} else {
if (Symbol.doubleEngine) {
decode(data, size.width, size.height);
} else {
allowAnalysis = true;
}
}
}
};
/**
* zxing解码
*
* @param data
* @param width
* @param height
*/
private void decode(byte[] data, int width, int height) {
Result rawResult = null;
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; // Here we are swapping, that's the difference to #11
width = height;
height = tmp;
data = rotatedData;
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, 0,
0, width, height, true);
;
Hashtable<DecodeHintType, Object> scanOption = new Hashtable<>();
scanOption.put(DecodeHintType.CHARACTER_SET, "utf-8");
Collection<Reader> readers = new ArrayList<>();
readers.add((new QRCodeReader()));
scanOption.put(DecodeHintType.POSSIBLE_FORMATS,readers);
multiFormatReader.setHints(scanOption);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = multiFormatReader.decodeWithState(bitmap);
String resultStr = rawResult.toString();
BarcodeFormat resultFormat = rawResult.getBarcodeFormat();
if (!TextUtils.isEmpty(resultStr)) {
ScanResult scanResult = new ScanResult();
scanResult.setContent(resultStr);
scanResult.setType(resultFormat == BarcodeFormat.QR_CODE ? ScanResult.CODE_QR : ScanResult.CODE_BAR);
Message message = mHandler.obtainMessage();
message.obj = scanResult;
message.sendToTarget();
lastResultTime = System.currentTimeMillis();
if (Symbol.looperScan) {
allowAnalysis = true;
}
} else allowAnalysis = true;
} catch (ReaderException re) {
allowAnalysis = true;
//Log.i("解码异常",re.toString());
} finally {
multiFormatReader.reset();
}
} else {
allowAnalysis = true;
}
}
}
@@ -0,0 +1,496 @@
package cn.bertsir.zbar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import com.gyf.immersionbar.ImmersionBar;
import com.soundcloud.android.crop.Crop;
import java.io.File;
import cn.bertsir.zbar.Qr.ScanResult;
import cn.bertsir.zbar.Qr.Symbol;
import cn.bertsir.zbar.utils.GetPathFromUri;
import cn.bertsir.zbar.utils.QRUtils;
import cn.bertsir.zbar.view.ScanView;
import cn.bertsir.zbar.view.VerticalSeekBar;
public class QRActivity extends Activity implements View.OnClickListener, SensorEventListener {
private CameraPreview cp;
private SoundPool soundPool;
private ScanView sv;
private ImageView mo_scanner_back;
private ImageView iv_flash;
private ImageView iv_album;
private static final String TAG = "QRActivity";
private TextView textDialog;
private TextView tv_title;
private FrameLayout fl_title;
private TextView tv_des;
private QrConfig options;
static final int REQUEST_IMAGE_GET = 1;
static final int REQUEST_PHOTO_CUT = 2;
public static final int RESULT_CANCELED = 401;
public final float AUTOLIGHTMIN = 10F;
private Uri uricropFile;
private String cropTempPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "cropQr.jpg";
private VerticalSeekBar vsb_zoom;
private AlertDialog progressDialog;
private float oldDist = 1f;
//用于检测光线
private SensorManager sensorManager;
private Sensor sensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
// Log.i("zBarLibary", "version: "+BuildConfig.VERSION_NAME);
options = (QrConfig) getIntent().getExtras().get(QrConfig.EXTRA_THIS_CONFIG);
initParm();
setContentView(R.layout.activity_qr);
initView();
}
/**
* 初始化参数
*/
private void initParm() {
switch (options.getSCREEN_ORIENTATION()) {
case QrConfig.SCREEN_LANDSCAPE:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
break;
case QrConfig.SCREEN_PORTRAIT:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
case QrConfig.SCREEN_SENSOR:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
break;
default:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
break;
}
Symbol.scanType = options.getScan_type();
Symbol.scanFormat = options.getCustombarcodeformat();
Symbol.is_only_scan_center = options.isOnly_center();
Symbol.is_auto_zoom = options.isAuto_zoom();
Symbol.doubleEngine = options.isDouble_engine();
Symbol.looperScan = options.isLoop_scan();
Symbol.looperWaitTime = options.getLoop_wait_time();
Symbol.screenWidth = QRUtils.getInstance().getScreenWidth(this);
Symbol.screenHeight = QRUtils.getInstance().getScreenHeight(this);
if (options.isAuto_light()) {
getSensorManager();
}
}
/**
* 初始化布局
*/
private void initView() {
cp = (CameraPreview) findViewById(R.id.cp);
//bi~
soundPool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
soundPool.load(this, options.getDing_path(), 1);
sv = (ScanView) findViewById(R.id.sv);
sv.setType(options.getScan_view_type());
mo_scanner_back = (ImageView) findViewById(R.id.mo_scanner_back);
mo_scanner_back.setOnClickListener(this);
mo_scanner_back.setImageResource(options.getBackImgRes());
iv_flash = (ImageView) findViewById(R.id.iv_flash);
iv_flash.setOnClickListener(this);
iv_flash.setImageResource(options.getLightImageRes());
iv_album = (ImageView) findViewById(R.id.iv_album);
iv_album.setOnClickListener(this);
iv_album.setImageResource(options.getAblumImageRes());
tv_title = (TextView) findViewById(R.id.tv_title);
fl_title = (FrameLayout) findViewById(R.id.fl_title);
ImmersionBar.with(this).keyboardEnable(true).statusBarDarkFont(true).titleBar(fl_title).init();
tv_des = (TextView) findViewById(R.id.tv_des);
vsb_zoom = (VerticalSeekBar) findViewById(R.id.vsb_zoom);
iv_album.setVisibility(options.isShow_light() ? View.VISIBLE : View.GONE);
fl_title.setVisibility(options.isShow_title() ? View.VISIBLE : View.GONE);
iv_flash.setVisibility(options.isShow_light() ? View.VISIBLE : View.GONE);
iv_album.setVisibility(options.isShow_album() ? View.VISIBLE : View.GONE);
tv_des.setVisibility(options.isShow_des() ? View.VISIBLE : View.GONE);
vsb_zoom.setVisibility(options.isShow_zoom() ? View.VISIBLE : View.GONE);
tv_des.setText(options.getDes_text());
tv_title.setText(options.getTitle_text());
fl_title.setBackgroundColor(options.getTITLE_BACKGROUND_COLOR());
tv_title.setTextColor(options.getTITLE_TEXT_COLOR());
sv.setCornerColor(options.getCORNER_COLOR());
sv.setLineSpeed(options.getLine_speed());
sv.setLineColor(options.getLINE_COLOR());
sv.setScanLineStyle(options.getLine_style());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
setSeekBarColor(vsb_zoom, options.getCORNER_COLOR());
}
vsb_zoom.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
cp.setZoom((progress / 100f));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
/**
* 获取光线传感器
*/
public void getSensorManager() {
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager != null) {
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void setSeekBarColor(SeekBar seekBar, int color) {
seekBar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
seekBar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
/**
* 识别结果回调
*/
private ScanCallback resultCallback = new ScanCallback() {
@Override
public void onScanResult(ScanResult result) {
if (options.isPlay_sound()) {
soundPool.play(1, 1, 1, 0, 0, 1);
}
if (options.isShow_vibrator()) {
QRUtils.getInstance().getVibrator(getApplicationContext());
}
if (cp != null) {
cp.setFlash(false);
}
QrManager.getInstance().getResultCallback().onScanSuccess(result);
if (!Symbol.looperScan) {
finish();
}
}
};
@Override
public void onClick(View v) {
if (v.getId() == R.id.iv_album) {
fromAlbum();
} else if (v.getId() == R.id.iv_flash) {
if (cp != null) {
cp.setFlash();
}
} else if (v.getId() == R.id.mo_scanner_back) {
setResult(RESULT_CANCELED);//兼容混合开发
finish();
}
}
@Override
protected void onResume() {
super.onResume();
if (cp != null) {
cp.setScanCallback(resultCallback);
cp.start();
}
if (sensorManager != null) {
//一般在Resume方法中注册
/**
* 第三个参数决定传感器信息更新速度
* SensorManager.SENSOR_DELAY_NORMAL:一般
* SENSOR_DELAY_FASTEST:最快
* SENSOR_DELAY_GAME:比较快,适合游戏
* SENSOR_DELAY_UI:慢
*/
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
protected void onPause() {
super.onPause();
if (cp != null) {
cp.stop();
}
if (sensorManager != null) {
//解除注册
sensorManager.unregisterListener(this, sensor);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (cp != null) {
cp.setFlash(false);
cp.stop();
}
soundPool.release();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case REQUEST_IMAGE_GET:
if (options.isNeed_crop()) {
cropPhoto(data.getData());
} else {
recognitionLocation(data.getData());
}
break;
case Crop.REQUEST_CROP:
recognitionLocation(uricropFile);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* 从相册选择
*/
private void fromAlbum() {
if (QRUtils.getInstance().isMIUI()) {//是否是小米设备,是的话用到弹窗选取入口的方法去选取
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(Intent.createChooser(intent, options.getOpen_album_text()), REQUEST_IMAGE_GET);
} else {//直接跳到系统相册去选取
Intent intent = new Intent();
if (Build.VERSION.SDK_INT < 19) {
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
} else {
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
}
startActivityForResult(Intent.createChooser(intent, options.getOpen_album_text()), REQUEST_IMAGE_GET);
}
}
/**
* 识别本地
*
* @param uri
*/
private void recognitionLocation(Uri uri) {
final String imagePath = GetPathFromUri.getPath(this, uri);
textDialog = showProgressDialog();
textDialog.setText("请稍后...");
new Thread(new Runnable() {
@Override
public void run() {
try {
if (TextUtils.isEmpty(imagePath)) {
Toast.makeText(getApplicationContext(), "获取图片失败!", Toast.LENGTH_SHORT).show();
return;
}
//优先使用zbar识别一次二维码
final String qrcontent = QRUtils.getInstance().decodeQRcode(imagePath);
runOnUiThread(new Runnable() {
@Override
public void run() {
ScanResult scanResult = new ScanResult();
if (!TextUtils.isEmpty(qrcontent)) {
closeProgressDialog();
scanResult.setContent(qrcontent);
scanResult.setType(ScanResult.CODE_QR);
QrManager.getInstance().getResultCallback().onScanSuccess(scanResult);
QRUtils.getInstance().deleteTempFile(cropTempPath);//删除裁切的临时文件
finish();
} else {
//尝试用zxing再试一次识别二维码
final String qrcontent = QRUtils.getInstance().decodeQRcodeByZxing(imagePath);
if (!TextUtils.isEmpty(qrcontent)) {
closeProgressDialog();
scanResult.setContent(qrcontent);
scanResult.setType(ScanResult.CODE_QR);
QrManager.getInstance().getResultCallback().onScanSuccess(scanResult);
QRUtils.getInstance().deleteTempFile(cropTempPath);//删除裁切的临时文件
finish();
} else {
//再试试是不是条形码
try {
String barcontent = QRUtils.getInstance().decodeBarcode(imagePath);
if (!TextUtils.isEmpty(barcontent)) {
closeProgressDialog();
scanResult.setContent(barcontent);
scanResult.setType(ScanResult.CODE_BAR);
QrManager.getInstance().getResultCallback().onScanSuccess(scanResult);
QRUtils.getInstance().deleteTempFile(cropTempPath);//删除裁切的临时文件
finish();
} else {
Toast.makeText(getApplicationContext(), "识别失败!", Toast.LENGTH_SHORT).show();
closeProgressDialog();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "识别异常!", Toast.LENGTH_SHORT).show();
closeProgressDialog();
e.printStackTrace();
}
}
}
}
});
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "识别异常!", Toast.LENGTH_SHORT).show();
closeProgressDialog();
}
}
}).start();
}
/**
* 裁切照片
*
* @param uri
*/
public void cropPhoto(Uri uri) {
uricropFile = Uri.parse("file://" + "/" + cropTempPath);
Crop.of(uri, uricropFile).asSquare().start(this);
}
public TextView showProgressDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AlertDialogStyle);
builder.setCancelable(false);
View view = View.inflate(this, R.layout.dialog_loading, null);
builder.setView(view);
ProgressBar pb_loading = (ProgressBar) view.findViewById(R.id.pb_loading);
TextView tv_hint = (TextView) view.findViewById(R.id.tv_hint);
if (Build.VERSION.SDK_INT >= 23) {
pb_loading.setIndeterminateTintList(getColorStateList(R.color.dialog_pro_color));
}
progressDialog = builder.create();
progressDialog.show();
return tv_hint;
}
public void closeProgressDialog() {
try {
if (progressDialog != null) {
progressDialog.dismiss();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (options.isFinger_zoom()) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = QRUtils.getInstance().getFingerSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() == 2) {
float newDist = QRUtils.getInstance().getFingerSpacing(event);
if (newDist > oldDist) {
cp.handleZoom(true);
} else if (newDist < oldDist) {
cp.handleZoom(false);
}
oldDist = newDist;
}
break;
}
}
return super.onTouchEvent(event);
}
@Override
public void onSensorChanged(SensorEvent event) {
float light = event.values[0];
if (light < AUTOLIGHTMIN) {//暂定值
if (cp.isPreviewStart()) {
cp.setFlash(true);
sensorManager.unregisterListener(this, sensor);
sensor = null;
sensorManager = null;
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
@@ -0,0 +1,76 @@
/*------------------------------------------------------------------------
* Config
*
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Decoder configuration options.
*/
public class Config {
/**
* Enable symbology/feature.
*/
public static final int ENABLE = 0;
/**
* Enable check digit when optional.
*/
public static final int ADD_CHECK = 1;
/**
* Return check digit when present.
*/
public static final int EMIT_CHECK = 2;
/**
* Enable full ASCII character set.
*/
public static final int ASCII = 3;
/**
* Minimum data length for valid decode.
*/
public static final int MIN_LEN = 0x20;
/**
* Maximum data length for valid decode.
*/
public static final int MAX_LEN = 0x21;
/**
* Required video consistency frames.
*/
public static final int UNCERTAINTY = 0x40;
/**
* Enable scanner to collect position data.
*/
public static final int POSITION = 0x80;
/**
* Image scanner vertical scan density.
*/
public static final int X_DENSITY = 0x100;
/**
* Image scanner horizontal scan density.
*/
public static final int Y_DENSITY = 0x101;
}
@@ -0,0 +1,196 @@
/*------------------------------------------------------------------------
* Image
*
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* stores image data samples along with associated format and size
* metadata.
*/
@SuppressWarnings("JniMissingFunction")
public class Image {
/**
* C pointer to a zbar_symbol_t.
*/
private long peer;
private Object data;
static {
System.loadLibrary("zbar");
init();
}
private static native void init();
public Image() {
peer = create();
}
public Image(int width, int height) {
this();
setSize(width, height);
}
public Image(int width, int height, String format) {
this();
setSize(width, height);
setFormat(format);
}
public Image(String format) {
this();
setFormat(format);
}
Image(long peer) {
this.peer = peer;
}
/**
* Create an associated peer instance.
*/
private native long create();
protected void finalize() {
destroy();
}
/**
* Clean up native data associated with an instance.
*/
public synchronized void destroy() {
if (peer != 0) {
destroy(peer);
peer = 0;
}
}
/**
* Destroy the associated peer instance.
*/
private native void destroy(long peer);
/**
* Image format conversion.
*
* @returns a @em new image with the sample data from the original
* image converted to the requested format fourcc. the original
* image is unaffected.
*/
public Image convert(String format) {
long newpeer = convert(peer, format);
if (newpeer == 0)
return (null);
return (new Image(newpeer));
}
private native long convert(long peer, String format);
/**
* Retrieve the image format fourcc.
*/
public native String getFormat();
/**
* Specify the fourcc image format code for image sample data.
*/
public native void setFormat(String format);
/**
* Retrieve a "sequence" (page/frame) number associated with this
* image.
*/
public native int getSequence();
/**
* Associate a "sequence" (page/frame) number with this image.
*/
public native void setSequence(int seq);
/**
* Retrieve the width of the image.
*/
public native int getWidth();
/**
* Retrieve the height of the image.
*/
public native int getHeight();
/**
* Retrieve the size of the image.
*/
public native int[] getSize();
/**
* Specify the pixel size of the image.
*/
public native void setSize(int width, int height);
/**
* Specify the pixel size of the image.
*/
public native void setSize(int[] size);
/**
* Retrieve the crop region of the image.
*/
public native int[] getCrop();
/**
* Specify the crop region of the image.
*/
public native void setCrop(int x, int y, int width, int height);
/**
* Specify the crop region of the image.
*/
public native void setCrop(int[] crop);
/**
* Retrieve the image sample data.
*/
public native byte[] getData();
/**
* Specify image sample data.
*/
public native void setData(byte[] data);
/**
* Specify image sample data.
*/
public native void setData(int[] data);
/**
* Retrieve the decoded results associated with this image.
*/
public SymbolSet getSymbols() {
return (new SymbolSet(getSymbols(peer)));
}
private native long getSymbols(long peer);
}
@@ -0,0 +1,111 @@
/*------------------------------------------------------------------------
* ImageScanner
*
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Read barcodes from 2-D images.
*/
@SuppressWarnings("JniMissingFunction")
public class ImageScanner {
/**
* C pointer to a zbar_image_scanner_t.
*/
private long peer;
static {
System.loadLibrary("zbar");
init();
}
private static native void init();
public ImageScanner() {
peer = create();
}
/**
* Create an associated peer instance.
*/
private native long create();
protected void finalize() {
destroy();
}
/**
* Clean up native data associated with an instance.
*/
public synchronized void destroy() {
if (peer != 0) {
destroy(peer);
peer = 0;
}
}
/**
* Destroy the associated peer instance.
*/
private native void destroy(long peer);
/**
* Set config for indicated symbology (0 for all) to specified value.
*/
public native void setConfig(int symbology, int config, int value)
throws IllegalArgumentException;
/**
* Parse configuration string and apply to image scanner.
*/
public native void parseConfig(String config);
/**
* Enable or disable the inter-image result cache (default disabled).
* Mostly useful for scanning video frames, the cache filters duplicate
* results from consecutive images, while adding some consistency
* checking and hysteresis to the results. Invoking this method also
* clears the cache.
*/
public native void enableCache(boolean enable);
/**
* Retrieve decode results for last scanned image.
*
* @returns the SymbolSet result container
*/
public SymbolSet getResults() {
return (new SymbolSet(getResults(peer)));
}
private native long getResults(long peer);
/**
* Scan for symbols in provided Image.
* The image format must currently be "Y800" or "GRAY".
*
* @returns the number of symbols successfully decoded from the image.
*/
public native int scanImage(Image image);
}
@@ -0,0 +1,44 @@
/*------------------------------------------------------------------------
* Modifier
*
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Decoder symbology modifiers.
*/
public class Modifier {
/**
* barcode tagged as GS1 (EAN.UCC) reserved
* (eg, FNC1 before first data character).
* data may be parsed as a sequence of GS1 AIs
*/
public static final int GS1 = 0;
/**
* barcode tagged as AIM reserved
* (eg, FNC1 after first character or digit pair)
*/
public static final int AIM = 1;
}
@@ -0,0 +1,52 @@
/*------------------------------------------------------------------------
* Orientation
*
* Copyright 2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Decoded symbol coarse orientation.
*/
public class Orientation {
/**
* Unable to determine orientation.
*/
public static final int UNKNOWN = -1;
/**
* Upright, read left to right.
*/
public static final int UP = 0;
/**
* sideways, read top to bottom
*/
public static final int RIGHT = 1;
/**
* upside-down, read right to left
*/
public static final int DOWN = 2;
/**
* sideways, read bottom to top
*/
public static final int LEFT = 3;
}
@@ -0,0 +1,31 @@
package cn.bertsir.zbar.Qr;
/**
* Created by Bert on 2019-08-19.
* Mail: bertsir@163.com
*/
public class ScanResult {
public String content;
public int type;
public static final int CODE_QR = 1;//二维码
public static final int CODE_BAR = 2;//条形码
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
@@ -0,0 +1,326 @@
/*------------------------------------------------------------------------
* Symbol
*
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Immutable container for decoded result symbols associated with an image
* or a composite symbol.
*/
@SuppressWarnings("JniMissingFunction")
public class Symbol {
/**
* No symbol decoded.
*/
public static final int NONE = 0;
/**
* Symbol detected but not decoded.
*/
public static final int PARTIAL = 1;
/**
* EAN-8.
*/
public static final int EAN8 = 8;
/**
* UPC-E.
*/
public static final int UPCE = 9;
/**
* ISBN-10 (from EAN-13).
*/
public static final int ISBN10 = 10;
/**
* UPC-A.
*/
public static final int UPCA = 12;
/**
* EAN-13.
*/
public static final int EAN13 = 13;
/**
* ISBN-13 (from EAN-13).
*/
public static final int ISBN13 = 14;
/**
* Interleaved 2 of 5.
*/
public static final int I25 = 25;
/**
* DataBar (RSS-14).
*/
public static final int DATABAR = 34;
/**
* DataBar Expanded.
*/
public static final int DATABAR_EXP = 35;
/**
* Codabar.
*/
public static final int CODABAR = 38;
/**
* Code 39.
*/
public static final int CODE39 = 39;
/**
* PDF417.
*/
public static final int PDF417 = 57;
/**
* QR Code.
*/
public static final int QRCODE = 64;
/**
* Code 93.
*/
public static final int CODE93 = 93;
/**
* Code 128.
*/
public static final int CODE128 = 128;
/**
* 裁剪的X轴
*/
public static int cropX = 0;
/**
* 裁剪的Y轴
*/
public static int cropY = 0;
/**
* 裁剪的宽
*/
public static int cropWidth = 0;
/**
* 裁剪的高
*/
public static int cropHeight = 0;
/**
* 屏幕的宽
*/
public static int screenWidth = 0;
/**
* 屏幕的高
*/
public static int screenHeight = 0;
/**
* 识别类型
*/
public static int scanType = 0;//1二维码 2UPCA条形码 3全部类型 4用户指定类型
/**
* 识别码类
*/
public static int scanFormat = 0;
/**
* 是否只识别框中内容
*/
public static boolean is_only_scan_center = false;
/**
* 是否自动拉近
*/
public static boolean is_auto_zoom = false;
/**
* 双识别引擎
*/
public static boolean doubleEngine = false;
/**
* 持续扫描
*/
public static boolean looperScan = false;
/**
* 持续扫描间隔时间
*/
public static int looperWaitTime = 0;
/**
* C pointer to a zbar_symbol_t.
*/
private long peer;
/**
* Cached attributes.
*/
private int type;
static {
System.loadLibrary("zbar");
init();
}
private static native void init();
/**
* Symbols are only created by other package methods.
*/
Symbol(long peer) {
this.peer = peer;
}
protected void finalize() {
destroy();
}
/**
* Clean up native data associated with an instance.
*/
public synchronized void destroy() {
if (peer != 0) {
destroy(peer);
peer = 0;
}
}
/**
* Release the associated peer instance.
*/
private native void destroy(long peer);
/**
* Retrieve type of decoded symbol.
*/
public int getType() {
if (type == 0)
type = getType(peer);
return (type);
}
private native int getType(long peer);
/**
* Retrieve symbology boolean configs settings used during decode.
*/
public native int getConfigMask();
/**
* Retrieve symbology characteristics detected during decode.
*/
public native int getModifierMask();
/**
* Retrieve data decoded from symbol as a String.
*/
public native String getData();
/**
* Retrieve raw data bytes decoded from symbol.
*/
public native byte[] getDataBytes();
/**
* Retrieve a symbol confidence metric. Quality is an unscaled,
* relative quantity: larger values are better than smaller
* values, where "large" and "small" are application dependent.
*/
public native int getQuality();
/**
* Retrieve current cache count. When the cache is enabled for
* the image_scanner this provides inter-frame reliability and
* redundancy information for video streams.
*
* @returns < 0 if symbol is still uncertain
* @returns 0 if symbol is newly verified
* @returns > 0 for duplicate symbols
*/
public native int getCount();
/**
* Retrieve an approximate, axis-aligned bounding box for the
* symbol.
*/
public int[] getBounds() {
int n = getLocationSize(peer);
if (n <= 0)
return (null);
int[] bounds = new int[4];
int xmin = Integer.MAX_VALUE;
int xmax = Integer.MIN_VALUE;
int ymin = Integer.MAX_VALUE;
int ymax = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
int x = getLocationX(peer, i);
if (xmin > x) xmin = x;
if (xmax < x) xmax = x;
int y = getLocationY(peer, i);
if (ymin > y) ymin = y;
if (ymax < y) ymax = y;
}
bounds[0] = xmin;
bounds[1] = ymin;
bounds[2] = xmax - xmin;
bounds[3] = ymax - ymin;
return (bounds);
}
private native int getLocationSize(long peer);
private native int getLocationX(long peer, int idx);
private native int getLocationY(long peer, int idx);
public int[] getLocationPoint(int idx) {
int[] p = new int[2];
p[0] = getLocationX(peer, idx);
p[1] = getLocationY(peer, idx);
return (p);
}
/**
* Retrieve general axis-aligned, orientation of decoded
* symbol.
*/
public native int getOrientation();
/**
* Retrieve components of a composite result.
*/
public SymbolSet getComponents() {
return (new SymbolSet(getComponents(peer)));
}
private native long getComponents(long peer);
native long next();
}
@@ -0,0 +1,76 @@
/*------------------------------------------------------------------------
* SymbolIterator
*
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Iterator over a SymbolSet.
*/
public class SymbolIterator
implements java.util.Iterator<Symbol> {
/**
* Next symbol to be returned by the iterator.
*/
private Symbol current;
/**
* SymbolIterators are only created by internal interface methods.
*/
SymbolIterator(Symbol first) {
current = first;
}
/**
* Returns true if the iteration has more elements.
*/
public boolean hasNext() {
return (current != null);
}
/**
* Retrieves the next element in the iteration.
*/
public Symbol next() {
if (current == null)
throw (new java.util.NoSuchElementException
("access past end of SymbolIterator"));
Symbol result = current;
long sym = current.next();
if (sym != 0)
current = new Symbol(sym);
else
current = null;
return (result);
}
/**
* Raises UnsupportedOperationException.
*/
public void remove() {
throw (new UnsupportedOperationException
("SymbolIterator is immutable"));
}
}
@@ -0,0 +1,93 @@
/*------------------------------------------------------------------------
* SymbolSet
*
* Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
*
* This file is part of the ZBar Bar Code Reader.
*
* The ZBar Bar Code Reader is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* The ZBar Bar Code Reader is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser Public License
* along with the ZBar Bar Code Reader; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*
* http://sourceforge.net/projects/zbar
*------------------------------------------------------------------------*/
package cn.bertsir.zbar.Qr;
/**
* Immutable container for decoded result symbols associated with an image
* or a composite symbol.
*/
@SuppressWarnings("JniMissingFunction")
public class SymbolSet
extends java.util.AbstractCollection<Symbol> {
/**
* C pointer to a zbar_symbol_set_t.
*/
private long peer;
static {
System.loadLibrary("zbar");
init();
}
private static native void init();
/**
* SymbolSets are only created by other package methods.
*/
SymbolSet(long peer) {
this.peer = peer;
}
protected void finalize() {
destroy();
}
/**
* Clean up native data associated with an instance.
*/
public synchronized void destroy() {
if (peer != 0) {
destroy(peer);
peer = 0;
}
}
/**
* Release the associated peer instance.
*/
private native void destroy(long peer);
/**
* Retrieve an iterator over the Symbol elements in this collection.
*/
public java.util.Iterator<Symbol> iterator() {
long sym = firstSymbol(peer);
if (sym == 0)
return (new SymbolIterator(null));
return (new SymbolIterator(new Symbol(sym)));
}
/**
* Retrieve the number of elements in the collection.
*/
public native int size();
/**
* Retrieve C pointer to first symbol in the set.
*/
private native long firstSymbol(long peer);
}
@@ -0,0 +1,445 @@
package cn.bertsir.zbar;
import android.graphics.Color;
import java.io.Serializable;
import androidx.annotation.DrawableRes;
import cn.bertsir.zbar.view.ScanLineView;
/**
* Created by Bert on 2017/9/22.
*/
public class QrConfig implements Serializable {
public static final int LINE_FAST = 1000;
public static final int LINE_MEDIUM = 2000;
public static final int LINE_SLOW = 3000;
public int CORNER_COLOR = Color.parseColor("#ff5f00");
public int LINE_COLOR = Color.parseColor("#ff5f00");
public int TITLE_BACKGROUND_COLOR = Color.parseColor("#ff5f00");
public int TITLE_TEXT_COLOR = Color.parseColor("#ffffff");
public boolean show_title = true;
public boolean show_light = true;
public boolean show_album = true;
public boolean show_des = true;
public boolean need_crop = true;
public boolean show_zoom = false;
public boolean auto_zoom = false;
public boolean finger_zoom = false;
public boolean only_center = false;
public boolean play_sound = true;
public boolean double_engine = false;
public boolean loop_scan = false;
public boolean show_vibrator = false;
public String title_text = "扫描二维码";
public String des_text = "(识别二维码)";
public String open_album_text = "选择要识别的图片";
public int line_speed = LINE_FAST;
public int line_style = ScanLineView.style_hybrid;
public int corner_width = 10;
public int loop_wait_time = 0;
// public int back_img_res = R.drawable.scanner_back_img;
public int back_img_res = R.drawable.top_back;
public int falsh_img_res = R.drawable.scanner_light;
public int album_img_res = R.drawable.scanner_album;
public boolean auto_light = false;
public static int ding_path = R.raw.qrcode;//默认声音
public int custombarcodeformat = -1;
public static final int TYPE_QRCODE = 1;//扫描二维码
public static final int TYPE_BARCODE = 2;//扫描条形码(UPCA
public static final int TYPE_ALL = 3;//扫描全部类型码
public static final int TYPE_CUSTOM = 4;//扫描用户定义类型码
public static final int SCANVIEW_TYPE_QRCODE = 1;//二维码框
public static final int SCANVIEW_TYPE_BARCODE = 2;//条形码框
public static final int SCREEN_PORTRAIT = 1;//屏幕纵向
public static final int SCREEN_LANDSCAPE = 2;//屏幕横向
public static final int SCREEN_SENSOR = 3;//屏幕自动
public int scan_type = TYPE_QRCODE;//默认只扫描二维码
public int scan_view_type = SCANVIEW_TYPE_QRCODE;//默认为二维码扫描框
public final static int REQUEST_CAMERA = 99;
public final static String EXTRA_THIS_CONFIG = "extra_this_config";
public int SCREEN_ORIENTATION = SCREEN_PORTRAIT;
/**
* EAN-8.
*/
public static final int BARCODE_EAN8 = 8;
/**
* UPC-E.
*/
public static final int BARCODE_UPCE = 9;
/**
* ISBN-10 (from EAN-13).
*/
public static final int BARCODE_ISBN10 = 10;
/**
* UPC-A.
*/
public static final int BARCODE_UPCA = 12;
/**
* EAN-13.
*/
public static final int BARCODE_EAN13 = 13;
/**
* ISBN-13 (from EAN-13).
*/
public static final int BARCODE_ISBN13 = 14;
/**
* Interleaved 2 of 5.
*/
public static final int BARCODE_I25 = 25;
/**
* DataBar (RSS-14).
*/
public static final int BARCODE_DATABAR = 34;
/**
* DataBar Expanded.
*/
public static final int BARCODE_DATABAR_EXP = 35;
/**
* Codabar.
*/
public static final int BARCODE_CODABAR = 38;
/**
* Code 39.
*/
public static final int BARCODE_CODE39 = 39;
/**
* PDF417.
*/
public static final int BARCODE_PDF417 = 57;
/**
* Code 93.
*/
public static final int BARCODE_CODE93 = 93;
/**
* Code 128.
*/
public static final int BARCODE_CODE128 = 128;
public int getScan_type() {
return scan_type;
}
public boolean isPlay_sound() {
return play_sound;
}
public int getCORNER_COLOR() {
return CORNER_COLOR;
}
public int getLINE_COLOR() {
return LINE_COLOR;
}
public int getTITLE_BACKGROUND_COLOR() {
return TITLE_BACKGROUND_COLOR;
}
public int getTITLE_TEXT_COLOR() {
return TITLE_TEXT_COLOR;
}
public boolean isShow_title() {
return show_title;
}
public boolean isShow_light() {
return show_light;
}
public boolean isShow_album() {
return show_album;
}
public boolean isShow_des() {
return show_des;
}
public boolean isNeed_crop(){
return need_crop;
}
public String getTitle_text() {
return title_text;
}
public String getDes_text() {
return des_text;
}
public String getOpen_album_text() {
return open_album_text;
}
public int getLine_speed() {
return line_speed;
}
public int getLine_style() {
return line_style;
}
public int getCorner_width() {
return corner_width;
}
public int getCustombarcodeformat() {
return custombarcodeformat;
}
public int getScan_view_type() {
return scan_view_type;
}
public boolean isOnly_center() {
return only_center;
}
public static int getDing_path() {
return ding_path;
}
public boolean isShow_zoom() {
return show_zoom;
}
public boolean isAuto_zoom() {
return auto_zoom;
}
public boolean isFinger_zoom() {
return finger_zoom;
}
public int getSCREEN_ORIENTATION() {
return SCREEN_ORIENTATION;
}
public boolean isDouble_engine() {
return double_engine;
}
public boolean isLoop_scan() {
return loop_scan;
}
public int getLoop_wait_time() {
return loop_wait_time;
}
public boolean isAuto_light() {
return auto_light;
}
public boolean isShow_vibrator() {
return show_vibrator;
}
public int getBackImgRes(){ return back_img_res; }
public int getLightImageRes(){return falsh_img_res;}
public int getAblumImageRes(){ return album_img_res;}
public static class Builder{
private QrConfig watcher;
public Builder(){
watcher = new QrConfig();
}
public Builder setLineSpeed(int speed) {
watcher.line_speed = speed;
return this;
}
public Builder setLineColor(int color){
watcher.LINE_COLOR = color;
return this;
}
public Builder setCornerColor(int color){
watcher.CORNER_COLOR = color;
return this;
}
public Builder setCornerWidth(int dp){
watcher.corner_width = dp;
return this;
}
public Builder setDesText(String text){
watcher.des_text = text;
return this;
}
public Builder setTitleText(String text){
watcher.title_text = text;
return this;
}
public Builder setShowTitle(boolean show){
watcher.show_title = show;
return this;
}
public Builder setShowLight(boolean show){
watcher.show_light = show;
return this;
}
public Builder setShowAlbum(boolean show){
watcher.show_album = show;
return this;
}
public Builder setShowDes(boolean show){
watcher.show_des = show;
return this;
}
public Builder setNeedCrop(boolean crop){
watcher.need_crop = crop;
return this;
}
public Builder setTitleBackgroudColor(int color){
watcher.TITLE_BACKGROUND_COLOR = color;
return this;
}
public Builder setTitleTextColor(int color){
watcher.TITLE_TEXT_COLOR = color;
return this;
}
public Builder setScanType(int type){
watcher.scan_type = type;
return this;
}
public Builder setPlaySound(boolean play){
watcher.play_sound = play;
return this;
}
public Builder setCustombarcodeformat(int format){
watcher.custombarcodeformat = format;
return this;
}
public Builder setScanViewType(int type){
watcher.scan_view_type = type;
return this;
}
public Builder setIsOnlyCenter(boolean isOnlyCenter){
watcher.only_center = isOnlyCenter;
return this;
}
public Builder setDingPath(int ding){
watcher.ding_path = ding;
return this;
}
public Builder setShowZoom(boolean zoom){
watcher.show_zoom = zoom;
return this;
}
public Builder setAutoZoom(boolean auto){
watcher.auto_zoom = auto;
return this;
}
public Builder setFingerZoom(boolean auto){
watcher.finger_zoom = auto;
return this;
}
public Builder setScreenOrientation(int SCREEN_ORIENTATION) {
watcher.SCREEN_ORIENTATION = SCREEN_ORIENTATION;
return this;
}
public Builder setDoubleEngine(boolean open) {
watcher.double_engine = open;
return this;
}
public Builder setOpenAlbumText(String text) {
watcher.open_album_text = text;
return this;
}
public Builder setLooperScan(boolean looper){
watcher.loop_scan = looper;
return this;
}
public Builder setLooperWaitTime(int time){
watcher.loop_wait_time = time;
return this;
}
public Builder setScanLineStyle(int style){
watcher.line_style = style;
return this;
}
public Builder setAutoLight(boolean light){
watcher.auto_light = light;
return this;
}
public Builder setShowVibrator(boolean vibrator){
watcher.show_vibrator = vibrator;
return this;
}
public Builder setBackImageRes(@DrawableRes int res){
watcher.back_img_res = res;
return this;
}
public Builder setLightImageRes(@DrawableRes int res){
watcher.falsh_img_res = res;
return this;
}
public Builder setAblumImageRes(@DrawableRes int res){
watcher.album_img_res = res;
return this;
}
public QrConfig create(){
return watcher;
}
}
}
@@ -0,0 +1,88 @@
package cn.bertsir.zbar;
import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;
import java.util.List;
import cn.bertsir.zbar.Qr.ScanResult;
import cn.bertsir.zbar.utils.PermissionConstants;
import cn.bertsir.zbar.utils.PermissionUtils;
/**
* Created by Bert on 2017/9/22.
*/
public class QrManager {
private static QrManager instance;
private QrConfig options;
public OnScanResultCallback resultCallback;
public synchronized static QrManager getInstance() {
if(instance == null)
instance = new QrManager();
return instance;
}
public OnScanResultCallback getResultCallback() {
return resultCallback;
}
public QrManager init(QrConfig options) {
this.options = options;
return this;
}
public void startScan(final Activity activity, OnScanResultCallback resultCall){
if (options == null) {
options = new QrConfig.Builder().create();
}
PermissionUtils.permission(activity, PermissionConstants.CAMERA,PermissionConstants.STORAGE)
.rationale(new PermissionUtils.OnRationaleListener() {
@Override
public void rationale(final ShouldRequest shouldRequest) {
shouldRequest.again(true);
}
})
.callback(new PermissionUtils.FullCallback() {
@Override
public void onGranted(List<String> permissionsGranted) {
Intent intent = new Intent(activity, QRActivity.class);
intent.putExtra(QrConfig.EXTRA_THIS_CONFIG, options);
activity.startActivity(intent);
}
@Override
public void onDenied(List<String> permissionsDeniedForever,
List<String> permissionsDenied) {
Toast.makeText(activity,"摄像头权限被拒绝!",Toast.LENGTH_SHORT).show();
}
}).request();
// 绑定图片接口回调函数事件
resultCallback = resultCall;
}
public interface OnScanResultCallback {
/**
* 处理成功
* 多选
*
* @param result
*/
void onScanSuccess(ScanResult result);
}
}
@@ -0,0 +1,31 @@
/*
* Copyright © Yan Zhenjie
*
* 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 cn.bertsir.zbar;
import cn.bertsir.zbar.Qr.ScanResult;
/**
* <p>Scan results callback.</p>
*/
public interface ScanCallback {
/**
* 扫描结果回调
*
*/
void onScanResult(ScanResult result);
}
@@ -0,0 +1,133 @@
package cn.bertsir.zbar.utils;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
/**
* Created by Bert on 2018/9/5.
*/
public class GetPathFromUri {
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
@@ -0,0 +1,91 @@
package cn.bertsir.zbar.utils;
import android.Manifest;
import android.Manifest.permission;
import android.annotation.SuppressLint;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2017/12/29
* desc : constants of permission
* </pre>
*/
@SuppressLint("InlinedApi")
public final class PermissionConstants {
public static final String CALENDAR = Manifest.permission_group.CALENDAR;
public static final String CAMERA = Manifest.permission_group.CAMERA;
public static final String CONTACTS = Manifest.permission_group.CONTACTS;
public static final String LOCATION = Manifest.permission_group.LOCATION;
public static final String MICROPHONE = Manifest.permission_group.MICROPHONE;
public static final String PHONE = Manifest.permission_group.PHONE;
public static final String SENSORS = Manifest.permission_group.SENSORS;
public static final String SMS = Manifest.permission_group.SMS;
public static final String STORAGE = Manifest.permission_group.STORAGE;
private static final String[] GROUP_CALENDAR = {
permission.READ_CALENDAR, permission.WRITE_CALENDAR
};
private static final String[] GROUP_CAMERA = {
permission.CAMERA
};
private static final String[] GROUP_CONTACTS = {
permission.READ_CONTACTS, permission.WRITE_CONTACTS, permission.GET_ACCOUNTS
};
private static final String[] GROUP_LOCATION = {
permission.ACCESS_FINE_LOCATION, permission.ACCESS_COARSE_LOCATION
};
private static final String[] GROUP_MICROPHONE = {
permission.RECORD_AUDIO
};
private static final String[] GROUP_PHONE = {
permission.READ_PHONE_STATE, permission.CALL_PHONE
, permission.READ_CALL_LOG, permission.WRITE_CALL_LOG,
permission.ADD_VOICEMAIL, permission.USE_SIP, permission.PROCESS_OUTGOING_CALLS
};
private static final String[] GROUP_SENSORS = {
permission.BODY_SENSORS
};
private static final String[] GROUP_SMS = {
permission.SEND_SMS, permission.RECEIVE_SMS, permission.READ_SMS,
permission.RECEIVE_WAP_PUSH, permission.RECEIVE_MMS,
};
private static final String[] GROUP_STORAGE = {
permission.READ_EXTERNAL_STORAGE, permission.WRITE_EXTERNAL_STORAGE
};
//@StringDef({CALENDAR, CAMERA, CONTACTS, LOCATION, MICROPHONE, PHONE, SENSORS, SMS, STORAGE,})
@Retention(RetentionPolicy.SOURCE)
public @interface Permission {
}
public static String[] getPermissions(@Permission final String permission) {
switch (permission) {
case CALENDAR:
return GROUP_CALENDAR;
case CAMERA:
return GROUP_CAMERA;
case CONTACTS:
return GROUP_CONTACTS;
case LOCATION:
return GROUP_LOCATION;
case MICROPHONE:
return GROUP_MICROPHONE;
case PHONE:
return GROUP_PHONE;
case SENSORS:
return GROUP_SENSORS;
case SMS:
return GROUP_SMS;
case STORAGE:
return GROUP_STORAGE;
}
return new String[]{permission};
}
}
@@ -0,0 +1,369 @@
package cn.bertsir.zbar.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
/**
* <pre>
* author: Blankj
* blog : http://blankj.com
* time : 2017/12/29
* desc : utils about permission
* </pre>
*/
public final class PermissionUtils {
private static List<String> PERMISSIONS = null;
private static PermissionUtils sInstance;
private OnRationaleListener mOnRationaleListener;
private SimpleCallback mSimpleCallback;
private FullCallback mFullCallback;
private ThemeCallback mThemeCallback;
private Set<String> mPermissions;
private List<String> mPermissionsRequest;
private List<String> mPermissionsGranted;
private List<String> mPermissionsDenied;
private List<String> mPermissionsDeniedForever;
private static Context mApp;
/**
* Return the permissions used in application.
*
* @return the permissions used in application
*/
public static List<String> getPermissions() {
return getPermissions(mApp.getPackageName());
}
/**
* Return the permissions used in application.
*
* @param packageName The name of the package.
* @return the permissions used in application
*/
public static List<String> getPermissions(final String packageName) {
PackageManager pm = mApp.getPackageManager();
try {
return Arrays.asList(
pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
.requestedPermissions
);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
/**
* Return whether <em>you</em> have granted the permissions.
*
* @param permissions The permissions.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isGranted(final String... permissions) {
for (String permission : permissions) {
if (!isGranted(permission)) {
return false;
}
}
return true;
}
private static boolean isGranted(final String permission) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|| PackageManager.PERMISSION_GRANTED
== ContextCompat.checkSelfPermission(mApp, permission);
}
/**
* Launch the application's details settings.
*/
public static void launchAppDetailsSettings() {
Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.parse("package:" + mApp.getPackageName()));
mApp.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
/**
* Set the permissions.
*
* @param permissions The permissions.
* @return the single {@link PermissionUtils} instance
*/
public static PermissionUtils permission(Context mContext, @PermissionConstants.Permission final String...
permissions
) {
mApp = mContext;
PERMISSIONS = getPermissions();
return new PermissionUtils(permissions);
}
private PermissionUtils(final String... permissions) {
mPermissions = new LinkedHashSet<>();
for (String permission : permissions) {
for (String aPermission : PermissionConstants.getPermissions(permission)) {
if (PERMISSIONS.contains(aPermission)) {
mPermissions.add(aPermission);
}
}
}
sInstance = this;
}
/**
* Set rationale listener.
*
* @param listener The rationale listener.
* @return the single {@link PermissionUtils} instance
*/
public PermissionUtils rationale(final OnRationaleListener listener) {
mOnRationaleListener = listener;
return this;
}
/**
* Set the simple call back.
*
* @param callback the simple call back
* @return the single {@link PermissionUtils} instance
*/
public PermissionUtils callback(final SimpleCallback callback) {
mSimpleCallback = callback;
return this;
}
/**
* Set the full call back.
*
* @param callback the full call back
* @return the single {@link PermissionUtils} instance
*/
public PermissionUtils callback(final FullCallback callback) {
mFullCallback = callback;
return this;
}
/**
* Set the theme callback.
*
* @param callback The theme callback.
* @return the single {@link PermissionUtils} instance
*/
public PermissionUtils theme(final ThemeCallback callback) {
mThemeCallback = callback;
return this;
}
/**
* Start request.
*/
public void request() {
mPermissionsGranted = new ArrayList<>();
mPermissionsRequest = new ArrayList<>();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mPermissionsGranted.addAll(mPermissions);
requestCallback();
} else {
for (String permission : mPermissions) {
if (isGranted(permission)) {
mPermissionsGranted.add(permission);
} else {
mPermissionsRequest.add(permission);
}
}
if (mPermissionsRequest.isEmpty()) {
requestCallback();
} else {
startPermissionActivity();
}
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void startPermissionActivity() {
mPermissionsDenied = new ArrayList<>();
mPermissionsDeniedForever = new ArrayList<>();
PermissionActivity.start(mApp);
}
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean rationale(final Activity activity) {
boolean isRationale = false;
if (mOnRationaleListener != null) {
for (String permission : mPermissionsRequest) {
if (activity.shouldShowRequestPermissionRationale(permission)) {
getPermissionsStatus(activity);
mOnRationaleListener.rationale(new OnRationaleListener.ShouldRequest() {
@Override
public void again(boolean again) {
if (again) {
startPermissionActivity();
} else {
requestCallback();
}
}
});
isRationale = true;
break;
}
}
mOnRationaleListener = null;
}
return isRationale;
}
private void getPermissionsStatus(final Activity activity) {
for (String permission : mPermissionsRequest) {
if (isGranted(permission)) {
mPermissionsGranted.add(permission);
} else {
mPermissionsDenied.add(permission);
if (!activity.shouldShowRequestPermissionRationale(permission)) {
mPermissionsDeniedForever.add(permission);
}
}
}
}
private void requestCallback() {
if (mSimpleCallback != null) {
if (mPermissionsRequest.size() == 0
|| mPermissions.size() == mPermissionsGranted.size()) {
mSimpleCallback.onGranted();
} else {
if (!mPermissionsDenied.isEmpty()) {
mSimpleCallback.onDenied();
}
}
mSimpleCallback = null;
}
if (mFullCallback != null) {
if (mPermissionsRequest.size() == 0
|| mPermissions.size() == mPermissionsGranted.size()) {
mFullCallback.onGranted(mPermissionsGranted);
} else {
if (!mPermissionsDenied.isEmpty()) {
mFullCallback.onDenied(mPermissionsDeniedForever, mPermissionsDenied);
}
}
mFullCallback = null;
}
mOnRationaleListener = null;
mThemeCallback = null;
}
private void onRequestPermissionsResult(final Activity activity) {
getPermissionsStatus(activity);
requestCallback();
}
@RequiresApi(api = Build.VERSION_CODES.M)
public static class PermissionActivity extends Activity {
public static void start(final Context context) {
Intent starter = new Intent(context, PermissionActivity.class);
starter.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(starter);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
getWindow().setStatusBarColor(Color.TRANSPARENT);
if (sInstance == null) {
super.onCreate(savedInstanceState);
Log.e("PermissionUtils", "request permissions failed");
finish();
return;
}
if (sInstance.mThemeCallback != null) {
sInstance.mThemeCallback.onActivityCreate(this);
}
super.onCreate(savedInstanceState);
if (sInstance.rationale(this)) {
finish();
return;
}
if (sInstance.mPermissionsRequest != null) {
int size = sInstance.mPermissionsRequest.size();
if (size <= 0) {
finish();
return;
}
requestPermissions(sInstance.mPermissionsRequest.toArray(new String[size]), 1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
sInstance.onRequestPermissionsResult(this);
finish();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
finish();
return true;
}
}
///////////////////////////////////////////////////////////////////////////
// interface
///////////////////////////////////////////////////////////////////////////
public interface OnRationaleListener {
void rationale(ShouldRequest shouldRequest);
interface ShouldRequest {
void again(boolean again);
}
}
public interface SimpleCallback {
void onGranted();
void onDenied();
}
public interface FullCallback {
void onGranted(List<String> permissionsGranted);
void onDenied(List<String> permissionsDeniedForever, List<String> permissionsDenied);
}
public interface ThemeCallback {
void onActivityCreate(Activity activity);
}
}
@@ -0,0 +1,670 @@
package cn.bertsir.zbar.utils;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Vibrator;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.File;
import java.util.Hashtable;
import cn.bertsir.zbar.Qr.Config;
import cn.bertsir.zbar.Qr.Image;
import cn.bertsir.zbar.Qr.ImageScanner;
import cn.bertsir.zbar.Qr.Symbol;
import cn.bertsir.zbar.Qr.SymbolSet;
/**
* Created by Bert on 2017/9/20.
*/
public class QRUtils {
private static QRUtils instance;
private Bitmap scanBitmap;
private Context mContext;
public static QRUtils getInstance() {
if (instance == null) {
instance = new QRUtils();
}
return instance;
}
/**
* 识别本地二维码
*
* @param path
* @return
*/
public String decodeQRcode(String path) throws Exception {
//对图片进行灰度处理,为了兼容彩色二维码
Bitmap qrbmp = compressImage(path);
qrbmp = toGrayscale(qrbmp);
if (qrbmp != null) {
return decodeQRcode(qrbmp);
} else {
return "";
}
}
public String decodeQRcode(ImageView iv) throws Exception {
Bitmap qrbmp = ((BitmapDrawable) (iv).getDrawable()).getBitmap();
if (qrbmp != null) {
return decodeQRcode(qrbmp);
} else {
return "";
}
}
public String decodeQRcode(Bitmap barcodeBmp) throws Exception {
int width = barcodeBmp.getWidth();
int height = barcodeBmp.getHeight();
int[] pixels = new int[width * height];
barcodeBmp.getPixels(pixels, 0, width, 0, 0, width, height);
Image barcode = new Image(width, height, "RGB4");
barcode.setData(pixels);
ImageScanner reader = new ImageScanner();
reader.setConfig(Symbol.NONE, Config.ENABLE, 0);
reader.setConfig(Symbol.QRCODE, Config.ENABLE, 1);
int result = reader.scanImage(barcode.convert("Y800"));
String qrCodeString = null;
if (result != 0) {
SymbolSet syms = reader.getResults();
for (Symbol sym : syms) {
qrCodeString = sym.getData();
}
}
barcodeBmp.recycle();
return qrCodeString;
}
/**
* 扫描二维码图片的方法
* @param path
* @return
*/
public String decodeQRcodeByZxing(String path) {
if (TextUtils.isEmpty(path)) {
return null;
}
Hashtable<DecodeHintType, String> hints = new Hashtable();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); // 设置二维码内容的编码
Bitmap scanBitmap = compressImage(path);
int[] data = new int[scanBitmap.getWidth() * scanBitmap.getHeight()];
scanBitmap.getPixels(data, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight());
RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),data);
BinaryBitmap binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(rgbLuminanceSource));
QRCodeReader reader = new QRCodeReader();
Result result = null;
try {
result = reader.decode(binaryBitmap, hints);
} catch (NotFoundException e) {
}catch (ChecksumException e){
}catch(FormatException e){
}
if(result == null){
return "";
}else {
return result.getText();
}
}
/**
* 扫描二维码图片的方法
* @return
*/
public String decodeQRcodeByZxing(Bitmap bitmap) {
Hashtable<DecodeHintType, String> hints = new Hashtable();
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); // 设置二维码内容的编码
scanBitmap =bitmap;
int[] data = new int[scanBitmap.getWidth() * scanBitmap.getHeight()];
scanBitmap.getPixels(data, 0, scanBitmap.getWidth(), 0, 0, scanBitmap.getWidth(), scanBitmap.getHeight());
RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(scanBitmap.getWidth(),scanBitmap.getHeight(),data);
BinaryBitmap binaryBitmap = new BinaryBitmap(new GlobalHistogramBinarizer(rgbLuminanceSource));
QRCodeReader reader = new QRCodeReader();
Result result = null;
try {
result = reader.decode(binaryBitmap, hints);
} catch (NotFoundException e) {
}catch (ChecksumException e){
}catch(FormatException e){
}
if(result == null){
return "";
}else {
return result.getText();
}
}
/**
* 识别本地条形码
*
* @param url
* @return
*/
public String decodeBarcode(String url) {
Bitmap qrbmp = BitmapFactory.decodeFile(url);
if (qrbmp != null) {
return decodeBarcode(qrbmp);
} else {
return "";
}
}
public String decodeBarcode(ImageView iv) {
Bitmap qrbmp = ((BitmapDrawable) (iv).getDrawable()).getBitmap();
if (qrbmp != null) {
return decodeBarcode(qrbmp);
} else {
return "";
}
}
public String decodeBarcode(Bitmap barcodeBmp) {
int width = barcodeBmp.getWidth();
int height = barcodeBmp.getHeight();
int[] pixels = new int[width * height];
barcodeBmp.getPixels(pixels, 0, width, 0, 0, width, height);
Image barcode = new Image(width, height, "RGB4");
barcode.setData(pixels);
ImageScanner reader = new ImageScanner();
reader.setConfig(Symbol.NONE, Config.ENABLE, 0);
reader.setConfig(Symbol.CODE128, Config.ENABLE, 1);
reader.setConfig(Symbol.CODE39, Config.ENABLE, 1);
reader.setConfig(Symbol.EAN13, Config.ENABLE, 1);
reader.setConfig(Symbol.EAN8, Config.ENABLE, 1);
reader.setConfig(Symbol.UPCA, Config.ENABLE, 1);
reader.setConfig(Symbol.UPCE, Config.ENABLE, 1);
int result = reader.scanImage(barcode.convert("Y800"));
String qrCodeString = null;
if (result != 0) {
SymbolSet syms = reader.getResults();
for (Symbol sym : syms) {
qrCodeString = sym.getData();
}
}
return qrCodeString;
}
/**
* 生成二维码
*
* @param content
* @return
*/
public Bitmap createQRCode(String content) {
return createQRCode(content, 300, 300);
}
/**
* 生成二维码
*
* @param content
* @return
*/
public Bitmap createQRCode(String content, int width, int height) {
Bitmap bitmap = null;
BitMatrix result = null;
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
try {
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//这里调整二维码的容错率
hints.put(EncodeHintType.MARGIN, 1); //设置白边取值1-4,值越大白边越大
result = multiFormatWriter.encode(new String(content.getBytes("UTF-8"), "ISO-8859-1"), BarcodeFormat
.QR_CODE, width, height, hints);
int w = result.getWidth();
int h = result.getHeight();
int[] pixels = new int[w * h];
for (int y = 0; y < h; y++) {
int offset = y * w;
for (int x = 0; x < w; x++) {
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
}
}
bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, w, 0, 0, w, h);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
/**
* 生成带logo的二维码
*
* @param content
* @param logo
* @return
*/
public Bitmap createQRCodeAddLogo(String content, Bitmap logo) {
Bitmap qrCode = createQRCode(content);
int qrheight = qrCode.getHeight();
int qrwidth = qrCode.getWidth();
int waterWidth = (int) (qrwidth * 0.3);//0.3为logo占二维码大小的倍数 建议不要过大,否则二维码失效
float scale = waterWidth / (float) logo.getWidth();
Bitmap waterQrcode = createWaterMaskCenter(qrCode, zoomImg(logo, scale));
return waterQrcode;
}
public Bitmap createQRCodeAddLogo(String content, int width, int height, Bitmap logo) {
Bitmap qrCode = createQRCode(content, width, height);
int qrheight = qrCode.getHeight();
int qrwidth = qrCode.getWidth();
int waterWidth = (int) (qrwidth * 0.3);//0.3为logo占二维码大小的倍数 建议不要过大,否则二维码失效
float scale = waterWidth / (float) logo.getWidth();
Bitmap waterQrcode = createWaterMaskCenter(qrCode, zoomImg(logo, scale));
return waterQrcode;
}
/**
* 生成条形码
*
* @param context
* @param contents
* @param desiredWidth
* @param desiredHeight
* @return
*/
@Deprecated
public Bitmap createBarcode(Context context, String contents, int desiredWidth, int desiredHeight) {
if (TextUtils.isEmpty(contents)) {
throw new NullPointerException("contents not be null");
}
if (desiredWidth == 0 || desiredHeight == 0) {
throw new NullPointerException("desiredWidth or desiredHeight not be null");
}
Bitmap resultBitmap;
/**
* 条形码的编码类型
*/
BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128;
resultBitmap = encodeAsBitmap(contents, barcodeFormat,
desiredWidth, desiredHeight);
return resultBitmap;
}
/**
* 生成条形码
*
* @param context
* @param contents
* @param desiredWidth
* @param desiredHeight
* @return
*/
public Bitmap createBarCodeWithText(Context context, String contents, int desiredWidth,
int desiredHeight) {
return createBarCodeWithText(context, contents, desiredWidth, desiredHeight, null);
}
public Bitmap createBarCodeWithText(Context context, String contents, int desiredWidth,
int desiredHeight, TextViewConfig config) {
if (TextUtils.isEmpty(contents)) {
throw new NullPointerException("contents not be null");
}
if (desiredWidth == 0 || desiredHeight == 0) {
throw new NullPointerException("desiredWidth or desiredHeight not be null");
}
Bitmap resultBitmap;
/**
* 条形码的编码类型
*/
BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128;
Bitmap barcodeBitmap = encodeAsBitmap(contents, barcodeFormat,
desiredWidth, desiredHeight);
Bitmap codeBitmap = createCodeBitmap(contents, barcodeBitmap.getWidth(),
barcodeBitmap.getHeight(), context, config);
resultBitmap = mixtureBitmap(barcodeBitmap, codeBitmap, new PointF(
0, desiredHeight));
return resultBitmap;
}
private Bitmap encodeAsBitmap(String contents, BarcodeFormat format, int desiredWidth, int desiredHeight) {
final int WHITE = 0xFFFFFFFF;
final int BLACK = 0xFF000000;
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix result = null;
try {
result = writer.encode(contents, format, desiredWidth,
desiredHeight, null);
} catch (WriterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int width = result.getWidth();
int height = result.getHeight();
int[] pixels = new int[width * height];
// All are 0, or black, by default
for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
private Bitmap createCodeBitmap(String contents, int width, int height, Context context,
TextViewConfig config) {
if (config == null) {
config = new TextViewConfig();
}
TextView tv = new TextView(context);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv.setLayoutParams(layoutParams);
tv.setText(contents);
tv.setTextSize(config.size == 0 ? tv.getTextSize() : config.size);
tv.setHeight(height);
tv.setGravity(config.gravity);
tv.setMaxLines(config.maxLines);
tv.setWidth(width);
tv.setDrawingCacheEnabled(true);
tv.setTextColor(config.color);
tv.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
tv.buildDrawingCache();
return tv.getDrawingCache();
}
public static class TextViewConfig {
private int gravity = Gravity.CENTER;
private int maxLines = 1;
private int color = Color.BLACK;
private float size;
public TextViewConfig() {
}
public void setGravity(int gravity) {
this.gravity = gravity;
}
public void setMaxLines(int maxLines) {
this.maxLines = maxLines;
}
public void setColor(int color) {
this.color = color;
}
public void setSize(float size) {
this.size = size;
}
}
/**
* 将两个Bitmap合并成一个
*
* @param first
* @param second
* @param fromPoint 第二个Bitmap开始绘制的起始位置(相对于第一个Bitmap)
* @return
*/
private Bitmap mixtureBitmap(Bitmap first, Bitmap second, PointF fromPoint) {
if (first == null || second == null || fromPoint == null) {
return null;
}
int width = Math.max(first.getWidth(), second.getWidth());
Bitmap newBitmap = Bitmap.createBitmap(
width,
first.getHeight() + second.getHeight(), Bitmap.Config.ARGB_4444);
Canvas cv = new Canvas(newBitmap);
cv.drawBitmap(first, 0, 0, null);
cv.drawBitmap(second, fromPoint.x, fromPoint.y, null);
cv.save(Canvas.ALL_SAVE_FLAG);
cv.restore();
return newBitmap;
}
/**
* 设置水印图片到中间
*
* @param src
* @param watermark
* @return
*/
private Bitmap createWaterMaskCenter(Bitmap src, Bitmap watermark) {
return createWaterMaskBitmap(src, watermark,
(src.getWidth() - watermark.getWidth()) / 2,
(src.getHeight() - watermark.getHeight()) / 2);
}
private Bitmap createWaterMaskBitmap(Bitmap src, Bitmap watermark, int paddingLeft, int paddingTop) {
if (src == null) {
return null;
}
int width = src.getWidth();
int height = src.getHeight();
Bitmap newb = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);// 创建一个新的和SRC长度宽度一样的位图
Canvas canvas = new Canvas(newb);
canvas.drawBitmap(src, 0, 0, null);
canvas.drawBitmap(watermark, paddingLeft, paddingTop, null);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
return newb;
}
/**
* 缩放Bitmap
*
* @param bm
* @param f
* @return
*/
private Bitmap zoomImg(Bitmap bm, float f) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = f;
float scaleHeight = f;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
return newbm;
}
public boolean isMIUI() {
String manufacturer = Build.MANUFACTURER;
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
return true;
}
return false;
}
/**
* Return the width of screen, in pixel.
*
* @return the width of screen, in pixel
*/
public int getScreenWidth(Context mContext) {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
//noinspection ConstantConditions
wm.getDefaultDisplay().getRealSize(point);
} else {
//noinspection ConstantConditions
wm.getDefaultDisplay().getSize(point);
}
return point.x;
}
/**
* Return the height of screen, in pixel.
*
* @return the height of screen, in pixel
*/
public int getScreenHeight(Context mContext) {
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
//noinspection ConstantConditions
wm.getDefaultDisplay().getRealSize(point);
} else {
//noinspection ConstantConditions
wm.getDefaultDisplay().getSize(point);
}
return point.y;
}
/**
* 返回当前屏幕是否为竖屏。
* @param context
* @return 当且仅当当前屏幕为竖屏时返回true,否则返回false。
*/
public boolean isScreenOriatationPortrait(Context context) {
return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
}
public float getFingerSpacing(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);
}
/**
* 对bitmap进行灰度处理
* @param bmpOriginal
* @return
*/
private Bitmap toGrayscale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
/**
* 压缩图片
* @param path
* @return
*/
private Bitmap compressImage(String path){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true; // 先获取原大小
scanBitmap = BitmapFactory.decodeFile(path,options);
options.inJustDecodeBounds = false;
int sampleSizeH = (int) (options.outHeight / (float) 800);
int sampleSizeW = (int) (options.outWidth / (float) 800);
int sampleSize = Math.max(sampleSizeH,sampleSizeW);
if (sampleSize <= 0) {
sampleSize = 1;
}
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap qrbmp = BitmapFactory.decodeFile(path,options);
return qrbmp;
}
public boolean deleteTempFile(String delFile) {
File file = new File(delFile);
if (file.exists() && file.isFile()) {
if (file.delete()) {
return true;
} else {
return false;
}
} else {
return false;
}
}
//震动提醒
public void getVibrator(Context mContext){
Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {0, 50, 0, 0};
vibrator.vibrate(pattern, -1);
}
}
@@ -0,0 +1,11 @@
package cn.bertsir.zbar.utils;
import androidx.core.content.FileProvider;
/**
* Created by Bert on 2019/3/4.
* Mail: bertsir@163.com
*/
public class QrFileProvider extends FileProvider {
}
@@ -0,0 +1,109 @@
package cn.bertsir.zbar.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import cn.bertsir.zbar.R;
/**
* Created by Bert on 2017/9/22.
*/
public class CornerView extends View {
private Paint paint;//声明画笔
private Canvas canvas;//画布
private static final String TAG = "CornerView";
private int width = 0;
private int height = 0;
private int cornerColor;
private int cornerWidth;
private int cornerGravity;
private static final int LEFT_TOP = 0;
private static final int LEFT_BOTTOM = 1;
private static final int RIGHT_TOP = 2;
private static final int RIGHT_BOTTOM = 3;
public CornerView(Context context) {
super(context,null);
}
public CornerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CornerView);
cornerColor = a.getColor(R.styleable.CornerView_corner_color, getResources().getColor(R.color.common_color));
cornerWidth = (int) a.getDimension(R.styleable.CornerView_corner_width, 10);
cornerGravity = a.getInt(R.styleable.CornerView_corner_gravity, 1);
a.recycle();
paint=new Paint();//创建一个画笔
canvas=new Canvas();
paint.setStyle(Paint.Style.FILL);//设置非填充
paint.setStrokeWidth(cornerWidth);//笔宽5像素
paint.setColor(cornerColor);//设置为红笔
paint.setAntiAlias(true);//锯齿不显示
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (cornerGravity){
case LEFT_TOP:
canvas.drawLine(0, 0, width, 0, paint);
canvas.drawLine(0, 0, 0, height, paint);
break;
case LEFT_BOTTOM:
canvas.drawLine(0, 0, 0, height, paint);
canvas.drawLine(0, height, width, height, paint);
break;
case RIGHT_TOP:
canvas.drawLine(0, 0, width, 0, paint);
canvas.drawLine(width, 0, width, height, paint);
break;
case RIGHT_BOTTOM:
canvas.drawLine(width, 0, width, height, paint);
canvas.drawLine(0, height, width, height, paint);
break;
}
}
public void setColor(int color){
cornerColor = color;
paint.setColor(cornerColor);
invalidate();
}
public void setLineWidth(int dp){
cornerWidth = dip2px(dp);
paint.setStrokeWidth(cornerWidth);
invalidate();
}
public int dip2px(int dp) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5);
}
}
@@ -0,0 +1,61 @@
package cn.bertsir.zbar.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import cn.bertsir.zbar.R;
import static android.R.attr.width;
/**
* Created by Bert on 2017/9/22.
*/
@Deprecated
public class LineView extends View {
private Paint paint;//声明画笔
private Canvas canvas;//画布
private int line_color = getResources().getColor(R.color.common_color);
private Shader mShader;
public LineView(Context context) {
super(context);
}
public LineView(Context context, AttributeSet attrs) {
super(context, attrs);
paint=new Paint();//创建一个画笔
canvas=new Canvas();
paint.setStyle(Paint.Style.FILL);//设置非填充
paint.setStrokeWidth(10);//笔宽5像素
// paint.setColor(line_color);//设置为红笔
paint.setAntiAlias(true);//锯齿不显示
}
public void setLinecolor(int color){
line_color = color;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String line_colors = String.valueOf(Integer.toHexString(line_color));
line_colors = line_colors.substring(line_colors.length() - 6, line_colors.length() - 0);
mShader = new LinearGradient(0,0,getMeasuredWidth(),0,new int[] {Color.parseColor("#00"+line_colors),line_color, Color.parseColor("#00"+line_colors),},null,
Shader.TileMode.CLAMP);
paint.setShader(mShader);
canvas.drawLine(0, 0, width, 0, paint);
}
}
@@ -0,0 +1,285 @@
package cn.bertsir.zbar.view;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import cn.bertsir.zbar.R;
/**
* Created by Bert on 2019-09-16.
* Mail: bertsir@163.com
*/
public class ScanLineView extends View {
private static final String TAG = "ScanView";
public static final int style_gridding = 0;//扫描区域的样式
public static final int style_radar = 1;
public static final int style_hybrid = 2;
public static final int style_line = 3;
private Rect mFrame;//最佳扫描区域的Rect
private Paint mScanPaint_Gridding;//网格样式画笔
private Paint mScanPaint_Radio;//雷达样式画笔
private Paint mScanPaint_Line;//线条样式画笔
private Path mBoundaryLinePath;//边框path
private Path mGriddingPath;//网格样式的path
private LinearGradient mLinearGradient_Radar;//雷达样式的画笔shader
private LinearGradient mLinearGradient_Gridding;//网格画笔的shader
private LinearGradient mLinearGradient_line;
private float mGriddingLineWidth = 4;//网格线的线宽,单位pix
private int mGriddingDensity = 50;//网格样式的,网格密度,值越大越密集
private float mCornerLineLen = 50f;//根据比例计算的边框长度,从四角定点向临近的定点画出的长度
private Matrix mScanMatrix;//变换矩阵,用来实现动画效果
private ValueAnimator mValueAnimator;//值动画,用来变换矩阵操作
private int mScanAnimatorDuration = 1800;//值动画的时长
private int mScancolor;//扫描颜色
private int mScanStyle = style_gridding;//网格 0:网格,1:纵向雷达 2:综合 3:线
private float animatedValue;
public ScanLineView(Context context) {
this(context, null);
}
// This constructor is used when the class is built from an XML resource.
public ScanLineView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScanLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// Initialize these once for performance rather than calling them every time in onDraw().
mScanPaint_Gridding = new Paint(Paint.ANTI_ALIAS_FLAG);
mScanPaint_Gridding.setStyle(Paint.Style.STROKE);
mScanPaint_Gridding.setStrokeWidth(mGriddingLineWidth);
mScanPaint_Radio = new Paint(Paint.ANTI_ALIAS_FLAG);
mScanPaint_Radio.setStyle(Paint.Style.FILL);
Resources resources = getResources();
mScancolor = resources.getColor(R.color.common_color);
mScanPaint_Line=new Paint();//创建一个画笔
mScanPaint_Line.setStyle(Paint.Style.FILL);//设置非填充
mScanPaint_Line.setStrokeWidth(10);//笔宽5像素
mScanPaint_Line.setAntiAlias(true);//锯齿不显示
//变换矩阵,用来处理扫描的上下扫描效果
mScanMatrix = new Matrix();
mScanMatrix.setTranslate(0, 30);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mFrame = new Rect(left,top,right,bottom);
initBoundaryAndAnimator();
}
private void initBoundaryAndAnimator() {
if (mBoundaryLinePath == null) {
mBoundaryLinePath = new Path();
mBoundaryLinePath.moveTo(mFrame.left, mFrame.top + mCornerLineLen);
mBoundaryLinePath.lineTo(mFrame.left, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.left + mCornerLineLen, mFrame.top);
mBoundaryLinePath.moveTo(mFrame.right - mCornerLineLen, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.top);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.top + mCornerLineLen);
mBoundaryLinePath.moveTo(mFrame.right, mFrame.bottom - mCornerLineLen);
mBoundaryLinePath.lineTo(mFrame.right, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.right - mCornerLineLen, mFrame.bottom);
mBoundaryLinePath.moveTo(mFrame.left + mCornerLineLen, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom);
mBoundaryLinePath.lineTo(mFrame.left, mFrame.bottom - mCornerLineLen);
}
if (mValueAnimator == null) {
initScanValueAnim(mFrame.height());
}
}
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
if (mFrame == null||mBoundaryLinePath==null) {
return;
}
switch (mScanStyle) {
case style_gridding:
initGriddingPathAndStyle();
canvas.drawPath(mGriddingPath, mScanPaint_Gridding);
break;
case style_radar:
initRadarStyle();
canvas.drawRect(mFrame, mScanPaint_Radio);
break;
case style_line:
initLineStyle();
canvas.drawLine(0,(mFrame.height()- Math.abs(animatedValue)),getMeasuredWidth(),
(mFrame.height()- Math.abs(animatedValue)), mScanPaint_Line);
break;
case style_hybrid:
default:
initGriddingPathAndStyle();
initRadarStyle();
canvas.drawPath(mGriddingPath, mScanPaint_Gridding);
canvas.drawRect(mFrame, mScanPaint_Radio);
break;
}
}
private void initRadarStyle() {
if (mLinearGradient_Radar == null) {
mLinearGradient_Radar = new LinearGradient(0, mFrame.top, 0, mFrame.bottom + 0.01f * mFrame.height(),
new int[]{Color.TRANSPARENT, Color.TRANSPARENT, mScancolor, Color.TRANSPARENT}, new float[]{0, 0.85f, 0.99f, 1f}, LinearGradient.TileMode.CLAMP);
mLinearGradient_Radar.setLocalMatrix(mScanMatrix);
mScanPaint_Radio.setShader(mLinearGradient_Radar);
}
}
private void initLineStyle() {
if (mLinearGradient_line == null) {
String line_colors = String.valueOf(Integer.toHexString(mScancolor));
line_colors = line_colors.substring(line_colors.length() - 6, line_colors.length() - 0);
mLinearGradient_line = new LinearGradient(0,0,getMeasuredWidth(),0,new int[] {Color.parseColor("#00"+line_colors),
mScancolor, Color.parseColor("#00"+line_colors),},null, Shader.TileMode.CLAMP);
mLinearGradient_line.setLocalMatrix(mScanMatrix);
mScanPaint_Line.setShader(mLinearGradient_line);
}
}
private void initGriddingPathAndStyle() {
if (mGriddingPath == null) {
mGriddingPath = new Path();
float wUnit = mFrame.width() / (mGriddingDensity + 0f);
float hUnit = mFrame.height() / (mGriddingDensity + 0f);
for (int i = 0; i <= mGriddingDensity; i++) {
mGriddingPath.moveTo(mFrame.left + i * wUnit, mFrame.top);
mGriddingPath.lineTo(mFrame.left + i * wUnit, mFrame.bottom);
}
for (int i = 0; i <= mGriddingDensity; i++) {
mGriddingPath.moveTo(mFrame.left, mFrame.top + i * hUnit);
mGriddingPath.lineTo(mFrame.right, mFrame.top + i * hUnit);
}
}
if (mLinearGradient_Gridding == null) {
mLinearGradient_Gridding = new LinearGradient(0, mFrame.top, 0, mFrame.bottom + 0.01f * mFrame.height(), new int[]{Color.TRANSPARENT, Color.TRANSPARENT, mScancolor, Color.TRANSPARENT}, new float[]{0, 0.5f, 0.99f, 1f}, LinearGradient.TileMode.CLAMP);
mLinearGradient_Gridding.setLocalMatrix(mScanMatrix);
mScanPaint_Gridding.setShader(mLinearGradient_Gridding);
}
}
public void initScanValueAnim(int height) {
mValueAnimator = new ValueAnimator();
mValueAnimator.setDuration(mScanAnimatorDuration);
mValueAnimator.setFloatValues(-height, 0);
mValueAnimator.setRepeatMode(ValueAnimator.RESTART);
mValueAnimator.setInterpolator(new DecelerateInterpolator());
mValueAnimator.setRepeatCount(Animation.INFINITE);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if(mLinearGradient_Gridding == null){
initGriddingPathAndStyle();
}
if(mLinearGradient_Radar == null){
initRadarStyle();
}
if(mLinearGradient_line == null){
initLineStyle();
}
if (mScanMatrix != null ) {
animatedValue = (float) animation.getAnimatedValue();
mScanMatrix.setTranslate(0, animatedValue);
mLinearGradient_Gridding.setLocalMatrix(mScanMatrix);
mLinearGradient_Radar.setLocalMatrix(mScanMatrix);
mLinearGradient_line.setLocalMatrix(mScanMatrix);
//mScanPaint.setShader(mLinearGradient); //不是必须的设置到shader即可
invalidate();
}
}
});
mValueAnimator.start();
}
@Override
protected void onDetachedFromWindow() {
if (mValueAnimator != null && mValueAnimator.isRunning()) {
mValueAnimator.cancel();
}
super.onDetachedFromWindow();
}
//设定扫描的颜色
public void setScancolor(int colorValue) {
this.mScancolor = colorValue;
}
public void setScanAnimatorDuration(int duration) {
this.mScanAnimatorDuration = duration;
}
/*
* @description 扫描区域的样式
* @scanStyle
*
* */
public void setScanStyle(int scanStyle) {
this.mScanStyle = scanStyle;
}
/*
* 扫描区域网格的样式
* @params strokeWidth:网格的线宽
* @params density:网格的密度
* */
public void setScanGriddingStyle(float strokeWidh, int density) {
this.mGriddingLineWidth = strokeWidh;
this.mGriddingDensity = density;
}
}
@@ -0,0 +1,134 @@
package cn.bertsir.zbar.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.gyf.immersionbar.ImmersionBar;
import java.util.ArrayList;
import cn.bertsir.zbar.Qr.Symbol;
import cn.bertsir.zbar.QrConfig;
import cn.bertsir.zbar.R;
/**
* Created by Bert on 2017/9/20.
*/
public class ScanView extends FrameLayout {
private ScanLineView iv_scan_line;
private FrameLayout fl_scan;
private int CURRENT_TYEP = 1;
private CornerView cnv_left_top;
private CornerView cnv_left_bottom;
private CornerView cnv_right_top;
private CornerView cnv_right_bottom;
private ArrayList<CornerView> cornerViews;
private int line_speed = 3000;
public ScanView(Context context) {
super(context);
initView(context);
}
public ScanView(Context context,AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public ScanView(Context context,AttributeSet attrs,int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context mContext){
View scan_view = View.inflate(mContext, R.layout.view_scan, this);
cnv_left_top = (CornerView) scan_view.findViewById(R.id.cnv_left_top);
cnv_left_bottom = (CornerView) scan_view.findViewById(R.id.cnv_left_bottom);
cnv_right_top = (CornerView) scan_view.findViewById(R.id.cnv_right_top);
cnv_right_bottom = (CornerView) scan_view.findViewById(R.id.cnv_right_bottom);
cornerViews = new ArrayList<>();
cornerViews.add(cnv_left_top);
cornerViews.add(cnv_left_bottom);
cornerViews.add(cnv_right_top);
cornerViews.add(cnv_right_bottom);
iv_scan_line = (ScanLineView) scan_view.findViewById(R.id.iv_scan_line);
fl_scan = (FrameLayout) scan_view.findViewById(R.id.fl_scan);
getViewWidthHeight();
}
/**
* 设置扫描速度
* @param speed
*/
public void setLineSpeed(int speed){
iv_scan_line.setScanAnimatorDuration(speed);
}
/**
* 设置扫描样式
*/
public void setScanLineStyle(int style){
iv_scan_line.setScanStyle(style);
}
public void setType(int type){
CURRENT_TYEP = type;
LinearLayout.LayoutParams fl_params = (LinearLayout.LayoutParams) fl_scan.getLayoutParams();
if(CURRENT_TYEP == QrConfig.SCANVIEW_TYPE_QRCODE){
fl_params.width = dip2px(200);
fl_params.height = dip2px(200);
}else if(CURRENT_TYEP == QrConfig.SCANVIEW_TYPE_BARCODE){
fl_params.width = dip2px(300);
fl_params.height = dip2px(100);
}
fl_scan.setLayoutParams(fl_params);
}
public void setCornerColor(int color){
for (int i = 0; i < cornerViews.size(); i++) {
cornerViews.get(i).setColor(color);
}
}
public void setCornerWidth(int dp){
for (int i = 0; i < cornerViews.size(); i++) {
cornerViews.get(i).setLineWidth(dp);
}
}
public void setLineColor(int color){
iv_scan_line.setScancolor(color);
}
public int dip2px(int dp) {
float density = getContext().getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5);
}
public void getViewWidthHeight(){
fl_scan.post(new Runnable() {
@Override
public void run() {
Symbol.cropWidth = fl_scan.getWidth();
Symbol.cropHeight = fl_scan.getHeight();
}
});
}
}
@@ -0,0 +1,104 @@
package cn.bertsir.zbar.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.SeekBar;
import cn.bertsir.zbar.R;
/**
* Created by Bert on 2019/3/1.
* Mail: bertsir@163.com
*/
public class VerticalSeekBar extends SeekBar {
private static final String TAG = VerticalSeekBar.class.getSimpleName();
public static final int ROTATION_ANGLE_CW_90 = 90;
public static final int ROTATION_ANGLE_CW_270 = 270;
private int mRotationAngle = ROTATION_ANGLE_CW_90;
public VerticalSeekBar(Context context) {
super(context);//注意是super 而不是调用其他构造函数
initialize(context, null, 0, 0);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs, 0, 0);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize(context, attrs, defStyle, 0);
}
private void initialize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, defStyleRes);
final int rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0);
if (isValidRotationAngle(rotationAngle)) {
mRotationAngle = rotationAngle;
}
a.recycle();
}
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
if (mRotationAngle == ROTATION_ANGLE_CW_270) {
//从下到上
c.rotate(270);
c.translate(-getHeight(), 0);
} else if (mRotationAngle == ROTATION_ANGLE_CW_90) {
//从上到下
c.rotate(90);
c.translate(0, -getWidth());
}
super.onDraw(c);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
if (mRotationAngle == ROTATION_ANGLE_CW_270) {
//从下到上
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
} else if (mRotationAngle == ROTATION_ANGLE_CW_90) {
//从上到下
setProgress((int) (getMax() * event.getY() / getHeight()));
}
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
private static boolean isValidRotationAngle(int angle) {
return (angle == ROTATION_ANGLE_CW_90 || angle == ROTATION_ANGLE_CW_270);
}
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/white"/>
</selector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- 填充的颜色 -->
<solid android:color="#c1333333" />
<!-- 设置按钮的四个角为弧形 -->
<!-- android:radius 弧形的半径 -->
<corners android:radius="360dip" />
<!-- padding: Button 里面的文字与Button边界的间隔 -->
<padding
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp"
/>
</shape>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#c1333333" />
<corners android:radius="5dip" />
</shape>
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- 二维码识别界面 -->
<cn.bertsir.zbar.CameraPreview
android:id="@+id/cp"
android:layout_width="match_parent"
android:layout_height="match_parent"></cn.bertsir.zbar.CameraPreview>
<cn.bertsir.zbar.view.ScanView
android:id="@+id/sv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/fl_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFEFEFEF"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="bottom"
>
<ImageView
android:id="@+id/mo_scanner_back"
android:layout_width="50dp"
android:layout_height="50dp"
android:padding="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/top_back" />
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:text="扫描二维码"
android:layout_gravity="center"
android:gravity="center"
android:textSize="20sp"
/>
</FrameLayout>
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="center"
android:layout_marginTop="50dp"
>
<TextView
android:id="@+id/tv_des"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:text="扫一扫"
android:textColor="#ffffffff"
android:textSize="15sp" />
</LinearLayout>
<ImageView
android:id="@+id/iv_flash"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/circle_trans_black"
android:src="@drawable/scanner_light"
android:padding="5dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="70dp"
android:layout_marginRight="10dp"
/>
<ImageView
android:id="@+id/iv_album"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/circle_trans_black"
android:src="@drawable/scanner_album"
android:padding="5dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="20dp"
android:layout_marginRight="10dp"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="30dp"
>
<cn.bertsir.zbar.view.VerticalSeekBar
android:id="@+id/vsb_zoom"
android:layout_width="wrap_content"
android:layout_height="200dp"
app:seekBarRotation ="CW270"
/>
</LinearLayout>
</FrameLayout>
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_dialog_bg"
android:orientation="vertical"
android:gravity="center"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_margin="30dp"
>
<ProgressBar
android:id="@+id/pb_loading"
android:layout_width="40dp"
android:layout_height="40dp"
/>
<TextView
android:id="@+id/tv_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textSize="14sp"
android:textColor="#fff"
android:text="请稍后..."
android:layout_marginTop="10dp"
/>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 扫描动画 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="160dp"
android:src="@drawable/shadow"
android:scaleType="fitXY"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/shadow"
android:layout_weight="1"
android:scaleType="fitXY"
/>
<FrameLayout
android:id="@+id/fl_scan"
android:layout_width="@dimen/scan_frame_width"
android:layout_height="@dimen/scan_frame_width"
android:layout_gravity="center_horizontal"
android:background="@drawable/capture1"
>
<cn.bertsir.zbar.view.CornerView
android:id="@+id/cnv_left_top"
android:layout_width="20dp"
android:layout_height="20dp"
app:corner_width="5dp"
android:visibility="gone"
app:corner_gravity="leftTop"
/>
<cn.bertsir.zbar.view.CornerView
android:id="@+id/cnv_left_bottom"
android:layout_width="20dp"
android:layout_height="20dp"
app:corner_width="5dp"
android:visibility="gone"
app:corner_gravity="leftBottom"
android:layout_gravity="bottom|left"
/>
<cn.bertsir.zbar.view.CornerView
android:id="@+id/cnv_right_top"
android:layout_width="20dp"
android:layout_height="20dp"
app:corner_width="5dp"
android:visibility="gone"
app:corner_gravity="rightTop"
android:layout_gravity="right|top"
/>
<cn.bertsir.zbar.view.CornerView
android:id="@+id/cnv_right_bottom"
android:layout_width="20dp"
android:layout_height="20dp"
app:corner_width="5dp"
android:visibility="gone"
app:corner_gravity="rightBottom"
android:layout_gravity="right|bottom"
/>
<cn.bertsir.zbar.view.ScanLineView
android:id="@+id/iv_scan_line"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/shadow"
android:layout_weight="1"
android:scaleType="fitXY"
/>
</LinearLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scaleType="fitXY"
android:src="@drawable/shadow"
/>
</LinearLayout>
</LinearLayout>
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CornerView">
<attr name="corner_color" format="color" />
<attr name="corner_width" format="dimension" />
<attr name="corner_gravity" format="enum">
<enum name="leftBottom" value="1" />
<enum name="rightBottom" value="3" />
<enum name="leftTop" value="0" />
<enum name="rightTop" value="2" />
</attr>
</declare-styleable>
<declare-styleable name="VerticalSeekBar">
<attr name="seekBarRotation">
<enum name="CW90" value="90" />
<enum name="CW270" value="270" />
</attr>
</declare-styleable>
</resources>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="common_color">#ff5f00</color>
</resources>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="scan_frame_width">200dp</dimen>
</resources>
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">zBarLibary</string>
</resources>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AlertDialogStyle" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowFrame">@null</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<style name="ActivityTranslucent">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:activityOpenEnterAnimation">@null</item>
<item name="android:activityOpenExitAnimation">@null</item>
<item name="android:activityCloseEnterAnimation">@null</item>
<item name="android:activityCloseExitAnimation">@null</item>
</style>
</resources>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="camera_photos"
path="." />
</paths>