前段时间因为项目需要,做了一段时间关于Android USB Host的开发,最近闲下来总结一下。
Android模拟器无法测试USB,大部分的平板都不能使用usb host api,这里使用的测试平板是华硕的TF101,有一款可以测试Android平板是否支持USB HostAPI的apk http://download.csdn.net/download/limitemp/4837706
使用usb host api的使用步骤:
注册广播:
AndroidManifest.xml
...>
...
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
device_filter.xml
xml version="1.0" encoding="utf-8"?>vendor-id="1234" product-id="5678" />
代码中:
BroadcastReceiver mUsbReceiver= new BroadcastReceiver() {
public void onReceive(Context context,Intent intent){
String action = intent.getAction();
if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)){
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device!= null){
// call your method that cleans up and closescommunication with the device
}
}
}
};
上面的语句主要是为了向系统注册广播,当有USB设备插入的时候系统会弹出提示,如:
vendor-id,product-id是需要提示的usb设备的两个属性,这些属性可是使用一些USB查看工具来获取,xp下有一个USBtrace挺好用。如果这里什么都不写,则表示对于任何插入的USB设备都会有提示(其实并非任何例如键盘鼠标这类的HID设备就会提示)。
1. 获取UsbManager:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
2. 获取设备列表:
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
3. 通过UsbDevice来获得USBInterface:
UsbInterface getInterface(int index);
获取Interface以后可以根据其类型判断该USB设备的类型
Int getInterfaceClass();返回值为Int类型可以在UsbConstants类中找到对应的值例如:
public static final intUSB_CLASS_AUDIO
USB class for audio devices.
Constant Value: 1 (0x00000001)
该设备为audio设备,int值为1;
4. 根据获得的Interface获取Endpoint:
Endpoint的传输方向有两种,一种是In,一种是Out;对于Android为Host模式来说,in就是传向Host设备的,out是传向Device的;同时Endpoint分为四种类型:USB_ENDPOINT_XFER_CONTROL (endpoint zero)
USB_ENDPOINT_XFER_ISOC (isochronousendpoint)
USB_ENDPOINT_XFER_BULK (bulkendpoint)
USB_ENDPOINT_XFER_INT (interruptendpoint)
分别为对应四种不同的传输类型:控制传输,实时传输,批量传输,中断传输。
根据不同的传输类型选择不同的方法去传输数据。在UsbRequest中有这样一段话:
UsbRequests can beused to transfer data on bulk and interrupt endpoints. Requests on bulkendpoints can be sent synchronously via bulkTransfer(UsbEndpoint, byte[],int, int) or asynchronously via queue(ByteBuffer, int) and requestWait().Requests on interrupt endpoints are only send and received asynchronously.
Requests onendpoint zero are not supported by this class; use controlTransfer(int,int, int, int, byte[], int, int) for endpoint zero requests instead.
就是说对于bulkendpoint可是使用bulkTransfer方法同步传输或者使用queue和requestWait方法异步传输,但是对于interrupt endpoint使用Request只能进行异步传输。而对于endpoint zero端口只能使用controlTransfer方法。所以要根据自己的端口类型来选择合适的方法来传输,否则可能接收不到数据。
例如使用的USB设备的端口类型为bulk endpoint所以直接使用bulkTransfer方法就行了。过程如下:
UsbDeviceConnection connection = mUsbManager.openDevice(device);
//device 为你要打开的设备,这里涉及权限的问题,下面再说
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT)
//endpoint如果要接收数据就选择In端口,发送数据选择Out端口,同事这个方法是个阻塞式的方法,所以应该放到其他的线程中。
5. 关于UsbDeviceConnection connection = mUsbManager.openDevice(device);权限的问题:
SDK中有说明,如果设备是通过系统广播的形式获得,则不需要权限就可以直接打开。如果设备是通过manager.getDeviceList();枚举的方式获得,则在打开设备的时候需要权限。SDK中有这样一段代码:
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
private staticfinal String ACTION_USB_PERMISSION=
"com.android.example.USB_PERMISSION";
...
mPermissionIntent = PendingIntent.getBroadcast(this,0, new Intent(ACTION_USB_PERMISSION),0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
当运行到openDevice()时,系统会检查应用程序是否存在权限,若没有则会弹出用户授权的对话框。同意则打开成功,否则失败提示没有权限。