翻译Android USB HOST API

源码地址:http://developer.android.com/guide/topics/connectivity/usb/host.html

译者注:翻译的好不好不是太重要,重点是在翻译的过程中会把每句话都看认真看一遍,或者说是抱着翻译的思想来完成一个读懂的目的。

USB Host通信

当你的可供电Android设备处理USB host模式时,它担任着为USB总线供电,枚举连接的USB从设备等等一个主设备应用的工作。Android 3.1及以后版本开始支持USB host模式。

API概述

开始之前,有必要弄明白以后要用到的类。下表中描述了包含在android.hardware.usb包中的USB host APIs。

表1. USB host APIs.

Class

Description

UsbManger

允许你枚举USB从设备以及和其通信

UsbDevice

代表一个USB从设备,获取其信息。如接口,端点等等。

UsbInterface

代表一个USB从设备的接口,一个设备可以拥有多个接口用于通信。

UsbEndpoint

代表接口的一个端点,它是该端点一个通信通道。一个接口可以拥有一个或者多个端点,通常输入输出端点用于和设备进行双向通信。

UsbDeviceConnection

代表一个设备的连接,通过端点传输数据,该类允许你发送接收数据,通信方式可以是同步或者异步。

UsbRequest

代表通过UsbDeviceConnection通信的异步请求。

UsbConstants

定义USB常量对应Linux内核中linux/usb/ch9.h中的宏。

多数情况下,在和USB设备进行通信的时候,你需要使用这里所有的类(UsbRequest只用在异步通信一个请求)。一般是这样的,使用UsbManager来获取UsbDevice。确定了设备,需要查找用于通信接口的UsbInterface和UsbEndpoint。一旦获取了恰当的端点,打开UsbDeviceConnection与USB设备进行通信。

下列表中描述了使用USB host APIs之前需要添加到应用程序的manifest文件中的内容:

由于并不是所有的Android带供电设备确保支持USB host APIs,添加 <uses-feature>对象来表明你的应用使用了android.hardware.usb.host特性。

SDK最低版本设置为12或者更高。USB host APIs不支持更老版本的API。

如果你想让你的应用检测一个USB设备的话,在主Activity指定 <intent-filter> 和<meta-data> 对象去匹配android.hardware.usb.action.USB_DEVICE_ATTACHED。<meta-data>对象指向一个外部的XML资源文件,文件中描述你想要探测的USB设备的过滤信息。

在这个XML资源文件中,为你想要过滤的USB设备声明<usb-device>对象。下列表中描述了<usb-device>的属性。通常,使用vendor 和 product ID过滤特殊设备,使用类,子类和协议来过滤一组设备,比如大容量存储设备(优盘)或者数码相机。你可以完全指定这个属性值,也可以一个也不指定。没有属性值说明会过滤每个一个USB设备。所以说,你的应用程序有这个需求的情况下可以指定。

  • vendor-id
  • product-id
  • class
  • subclass
  • protocol (device or interface)

保存资源文件到res/xml/目录下。资源文件名(不包含.xml后缀)必须要和<meta-data>中指定的相同。XML资源文件格式如果以下示例:

<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>

在本例中,以下资源文件应该保存在res/xml/device_filter.xml中,指定需要过滤USB设备的属性:

<?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上时,无论你的应用程序是否对此USB设备感兴趣Android系统都会检测到。你可以和设备建立通信。你的应用程序需要做如下事情:

1.探测USB设备通过意图过滤器检测用户连接的设备,或者枚举已经连接的USB设备。

2.如果之前没有请求过,向用户请求权限以连接USB设备。

3.和USB设备进行通信,通过接口端点读写数据。

探测设备

应用程序可以通过两种方式进行USB设备的探测,使用意图过滤器监听用户连接设备或者枚举已经连接的USB设备。前者可以方便的实现自动检测设备。如果想列出所有的已连接设备或者没有使用意图过滤器过滤的设备,可以使用枚举设备来完成。

使用意图过滤器

探测设备可以指定意图过滤器来过滤android.hardware.usb.action.USB_DEVICE_ATTACHED意图。此外需要指定一个资源文件描述USB设备,比如product and vendor ID. 当用户连接上和你探测的设备匹配时,系统会弹出一个对话框询问用户是否允许启动的你的应用程序。如果允许,你的应用程序将会自动被赋予权限和该设备通信,直到设备被移除。

以下示例显示如何描述意图过滤器:

<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,它代表使用意图探测到的设备。如:

UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

枚举设备

在你的应用程序运行时,如果对所以当前正在连接的USB设备感兴趣,可以枚举设备。枚举设备使用的是getDeviceList()方法获取所有连接设备的哈希表。如果你想获取一个设备可以根据USB设备的名字为关键字进行索引。

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设备以及与设备通信。通信之前你需要检查权限,否则如果用户权限拒绝你将会收到一个运行错误。

申请权限,首先创建创建一个广播接收器。调用requestPermission()时,接收器监听广播意图。调用requestRermission()向给用户显示一个对话框请求连接该设备的权限。

下列代码显示如何创建这样一个广播接收器:

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意图,它是一个布尔代表答案。通信之前检查这个额外值是否为真。

与设备通信

通信方式可以是同步或者异步。在这两种情况下,你应该创建一个线程执行所有数据的传输,不要阻塞界面线程。建立一个通信,你需要获取需要通信设备的UsbInterface和UsbEndpoint,以及使用UsbDeviceConnection申请端点。一般地,你的代码应该是:

  • 检查UsbDevice对象的属性,比如 product ID, vendor ID或者设备类别。以识别是不是需要通信的设备。
  • 如果确定了是要通信的设备,检索出你需要通信设备的接口,以及该接口的端点。接口可以有一个或者多个端点,一般会有输入输出各一的双向通信的端点。
  • 如果确定了端点,在该端点上打开 UsbDeviceConnection。
  • 使用bulkTransfer()或者controlTransfer()方法将需要传输的数据提供到端点上。你需要将上述操作实现在其它线程以免阻塞当前主界面线程。更多关于Android中线程的使用,见Processes and Threads.

下面的代码片段简单的实现了同步数据传输。你的代码应该使用更多逻辑上的来查找出正确的通信接口和端点,同样需要在主界面以外的线程中进行数据的传输:

private Byte[] bytes
private 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例子,它显示了如何进行块传输的方法异步通信,以及MissleLauncher sample它显示了如何监听中断端点异步。

终止通信

当完成了通信或者设备被移除了,调用releaseInterface()和close()来关闭UsbInterface和UsbDeviceConection。监听设备移除事件,创建一个广播接收器如下:

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}}}
};

创建广播接收器是在应用程序内部,而非manifest中。仅在应用程序程序运行时处理设备移除事件。如此,移除事件只会发送给正在运行的应用而不是所有的应用。

感悟:

  • 与原文无关纯属个人感想,USB通信越向下越复杂。Android封装好一些,其次是libusb,再然后就是Linux内核中进行的USB通信。依次需要了解的知识多少都不一样,比如这个完整的通信过程中并没有用到urb等等。
  • 目前测试的Android4.2.2上通信的最大块为:16KiB。所以数据要分割为16KiB大小进行传输。
  • 文件中提到的那个例子AdbTest和MissleLauncher的源码位于:development/samples/USB/中。前者功能是读取usb设备(同样也是Android系统)的LOG,后者功能是控制一个火箭发射器玩具。
  • Android这套API并不能检测所有的USB设备,有些设备检测不到。比如无线数据的适配器。目前测试成功的有打印机。
  • 关于对其了解的程度,我一直有个毛病就是了解一个东西没有上限。类似写文章没有主线,想到哪里就深入到哪里。我要逐渐改点这个习惯。我对这个的练习是将数据发送打印机,完成打印。当我刚刚实现的时候,我就又开始幻想我是不是可以做一个很牛叉的USB打印APP了。这个是可以实现的,但并不是目前的主要任务,如果我坚持做,很多东西都需要去实现,这也违背了我当前仅仅是了解Android USB host API的初衷。还好,这次我刹住了闸,毕竟我这次是真实的了解了,之前只知道在Linux内核中的通信以及基于Libusb通信,直接使用java通信的好处是解析xml等等在C语言中相对复杂的东西到java中都不显示复杂了。
  • l 测试APK和上文提到的那两个例子打包上传到Here,方便那些没有Android系统源码的同志。

翻译Android USB HOST API相关推荐

  1. Android 系统使用USB OTG功能/打开USB Host API功能

    步骤一:确定 Android 设备是否支持 USB Host 功能,具体可以通过以下步骤进行确认: 1. 查看手机或平板设备参数,或者直接联系厂家咨询: 2. 使用 UsbHostDiagnostic ...

  2. Android USB Host与HID通讯(二)

    2019独角兽企业重金招聘Python工程师标准>>> 原文出处:http://han21912.lofter.com/post/c3919_51401d 接上一篇:Android ...

  3. Android USB Host与HID通讯

    Android USB Host与HID通讯 (一) Android USB Host与HID通讯 (二) Android USB Host与HID通讯Demo android usb host 读写 ...

  4. android USB host编程

    测试手机:华为p8 测试系统:android ------------------------------------------- android的native层usbhost供java层andro ...

  5. Android usb host

    当你的Android主机是处于USB主模式下,它充当USB主机,开启设备并列举出所有已连接的USB设备.这种模式在Android 3.1及以上的版本支持. API预览 在开始开发USB Host之前, ...

  6. android usb host hid,Android USB Host与HID通讯

    前端时间捣鼓一个HID的硬件, 需要和android通信, 网上搜索了一圈,收获不小. 其中代码之处有些地方需要注意的, 特此注明一下: /*** USB HOST 连接 HID *@authorIV ...

  7. Android USB Host开发之manager.getDeviceList()获取不到设备列表【转载】

    原文:https://www.2cto.com/kf/201305/211304.html 同样遇到这样的问题,我的Android设备是原道N12C,官方的4.0.3系统,遇到这个问题,后来找了半天找 ...

  8. Android USB Host开发之manager.getDeviceList()获取不到设备列表

    同样遇到这样的问题,我的Android设备是原道N12C,官方的4.0.3系统,遇到这个问题,后来找了半天找到的,现在汇总一下吧: 1.创建 android.hardware.usb.host.xml ...

  9. android otg读写文件,Android USB Host在USB设备OTG中读/写文件

    我正在编写Android设备是主机的应用程序.用户将USB驱动器连接到Android设备,我的应用程序将在USB驱动器中写入一些文本文件.文本文件的路径就像USB_DRIVE/Data/APP_NAM ...

最新文章

  1. OPPO小游戏vConsole开启方法
  2. java断言assert初步使用:断言开启、断言使用
  3. AccountManagment
  4. 20应用统计考研复试要点(part33)--简答题
  5. 带有API网关的AWS Lambda
  6. 基于IntelliJ IDEA和Ubuntu的Chisel开发环境搭建
  7. 中科大 计算机网络1 课程主要内容大概介绍
  8. (pytorch-深度学习系列)pytorch实现多层感知机(手动定义模型)对Fashion-MNIST数据集进行分类-学习笔记
  9. 小区信息发布服务器,基于串口服务器的智能小区信息发布系统
  10. php算法求出一个数可以被分解成多少个_面试时写不出排序算法?看这篇就够了(下)...
  11. HTML示例06---水平线
  12. ArcGIS导出地图后部分图例不显示
  13. Hadoop实战第2版 - 电子书下载(高清版PDF格式+EPUB格式)
  14. java 删除 指定图片_java删除服务器上指定图片
  15. 电子合同的一个“安全漏洞”
  16. 【转载】常备JS操作
  17. 【2020年保研记】浙大软院+中科院信工所+北师大人工智能学院+华中科技网安学院+四川大学网安学院+中山大学系统科学与工程学院
  18. k8s-搭建虚拟机centos7环境,虚拟机固定IP地址
  19. 金蝶K3案例教程应收账款前台操作
  20. PS渐变自行车的做法

热门文章

  1. 人气头像榜单壁纸套图下载流量主微信小程序开发
  2. 慕课HTML学习之网页链接
  3. Spring Cloud Gateway 过滤器执行顺序原理分析
  4. mysql 安装 se_mysql-5.7安装
  5. 全球及中国预取向丝POY行业市场运营模式与投资规划研究报告2022-2028年
  6. 我用python玩炉石传说(2)-----炉石卡牌套牌爬取器及自动分析卡牌相关度
  7. R语言用CPV模型的房地产信贷信用风险的度量和预测
  8. docker rm -r 删除容器如何恢复数据?
  9. js获取滚动条的高度
  10. php如何禁掉文本框输入,如何禁止input文本框输入