Repository: liang530/ScanCode
Branch: master
Commit: 404dbb4ca783
Files: 74
Total size: 127.1 KB
Directory structure:
gitextract_qo_l_5id/
├── .gitignore
├── .idea/
│ ├── .name
│ ├── compiler.xml
│ ├── copyright/
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── README.md
├── ScanCode.iml
├── app/
│ ├── .gitignore
│ ├── app.iml
│ ├── build.gradle
│ ├── libs/
│ │ ├── butterknife-7.0.1.jar
│ │ └── zxing.jar
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── com/
│ │ └── liang/
│ │ └── scancode/
│ │ ├── CommonScanActivity.java
│ │ ├── CreateCodeActivity.java
│ │ ├── MainActivity.java
│ │ ├── defineview/
│ │ │ └── MyImageView.java
│ │ ├── utils/
│ │ │ └── Constant.java
│ │ └── zxing/
│ │ ├── ScanListener.java
│ │ ├── ScanManager.java
│ │ ├── camera/
│ │ │ ├── AutoFocusManager.java
│ │ │ ├── CameraConfigurationManager.java
│ │ │ ├── CameraManager.java
│ │ │ ├── PreviewCallback.java
│ │ │ └── open/
│ │ │ └── OpenCameraInterface.java
│ │ ├── decode/
│ │ │ ├── DecodeFormatManager.java
│ │ │ ├── DecodeHandler.java
│ │ │ ├── DecodeThread.java
│ │ │ ├── PhotoScanHandler.java
│ │ │ ├── RGBLuminanceSource.java
│ │ │ └── Utils.java
│ │ ├── encode/
│ │ │ └── EncodingHandler.java
│ │ └── utils/
│ │ ├── AppliationUtil.java
│ │ ├── BeepManager.java
│ │ ├── BitmapUtil.java
│ │ ├── CaptureActivityHandler.java
│ │ └── InactivityTimer.java
│ └── res/
│ ├── anim/
│ │ ├── popupwin_nearperson_exit.xml
│ │ ├── popupwin_nearperson_show.xml
│ │ ├── shouquan_dialog_enter.xml
│ │ └── shouquan_dialog_exit.xml
│ ├── drawable/
│ │ ├── base_bgpic.xml
│ │ ├── rescan_shape_button.xml
│ │ ├── shouquan_bg_loading_dialog_shape.xml
│ │ ├── shouquan_loading_dialog_progressbar.xml
│ │ ├── shouquan_qrcode_g_gallery.xml
│ │ ├── shouquan_qrcode_ic_back.xml
│ │ └── shouquan_qrcode_s_flashgun.xml
│ ├── layout/
│ │ ├── activity_create_code.xml
│ │ ├── activity_main.xml
│ │ ├── activity_scan_code.xml
│ │ └── activity_scan_result.xml
│ ├── menu/
│ │ ├── menu_jump_to.xml
│ │ └── menu_sao_mao.xml
│ ├── raw/
│ │ └── beep.ogg
│ ├── values/
│ │ ├── Qrcode_ids.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── values-w820dp/
│ └── dimens.xml
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
### Android template
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
================================================
FILE: .idea/.name
================================================
ScanCode
================================================
FILE: .idea/compiler.xml
================================================
================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
================================================
FILE: .idea/encodings.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/modules.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: README.md
================================================
# ScanCode
使用zxing封装的android扫描全功能系列,包括二维码扫描,条形码扫描,二维码生成,条形码生成,从图片中扫描二维码或者条形码,闪光灯控制。
优点:
1.该有的功能一个都不少!
2.扫描界面布局xml完成,可自行订制!
3.不乱码,不变形!
4.扫描后可得到扫描的截图!
5.支持连续扫描!
6.在一个项目中可多处使用,根据CommonScanActivity在多写一个自己的扫描界面就行了!
#项目截图






================================================
FILE: ScanCode.iml
================================================
================================================
FILE: app/.gitignore
================================================
### Android template
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
/build
================================================
FILE: app/app.iml
================================================
generateDebugAndroidTestSources
generateDebugSources
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.liang.scancode"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/hongliang/android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class goodsid to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/java/com/liang/scancode/CommonScanActivity.java
================================================
/*
* Copyright (C) 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liang.scancode;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.Result;
import butterknife.ButterKnife;
import butterknife.Bind;
import com.liang.scancode.utils.Constant;
import com.liang.scancode.zxing.ScanListener;
import com.liang.scancode.zxing.ScanManager;
import com.liang.scancode.zxing.decode.DecodeThread;
import com.liang.scancode.zxing.decode.Utils;
/**
* 二维码扫描使用
*
* @author 刘红亮 2015年4月29日 下午5:49:45
*/
public final class CommonScanActivity extends Activity implements ScanListener, View.OnClickListener {
static final String TAG = CommonScanActivity.class.getSimpleName();
SurfaceView scanPreview = null;
View scanContainer;
View scanCropView;
ImageView scanLine;
ScanManager scanManager;
TextView iv_light;
TextView qrcode_g_gallery;
TextView qrcode_ic_back;
final int PHOTOREQUESTCODE = 1111;
@Bind(R.id.service_register_rescan)
Button rescan;
@Bind(R.id.scan_image)
ImageView scan_image;
@Bind(R.id.authorize_return)
ImageView authorize_return;
private int scanMode;//扫描模型(条形,二维码,全部)
@Bind(R.id.common_title_TV_center)
TextView title;
@Bind(R.id.scan_hint)
TextView scan_hint;
@Bind(R.id.tv_scan_result)
TextView tv_scan_result;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_scan_code);
ButterKnife.bind(this);
scanMode=getIntent().getIntExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_ALL_MODE);
initView();
}
void initView() {
switch (scanMode){
case DecodeThread.BARCODE_MODE:
title.setText(R.string.scan_barcode_title);
scan_hint.setText(R.string.scan_barcode_hint);
break;
case DecodeThread.QRCODE_MODE:
title.setText(R.string.scan_qrcode_title);
scan_hint.setText(R.string.scan_qrcode_hint);
break;
case DecodeThread.ALL_MODE:
title.setText(R.string.scan_allcode_title);
scan_hint.setText(R.string.scan_allcode_hint);
break;
}
scanPreview = (SurfaceView) findViewById(R.id.capture_preview);
scanContainer = findViewById(R.id.capture_container);
scanCropView = findViewById(R.id.capture_crop_view);
scanLine = (ImageView) findViewById(R.id.capture_scan_line);
qrcode_g_gallery = (TextView) findViewById(R.id.qrcode_g_gallery);
qrcode_g_gallery.setOnClickListener(this);
qrcode_ic_back = (TextView) findViewById(R.id.qrcode_ic_back);
qrcode_ic_back.setOnClickListener(this);
iv_light = (TextView) findViewById(R.id.iv_light);
iv_light.setOnClickListener(this);
rescan.setOnClickListener(this);
authorize_return.setOnClickListener(this);
//构造出扫描管理器
scanManager = new ScanManager(this, scanPreview, scanContainer, scanCropView, scanLine, scanMode,this);
}
@Override
public void onResume() {
super.onResume();
scanManager.onResume();
rescan.setVisibility(View.INVISIBLE);
scan_image.setVisibility(View.GONE);
}
@Override
public void onPause() {
super.onPause();
scanManager.onPause();
}
/**
*
*/
public void scanResult(Result rawResult, Bundle bundle) {
//扫描成功后,扫描器不会再连续扫描,如需连续扫描,调用reScan()方法。
//scanManager.reScan();
// Toast.makeText(that, "result="+rawResult.getText(), Toast.LENGTH_LONG).show();
if (!scanManager.isScanning()) { //如果当前不是在扫描状态
//设置再次扫描按钮出现
rescan.setVisibility(View.VISIBLE);
scan_image.setVisibility(View.VISIBLE);
Bitmap barcode = null;
byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
if (compressedBitmap != null) {
barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
}
scan_image.setImageBitmap(barcode);
}
rescan.setVisibility(View.VISIBLE);
scan_image.setVisibility(View.VISIBLE);
tv_scan_result.setVisibility(View.VISIBLE);
tv_scan_result.setText("结果:"+rawResult.getText());
}
void startScan() {
if (rescan.getVisibility() == View.VISIBLE) {
rescan.setVisibility(View.INVISIBLE);
scan_image.setVisibility(View.GONE);
scanManager.reScan();
}
}
@Override
public void scanError(Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
//相机扫描出错时
if(e.getMessage()!=null&&e.getMessage().startsWith("相机")){
scanPreview.setVisibility(View.INVISIBLE);
}
}
public void showPictures(int requestCode) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, requestCode);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
String photo_path;
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PHOTOREQUESTCODE:
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = this.getContentResolver().query(data.getData(), proj, null, null, null);
if (cursor.moveToFirst()) {
int colum_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
photo_path = cursor.getString(colum_index);
if (photo_path == null) {
photo_path = Utils.getPath(getApplicationContext(), data.getData());
}
scanManager.scanningImage(photo_path);
}
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.qrcode_g_gallery:
showPictures(PHOTOREQUESTCODE);
break;
case R.id.iv_light:
scanManager.switchLight();
break;
case R.id.qrcode_ic_back:
finish();
break;
case R.id.service_register_rescan://再次开启扫描
startScan();
break;
case R.id.authorize_return:
finish();
break;
default:
break;
}
}
}
================================================
FILE: app/src/main/java/com/liang/scancode/CreateCodeActivity.java
================================================
package com.liang.scancode;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.google.zxing.WriterException;
import java.io.UnsupportedEncodingException;
import butterknife.ButterKnife;
import butterknife.Bind;
import butterknife.OnClick;
import com.liang.scancode.zxing.encode.EncodingHandler;
/**
* Created by 刘红亮 on 2015/9/24 14:37.
*/
public class CreateCodeActivity extends Activity {
@Bind(R.id.et_code_key)
EditText etCodeKey;
@Bind(R.id.btn_create_code)
Button btnCreateCode;
@Bind(R.id.iv_2_code)
ImageView iv2Code;
@Bind(R.id.iv_bar_code)
ImageView ivBarCode;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_code);
ButterKnife.bind(this);
}
@OnClick({R.id.btn_create_code,R.id.btn_create_code_and_img})
public void clickListener(View view){
String key=etCodeKey.getText().toString();
switch (view.getId()){
case R.id.btn_create_code: //生成码
if(TextUtils.isEmpty(key)){
Toast.makeText(this,"请输入内容",Toast.LENGTH_SHORT).show();
}else{
create2Code(key);
createBarCode(key);
}
break;
case R.id.btn_create_code_and_img: //生成码
Bitmap bitmap = create2Code(key);
Bitmap headBitmap = getHeadBitmap(60);
if(bitmap!=null&&headBitmap!=null){
createQRCodeBitmapWithPortrait(bitmap,headBitmap);
}
break;
}
}
private Bitmap createBarCode(String key) {
Bitmap qrCode = null;
try {
qrCode = EncodingHandler.createBarCode(key, 600, 300);
ivBarCode.setImageBitmap(qrCode);
} catch (Exception e) {
Toast.makeText(this,"输入的内容条形码不支持!",Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
return qrCode;
}
/**
* 生成二维码
* @param key
*/
private Bitmap create2Code(String key) {
Bitmap qrCode=null;
try {
qrCode= EncodingHandler.create2Code(key, 400);
iv2Code.setImageBitmap(qrCode);
} catch (WriterException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return qrCode;
}
/**
* 初始化头像图片
*/
private Bitmap getHeadBitmap(int size) {
try {
// 这里采用从asset中加载图片abc.jpg
Bitmap portrait = BitmapFactory.decodeResource(getResources(),R.drawable.head);
// 对原有图片压缩显示大小
Matrix mMatrix = new Matrix();
float width = portrait.getWidth();
float height = portrait.getHeight();
mMatrix.setScale(size / width, size / height);
return Bitmap.createBitmap(portrait, 0, 0, (int) width,
(int) height, mMatrix, true);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 在二维码上绘制头像
*/
private void createQRCodeBitmapWithPortrait(Bitmap qr, Bitmap portrait) {
// 头像图片的大小
int portrait_W = portrait.getWidth();
int portrait_H = portrait.getHeight();
// 设置头像要显示的位置,即居中显示
int left = (qr.getWidth() - portrait_W) / 2;
int top = (qr.getHeight() - portrait_H) / 2;
int right = left + portrait_W;
int bottom = top + portrait_H;
Rect rect1 = new Rect(left, top, right, bottom);
// 取得qr二维码图片上的画笔,即要在二维码图片上绘制我们的头像
Canvas canvas = new Canvas(qr);
// 设置我们要绘制的范围大小,也就是头像的大小范围
Rect rect2 = new Rect(0, 0, portrait_W, portrait_H);
// 开始绘制
canvas.drawBitmap(portrait, rect2, rect1, null);
}
}
================================================
FILE: app/src/main/java/com/liang/scancode/MainActivity.java
================================================
package com.liang.scancode;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.liang.scancode.utils.Constant;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
int mode = getIntent().getIntExtra(Constant.REQUEST_SCAN_MODE, Constant.REQUEST_SCAN_MODE_ALL_MODE);
}
/**
* 按钮监听事件,这里我使用Butterknife,不喜欢的也可以直接写监听
* @param view
*/
@OnClick({R.id.create_code,R.id.scan_2code,R.id.scan_bar_code,R.id.scan_code})
public void clickListener(View view){
Intent intent;
switch (view.getId()){
case R.id.create_code: //生成码
intent=new Intent(this,CreateCodeActivity.class);
startActivity(intent);
break;
case R.id.scan_2code: //扫描二维码
intent=new Intent(this,CommonScanActivity.class);
intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_QRCODE_MODE);
startActivity(intent);
break;
case R.id.scan_bar_code://扫描条形码
intent=new Intent(this,CommonScanActivity.class);
intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_BARCODE_MODE);
startActivity(intent);
break;
case R.id.scan_code://扫描条形码或者二维码
intent=new Intent(this,CommonScanActivity.class);
intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_ALL_MODE);
startActivity(intent);
break;
}
}
}
================================================
FILE: app/src/main/java/com/liang/scancode/defineview/MyImageView.java
================================================
package com.liang.scancode.defineview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;
/**
* 作者:王敏 on 2015/8/21 17:31
* 类说明:画出扫描框的四个脚的脚边框,也可以直接用一张图片代替
*/
public class MyImageView extends ImageView{
private Context context;
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public MyImageView(Context context) {
super(context);
this.context = context;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
Paint paint = new Paint();
paint.setColor(Color.rgb(9,187,7));
paint.setAntiAlias(true);
paint.setStrokeWidth(t(5));
canvas.drawLine(0, 0, 0, t(18), paint);
canvas.drawLine(0, 0, t(18), 0, paint);
canvas.drawLine(0, height - t(18), 0, height, paint);
canvas.drawLine(0, height, t(18),height,paint);
canvas.drawLine(width-t(18), 0, width, 0, paint);
canvas.drawLine(width, 0, width,t(18),paint);
canvas.drawLine(width, height-t(18), width, height, paint);
canvas.drawLine(width-t(18), height, width,height,paint);
}
public int dp2px(float dpVal)
{
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.getResources().getDisplayMetrics());
}
public int t(float dpVal){
return dp2px(dpVal);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
// setMeasuredDimension(t(248),t(248));
}
}
================================================
FILE: app/src/main/java/com/liang/scancode/utils/Constant.java
================================================
package com.liang.scancode.utils;
/**
* Created by 刘红亮 on 2015/9/24 14:08.
*/
public interface Constant {
/**
* 二维码请求的type
*/
public static final String REQUEST_SCAN_TYPE="type";
/**
* 普通类型,扫完即关闭
*/
public static final int REQUEST_SCAN_TYPE_COMMON=0;
/**
* 服务商登记类型,扫描
*/
public static final int REQUEST_SCAN_TYPE_REGIST=1;
/**
* 扫描类型
* 条形码或者二维码:REQUEST_SCAN_MODE_ALL_MODE
* 条形码: REQUEST_SCAN_MODE_BARCODE_MODE
* 二维码:REQUEST_SCAN_MODE_QRCODE_MODE
*
*/
public static final String REQUEST_SCAN_MODE="ScanMode";
/**
* 条形码: REQUEST_SCAN_MODE_BARCODE_MODE
*/
public static final int REQUEST_SCAN_MODE_BARCODE_MODE = 0X100;
/**
* 二维码:REQUEST_SCAN_MODE_ALL_MODE
*/
public static final int REQUEST_SCAN_MODE_QRCODE_MODE = 0X200;
/**
* 条形码或者二维码:REQUEST_SCAN_MODE_ALL_MODE
*/
public static final int REQUEST_SCAN_MODE_ALL_MODE = 0X300;
}
================================================
FILE: app/src/main/java/com/liang/scancode/zxing/ScanListener.java
================================================
package com.liang.scancode.zxing;
import android.os.Bundle;
import com.google.zxing.Result;
/**
* 二维码结果监听返回
* @author 刘红亮 2015年4月29日 下午8:08:13
*
*/
public interface ScanListener {
/**
* 返回扫描结果
* @param rawResult 结果对象
* @param bundle 存放了截图,或者是空的
*/
public void scanResult(Result rawResult, Bundle bundle);
/**
* 扫描抛出的异常
* @param e
*/
public void scanError(Exception e);
}
================================================
FILE: app/src/main/java/com/liang/scancode/zxing/ScanManager.java
================================================
package com.liang.scancode.zxing;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.liang.scancode.R;
import com.liang.scancode.zxing.camera.CameraManager;
import com.liang.scancode.zxing.decode.DecodeThread;
import com.liang.scancode.zxing.decode.PhotoScanHandler;
import com.liang.scancode.zxing.decode.RGBLuminanceSource;
import com.liang.scancode.zxing.utils.BeepManager;
import com.liang.scancode.zxing.utils.BitmapUtil;
import com.liang.scancode.zxing.utils.CaptureActivityHandler;
import com.liang.scancode.zxing.utils.InactivityTimer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Map;
public class ScanManager implements SurfaceHolder.Callback{
boolean isHasSurface = false;
CameraManager cameraManager;
//用于拍摄扫描的handler
CaptureActivityHandler handler;
//用于照片扫描的handler,不可共用,图片扫描是不需要摄像机的
PhotoScanHandler photoScanHandler;
Rect mCropRect = null;
InactivityTimer inactivityTimer;
public BeepManager beepManager;
SurfaceView scanPreview = null;
View scanContainer;
View scanCropView;
ImageView scanLine;
final String TAG= ScanManager.class.getSimpleName();
Activity activity;
ScanListener listener;
boolean isOpenLight=false;
private int scanMode;//扫描模型(条形,二维码,全部)
/**
* 用于启动照相机扫描二维码,在activity的onCreate里面构造出来
* 在activity的生命周期中调用此类相对应的生命周期方法
* @param activity 扫描的activity
* @param scanPreview 预览的SurfaceView
* @param scanContainer 扫描的布局,全屏布局
* @param scanCropView 扫描的矩形区域
* @param scanLine 扫描线
*
*
*/
public ScanManager(Activity activity,SurfaceView scanPreview,View scanContainer,
View scanCropView,ImageView scanLine,int scanMode,ScanListener listener) {
this.activity=activity;
this.scanPreview=scanPreview;
this.scanContainer=scanContainer;
this.scanCropView=scanCropView;
this.scanLine=scanLine;
this.listener=listener;
this.scanMode=scanMode;
//启动动画
TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT,
0.9f);
animation.setDuration(4500);
animation.setRepeatCount(-1);
animation.setRepeatMode(Animation.RESTART);
scanLine.startAnimation(animation);
}
/**
* 用于图片扫描的构造函数
* @param listener 结果的监听回调
*/
public ScanManager(ScanListener listener){
this.listener=listener;
}
public void onResume(){
// CameraManager must be initialized here, not in onCreate(). This is
// necessary because we don't
// want to open the camera driver and measure the screen size if we're
// going to show the help on
// first launch. That led to bugs where the scanning rectangle was the
// wrong size and partially
// off screen.
inactivityTimer = new InactivityTimer(activity);
beepManager = new BeepManager(activity);
cameraManager = new CameraManager(activity.getApplicationContext());
handler = null;
if (isHasSurface) {
// The activity was paused but not stopped, so the surface still
// exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(scanPreview.getHolder());
} else {
// Install the callback and wait for surfaceCreated() to init the
// camera.
scanPreview.getHolder().addCallback(this);
}
inactivityTimer.onResume();
}
public void onPause() {
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
inactivityTimer.onPause();
beepManager.close();
cameraManager.closeDriver();
if (!isHasSurface) {
scanPreview.getHolder().removeCallback(this);
}
}
public void onDestroy() {
inactivityTimer.shutdown();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (holder == null) {
Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
}
if (!isHasSurface) {
isHasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
isHasSurface = false;
}
void initCamera(SurfaceHolder surfaceHolder) {
if (surfaceHolder == null) {
throw new IllegalStateException("No SurfaceHolder provided");
}
if (cameraManager.isOpen()) {
Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
return;
}
try {
cameraManager.openDriver(surfaceHolder);
// Creating the handler starts the preview, which can also throw a
// RuntimeException.
if (handler == null) {
handler = new CaptureActivityHandler(this, cameraManager, scanMode);
Log.e("hongliang1", "handler new成功!:"+handler);
}
initCrop();
} catch (IOException ioe) {
Log.e(TAG,"hongliang", ioe);
//弹出提示,报错
ioe.printStackTrace();
listener.scanError(new Exception("相机打开出错,请检查是否被禁止了该权限!"));
} catch (RuntimeException e) {
Log.e(TAG, "hongliang", e);
//弹出提示,报错
e.printStackTrace();
listener.scanError(new Exception("相机打开出错,请检查是否被禁止了该权限!"));
}
}
/**
* 开关闪关灯
*/
public void switchLight(){
if(isOpenLight){
cameraManager.offLight();
}else{
cameraManager.openLight();
}
isOpenLight=!isOpenLight;
}
public Handler getHandler() {
return handler;
}
public CameraManager getCameraManager() {
return cameraManager;
}
public Rect getCropRect() {
return mCropRect;
}
/**
* 扫描成功的结果回调
* @param rawResult
* @param bundle
*/
public void handleDecode(Result rawResult, Bundle bundle) {
inactivityTimer.onActivity();
//扫描成功播放声音滴一下,可根据需要自行确定什么时候播
beepManager.playBeepSoundAndVibrate();
bundle.putInt("width", mCropRect.width());
bundle.putInt("height", mCropRect.height());
bundle.putString("result", rawResult.getText());
listener.scanResult(rawResult, bundle);
}
public void handleDecodeError(Exception e){
listener.scanError(e);
}
/**
* 初始化截取的矩形区域
*/
void initCrop() {
int cameraWidth = cameraManager.getCameraResolution().y;
int cameraHeight = cameraManager.getCameraResolution().x;
/** 获取布局中扫描框的位置信息 */
int[] location = new int[2];
scanCropView.getLocationInWindow(location);
int cropLeft = location[0];
int cropTop = location[1] - getStatusBarHeight();
int cropWidth = scanCropView.getWidth();
int cropHeight = scanCropView.getHeight();
/** 获取布局容器的宽高 */
int containerWidth = scanContainer.getWidth();
int containerHeight = scanContainer.getHeight();
/** 计算最终截取的矩形的左上角顶点x坐标 */
int x = cropLeft * cameraWidth / containerWidth;
/** 计算最终截取的矩形的左上角顶点y坐标 */
int y = cropTop * cameraHeight / containerHeight;
/** 计算最终截取的矩形的宽度 */
int width = cropWidth * cameraWidth / containerWidth;
/** 计算最终截取的矩形的高度 */
int height = cropHeight * cameraHeight / containerHeight;
/** 生成最终的截取的矩形 */
mCropRect = new Rect(x, y, width + x, height + y);
}
int getStatusBarHeight() {
try {
Class> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return activity.getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
/**
* 用于扫描本地图片二维码或者一维码
* @param photo_path2 本地图片的所在位置
* @return
*/
public void scanningImage(final String photo_path2) {
if(TextUtils.isEmpty(photo_path2)){
listener.scanError(new Exception("photo url is null!"));
}
photoScanHandler=new PhotoScanHandler(this);
new Thread(new Runnable() {
@Override
public void run() {
//获取初始化的设置器
Map hints = DecodeThread.getHints();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
// Hashtable hints = new Hashtable();
Bitmap bitmap= BitmapUtil.decodeBitmapFromPath(photo_path2,600,600);
RGBLuminanceSource source = new RGBLuminanceSource(bitmap);
BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
QRCodeReader reader = new QRCodeReader();
MultiFormatReader multiFormatReader=new MultiFormatReader();
try {
Message msg=Message.obtain();
msg.what=PhotoScanHandler.PHOTODECODEOK;
msg.obj = multiFormatReader.decode(bitmap1, hints);
photoScanHandler.sendMessage(msg);
} catch (Exception e) {
Message msg=Message.obtain();
msg.what=PhotoScanHandler.PHOTODECODEERROR;
msg.obj=new Exception("图片有误,或者图片模糊!");
photoScanHandler.sendMessage(msg);
}
}
}).start();
}
/**
* 扫描一次后,如需再次扫描,请调用这个方法
*/
public void reScan(){
if(handler!=null){
handler.sendEmptyMessage(R.id.restart_preview);
}
}
public boolean isScanning(){
if(handler!=null){
return handler.isScanning();
}
return false;
}
}
================================================
FILE: app/src/main/java/com/liang/scancode/zxing/camera/AutoFocusManager.java
================================================
/*
* Copyright (C) 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liang.scancode.zxing.camera;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.RejectedExecutionException;
public class AutoFocusManager implements Camera.AutoFocusCallback {
static final String TAG = AutoFocusManager.class.getSimpleName();
static final long AUTO_FOCUS_INTERVAL_MS = 2000L;
static final Collection FOCUS_MODES_CALLING_AF;
static {
FOCUS_MODES_CALLING_AF = new ArrayList(2);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
}
boolean stopped;
boolean focusing;
final boolean useAutoFocus;
final Camera camera;
AsyncTask, ?, ?> outstandingTask;
public AutoFocusManager(Context context, Camera camera) {
this.camera = camera;
String currentFocusMode = camera.getParameters().getFocusMode();
useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
start();
}
@Override
public synchronized void onAutoFocus(boolean success, Camera theCamera) {
focusing = false;
autoFocusAgainLater();
}
@SuppressLint("NewApi")
synchronized void autoFocusAgainLater() {
if (!stopped && outstandingTask == null) {
AutoFocusTask newTask = new AutoFocusTask();
try {
if (Build.VERSION.SDK_INT >= 11) {
newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
newTask.execute();
}
outstandingTask = newTask;
} catch (RejectedExecutionException ree) {
Log.w(TAG, "Could not request auto focus", ree);
}
}
}
public synchronized void start() {
if (useAutoFocus) {
outstandingTask = null;
if (!stopped && !focusing) {
try {
camera.autoFocus(this);
focusing = true;
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+;
// continue?
Log.w(TAG, "Unexpected exception while focusing", re);
// Try again later to keep cycle going
autoFocusAgainLater();
}
}
}
}
synchronized void cancelOutstandingTask() {
if (outstandingTask != null) {
if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
outstandingTask.cancel(true);
}
outstandingTask = null;
}
}
public synchronized void stop() {
stopped = true;
if (useAutoFocus) {
cancelOutstandingTask();
// Doesn't hurt to call this even if not focusing
try {
camera.cancelAutoFocus();
} catch (RuntimeException re) {
// Have heard RuntimeException reported in Android 4.0.x+;
// continue?
Log.w(TAG, "Unexpected exception while cancelling focusing", re);
}
}
}
final class AutoFocusTask extends AsyncTask