├── .gitignore ├── .idea ├── caches │ └── build_file_checksums.ser ├── codeStyles │ └── Project.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── winton │ │ └── easyzxing │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── winton │ │ │ └── easyzxing │ │ │ └── ManiActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── winton │ └── easyzxing │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screen ├── screen.jpg └── screen1.jpg ├── settings.gradle └── zxing ├── .gitignore ├── build.gradle ├── libs └── zxing_core_3.0.1.jar ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── zxing │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── zxing │ │ ├── DisplayUtil.java │ │ ├── UriUtils.java │ │ ├── activity │ │ ├── CaptureActivity.java │ │ ├── CaptureFragment.java │ │ ├── CodeUtils.java │ │ ├── ScanActivity.java │ │ └── ZXingLibrary.java │ │ ├── camera │ │ ├── AutoFocusCallback.java │ │ ├── BitmapLuminanceSource.java │ │ ├── CameraConfigurationManager.java │ │ ├── CameraManager.java │ │ ├── FlashlightManager.java │ │ ├── PlanarYUVLuminanceSource.java │ │ └── PreviewCallback.java │ │ ├── decoding │ │ ├── CaptureActivityHandler.java │ │ ├── DecodeFormatManager.java │ │ ├── DecodeHandler.java │ │ ├── DecodeThread.java │ │ ├── FinishListener.java │ │ ├── InactivityTimer.java │ │ └── Intents.java │ │ ├── encoding │ │ └── EncodingHandler.java │ │ └── view │ │ ├── ViewfinderResultPointCallback.java │ │ └── ViewfinderView.java └── res │ ├── drawable │ └── scan_light.png │ ├── layout │ ├── act_scan.xml │ ├── camera.xml │ ├── fragment_capture.xml │ └── layout_scan.xml │ ├── mipmap-xhdpi │ ├── ic_back.png │ └── iv_light_switch.png │ ├── mipmap │ ├── ic_back.png │ └── iv_light_switch.png │ ├── raw │ └── beep.ogg │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml └── test └── java └── com └── zxing └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /.idea/caches/build_file_checksums.ser: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/.idea/caches/build_file_checksums.ser -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyZxing 2 | 基于Zxing二次开发封装,可直接使用,封装了权限/相册等等 3 | 4 | 5 | ## 集成方式 6 | 7 | ### gradle 8 | Step 1. Add the JitPack repository to your build file 9 | Add it in your root build.gradle at the end of repositories: 10 | ``` 11 | allprojects { 12 | repositories { 13 | ... 14 | maven { url 'https://jitpack.io' } 15 | } 16 | } 17 | ``` 18 | Step 2. Add the dependency 19 | ``` 20 | dependencies { 21 | implementation 'com.github.wintonBy:EasyZxing:1.0' 22 | } 23 | ``` 24 | ##使用方法 25 | ### 直接调用(不需要相册选择) 26 | ``` 27 | public static void start(Activity context,int req) 28 | ``` 29 | ### 直接调用(需要相册选择) 30 | ``` 31 | public static void start(Activity context,int req,boolean needAlbum) 32 | ``` 33 | ## 界面简介,通用 34 |
35 | 36 |
37 | 38 | ## 手电筒开关会在光线若的情况下自动打开 39 | 40 | 41 | ## 读取相册 使用相机权限也已经封装 42 | 43 | ## 参数 44 | ### req:回调结果code 45 | ### needAlbum:是否需要相册选择 46 | 47 | ### 请求示例 48 | ``` 49 | ScanActivity.start(ManiActivity.this,123); 50 | ``` 51 | ### 回调处理 52 | ``` 53 | @Override 54 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 55 | super.onActivityResult(requestCode, resultCode, data); 56 | switch (requestCode){ 57 | case 123: 58 | if(resultCode == RESULT_OK){ 59 | String type = data.getStringExtra(CodeUtils.RESULT_TYPE); 60 | String result = data.getStringExtra(CodeUtils.RESULT_STRING); 61 | if(type.equals(CodeUtils.RESULT_SUCCESS)){ 62 | Toast.makeText(this,result,Toast.LENGTH_SHORT).show(); 63 | }else { 64 | Toast.makeText(this,"扫描失败",Toast.LENGTH_SHORT).show(); 65 | } 66 | } 67 | break; 68 | default:break; 69 | } 70 | 71 | } 72 | ``` 73 | 74 | ## License 75 | Copyright 2018 Winton 76 | 77 | Licensed under the Apache License, Version 2.0 (the "License"); 78 | you may not use this file except in compliance with the License. 79 | You may obtain a copy of the License at 80 | 81 | http://www.apache.org/licenses/LICENSE-2.0 82 | 83 | Unless required by applicable law or agreed to in writing, software 84 | distributed under the License is distributed on an "AS IS" BASIS, 85 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 86 | See the License for the specific language governing permissions and 87 | limitations under the License. 88 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.winton.easyzxing" 7 | minSdkVersion 15 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'com.android.support:appcompat-v7:28.0.0-rc02' 24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 25 | testImplementation 'junit:junit:4.12' 26 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 28 | 29 | implementation 'com.github.wintonBy:EasyZxing:1.0' 30 | } 31 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/winton/easyzxing/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.winton.easyzxing 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.winton.easyzxing", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/winton/easyzxing/ManiActivity.java: -------------------------------------------------------------------------------- 1 | package com.winton.easyzxing; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import com.zxing.activity.CodeUtils; 12 | import com.zxing.activity.ScanActivity; 13 | 14 | import javax.xml.transform.Result; 15 | 16 | /** 17 | * @author: winton 18 | * @time: 2018/9/6 下午6:24 19 | * @desc: 描述 20 | */ 21 | public class ManiActivity extends AppCompatActivity { 22 | 23 | TextView textView ; 24 | 25 | @Override 26 | protected void onCreate(@Nullable Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | textView = new TextView(this); 29 | textView.setText("点击这里"); 30 | setContentView(textView); 31 | textView.setOnClickListener(new View.OnClickListener() { 32 | @Override 33 | public void onClick(View v) { 34 | ScanActivity.start(ManiActivity.this,123); 35 | } 36 | }); 37 | } 38 | 39 | 40 | @Override 41 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 42 | super.onActivityResult(requestCode, resultCode, data); 43 | switch (requestCode){ 44 | case 123: 45 | if(resultCode == RESULT_OK){ 46 | int type = data.getIntExtra(CodeUtils.RESULT_TYPE,-1); 47 | String result = data.getStringExtra(CodeUtils.RESULT_STRING); 48 | if(type == CodeUtils.RESULT_SUCCESS){ 49 | Toast.makeText(this,result,Toast.LENGTH_SHORT).show(); 50 | }else { 51 | Toast.makeText(this,"扫描失败",Toast.LENGTH_SHORT).show(); 52 | } 53 | } 54 | break; 55 | default:break; 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | EasyZxing 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/winton/easyzxing/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.winton.easyzxing 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | jcenter() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.1.4' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | maven { url 'https://jitpack.io' } 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Sep 06 16:55:30 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /screen/screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/screen/screen.jpg -------------------------------------------------------------------------------- /screen/screen1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/screen/screen1.jpg -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app',':zxing' 2 | -------------------------------------------------------------------------------- /zxing/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /zxing/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | minSdkVersion 15 7 | targetSdkVersion 28 8 | versionCode 1 9 | versionName "1.0" 10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | 25 | implementation 'com.android.support:appcompat-v7:28.0.0-rc02' 26 | 27 | // 二维码扫描 28 | implementation files('libs/zxing_core_3.0.1.jar') 29 | } 30 | -------------------------------------------------------------------------------- /zxing/libs/zxing_core_3.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/libs/zxing_core_3.0.1.jar -------------------------------------------------------------------------------- /zxing/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /zxing/src/androidTest/java/com/zxing/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zxing; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zxing.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /zxing/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 21 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/DisplayUtil.java: -------------------------------------------------------------------------------- 1 | package com.zxing; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by aaron on 16/8/3. 7 | */ 8 | public class DisplayUtil 9 | { 10 | 11 | public static int screenWidthPx; //屏幕宽 px 12 | public static int screenhightPx; //屏幕高 px 13 | public static float density;//屏幕密度 14 | public static int densityDPI;//屏幕密度 15 | public static float screenWidthDip;// dp单位 16 | public static float screenHightDip;// dp单位 17 | 18 | 19 | 20 | /** 21 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 22 | */ 23 | public static int dip2px(Context context, float dpValue) { 24 | final float scale = context.getResources().getDisplayMetrics().density; 25 | return (int) (dpValue * scale + 0.5f); 26 | } 27 | 28 | /** 29 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 30 | */ 31 | public static int px2dip(Context context, float pxValue) { 32 | final float scale = context.getResources().getDisplayMetrics().density; 33 | return (int) (pxValue / scale + 0.5f); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/UriUtils.java: -------------------------------------------------------------------------------- 1 | package com.zxing; 2 | 3 | import android.content.ContentUris; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Build; 8 | import android.os.Environment; 9 | import android.provider.DocumentsContract; 10 | import android.provider.MediaStore; 11 | 12 | /** 13 | * @author: winton 14 | * @time: 2018/8/10 15:19 15 | * @package: com.android.wasu.enjoytv.utils 16 | * @project: wasuenjoytv 17 | * @mail: 18 | * @describe: 一句话描述 19 | */ 20 | public class UriUtils { 21 | 22 | public static String getPath(final Context context, final Uri uri) { 23 | 24 | final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; 25 | 26 | // DocumentProvider 27 | if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { 28 | // ExternalStorageProvider 29 | if (isExternalStorageDocument(uri)) { 30 | final String docId = DocumentsContract.getDocumentId(uri); 31 | final String[] split = docId.split(":"); 32 | final String type = split[0]; 33 | 34 | if ("primary".equalsIgnoreCase(type)) { 35 | return Environment.getExternalStorageDirectory() + "/" 36 | + split[1]; 37 | } 38 | 39 | // TODO handle non-primary volumes 40 | } 41 | // DownloadsProvider 42 | else if (isDownloadsDocument(uri)) { 43 | 44 | final String id = DocumentsContract.getDocumentId(uri); 45 | final Uri contentUri = ContentUris.withAppendedId( 46 | Uri.parse("content://downloads/public_downloads"), 47 | Long.valueOf(id)); 48 | 49 | return getDataColumn(context, contentUri, null, null); 50 | } 51 | // MediaProvider 52 | else if (isMediaDocument(uri)) { 53 | final String docId = DocumentsContract.getDocumentId(uri); 54 | final String[] split = docId.split(":"); 55 | final String type = split[0]; 56 | 57 | Uri contentUri = null; 58 | if ("image".equals(type)) { 59 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 60 | } else if ("video".equals(type)) { 61 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 62 | } else if ("audio".equals(type)) { 63 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 64 | } 65 | 66 | final String selection = "_id=?"; 67 | final String[] selectionArgs = new String[] { split[1] }; 68 | 69 | return getDataColumn(context, contentUri, selection, 70 | selectionArgs); 71 | } 72 | } 73 | // MediaStore (and general) 74 | else if ("content".equalsIgnoreCase(uri.getScheme())) { 75 | return getDataColumn(context, uri, null, null); 76 | } 77 | // File 78 | else if ("file".equalsIgnoreCase(uri.getScheme())) { 79 | return uri.getPath(); 80 | } 81 | 82 | return null; 83 | } 84 | 85 | /** 86 | * Get the value of the data column for this Uri. This is useful for 87 | * MediaStore Uris, and other file-based ContentProviders. 88 | * 89 | * @param context 90 | * The context. 91 | * @param uri 92 | * The Uri to query. 93 | * @param selection 94 | * (Optional) Filter used in the query. 95 | * @param selectionArgs 96 | * (Optional) Selection arguments used in the query. 97 | * @return The value of the _data column, which is typically a file path. 98 | */ 99 | public static String getDataColumn(Context context, Uri uri, 100 | String selection, String[] selectionArgs) { 101 | 102 | Cursor cursor = null; 103 | final String column = "_data"; 104 | final String[] projection = { column }; 105 | 106 | try { 107 | cursor = context.getContentResolver().query(uri, projection, 108 | selection, selectionArgs, null); 109 | if (cursor != null && cursor.moveToFirst()) { 110 | final int column_index = cursor.getColumnIndexOrThrow(column); 111 | return cursor.getString(column_index); 112 | } 113 | } finally { 114 | if (cursor != null) 115 | cursor.close(); 116 | } 117 | return null; 118 | } 119 | 120 | /** 121 | * @param uri 122 | * The Uri to check. 123 | * @return Whether the Uri authority is ExternalStorageProvider. 124 | */ 125 | public static boolean isExternalStorageDocument(Uri uri) { 126 | return "com.android.externalstorage.documents".equals(uri 127 | .getAuthority()); 128 | } 129 | 130 | /** 131 | * @param uri 132 | * The Uri to check. 133 | * @return Whether the Uri authority is DownloadsProvider. 134 | */ 135 | public static boolean isDownloadsDocument(Uri uri) { 136 | return "com.android.providers.downloads.documents".equals(uri 137 | .getAuthority()); 138 | } 139 | 140 | /** 141 | * @param uri 142 | * The Uri to check. 143 | * @return Whether the Uri authority is MediaProvider. 144 | */ 145 | public static boolean isMediaDocument(Uri uri) { 146 | return "com.android.providers.media.documents".equals(uri 147 | .getAuthority()); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/activity/CaptureActivity.java: -------------------------------------------------------------------------------- 1 | package com.zxing.activity; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Bitmap; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | 9 | import com.zxing.R; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | 15 | /** 16 | * Initial the camera 17 | *

18 | * 默认的二维码扫描Activity 19 | */ 20 | public class CaptureActivity extends AppCompatActivity { 21 | 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.camera); 28 | CaptureFragment captureFragment = new CaptureFragment(); 29 | captureFragment.setAnalyzeCallback(analyzeCallback); 30 | getSupportFragmentManager().beginTransaction().replace(R.id.fl_zxing_container, captureFragment).commit(); 31 | captureFragment.setCameraInitCallBack(new CaptureFragment.CameraInitCallBack() { 32 | @Override 33 | public void callBack(Exception e) { 34 | if (e == null) { 35 | 36 | } else { 37 | Log.e("TAG", "callBack: ", e); 38 | } 39 | } 40 | }); 41 | 42 | } 43 | 44 | /** 45 | * 二维码解析回调函数 46 | */ 47 | CodeUtils.AnalyzeCallback analyzeCallback = new CodeUtils.AnalyzeCallback() { 48 | @Override 49 | public void onAnalyzeSuccess(Bitmap mBitmap, String result) { 50 | Intent resultIntent = new Intent(); 51 | Bundle bundle = new Bundle(); 52 | bundle.putInt(CodeUtils.RESULT_TYPE, CodeUtils.RESULT_SUCCESS); 53 | bundle.putString(CodeUtils.RESULT_STRING, result); 54 | resultIntent.putExtras(bundle); 55 | CaptureActivity.this.setResult(RESULT_OK, resultIntent); 56 | CaptureActivity.this.finish(); 57 | } 58 | 59 | @Override 60 | public void onAnalyzeFailed() { 61 | Intent resultIntent = new Intent(); 62 | Bundle bundle = new Bundle(); 63 | bundle.putInt(CodeUtils.RESULT_TYPE, CodeUtils.RESULT_FAILED); 64 | bundle.putString(CodeUtils.RESULT_STRING, ""); 65 | resultIntent.putExtras(bundle); 66 | CaptureActivity.this.setResult(RESULT_OK, resultIntent); 67 | CaptureActivity.this.finish(); 68 | } 69 | }; 70 | } -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/activity/CaptureFragment.java: -------------------------------------------------------------------------------- 1 | package com.zxing.activity; 2 | 3 | import android.content.res.AssetFileDescriptor; 4 | import android.graphics.Bitmap; 5 | import android.hardware.Camera; 6 | import android.media.AudioManager; 7 | import android.media.MediaPlayer; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | import android.os.Vibrator; 11 | import android.support.annotation.Nullable; 12 | import android.support.v4.app.Fragment; 13 | import android.text.TextUtils; 14 | import android.view.LayoutInflater; 15 | import android.view.SurfaceHolder; 16 | import android.view.SurfaceView; 17 | import android.view.View; 18 | import android.view.ViewGroup; 19 | 20 | import com.google.zxing.BarcodeFormat; 21 | import com.google.zxing.Result; 22 | import com.zxing.R; 23 | import com.zxing.camera.CameraManager; 24 | import com.zxing.decoding.CaptureActivityHandler; 25 | import com.zxing.decoding.InactivityTimer; 26 | import com.zxing.view.ViewfinderView; 27 | 28 | import java.io.IOException; 29 | import java.util.Vector; 30 | 31 | /** 32 | * 自定义实现的扫描Fragment 33 | */ 34 | public class CaptureFragment extends Fragment implements SurfaceHolder.Callback { 35 | 36 | private CaptureActivityHandler handler; 37 | private ViewfinderView viewfinderView; 38 | private boolean hasSurface; 39 | private Vector decodeFormats; 40 | private String characterSet; 41 | private InactivityTimer inactivityTimer; 42 | private MediaPlayer mediaPlayer; 43 | private boolean playBeep; 44 | private static final float BEEP_VOLUME = 0.10f; 45 | private boolean vibrate; 46 | private SurfaceView surfaceView; 47 | private SurfaceHolder surfaceHolder; 48 | private CodeUtils.AnalyzeCallback analyzeCallback; 49 | private Camera camera; 50 | 51 | @Override 52 | public void onCreate(@Nullable Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | CameraManager.init(getActivity().getApplication()); 55 | 56 | hasSurface = false; 57 | inactivityTimer = new InactivityTimer(this.getActivity()); 58 | } 59 | 60 | @Nullable 61 | @Override 62 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 63 | 64 | Bundle bundle = getArguments(); 65 | View view = null; 66 | if (bundle != null) { 67 | int layoutId = bundle.getInt(CodeUtils.LAYOUT_ID); 68 | if (layoutId != -1) { 69 | view = inflater.inflate(layoutId, null); 70 | } 71 | } 72 | 73 | if (view == null) { 74 | view = inflater.inflate(R.layout.fragment_capture, null); 75 | } 76 | 77 | viewfinderView = (ViewfinderView) view.findViewById(R.id.viewfinder_view); 78 | surfaceView = (SurfaceView) view.findViewById(R.id.preview_view); 79 | surfaceHolder = surfaceView.getHolder(); 80 | 81 | return view; 82 | } 83 | 84 | @Override 85 | public void onResume() { 86 | super.onResume(); 87 | if (hasSurface) { 88 | initCamera(surfaceHolder); 89 | } else { 90 | surfaceHolder.addCallback(this); 91 | surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 92 | } 93 | decodeFormats = null; 94 | characterSet = null; 95 | 96 | playBeep = true; 97 | AudioManager audioService = (AudioManager) getActivity().getSystemService(getActivity().AUDIO_SERVICE); 98 | if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { 99 | playBeep = false; 100 | } 101 | initBeepSound(); 102 | vibrate = true; 103 | } 104 | 105 | @Override 106 | public void onPause() { 107 | super.onPause(); 108 | if (handler != null) { 109 | handler.quitSynchronously(); 110 | handler = null; 111 | } 112 | CameraManager.get().closeDriver(); 113 | } 114 | 115 | @Override 116 | public void onDestroy() { 117 | super.onDestroy(); 118 | inactivityTimer.shutdown(); 119 | } 120 | 121 | 122 | /** 123 | * Handler scan result 124 | * 125 | * @param result 126 | * @param barcode 127 | */ 128 | public void handleDecode(Result result, Bitmap barcode) { 129 | inactivityTimer.onActivity(); 130 | playBeepSoundAndVibrate(); 131 | 132 | if (result == null || TextUtils.isEmpty(result.getText())) { 133 | if (analyzeCallback != null) { 134 | analyzeCallback.onAnalyzeFailed(); 135 | } 136 | } else { 137 | if (analyzeCallback != null) { 138 | analyzeCallback.onAnalyzeSuccess(barcode, result.getText()); 139 | } 140 | } 141 | } 142 | 143 | private void initCamera(SurfaceHolder surfaceHolder) { 144 | try { 145 | CameraManager.get().openDriver(surfaceHolder); 146 | camera = CameraManager.get().getCamera(); 147 | } catch (Exception e) { 148 | if (callBack != null) { 149 | callBack.callBack(e); 150 | } 151 | return; 152 | } 153 | if (callBack != null) { 154 | callBack.callBack(null); 155 | } 156 | if (handler == null) { 157 | handler = new CaptureActivityHandler(this, decodeFormats, characterSet, viewfinderView); 158 | } 159 | } 160 | 161 | @Override 162 | public void surfaceChanged(SurfaceHolder holder, int format, int width, 163 | int height) { 164 | 165 | } 166 | 167 | @Override 168 | public void surfaceCreated(SurfaceHolder holder) { 169 | if (!hasSurface) { 170 | hasSurface = true; 171 | initCamera(holder); 172 | } 173 | 174 | } 175 | 176 | @Override 177 | public void surfaceDestroyed(SurfaceHolder holder) { 178 | hasSurface = false; 179 | if (camera != null) { 180 | if (camera != null && CameraManager.get().isPreviewing()) { 181 | if (!CameraManager.get().isUseOneShotPreviewCallback()) { 182 | camera.setPreviewCallback(null); 183 | } 184 | camera.stopPreview(); 185 | CameraManager.get().getPreviewCallback().setHandler(null, 0); 186 | CameraManager.get().getAutoFocusCallback().setHandler(null, 0); 187 | CameraManager.get().setPreviewing(false); 188 | } 189 | } 190 | } 191 | 192 | public Handler getHandler() { 193 | return handler; 194 | } 195 | 196 | public void drawViewfinder() { 197 | viewfinderView.drawViewfinder(); 198 | 199 | } 200 | 201 | private void initBeepSound() { 202 | if (playBeep && mediaPlayer == null) { 203 | // The volume on STREAM_SYSTEM is not adjustable, and users found it 204 | // too loud, 205 | // so we now play on the music stream. 206 | getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC); 207 | mediaPlayer = new MediaPlayer(); 208 | mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 209 | mediaPlayer.setOnCompletionListener(beepListener); 210 | 211 | AssetFileDescriptor file = getResources().openRawResourceFd( 212 | R.raw.beep); 213 | try { 214 | mediaPlayer.setDataSource(file.getFileDescriptor(), 215 | file.getStartOffset(), file.getLength()); 216 | file.close(); 217 | mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); 218 | mediaPlayer.prepare(); 219 | } catch (IOException e) { 220 | mediaPlayer = null; 221 | } 222 | } 223 | } 224 | 225 | private static final long VIBRATE_DURATION = 200L; 226 | 227 | private void playBeepSoundAndVibrate() { 228 | if (playBeep && mediaPlayer != null) { 229 | mediaPlayer.start(); 230 | } 231 | if (vibrate) { 232 | Vibrator vibrator = (Vibrator) getActivity().getSystemService(getActivity().VIBRATOR_SERVICE); 233 | vibrator.vibrate(VIBRATE_DURATION); 234 | } 235 | } 236 | 237 | /** 238 | * When the beep has finished playing, rewind to queue up another one. 239 | */ 240 | private final MediaPlayer.OnCompletionListener beepListener = new MediaPlayer.OnCompletionListener() { 241 | public void onCompletion(MediaPlayer mediaPlayer) { 242 | mediaPlayer.seekTo(0); 243 | } 244 | }; 245 | 246 | public CodeUtils.AnalyzeCallback getAnalyzeCallback() { 247 | return analyzeCallback; 248 | } 249 | 250 | public void setAnalyzeCallback(CodeUtils.AnalyzeCallback analyzeCallback) { 251 | this.analyzeCallback = analyzeCallback; 252 | } 253 | 254 | @Nullable 255 | CameraInitCallBack callBack; 256 | 257 | /** 258 | * Set callback for Camera check whether Camera init success or not. 259 | */ 260 | public void setCameraInitCallBack(CameraInitCallBack callBack) { 261 | this.callBack = callBack; 262 | } 263 | 264 | interface CameraInitCallBack { 265 | /** 266 | * Callback for Camera init result. 267 | * @param e If is's null,means success.otherwise Camera init failed with the Exception. 268 | */ 269 | void callBack(Exception e); 270 | } 271 | 272 | 273 | } 274 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/activity/CodeUtils.java: -------------------------------------------------------------------------------- 1 | package com.zxing.activity; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.hardware.Camera; 8 | import android.os.Bundle; 9 | import android.text.TextUtils; 10 | 11 | import com.google.zxing.BarcodeFormat; 12 | import com.google.zxing.BinaryBitmap; 13 | import com.google.zxing.DecodeHintType; 14 | import com.google.zxing.EncodeHintType; 15 | import com.google.zxing.MultiFormatReader; 16 | import com.google.zxing.Result; 17 | import com.google.zxing.WriterException; 18 | import com.google.zxing.common.BitMatrix; 19 | import com.google.zxing.common.HybridBinarizer; 20 | import com.google.zxing.qrcode.QRCodeWriter; 21 | import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; 22 | import com.zxing.camera.BitmapLuminanceSource; 23 | import com.zxing.camera.CameraManager; 24 | import com.zxing.decoding.DecodeFormatManager; 25 | 26 | import java.util.Hashtable; 27 | import java.util.Objects; 28 | import java.util.Vector; 29 | 30 | /** 31 | * Created by aaron on 16/7/27. 32 | * 二维码扫描工具类 33 | */ 34 | public class CodeUtils { 35 | 36 | public static final String RESULT_TYPE = "result_type"; 37 | public static final String RESULT_STRING = "result_string"; 38 | public static final int RESULT_SUCCESS = 1; 39 | public static final int RESULT_FAILED = 2; 40 | 41 | public static final String LAYOUT_ID = "layout_id"; 42 | 43 | 44 | 45 | /** 46 | * 解析二维码图片工具类 47 | * @param analyzeCallback 48 | */ 49 | public static void analyzeBitmap(String path, AnalyzeCallback analyzeCallback) { 50 | 51 | /** 52 | * 首先判断图片的大小,若图片过大,则执行图片的裁剪操作,防止OOM 53 | */ 54 | BitmapFactory.Options options = new BitmapFactory.Options(); 55 | options.inJustDecodeBounds = true; // 先获取原大小 56 | Bitmap mBitmap = BitmapFactory.decodeFile(path, options); 57 | options.inJustDecodeBounds = false; // 获取新的大小 58 | 59 | int sampleSize = (int) (options.outHeight / (float) 400); 60 | 61 | if (sampleSize <= 0) 62 | sampleSize = 1; 63 | options.inSampleSize = sampleSize; 64 | mBitmap = BitmapFactory.decodeFile(path, options); 65 | 66 | MultiFormatReader multiFormatReader = new MultiFormatReader(); 67 | 68 | // 解码的参数 69 | Hashtable hints = new Hashtable(2); 70 | // 可以解析的编码类型 71 | Vector decodeFormats = new Vector(); 72 | if (decodeFormats == null || decodeFormats.isEmpty()) { 73 | decodeFormats = new Vector(); 74 | 75 | // 这里设置可扫描的类型,我这里选择了都支持 76 | decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); 77 | decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); 78 | decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); 79 | } 80 | hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); 81 | // 设置继续的字符编码格式为UTF8 82 | // hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); 83 | // 设置解析配置参数 84 | multiFormatReader.setHints(hints); 85 | 86 | // 开始对图像资源解码 87 | Result rawResult = null; 88 | try { 89 | rawResult = multiFormatReader.decodeWithState(new BinaryBitmap(new HybridBinarizer(new BitmapLuminanceSource(mBitmap)))); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | 94 | if (rawResult != null) { 95 | if (analyzeCallback != null) { 96 | analyzeCallback.onAnalyzeSuccess(mBitmap, rawResult.getText()); 97 | } 98 | } else { 99 | if (analyzeCallback != null) { 100 | analyzeCallback.onAnalyzeFailed(); 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * 生成二维码图片 107 | * @param text 108 | * @param w 109 | * @param h 110 | * @param logo 111 | * @return 112 | */ 113 | public static Bitmap createImage(String text,int w,int h,Bitmap logo) { 114 | if (TextUtils.isEmpty(text)) { 115 | return null; 116 | } 117 | try { 118 | Bitmap scaleLogo = getScaleLogo(logo,w,h); 119 | 120 | int offsetX = w / 2; 121 | int offsetY = h / 2; 122 | 123 | int scaleWidth = 0; 124 | int scaleHeight = 0; 125 | if (scaleLogo != null) { 126 | scaleWidth = scaleLogo.getWidth(); 127 | scaleHeight = scaleLogo.getHeight(); 128 | offsetX = (w - scaleWidth) / 2; 129 | offsetY = (h - scaleHeight) / 2; 130 | } 131 | Hashtable hints = new Hashtable(); 132 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 133 | //容错级别 134 | hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); 135 | //设置空白边距的宽度 136 | hints.put(EncodeHintType.MARGIN, 0); 137 | BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, w, h, hints); 138 | int[] pixels = new int[w * h]; 139 | for (int y = 0; y < h; y++) { 140 | for (int x = 0; x < w; x++) { 141 | if(x >= offsetX && x < offsetX + scaleWidth && y>= offsetY && y < offsetY + scaleHeight){ 142 | int pixel = scaleLogo.getPixel(x-offsetX,y-offsetY); 143 | if(pixel == 0){ 144 | if(bitMatrix.get(x, y)){ 145 | pixel = 0xff000000; 146 | }else{ 147 | pixel = 0xffffffff; 148 | } 149 | } 150 | pixels[y * w + x] = pixel; 151 | }else{ 152 | if (bitMatrix.get(x, y)) { 153 | pixels[y * w + x] = 0xff000000; 154 | } else { 155 | pixels[y * w + x] = 0xffffffff; 156 | } 157 | } 158 | } 159 | } 160 | Bitmap bitmap = Bitmap.createBitmap(w, h, 161 | Bitmap.Config.ARGB_8888); 162 | bitmap.setPixels(pixels, 0, w, 0, 0, w, h); 163 | return bitmap; 164 | } catch (WriterException e) { 165 | e.printStackTrace(); 166 | } 167 | return null; 168 | } 169 | 170 | private static Bitmap getScaleLogo(Bitmap logo,int w,int h){ 171 | if(logo == null)return null; 172 | Matrix matrix = new Matrix(); 173 | float scaleFactor = Math.min(w * 1.0f / 5 / logo.getWidth(), h * 1.0f / 5 /logo.getHeight()); 174 | matrix.postScale(scaleFactor,scaleFactor); 175 | Bitmap result = Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true); 176 | return result; 177 | } 178 | 179 | /** 180 | * 解析二维码结果 181 | */ 182 | public interface AnalyzeCallback{ 183 | 184 | public void onAnalyzeSuccess(Bitmap mBitmap, String result); 185 | 186 | public void onAnalyzeFailed(); 187 | } 188 | 189 | 190 | /** 191 | * 为CaptureFragment设置layout参数 192 | * @param captureFragment 193 | * @param layoutId 194 | */ 195 | public static void setFragmentArgs(CaptureFragment captureFragment, int layoutId) { 196 | if (captureFragment == null || layoutId == -1) { 197 | return; 198 | } 199 | 200 | Bundle bundle = new Bundle(); 201 | bundle.putInt(LAYOUT_ID, layoutId); 202 | captureFragment.setArguments(bundle); 203 | } 204 | 205 | public static void isLightEnable(boolean isEnable) { 206 | if (isEnable) { 207 | Camera camera = CameraManager.get().getCamera(); 208 | if (camera != null) { 209 | Camera.Parameters parameter = camera.getParameters(); 210 | parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 211 | camera.setParameters(parameter); 212 | } 213 | } else { 214 | Camera camera = CameraManager.get().getCamera(); 215 | if (camera != null) { 216 | Camera.Parameters parameter = camera.getParameters(); 217 | parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 218 | camera.setParameters(parameter); 219 | } 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/activity/ScanActivity.java: -------------------------------------------------------------------------------- 1 | package com.zxing.activity; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.pm.PackageManager; 9 | import android.graphics.Bitmap; 10 | import android.hardware.Sensor; 11 | import android.hardware.SensorEvent; 12 | import android.hardware.SensorEventListener; 13 | import android.hardware.SensorManager; 14 | import android.net.Uri; 15 | import android.os.Bundle; 16 | import android.support.annotation.NonNull; 17 | import android.support.annotation.Nullable; 18 | import android.support.v4.app.ActivityCompat; 19 | import android.support.v7.app.AppCompatActivity; 20 | import android.view.View; 21 | import android.view.WindowManager; 22 | import android.view.animation.AlphaAnimation; 23 | import android.widget.LinearLayout; 24 | import android.widget.Toast; 25 | 26 | import com.zxing.R; 27 | import com.zxing.UriUtils; 28 | import com.zxing.camera.CameraManager; 29 | 30 | /** 31 | * @author: winton 32 | * @time: 2018/9/6 下午5:13 33 | * @desc: 描述 34 | */ 35 | public class ScanActivity extends AppCompatActivity implements View.OnClickListener{ 36 | 37 | private CaptureFragment mFragment; 38 | private CodeUtils.AnalyzeCallback mCallback; 39 | private LinearLayout mLightLayout; 40 | 41 | private boolean isLightOpen = false; 42 | 43 | 44 | private static final int REQ_CAMERA = 0x101; 45 | private static final int REQ_PHOTO = 0x102; 46 | private static final int REQ_CHOOSE_PHOTO = 0x103; 47 | 48 | 49 | public static void start(Activity context,int req){ 50 | Intent intent = new Intent(context,ScanActivity.class); 51 | context.startActivityForResult(intent,req); 52 | } 53 | 54 | public static void start(Activity context,int req,boolean needAlbum){ 55 | Intent intent = new Intent(context,ScanActivity.class); 56 | intent.putExtra("needAlbum",needAlbum); 57 | context.startActivityForResult(intent,req); 58 | } 59 | 60 | 61 | @Override 62 | protected void onCreate(@Nullable Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | setContentView(R.layout.act_scan); 65 | checkCameraPermission(); 66 | initListener(); 67 | initData(); 68 | } 69 | 70 | private void initListener(){ 71 | findViewById(R.id.iv_back).setOnClickListener(this); 72 | boolean needAlbum = getIntent().getBooleanExtra("needAlbum",false); 73 | if(needAlbum){ 74 | findViewById(R.id.tv_ablumn).setOnClickListener(this); 75 | findViewById(R.id.tv_ablumn).setVisibility(View.INVISIBLE); 76 | } 77 | 78 | 79 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 80 | checkCameraPermission(); 81 | CameraManager.init(getApplicationContext()); 82 | SensorManager mSM = (SensorManager) getSystemService(SENSOR_SERVICE); 83 | Sensor mLightSensor = mSM.getDefaultSensor(Sensor.TYPE_LIGHT); 84 | mSM.registerListener(new SensorEventListener() { 85 | @Override 86 | public void onSensorChanged(SensorEvent event) { 87 | //获取光线强度 88 | float lux = event.values[0]; 89 | if(lux > 10){ 90 | if(!isLightOpen && mLightLayout.getVisibility() == View.VISIBLE){ 91 | mLightLayout.setVisibility(View.GONE); 92 | } 93 | }else { 94 | //光线强度小于阈值时,显示电灯开关 95 | if(mLightLayout.getVisibility() != View.VISIBLE){ 96 | mLightLayout.setVisibility(View.VISIBLE); 97 | showLightAnim(mLightLayout); 98 | } 99 | } 100 | } 101 | @Override 102 | public void onAccuracyChanged(Sensor sensor, int accuracy) { 103 | 104 | } 105 | },mLightSensor,SensorManager.SENSOR_DELAY_NORMAL); 106 | 107 | } 108 | 109 | /** 110 | * 灯展示出来时动画 111 | * @param view 112 | */ 113 | private void showLightAnim(View view){ 114 | AlphaAnimation alphaAnimation = new AlphaAnimation(0,1); 115 | alphaAnimation.setDuration(500); 116 | view.startAnimation(alphaAnimation); 117 | } 118 | 119 | private void initData(){ 120 | mFragment = new CaptureFragment(); 121 | mLightLayout = findViewById(R.id.ll_light); 122 | mLightLayout.setOnClickListener(this); 123 | CodeUtils.setFragmentArgs(mFragment,R.layout.layout_scan); 124 | mCallback = new CodeUtils.AnalyzeCallback() { 125 | @Override 126 | public void onAnalyzeSuccess(Bitmap mBitmap, String result) { 127 | Intent intent= new Intent(); 128 | Bundle bundle = new Bundle(); 129 | bundle.putInt(CodeUtils.RESULT_TYPE,CodeUtils.RESULT_SUCCESS); 130 | bundle.putString(CodeUtils.RESULT_STRING,result); 131 | intent.putExtras(bundle); 132 | setResult(RESULT_OK,intent); 133 | finish(); 134 | } 135 | 136 | @Override 137 | public void onAnalyzeFailed() { 138 | Intent intent= new Intent(); 139 | Bundle bundle = new Bundle(); 140 | bundle.putInt(CodeUtils.RESULT_TYPE,CodeUtils.RESULT_FAILED); 141 | intent.putExtras(bundle); 142 | setResult(RESULT_OK,intent); 143 | finish(); 144 | } 145 | }; 146 | 147 | mFragment.setAnalyzeCallback(mCallback); 148 | getSupportFragmentManager().beginTransaction().replace(R.id.fl_my_container,mFragment).commit(); 149 | } 150 | 151 | @Override 152 | public void onClick(View v) { 153 | int id = v.getId(); 154 | if(id == R.id.iv_back){ 155 | this.finish(); 156 | return; 157 | } 158 | if(id == R.id.tv_ablumn){ 159 | checkAlbumPermission(); 160 | return; 161 | } 162 | if(id == R.id.ll_light){ 163 | openLight(!isLightOpen); 164 | return; 165 | } 166 | } 167 | 168 | /** 169 | * 控制闪光灯的打开关闭 170 | * @param isLightOpen 171 | */ 172 | private void openLight(boolean isLightOpen) { 173 | this.isLightOpen = isLightOpen; 174 | CodeUtils.isLightEnable(isLightOpen); 175 | } 176 | 177 | 178 | @Override 179 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 180 | super.onActivityResult(requestCode, resultCode, data); 181 | switch (requestCode){ 182 | case REQ_CHOOSE_PHOTO: 183 | if(resultCode == RESULT_OK){ 184 | String path = ""; 185 | Uri uri = data.getData(); 186 | try { 187 | path = UriUtils.getPath(getApplicationContext(),uri); 188 | CodeUtils.analyzeBitmap(path,mCallback); 189 | } catch (Exception e) { 190 | e.printStackTrace(); 191 | } 192 | } 193 | break; 194 | default:break; 195 | } 196 | } 197 | 198 | /** 199 | * 检查相机权限 200 | */ 201 | @TargetApi(23) 202 | private void checkCameraPermission(){ 203 | int code = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA); 204 | if(code == PackageManager.PERMISSION_GRANTED){ 205 | return; 206 | } 207 | if(shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)){ 208 | Toast.makeText(getApplication(),"拒绝此权限将导致功能不可用!",Toast.LENGTH_SHORT).show(); 209 | ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},REQ_CAMERA); 210 | }else { 211 | ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},REQ_CAMERA); 212 | } 213 | } 214 | 215 | /** 216 | * 查看相册权限 217 | */ 218 | @TargetApi(23) 219 | private void checkAlbumPermission(){ 220 | int code = ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE); 221 | if(code == PackageManager.PERMISSION_GRANTED){ 222 | choosePhoto(); 223 | return; 224 | } 225 | if(shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)){ 226 | Toast.makeText(getApplication(),"拒绝此权限将导致功能不可用!",Toast.LENGTH_SHORT).show(); 227 | ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQ_PHOTO); 228 | }else { 229 | ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},REQ_PHOTO); 230 | } 231 | } 232 | 233 | @Override 234 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 235 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 236 | switch (requestCode){ 237 | case REQ_CAMERA: 238 | break; 239 | case REQ_PHOTO: 240 | if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ 241 | choosePhoto(); 242 | } 243 | break; 244 | default: 245 | break; 246 | } 247 | } 248 | 249 | /** 250 | * 跳转相册选择 251 | */ 252 | private void choosePhoto() { 253 | Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 254 | intent.setType("image/*"); 255 | startActivityForResult(intent,REQ_CHOOSE_PHOTO); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/activity/ZXingLibrary.java: -------------------------------------------------------------------------------- 1 | package com.zxing.activity; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | 6 | import com.zxing.DisplayUtil; 7 | 8 | 9 | /** 10 | * Created by aaron on 16/9/7. 11 | */ 12 | 13 | public class ZXingLibrary { 14 | 15 | public static void initDisplayOpinion(Context context) { 16 | if (context == null) { 17 | return; 18 | } 19 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 20 | DisplayUtil.density = dm.density; 21 | DisplayUtil.densityDPI = dm.densityDpi; 22 | DisplayUtil.screenWidthPx = dm.widthPixels; 23 | DisplayUtil.screenhightPx = dm.heightPixels; 24 | DisplayUtil.screenWidthDip = DisplayUtil.px2dip(context, dm.widthPixels); 25 | DisplayUtil.screenHightDip = DisplayUtil.px2dip(context, dm.heightPixels); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/AutoFocusCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.camera; 18 | 19 | import android.hardware.Camera; 20 | import android.os.Handler; 21 | import android.os.Message; 22 | import android.util.Log; 23 | 24 | public final class AutoFocusCallback implements Camera.AutoFocusCallback { 25 | 26 | private static final String TAG = AutoFocusCallback.class.getSimpleName(); 27 | 28 | private static final long AUTOFOCUS_INTERVAL_MS = 1500L; 29 | 30 | private Handler autoFocusHandler; 31 | private int autoFocusMessage; 32 | 33 | public void setHandler(Handler autoFocusHandler, int autoFocusMessage) { 34 | this.autoFocusHandler = autoFocusHandler; 35 | this.autoFocusMessage = autoFocusMessage; 36 | } 37 | 38 | public void onAutoFocus(boolean success, Camera camera) { 39 | if (autoFocusHandler != null) { 40 | Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success); 41 | autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS); 42 | autoFocusHandler = null; 43 | } else { 44 | Log.d(TAG, "Got auto-focus callback, but no handler for it"); 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/BitmapLuminanceSource.java: -------------------------------------------------------------------------------- 1 | package com.zxing.camera; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.google.zxing.LuminanceSource; 6 | 7 | /** 8 | * Created by aaron on 16/7/27. 9 | * 自定义解析Bitmap LuminanceSource 10 | */ 11 | public class BitmapLuminanceSource extends LuminanceSource { 12 | 13 | private byte bitmapPixels[]; 14 | 15 | public BitmapLuminanceSource(Bitmap bitmap) { 16 | super(bitmap.getWidth(), bitmap.getHeight()); 17 | 18 | // 首先,要取得该图片的像素数组内容 19 | int[] data = new int[bitmap.getWidth() * bitmap.getHeight()]; 20 | this.bitmapPixels = new byte[bitmap.getWidth() * bitmap.getHeight()]; 21 | bitmap.getPixels(data, 0, getWidth(), 0, 0, getWidth(), getHeight()); 22 | 23 | // 将int数组转换为byte数组,也就是取像素值中蓝色值部分作为辨析内容 24 | for (int i = 0; i < data.length; i++) { 25 | this.bitmapPixels[i] = (byte) data[i]; 26 | } 27 | } 28 | 29 | @Override 30 | public byte[] getMatrix() { 31 | // 返回我们生成好的像素数据 32 | return bitmapPixels; 33 | } 34 | 35 | @Override 36 | public byte[] getRow(int y, byte[] row) { 37 | // 这里要得到指定行的像素数据 38 | System.arraycopy(bitmapPixels, y * getWidth(), row, 0, getWidth()); 39 | return row; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/CameraConfigurationManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.camera; 18 | 19 | import android.content.Context; 20 | import android.graphics.Point; 21 | import android.hardware.Camera; 22 | import android.os.Build; 23 | import android.util.Log; 24 | import android.view.Display; 25 | import android.view.WindowManager; 26 | 27 | import java.util.regex.Pattern; 28 | 29 | final class CameraConfigurationManager { 30 | 31 | private static final String TAG = CameraConfigurationManager.class.getSimpleName(); 32 | 33 | private static final int TEN_DESIRED_ZOOM = 27; 34 | private static final int DESIRED_SHARPNESS = 30; 35 | 36 | private static final Pattern COMMA_PATTERN = Pattern.compile(","); 37 | 38 | private final Context context; 39 | private Point screenResolution; 40 | private Point cameraResolution; 41 | private int previewFormat; 42 | private String previewFormatString; 43 | 44 | CameraConfigurationManager(Context context) { 45 | this.context = context; 46 | } 47 | 48 | /** 49 | * Reads, one time, values from the camera that are needed by the app. 50 | */ 51 | void initFromCameraParameters(Camera camera) { 52 | Camera.Parameters parameters = camera.getParameters(); 53 | previewFormat = parameters.getPreviewFormat(); 54 | previewFormatString = parameters.get("preview-format"); 55 | Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString); 56 | WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 57 | Display display = manager.getDefaultDisplay(); 58 | screenResolution = new Point(display.getWidth(), display.getHeight()); 59 | Log.d(TAG, "Screen resolution: " + screenResolution); 60 | 61 | Point screenResolutionForCamera = new Point(); 62 | screenResolutionForCamera.x = screenResolution.x; 63 | screenResolutionForCamera.y = screenResolution.y; 64 | // preview size is always something like 480*320, other 320*480 65 | if (screenResolution.x < screenResolution.y) { 66 | screenResolutionForCamera.x = screenResolution.y; 67 | screenResolutionForCamera.y = screenResolution.x; 68 | } 69 | Log.i("#########", "screenX:" + screenResolutionForCamera.x + " screenY:" + screenResolutionForCamera.y); 70 | cameraResolution = getCameraResolution(parameters, screenResolutionForCamera); 71 | 72 | // cameraResolution = getCameraResolution(parameters, screenResolution); 73 | Log.d(TAG, "Camera resolution: " + screenResolution); 74 | } 75 | 76 | /** 77 | * Sets the camera up to take preview images which are used for both preview and decoding. 78 | * We detect the preview format here so that buildLuminanceSource() can build an appropriate 79 | * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest, 80 | * and the planar Y can be used for barcode scanning without a copy in some cases. 81 | */ 82 | void setDesiredCameraParameters(Camera camera) { 83 | Camera.Parameters parameters = camera.getParameters(); 84 | Log.d(TAG, "Setting preview size: " + cameraResolution); 85 | parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); 86 | setFlash(parameters); 87 | setZoom(parameters); 88 | //setSharpness(parameters); 89 | //modify here 90 | camera.setDisplayOrientation(90); 91 | camera.setParameters(parameters); 92 | } 93 | 94 | Point getCameraResolution() { 95 | return cameraResolution; 96 | } 97 | 98 | Point getScreenResolution() { 99 | return screenResolution; 100 | } 101 | 102 | int getPreviewFormat() { 103 | return previewFormat; 104 | } 105 | 106 | String getPreviewFormatString() { 107 | return previewFormatString; 108 | } 109 | 110 | private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) { 111 | 112 | String previewSizeValueString = parameters.get("preview-size-values"); 113 | // saw this on Xperia 114 | if (previewSizeValueString == null) { 115 | previewSizeValueString = parameters.get("preview-size-value"); 116 | } 117 | 118 | Point cameraResolution = null; 119 | 120 | if (previewSizeValueString != null) { 121 | Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString); 122 | cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution); 123 | } 124 | 125 | if (cameraResolution == null) { 126 | // Ensure that the camera resolution is a multiple of 8, as the screen may not be. 127 | cameraResolution = new Point( 128 | (screenResolution.x >> 3) << 3, 129 | (screenResolution.y >> 3) << 3); 130 | } 131 | 132 | return cameraResolution; 133 | } 134 | 135 | private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) { 136 | int bestX = 0; 137 | int bestY = 0; 138 | int diff = Integer.MAX_VALUE; 139 | for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) { 140 | 141 | previewSize = previewSize.trim(); 142 | int dimPosition = previewSize.indexOf('x'); 143 | if (dimPosition < 0) { 144 | Log.w(TAG, "Bad preview-size: " + previewSize); 145 | continue; 146 | } 147 | 148 | int newX; 149 | int newY; 150 | try { 151 | newX = Integer.parseInt(previewSize.substring(0, dimPosition)); 152 | newY = Integer.parseInt(previewSize.substring(dimPosition + 1)); 153 | } catch (NumberFormatException nfe) { 154 | Log.w(TAG, "Bad preview-size: " + previewSize); 155 | continue; 156 | } 157 | 158 | int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y); 159 | if (newDiff == 0) { 160 | bestX = newX; 161 | bestY = newY; 162 | break; 163 | } else if (newDiff < diff) { 164 | bestX = newX; 165 | bestY = newY; 166 | diff = newDiff; 167 | } 168 | 169 | } 170 | 171 | if (bestX > 0 && bestY > 0) { 172 | return new Point(bestX, bestY); 173 | } 174 | return null; 175 | } 176 | 177 | private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) { 178 | int tenBestValue = 0; 179 | for (String stringValue : COMMA_PATTERN.split(stringValues)) { 180 | stringValue = stringValue.trim(); 181 | double value; 182 | try { 183 | value = Double.parseDouble(stringValue); 184 | } catch (NumberFormatException nfe) { 185 | return tenDesiredZoom; 186 | } 187 | int tenValue = (int) (10.0 * value); 188 | if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) { 189 | tenBestValue = tenValue; 190 | } 191 | } 192 | return tenBestValue; 193 | } 194 | 195 | private void setFlash(Camera.Parameters parameters) { 196 | // FIXME: This is a hack to turn the flash off on the Samsung Galaxy. 197 | // And this is a hack-hack to work around a different value on the Behold II 198 | // Restrict Behold II check to Cupcake, per Samsung's advice 199 | //if (Build.MODEL.contains("Behold II") && 200 | // CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) { 201 | if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake 202 | parameters.set("flash-value", 1); 203 | } else { 204 | parameters.set("flash-value", 2); 205 | } 206 | // This is the standard setting to turn the flash off that all devices should honor. 207 | parameters.set("flash-mode", "off"); 208 | } 209 | 210 | private void setZoom(Camera.Parameters parameters) { 211 | 212 | String zoomSupportedString = parameters.get("zoom-supported"); 213 | if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) { 214 | return; 215 | } 216 | 217 | int tenDesiredZoom = TEN_DESIRED_ZOOM; 218 | 219 | String maxZoomString = parameters.get("max-zoom"); 220 | if (maxZoomString != null) { 221 | try { 222 | int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString)); 223 | if (tenDesiredZoom > tenMaxZoom) { 224 | tenDesiredZoom = tenMaxZoom; 225 | } 226 | } catch (NumberFormatException nfe) { 227 | Log.w(TAG, "Bad max-zoom: " + maxZoomString); 228 | } 229 | } 230 | 231 | String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max"); 232 | if (takingPictureZoomMaxString != null) { 233 | try { 234 | int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString); 235 | if (tenDesiredZoom > tenMaxZoom) { 236 | tenDesiredZoom = tenMaxZoom; 237 | } 238 | } catch (NumberFormatException nfe) { 239 | Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString); 240 | } 241 | } 242 | 243 | String motZoomValuesString = parameters.get("mot-zoom-values"); 244 | if (motZoomValuesString != null) { 245 | tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom); 246 | } 247 | 248 | String motZoomStepString = parameters.get("mot-zoom-step"); 249 | if (motZoomStepString != null) { 250 | try { 251 | double motZoomStep = Double.parseDouble(motZoomStepString.trim()); 252 | int tenZoomStep = (int) (10.0 * motZoomStep); 253 | if (tenZoomStep > 1) { 254 | tenDesiredZoom -= tenDesiredZoom % tenZoomStep; 255 | } 256 | } catch (NumberFormatException nfe) { 257 | // continue 258 | } 259 | } 260 | 261 | // Set zoom. This helps encourage the user to pull back. 262 | // Some devices like the Behold have a zoom parameter 263 | if (maxZoomString != null || motZoomValuesString != null) { 264 | parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0)); 265 | } 266 | 267 | // Most devices, like the Hero, appear to expose this zoom parameter. 268 | // It takes on values like "27" which appears to mean 2.7x zoom 269 | if (takingPictureZoomMaxString != null) { 270 | parameters.set("taking-picture-zoom", tenDesiredZoom); 271 | } 272 | } 273 | 274 | public static int getDesiredSharpness() { 275 | return DESIRED_SHARPNESS; 276 | } 277 | 278 | } 279 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/CameraManager.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 | 17 | package com.zxing.camera; 18 | 19 | import android.content.Context; 20 | import android.graphics.PixelFormat; 21 | import android.graphics.Point; 22 | import android.graphics.Rect; 23 | import android.hardware.Camera; 24 | import android.os.Build; 25 | import android.os.Handler; 26 | import android.view.SurfaceHolder; 27 | 28 | import java.io.IOException; 29 | 30 | /** 31 | * This object wraps the Camera service object and expects to be the only one talking to it. The 32 | * implementation encapsulates the steps needed to take preview-sized images, which are used for 33 | * both preview and decoding. 34 | */ 35 | public final class CameraManager { 36 | 37 | private static final String TAG = CameraManager.class.getSimpleName(); 38 | 39 | public static int FRAME_WIDTH = -1; 40 | public static int FRAME_HEIGHT = -1; 41 | public static int FRAME_MARGINTOP = -1; 42 | 43 | private static CameraManager cameraManager; 44 | 45 | static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT 46 | 47 | static { 48 | int sdkInt; 49 | try { 50 | sdkInt = Integer.parseInt(Build.VERSION.SDK); 51 | } catch (NumberFormatException nfe) { 52 | // Just to be safe 53 | sdkInt = 10000; 54 | } 55 | SDK_INT = sdkInt; 56 | } 57 | 58 | private final Context context; 59 | private final CameraConfigurationManager configManager; 60 | private Camera camera; 61 | private Rect framingRect; 62 | private Rect framingRectInPreview; 63 | private boolean initialized; 64 | private boolean previewing; 65 | private final boolean useOneShotPreviewCallback; 66 | /** 67 | * Preview frames are delivered here, which we pass on to the registered handler. Make sure to 68 | * clear the handler so it will only receive one message. 69 | */ 70 | private final PreviewCallback previewCallback; 71 | /** 72 | * Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. 73 | */ 74 | private final AutoFocusCallback autoFocusCallback; 75 | 76 | /** 77 | * Initializes this static object with the Context of the calling Activity. 78 | * 79 | * @param context The Activity which wants to use the camera. 80 | */ 81 | public static void init(Context context) { 82 | if (cameraManager == null) { 83 | cameraManager = new CameraManager(context); 84 | } 85 | } 86 | 87 | /** 88 | * Gets the CameraManager singleton instance. 89 | * 90 | * @return A reference to the CameraManager singleton. 91 | */ 92 | public static CameraManager get() { 93 | return cameraManager; 94 | } 95 | 96 | private CameraManager(Context context) { 97 | 98 | this.context = context; 99 | this.configManager = new CameraConfigurationManager(context); 100 | 101 | // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older 102 | // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use 103 | // the more efficient one shot callback, as the older one can swamp the system and cause it 104 | // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK. 105 | //useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE; 106 | useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake 107 | 108 | previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback); 109 | autoFocusCallback = new AutoFocusCallback(); 110 | } 111 | 112 | /** 113 | * Opens the camera driver and initializes the hardware parameters. 114 | * 115 | * @param holder The surface object which the camera will draw preview frames into. 116 | * @throws IOException Indicates the camera driver failed to open. 117 | */ 118 | public void openDriver(SurfaceHolder holder) throws IOException { 119 | if (camera == null) { 120 | camera = Camera.open(); 121 | if (camera == null) { 122 | throw new IOException(); 123 | } 124 | camera.setPreviewDisplay(holder); 125 | 126 | if (!initialized) { 127 | initialized = true; 128 | configManager.initFromCameraParameters(camera); 129 | } 130 | configManager.setDesiredCameraParameters(camera); 131 | 132 | //FIXME 133 | // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 134 | //�Ƿ�ʹ��ǰ�� 135 | // if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) { 136 | // FlashlightManager.enableFlashlight(); 137 | // } 138 | FlashlightManager.enableFlashlight(); 139 | } 140 | } 141 | 142 | /** 143 | * Closes the camera driver if still in use. 144 | */ 145 | public void closeDriver() { 146 | if (camera != null) { 147 | FlashlightManager.disableFlashlight(); 148 | camera.release(); 149 | camera = null; 150 | } 151 | } 152 | 153 | /** 154 | * Asks the camera hardware to begin drawing preview frames to the screen. 155 | */ 156 | public void startPreview() { 157 | if (camera != null && !previewing) { 158 | camera.startPreview(); 159 | previewing = true; 160 | } 161 | } 162 | 163 | /** 164 | * Tells the camera to stop drawing preview frames. 165 | */ 166 | public void stopPreview() { 167 | if (camera != null && previewing) { 168 | if (!useOneShotPreviewCallback) { 169 | camera.setPreviewCallback(null); 170 | } 171 | camera.stopPreview(); 172 | previewCallback.setHandler(null, 0); 173 | autoFocusCallback.setHandler(null, 0); 174 | previewing = false; 175 | } 176 | } 177 | 178 | /** 179 | * A single preview frame will be returned to the handler supplied. The data will arrive as byte[] 180 | * in the message.obj field, with width and height encoded as message.arg1 and message.arg2, 181 | * respectively. 182 | * 183 | * @param handler The handler to send the message to. 184 | * @param message The what field of the message to be sent. 185 | */ 186 | public void requestPreviewFrame(Handler handler, int message) { 187 | if (camera != null && previewing) { 188 | previewCallback.setHandler(handler, message); 189 | if (useOneShotPreviewCallback) { 190 | camera.setOneShotPreviewCallback(previewCallback); 191 | } else { 192 | camera.setPreviewCallback(previewCallback); 193 | } 194 | } 195 | } 196 | 197 | /** 198 | * Asks the camera hardware to perform an autofocus. 199 | * 200 | * @param handler The Handler to notify when the autofocus completes. 201 | * @param message The message to deliver. 202 | */ 203 | public void requestAutoFocus(Handler handler, int message) { 204 | if (camera != null && previewing) { 205 | autoFocusCallback.setHandler(handler, message); 206 | //Log.d(TAG, "Requesting auto-focus callback"); 207 | camera.autoFocus(autoFocusCallback); 208 | } 209 | } 210 | 211 | /** 212 | * Calculates the framing rect which the UI should draw to show the user where to place the 213 | * barcode. This target helps with alignment as well as forces the user to hold the device 214 | * far enough away to ensure the image will be in focus. 215 | * 216 | * @return The rectangle to draw on screen in window coordinates. 217 | */ 218 | public Rect getFramingRect() { 219 | try { 220 | Point screenResolution = configManager.getScreenResolution(); 221 | // if (framingRect == null) { 222 | if (camera == null) { 223 | return null; 224 | } 225 | 226 | int leftOffset = (screenResolution.x - FRAME_WIDTH) / 2; 227 | 228 | int topOffset; 229 | if (FRAME_MARGINTOP != -1) { 230 | topOffset = FRAME_MARGINTOP; 231 | } else { 232 | topOffset = (screenResolution.y - FRAME_HEIGHT) / 2; 233 | } 234 | framingRect = new Rect(leftOffset, topOffset, leftOffset + FRAME_WIDTH, topOffset + FRAME_HEIGHT); 235 | // } 236 | return framingRect; 237 | } catch (Exception e) { 238 | e.printStackTrace(); 239 | return null; 240 | } 241 | } 242 | 243 | /** 244 | * Like {@link #getFramingRect} but coordinates are in terms of the preview frame, 245 | * not UI / screen. 246 | */ 247 | public Rect getFramingRectInPreview() { 248 | if (framingRectInPreview == null) { 249 | Rect rect = new Rect(getFramingRect()); 250 | Point cameraResolution = configManager.getCameraResolution(); 251 | Point screenResolution = configManager.getScreenResolution(); 252 | //modify here 253 | // rect.left = rect.left * cameraResolution.x / screenResolution.x; 254 | // rect.right = rect.right * cameraResolution.x / screenResolution.x; 255 | // rect.top = rect.top * cameraResolution.y / screenResolution.y; 256 | // rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y; 257 | rect.left = rect.left * cameraResolution.y / screenResolution.x; 258 | rect.right = rect.right * cameraResolution.y / screenResolution.x; 259 | rect.top = rect.top * cameraResolution.x / screenResolution.y; 260 | rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y; 261 | framingRectInPreview = rect; 262 | } 263 | return framingRectInPreview; 264 | } 265 | 266 | /** 267 | * Converts the result points from still resolution coordinates to screen coordinates. 268 | * 269 | * @param points The points returned by the Reader subclass through Result.getResultPoints(). 270 | * @return An array of Points scaled to the size of the framing rect and offset appropriately 271 | * so they can be drawn in screen coordinates. 272 | */ 273 | /* 274 | public Point[] convertResultPoints(ResultPoint[] points) { 275 | Rect frame = getFramingRectInPreview(); 276 | int count = points.length; 277 | Point[] output = new Point[count]; 278 | for (int x = 0; x < count; x++) { 279 | output[x] = new Point(); 280 | output[x].x = frame.left + (int) (points[x].getX() + 0.5f); 281 | output[x].y = frame.top + (int) (points[x].getY() + 0.5f); 282 | } 283 | return output; 284 | } 285 | */ 286 | 287 | /** 288 | * A factory method to build the appropriate LuminanceSource object based on the format 289 | * of the preview buffers, as described by Camera.Parameters. 290 | * 291 | * @param data A preview frame. 292 | * @param width The width of the image. 293 | * @param height The height of the image. 294 | * @return A PlanarYUVLuminanceSource instance. 295 | */ 296 | public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { 297 | Rect rect = getFramingRectInPreview(); 298 | int previewFormat = configManager.getPreviewFormat(); 299 | String previewFormatString = configManager.getPreviewFormatString(); 300 | switch (previewFormat) { 301 | // This is the standard Android format which all devices are REQUIRED to support. 302 | // In theory, it's the only one we should ever care about. 303 | case PixelFormat.YCbCr_420_SP: 304 | // This format has never been seen in the wild, but is compatible as we only care 305 | // about the Y channel, so allow it. 306 | case PixelFormat.YCbCr_422_SP: 307 | return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, 308 | rect.width(), rect.height()); 309 | default: 310 | // The Samsung Moment incorrectly uses this variant instead of the 'sp' version. 311 | // Fortunately, it too has all the Y data up front, so we can read it. 312 | if ("yuv420p".equals(previewFormatString)) { 313 | return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, 314 | rect.width(), rect.height()); 315 | } 316 | } 317 | throw new IllegalArgumentException("Unsupported picture format: " + 318 | previewFormat + '/' + previewFormatString); 319 | } 320 | 321 | public Context getContext() { 322 | return context; 323 | } 324 | 325 | public Camera getCamera() { 326 | return camera; 327 | } 328 | 329 | public boolean isPreviewing() { 330 | return previewing; 331 | } 332 | 333 | public boolean isUseOneShotPreviewCallback() { 334 | return useOneShotPreviewCallback; 335 | } 336 | 337 | public PreviewCallback getPreviewCallback() { 338 | return previewCallback; 339 | } 340 | 341 | public AutoFocusCallback getAutoFocusCallback() { 342 | return autoFocusCallback; 343 | } 344 | 345 | public void setPreviewing(boolean previewing) { 346 | this.previewing = previewing; 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/FlashlightManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.camera; 18 | 19 | import android.os.IBinder; 20 | import android.util.Log; 21 | 22 | import java.lang.reflect.InvocationTargetException; 23 | import java.lang.reflect.Method; 24 | 25 | /** 26 | * This class is used to activate the weak light on some camera phones (not flash) 27 | * in order to illuminate surfaces for scanning. There is no official way to do this, 28 | * but, classes which allow access to this function still exist on some devices. 29 | * This therefore proceeds through a great deal of reflection. 30 | *

31 | * See 32 | * http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/ and 33 | * 34 | * http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java. 35 | * Thanks to Ryan Alford for pointing out the availability of this class. 36 | */ 37 | final class FlashlightManager { 38 | 39 | private static final String TAG = FlashlightManager.class.getSimpleName(); 40 | 41 | private static final Object iHardwareService; 42 | private static final Method setFlashEnabledMethod; 43 | 44 | static { 45 | iHardwareService = getHardwareService(); 46 | setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService); 47 | if (iHardwareService == null) { 48 | Log.v(TAG, "This device does supports control of a flashlight"); 49 | } else { 50 | Log.v(TAG, "This device does not support control of a flashlight"); 51 | } 52 | } 53 | 54 | private FlashlightManager() { 55 | } 56 | 57 | /** 58 | * �����������ƿ��� 59 | */ 60 | //FIXME 61 | static void enableFlashlight() { 62 | setFlashlight(false); 63 | } 64 | 65 | static void disableFlashlight() { 66 | setFlashlight(false); 67 | } 68 | 69 | private static Object getHardwareService() { 70 | Class serviceManagerClass = maybeForName("android.os.ServiceManager"); 71 | if (serviceManagerClass == null) { 72 | return null; 73 | } 74 | 75 | Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class); 76 | if (getServiceMethod == null) { 77 | return null; 78 | } 79 | 80 | Object hardwareService = invoke(getServiceMethod, null, "hardware"); 81 | if (hardwareService == null) { 82 | return null; 83 | } 84 | 85 | Class iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub"); 86 | if (iHardwareServiceStubClass == null) { 87 | return null; 88 | } 89 | 90 | Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", IBinder.class); 91 | if (asInterfaceMethod == null) { 92 | return null; 93 | } 94 | 95 | return invoke(asInterfaceMethod, null, hardwareService); 96 | } 97 | 98 | private static Method getSetFlashEnabledMethod(Object iHardwareService) { 99 | if (iHardwareService == null) { 100 | return null; 101 | } 102 | Class proxyClass = iHardwareService.getClass(); 103 | return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class); 104 | } 105 | 106 | private static Class maybeForName(String name) { 107 | try { 108 | return Class.forName(name); 109 | } catch (ClassNotFoundException cnfe) { 110 | // OK 111 | return null; 112 | } catch (RuntimeException re) { 113 | Log.w(TAG, "Unexpected error while finding class " + name, re); 114 | return null; 115 | } 116 | } 117 | 118 | private static Method maybeGetMethod(Class clazz, String name, Class... argClasses) { 119 | try { 120 | return clazz.getMethod(name, argClasses); 121 | } catch (NoSuchMethodException nsme) { 122 | // OK 123 | return null; 124 | } catch (RuntimeException re) { 125 | Log.w(TAG, "Unexpected error while finding method " + name, re); 126 | return null; 127 | } 128 | } 129 | 130 | private static Object invoke(Method method, Object instance, Object... args) { 131 | try { 132 | return method.invoke(instance, args); 133 | } catch (IllegalAccessException e) { 134 | Log.w(TAG, "Unexpected error while invoking " + method, e); 135 | return null; 136 | } catch (InvocationTargetException e) { 137 | Log.w(TAG, "Unexpected error while invoking " + method, e.getCause()); 138 | return null; 139 | } catch (RuntimeException re) { 140 | Log.w(TAG, "Unexpected error while invoking " + method, re); 141 | return null; 142 | } 143 | } 144 | 145 | private static void setFlashlight(boolean active) { 146 | if (iHardwareService != null) { 147 | invoke(setFlashEnabledMethod, iHardwareService, active); 148 | } 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/PlanarYUVLuminanceSource.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 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.zxing.camera; 18 | 19 | import android.graphics.Bitmap; 20 | 21 | import com.google.zxing.LuminanceSource; 22 | 23 | /** 24 | * This object extends LuminanceSource around an array of YUV data returned from the camera driver, 25 | * with the option to crop to a rectangle within the full data. This can be used to exclude 26 | * superfluous pixels around the perimeter and speed up decoding. 27 | *

28 | * It works for any pixel format where the Y channel is planar and appears first, including 29 | * YCbCr_420_SP and YCbCr_422_SP. 30 | * 31 | * @author dswitkin@google.com (Daniel Switkin) 32 | */ 33 | public final class PlanarYUVLuminanceSource extends LuminanceSource { 34 | private final byte[] yuvData; 35 | private final int dataWidth; 36 | private final int dataHeight; 37 | private final int left; 38 | private final int top; 39 | 40 | public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top, 41 | int width, int height) { 42 | super(width, height); 43 | 44 | if (left + width > dataWidth || top + height > dataHeight) { 45 | throw new IllegalArgumentException("Crop rectangle does not fit within image data."); 46 | } 47 | 48 | this.yuvData = yuvData; 49 | this.dataWidth = dataWidth; 50 | this.dataHeight = dataHeight; 51 | this.left = left; 52 | this.top = top; 53 | } 54 | 55 | @Override 56 | public byte[] getRow(int y, byte[] row) { 57 | if (y < 0 || y >= getHeight()) { 58 | throw new IllegalArgumentException("Requested row is outside the image: " + y); 59 | } 60 | int width = getWidth(); 61 | if (row == null || row.length < width) { 62 | row = new byte[width]; 63 | } 64 | int offset = (y + top) * dataWidth + left; 65 | System.arraycopy(yuvData, offset, row, 0, width); 66 | return row; 67 | } 68 | 69 | @Override 70 | public byte[] getMatrix() { 71 | int width = getWidth(); 72 | int height = getHeight(); 73 | 74 | // If the caller asks for the entire underlying image, save the copy and give them the 75 | // original data. The docs specifically warn that result.length must be ignored. 76 | if (width == dataWidth && height == dataHeight) { 77 | return yuvData; 78 | } 79 | 80 | int area = width * height; 81 | byte[] matrix = new byte[area]; 82 | int inputOffset = top * dataWidth + left; 83 | 84 | // If the width matches the full width of the underlying data, perform a single copy. 85 | if (width == dataWidth) { 86 | System.arraycopy(yuvData, inputOffset, matrix, 0, area); 87 | return matrix; 88 | } 89 | 90 | // Otherwise copy one cropped row at a time. 91 | byte[] yuv = yuvData; 92 | for (int y = 0; y < height; y++) { 93 | int outputOffset = y * width; 94 | System.arraycopy(yuv, inputOffset, matrix, outputOffset, width); 95 | inputOffset += dataWidth; 96 | } 97 | return matrix; 98 | } 99 | 100 | @Override 101 | public boolean isCropSupported() { 102 | return true; 103 | } 104 | 105 | public int getDataWidth() { 106 | return dataWidth; 107 | } 108 | 109 | public int getDataHeight() { 110 | return dataHeight; 111 | } 112 | 113 | public Bitmap renderCroppedGreyscaleBitmap() { 114 | int width = getWidth(); 115 | int height = getHeight(); 116 | int[] pixels = new int[width * height]; 117 | byte[] yuv = yuvData; 118 | int inputOffset = top * dataWidth + left; 119 | 120 | for (int y = 0; y < height; y++) { 121 | int outputOffset = y * width; 122 | for (int x = 0; x < width; x++) { 123 | int grey = yuv[inputOffset + x] & 0xff; 124 | pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101); 125 | } 126 | inputOffset += dataWidth; 127 | } 128 | 129 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 130 | bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 131 | return bitmap; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/camera/PreviewCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.camera; 18 | 19 | import android.graphics.Point; 20 | import android.hardware.Camera; 21 | import android.os.Handler; 22 | import android.os.Message; 23 | import android.util.Log; 24 | 25 | public final class PreviewCallback implements Camera.PreviewCallback { 26 | 27 | private static final String TAG = PreviewCallback.class.getSimpleName(); 28 | 29 | private final CameraConfigurationManager configManager; 30 | private final boolean useOneShotPreviewCallback; 31 | private Handler previewHandler; 32 | private int previewMessage; 33 | 34 | PreviewCallback(CameraConfigurationManager configManager, boolean useOneShotPreviewCallback) { 35 | this.configManager = configManager; 36 | this.useOneShotPreviewCallback = useOneShotPreviewCallback; 37 | } 38 | 39 | public void setHandler(Handler previewHandler, int previewMessage) { 40 | this.previewHandler = previewHandler; 41 | this.previewMessage = previewMessage; 42 | } 43 | 44 | public void onPreviewFrame(byte[] data, Camera camera) { 45 | Point cameraResolution = configManager.getCameraResolution(); 46 | if (!useOneShotPreviewCallback) { 47 | camera.setPreviewCallback(null); 48 | } 49 | if (previewHandler != null) { 50 | Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x, 51 | cameraResolution.y, data); 52 | message.sendToTarget(); 53 | previewHandler = null; 54 | } else { 55 | Log.d(TAG, "Got preview callback, but no handler for it"); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/CaptureActivityHandler.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 | 17 | package com.zxing.decoding; 18 | 19 | import android.app.Activity; 20 | import android.content.Intent; 21 | import android.graphics.Bitmap; 22 | import android.net.Uri; 23 | import android.os.Bundle; 24 | import android.os.Handler; 25 | import android.os.Message; 26 | import android.util.Log; 27 | 28 | import com.google.zxing.BarcodeFormat; 29 | import com.google.zxing.Result; 30 | import com.zxing.R; 31 | import com.zxing.activity.CaptureFragment; 32 | import com.zxing.camera.CameraManager; 33 | import com.zxing.view.ViewfinderResultPointCallback; 34 | import com.zxing.view.ViewfinderView; 35 | 36 | import java.util.Vector; 37 | 38 | /** 39 | * This class handles all the messaging which comprises the state machine for capture. 40 | */ 41 | public final class CaptureActivityHandler extends Handler { 42 | 43 | private static final String TAG = CaptureActivityHandler.class.getSimpleName(); 44 | 45 | private final CaptureFragment fragment; 46 | private final DecodeThread decodeThread; 47 | private State state; 48 | 49 | private enum State { 50 | PREVIEW, 51 | SUCCESS, 52 | DONE 53 | } 54 | 55 | public CaptureActivityHandler(CaptureFragment fragment, Vector decodeFormats, 56 | String characterSet, ViewfinderView viewfinderView) { 57 | this.fragment = fragment; 58 | decodeThread = new DecodeThread(fragment, decodeFormats, characterSet, 59 | new ViewfinderResultPointCallback(viewfinderView)); 60 | decodeThread.start(); 61 | state = State.SUCCESS; 62 | // Start ourselves capturing previews and decoding. 63 | CameraManager.get().startPreview(); 64 | restartPreviewAndDecode(); 65 | } 66 | 67 | @Override 68 | public void handleMessage(Message message) { 69 | if (message.what == R.id.auto_focus) { 70 | //Log.d(TAG, "Got auto-focus message"); 71 | // When one auto focus pass finishes, start another. This is the closest thing to 72 | // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do. 73 | if (state == State.PREVIEW) { 74 | CameraManager.get().requestAutoFocus(this, R.id.auto_focus); 75 | } 76 | } else if (message.what == R.id.restart_preview) { 77 | Log.d(TAG, "Got restart preview message"); 78 | restartPreviewAndDecode(); 79 | } else if (message.what == R.id.decode_succeeded) { 80 | Log.d(TAG, "Got decode succeeded message"); 81 | state = State.SUCCESS; 82 | Bundle bundle = message.getData(); 83 | 84 | /***********************************************************************/ 85 | Bitmap barcode = bundle == null ? null : 86 | (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);//���ñ����߳� 87 | 88 | fragment.handleDecode((Result) message.obj, barcode);//���ؽ�� 89 | /***********************************************************************/ 90 | } else if (message.what == R.id.decode_failed) { 91 | // We're decoding as fast as possible, so when one decode fails, start another. 92 | state = State.PREVIEW; 93 | CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); 94 | } else if (message.what == R.id.return_scan_result) { 95 | Log.d(TAG, "Got return scan result message"); 96 | fragment.getActivity().setResult(Activity.RESULT_OK, (Intent) message.obj); 97 | fragment.getActivity().finish(); 98 | } else if (message.what == R.id.launch_product_query) { 99 | Log.d(TAG, "Got product query message"); 100 | String url = (String) message.obj; 101 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 102 | intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 103 | fragment.getActivity().startActivity(intent); 104 | } 105 | } 106 | 107 | public void quitSynchronously() { 108 | state = State.DONE; 109 | CameraManager.get().stopPreview(); 110 | Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); 111 | quit.sendToTarget(); 112 | try { 113 | decodeThread.join(); 114 | } catch (InterruptedException e) { 115 | // continue 116 | } 117 | 118 | // Be absolutely sure we don't send any queued up messages 119 | removeMessages(R.id.decode_succeeded); 120 | removeMessages(R.id.decode_failed); 121 | } 122 | 123 | private void restartPreviewAndDecode() { 124 | if (state == State.SUCCESS) { 125 | state = State.PREVIEW; 126 | CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode); 127 | CameraManager.get().requestAutoFocus(this, R.id.auto_focus); 128 | fragment.drawViewfinder(); 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/DecodeFormatManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.decoding; 18 | 19 | import android.content.Intent; 20 | import android.net.Uri; 21 | 22 | import com.google.zxing.BarcodeFormat; 23 | 24 | import java.util.Arrays; 25 | import java.util.List; 26 | import java.util.Vector; 27 | import java.util.regex.Pattern; 28 | 29 | public class DecodeFormatManager { 30 | 31 | private static final Pattern COMMA_PATTERN = Pattern.compile(","); 32 | 33 | public static final Vector PRODUCT_FORMATS; 34 | public static final Vector ONE_D_FORMATS; 35 | public static final Vector QR_CODE_FORMATS; 36 | public static final Vector DATA_MATRIX_FORMATS; 37 | 38 | static { 39 | PRODUCT_FORMATS = new Vector(5); 40 | PRODUCT_FORMATS.add(BarcodeFormat.UPC_A); 41 | PRODUCT_FORMATS.add(BarcodeFormat.UPC_E); 42 | PRODUCT_FORMATS.add(BarcodeFormat.EAN_13); 43 | PRODUCT_FORMATS.add(BarcodeFormat.EAN_8); 44 | // PRODUCT_FORMATS.add(BarcodeFormat.RSS14); 45 | ONE_D_FORMATS = new Vector(PRODUCT_FORMATS.size() + 4); 46 | ONE_D_FORMATS.addAll(PRODUCT_FORMATS); 47 | ONE_D_FORMATS.add(BarcodeFormat.CODE_39); 48 | ONE_D_FORMATS.add(BarcodeFormat.CODE_93); 49 | ONE_D_FORMATS.add(BarcodeFormat.CODE_128); 50 | ONE_D_FORMATS.add(BarcodeFormat.ITF); 51 | QR_CODE_FORMATS = new Vector(1); 52 | QR_CODE_FORMATS.add(BarcodeFormat.QR_CODE); 53 | DATA_MATRIX_FORMATS = new Vector(1); 54 | DATA_MATRIX_FORMATS.add(BarcodeFormat.DATA_MATRIX); 55 | } 56 | 57 | private DecodeFormatManager() { 58 | } 59 | 60 | static Vector parseDecodeFormats(Intent intent) { 61 | List scanFormats = null; 62 | String scanFormatsString = intent.getStringExtra(Intents.Scan.SCAN_FORMATS); 63 | if (scanFormatsString != null) { 64 | scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString)); 65 | } 66 | return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE)); 67 | } 68 | 69 | static Vector parseDecodeFormats(Uri inputUri) { 70 | List formats = inputUri.getQueryParameters(Intents.Scan.SCAN_FORMATS); 71 | if (formats != null && formats.size() == 1 && formats.get(0) != null) { 72 | formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0))); 73 | } 74 | return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE)); 75 | } 76 | 77 | private static Vector parseDecodeFormats(Iterable scanFormats, 78 | String decodeMode) { 79 | if (scanFormats != null) { 80 | Vector formats = new Vector(); 81 | try { 82 | for (String format : scanFormats) { 83 | formats.add(BarcodeFormat.valueOf(format)); 84 | } 85 | return formats; 86 | } catch (IllegalArgumentException iae) { 87 | // ignore it then 88 | } 89 | } 90 | if (decodeMode != null) { 91 | if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) { 92 | return PRODUCT_FORMATS; 93 | } 94 | if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) { 95 | return QR_CODE_FORMATS; 96 | } 97 | if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) { 98 | return DATA_MATRIX_FORMATS; 99 | } 100 | if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) { 101 | return ONE_D_FORMATS; 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/DecodeHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.decoding; 18 | 19 | import android.os.Bundle; 20 | import android.os.Handler; 21 | import android.os.Looper; 22 | import android.os.Message; 23 | import android.util.Log; 24 | 25 | import com.google.zxing.BinaryBitmap; 26 | import com.google.zxing.DecodeHintType; 27 | import com.google.zxing.MultiFormatReader; 28 | import com.google.zxing.ReaderException; 29 | import com.google.zxing.Result; 30 | import com.google.zxing.common.HybridBinarizer; 31 | import com.zxing.R; 32 | import com.zxing.activity.CaptureFragment; 33 | import com.zxing.camera.CameraManager; 34 | import com.zxing.camera.PlanarYUVLuminanceSource; 35 | 36 | import java.util.Hashtable; 37 | 38 | final class DecodeHandler extends Handler { 39 | 40 | private static final String TAG = DecodeHandler.class.getSimpleName(); 41 | 42 | private final CaptureFragment fragment; 43 | private final MultiFormatReader multiFormatReader; 44 | 45 | DecodeHandler(CaptureFragment fragment, Hashtable hints) { 46 | multiFormatReader = new MultiFormatReader(); 47 | multiFormatReader.setHints(hints); 48 | this.fragment = fragment; 49 | } 50 | 51 | @Override 52 | public void handleMessage(Message message) { 53 | if (message.what == R.id.decode) { 54 | decode((byte[]) message.obj, message.arg1, message.arg2); 55 | } else if (message.what == R.id.quit) { 56 | Looper.myLooper().quit(); 57 | } 58 | } 59 | 60 | /** 61 | * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency, 62 | * reuse the same reader objects from one decode to the next. 63 | * 64 | * @param data The YUV preview frame. 65 | * @param width The width of the preview frame. 66 | * @param height The height of the preview frame. 67 | */ 68 | private void decode(byte[] data, int width, int height) { 69 | long start = System.currentTimeMillis(); 70 | Result rawResult = null; 71 | 72 | //modify here 73 | byte[] rotatedData = new byte[data.length]; 74 | for (int y = 0; y < height; y++) { 75 | for (int x = 0; x < width; x++) 76 | rotatedData[x * height + height - y - 1] = data[x + y * width]; 77 | } 78 | int tmp = width; // Here we are swapping, that's the difference to #11 79 | width = height; 80 | height = tmp; 81 | 82 | PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height); 83 | BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); 84 | try { 85 | rawResult = multiFormatReader.decodeWithState(bitmap); 86 | } catch (ReaderException re) { 87 | // continue 88 | } finally { 89 | multiFormatReader.reset(); 90 | } 91 | 92 | if (rawResult != null) { 93 | long end = System.currentTimeMillis(); 94 | Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString()); 95 | Message message = Message.obtain(fragment.getHandler(), R.id.decode_succeeded, rawResult); 96 | Bundle bundle = new Bundle(); 97 | bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap()); 98 | message.setData(bundle); 99 | //Log.d(TAG, "Sending decode succeeded message..."); 100 | message.sendToTarget(); 101 | } else { 102 | Message message = Message.obtain(fragment.getHandler(), R.id.decode_failed); 103 | message.sendToTarget(); 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/DecodeThread.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 | 17 | package com.zxing.decoding; 18 | 19 | import android.os.Handler; 20 | import android.os.Looper; 21 | 22 | import com.google.zxing.BarcodeFormat; 23 | import com.google.zxing.DecodeHintType; 24 | import com.google.zxing.ResultPointCallback; 25 | import com.zxing.activity.CaptureFragment; 26 | 27 | import java.util.Hashtable; 28 | import java.util.Vector; 29 | import java.util.concurrent.CountDownLatch; 30 | 31 | /** 32 | * This thread does all the heavy lifting of decoding the images. 33 | * �����߳� 34 | */ 35 | final class DecodeThread extends Thread { 36 | 37 | public static final String BARCODE_BITMAP = "barcode_bitmap"; 38 | private final CaptureFragment fragment; 39 | private final Hashtable hints; 40 | private Handler handler; 41 | private final CountDownLatch handlerInitLatch; 42 | 43 | DecodeThread(CaptureFragment fragment, 44 | Vector decodeFormats, 45 | String characterSet, 46 | ResultPointCallback resultPointCallback) { 47 | 48 | this.fragment = fragment; 49 | handlerInitLatch = new CountDownLatch(1); 50 | 51 | hints = new Hashtable(3); 52 | 53 | if (decodeFormats == null || decodeFormats.isEmpty()) { 54 | decodeFormats = new Vector(); 55 | decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS); 56 | decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS); 57 | decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS); 58 | } 59 | 60 | hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); 61 | 62 | if (characterSet != null) { 63 | hints.put(DecodeHintType.CHARACTER_SET, characterSet); 64 | } 65 | 66 | hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback); 67 | } 68 | 69 | Handler getHandler() { 70 | try { 71 | handlerInitLatch.await(); 72 | } catch (InterruptedException ie) { 73 | // continue? 74 | } 75 | return handler; 76 | } 77 | 78 | @Override 79 | public void run() { 80 | Looper.prepare(); 81 | handler = new DecodeHandler(fragment, hints); 82 | handlerInitLatch.countDown(); 83 | Looper.loop(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/FinishListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.decoding; 18 | 19 | import android.app.Activity; 20 | import android.content.DialogInterface; 21 | 22 | /** 23 | * Simple listener used to exit the app in a few cases. 24 | */ 25 | public final class FinishListener 26 | implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, Runnable { 27 | 28 | private final Activity activityToFinish; 29 | 30 | public FinishListener(Activity activityToFinish) { 31 | this.activityToFinish = activityToFinish; 32 | } 33 | 34 | public void onCancel(DialogInterface dialogInterface) { 35 | run(); 36 | } 37 | 38 | public void onClick(DialogInterface dialogInterface, int i) { 39 | run(); 40 | } 41 | 42 | public void run() { 43 | activityToFinish.finish(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/InactivityTimer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 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.zxing.decoding; 18 | 19 | import android.app.Activity; 20 | 21 | import java.util.concurrent.Executors; 22 | import java.util.concurrent.ScheduledExecutorService; 23 | import java.util.concurrent.ScheduledFuture; 24 | import java.util.concurrent.ThreadFactory; 25 | import java.util.concurrent.TimeUnit; 26 | 27 | /** 28 | * Finishes an activity after a period of inactivity. 29 | */ 30 | public final class InactivityTimer { 31 | 32 | private static final int INACTIVITY_DELAY_SECONDS = 5 * 60; 33 | 34 | private final ScheduledExecutorService inactivityTimer = 35 | Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory()); 36 | private final Activity activity; 37 | private ScheduledFuture inactivityFuture = null; 38 | 39 | public InactivityTimer(Activity activity) { 40 | this.activity = activity; 41 | onActivity(); 42 | } 43 | 44 | public void onActivity() { 45 | cancel(); 46 | inactivityFuture = inactivityTimer.schedule(new FinishListener(activity), 47 | INACTIVITY_DELAY_SECONDS, 48 | TimeUnit.SECONDS); 49 | } 50 | 51 | private void cancel() { 52 | if (inactivityFuture != null) { 53 | inactivityFuture.cancel(true); 54 | inactivityFuture = null; 55 | } 56 | } 57 | 58 | public void shutdown() { 59 | cancel(); 60 | inactivityTimer.shutdown(); 61 | } 62 | 63 | private static final class DaemonThreadFactory implements ThreadFactory { 64 | public Thread newThread(Runnable runnable) { 65 | Thread thread = new Thread(runnable); 66 | thread.setDaemon(true); 67 | return thread; 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/decoding/Intents.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 | 17 | package com.zxing.decoding; 18 | 19 | /** 20 | * This class provides the constants to use when sending an Intent to Barcode Scanner. 21 | * These strings are effectively API and cannot be changed. 22 | */ 23 | public final class Intents { 24 | private Intents() { 25 | } 26 | 27 | public static final class Scan { 28 | /** 29 | * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return 30 | * the results. 31 | */ 32 | public static final String ACTION = "com.google.zxing.client.android.SCAN"; 33 | 34 | /** 35 | * By default, sending Scan.ACTION will decode all barcodes that we understand. However it 36 | * may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with 37 | * one of the values below ({@link #PRODUCT_MODE}, {@link #ONE_D_MODE}, {@link #QR_CODE_MODE}). 38 | * Optional. 39 | *

40 | * Setting this is effectively shorthnad for setting explicit formats with {@link #SCAN_FORMATS}. 41 | * It is overridden by that setting. 42 | */ 43 | public static final String MODE = "SCAN_MODE"; 44 | 45 | /** 46 | * Comma-separated list of formats to scan for. The values must match the names of 47 | * {@link com.google.zxing.BarcodeFormat}s, such as {@link com.google.zxing.BarcodeFormat#EAN_13}. 48 | * Example: "EAN_13,EAN_8,QR_CODE" 49 | *

50 | * This overrides {@link #MODE}. 51 | */ 52 | public static final String SCAN_FORMATS = "SCAN_FORMATS"; 53 | 54 | /** 55 | * @see com.google.zxing.DecodeHintType#CHARACTER_SET 56 | */ 57 | public static final String CHARACTER_SET = "CHARACTER_SET"; 58 | 59 | /** 60 | * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get 61 | * prices, reviews, etc. for products. 62 | */ 63 | public static final String PRODUCT_MODE = "PRODUCT_MODE"; 64 | 65 | /** 66 | * Decode only 1D barcodes (currently UPC, EAN, Code 39, and Code 128). 67 | */ 68 | public static final String ONE_D_MODE = "ONE_D_MODE"; 69 | 70 | /** 71 | * Decode only QR codes. 72 | */ 73 | public static final String QR_CODE_MODE = "QR_CODE_MODE"; 74 | 75 | /** 76 | * Decode only Data Matrix codes. 77 | */ 78 | public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE"; 79 | 80 | /** 81 | * If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which 82 | * requested the scan via startSubActivity(). The barcodes contents can be retrieved with 83 | * intent.getStringExtra(RESULT). If the user presses Back, the result code will be 84 | * RESULT_CANCELED. 85 | */ 86 | public static final String RESULT = "SCAN_RESULT"; 87 | 88 | /** 89 | * Call intent.getStringExtra(RESULT_FORMAT) to determine which barcode format was found. 90 | * See Contents.Format for possible values. 91 | */ 92 | public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT"; 93 | 94 | /** 95 | * Setting this to false will not save scanned codes in the history. 96 | */ 97 | public static final String SAVE_HISTORY = "SAVE_HISTORY"; 98 | 99 | private Scan() { 100 | } 101 | } 102 | 103 | public static final class Encode { 104 | /** 105 | * Send this intent to encode a piece of data as a QR code and display it full screen, so 106 | * that another person can scan the barcode from your screen. 107 | */ 108 | public static final String ACTION = "com.google.zxing.client.android.ENCODE"; 109 | 110 | /** 111 | * The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a 112 | * Bundle, depending on the type and format specified. Non-QR Code formats should 113 | * just use a String here. For QR Code, see Contents for details. 114 | */ 115 | public static final String DATA = "ENCODE_DATA"; 116 | 117 | /** 118 | * The type of data being supplied if the format is QR Code. Use 119 | * Intent.putExtra(TYPE, type) with one of Contents.Type. 120 | */ 121 | public static final String TYPE = "ENCODE_TYPE"; 122 | 123 | /** 124 | * The barcode format to be displayed. If this isn't specified or is blank, 125 | * it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where 126 | * format is one of Contents.Format. 127 | */ 128 | public static final String FORMAT = "ENCODE_FORMAT"; 129 | 130 | private Encode() { 131 | } 132 | } 133 | 134 | public static final class SearchBookContents { 135 | /** 136 | * Use Google Book Search to search the contents of the book provided. 137 | */ 138 | public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS"; 139 | 140 | /** 141 | * The book to search, identified by ISBN number. 142 | */ 143 | public static final String ISBN = "ISBN"; 144 | 145 | /** 146 | * An optional field which is the text to search for. 147 | */ 148 | public static final String QUERY = "QUERY"; 149 | 150 | private SearchBookContents() { 151 | } 152 | } 153 | 154 | public static final class WifiConnect { 155 | /** 156 | * Internal intent used to trigger connection to a wi-fi network. 157 | */ 158 | public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT"; 159 | 160 | /** 161 | * The network to connect to, all the configuration provided here. 162 | */ 163 | public static final String SSID = "SSID"; 164 | 165 | /** 166 | * The network to connect to, all the configuration provided here. 167 | */ 168 | public static final String TYPE = "TYPE"; 169 | 170 | /** 171 | * The network to connect to, all the configuration provided here. 172 | */ 173 | public static final String PASSWORD = "PASSWORD"; 174 | 175 | private WifiConnect() { 176 | } 177 | } 178 | 179 | 180 | public static final class Share { 181 | /** 182 | * Give the user a choice of items to encode as a barcode, then render it as a QR Code and 183 | * display onscreen for a friend to scan with their phone. 184 | */ 185 | public static final String ACTION = "com.google.zxing.client.android.SHARE"; 186 | 187 | private Share() { 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/encoding/EncodingHandler.java: -------------------------------------------------------------------------------- 1 | package com.zxing.encoding; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.google.zxing.BarcodeFormat; 6 | import com.google.zxing.EncodeHintType; 7 | import com.google.zxing.MultiFormatWriter; 8 | import com.google.zxing.WriterException; 9 | import com.google.zxing.common.BitMatrix; 10 | 11 | import java.util.Hashtable; 12 | 13 | /** 14 | * @author Ryan Tang 15 | */ 16 | public final class EncodingHandler { 17 | private static final int BLACK = 0xff000000; 18 | 19 | public static Bitmap createQRCode(String str, int widthAndHeight) throws WriterException { 20 | Hashtable hints = new Hashtable(); 21 | hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 22 | BitMatrix matrix = new MultiFormatWriter().encode(str, 23 | BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight); 24 | int width = matrix.getWidth(); 25 | int height = matrix.getHeight(); 26 | int[] pixels = new int[width * height]; 27 | 28 | for (int y = 0; y < height; y++) { 29 | for (int x = 0; x < width; x++) { 30 | if (matrix.get(x, y)) { 31 | pixels[y * width + x] = BLACK; 32 | } 33 | } 34 | } 35 | Bitmap bitmap = Bitmap.createBitmap(width, height, 36 | Bitmap.Config.ARGB_8888); 37 | bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 38 | return bitmap; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/view/ViewfinderResultPointCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 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.zxing.view; 18 | 19 | import com.google.zxing.ResultPoint; 20 | import com.google.zxing.ResultPointCallback; 21 | 22 | public final class ViewfinderResultPointCallback implements ResultPointCallback { 23 | 24 | private final ViewfinderView viewfinderView; 25 | 26 | public ViewfinderResultPointCallback(ViewfinderView viewfinderView) { 27 | this.viewfinderView = viewfinderView; 28 | } 29 | 30 | public void foundPossibleResultPoint(ResultPoint point) { 31 | viewfinderView.addPossibleResultPoint(point); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /zxing/src/main/java/com/zxing/view/ViewfinderView.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 | 17 | package com.zxing.view; 18 | 19 | import android.animation.ValueAnimator; 20 | import android.content.Context; 21 | import android.content.res.Resources; 22 | import android.content.res.TypedArray; 23 | import android.graphics.Bitmap; 24 | import android.graphics.BitmapFactory; 25 | import android.graphics.Canvas; 26 | import android.graphics.Color; 27 | import android.graphics.Paint; 28 | import android.graphics.Rect; 29 | import android.graphics.drawable.Drawable; 30 | import android.util.AttributeSet; 31 | import android.view.View; 32 | 33 | import com.google.zxing.ResultPoint; 34 | import com.zxing.DisplayUtil; 35 | import com.zxing.R; 36 | import com.zxing.camera.CameraManager; 37 | 38 | import java.util.Collection; 39 | import java.util.HashSet; 40 | 41 | /** 42 | * 自定义组件实现,扫描功能 43 | */ 44 | public final class ViewfinderView extends View { 45 | 46 | private static final long ANIMATION_DELAY = 10L; 47 | private static final int OPAQUE = 0xFF; 48 | 49 | private final Paint paint; 50 | private Bitmap resultBitmap; 51 | private final int maskColor; 52 | private final int resultColor; 53 | private final int resultPointColor; 54 | private Collection possibleResultPoints; 55 | private Collection lastPossibleResultPoints; 56 | 57 | public ViewfinderView(Context context) { 58 | this(context, null); 59 | } 60 | 61 | public ViewfinderView(Context context, AttributeSet attrs) { 62 | this(context, attrs, -1); 63 | 64 | } 65 | public ViewfinderView(Context context, AttributeSet attrs, int defStyleAttr) { 66 | super(context, attrs, defStyleAttr); 67 | paint = new Paint(); 68 | Resources resources = getResources(); 69 | maskColor = resources.getColor(R.color.viewfinder_mask); 70 | resultColor = resources.getColor(R.color.result_view); 71 | resultPointColor = resources.getColor(R.color.possible_result_points); 72 | possibleResultPoints = new HashSet<>(5); 73 | scanLight = BitmapFactory.decodeResource(resources, R.drawable.scan_light); 74 | initInnerRect(context, attrs); 75 | } 76 | 77 | /** 78 | * 初始化内部框的大小 79 | * 80 | * @param context 81 | * @param attrs 82 | */ 83 | private void initInnerRect(Context context, AttributeSet attrs) { 84 | TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView); 85 | 86 | // 扫描框距离顶部 87 | float innerMarginTop = ta.getDimension(R.styleable.ViewfinderView_inner_margintop, -1); 88 | if (innerMarginTop != -1) { 89 | CameraManager.FRAME_MARGINTOP = (int) innerMarginTop; 90 | } 91 | 92 | // 扫描框的宽度 93 | CameraManager.FRAME_WIDTH = (int) ta.getDimension(R.styleable.ViewfinderView_inner_width, DisplayUtil.screenWidthPx / 2); 94 | 95 | // 扫描框的高度 96 | CameraManager.FRAME_HEIGHT = (int) ta.getDimension(R.styleable.ViewfinderView_inner_height, DisplayUtil.screenWidthPx / 2); 97 | 98 | // 扫描框边角颜色 99 | innercornercolor = ta.getColor(R.styleable.ViewfinderView_inner_corner_color, Color.parseColor("#45DDDD")); 100 | // 扫描框边角长度 101 | innercornerlength = (int) ta.getDimension(R.styleable.ViewfinderView_inner_corner_length, 65); 102 | // 扫描框边角宽度 103 | innercornerwidth = (int) ta.getDimension(R.styleable.ViewfinderView_inner_corner_width, 15); 104 | 105 | // 扫描bitmap 106 | Drawable drawable = ta.getDrawable(R.styleable.ViewfinderView_inner_scan_bitmap); 107 | if (drawable != null) { 108 | } 109 | 110 | // 扫描控件 111 | scanLight = BitmapFactory.decodeResource(getResources(), ta.getResourceId(R.styleable.ViewfinderView_inner_scan_bitmap, R.drawable.scan_light)); 112 | // 扫描速度 113 | SCAN_VELOCITY = ta.getInt(R.styleable.ViewfinderView_inner_scan_speed, 5); 114 | 115 | isCircle = ta.getBoolean(R.styleable.ViewfinderView_inner_scan_iscircle, true); 116 | 117 | ta.recycle(); 118 | } 119 | 120 | @Override 121 | public void onDraw(Canvas canvas) { 122 | Rect frame = CameraManager.get().getFramingRect(); 123 | if (frame == null) { 124 | return; 125 | } 126 | int width = canvas.getWidth(); 127 | int height = canvas.getHeight(); 128 | 129 | // Draw the exterior (i.e. outside the framing rect) darkened 130 | paint.setColor(resultBitmap != null ? resultColor : maskColor); 131 | canvas.drawRect(0, 0, width, frame.top, paint); 132 | canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); 133 | canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint); 134 | canvas.drawRect(0, frame.bottom + 1, width, height, paint); 135 | 136 | if (resultBitmap != null) { 137 | // Draw the opaque result bitmap over the scanning rectangle 138 | paint.setAlpha(OPAQUE); 139 | canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint); 140 | } else { 141 | 142 | drawFrameBounds(canvas, frame); 143 | 144 | drawScanLight(canvas, frame); 145 | 146 | Collection currentPossible = possibleResultPoints; 147 | Collection currentLast = lastPossibleResultPoints; 148 | if (currentPossible.isEmpty()) { 149 | lastPossibleResultPoints = null; 150 | } else { 151 | possibleResultPoints = new HashSet(5); 152 | lastPossibleResultPoints = currentPossible; 153 | paint.setAlpha(OPAQUE); 154 | paint.setColor(resultPointColor); 155 | 156 | if (isCircle) { 157 | for (ResultPoint point : currentPossible) { 158 | canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint); 159 | } 160 | } 161 | } 162 | if (currentLast != null) { 163 | paint.setAlpha(OPAQUE / 2); 164 | paint.setColor(resultPointColor); 165 | 166 | if (isCircle) { 167 | for (ResultPoint point : currentLast) { 168 | canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint); 169 | } 170 | } 171 | } 172 | 173 | postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom); 174 | } 175 | } 176 | 177 | // 扫描线移动的y 178 | private int scanLineTop; 179 | // 扫描线移动速度 180 | private int SCAN_VELOCITY; 181 | // 扫描线 182 | private Bitmap scanLight; 183 | // 是否展示小圆点 184 | private boolean isCircle; 185 | 186 | /** 187 | * 绘制移动扫描线 188 | * 189 | * @param canvas 190 | * @param frame 191 | */ 192 | private void drawScanLight(Canvas canvas, Rect frame) { 193 | 194 | if (scanLineTop == 0) { 195 | scanLineTop = frame.top; 196 | } 197 | 198 | if (scanLineTop >= frame.bottom - 30) { 199 | scanLineTop = frame.top; 200 | } else { 201 | scanLineTop += SCAN_VELOCITY; 202 | } 203 | Rect scanRect = new Rect(frame.left, scanLineTop, frame.right, 204 | scanLineTop + 30); 205 | canvas.drawBitmap(scanLight, null, scanRect, paint); 206 | } 207 | 208 | private ValueAnimator valueAnimator; 209 | 210 | 211 | 212 | 213 | // 扫描框边角颜色 214 | private int innercornercolor; 215 | // 扫描框边角长度 216 | private int innercornerlength; 217 | // 扫描框边角宽度 218 | private int innercornerwidth; 219 | 220 | /** 221 | * 绘制取景框边框 222 | * 223 | * @param canvas 224 | * @param frame 225 | */ 226 | private void drawFrameBounds(Canvas canvas, Rect frame) { 227 | 228 | /*paint.setColor(Color.WHITE); 229 | paint.setStrokeWidth(2); 230 | paint.setStyle(Paint.Style.STROKE); 231 | 232 | canvas.drawRect(frame, paint);*/ 233 | 234 | paint.setColor(innercornercolor); 235 | paint.setStyle(Paint.Style.FILL); 236 | 237 | int corWidth = innercornerwidth; 238 | int corLength = innercornerlength; 239 | 240 | // 左上角 241 | canvas.drawRect(frame.left, frame.top, frame.left + corWidth, frame.top 242 | + corLength, paint); 243 | canvas.drawRect(frame.left, frame.top, frame.left 244 | + corLength, frame.top + corWidth, paint); 245 | // 右上角 246 | canvas.drawRect(frame.right - corWidth, frame.top, frame.right, 247 | frame.top + corLength, paint); 248 | canvas.drawRect(frame.right - corLength, frame.top, 249 | frame.right, frame.top + corWidth, paint); 250 | // 左下角 251 | canvas.drawRect(frame.left, frame.bottom - corLength, 252 | frame.left + corWidth, frame.bottom, paint); 253 | canvas.drawRect(frame.left, frame.bottom - corWidth, frame.left 254 | + corLength, frame.bottom, paint); 255 | // 右下角 256 | canvas.drawRect(frame.right - corWidth, frame.bottom - corLength, 257 | frame.right, frame.bottom, paint); 258 | canvas.drawRect(frame.right - corLength, frame.bottom - corWidth, 259 | frame.right, frame.bottom, paint); 260 | } 261 | 262 | 263 | public void drawViewfinder() { 264 | resultBitmap = null; 265 | invalidate(); 266 | } 267 | 268 | public void addPossibleResultPoint(ResultPoint point) { 269 | possibleResultPoints.add(point); 270 | } 271 | 272 | 273 | /** 274 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 275 | */ 276 | public static int dip2px(Context context, float dpValue) { 277 | final float scale = context.getResources().getDisplayMetrics().density; 278 | return (int) (dpValue * scale + 0.5f); 279 | } 280 | 281 | 282 | } 283 | -------------------------------------------------------------------------------- /zxing/src/main/res/drawable/scan_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/drawable/scan_light.png -------------------------------------------------------------------------------- /zxing/src/main/res/layout/act_scan.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 18 | 19 | 29 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | 59 | 66 | 67 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /zxing/src/main/res/layout/camera.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /zxing/src/main/res/layout/fragment_capture.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /zxing/src/main/res/layout/layout_scan.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /zxing/src/main/res/mipmap-xhdpi/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/mipmap-xhdpi/ic_back.png -------------------------------------------------------------------------------- /zxing/src/main/res/mipmap-xhdpi/iv_light_switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/mipmap-xhdpi/iv_light_switch.png -------------------------------------------------------------------------------- /zxing/src/main/res/mipmap/ic_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/mipmap/ic_back.png -------------------------------------------------------------------------------- /zxing/src/main/res/mipmap/iv_light_switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/mipmap/iv_light_switch.png -------------------------------------------------------------------------------- /zxing/src/main/res/raw/beep.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wintonBy/EasyZxing/91dc97f7c2bcb086bba93f4c6b1d2051a8a6b02c/zxing/src/main/res/raw/beep.ogg -------------------------------------------------------------------------------- /zxing/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /zxing/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #59a9ff 4 | 5 | #EDEDED 6 | #ff000000 7 | #ffffffff 8 | #ffcccccc 9 | #ff404040 10 | #c0ffff00 11 | #ffffffff 12 | #ffc0c0c0 13 | #c000ff00 14 | #ffffffff 15 | #b0000000 16 | #ff808080 17 | #ffffffff 18 | #fffff0e0 19 | #ffffffff 20 | #ff000000 21 | #ff4b4b4b 22 | #ff000000 23 | #ffffffff 24 | #50000000 25 | #ffffffff 26 | #00000000 27 | #ff000000 28 | #ffff0000 29 | #60000000 30 | #58567D 31 | #686868 32 | 33 | 34 | -------------------------------------------------------------------------------- /zxing/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /zxing/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Lib-zxing 3 | 4 | 5 | Hello blank fragment 6 | 7 | -------------------------------------------------------------------------------- /zxing/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /zxing/src/test/java/com/zxing/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zxing; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } --------------------------------------------------------------------------------