原文:http://android.eoe.cn/topic/summary

文档内容

  • API概述
  • Android中manifest文件需求
  • 工作的设备
  • * 发现设备
  • * 获得和设备进行“交流”的权限
  • * 和设备进行“交流”
  • * 中止和设备的“交流”

相关例子

  • Adb测试用例
  • 相关链接 当您搭载Android系统的设备处于USB主机模式时,它就像一个USB主机,为总线提供能源,并且列举出所有已经连接上的设备。在Android 3.1或者更高的版本中支持USB主机模式。

API概述

在您开始之前,有个很重要的一点就是您必须对将要用到的类有个了解。下面的表格就向您描述了在android.hardware.usb这个包下USB主机APIs的一些特点。

  • 表1.* USB主机APIs <!-- 表格开始 --> {|style="border-spacing: 0px;margin: 4px 4px; width: 90%; border-left:1px solid #ccc;border-top:1px solid #ccc; "

<!-- 这段是表头 -->
|-style="background:#DEE8F1; "
! style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px" | Class/Interface
! style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px" | Description

<!-- 这段是表格 -->
|- style=" vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px; " |
UsbManager
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px; " |
允许您枚举已连接的USB设备并且与其进行“交流”。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbDevice
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
代表了一个已连接的USB的设备并且包含具有该设备验证信息,接口和接入点的方法。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbInterface
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
代表了一个USB设备的一个接口,该接口定义了一系列关于设备的函数。一个设备在进行“交流”的时候可以有一个或者多个接口。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbEndpoint
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
代表一个接口的接入点,该接入点就是这个接口的通信信道。一个接口可以有一个或者多个这样的接入点,而且一般都是有输入和输出双向通信的接入点。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbDeviceConnection
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
代表该设备的一个连接,用来在接入点上传输数据。这个类允许您能用同步或者异步的方式发送和返回数据。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbRequest
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
在通过UsbDeviceConnection和设备进行“交流”的一个异步请求。

<!-- 这段是表格 -->
|- style="vertical-align:top;"
| style=" border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
UsbConstants
| style="border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding:5px 15px;" |
关于在linux内核中linux/usb/ch9.h的相关定义的USB常量。
|}
<!-- 表格结束 -->
在大多数的情况之下,在和一个USB设备进行“交流”时,上面这些类都需要用到(UsbRequest这个类只有在您做异步通信的时候才会用到)。一般来说,您可以通过查询要操作的UsbDevice来获得一个UsbManager。当您有这个设备时,您需要找到正确的UsbInterface以及和这个接口所对应的UsbEndpoint来进行和设备的“交流”。一旦您获得了正确的接入点,打开UsbDeviceConnection来和该USB设备进行“交流”。

Android中manifest文件的需求

下面的列表就是描述您应该在用USB主机APIs之前应该在您的应用中的manifest文件中添加些什么:
* 因为不是所有的搭载Android系统的设备都能保证支持USB主机的APIs,不能包含那个声明您的应用使用android.hardware.usb.host的这一元素。
* 设置您的应用的最低的SDK版本在12级或者更高。这个USB主机APIs不在更前面的版本之中。
* 如果您希望您的应用能够被连接的USB设备所提示,只要在您的主activity中在元素对中添加一个元素指向一个额外的XML资源文件,该文件是用来声明验证您希望探测到的设备的验证信息。
   在这个XML资源文件中,为您希望过滤的USB设备声明的属性。一般来说,如果您想为一个特定的设备过滤就使用该产品的供应商和产品ID,如果您希望为一组USB设备,例如大量存储设备或者是数码相机来进行过滤那么就应该用类,子类和协议。您可以不指定这些属性,也可以指定所有的属性。不为每个设备指定属性,只有在您的应用需要它时才这么做(这句话翻译的一点问题^_^):
:* 供应商ID
:* 产品ID
:* 类
:* 子类
:* 协议(设备或者借口)
   将您的资源文件保存到元素中指明的那个名字。在下面的例子中是这个XML资源文件的格式。

Manifest文件和资源文件的例子

下面的例子告诉您一个manifest文件以及与它相关资源文件的例子:

...

...

1
2
3
4
        <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>

在这种情况下,下面的资源文件应该被保存在res/xml/device_filter.xml来确保找到那些特定符合您要求属性的USB设备:

<?xml version"utf-8"?>

用配件工作

当用户将USB配件连接到搭载Android系统的设备上面时,Android系统会判断您的应用是否适用于已连接的该配件。如果适用,您就可以根据您的喜好为该设备建立连接。要这么做,您的应用必须做下面这些动作:

您需要通过一个可以过滤USB设备附加事件的意图过滤器或者枚举已连接的USB设备来发现连接的配件来找到合适的接口。

尚未获得许可的用户在适用USB设备操作时需要验证权限。

通过在接入的端点进行读写数据的操作达到和USB设备交互的目的。

发现设备

您的应用可以通过两种方式来发现USB设备,一种是用一个意图过滤器在用户连接一个设备时对其进行通知,另一种则是通过枚举您已经连接的所有USB设备。如果您希望您的应用能够自动的探测到你想要的设备,请使用一个意图过滤器来做。但是,如果您希望得到一个已连接设备的列表或者您不希望过滤意图,枚举所有的设备会是一个更好的选择。

使用一个意图过滤器

为了让您的应用可以发现一个特定的USB设备,您可以为android.hardware.usb.action.USB_DEVICE_ATTACHED这个意图指定一个意图来进行过滤。伴随着这个意图过滤器,您需要指定一个资源文件来特别说明这个USB设备的属性,例如供应商和产品ID。当用户连接到一个符合您配件过滤条件的配件时,这个系统会谈出一个对话框询问他们是否希望开始您的应用。如果用户同意,那么您的应用在失去连接之前会自动获取和设备连接的权限。

下面的例子告诉您该如何声明这个意图过滤器:

...

1
2
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />

下面的例子告诉您怎么样声明指定您希望连接的USB设备的相关资源文件:

<?xml version"utf-8"?>

在您的activity文件中,您可以从像这样的意图(有附加类的)中获取UsbDevice来代表这个相关的配件:

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

枚举所有配件

您可以使您的应用在运行时列举出所有能够被识别的USB设备。通过getDeviceList()方法来获得一个包含所有已连接USB配件的数组:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...

HashMap deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");

如果您喜欢,您也可以一个接一个的从每一个设备的哈希图和过程中获取一个迭代器:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap deviceList = manager.getDeviceList();
Iterator deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next()
//your code
}

获得使用一个配件的权限

在您使用一个USB设备前,您的应用必须从用户那里获得权限。

* 注意:* 如果您的应用在连接USB设备时通过一个意图过滤器来发现它们,如果用户允许您的应用来处理这个意图,它将自动接收这个权限。如果用户不允许,那么您就必须在连接设备之前详细在您的应用中写明需要请求的权限。

在某些情况下很有必要明确权限的许可要求,例如当您的应用枚举出所有已经连接的USB设备并且您希望和其中的一个进行“交流”。您必须在和该设备“交流”前检查是否有连接该设备的权限。如果不是这样,您的应用将在用户拒绝您连接该设备的权限之后收到个运行错误。

为了确切地获得权限,首先需要创建个广播接收器。这个接收器在您调用requestPermission()这个方法时从您得到的广播中监听这个意图。通过调用requestPermission()这个方法为用户跳出一个是否连接该设备的对话框。下面的例子告诉您如何创建一个广播接收器:

private static final String ACTION_USB_PERMISSION =
"com.android.example.USB_PERMISSION";
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);

当用户回应这个对话框时,你的广播接收器就会收到一个包含用一个boolean值来表示结果的EXTRA_PERMISSION_GRANTED字段的意图。在您连接设备之前检查这个字段的值是否为true。

和设备之间的“交流”

我们可以同步或者异步的和USB设备进行“交流”。在任意一种情况之下,您都应该创建一个新的线程来进行数据传输,这样就不会阻塞您的主线程了。要想正确的设置好和一个设备之间的连接,您需要获得该设备正确的UsbInterface和UsbEndpoint来和您进行“交流”以及通过UsbDeviceConnection在这个接入点上发送请求。一般来说,您的代码应该这样:
* 检查一个UsbDevice对象的属性,例如产品ID,供应商ID,或者是关于设备的类,以此来确认您是否希望和该设备进行“交流”。
* 当您确信您希望和该设备进行“交流”时,找到关于该设备正确的UsbInterface以及和该接口所对应的UsbEndpoint。接口可以有一个或者多个接入点,而且一般都会有一个双向通信的输入和输出接入点。
* 当您找到正确的接入点时,在该接入点时打开一个UsbDeviceConnection。
* 您可以通过bulkTransfer()和controlTransfer()这两个方法在接入点上传输您所需要传递的数据。您最好在另起一个新的线程来进行这个步骤以避免阻塞主线程。想要详细地了解关于Android中使用线程的信息,详见线程和进程。
下面的代码段是做同步数据传输的一个简单方式。您的代码应该有更多的逻辑来准确地找到和设备“交流”的接口和接入点,而且应该能够在不同于主线程的线程中能够传输任何的数据传输。

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类来初始队列化一个异步请求,然后等待requestWait()方法的结果。

想要了解更多地信息,请您参考Adb Test sample,这个参考将会告诉您如何进行异步批量传输,还有MissleLauncher sample将会告诉您如何异步监听一个中断端点。

中止和设备的“交流”

当您在完成和设备的“交流”之后,又或者该设备被移除了,通过调用releaseInterface()和close()的方法来关闭UseInterface和UsbDeviceConnection。为了监听分离这样的事件,您需要创建一个如下的广播接收器:

BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();

1
2
3
4
5
6
7
  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文件中,允许您的应用只能在它运行的时候处理这样的设备分离事件。这样的话,设备分离这个事件就只向正在运行的应用广播,而不是向所有的应用进行广播。

【Android开发】Android Host详解(翻译自官方文档)的更多相关文章

  1. Android开发–Intent-filter属性详解

    Android开发–Intent-filter属性详解 2011年05月09日 ⁄ Andriod ⁄ 暂无评论 ⁄ 被围观 1,396 views+ 如果一个 Intent 请求在一片数据上执行一个 ...

  2. android 开发 View _6_Canvas详解

    牛逼大神的博客地址:http://www.gcssloop.com/customview/Canvas_BasicGraphics 安卓自定义View进阶-Canvas之绘制图形 在上一篇自定义Vie ...

  3. Apache Flume入门指南[翻译自官方文档]

    声明: 根据官方文档选择性的翻译了下,不对请指正 https://flume.apache.org/FlumeUserGuide.html

  4. 自己翻译 delegation 官方文档

    什么是代理,知道怎么用,见过N次.会用代理传值,还不够.代理到底是用来干嘛的嘛?还是看看官方文档吧,自己翻译出来看看是不是通顺 代理: 代理是一个简单高效的模式,尤其是一个类在编程的过程中代表或者需要 ...

  5. 为开源社区尽一份力,翻译RocketMQ官方文档

    正如在上一篇文章中写道:"据我所知,现在RocketMQ还没有中文文档.我打算自己试着在github上开一个项目,自行翻译."我这几天抽空翻译了文档的前3个小节,发现翻译真的不是一 ...

  6. [翻译]PyMongo官方文档

    PyMongo官方文档翻译 周煦辰 2016-06-30 这是本人翻译的PyMongo官方文档.现在网上分(抄)享(袭)的PyMongo博客文章很多,一方面这些文章本就是抄袭的,谈不上什么格式美观,另 ...

  7. 我为什么要翻译ES6官方文档

    ES6出来很久了,现在网上也有很多教程,其中以阮一峰老师的教程最为经典.大家通过学习阮老师的教程肯定能学懂ES6最新的技术. ES6官方文档是一个规范,各浏览器在实现ES6的具体API时都会遵循它.我 ...

  8. 搭建Android开发环境附图详解+模拟器安装(JDK+Eclipse+SDK+ADT)

    ——搭建android开发环境的方式有多种,比如:JDK+Eclipse+SDK+ADT或者JDK+Eclipse+捆绑好的AndroidSDK或者Android Studio. Google 决定将 ...

  9. Android 开发 之 Fragment 详解

    本文转载于 : http://blog.csdn.net/shulianghan/article/details/38064191 本博客代码地址 : -- 单一 Fragment 示例 : http ...

随机推荐

  1. 用Power BI解读幸福星球指数

    "你幸福吗?"已经成了网络热词,简单的问句背后蕴含着一个普通中国人对于所处时代的政治.经济.自然环境等方方面面的感受和体会.引发当代中国人对幸福的深入思考.实际上,国际上对幸福的讨 ...

  2. JavaWeb项目配置化之Properties类的使用

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6397370.html  在项目中的应用见: https://github.com/ygj0930/Couple ...

  3. Generate BKS File( Bouncy Castle KeyStore)

    echo "Enter BKS output file name : \c" read filename echo "Enter BKS Password : \c&qu ...

  4. 亲历H5移动端游戏微信支付接入及那些坑(三)——支付接入

    终于到接入支付了,小小的一个微信支付,居然也写了3篇,好长,好累. 接入环境 对接入环境,前端的话,应该是以js为主吧,也有可能是,PHP,Java,C++,或者C#都可以.为什么在此特意提一下接入环 ...

  5. 读取csv文件并打印其结果

    In [5]: import pandas as pd In [6]: df=pd.read_csv('https://raw.githubusercontent.com/alstat/Analysi ...

  6. DATEDIF函数

    DATEDIF(start_date,end_date,unit) DATEDIF函数是Excel隐藏函数,在帮助和插入公式里面没有. 返回两个日期之间的年\月\日间隔数.常使用DATEDIF函数计算 ...

  7. Linux chattr 命令

    不让用户修改.删除文件等,使用 chattr保护 chattr命令的用法:chattr [ -RV ] [ -v version ] [ mode ] files… 最关键的是在[mode]部分,[m ...

  8. window.parent 与 Window.top

    window.parent 返回当前窗口的父窗口对象. 如果一个窗口没有父窗口,则它的 parent 属性为自身的引用. 如果当前窗口是一个 <iframe>, <object> ...

  9. kafka负载均衡相关资料收集(三)

    apache kafka系列之Producer处理逻辑 下文是转载的,原文链接地址:点这儿 [转] Kafka ProducerKafka Producer处理逻辑kafka生产者处理逻辑apache ...

  10. 解决编译Apache出现的问题:configure: error: APR not found

    今日编译apache时出错: #./configure --prefix……检查编辑环境时出现: checking for APR... noconfigure: error: APR not fou ...