【转载请注明出处】

首先介绍一个概念:USB Host and Accessory

Android通过两种模式支持一系列的USB外围设备和Android USB附件(实现了Android附件协议的硬件设备):USB从设备模式和USB主设备模式,在USB从设备模式下,外围的USB硬件设备作为USB主设备,从设备模式的例子包括扩展坞,读卡器等等。这使得Android设备不具备和USB硬件主动交流的能力,Android USB附件必须遵循Android附件交流协议。在USB主设备模式下,Android设备是作为主设备的,例子包括游戏控制器,数码相机等等。

下面两幅图展示了两种模式的区别。的那个Android设备处于主设备模式的时候,它给USB提供动力,当它是从设备模式的时候,连接的USB硬件设备作为主设备,给USB提供动力。

USB主设备和从设备模式在Android3.1(API 12)或者更新的平台上被直接支持,也可以在Android2.3.4(API 10)上被支持,需要一个add-on库,设备制造商可以选择是否在系统镜像中包含该库。(备注:对USB的主/从设备的支持完全独立于硬件,而且不限于API Level。开发者可以使用<uses-feature>元素来过滤支持USB主/从设备模式的设备)。

HSB Host

主设备模式下,你可以主动的和对方设备进行交互。涉及到的类包括:UsbManager,UsbDevice,UsbInterface,UsbEndpoint,UsbDeviceConnection,UsbRequest,UsbConstants.一般情况下你需要用到全部这些类(UsbRequest只在你需要进行异步通信的时候使用),你需要一个UsbManager对象去检索需要的UsbDevice对象,当你获得这个设备之后,就需要找到合适UsbInterface和它的UsbEndpoint进行交互,一旦获得了正确的endpoint,就可以打开一个UsbDeviceConnection与USB设备进行交互了。

Android Manifest Requirements

下面列举了在使用USB host API之前需要对应用的manifest文件作出的改变:

1)因为不是所有的Android设备都保证支持USB host API,所以应用中需要包含<uses-featrue>元素来声明,你的应用需要用到android.hardware.usb.host特征;

2)将SDK的最小值设置为12或者更高,USB host API在更早的版本上不被支持;

3)如果你想你的应用在有USB设备连接上去的时候得到通知,需要声明<intent-filter>和<meta-data>元素对(详情见后面),<meta-data>指向一个外部的xml资源文件,该文件描述了应用关心的设备的身份信息。在XML资源文件中,使用<usb-device>元素来过滤关心的USB设备,接下去的列表则描述了设备的属性,包括vendor-id,product-id,class,subclass,protocol。如果没有列出属性,则表示对任何设备都感兴趣。资源文件放在res/xml/文件夹下面,文件的名字必须和<meta-data>元素中声明的一样。例子:

 <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 文件,内容如下:

 <?xml version="1.0" encoding="utf-8"?>

 <resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>

和设备交互的步骤如下:

1)发现设备

应用可以通过intent filter发现设备或者主动列举已经连接的设备来发现设备。如果你想应用自动发现想要的设备,使用Intent-filter是非常有效的。如果你的设备没有过滤器,而且想获得连接设备的列表,列举USB设备就会变得非常有用。

使用Intent filter的manifest文件的改变如上代码已经列出,我们写明了一个Intent filter,用于过滤得到android.hardware.usb.action.USB_DEVICE_ATTACHED intent,然后写明xml文件,当连接的设备符合你的filter之后,系统会弹出一个对话框,询问是否打开你的应用,如果用户接受,你的应用就会自动获取访问设备的的权限,直到设备断开连接。

这个时候我们就在Activity中,使用下面的代码获取Intent代表的设备:

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

2)列举设备

如果你的应用在运行的时候对所有连接的设备都感兴趣,它可以列举在连接在总线上的所有设备,使用getDeviceList()方法就可以得到一个所有连接的设备的hash map列表。hashmap的key是设备的名字。代码如下:

 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
}

3)获取和设备交互的权限

在进行交互之前,应用必须获得用户的许可,也就是必须需要用户同意才可以和设备交互。(备注“如果你的应用使用intent-filter来发现设备,当用户允许应用处理Intent的时候就自动获取了权限,如果不是,则需要显示的向用户发出请求)

有些时候,显示的请求是必须的,假如不获取权限就进行交互,就会收到一个runtime error。为了显示的获取权限,首先需要创建一个广播接收器,接收器接收你调用requestPermission()方法产生的Intent,该方法调用会产生一个对话框询问连接到该设备的权限,下面是示例代码:

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

只需要下面的步骤就可以弹出对话框:

 UsbDevice device;
...
mUsbManager.requestPermission(device, mPermissionIntent);

当用户做出选择之后,就会产生一个广播,接收到之后就可以做出相应的判断。

4)和设备交互

和USB设备的交流既可以是同步的也可以是异步的,不管是哪种,都需要创建一个新的线程来执行数据传输以避免阻塞UI线程。为了和设备正确交互,我们需要获取设备正确的UsbInterface和UsbEndpoint,然后在该endpoint使用正确的UsbDeviceConnection发送请求。使用bulkTransfer()或者controlTransfer()方法传送数据。下面的代码是一段同步数据传输的例子,实际的代码需要更加严密的逻辑:

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

5)终止交互

当应用完成了交互或者设备被移除了,就需要通过调用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中,这样就可以使得只有在程序运行的时候监听到该事件,就可以让移除时间不会被发送给所有的应用程序而只是运行中的程序。

HSB Accessory

USB Accessory允许用连接专门为Android设备设计的USB主设备硬件。这些硬件必须遵循相应的协议。这允许不能作为USB主设备的Android设备也能和USB硬件交互,当一个设备处于USB从设备模式的时候,连接上来的硬件就是主设备,硬件就会给USB提供电能,并且列举连接的设备。

Choosing the Right YSB Accessory APIs

尽管USB Accessory API是在Android 3.1被引入的,它在Android 2.3.4上面也可以通过附加库使用,因为是通过外部库,总共有两个库可以被导入支持USB从设备模式,使用哪一个库决定于你支持的设备:

1)com.android.future.usb:为了在Android2.3.4上面支持USB从设备模式, Google APIs add-on library包含了这些API,并且就存在于该名称空间下面。Android3.1也支持导入和使用该名称空间中的类。这个库是android.hardware.usb中接口的一层薄包裹,并且不支持USB主设备模式,如果你想最大范围的支持USB从属设备模式,使用附加库,导入该包!值得注意的是并非所有的Android2.3.4设备都被要求支持USB accessory特征。每一个设备生产商自行决定是否要支持该功能,所有你要在你的manifest文件声明(是否需要使用该特征);

2)android.hardware.usb:该名称空间包括了Android3.1下面支持USB从属设备模式的所有类,它是Framework API的一部分,因而Androuid3.1并不需要附加库来实现从属设备模式,如果你只关心Android3.1或者更新的设备,你可以使用该库。

API Overview

有两个类涉及到Android从设备模式,一个是UsbManager,另外一个是UsbAccessory。因为附加库是framework API的一个包裹,所以接口基本一直,你可以看着android.hardware.usb库的文档使用附加库。但是略有不同:

如果你使用附加库,则可以使用以下代码获取UsbManager:

 UsbManager manager = UsbManager.getInstance(this);

否则使用如下代码:

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

使用Intent filter捕捉设备连接事件的时候,如果你是使用的附加库,则使用以下语句获取UsbAccessory:

 UsbAccessory accessory = UsbManager.getAccessory(intent);

否则使用如下代码:

 UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

Android Manifest requirements

下面列举了在使用USB accessory API之前需要对应用的manifest文件作出的改变:

1)因为不是所有的设备都保证支持USB accessory APIs,所以必须在文件中包含<uses-feature>元素,声明应用需要使用android.hardware.usb.accessory特征;

2)如果你是在使用附加库,则添加<uses-library>元素明确需要使用android.hardware.usb包;

3)如果你在使用附加库,将SDK的最小值设置为10,如果在使用android.hardware.usb包,则设置为12;

4)如果你想你的应用在有USB设备连接上去的时候得到通知,需要在主Activity中声明<intent-filter>和<meta-data>元素对(详情见后面),<meta-data>指向一个外部的xml资源文件,该文件描述了应用关心的设备的身份信息。在XML资源文件中,使用<usb-accessory>元素来过滤关心的USB设备,每个<usb-accessory>包含下列属性,包括manufactures,model,version。如果没有列出属性,则表示对任何设备都感兴趣。资源文件放在res/xml/文件夹下面,文件的名字必须和<meta-data>元素中声明的一样。例子:

 <manifest ...>
<uses-feature android:name="android.hardware.usb.accessory" /> <uses-sdk android:minSdkVersion="<version>" />
...
<application>
<uses-library android:name="com.android.future.usb.accessory" />
<activity ...>
...
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter> <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" />
</activity>
</application>
</manifest>

接下来,我们在res/xml/文件夹下面新建一个accessory_filter.xml 文件,内容如下:

 <?xml version="1.0" encoding="utf-8"?>

 <resources>
<usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
</resources>

和设备交互的步骤如下:

1)发现设备

这里大致和主设备模式一样,代码前面都有,intent-filter获得的时候,要注意区分是不是使用的附加库。

2)列举设备

当你的程序正在运行的时候,可以列举确认了它们作为附件的设备,代码如下:

 UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory[] accessoryList = manager.getAcccessoryList();

备注:目前,Android设备一次只能作为一个硬件设备的附件,API如此设计是为了未来的发展。

3)获取和设备交互的权限

这里基本上和从设别一直,只是用户确认以后,是使用:

 UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

语句获取设备的句柄的。其余一致。

4)与设备交互

应用可以使用UsbManager来获得附件的一个文件描述符,然后使用建立一个输入输出流来向文件描述符读写数据。这些流代表着附件的输入输出endpoints,你同样应该为此新建一个线程。例子:

 UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream; ... private void openAccessory() {
Log.d(TAG, "openAccessory: " + accessory);
mFileDescriptor = mUsbManager.openAccessory(mAccessory);
if (mFileDescriptor != null) {
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(null, this, "AccessoryThread");
thread.start();
}
}

在线程的run()方法中你可以使用FileInputStream和FileOutputStream对象来读写附件,当你从设备上使用FileInputStream对象读取数据的时候,要确保你的缓冲区足够大,可以存储USB包数据,Android附件协议支持包的大小上限是16384bytes,所以你可以选择简单的就声明成这个大小。

5)终止交互

当应用完成了交互或者设备被移除了,就需要通过调用rclose()关闭文件描述符,为了监听移除时间,需要使用以下监听器:

 BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction(); if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null) {
// call your method that cleans up and closes communication with the accessory
}
}
}
};

在应用中创建监听器,而不要在manifest中,这样就可以使得只有在程序运行的时候监听到该事件,就可以让移除时间不会被发送给所有的应用程序而只是运行中的程序。

以上就是有关Android USB的相关知识了,具体的开发需要参考SDK中的例子,以及相应的开发文档。

【Android】Android之USB的更多相关文章

  1. Android OTG支持USB读卡器

    我们知道,三星Android手机将USB读卡器通过OTG线插入Micro USB插口后,插拔读卡器里的SD卡,文件管理器也能够识别卡的插拔:而很多手机的OTG连上USB读卡器也来插拔SD卡,会发现文件 ...

  2. 【转】Android Service创建USB HOST通信

    之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信.要使用Android的USB Host ...

  3. Android Studio关于USB device not found的解决的方法

    Android Studio关于USB device not found的解决的方法 我们使用Android Studio进行Android开发时.当我们使用真机进行调试时.非常可能会出现USB de ...

  4. Android 下的usb框架及功能点【转】

    本文转载自:https://blog.csdn.net/tianruxishui/article/details/37902959 有关USB android框架的链接 http://blog.sin ...

  5. Android Service创建USB HOST通信

    之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信.要使用Android的USB Host ...

  6. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  7. Stack Overflow 排错翻译 - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder

    Stack Overflow 排错翻译  - Closing AlertDialog.Builder in Android -Android环境中关闭AlertDialog.Builder 转自:ht ...

  8. [Android]Android端ORM框架——RapidORM(v2.1)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6020412.html [Android]Android端ORM ...

  9. [Android]Android端ORM框架——RapidORM(v2.0)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5626716.html [Android]Android端ORM ...

  10. Android android:gravity属性介绍及效果图

    转自: http://blog.csdn.net/aminfo/article/details/7784229 Android:gravity的属性官方说明如下: public static fina ...

随机推荐

  1. [leetcode-662-Maximum Width of Binary Tree]

    Given a binary tree, write a function to get the maximum width of the given tree. The width of a tre ...

  2. Pipeline组Alpha版本发布说明

    Pipeline组Alpha版本发布说明 项目名称 Pipeline 项目版本 Alpha版本 负责人 北京航空航天大学计算机学院 ILoveSE 联系方式 http://www.cnblogs.co ...

  3. UVALive - 6869 Repeated Substrings 后缀数组

    题目链接: http://acm.hust.edu.cn/vjudge/problem/113725 Repeated Substrings Time Limit: 3000MS 样例 sample ...

  4. TCP系列22—重传—12、Forward Retransmit

    一.概述 forward retransmit相关的内容在RFC6675中有描述,可以参考RFC6675 section 4中NextSeg ()的定义.forward retransmit中文名可以 ...

  5. thrift多平台安装

    thrift支持多语言的RPC,一直都想深入学习了解thrift,最近有空,就上网查了些资料,学习了一下,对它的使用有了一些了解.本篇是写thrift的安装,使用方法会另起一篇来写. 本文使用thri ...

  6. 分享几个.Net计划任务组件

    Quartz http://www.quartz-scheduler.net/ Hangfire http://hangfire.io/ Install-Package Hangfire 使用OWIN ...

  7. [计算机网络] C++模拟telnet登陆SMTP服务发送邮件过程

    在百度文库中的<使用telnet协议收发邮件>,我们可以很清楚地看到如何通过telnet来进行发送邮件,下面是一些需要用到的命令,通过以下命令可以很容易实现邮件发送功能.为了更好地理解其中 ...

  8. overflow:scroll 滚动条不显示

    overflow:scroll 滚动条不显示 ::-webkit-scrollbar-thumb 可能因为 自定义的滚动条height比元素可展示内容大

  9. input 输入框不能点 readonly , disabled

    只读 readonly="readonly" 不可用 disabled="disabled" 背景变 灰色

  10. WPF实例,以getFiles()获取文件夹,treeview的应用

    读取电脑硬盘根目录添加到TreeView控件 foreach (DriveInfo item in System.IO.DriveInfo.GetDrives()) { if(item.ToStrin ...