Class | Description |
UsbManager | 可以让你列举USB设备,并和设备交互; |
UsbDevice |
表示已连接的USB设备, 包含了访问设备标识信息的方法、接口和挂在点。
|
UsbInterface |
表示设备接口,定义了一些列的功能函数。一个设备可以包含一个或者多个接口。
|
UsbEndpoint |
表示一个挂载点接口,定义了一个交互通道。一个接口可以包含一个或者多个挂载点,
通常都包含用于和USB设备交互的输入输出双向端点
。
|
UsbDeviceConnection |
表示到USB设备的一个基于端点通信的接口,这个类支持同步或者异步数据的来回通讯;
|
UsbRequest | 代表一个异步的,基于UsbDeviceConnection通讯的异步请求。 |
UsbConstants | 定义了一些USB常量,与linux内核中的 linux/usb/ch9.h 中的定义一致。 |
UsbManager
对象来查询目标设备 UsbDevice。当获得设备 UsbDevice之后,你需要找到适当的
UsbInterface
以及该接口对应的
UsbEndpoint
,从而进行交互。一旦拿到真确的端点,打开连接 UsbDeviceConnection,以此和USB设备进行交互。
<uses-feature>
节点,来声明我们的应用需要android.hardware.usb.host
支持.<intent-filter>
和<meta-data>
节点对. <meta-data>
节点对应着一个外部XML 资源文件,这个资源文件定义了你想检测的设备的一些唯一标识信息.<usb-device>
来过滤你想要过滤的设备. 以下列表列出了
<usb-device>的属性. 总的来说, 使用 vendor-id 和 product-id 来过滤指定的USB设备,使用 class, subclass 和 protocol 来过滤一组设备, 比如说大容量存储设备和数码相机. 你可以指定所有的属性或者一个都不指定.如果你什么属性都不设置,就将匹配所有的USB设备,当程序需要的时候,你可以这么指定:
vendor-id
product-id
class
subclass
protocol
(device or interface)该资源文件保存在 res/xml/
目录下. 它的文件名(不包含.xml后缀名) 必须和<meta-data>
节点指定的名字一样. 文件的格式样式如下example:
<manifest ...> <uses-feature android:name="android.hardware.usb.host" /> <uses-sdk android:minSdkVersion="12" /> ... <application> <activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> </activity> </application> </manifest>
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" /> </resources>
当用户将一个USB设备连接到Android设备, Android系统可以决定你的程序是否有兴趣连接这个USB设备. 若确实有, 你的程序可以和设备如愿的进行交互. 为了让系统知道我们的应用程序确实有兴趣, 你必须做到:
你的应用可以使用意图过滤器(Intent Filter)使得程序可以接收到用户USB挂载通知或者列举出那些已连接的USB设备. 如果你希望你的应用能够自动的探寻的目标设备,使用一个意图过滤器是很有用的. 如果你希望获得一个所有的已连接的设备的列表或者你的应用并没有使用意图来过滤,那么列举出所有已连接的USB设备这个方式很有用.
为了使得你的应用能够发现某个USB设备, 你可以指定一个android.hardware.usb.action.USB_DEVICE_ATTACHED 意图来过滤设备. 指定了这个意图之后, 你需要为它指定一个包含了某个USB设备的特定属性(比如说 product-id 和 vendor-id)的资源文件. 当用户插入一个与意图过滤器符合的设备时, 系统将弹出一个包含了这些信息的对话框,来询问用户是否能够启动你的应用 , 如果用户接受了请求,你的应用将自动有权限去访问这个USB设备,直到USB设备断开连接.
下面的例子表明了如何声明意图过滤器:
<activity ...> ... <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" /> </activity>
下面的例子表明了如何声明对应的指定了你所感兴趣的USB设备的资源文件:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-device vendor-id="1234" product-id="5678" /> </resources>
在你的Activity 中, 你可以像下面这样获取 UsbDevice
对象,该对象代表了从意图(Intent)中检测到的设备:
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
如果你的应用在运行时,想要获得所有的当前已经连接的USB设备, 可以枚举出所有挂在在IO上的设备. 使用方法 getDeviceList() 获取一个包含所有已挂载的USB设备的HashMap. 这个HashMap使用USB设备的名字作为键值,如果你想从这个HashMap获取设备.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); UsbDevice device = deviceList.get("deviceName");
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMap<String, UsbDevice> deviceList = manager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next() //your code }
注意: 当USB设备连接的时候,如果你的应用使用意图过滤器来发现设备, 并且在应用安装的时候,用户允许你的应用处理这些事件,则应用将自动获得权限,否则, 在连接设备之前,你的应用必须明确的跟用户请求权限.
在一些情况下,明确的请求权限是必须的,比如当你的应用试图枚举已连接的USB设备并期望和其中一个交互的时候. 在应用于设备交互之前,你必须检查应用是否具有访问设备的权限. 否则的话,如果用户拒绝给予应用访问设备的权限,你将收到一个运行时错误.
为了明确获得权限,首先创建一个广播接收者(Broadcast Receiver). 当你调用方法requestPermission()
的时候, 这个接收者能够得到广播, 从而监听到你的意图. 调用方法 requestPermission()
将为用户弹出对话框,以询问是否允许应用连接设备. 以下的简单的例子表明了如何创建这个广播接收者:
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); 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 != null){ //call method to set up device communication } }else{ Log.d(TAG, "permission denied for device " + device); } } } } };
为了注册这个广播接收者,你需要在Activity的 onCreate()
中添加如下代码:
UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); private static final 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);
为了显示对话框以询问用户是否给予应用连接设备的权限,可以调用方法requestPermission()
:
UsbDevice device; ... mUsbManager.requestPermission(device, mPermissionIntent);
当用户回应对话框,你的广播接收者将接收到包含EXTRA_PERMISSION_GRANTED
的额外数据的意图, 这些额外的数据是一个代表着用户的回应的boolean值. 只有检测到这个额外的数据为true, 才有权限连接设备.
与设备交互,可以是同步的,也可以是异步的. 不管哪种情况, 你都需要创建一个新的线程,用于所有的数据传输,以致不阻塞UI主线程. 为了正确的建立与设备的交互, 你需要获得对应的UsbInterface
和 设备的 UsbEndpoint
,这个UsbEndpoint是你使用UsbDeviceConnection进行交互和发送请求的基本. 总的来说, 你的代码应该像这样:
UsbDevice
对象的属性, 比如 product-id, vendor-id, 或者是决定你是否想要和设备交互的设备类class节点.UsbInterface
以及用于和这个接口交互的合适的UsbEndpoint . 接口可以含有一个或者多个端点, 而通常情况下,都含有一个输入输入和输出的交互端点对.UsbDeviceConnection
.controlTransfer()
来提供传输的数据. 你应该在另一个线程中实现这一步,从而避免阻塞UI主线程. 关于如何在Android中使用线程,请查看Processes and Threads.下面的一小段代码,是一种简单的同步的数据传输方式. 在实际中,你的代码应该包含更多的逻辑来正确的获取到正确的交互接口和端点,而且应该在不同的线程中做数据的传输操作,而不是在UI主线程中:
private Byte[] bytesprivate static int TIMEOUT = 0; private boolean forceClaim = true; ... UsbInterface intf = device.getInterface(0); UsbEndpoint endpoint = intf.getEndpoint(0); UsbDeviceConnection connection = mUsbManager.openDevice(device); connection.claimInterface(intf, forceClaim); connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
为了异步的发送数据, 我们使用类UsbRequest
来初始化initialize
和序列化 queue
一个异步的请求, 然后调用方法requestWait()等待请求
.
更多信息请看AdbTest sample, 例中展示了如何进行大容量的异步传输, 还有例子MissleLauncher sample, 这个例子展示了如何异步的监听一个可阻断的端点。
当完成了与设备的交互、设备断开、关闭接口UsbInterface或者连接UsbDeviceConnection调用了方法releaseInterface()和close(). 为了监听设备断开事件,我们创建一个像下面这样创建一个广播接收者:
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 closes communication with the device } } } };