记录:UsbManager的使用
来源:互联网 发布:龙腾世纪审判捏脸数据 编辑:程序博客网 时间:2024/06/12 01:51
摘要:最近一直使用到身份证刷卡器,M1刷卡器。都有相关的demo。很快的使用上了,不过在使用M1的时候,没有循环(类似公交卡可以一直刷卡)读卡的demo,自己随便的开一个线程去无限读。事与愿违,不没有成功,不能抽时间查相关的UsbManager相关的资料。在这里把其简单的记录一下,^_^, 毕竟口号就抄,抄,抄. .(侵删)
USB背景知识
USB是一种数据通信方式,也是一种数据总线,而且是最复杂的总线之一
硬件上,它是用插头连接。一边是公头(plug),一边是母头(receptacle)。例如:PC上的插头就是母头,USB设备使用公头与PC相连
Host
USB是由 Host端控制整个总线的数据传输。单个USB上,只能有一个Host
OTG
On The Go,这是在 USB2.0引入的一种mode,提出了一个新的概念叫主机协商协议(Host Negotiation Protocol),允许两个设备间商量谁去当Host
Android中的USB
Android中对USB支持是3.1开始,显然是加强Android平板的对外扩展能力。而对 USB使用更多的是Android在工业中的使用。Android功能板子一般都会提供多个USB和串口,它们是连接外设手段的桥梁。比如:现在市面上的一体机,Android的板子上面会有很多的USB和串口,但是其中Android板子除了一个系统什么都没有,没有任何的传感器,摄像头等等。。全部是外接,就等同于一台式电脑。
我们在使用这些外接设备的时候,我们需要来了解一下Android为我们提供的API。其具体在android.hardware.usb包中。我们需要了解一下UsbManager
、 UsbDevice
、 UsbDeviceConnection
, UsbEndpoint
, UsbInterface
UsbRequest
, UsbConstants
, 这几个类,只要使用到USB都要用到它们。
- UsbManager:获得USB的状态,与连接的USB设备通信
- UsbDevice:USB设备的抽象,它包含了一个或多个的UsbInterface,而每个UsbInterface包含多个UsbEndpoint。Host与其通信,先打开UsbDeviceConnection,使用UsbRequest在一个端点(UsbEndpoint)发送和接受数据。
- UsbDeviceConnection:host与device建立的连接,并在endpoint传输数据。
- UsbEndpoint:endpoint是interface的通信信道。
- UsbInterface : 定理设备的功能集,一个UsbDevice包含多个UsbInterface,每个UsbInterface都是独立的。
- UsbRequest:usb请求包。可以在UsbDeviceConnection上异步传输数据。注意是只在异步通信时才会使用到它。
- UsbConstants:usb常量定义,对应 linux/usb/ch9.h
USB的广播
可以通过广播接接收器接收USB的插拔信息:当插入USB插头到一个USB端口或从一个USB端口移除一USB插头。都可以获取到
PendingIntent permissionIntent1 = PendingIntent.getBroadcast(this, 0,new Intent(ACTION_USB_PERMISSION), 0); // Broadcast listen for new devices IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_USB_PERMISSION); filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); this.registerReceiver(mUsbReceiver, filter); /* * BroadcastReceiver when insert/remove the device USB plug into/from a USB port * 创建一个广播接收器接收USB插拔信息:当插入USB插头插到一个USB端口,或从一个USB端口,移除装置的USB插头 */ BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { //插入事件 } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { //拔出事件 } else if (ACTION_USB_PERMISSION.equals(action)) { //权限请求事件 synchronized (this) { UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if ((device.getProductId() == 8211 && device.getVendorId() == 1305) || (device.getProductId() == 8213 && device .getVendorId() == 1305)) { if(mUsbDriver.openUsbDevice(device)) { if(device.getProductId()==8211) mUsbDev1 = device; else mUsbDev2 = device; } } } else { Toast.makeText(MainActivity.this,"permission denied for device", Toast.LENGTH_SHORT).show(); //Log.d(TAG, "permission denied for device " + device); } } } } };
USB的启动程序和 pid的注册
时常在有多个视屏播放器,浏览器没有设置为默认的情况下都会弹出一个选择框。usb也一样,需要我们在AndroidManifest.xml进行注册。可以注册在activity标签里面,也可以注册在 application标签里面。不管在那里面,都需要在对应的activity标签里面注册
<intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter>
和添加权限
<uses-feature android:name="android.hardware.usb.host" android:required="true"/> <uses-permission android:name="android.permission.MANAGE_USB"/> <uses-permission android:name="android.permission.HARDWARE_TEST"/>
进行筛选我们自己的 USB的厂家id和产品id。可以在res下新建一个xml。
<?xml version="1.0" encoding="utf-8"?><resources> <!-- 以下内容的 vendor-id、product-id就是USB的vid和pid了--> <usb-device vendor-id="4292" product-id="33896"/> <usb-device vendor-id="1024" product-id="50010"/> <usb-device vendor-id="1155" product-id="19799"/> <usb-device vendor-id="4292" product-id="33485"/></resources>
再在AndroidManifest.xml的activity或者application标签注册
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter"/>
在这样之后,在USB插入的时候,就会自行启动我们的activity。
USB的通信
把USB连接成功,就需要进行与它通信了。
bulkTransfer(this.h[this.g], var5, var4, 3000)
在做好准备之后,就这一个话。哈哈哈哈哈,啊嗝
这里摘抄两个前辈写的
前辈一:
private void initCommunication(UsbDevice device) { tvInfo.append("initCommunication in\n"); if(1234 == device.getVendorId() && 5678 == device.getProductId()) { tvInfo.append("initCommunication in right device\n"); int interfaceCount = device.getInterfaceCount(); for (int interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) { UsbInterface usbInterface = device.getInterface(interfaceIndex); if ((UsbConstants.USB_CLASS_CDC_DATA != usbInterface.getInterfaceClass()) && (UsbConstants.USB_CLASS_COMM != usbInterface.getInterfaceClass())) { continue; } for (int i = 0; i < usbInterface.getEndpointCount(); i++) { UsbEndpoint ep = usbInterface.getEndpoint(i); if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) { if (ep.getDirection() == UsbConstants.USB_DIR_OUT) { mUsbEndpointIn = ep; } else { mUsbEndpointOut = ep; } } } if ((null == mUsbEndpointIn) || (null == mUsbEndpointOut)) { tvInfo.append("endpoint is null\n"); mUsbEndpointIn = null; mUsbEndpointOut = null; mUsbInterface = null; } else { tvInfo.append("\nendpoint out: " + mUsbEndpointOut + ",endpoint in: " + mUsbEndpointIn.getAddress()+"\n"); mUsbInterface = usbInterface; mUsbDeviceConnection = mUsbManager.openDevice(device); break; } } } }
前辈二 : (一个jar,这里只截取其获取getEndpoint)
private UsbInterface[] e = new UsbInterface[2]; private UsbDeviceConnection[] f = new UsbDeviceConnection[2]; private int g = -1; private UsbEndpoint[] h = new UsbEndpoint[2]; private UsbEndpoint[] i = new UsbEndpoint[2]; int var2 = this.d[this.g].getInterfaceCount(); Log.i("UsbDriver", " m_Device[m_UsbDevIdx].getInterfaceCount():" + var2); if(var2 == 0) { return false; } else { if(var2 > 0) { this.e[this.g] = this.d[this.g].getInterface(0); } if(this.e[this.g].getEndpoint(1) != null) { this.i[this.g] = this.e[this.g].getEndpoint(1); } if(this.e[this.g].getEndpoint(0) != null) { this.h[this.g] = this.e[this.g].getEndpoint(0); }
这个指示一部分,可以看出里面获取的手法就简化了很多
上面的可以愉快的玩耍了,就讲一下把其转化成一直读卡遇到的问题。代码如下:
public boolean init(Context context) { UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE); HashMap<String, UsbDevice> devices = manager.getDeviceList(); LoggerUtil.i(TAG, "device.size = " + devices.size()); if (devices.size() <= 0) { return false; } UsbDevice myUsbDevice = null; Iterator<UsbDevice> iterator = devices.values().iterator(); while (iterator.hasNext()) { UsbDevice device = iterator.next(); LoggerUtil.i(TAG, "device vid = " + device.getVendorId() + " , pid = " + device.getProductId()); if (ReaderAndroidUsb.isSupported(device)) { myUsbDevice = device; break; } } if (myUsbDevice == null) { return false; } // 判断是否拥有该设备的连接权限 if (!manager.hasPermission(myUsbDevice)) { PendingIntent pd = PendingIntent.getBroadcast(context, 0, new Intent(Device_USB), PendingIntent.FLAG_UPDATE_CURRENT); /* * 展示征求用户同意连接这个设备的权限的对话框。 当用户回应这个对话框时, * 广播接收器就会收到一个包含用一个boolean值来表示结果的EXTRA_PERMISSION_GRANTED字段的意图。 * 在连接设备之前检查这个字段的值是否为true和设备之间的“交流” */ manager.requestPermission(myUsbDevice, pd); } if (!manager.hasPermission(myUsbDevice)) { return false; } // 如果已经拥有该设备的连接权限,直接对该设备操作 ReaderAndroidUsb readerAndroidUsb = new ReaderAndroidUsb(manager); readerAndroidUsb.closeReader(); try { /* * 函数说明: 直接打开 USB 接口读写器 * 返回值: * >=0 表示打开读写器成功 * <0 表示打开读写器失败。 */ int st = readerAndroidUsb.openReader(myUsbDevice); if (st >= 0) { reader = readerAndroidUsb; return true; } else { return false; } } catch (Exception e) { return false; } }
ReaderAndroidUsb 为我使用读卡器中的一个打开卡的方法。最初的时候我没有在 init( )方法里面传递 context,其中的 USBmanager也只在类的初始化的时候,进行初始化一次。后面的循环读卡中,刷卡一段时间就再也刷不起了。
后面的而修改办法就是,同上。初始化传入context,重新获取 UsbManager,一切重新开始。在刷卡成功后,关闭当前的usb的连接。等同于每一次都是单次刷卡,只是把单次刷卡需要调用的东西通过代码实时完成。
参考链接
- USB基础知识概论
- usb中的endpoint(端点)和传输模式
- Android实战技巧之四十九:Usb通信之USB Host
- Android下的USB Host介绍和开发
- Android开发之USB数据通信
- 记录:UsbManager的使用
- Android UsbManager 获取不到HID设备(实际上就是Input设备)怎样通信的问题(已解决)!
- 记录的使用
- FCK使用的记录
- 使用HessianKit的记录
- sourceinsight的使用记录
- movefileex的使用记录
- VIM的使用记录
- hadoop的使用记录
- SVN的使用记录
- CVS的使用记录
- AppScan的使用记录
- QTableWidget的使用记录
- netty的使用记录
- JSPWiki的使用记录
- hibernate记录的使用
- mysqlslap的使用记录
- UITextView的使用记录
- 18项火眼金睛
- Java爬虫,信息抓取的实现
- Ubuntu 16.04 – Configure your system to have x11vnc running at startup
- BZOJ4999 树剖+动态开点
- 2017杭州云栖大会参会体验
- 记录:UsbManager的使用
- Android简单使用GSON
- 【云计算的1024种玩法】手把手教你如何编译一个高性能 OpenResty
- 破解MD5算法的女强人——王小云
- 【原创】二分图模板
- 最简单的MD5加密
- Oracle远程错误:ORA-28547:connection to server failed, probable Oracle Net admin error
- 你的流量加密尚需功能再升级
- 转载泡泡机器人讲解orbslam