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在多写一个自己的扫描界面就行了!
#项目截图 ![](https://github.com/liang530/ScanCode/raw/master/images/main.png)
![](https://github.com/liang530/ScanCode/raw/master/images/createCode.png)
![](https://github.com/liang530/ScanCode/raw/master/images/scanCode.png)
![](https://github.com/liang530/ScanCode/raw/master/images/scan2code.png)
![](https://github.com/liang530/ScanCode/raw/master/images/scan_bar_code.png)
![](https://github.com/liang530/ScanCode/raw/master/images/scan_photo.png)
================================================ 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 ================================================ ================================================ 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 { @Override protected Object doInBackground(Object... voids) { try { Thread.sleep(AUTO_FOCUS_INTERVAL_MS); } catch (InterruptedException e) { // continue } start(); return null; } } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/camera/CameraConfigurationManager.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.zxing.camera; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Point; import android.hardware.Camera; 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; /** * * 邮箱: 1076559197@qq.com | tauchen1990@gmail.com * * 作者: 陈涛 * * 日期: 2014年8月20日 * * 描述: 该类主要负责设置相机的参数信息,获取最佳的预览界面 * */ public final class CameraConfigurationManager { static final String TAG = "CameraConfiguration"; static final int MIN_PREVIEW_PIXELS = 480 * 320; static final double MAX_ASPECT_DISTORTION = 0.15; final Context context; // 屏幕分辨率 Point screenResolution; // 相机分辨率 Point cameraResolution; public CameraConfigurationManager(Context context) { this.context = context; } public void initFromCameraParameters(Camera camera) { Camera.Parameters parameters = camera.getParameters(); WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); Point theScreenResolution = new Point(); theScreenResolution = getDisplaySize(display); screenResolution = theScreenResolution; Log.i(TAG, "Screen resolution: " + screenResolution); /** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */ Point screenResolutionForCamera = new Point(); screenResolutionForCamera.x = screenResolution.x; screenResolutionForCamera.y = screenResolution.y; if (screenResolution.x < screenResolution.y) { screenResolutionForCamera.x = screenResolution.y; screenResolutionForCamera.y = screenResolution.x; } cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera); Log.i(TAG, "Camera resolution x: " + cameraResolution.x); Log.i(TAG, "Camera resolution y: " + cameraResolution.y); } @SuppressWarnings("deprecation") @SuppressLint("NewApi") Point getDisplaySize(final Display display) { final Point point = new Point(); try { display.getSize(point); } catch (NoSuchMethodError ignore) { point.x = display.getWidth(); point.y = 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; } Log.i(TAG, "Initial camera parameters: " + parameters.flatten()); if (safeMode) { Log.w(TAG, "In camera config safe mode -- most settings will not be honored"); } 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)) { Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + cameraResolution.y + ", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height); cameraResolution.x = afterSize.width; cameraResolution.y = afterSize.height; } /** 设置相机预览为竖屏 */ camera.setDisplayOrientation(90); } public Point getCameraResolution() { return cameraResolution; } public Point getScreenResolution() { return screenResolution; } /** * 从相机支持的分辨率中计算出最适合的预览界面尺寸 * * @param parameters * @param screenResolution * @return */ Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { List 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 supportedPreviewSizes = new ArrayList(rawSupportedSizes); Collections.sort(supportedPreviewSizes, new Comparator() { @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 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 shouquan_ic_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; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/camera/CameraManager.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.zxing.camera; import android.content.Context; import android.graphics.Point; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; import android.os.Handler; import android.util.Log; import android.view.SurfaceHolder; import java.io.IOException; import com.liang.scancode.zxing.camera.open.OpenCameraInterface; /** * This object wraps the Camera service object and expects to be the only one * talking to it. The implementation encapsulates the steps needed to take * preview-sized images, which are used for both preview and decoding. * * @author dswitkin@google.com (Daniel Switkin) */ public class CameraManager { static final String TAG = CameraManager.class.getSimpleName(); final Context context; final CameraConfigurationManager configManager; Camera camera; AutoFocusManager autoFocusManager; boolean initialized; boolean previewing; int requestedCameraId = -1; /** * Preview frames are delivered here, which we pass on to the registered * handler. Make sure to clear the handler so it will only receive one * message. */ final PreviewCallback previewCallback; public CameraManager(Context context) { this.context = context; this.configManager = new CameraConfigurationManager(context); previewCallback = new PreviewCallback(configManager); } /** * Opens the camera driver and initializes the hardware parameters. * * @param holder * The surface object which the camera will draw preview frames * into. * @throws IOException * Indicates the camera driver failed to open. */ public synchronized void openDriver(SurfaceHolder holder) throws IOException { Camera theCamera = camera; if (theCamera == null) { if (requestedCameraId >= 0) { theCamera = OpenCameraInterface.open(requestedCameraId); } else { theCamera = OpenCameraInterface.open(); } if (theCamera == null) { throw new IOException(); } camera = theCamera; } theCamera.setPreviewDisplay(holder); if (!initialized) { initialized = true; configManager.initFromCameraParameters(theCamera); } Parameters parameters = theCamera.getParameters(); String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save // these, // temporarily try { configManager.setDesiredCameraParameters(theCamera, false); } catch (RuntimeException re) { // Driver failed Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters"); Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened); // Reset: if (parametersFlattened != null) { parameters = theCamera.getParameters(); parameters.unflatten(parametersFlattened); try { theCamera.setParameters(parameters); configManager.setDesiredCameraParameters(theCamera, true); } catch (RuntimeException re2) { // Well, darn. Give up Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration"); } } } } public synchronized boolean isOpen() { return camera != null; } /** * Closes the camera driver if still in use. */ public synchronized void closeDriver() { if (camera != null) { camera.release(); camera = null; // Make sure to clear these each time we close the camera, so that // any scanning rect // requested by intent is forgotten. } } /** * Asks the camera hardware to begin drawing preview frames to the screen. */ public synchronized void startPreview() { Camera theCamera = camera; if (theCamera != null && !previewing) { theCamera.startPreview(); previewing = true; autoFocusManager = new AutoFocusManager(context, camera); } } /** * Tells the camera to stop drawing preview frames. */ public synchronized void stopPreview() { if (autoFocusManager != null) { autoFocusManager.stop(); autoFocusManager = null; } if (camera != null && previewing) { camera.stopPreview(); previewCallback.setHandler(null, 0); previewing = false; } } /** * A single preview frame will be returned to the handler supplied. The data * will arrive as byte[] in the message.obj field, with width and height * encoded as message.arg1 and message.arg2, respectively. * * @param handler * The handler to send the message to. * @param message * The what field of the message to be sent. */ public synchronized void requestPreviewFrame(Handler handler, int message) { Camera theCamera = camera; if (theCamera != null && previewing) { previewCallback.setHandler(handler, message); theCamera.setOneShotPreviewCallback(previewCallback); } } /** * Allows third party apps to specify the camera ID, rather than determine * it automatically based on available cameras and their orientation. * * @param cameraId * camera ID of the camera to use. A negative value means * "no preference". */ public synchronized void setManualCameraId(int cameraId) { requestedCameraId = cameraId; } /** * 获取相机分辨率 * * @return */ public Point getCameraResolution() { return configManager.getCameraResolution(); } public Size getPreviewSize() { if (null != camera) { return camera.getParameters().getPreviewSize(); } return null; } /** * 打开闪光灯 */ public void openLight() { if (camera != null) { Parameters parameter = camera.getParameters(); parameter.setFlashMode(Parameters.FLASH_MODE_TORCH); camera.setParameters(parameter); } } /** * 关闭闪光灯 */ public void offLight() { if (camera != null) { Parameters parameter = camera.getParameters(); parameter.setFlashMode(Parameters.FLASH_MODE_OFF); camera.setParameters(parameter); } } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/camera/PreviewCallback.java ================================================ /* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.liang.scancode.zxing.camera; import android.graphics.Point; import android.hardware.Camera; import android.os.Handler; import android.os.Message; import android.util.Log; public class PreviewCallback implements Camera.PreviewCallback { static final String TAG = PreviewCallback.class.getSimpleName(); final CameraConfigurationManager configManager; Handler previewHandler; int previewMessage; public PreviewCallback(CameraConfigurationManager configManager) { this.configManager = configManager; } public void setHandler(Handler previewHandler, int previewMessage) { this.previewHandler = previewHandler; this.previewMessage = previewMessage; } @Override public void onPreviewFrame(byte[] data, Camera camera) { Point cameraResolution = configManager.getCameraResolution(); Handler thePreviewHandler = previewHandler; if (cameraResolution != null && thePreviewHandler != null) { Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, cameraResolution.y, data); message.sendToTarget(); previewHandler = null; } else { Log.d(TAG, "Got preview callback, but no handler or resolution available"); } } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/camera/open/OpenCameraInterface.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.open; import android.hardware.Camera; import android.util.Log; public class OpenCameraInterface { static final String TAG = OpenCameraInterface.class.getName(); /** * Opens the requested camera with {@link Camera#open(int)}, if one exists. * * @param cameraId * camera ID of the camera to use. A negative value means * "no preference" * @return handle to {@link Camera} that was opened */ public static Camera open(int cameraId) { int numCameras = Camera.getNumberOfCameras(); if (numCameras == 0) { Log.w(TAG, "No cameras!"); return null; } boolean explicitRequest = cameraId >= 0; if (!explicitRequest) { // Select a camera if no explicit camera requested int index = 0; while (index < numCameras) { Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); Camera.getCameraInfo(index, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { break; } index++; } cameraId = index; } Camera camera; if (cameraId < numCameras) { Log.i(TAG, "Opening camera #" + cameraId); camera = Camera.open(cameraId); } else { if (explicitRequest) { Log.w(TAG, "Requested camera does not exist: " + cameraId); camera = null; } else { Log.i(TAG, "No camera facing back; returning camera #0"); camera = Camera.open(0); } } return camera; } /** * Opens a rear-facing camera with {@link Camera#open(int)}, if one exists, * or opens camera 0. * * @return handle to {@link Camera} that was opened */ public static Camera open() { return open(-1); } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/DecodeFormatManager.java ================================================ /* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.liang.scancode.zxing.decode; import com.google.zxing.BarcodeFormat; import java.util.Collection; import java.util.EnumSet; import java.util.Set; public class DecodeFormatManager { // 1D解码 static final Set PRODUCT_FORMATS; static final Set INDUSTRIAL_FORMATS; static final Set ONE_D_FORMATS; // 二维码解码 static final Set QR_CODE_FORMATS; static { PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8, BarcodeFormat.RSS_14, BarcodeFormat.RSS_EXPANDED); INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat.CODE_128, BarcodeFormat.ITF, BarcodeFormat.CODABAR); ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS); ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS); QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE); } public static Collection getQrCodeFormats() { return QR_CODE_FORMATS; } public static Collection getBarCodeFormats() { return ONE_D_FORMATS; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/DecodeHandler.java ================================================ /* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.liang.scancode.zxing.decode; import android.graphics.Bitmap; import android.graphics.Rect; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.PlanarYUVLuminanceSource; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.common.HybridBinarizer; import com.liang.scancode.R; import com.liang.scancode.zxing.ScanManager; import java.io.ByteArrayOutputStream; import java.util.Map; public class DecodeHandler extends Handler { final ScanManager scanManager; final MultiFormatReader multiFormatReader; boolean running = true; public DecodeHandler(ScanManager scanManager, Map hints) { multiFormatReader = new MultiFormatReader(); multiFormatReader.setHints(hints); this.scanManager = scanManager; } @Override public void handleMessage(Message message) { if (!running) { return; } switch (message.what) { case R.id.decode: decode((byte[]) message.obj, message.arg1, message.arg2); break; case R.id.quit: running = false; Looper.myLooper().quit(); break; } } /** * Decode the data within the viewfinder rectangle, and time how long it * took. For efficiency, reuse the same reader objects from one decode to * the next. * * @param data * The YUV preview frame. * @param width * The width of the preview frame. * @param height * The height of the preview frame. */ void decode(byte[] data, int width, int height) { Size size = scanManager.getCameraManager().getPreviewSize(); // 这里需要将获取的data翻转一下,因为相机默认拿的的横屏的数据 byte[] rotatedData = new byte[data.length]; for (int y = 0; y < size.height; y++) { for (int x = 0; x < size.width; x++) rotatedData[x * size.height + size.height - y - 1] = data[x + y * size.width]; } // 宽高也要调整 int tmp = size.width; size.width = size.height; size.height = tmp; Result rawResult = null; PlanarYUVLuminanceSource source = buildLuminanceSource(rotatedData, size.width, size.height); if (source != null) { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); try { rawResult = multiFormatReader.decodeWithState(bitmap); } catch (ReaderException re) { // continue } finally { multiFormatReader.reset(); } } Handler handler = scanManager.getHandler(); if (rawResult != null) { // Don't log the barcode contents for security. if (handler != null) { Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult); Bundle bundle = new Bundle(); bundleThumbnail(source, bundle); message.setData(bundle); message.sendToTarget(); } } else { if (handler != null) { Message message = Message.obtain(handler, R.id.decode_failed); message.sendToTarget(); } } } static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) { int[] pixels = source.renderThumbnail(); int width = source.getThumbnailWidth(); int height = source.getThumbnailHeight(); Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); ByteArrayOutputStream out = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out); bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray()); } /** * A factory method to build the appropriate LuminanceSource object based on * the format of the preview buffers, as described by Camera.Parameters. * * @param data * A preview frame. * @param width * The width of the image. * @param height * The height of the image. * @return A PlanarYUVLuminanceSource instance. */ public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { Rect rect = scanManager.getCropRect(); if (rect == null) { return null; } // Go ahead and assume it's YUV rather than die. return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height(), false); } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/DecodeThread.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.zxing.decode; import android.os.Handler; import android.os.Looper; import com.google.zxing.BarcodeFormat; import com.google.zxing.DecodeHintType; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.concurrent.CountDownLatch; import com.liang.scancode.zxing.ScanManager; /** * This thread does shouquan_ic_all the heavy lifting of decoding the images. * * @author dswitkin@google.com (Daniel Switkin) */ public class DecodeThread extends Thread { public static final String BARCODE_BITMAP = "barcode_bitmap"; public static final int BARCODE_MODE = 0X100; public static final int QRCODE_MODE = 0X200; public static final int ALL_MODE = 0X300; final ScanManager scanManager; static Map hints; Handler handler; final CountDownLatch handlerInitLatch; public DecodeThread(ScanManager scanManager, int decodeMode) { this.scanManager = scanManager; handlerInitLatch = new CountDownLatch(1); hints = new EnumMap(DecodeHintType.class); Collection decodeFormats = new ArrayList(); decodeFormats.addAll(EnumSet.of(BarcodeFormat.AZTEC)); decodeFormats.addAll(EnumSet.of(BarcodeFormat.PDF_417)); switch (decodeMode) { case BARCODE_MODE: decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); break; case QRCODE_MODE: decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); break; case ALL_MODE: decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); break; default: break; } hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); } public Handler getHandler() { try { handlerInitLatch.await(); } catch (InterruptedException ie) { // continue? } return handler; } @Override public void run() { Looper.prepare(); handler = new DecodeHandler(scanManager, hints); handlerInitLatch.countDown(); Looper.loop(); } public static Map getHints() { return hints; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/PhotoScanHandler.java ================================================ package com.liang.scancode.zxing.decode; import android.os.Bundle; import android.os.Handler; import android.os.Message; import com.google.zxing.Result; import com.liang.scancode.zxing.ScanManager; public class PhotoScanHandler extends Handler{ public final static int PHOTODECODEERROR=0; public final static int PHOTODECODEOK=1; ScanManager scanManager; public PhotoScanHandler(ScanManager scanManager) { this.scanManager=scanManager; } @Override public void handleMessage(Message message) { switch (message.what) { case PHOTODECODEERROR: scanManager.handleDecodeError((Exception)message.obj); break; case PHOTODECODEOK: Bundle bundle = message.getData(); scanManager.handleDecode((Result) message.obj, bundle); break; default: break; } } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/RGBLuminanceSource.java ================================================ package com.liang.scancode.zxing.decode; /* * Copyright 2009 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import com.google.zxing.LuminanceSource; import java.io.FileNotFoundException; /** * This class is used to help decode images from files which arrive as RGB data * from Android bitmaps. It does not support cropping or rotation. * * @author dswitkin@google.com (Daniel Switkin) */ public final class RGBLuminanceSource extends LuminanceSource { final byte[] luminances; public RGBLuminanceSource(String path) throws FileNotFoundException { this(loadBitmap(path)); } public RGBLuminanceSource(Bitmap bitmap) { super(bitmap.getWidth(), bitmap.getHeight()); int width = bitmap.getWidth(); int height = bitmap.getHeight(); int[] pixels = new int[width * height]; bitmap.getPixels(pixels, 0, width, 0, 0, width, height); // In order to measure pure decoding speed, we convert the entire image // to a greyscale array // up front, which is the same as the Y channel of the // YUVLuminanceSource in the real app. luminances = new byte[width * height]; for (int y = 0; y < height; y++) { int offset = y * width; for (int x = 0; x < width; x++) { int pixel = pixels[offset + x]; int r = (pixel >> 16) & 0xff; int g = (pixel >> 8) & 0xff; int b = pixel & 0xff; if (r == g && g == b) { // Image is already greyscale, so pick any channel. luminances[offset + x] = (byte) r; } else { // Calculate luminance cheaply, favoring green. luminances[offset + x] = (byte) ((r + g + g + b) >> 2); } } } } @Override public byte[] getRow(int y, byte[] row) { if (y < 0 || y >= getHeight()) { throw new IllegalArgumentException( "Requested row is outside the image: " + y); } int width = getWidth(); if (row == null || row.length < width) { row = new byte[width]; } System.arraycopy(luminances, y * width, row, 0, width); return row; } // Since this class does not support cropping, the underlying byte array // already contains // exactly what the caller is asking for, so give it to them without a copy. @Override public byte[] getMatrix() { return luminances; } static Bitmap loadBitmap(String path) throws FileNotFoundException { Bitmap bitmap = BitmapFactory.decodeFile(path); if (bitmap == null) { throw new FileNotFoundException("Couldn't open " + path); } return bitmap; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/decode/Utils.java ================================================ package com.liang.scancode.zxing.decode; import android.annotation.SuppressLint; import android.content.ContentUris; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Matrix; import android.media.ExifInterface; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.DocumentsContract; import android.provider.MediaStore; import java.io.IOException; public class Utils { @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; } 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; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri .getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri .getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri .getAuthority()); } /** * 读取图片属性:旋转的角度 * @param path 图片绝对路径 * @return degree旋转的角度 */ public static int readPictureDegree(String path) { int degree = 0; try { ExifInterface exifInterface = new ExifInterface(path); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace(); } return degree; } /* * 旋转图片 * @param angle * @param bitmap * @return Bitmap */ public static Bitmap rotaingImageView(int angle , Bitmap bitmap) { //旋转图片 动作 Matrix matrix = new Matrix();; matrix.postRotate(angle); System.out.println("angle2=" + angle); // 创建新的图片 Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/encode/EncodingHandler.java ================================================ package com.liang.scancode.zxing.encode; import android.graphics.Bitmap; import android.util.Log; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import java.io.UnsupportedEncodingException; import java.util.Hashtable; /** * @author 刘红亮 2015年4月29日 下午3:27:08 * 用于生成二维码 */ public final class EncodingHandler { static final int BLACK = 0xff000000; static final int WHITE = 0xFFFFFFFF; /** * 生成二维码图片 * * @param str 要往二维码中写入的内容,需要utf-8格式 * @param widthAndHeight 图片的宽高,正方形 * @return 返回一个二维码bitmap * @throws WriterException * @throws UnsupportedEncodingException */ public static Bitmap create2Code(String str, int widthAndHeight) throws WriterException, UnsupportedEncodingException { BitMatrix matrix = new MultiFormatWriter().encode(str, BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight, getEncodeHintMap()); return BitMatrixToBitmap(matrix); } /** * 生成条形码图片 * @param str 要往二维码中写入的内容,需要utf-8格式 * @param width 图片的宽 * @param height 图片的高 * @return 返回一个条形bitmap * @throws Exception */ public static Bitmap createBarCode(String str, Integer width, Integer height) throws Exception{ BitMatrix bitMatrix = new MultiFormatWriter().encode(str, BarcodeFormat.CODE_128, width, height, getEncodeHintMap()); return BitMatrixToBitmap(bitMatrix); } /** * 获得设置好的编码参数 * @return 编码参数 */ private static Hashtable getEncodeHintMap() { Hashtable hints= new Hashtable(); //设置编码为utf-8 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); // 设置QR二维码的纠错级别——这里选择最高H级别 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); return hints; } /** * BitMatrix转换成Bitmap * * @param matrix * @return */ private static Bitmap BitMatrixToBitmap(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); int[] pixels = new int[width * height]; for (int y = 0; y < height; y++) { int offset = y * width; for (int x = 0; x < width; x++) { if(matrix.get(x,y)){ pixels[offset + x] =BLACK; //上面图案的颜色 }else{ pixels[offset + x] =WHITE;//底色 } } } Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, width, 0, 0, width, height); Log.e("hongliang","width:"+bitmap.getWidth()+" height:"+bitmap.getHeight()); return bitmap; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/utils/AppliationUtil.java ================================================ package com.liang.scancode.zxing.utils; /** * Created by 刘红亮 on 2015/7/23 22:35. */ public class AppliationUtil { //应用程序最大可用内存 public static int MAX_MEMORY = ((int) Runtime.getRuntime().maxMemory())/1024/1024; //应用程序已获得内存 public static long TOTAL_MEMORY = ((int) Runtime.getRuntime().totalMemory())/1024/1024; //应用程序已获得内存中未使用内存 public static long FREE_MEMORY = ((int) Runtime.getRuntime().freeMemory())/1024/1024; } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/utils/BeepManager.java ================================================ /* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.liang.scancode.zxing.utils; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Vibrator; import android.preference.PreferenceManager; import android.util.Log; import com.liang.scancode.R; import java.io.Closeable; import java.io.IOException; /** */ public class BeepManager implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, Closeable { static final String TAG = BeepManager.class.getSimpleName(); static final float BEEP_VOLUME = 0.10f; static final long VIBRATE_DURATION = 200L; final Activity activity; MediaPlayer mediaPlayer; boolean playBeep; boolean vibrate; public BeepManager(Activity activity) { this.activity = activity; this.mediaPlayer = null; updatePrefs(); } synchronized void updatePrefs() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); playBeep = shouldBeep(prefs, activity); vibrate = true; if (playBeep && mediaPlayer == null) { // The volume on STREAM_SYSTEM is not adjustable, and users found it // too loud, // so we now play on the music stream. activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); mediaPlayer = buildMediaPlayer(activity); } } public synchronized void playBeepSoundAndVibrate() { if (playBeep && mediaPlayer != null) { mediaPlayer.start(); } if (vibrate) { Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(VIBRATE_DURATION); } } static boolean shouldBeep(SharedPreferences prefs, Context activity) { boolean shouldPlayBeep = true; if (shouldPlayBeep) { // See if sound settings overrides this AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { shouldPlayBeep = false; } } return shouldPlayBeep; } MediaPlayer buildMediaPlayer(Context activity) { MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnErrorListener(this); try { AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep); try { mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); } finally { file.close(); } mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); mediaPlayer.prepare(); return mediaPlayer; } catch (IOException ioe) { Log.w(TAG, ioe); mediaPlayer.release(); return null; } } @Override public void onCompletion(MediaPlayer mp) { // When the beep has finished playing, rewind to queue up another one. mp.seekTo(0); } @Override public synchronized boolean onError(MediaPlayer mp, int what, int extra) { if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { // we are finished, so put up an appropriate error toast if required // and finish activity.finish(); } else { // possibly media player error, so release and recreate mp.release(); mediaPlayer = null; updatePrefs(); } return true; } @Override public synchronized void close() { if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/utils/BitmapUtil.java ================================================ package com.liang.scancode.zxing.utils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; /** * Created by 刘红亮 on 2015/7/23 22:30. */ public class BitmapUtil { /** * * @param options * @param reqWidth * @param reqHeight * @return */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // 源图片的高度和宽度 final int height = options.outHeight; final int width = options.outWidth; //压缩当前图片占用内存不超过应用可用内存的3/4 //ARGB_8888 一个像素占用4个字节 //1兆字节(mb)=1048576字节(b) while(reqHeight*reqWidth*4> AppliationUtil.FREE_MEMORY*1048576/4*3){ reqHeight-=50; reqWidth-=50; } int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // 计算出实际宽高和目标宽高的比率 final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高 // 一定都会大于等于目标的宽和高。 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } if(inSampleSize==0) return 1; Log.e("hongliang","inSampleSize=" + inSampleSize); return inSampleSize; } public static Bitmap decodeBitmapFromPath(String photo_path, int reqWidth, int reqHeight) { // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小 final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; Bitmap scanBitmap = BitmapFactory.decodeFile(photo_path, options); // 调用上面定义的方法计算inSampleSize值 options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // 使用获取到的inSampleSize值再次解析图片 options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(photo_path, options); } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/utils/CaptureActivityHandler.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.zxing.utils; import android.os.Bundle; import android.os.Handler; import android.os.Message; import com.google.zxing.Result; import com.liang.scancode.R; import com.liang.scancode.zxing.ScanManager; import com.liang.scancode.zxing.camera.CameraManager; import com.liang.scancode.zxing.decode.DecodeThread; /** * This class handles shouquan_ic_all the messaging which comprises the state machine for * capture. * * @author dswitkin@google.com (Daniel Switkin) */ public class CaptureActivityHandler extends Handler { final ScanManager scanManager; final DecodeThread decodeThread; final CameraManager cameraManager; State state; enum State { PREVIEW, SUCCESS, DONE } public CaptureActivityHandler(ScanManager scanManager, CameraManager cameraManager, int decodeMode) { this.scanManager = scanManager; decodeThread = new DecodeThread(scanManager, decodeMode); decodeThread.start(); state = State.SUCCESS; // Start ourselves capturing previews and decoding. this.cameraManager = cameraManager; cameraManager.startPreview(); restartPreviewAndDecode(); } @Override public void handleMessage(Message message) { switch (message.what) { case R.id.restart_preview: restartPreviewAndDecode(); break; case R.id.decode_succeeded: state = State.SUCCESS; Bundle bundle = message.getData(); scanManager.handleDecode((Result) message.obj, bundle); break; case R.id.decode_failed: // We're decoding as fast as possible, so when one decode fails, // start another. state = State.PREVIEW; cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); break; case R.id.decode_error: scanManager.handleDecodeError((Exception)message.obj); break; case R.id.return_scan_result: // activity.setResult(Activity.RESULT_OK, (Intent) message.obj); // activity.finish(); break; } } public void quitSynchronously() { state = State.DONE; cameraManager.stopPreview(); Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); quit.sendToTarget(); try { // Wait at most half a shouquan_icon_second; should be enough time, and onPause() // will timeout quickly decodeThread.join(500L); } catch (InterruptedException e) { // continue } // Be absolutely sure we don't send any queued up messages removeMessages(R.id.decode_succeeded); removeMessages(R.id.decode_failed); } void restartPreviewAndDecode() { if (state == State.SUCCESS) { state = State.PREVIEW; cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); } } /** * * @return 返回当前扫描状态,是否可扫描,State.PREVIEW 是可扫描状态 */ public boolean isScanning() { if(state == State.PREVIEW){ return true; } return false; } } ================================================ FILE: app/src/main/java/com/liang/scancode/zxing/utils/InactivityTimer.java ================================================ /* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.liang.scancode.zxing.utils; import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.BatteryManager; import android.os.Build; import android.util.Log; /** * Finishes an activity after a period of inactivity if the device is on battery * power. */ public class InactivityTimer { static final String TAG = InactivityTimer.class.getSimpleName(); static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L; Activity activity; BroadcastReceiver powerStatusReceiver; boolean registered; AsyncTask inactivityTask; public InactivityTimer(Activity activity) { this.activity = activity; powerStatusReceiver = new PowerStatusReceiver(); registered = false; onActivity(); } @SuppressLint("NewApi") public synchronized void onActivity() { cancel(); inactivityTask = new InactivityAsyncTask(); if (Build.VERSION.SDK_INT >= 11) { inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { inactivityTask.execute(); } } public synchronized void onPause() { cancel(); if (registered) { activity.unregisterReceiver(powerStatusReceiver); registered = false; } else { Log.w(TAG, "PowerStatusReceiver was never registered?"); } } public synchronized void onResume() { if (registered) { Log.w(TAG, "PowerStatusReceiver was already registered?"); } else { activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); registered = true; } onActivity(); } synchronized void cancel() { AsyncTask task = inactivityTask; if (task != null) { task.cancel(true); inactivityTask = null; } } public void shutdown() { cancel(); } class PowerStatusReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { // 0 indicates that we're on battery boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0; if (onBatteryNow) { InactivityTimer.this.onActivity(); } else { InactivityTimer.this.cancel(); } } } } class InactivityAsyncTask extends AsyncTask { @Override protected Object doInBackground(Object... objects) { try { Thread.sleep(INACTIVITY_DELAY_MS); Log.i(TAG, "Finishing activity due to inactivity"); activity.finish(); } catch (InterruptedException e) { // continue without killing } return null; } } } ================================================ FILE: app/src/main/res/anim/popupwin_nearperson_exit.xml ================================================ ================================================ FILE: app/src/main/res/anim/popupwin_nearperson_show.xml ================================================ ================================================ FILE: app/src/main/res/anim/shouquan_dialog_enter.xml ================================================ ================================================ FILE: app/src/main/res/anim/shouquan_dialog_exit.xml ================================================ ================================================ FILE: app/src/main/res/drawable/base_bgpic.xml ================================================ ================================================ FILE: app/src/main/res/drawable/rescan_shape_button.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shouquan_bg_loading_dialog_shape.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shouquan_loading_dialog_progressbar.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shouquan_qrcode_g_gallery.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shouquan_qrcode_ic_back.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shouquan_qrcode_s_flashgun.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_create_code.xml ================================================