├── .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-hdpi
│ ├── arrow.png
│ ├── flashlight.png
│ ├── ic_orderform_arrow_fanhui.png
│ └── kai.png
│ ├── drawable-xhdpi
│ ├── arrow.png
│ ├── flashlight.png
│ ├── ic_my_returns_arrow.png
│ ├── ic_orderform_arrow_fanhui.png
│ ├── ic_seller_seeps.png
│ ├── kai.png
│ ├── scan2code_icon_back_nor.png
│ ├── scan2code_icon_back_sel.png
│ ├── scan2code_icon_light_nor.png
│ ├── scan2code_icon_light_sel.png
│ ├── scan2code_icon_xiangce.png
│ ├── scan2code_icon_xiangce_sel.png
│ ├── scanning_line.png
│ ├── shouquan_icon_error.png
│ ├── shouquan_icon_ok.png
│ ├── shouquan_iloading_progress.png
│ └── yundan_scanline.png
│ ├── drawable-xxhdpi
│ ├── arrow.png
│ ├── flashlight.png
│ ├── ic_orderform_arrow_fanhui.png
│ ├── ic_seller_seeps.png
│ └── kai.png
│ ├── drawable
│ ├── base_bgpic.xml
│ ├── head.jpg
│ ├── 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
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── raw
│ └── beep.ogg
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── Qrcode_ids.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── createCode.png
├── main.png
├── scan2code.png
├── scanCode.png
├── scan_bar_code.png
└── scan_photo.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /captures
8 | ### Android template
9 | # Built application files
10 | *.apk
11 | *.ap_
12 |
13 | # Files for the Dalvik VM
14 | *.dex
15 |
16 | # Java class files
17 | *.class
18 |
19 | # Generated files
20 | bin/
21 | gen/
22 |
23 | # Gradle files
24 | .gradle/
25 | build/
26 |
27 | # Local configuration file (sdk path, etc)
28 | local.properties
29 |
30 | # Proguard folder generated by Eclipse
31 | proguard/
32 |
33 | # Log Files
34 | *.log
35 |
36 | # Android Studio Navigation editor temp files
37 | .navigation/
38 |
39 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | ScanCode
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ScanCode
2 | 使用zxing封装的android扫描全功能系列,包括二维码扫描,条形码扫描,二维码生成,条形码生成,从图片中扫描二维码或者条形码,闪光灯控制。
3 | 优点:
4 | 1.该有的功能一个都不少!
5 | 2.扫描界面布局xml完成,可自行订制!
6 | 3.不乱码,不变形!
7 | 4.扫描后可得到扫描的截图!
8 | 5.支持连续扫描!
9 | 6.在一个项目中可多处使用,根据CommonScanActivity在多写一个自己的扫描界面就行了!
10 | #项目截图
11 | 
12 |
13 | 
14 | 
15 | 
16 | 
17 | 
18 |
--------------------------------------------------------------------------------
/ScanCode.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | ### Android template
2 | # Built application files
3 | *.apk
4 | *.ap_
5 |
6 | # Files for the Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | /build
33 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | generateDebugAndroidTestSources
19 | generateDebugSources
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.liang.scancode"
9 | minSdkVersion 15
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(include: ['*.jar'], dir: 'libs')
24 | }
25 |
--------------------------------------------------------------------------------
/app/libs/butterknife-7.0.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liang530/ScanCode/404dbb4ca7830eab5e07c37ec54b3e86999f33c4/app/libs/butterknife-7.0.1.jar
--------------------------------------------------------------------------------
/app/libs/zxing.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liang530/ScanCode/404dbb4ca7830eab5e07c37ec54b3e86999f33c4/app/libs/zxing.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/hongliang/android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class goodsid to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
41 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/CommonScanActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 ZXing authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.liang.scancode;
17 |
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.database.Cursor;
21 | import android.graphics.Bitmap;
22 | import android.graphics.BitmapFactory;
23 | import android.os.Bundle;
24 | import android.provider.MediaStore;
25 | import android.view.SurfaceView;
26 | import android.view.View;
27 | import android.view.Window;
28 | import android.view.WindowManager;
29 | import android.widget.Button;
30 | import android.widget.ImageView;
31 | import android.widget.TextView;
32 | import android.widget.Toast;
33 |
34 | import com.google.zxing.Result;
35 |
36 | import butterknife.ButterKnife;
37 | import butterknife.Bind;
38 | import com.liang.scancode.utils.Constant;
39 | import com.liang.scancode.zxing.ScanListener;
40 | import com.liang.scancode.zxing.ScanManager;
41 | import com.liang.scancode.zxing.decode.DecodeThread;
42 | import com.liang.scancode.zxing.decode.Utils;
43 |
44 |
45 | /**
46 | * 二维码扫描使用
47 | *
48 | * @author 刘红亮 2015年4月29日 下午5:49:45
49 | */
50 | public final class CommonScanActivity extends Activity implements ScanListener, View.OnClickListener {
51 | static final String TAG = CommonScanActivity.class.getSimpleName();
52 | SurfaceView scanPreview = null;
53 | View scanContainer;
54 | View scanCropView;
55 | ImageView scanLine;
56 | ScanManager scanManager;
57 | TextView iv_light;
58 | TextView qrcode_g_gallery;
59 | TextView qrcode_ic_back;
60 | final int PHOTOREQUESTCODE = 1111;
61 |
62 | @Bind(R.id.service_register_rescan)
63 | Button rescan;
64 | @Bind(R.id.scan_image)
65 | ImageView scan_image;
66 | @Bind(R.id.authorize_return)
67 | ImageView authorize_return;
68 | private int scanMode;//扫描模型(条形,二维码,全部)
69 |
70 | @Bind(R.id.common_title_TV_center)
71 | TextView title;
72 | @Bind(R.id.scan_hint)
73 | TextView scan_hint;
74 | @Bind(R.id.tv_scan_result)
75 | TextView tv_scan_result;
76 |
77 |
78 |
79 | @Override
80 | public void onCreate(Bundle icicle) {
81 | super.onCreate(icicle);
82 |
83 | Window window = getWindow();
84 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
85 | setContentView(R.layout.activity_scan_code);
86 | ButterKnife.bind(this);
87 | scanMode=getIntent().getIntExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_ALL_MODE);
88 | initView();
89 | }
90 |
91 | void initView() {
92 | switch (scanMode){
93 | case DecodeThread.BARCODE_MODE:
94 | title.setText(R.string.scan_barcode_title);
95 | scan_hint.setText(R.string.scan_barcode_hint);
96 | break;
97 | case DecodeThread.QRCODE_MODE:
98 | title.setText(R.string.scan_qrcode_title);
99 | scan_hint.setText(R.string.scan_qrcode_hint);
100 | break;
101 | case DecodeThread.ALL_MODE:
102 | title.setText(R.string.scan_allcode_title);
103 | scan_hint.setText(R.string.scan_allcode_hint);
104 | break;
105 | }
106 | scanPreview = (SurfaceView) findViewById(R.id.capture_preview);
107 | scanContainer = findViewById(R.id.capture_container);
108 | scanCropView = findViewById(R.id.capture_crop_view);
109 | scanLine = (ImageView) findViewById(R.id.capture_scan_line);
110 | qrcode_g_gallery = (TextView) findViewById(R.id.qrcode_g_gallery);
111 | qrcode_g_gallery.setOnClickListener(this);
112 | qrcode_ic_back = (TextView) findViewById(R.id.qrcode_ic_back);
113 | qrcode_ic_back.setOnClickListener(this);
114 | iv_light = (TextView) findViewById(R.id.iv_light);
115 | iv_light.setOnClickListener(this);
116 | rescan.setOnClickListener(this);
117 | authorize_return.setOnClickListener(this);
118 | //构造出扫描管理器
119 | scanManager = new ScanManager(this, scanPreview, scanContainer, scanCropView, scanLine, scanMode,this);
120 | }
121 |
122 | @Override
123 | public void onResume() {
124 | super.onResume();
125 | scanManager.onResume();
126 | rescan.setVisibility(View.INVISIBLE);
127 | scan_image.setVisibility(View.GONE);
128 | }
129 |
130 | @Override
131 | public void onPause() {
132 | super.onPause();
133 | scanManager.onPause();
134 | }
135 | /**
136 | *
137 | */
138 | public void scanResult(Result rawResult, Bundle bundle) {
139 | //扫描成功后,扫描器不会再连续扫描,如需连续扫描,调用reScan()方法。
140 | //scanManager.reScan();
141 | // Toast.makeText(that, "result="+rawResult.getText(), Toast.LENGTH_LONG).show();
142 |
143 | if (!scanManager.isScanning()) { //如果当前不是在扫描状态
144 | //设置再次扫描按钮出现
145 | rescan.setVisibility(View.VISIBLE);
146 | scan_image.setVisibility(View.VISIBLE);
147 | Bitmap barcode = null;
148 | byte[] compressedBitmap = bundle.getByteArray(DecodeThread.BARCODE_BITMAP);
149 | if (compressedBitmap != null) {
150 | barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null);
151 | barcode = barcode.copy(Bitmap.Config.ARGB_8888, true);
152 | }
153 | scan_image.setImageBitmap(barcode);
154 | }
155 | rescan.setVisibility(View.VISIBLE);
156 | scan_image.setVisibility(View.VISIBLE);
157 | tv_scan_result.setVisibility(View.VISIBLE);
158 | tv_scan_result.setText("结果:"+rawResult.getText());
159 | }
160 |
161 | void startScan() {
162 | if (rescan.getVisibility() == View.VISIBLE) {
163 | rescan.setVisibility(View.INVISIBLE);
164 | scan_image.setVisibility(View.GONE);
165 | scanManager.reScan();
166 | }
167 | }
168 |
169 | @Override
170 | public void scanError(Exception e) {
171 | Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
172 | //相机扫描出错时
173 | if(e.getMessage()!=null&&e.getMessage().startsWith("相机")){
174 | scanPreview.setVisibility(View.INVISIBLE);
175 | }
176 | }
177 |
178 | public void showPictures(int requestCode) {
179 | Intent intent = new Intent(Intent.ACTION_PICK);
180 | intent.setType("image/*");
181 | startActivityForResult(intent, requestCode);
182 | }
183 |
184 | @Override
185 | public void onActivityResult(int requestCode, int resultCode, Intent data) {
186 | super.onActivityResult(requestCode, resultCode, data);
187 | String photo_path;
188 | if (resultCode == RESULT_OK) {
189 | switch (requestCode) {
190 | case PHOTOREQUESTCODE:
191 | String[] proj = {MediaStore.Images.Media.DATA};
192 | Cursor cursor = this.getContentResolver().query(data.getData(), proj, null, null, null);
193 | if (cursor.moveToFirst()) {
194 | int colum_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
195 | photo_path = cursor.getString(colum_index);
196 | if (photo_path == null) {
197 | photo_path = Utils.getPath(getApplicationContext(), data.getData());
198 | }
199 | scanManager.scanningImage(photo_path);
200 | }
201 | }
202 | }
203 | }
204 |
205 | @Override
206 | public void onClick(View v) {
207 | switch (v.getId()) {
208 | case R.id.qrcode_g_gallery:
209 | showPictures(PHOTOREQUESTCODE);
210 | break;
211 | case R.id.iv_light:
212 | scanManager.switchLight();
213 | break;
214 | case R.id.qrcode_ic_back:
215 | finish();
216 | break;
217 | case R.id.service_register_rescan://再次开启扫描
218 | startScan();
219 | break;
220 | case R.id.authorize_return:
221 | finish();
222 | break;
223 | default:
224 | break;
225 | }
226 | }
227 |
228 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/CreateCodeActivity.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Matrix;
8 | import android.graphics.Rect;
9 | import android.os.Bundle;
10 | import android.text.TextUtils;
11 | import android.view.View;
12 | import android.widget.Button;
13 | import android.widget.EditText;
14 | import android.widget.ImageView;
15 | import android.widget.Toast;
16 |
17 | import com.google.zxing.WriterException;
18 |
19 | import java.io.UnsupportedEncodingException;
20 |
21 | import butterknife.ButterKnife;
22 | import butterknife.Bind;
23 | import butterknife.OnClick;
24 | import com.liang.scancode.zxing.encode.EncodingHandler;
25 |
26 | /**
27 | * Created by 刘红亮 on 2015/9/24 14:37.
28 | */
29 | public class CreateCodeActivity extends Activity {
30 | @Bind(R.id.et_code_key)
31 | EditText etCodeKey;
32 | @Bind(R.id.btn_create_code)
33 | Button btnCreateCode;
34 | @Bind(R.id.iv_2_code)
35 | ImageView iv2Code;
36 | @Bind(R.id.iv_bar_code)
37 | ImageView ivBarCode;
38 |
39 | @Override
40 | public void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | setContentView(R.layout.activity_create_code);
43 | ButterKnife.bind(this);
44 | }
45 | @OnClick({R.id.btn_create_code,R.id.btn_create_code_and_img})
46 | public void clickListener(View view){
47 | String key=etCodeKey.getText().toString();
48 | switch (view.getId()){
49 | case R.id.btn_create_code: //生成码
50 | if(TextUtils.isEmpty(key)){
51 | Toast.makeText(this,"请输入内容",Toast.LENGTH_SHORT).show();
52 | }else{
53 | create2Code(key);
54 | createBarCode(key);
55 | }
56 | break;
57 | case R.id.btn_create_code_and_img: //生成码
58 | Bitmap bitmap = create2Code(key);
59 | Bitmap headBitmap = getHeadBitmap(60);
60 | if(bitmap!=null&&headBitmap!=null){
61 | createQRCodeBitmapWithPortrait(bitmap,headBitmap);
62 | }
63 | break;
64 | }
65 | }
66 | private Bitmap createBarCode(String key) {
67 | Bitmap qrCode = null;
68 | try {
69 | qrCode = EncodingHandler.createBarCode(key, 600, 300);
70 | ivBarCode.setImageBitmap(qrCode);
71 | } catch (Exception e) {
72 | Toast.makeText(this,"输入的内容条形码不支持!",Toast.LENGTH_SHORT).show();
73 | e.printStackTrace();
74 | }
75 | return qrCode;
76 | }
77 |
78 | /**
79 | * 生成二维码
80 | * @param key
81 | */
82 | private Bitmap create2Code(String key) {
83 | Bitmap qrCode=null;
84 | try {
85 | qrCode= EncodingHandler.create2Code(key, 400);
86 | iv2Code.setImageBitmap(qrCode);
87 | } catch (WriterException e) {
88 | e.printStackTrace();
89 | } catch (UnsupportedEncodingException e) {
90 | e.printStackTrace();
91 | }
92 | return qrCode;
93 | }
94 | /**
95 | * 初始化头像图片
96 | */
97 | private Bitmap getHeadBitmap(int size) {
98 | try {
99 | // 这里采用从asset中加载图片abc.jpg
100 | Bitmap portrait = BitmapFactory.decodeResource(getResources(),R.drawable.head);
101 | // 对原有图片压缩显示大小
102 | Matrix mMatrix = new Matrix();
103 | float width = portrait.getWidth();
104 | float height = portrait.getHeight();
105 | mMatrix.setScale(size / width, size / height);
106 | return Bitmap.createBitmap(portrait, 0, 0, (int) width,
107 | (int) height, mMatrix, true);
108 | } catch (Exception e) {
109 | e.printStackTrace();
110 | }
111 | return null;
112 | }
113 | /**
114 | * 在二维码上绘制头像
115 | */
116 | private void createQRCodeBitmapWithPortrait(Bitmap qr, Bitmap portrait) {
117 | // 头像图片的大小
118 | int portrait_W = portrait.getWidth();
119 | int portrait_H = portrait.getHeight();
120 |
121 | // 设置头像要显示的位置,即居中显示
122 | int left = (qr.getWidth() - portrait_W) / 2;
123 | int top = (qr.getHeight() - portrait_H) / 2;
124 | int right = left + portrait_W;
125 | int bottom = top + portrait_H;
126 | Rect rect1 = new Rect(left, top, right, bottom);
127 |
128 | // 取得qr二维码图片上的画笔,即要在二维码图片上绘制我们的头像
129 | Canvas canvas = new Canvas(qr);
130 |
131 | // 设置我们要绘制的范围大小,也就是头像的大小范围
132 | Rect rect2 = new Rect(0, 0, portrait_W, portrait_H);
133 | // 开始绘制
134 | canvas.drawBitmap(portrait, rect2, rect1, null);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 |
8 | import butterknife.ButterKnife;
9 | import butterknife.OnClick;
10 | import com.liang.scancode.utils.Constant;
11 |
12 |
13 | public class MainActivity extends Activity {
14 | @Override
15 | public void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 | ButterKnife.bind(this);
19 | int mode = getIntent().getIntExtra(Constant.REQUEST_SCAN_MODE, Constant.REQUEST_SCAN_MODE_ALL_MODE);
20 |
21 |
22 | }
23 |
24 | /**
25 | * 按钮监听事件,这里我使用Butterknife,不喜欢的也可以直接写监听
26 | * @param view
27 | */
28 | @OnClick({R.id.create_code,R.id.scan_2code,R.id.scan_bar_code,R.id.scan_code})
29 | public void clickListener(View view){
30 | Intent intent;
31 | switch (view.getId()){
32 | case R.id.create_code: //生成码
33 | intent=new Intent(this,CreateCodeActivity.class);
34 | startActivity(intent);
35 | break;
36 | case R.id.scan_2code: //扫描二维码
37 | intent=new Intent(this,CommonScanActivity.class);
38 | intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_QRCODE_MODE);
39 | startActivity(intent);
40 | break;
41 | case R.id.scan_bar_code://扫描条形码
42 | intent=new Intent(this,CommonScanActivity.class);
43 | intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_BARCODE_MODE);
44 | startActivity(intent);
45 | break;
46 | case R.id.scan_code://扫描条形码或者二维码
47 | intent=new Intent(this,CommonScanActivity.class);
48 | intent.putExtra(Constant.REQUEST_SCAN_MODE,Constant.REQUEST_SCAN_MODE_ALL_MODE);
49 | startActivity(intent);
50 | break;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/defineview/MyImageView.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode.defineview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.util.AttributeSet;
8 | import android.util.TypedValue;
9 | import android.widget.ImageView;
10 |
11 | /**
12 | * 作者:王敏 on 2015/8/21 17:31
13 | * 类说明:画出扫描框的四个脚的脚边框,也可以直接用一张图片代替
14 | */
15 | public class MyImageView extends ImageView{
16 | private Context context;
17 | public MyImageView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | this.context = context;
20 | }
21 | public MyImageView(Context context) {
22 | super(context);
23 | this.context = context;
24 | }
25 |
26 | @Override
27 | protected void onDraw(Canvas canvas) {
28 | super.onDraw(canvas);
29 | int width = getWidth();
30 | int height = getHeight();
31 |
32 | Paint paint = new Paint();
33 | paint.setColor(Color.rgb(9,187,7));
34 | paint.setAntiAlias(true);
35 | paint.setStrokeWidth(t(5));
36 |
37 | canvas.drawLine(0, 0, 0, t(18), paint);
38 | canvas.drawLine(0, 0, t(18), 0, paint);
39 |
40 | canvas.drawLine(0, height - t(18), 0, height, paint);
41 | canvas.drawLine(0, height, t(18),height,paint);
42 |
43 | canvas.drawLine(width-t(18), 0, width, 0, paint);
44 | canvas.drawLine(width, 0, width,t(18),paint);
45 |
46 | canvas.drawLine(width, height-t(18), width, height, paint);
47 | canvas.drawLine(width-t(18), height, width,height,paint);
48 | }
49 | public int dp2px(float dpVal)
50 | {
51 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
52 | dpVal, context.getResources().getDisplayMetrics());
53 | }
54 |
55 | public int t(float dpVal){
56 | return dp2px(dpVal);
57 | }
58 |
59 | @Override
60 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
61 | super.onMeasure(widthMeasureSpec,heightMeasureSpec);
62 | // setMeasuredDimension(t(248),t(248));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/utils/Constant.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode.utils;
2 |
3 | /**
4 | * Created by 刘红亮 on 2015/9/24 14:08.
5 | */
6 | public interface Constant {
7 | /**
8 | * 二维码请求的type
9 | */
10 | public static final String REQUEST_SCAN_TYPE="type";
11 | /**
12 | * 普通类型,扫完即关闭
13 | */
14 | public static final int REQUEST_SCAN_TYPE_COMMON=0;
15 | /**
16 | * 服务商登记类型,扫描
17 | */
18 | public static final int REQUEST_SCAN_TYPE_REGIST=1;
19 |
20 |
21 | /**
22 | * 扫描类型
23 | * 条形码或者二维码:REQUEST_SCAN_MODE_ALL_MODE
24 | * 条形码: REQUEST_SCAN_MODE_BARCODE_MODE
25 | * 二维码:REQUEST_SCAN_MODE_QRCODE_MODE
26 | *
27 | */
28 | public static final String REQUEST_SCAN_MODE="ScanMode";
29 | /**
30 | * 条形码: REQUEST_SCAN_MODE_BARCODE_MODE
31 | */
32 | public static final int REQUEST_SCAN_MODE_BARCODE_MODE = 0X100;
33 | /**
34 | * 二维码:REQUEST_SCAN_MODE_ALL_MODE
35 | */
36 | public static final int REQUEST_SCAN_MODE_QRCODE_MODE = 0X200;
37 | /**
38 | * 条形码或者二维码:REQUEST_SCAN_MODE_ALL_MODE
39 | */
40 | public static final int REQUEST_SCAN_MODE_ALL_MODE = 0X300;
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/zxing/ScanListener.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode.zxing;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.google.zxing.Result;
6 |
7 | /**
8 | * 二维码结果监听返回
9 | * @author 刘红亮 2015年4月29日 下午8:08:13
10 | *
11 | */
12 | public interface ScanListener {
13 | /**
14 | * 返回扫描结果
15 | * @param rawResult 结果对象
16 | * @param bundle 存放了截图,或者是空的
17 | */
18 | public void scanResult(Result rawResult, Bundle bundle);
19 | /**
20 | * 扫描抛出的异常
21 | * @param e
22 | */
23 | public void scanError(Exception e);
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/zxing/ScanManager.java:
--------------------------------------------------------------------------------
1 | package com.liang.scancode.zxing;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Rect;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import android.os.Message;
9 | import android.text.TextUtils;
10 | import android.util.Log;
11 | import android.view.SurfaceHolder;
12 | import android.view.SurfaceView;
13 | import android.view.View;
14 | import android.view.animation.Animation;
15 | import android.view.animation.TranslateAnimation;
16 | import android.widget.ImageView;
17 |
18 | import com.google.zxing.BinaryBitmap;
19 | import com.google.zxing.DecodeHintType;
20 | import com.google.zxing.MultiFormatReader;
21 | import com.google.zxing.Result;
22 | import com.google.zxing.common.HybridBinarizer;
23 | import com.google.zxing.qrcode.QRCodeReader;
24 | import com.liang.scancode.R;
25 | import com.liang.scancode.zxing.camera.CameraManager;
26 | import com.liang.scancode.zxing.decode.DecodeThread;
27 | import com.liang.scancode.zxing.decode.PhotoScanHandler;
28 | import com.liang.scancode.zxing.decode.RGBLuminanceSource;
29 | import com.liang.scancode.zxing.utils.BeepManager;
30 | import com.liang.scancode.zxing.utils.BitmapUtil;
31 | import com.liang.scancode.zxing.utils.CaptureActivityHandler;
32 | import com.liang.scancode.zxing.utils.InactivityTimer;
33 |
34 | import java.io.IOException;
35 | import java.lang.reflect.Field;
36 | import java.util.Map;
37 |
38 | public class ScanManager implements SurfaceHolder.Callback{
39 | boolean isHasSurface = false;
40 | CameraManager cameraManager;
41 | //用于拍摄扫描的handler
42 | CaptureActivityHandler handler;
43 | //用于照片扫描的handler,不可共用,图片扫描是不需要摄像机的
44 | PhotoScanHandler photoScanHandler;
45 | Rect mCropRect = null;
46 | InactivityTimer inactivityTimer;
47 | public BeepManager beepManager;
48 | SurfaceView scanPreview = null;
49 | View scanContainer;
50 | View scanCropView;
51 | ImageView scanLine;
52 | final String TAG= ScanManager.class.getSimpleName();
53 | Activity activity;
54 | ScanListener listener;
55 | boolean isOpenLight=false;
56 |
57 | private int scanMode;//扫描模型(条形,二维码,全部)
58 | /**
59 | * 用于启动照相机扫描二维码,在activity的onCreate里面构造出来
60 | * 在activity的生命周期中调用此类相对应的生命周期方法
61 | * @param activity 扫描的activity
62 | * @param scanPreview 预览的SurfaceView
63 | * @param scanContainer 扫描的布局,全屏布局
64 | * @param scanCropView 扫描的矩形区域
65 | * @param scanLine 扫描线
66 | *
67 | *
68 | */
69 | public ScanManager(Activity activity,SurfaceView scanPreview,View scanContainer,
70 | View scanCropView,ImageView scanLine,int scanMode,ScanListener listener) {
71 | this.activity=activity;
72 | this.scanPreview=scanPreview;
73 | this.scanContainer=scanContainer;
74 | this.scanCropView=scanCropView;
75 | this.scanLine=scanLine;
76 | this.listener=listener;
77 | this.scanMode=scanMode;
78 | //启动动画
79 | 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,
80 | 0.9f);
81 | animation.setDuration(4500);
82 | animation.setRepeatCount(-1);
83 | animation.setRepeatMode(Animation.RESTART);
84 | scanLine.startAnimation(animation);
85 |
86 | }
87 | /**
88 | * 用于图片扫描的构造函数
89 | * @param listener 结果的监听回调
90 | */
91 | public ScanManager(ScanListener listener){
92 | this.listener=listener;
93 | }
94 |
95 | public void onResume(){
96 | // CameraManager must be initialized here, not in onCreate(). This is
97 | // necessary because we don't
98 | // want to open the camera driver and measure the screen size if we're
99 | // going to show the help on
100 | // first launch. That led to bugs where the scanning rectangle was the
101 | // wrong size and partially
102 | // off screen.
103 | inactivityTimer = new InactivityTimer(activity);
104 | beepManager = new BeepManager(activity);
105 | cameraManager = new CameraManager(activity.getApplicationContext());
106 |
107 | handler = null;
108 | if (isHasSurface) {
109 | // The activity was paused but not stopped, so the surface still
110 | // exists. Therefore
111 | // surfaceCreated() won't be called, so init the camera here.
112 | initCamera(scanPreview.getHolder());
113 | } else {
114 | // Install the callback and wait for surfaceCreated() to init the
115 | // camera.
116 | scanPreview.getHolder().addCallback(this);
117 | }
118 | inactivityTimer.onResume();
119 | }
120 | public void onPause() {
121 | if (handler != null) {
122 | handler.quitSynchronously();
123 | handler = null;
124 | }
125 | inactivityTimer.onPause();
126 | beepManager.close();
127 | cameraManager.closeDriver();
128 | if (!isHasSurface) {
129 | scanPreview.getHolder().removeCallback(this);
130 | }
131 | }
132 | public void onDestroy() {
133 | inactivityTimer.shutdown();
134 | }
135 |
136 |
137 | @Override
138 | public void surfaceCreated(SurfaceHolder holder) {
139 | if (holder == null) {
140 | Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!");
141 | }
142 | if (!isHasSurface) {
143 | isHasSurface = true;
144 | initCamera(holder);
145 | }
146 | }
147 |
148 | @Override
149 | public void surfaceChanged(SurfaceHolder holder, int format, int width,
150 | int height) {
151 | }
152 |
153 | @Override
154 | public void surfaceDestroyed(SurfaceHolder holder) {
155 | isHasSurface = false;
156 | }
157 | void initCamera(SurfaceHolder surfaceHolder) {
158 | if (surfaceHolder == null) {
159 | throw new IllegalStateException("No SurfaceHolder provided");
160 | }
161 | if (cameraManager.isOpen()) {
162 | Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?");
163 | return;
164 | }
165 | try {
166 | cameraManager.openDriver(surfaceHolder);
167 | // Creating the handler starts the preview, which can also throw a
168 | // RuntimeException.
169 | if (handler == null) {
170 | handler = new CaptureActivityHandler(this, cameraManager, scanMode);
171 | Log.e("hongliang1", "handler new成功!:"+handler);
172 | }
173 |
174 | initCrop();
175 | } catch (IOException ioe) {
176 | Log.e(TAG,"hongliang", ioe);
177 | //弹出提示,报错
178 | ioe.printStackTrace();
179 | listener.scanError(new Exception("相机打开出错,请检查是否被禁止了该权限!"));
180 | } catch (RuntimeException e) {
181 | Log.e(TAG, "hongliang", e);
182 | //弹出提示,报错
183 | e.printStackTrace();
184 | listener.scanError(new Exception("相机打开出错,请检查是否被禁止了该权限!"));
185 | }
186 | }
187 | /**
188 | * 开关闪关灯
189 | */
190 | public void switchLight(){
191 | if(isOpenLight){
192 | cameraManager.offLight();
193 | }else{
194 | cameraManager.openLight();
195 | }
196 | isOpenLight=!isOpenLight;
197 | }
198 | public Handler getHandler() {
199 | return handler;
200 | }
201 |
202 | public CameraManager getCameraManager() {
203 | return cameraManager;
204 | }
205 | public Rect getCropRect() {
206 | return mCropRect;
207 | }
208 | /**
209 | * 扫描成功的结果回调
210 | * @param rawResult
211 | * @param bundle
212 | */
213 | public void handleDecode(Result rawResult, Bundle bundle) {
214 | inactivityTimer.onActivity();
215 | //扫描成功播放声音滴一下,可根据需要自行确定什么时候播
216 | beepManager.playBeepSoundAndVibrate();
217 | bundle.putInt("width", mCropRect.width());
218 | bundle.putInt("height", mCropRect.height());
219 | bundle.putString("result", rawResult.getText());
220 | listener.scanResult(rawResult, bundle);
221 | }
222 | public void handleDecodeError(Exception e){
223 | listener.scanError(e);
224 | }
225 | /**
226 | * 初始化截取的矩形区域
227 | */
228 | void initCrop() {
229 | int cameraWidth = cameraManager.getCameraResolution().y;
230 | int cameraHeight = cameraManager.getCameraResolution().x;
231 |
232 | /** 获取布局中扫描框的位置信息 */
233 | int[] location = new int[2];
234 | scanCropView.getLocationInWindow(location);
235 |
236 | int cropLeft = location[0];
237 | int cropTop = location[1] - getStatusBarHeight();
238 |
239 | int cropWidth = scanCropView.getWidth();
240 | int cropHeight = scanCropView.getHeight();
241 |
242 | /** 获取布局容器的宽高 */
243 | int containerWidth = scanContainer.getWidth();
244 | int containerHeight = scanContainer.getHeight();
245 |
246 | /** 计算最终截取的矩形的左上角顶点x坐标 */
247 | int x = cropLeft * cameraWidth / containerWidth;
248 | /** 计算最终截取的矩形的左上角顶点y坐标 */
249 | int y = cropTop * cameraHeight / containerHeight;
250 |
251 | /** 计算最终截取的矩形的宽度 */
252 | int width = cropWidth * cameraWidth / containerWidth;
253 | /** 计算最终截取的矩形的高度 */
254 | int height = cropHeight * cameraHeight / containerHeight;
255 |
256 | /** 生成最终的截取的矩形 */
257 | mCropRect = new Rect(x, y, width + x, height + y);
258 | }
259 | int getStatusBarHeight() {
260 | try {
261 | Class> c = Class.forName("com.android.internal.R$dimen");
262 | Object obj = c.newInstance();
263 | Field field = c.getField("status_bar_height");
264 | int x = Integer.parseInt(field.get(obj).toString());
265 | return activity.getResources().getDimensionPixelSize(x);
266 | } catch (Exception e) {
267 | e.printStackTrace();
268 | }
269 | return 0;
270 | }
271 | /**
272 | * 用于扫描本地图片二维码或者一维码
273 | * @param photo_path2 本地图片的所在位置
274 | * @return
275 | */
276 | public void scanningImage(final String photo_path2) {
277 | if(TextUtils.isEmpty(photo_path2)){
278 | listener.scanError(new Exception("photo url is null!"));
279 | }
280 | photoScanHandler=new PhotoScanHandler(this);
281 | new Thread(new Runnable() {
282 |
283 | @Override
284 | public void run() {
285 | //获取初始化的设置器
286 | Map hints = DecodeThread.getHints();
287 | hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
288 |
289 | // Hashtable hints = new Hashtable();
290 |
291 | Bitmap bitmap= BitmapUtil.decodeBitmapFromPath(photo_path2,600,600);
292 | RGBLuminanceSource source = new RGBLuminanceSource(bitmap);
293 | BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
294 | QRCodeReader reader = new QRCodeReader();
295 | MultiFormatReader multiFormatReader=new MultiFormatReader();
296 | try {
297 | Message msg=Message.obtain();
298 | msg.what=PhotoScanHandler.PHOTODECODEOK;
299 | msg.obj = multiFormatReader.decode(bitmap1, hints);
300 | photoScanHandler.sendMessage(msg);
301 | } catch (Exception e) {
302 | Message msg=Message.obtain();
303 | msg.what=PhotoScanHandler.PHOTODECODEERROR;
304 | msg.obj=new Exception("图片有误,或者图片模糊!");
305 | photoScanHandler.sendMessage(msg);
306 | }
307 | }
308 | }).start();
309 | }
310 | /**
311 | * 扫描一次后,如需再次扫描,请调用这个方法
312 | */
313 | public void reScan(){
314 | if(handler!=null){
315 | handler.sendEmptyMessage(R.id.restart_preview);
316 | }
317 | }
318 | public boolean isScanning(){
319 | if(handler!=null){
320 | return handler.isScanning();
321 | }
322 | return false;
323 | }
324 |
325 | }
326 |
--------------------------------------------------------------------------------
/app/src/main/java/com/liang/scancode/zxing/camera/AutoFocusManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 ZXing authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.liang.scancode.zxing.camera;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.content.Context;
21 | import android.hardware.Camera;
22 | import android.os.AsyncTask;
23 | import android.os.Build;
24 | import android.util.Log;
25 |
26 | import java.util.ArrayList;
27 | import java.util.Collection;
28 | import java.util.concurrent.RejectedExecutionException;
29 |
30 | public class AutoFocusManager implements Camera.AutoFocusCallback {
31 |
32 | static final String TAG = AutoFocusManager.class.getSimpleName();
33 |
34 | static final long AUTO_FOCUS_INTERVAL_MS = 2000L;
35 | static final Collection FOCUS_MODES_CALLING_AF;
36 |
37 | static {
38 | FOCUS_MODES_CALLING_AF = new ArrayList(2);
39 | FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
40 | FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
41 | }
42 |
43 | boolean stopped;
44 | boolean focusing;
45 | final boolean useAutoFocus;
46 | final Camera camera;
47 | AsyncTask, ?, ?> outstandingTask;
48 |
49 | public AutoFocusManager(Context context, Camera camera) {
50 | this.camera = camera;
51 | String currentFocusMode = camera.getParameters().getFocusMode();
52 | useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
53 | Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
54 | start();
55 | }
56 |
57 | @Override
58 | public synchronized void onAutoFocus(boolean success, Camera theCamera) {
59 | focusing = false;
60 | autoFocusAgainLater();
61 | }
62 |
63 | @SuppressLint("NewApi")
64 | synchronized void autoFocusAgainLater() {
65 | if (!stopped && outstandingTask == null) {
66 | AutoFocusTask newTask = new AutoFocusTask();
67 | try {
68 | if (Build.VERSION.SDK_INT >= 11) {
69 | newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
70 | } else {
71 | newTask.execute();
72 | }
73 | outstandingTask = newTask;
74 | } catch (RejectedExecutionException ree) {
75 | Log.w(TAG, "Could not request auto focus", ree);
76 | }
77 | }
78 | }
79 |
80 | public synchronized void start() {
81 | if (useAutoFocus) {
82 | outstandingTask = null;
83 | if (!stopped && !focusing) {
84 | try {
85 | camera.autoFocus(this);
86 | focusing = true;
87 | } catch (RuntimeException re) {
88 | // Have heard RuntimeException reported in Android 4.0.x+;
89 | // continue?
90 | Log.w(TAG, "Unexpected exception while focusing", re);
91 | // Try again later to keep cycle going
92 | autoFocusAgainLater();
93 | }
94 | }
95 | }
96 | }
97 |
98 | synchronized void cancelOutstandingTask() {
99 | if (outstandingTask != null) {
100 | if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
101 | outstandingTask.cancel(true);
102 | }
103 | outstandingTask = null;
104 | }
105 | }
106 |
107 | public synchronized void stop() {
108 | stopped = true;
109 | if (useAutoFocus) {
110 | cancelOutstandingTask();
111 | // Doesn't hurt to call this even if not focusing
112 | try {
113 | camera.cancelAutoFocus();
114 | } catch (RuntimeException re) {
115 | // Have heard RuntimeException reported in Android 4.0.x+;
116 | // continue?
117 | Log.w(TAG, "Unexpected exception while cancelling focusing", re);
118 | }
119 | }
120 | }
121 |
122 | final class AutoFocusTask extends AsyncTask