├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── asklin.xml ├── gradle.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── ScreenShot └── img1.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ronda │ │ └── barcodescanner │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ronda │ │ │ └── barcodescanner │ │ │ ├── BarcodeScannerResolver.java │ │ │ ├── KeyEventService.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── accessibilityservice.xml │ └── test │ └── java │ └── com │ └── ronda │ └── barcodescanner │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/asklin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | C/C++ 39 | 40 | 41 | Class structureJava 42 | 43 | 44 | Concurrency annotation issuesJava 45 | 46 | 47 | General 48 | 49 | 50 | Groovy 51 | 52 | 53 | Java 54 | 55 | 56 | Performance issuesJava 57 | 58 | 59 | Probable bugsJava 60 | 61 | 62 | Properties Files 63 | 64 | 65 | Threading issuesGroovy 66 | 67 | 68 | Threading issuesJava 69 | 70 | 71 | Type checksC/C++ 72 | 73 | 74 | Unused codeC/C++ 75 | 76 | 77 | 78 | 79 | Android 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | 102 | 103 | 104 | 105 | 106 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 扫码枪扫码功能(扫商品条码,支付条码等) 2 | 3 | 因为扫码枪就相当于外部输入设备(和键盘一样),所以就是监听按键输入事件(或者按键回调事件),然后获取这些输入的字符,最后拼接在一起就是一个完整的条码 4 | 5 | ## 两种思路: 6 | 1. 在 Activity 中的 dispatchKeyEvent()/onKeyDown() 回调事件中,捕获按键事件KeyEvent 7 | 2. 使用无障碍服务AccessibilityService,在后台实现按键监听,也是onKeyEvent() 回调方法中 (有使用条件) 8 | 9 | 10 | 11 | 12 | ## BarcodeScannerResolver(扫码枪事件解析类) 13 | 使用说明: 14 | * 在Activity中先创建BarcodeScannerResolver对象,并设置扫码成功监听器: setScanSuccessListener() [一般在onCreate()方法中初始化] 15 | * 接着在Activity#dispatchKeyEvent() 或者 Activity#onKeyDown() 中调用本类中的resolveKeyEvent()方法。当扫码结束之后,会自动回调第一步设置的监听器中的方法 16 | 17 | 原理分析: 18 | 1. 扫码枪就是一个外部的输入设备(和键盘一样)。扫码的时候,就是在极短的时间内输入了一系列的数字或字母 19 | 2. 这样就可以在键盘事件中抓捕这些输入的字符,但是又会产生一个问题(快速扫两次的情形):在键盘事件中应该抓捕多少个字符呢?即一个条码应该在哪个位置结束呢? (有的扫码枪会以一个回车或者换行作为一次扫码的结束符,但是有的就纯粹的是一系列的条码。这个得需要设置) 20 | 21 | 所以为了兼容性,应当是当短时间内不再输入字符的时候,就表示扫码已结束。这样只能定性描述,不能定量,只能自己在程序中用一个具体的数字来表示这个“短时间”,eg:500ms。(如果每个条码结束的时候都有一个结束符那该多好,直接判断这个结束符,就可以知道当前扫码已完成) 22 | 接下来就产生了BarcodeScannerResolver这个类。 23 | 24 | 核心原理就一句话:在Activity的键盘监听事件中,每抓捕到一个字符的时候,就先向 Handler 一次一个runnable对象,再延迟500ms发送一个runnable. 这样若两个输入字符的间隔时间超过了500ms,则视为两次扫码 25 | 26 | 27 | ## 后台无障碍服务AccessibilityService(也是Service的一种)实现按键监听的功能: 28 | 可以一直在后台运行,监听按键功能。 29 | 30 | * 对于扫码输入监听,使用 AccessibilityService 则有点大材小用了。因为我们的扫码功能只在特定的某些页面才有,所以只需要在这些Activity中的按键事件的回调方法中捕获输入的字符即可。 31 | * 而无障碍服务 AccessibilityService 来实现按键监听,则一般用于机顶盒或者智能电视,也就是AndroidTv。针对遥控器某些特殊按键,实现按键的监听,并实现相应的功能。 当然 AccessibilityService 的功能很强大,远不止按键监听这一项。 32 | 33 | 参考:http://blog.csdn.net/w815878564/article/details/53331086 34 | 35 | 启动:AccessibilityService 的方法:(要注意:用户应用的话,下面这种方式是启动不了的,只用系统级的应用才可以用下面这种方式启动。若系统是自己开发的话,可以直接把签名应用(要和系统的签名是一样的)放到/system/framework/目录下即可成为系统级应用) 36 | 用户级应用只用这样启动:设置 --> 辅助功能 --> 选择服务进行开启/关闭 37 | 38 | //代码启动AccessibilityService(只适用于系统级应用) 39 | private void startKeyEventService(){ 40 | //注意 这里可能为空(也就是如果当前没有任何一个无障碍服务被授权的时候 就为空了 ) 41 | String enabledServicesSetting = Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 42 | 43 | ComponentName selfComponentName = new ComponentName(getPackageName(), "com.ronda.barcodescanner.KeyEventService"); 44 | String flattenToString = selfComponentName.flattenToString(); 45 | if (enabledServicesSetting == null || !enabledServicesSetting.contains(flattenToString)) { 46 | enabledServicesSetting += flattenToString; 47 | } 48 | Settings.Secure.putString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServicesSetting); 49 | Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 1); 50 | } 51 | 52 | 使用 AccessibilityService 的要点: 53 | * AndroidManifest.xml 中的声明(除了android:name属性,其他都是固定的写法) 54 | 55 | 60 | 61 | 62 | 63 | 66 | 67 | 68 | * accessibilityservice.xml 的写法(基本形式如下) 69 | 70 | 71 | 81 | 82 | 83 | 84 | 85 | ![](ScreenShot/img1.png "") -------------------------------------------------------------------------------- /ScreenShot/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/githubRonda/BarcodeScanner/8cad2059e739fd21d2abe083a079b652d2fac7d6/ScreenShot/img1.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.ronda.barcodescanner" 8 | minSdkVersion 19 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | testCompile 'junit:junit:4.12' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android\as\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/ronda/barcodescanner/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.ronda.barcodescanner; 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 | * Instrumentation 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.ronda.barcodescanner", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/ronda/barcodescanner/BarcodeScannerResolver.java: -------------------------------------------------------------------------------- 1 | package com.ronda.barcodescanner; 2 | 3 | /** 4 | * Author: Ronda(1575558177@qq.com) 5 | * Date: 2017/03/07 6 | * Version: v1.0 7 | */ 8 | 9 | import android.os.Handler; 10 | import android.util.Log; 11 | import android.view.KeyEvent; 12 | 13 | /** 14 | * 扫码枪事件解析类 15 | *

16 | * 使用说明: 17 | * 1. 在Activity中先创建BarcodeScannerResolver对象,并设置扫码成功监听器: setScanSuccessListener() [一般在onCreate()方法中初始化] 18 | * 2. 接着在Activity#dispatchKeyEvent() 或者 Activity#onKeyDown() 中调用本类中的resolveKeyEvent()方法。当扫码结束之后,会自动回调第一步设置的监听器中的方法 19 | * 20 | * 原理分析: 21 | * 1. 扫码枪就是一个外部的输入设备(和键盘一样)。扫码的时候,就是在极短的时间内输入了一系列的数字或字母 22 | * 2. 这样就可以在键盘事件中抓捕这些输入的字符,但是又会产生一个问题(快速扫两次的情形):在键盘事件中应该抓捕多少个字符呢?即一个条码应该在哪个位置结束呢? (有的扫码枪会以一个回车或者换行作为一次扫码的结束符,但是有的就纯粹的是一系列的条码。这个得需要设置) 23 | * 所以为了兼容性,应当是当短时间内不再输入字符的时候,就表示扫码已结束。这样只能定性描述,不能定量,只能自己在程序中用一个具体的数字来表示这个“短时间”,eg:500ms。(如果每个条码结束的时候都有一个结束符那该多好,直接判断这个结束符,就可以知道当前扫码已完成) 24 | * 25 | * 接下来就产生了BarcodeScannerResolver这个类。 26 | * 核心原理就一句话:在Activity的键盘监听事件中,每抓捕到一个字符的时候,就先向 Handler 一次一个runnable对象,再延迟500ms发送一个runnable. 这样若两个输入字符的间隔时间超过了500ms,则视为两次扫码 27 | * 28 | */ 29 | public class BarcodeScannerResolver { 30 | 31 | private static final String TAG = BarcodeScannerResolver.class.getSimpleName(); 32 | 33 | // 若500ms之内无字符输入,则表示扫码完成. (若觉得时间还长,则可以设置成更小的值) 34 | private final static long MESSAGE_DELAY = 500; 35 | 36 | private boolean mCaps;//大写或小写 37 | private StringBuilder mResult = new StringBuilder();//扫码内容 38 | 39 | private OnScanSuccessListener mOnScanSuccessListener; 40 | private Handler mHandler = new Handler(); 41 | 42 | private final Runnable mScanningEndRunnable = new Runnable() { 43 | @Override 44 | public void run() { 45 | performScanSuccess(); 46 | } 47 | }; 48 | 49 | //调用回调方法 50 | private void performScanSuccess() { 51 | String barcode = mResult.toString(); 52 | //Log.i(TAG, "performScanSuccess -> barcode: "+barcode); 53 | if (mOnScanSuccessListener != null) { 54 | mOnScanSuccessListener.onScanSuccess(barcode); 55 | } 56 | mResult.setLength(0); 57 | } 58 | 59 | //key事件处理 60 | public void resolveKeyEvent(KeyEvent event) { 61 | 62 | int keyCode = event.getKeyCode(); 63 | 64 | checkLetterStatus(event);//字母大小写判断 65 | 66 | Log.w(TAG, "keyEvent:" + event + "keyCode: " + keyCode + "char: " + KeyEvent.keyCodeToString(keyCode)); 67 | if (event.getAction() == KeyEvent.ACTION_DOWN) { 68 | 69 | 70 | char aChar = getInputCode(event); 71 | Log.w(TAG, "aChar: " + aChar); 72 | 73 | if (aChar != 0) { 74 | mResult.append(aChar); 75 | } 76 | 77 | if (keyCode == KeyEvent.KEYCODE_ENTER) { 78 | //若为回车键,直接返回 79 | mHandler.removeCallbacks(mScanningEndRunnable); 80 | mHandler.post(mScanningEndRunnable); 81 | } else { 82 | //延迟post,若500ms内,有其他事件 83 | mHandler.removeCallbacks(mScanningEndRunnable); 84 | mHandler.postDelayed(mScanningEndRunnable, MESSAGE_DELAY); 85 | } 86 | 87 | } 88 | } 89 | 90 | //检查shift键 91 | private void checkLetterStatus(KeyEvent event) { 92 | int keyCode = event.getKeyCode(); 93 | if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT) { 94 | if (event.getAction() == KeyEvent.ACTION_DOWN) { 95 | //按着shift键,表示大写 96 | mCaps = true; 97 | } else { 98 | //松开shift键,表示小写 99 | mCaps = false; 100 | } 101 | } 102 | } 103 | 104 | //获取扫描内容 105 | private char getInputCode(KeyEvent event) { 106 | int keyCode = event.getKeyCode(); 107 | 108 | char aChar; 109 | if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) { 110 | //字母 111 | aChar = (char) ((mCaps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A); 112 | } else if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { 113 | //数字 114 | aChar = (char) ('0' + keyCode - KeyEvent.KEYCODE_0); 115 | } else { 116 | //其他符号 117 | switch (keyCode) { 118 | case KeyEvent.KEYCODE_PERIOD: 119 | aChar = '.'; 120 | break; 121 | case KeyEvent.KEYCODE_MINUS: 122 | aChar = mCaps ? '_' : '-'; 123 | break; 124 | case KeyEvent.KEYCODE_SLASH: 125 | aChar = '/'; 126 | break; 127 | case KeyEvent.KEYCODE_BACKSLASH: 128 | aChar = mCaps ? '|' : '\\'; 129 | break; 130 | default: 131 | aChar = 0; 132 | break; 133 | } 134 | } 135 | return aChar; 136 | } 137 | 138 | 139 | public interface OnScanSuccessListener { 140 | void onScanSuccess(String barcode); 141 | } 142 | 143 | public void setScanSuccessListener(OnScanSuccessListener onScanSuccessListener) { 144 | mOnScanSuccessListener = onScanSuccessListener; 145 | } 146 | 147 | public void removeScanSuccessListener() { 148 | mHandler.removeCallbacks(mScanningEndRunnable); 149 | mOnScanSuccessListener = null; 150 | } 151 | 152 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ronda/barcodescanner/KeyEventService.java: -------------------------------------------------------------------------------- 1 | package com.ronda.barcodescanner; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.util.Log; 5 | import android.view.KeyEvent; 6 | import android.view.accessibility.AccessibilityEvent; 7 | /* 8 | 后台无障碍服务AccessibilityService(也是Service的一种)实现按键监听的功能: 9 | 可以一直在后台运行,监听按键功能。 10 | 11 | 对于扫码输入监听,使用 AccessibilityService 则有点大材小用了。因为我们的扫码功能只在特定的某些页面才有,所以只需要在这些Activity中的按键事件的回调方法中捕获输入的字符即可。 12 | 而无障碍服务 AccessibilityService 来实现按键监听,则一般用于机顶盒或者智能电视,也就是AndroidTv。针对遥控器某些特殊按键,实现按键的监听,并实现相应的功能。 当然 AccessibilityService 的功能很强大,远不止按键监听这一项。 13 | 14 | 参考:http://blog.csdn.net/w815878564/article/details/53331086 15 | 16 | 启动:AccessibilityService 的方法:(要注意:用户应用的话,下面这种方式是启动不了的,只用系统级的应用才可以用下面这种方式启动。若系统是自己开发的话,可以直接把签名应用(要和系统的签名是一样的)放到/system/framework/目录下即可成为系统级应用) 17 | 用户级应用只用这样启动:设置 --> 辅助功能 --> 选择服务进行开启/关闭 18 | 19 | private void startKeyEventService(){ 20 | //注意 这里可能为空(也就是如果当前没有任何一个无障碍服务被授权的时候 就为空了 ) 21 | String enabledServicesSetting = Settings.Secure.getString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 22 | 23 | ComponentName selfComponentName = new ComponentName(getPackageName(), "com.ronda.barcodescanner.KeyEventService"); 24 | String flattenToString = selfComponentName.flattenToString(); 25 | if (enabledServicesSetting == null || !enabledServicesSetting.contains(flattenToString)) { 26 | enabledServicesSetting += flattenToString; 27 | } 28 | Settings.Secure.putString(getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, enabledServicesSetting); 29 | Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_ENABLED, 1); 30 | } 31 | 32 | */ 33 | 34 | public class KeyEventService extends AccessibilityService { 35 | private static final String TAG = KeyEventService.class.getSimpleName(); 36 | 37 | public KeyEventService() { 38 | } 39 | 40 | @Override 41 | public void onAccessibilityEvent(AccessibilityEvent event) { 42 | Log.i("Liu", "onAccessibilityEvent --> " + event); 43 | 44 | } 45 | 46 | @Override 47 | public void onInterrupt() { 48 | Log.i("Liu", "onInterrupt"); 49 | } 50 | 51 | /** 52 | * 复写这个方法可以捕获按键事件 53 | * 54 | * @param event 55 | * @return 56 | */ 57 | @Override 58 | protected boolean onKeyEvent(KeyEvent event) { 59 | int keyCode = event.getKeyCode(); 60 | Log.w(TAG, "keyEvent:" + event + "keyCode: " + keyCode + "char: " + KeyEvent.keyCodeToString(keyCode)); 61 | 62 | return super.onKeyEvent(event); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/ronda/barcodescanner/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ronda.barcodescanner; 2 | 3 | import android.content.res.Configuration; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.KeyEvent; 8 | import android.view.View; 9 | import android.widget.Toast; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | private static final String TAG = MainActivity.class.getSimpleName(); 14 | 15 | private BarcodeScannerResolver mBarcodeScannerResolver; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | 22 | 23 | } 24 | 25 | /** 26 | * 点击开始扫码监听按钮 27 | * 28 | * @param view 29 | */ 30 | public void startScanListen(View view) { 31 | mBarcodeScannerResolver = new BarcodeScannerResolver(); 32 | mBarcodeScannerResolver.setScanSuccessListener(new BarcodeScannerResolver.OnScanSuccessListener() { 33 | @Override 34 | public void onScanSuccess(String barcode) { 35 | //TODO 显示扫描内容 36 | Log.w(TAG, "barcode: " + barcode); 37 | Toast.makeText(MainActivity.this, "barcode: " + barcode, Toast.LENGTH_SHORT).show(); 38 | } 39 | }); 40 | } 41 | 42 | 43 | /** 44 | * 点击移除扫码监听按钮 45 | * 46 | * @param view 47 | */ 48 | public void removeScanListen(View view) { 49 | mBarcodeScannerResolver.removeScanSuccessListener(); 50 | mBarcodeScannerResolver = null; 51 | } 52 | 53 | 54 | /** 55 | * 扫码枪是输入设备,检测是否有外接输入设备.(这样判断其实并不严格) 56 | * 57 | * @return 58 | */ 59 | private boolean hasScanGun() { 60 | Configuration cfg = getResources().getConfiguration(); 61 | return cfg.keyboard != Configuration.KEYBOARD_NOKEYS; 62 | } 63 | 64 | // 65 | 66 | /** 67 | * Activity截获按键事件.发给 BarcodeScannerResolver 68 | * dispatchKeyEvent() 和 onKeyDown() 方法均可 69 | * 70 | * @param event 71 | * @return 72 | */ 73 | @Override 74 | public boolean dispatchKeyEvent(KeyEvent event) { 75 | // Log.i(TAG, "dispatchKeyEvent"); 76 | 77 | if (hasScanGun()) { 78 | mBarcodeScannerResolver.resolveKeyEvent(event); 79 | } 80 | return super.dispatchKeyEvent(event); 81 | } 82 | 83 | @Override 84 | public boolean onKeyDown(int keyCode, KeyEvent event) { 85 | // if (mBarcodeScannerResolver != null) { 86 | // mBarcodeScannerResolver.resolveKeyEvent(event); 87 | // } 88 | 89 | return super.onKeyDown(keyCode, event); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |