安卓USB开发教程 二 USB Host

USB Host(主机模式)

当 Android 设备处于 USB 主机模式时,它充当 USB 主机,为总线供电,并枚举连接的 USB 设备。Android 3.1 及更高版本支持 USB 主机模式。

API 概述

在开始之前,理解需要使用的类是很重要的。下表描述了 android.hardware.usb 包里的 USB 主机 API 函数。

Table 1. USB Host APIs

Class Description
UsbManager 负责枚举和与连接的 USB 设备通讯
UsbDevice 表示连接的 USB 设备并且包含访问其标识信息,接口和端点的方法
UsbInterface 表示 USB 设备的接口,它定义了设备的一组功能。 设备可以具有一个或多个接口进行通信。
UsbEndpoint 表示接口端点,它是该接口的通信通道。 接口可以有一个或多个端点,并且通常具有与设备进行双向通信的输入和输出端点。
UsbDeviceConnection 表示与设备的连接,该设备在端点上传输数据。 该类允许您以同步方式或异步方式来回发送数据。
UsbRequest 表示通过UsbDeviceConnection与设备通信的异步请求。
UsbConstants 定义与Linux内核的linux / usb / ch9.h中的定义对应的USB常量。

在大多数情况下,与 USB 设备通讯时需要使用所有这些类(UsbRequest 只在异步方式通讯的时候需要)。通常,会获取一个 UsbManager 来检索所需的 UsbDevice。当获取到设备时,需要查找合适的 UsbInterface 与接口中用于通讯的UsbEndpoint。一旦获取到正确的端点,打开一个 UsbDeviceConnection 与 USB 设备通讯。

Android Manifest 要求

下面的清单描述了在使用 USB host API 函数前需要添加到应用清单文件的内容:

1. 由于并非所有安卓设备被授权支持 USB host API 函数,因此需要包含一个 <uses-feature> 元素来声明你的应用使用 android.hardware.usb.host功能

2. 设置应用的最低 SDK 版本为 API 级别 12 或更高。USB host API 函数在更早的 API 级别中不存在。

3. 如果你希望应用收到 USB 设备插入的通知,请在主活动中为 android.hardware.usb.action.USB_DEVICE_ATTACHED 意图指定<intent-filter>  <meta-data> 元素对。<meta-data> 元素指向一个外部 XML 资源文件,它声明了要检测的设备的信息。

4. 在 XML 资源文件中,为你想过滤的 USB 设备声明 <usb-device>元素。下表描述了 <usb-device> 的属性。

通常,如果要过滤特定的设备使用厂商和产品 ID,如果要过滤一组 USB 设备使用 USB 类、子类和协议,如大容量存储类和数码相机。

你可以指定这些属性中的一个或者全部,不指定属性匹配任何 USB 设备,因此在应用需要时才进行指定:

vendor-id

product-id

class

subclass

protocol (device or interface)

将资源文件保存在 res/xml/ 目录中。资源文件名(不含 .xml 扩展名)必须与您在 <meta-data> 元素中指定的文件名相同。XML 资源文件的格式在下面的示例中。

Manifest 与资源文件示例

以下示例展示了 manifest 样例以及相应的资源文件:
<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 设备时,Android 系统可以确定应用程序是否对连接的设备感兴趣。如果是这样,您可以根据需要建立与设备的通信。为此,您的应用程序必须:

1.通过使用 intent filter 在用户连接设备时收到通知或通过枚举已连接的 USB 设备来发现 USB 设备

2. 请求用户连接 USB 设备的权限,如果尚未获得。

3. 通过在相应的接口端点上读写数据与 USB 设备进行通信。

发现设备

应用程序可以通过使用intent filter 在用户连接设备时收到通知或通过枚举已连接的 USB 设备来发现 USB 设备。如果您希望能够让应用程序自动检测到所需的设备,则使用 intent filter 非常有用。 如果要获取所有连接的设备列表,或者您的应用程序没有为 intent 进行过滤,则枚举已连接的 USB 设备的方法非常有用。

使用 intent filter(意图过滤器)

要使您的应用程序发现一个特定的 USB 设备,可以指定一个 intent filter 来过滤android.hardware.usb.action.USB_DEVICE_ATTACHED intent。 除了此 intent filter,您还需要指定一个资源文件,该资源文件指定USB设备的属性,如产品和供应商ID。 当用户连接与 device filter 匹配的设备时,系统会向他们显示一个对话框,询问他们是否要启动应用程序。 如果用户接受,应用程序自动获得访问设备权限,直到设备断开连接。

以下示例展示如何声明 intent filter:

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

在你的活动中,你可以像这样从 intent 中获取表示连接设备的 UsbDevice :

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

枚举设备

当应用程序运行时,如果应用程序有兴趣检查当前连接的所有 USB 设备,它可以枚举总线设备。使用 getDeviceList()方法获取所有已连接 USB 设备的哈希表,如果要从表中获取设备,通过作为键值传入的 USB 设备名

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");

如果需要,还可以从哈希表中获取 iterator(迭代器),并逐个处理每个设备:

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设备进行通信之前,应用程序必须获得用户的许可。

Note:如果应用程序使用 intent filter 来发现连接时的 USB 设备,则如果用户允许您的应用程序处理 intent,则它将自动接收权限。如果没有,您必须在连接到设备之前在应用程序中明确请求权限。

在某些情况下,显式请求许可可能是必需的,例如当您的应用程序枚举已连接的USB设备,然后要与其进行通信时。在尝试与之通信之前,您必须检查访问设备的权限。如果没有,用户拒绝访问设备的权限时,您将收到 runtime 错误。

要明确获得许可,首先创建一个广播接收器。该接收器侦听当您调用 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);}}}}
};

要注册广播接收器,在活动的 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 的 intent,这是表示答案的布尔值。 在连接设备之前,请检查这个额外值是否为 true。

与设备通信

与USB设备的通信可以是同步或异步的。在任一情况下,您应该创建一个新线程来执行所有数据传输,才不会阻塞UI线程。要正确建立与设备的通信,您需要获得要进行通信的设备的相应的UsbInterface UsbEndpoint,并使用UsbDeviceConnection 在此端点上发送请求。一般来说,您的代码应该:

1. 检查UsbDevice 对象的属性,如产品 ID,供应商 ID或设备类,以确定是否要与设备进行通信;

2. 当您确定要与设备通信时,请找到与合适的UsbEndpoint 进行通信的相应UsbInterface。接口可以具有一个或多个端点,并且通常会具有用于双向通信的输入和输出端点;

3. 找到正确的端点时,在该端点上打开一个UsbDeviceConnection

4. 使用bulkTransfer() 或controlTransfer() 方法提供在端点上传输的数据。您应该在另一个线程中执行此步骤,以防止阻塞主 UI 线程。有关在 Android 中使用线程的更多信息,请参阅 Processes and Threads

以下代码片段是进行同步数据传输的简单方法。您的代码应该有更多的逻辑来正确找到正确的接口和端点进行通信,并且还应该在与主UI线程不同的线程中进行数据传输:

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() 等待结果。

终止与设备通信

当你与设备通信完成或者设备拔出时,调用 releaseInterface()  close() 方法关闭 UsbInterface  UsbDeviceConnection为了监听拔除事件,如下所示创建广播接收器:

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 中创建广播接收器允许应用在运行时只处理拔除事件。通过这种方式,广播事件只会发送到当前正在运行的应用程序而不是广播到所有应用。

原文链接:https://developer.android.com/guide/topics/connectivity/usb/host.html





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403062.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓USB开发教程 三 USB Accessory

USB Accessory&#xff08;配件模式&#xff09; USB 配件模式允许用户连接专为 Android 设备设计的 USB 主机硬件。配件必须遵守 Android Accessory Development Kit 文档中列出的 Android 配件协议。 这使得 Android 设备无法充当 USB 主机时仍然可以与 USB 硬件交互。 当 A…

Android ADB

Android 调试桥 本文内容 adb 的工作方式在您的设备上启用 adb 调试通过 WLAN 连接到设备查询设备将命令发送至特定设备安装应用设置端口转发将文件复制到设备/从设备复制文件停止 adb 服务器adb 命令参考发出 shell 命令 调用 Activity Manager (am)调用软件包管理器 (pm)进行…

轻松访问 Android 系统源码与下载

有时研究 Android 某个特性或者协议的时候需要参阅安卓系统源代码中代码实现或者协议文档等。通过正常的建立 repo&#xff0c;git 获取十分耗时&#xff0c;并且速度很慢&#xff0c;除非是需要重新编译系统&#xff0c;定制系统才需要这样做。因此&#xff0c;推荐一个 Andro…

安卓系统源代码下载(官方教程)

下载源代码 Android 源代码树位于由 Google 托管的 Git 代码库中。Git 代码库中包含 Android 源代码的元数据&#xff0c;其中包括与对源代码进行的更改以及更改日期相关的元数据。本文档介绍了如何下载特定 Android 代码流水线的源代码树。 要从特定设备的出厂映像开始&#x…

Cygwin 下载极速源推荐

Cygwin 默认列表中的源下载速度太慢&#xff0c;国内使用时常用以下几个源&#xff0c;经过实际使用速度很快&#xff0c;下载时不妨几者都尝试下&#xff1a; 如上图所示&#xff0c;下载时在此栏填写 URL 地址即可&#xff0c;推荐地址&#xff1a; http://mirrors.sohu.com…

安卓USB开发教程 四 安卓 AOA

Android 开放性配件协议&#xff08;AOA&#xff09; Android 开放性配件协议&#xff08;AOA&#xff09;支持允许外部 USB 硬件&#xff08;Android USB 配件&#xff09;与工作在配件模式下的 Android 设备进行交互。当处于配件模式的 Android 设备被供电&#xff0c;所连接…

安卓USB开发教程 五 安卓 AOA 1.0

Android Open Accessory Protocol 1.0&#xff08;AOA 协议 1.0&#xff09; Android USB 配件必须遵从 Android Open Accessory&#xff08;AOA&#xff09;协议&#xff0c;该协议定义了配件如何检测和建立与 Android 设备的通信。配件应执行以下步骤&#xff1a; 1. 等待并…

安卓USB开发教程 六 安卓 AOA 2.0

Android Open Accessory Protocol 2.0 目录 Detecting AOAv2 support Audio support HID support Interoperability with AOAv1 Connecting AOAv2 without an Android app This document describes changes in the Android Open Accessory (AOA) protocol since its initial re…

Linux 驱动编译报错:error: macro __DATE__ might prevent reproducible builds [-Werror=date-time]

编译驱动时遇到这个错误提示&#xff0c;表示当前编译环境中将关于 DATE 以及 TIME 的警告也作为错误来进行处理的。有如下几种方法可以参考&#xff1a; 1. 在编译驱动的相应 Makefile 中增加一行&#xff1a;CFLAGS -Wno-errordate-time&#xff0c;然后保存重新 make&…

Java 结构体之 JavaStruct 使用教程一 初识 JavaStruct

Javastruct 是什么 简而言之&#xff0c;Javastruct 是一个第三方库&#xff0c;用于像处理 C 或者 C 结构体那样处理 java 对象。也即利用 Javastruct 可以在 java 上实现类似于结构体的功能和操作。 Javastruct 的用途 在 java 或者 Android 应用程序与一些嵌入式设备通讯…

Java 结构体之 JavaStruct 使用教程二 JavaStruct 用例分析

使用环境 前一篇在介绍 JavaStruct 类时指定了使用库使用环境为 Java 5 及以上&#xff0c;也即开发我们使用的 JDK 版本为1.5及以上就可以了。以下讲解的用例可以直接将 code 直接粘贴到 java 的 main 函数中执行就可以了&#xff0c;后面会给出测试用例和结果。 使用方法 Jav…

Java 结构体之 JavaStruct 使用教程三 JavaStruct 数组进阶

经过前面两篇博客的介绍&#xff0c;相信对于 JavaStruct 的认识以及编程使用&#xff0c;读者已经有一定的基础了。只要理解和实践结合起来&#xff0c;掌握还是很容易的。下面进行一些数组使用方面的实例说明及演示。 在结构体类中使用数组有几种方式&#xff0c;可以使用静…

Android开发如何使用JNA

1. JNA&#xff08;Java Native Access&#xff09;项目已经迁移到 github&#xff0c;最新的项目链接&#xff1a;https://github.com/java-native-access/jna 。首先前往该地址下载使用 JNA 需要的两个 jar 库文件&#xff0c;jna.jar&#xff0c;jna-platform.jar 。 2. 在…

JAVA循环队列

关于自定义循环队列的实现原理和要点可以参见之前的博文系列&#xff1a;循环队列及C语言实现。这里主要对JAVA下的具体实现方式与原理进行说明。 一、JAVA 中已经自带了 Queue、DQueue、ArrayList、LinkedList 等常用的数据结构&#xff0c;为什么还要单独实现循环队列&#…

VMware 虚拟机占用磁盘空间

使用VMware创建的虚拟机尽管已经设定分配的磁盘大小&#xff0c;但仍然会发现虚拟机占用的磁盘空间会越来越大&#xff0c;而直观体现就是虚拟机系统文件 vmdk 不断增大。因此下面介绍一个简单的方法&#xff0c;使用 VMware 自带的工具对 vmdk 文件进行压缩以节省磁盘空间。拿…

frameworks/av/media/CedarX-Projects/CedarAndroidLib/LIB_KK44_/Android.mk: No such file or directory

在安卓系统编译过程中如果遇到上述或者与之类似的错误&#xff0c;可以采取相同的处理方法进行解决。直接进入到 CedarAndroidLib 目录下&#xff0c;也即此例中的 frameworks/av/media/CedarX-Projects/CedarAndroidLib。看一下当前文件&#xff1a; 注意第9行为包含标题中报错…

《言简意赅之Linux设备驱动编程》 前言

linux 内核与驱动开发是一门很深的学问&#xff0c;主要是由于覆盖知识面较广、内核架构设计层级较深、软硬件知识要兼具。因此自己在学习理解时会经常遇到某一章节需要反复阅读理解多次。所以&#xff0c;我想用一种言简意赅的方式讲述 Linux 内核与设备驱动开发。我认为把一个…

Windows与Linux下tftp服务的使用

tftp 协议是基于 udp 的&#xff0c;轻量小巧&#xff0c;用在局域网和嵌入式上很顺手。大部分帖子把在 linux 上配置的过程描述的过于复杂&#xff0c;其实只是个工具而已。研究协议抓下包对比协议内容也可以满足需求了&#xff0c;下面进入正文。分别讲下在 linux 以及 windo…

Vmware提示:the operation was canceled by the user

一般遇到这种情况是由于当前虚拟机资源中的资源文件被其他进程占用导致的。如果你的系统中有 DAEMON Tools Lite 软件&#xff0c;那么多半是因为这个原因。因此下面针对此情况提出两种解决办法&#xff1a; 1. 检查有无安装 DAEMON Tools Lite 软件&#xff0c;若安装此程序&a…

USB OTG 的进一步理解

一直以来在做安卓系统相关的嵌入式通讯&#xff08;USB、BLE、网络、串口等&#xff09;&#xff0c;最近在讨论 OTG 问题的时候&#xff0c;对该规范又重新理解了一次&#xff0c;这里仅做一些概要和核心点说明&#xff0c;下方会给出具体 OTG 包含协议的参考链接&#xff0c;…