USB Host and Accessory
Android支持通过两种方式各种USB外设和Android USB配件(硬件,实现了Android附件协议):USB配件,USB主机。在USB配件模式下,外部USB硬件充当USB主机。配件可能包括机器人控制器的例子;基座;诊断和音乐设备;亭;读卡器;以及更多。这给那些没有主机功能与USB硬件交互的能力Android设备。 Android的USB配件的设计必须有Android设备工作,必须遵守Android配件通信协议。在USB主机模式下,Android设备充当主机。装置的实例包括数码相机,键盘,鼠标,和游戏控制器。被设计为广泛的应用和环境中可以与可以正确地与设备进行通信的Android应用仍然交互USB设备。
图1示出了这两种模式之间的差异。当Android设备在主机模式下,它作为USB主机和权力总线。当Android设备处于USB配件模式,连接的USB硬件(在这种情况下,一个Android USB附件)作为主机和权力总线。
图1. USB主机和配件模式
USB配件和主机模式直接支持的Android 3.1(API级别12)或新平台。 USB配件模式也向后移植到Android 2.3.4(API等级10)作为一个附加的库来支持设备的范围更广。设备制造商可以选择是否包括设备的系统映像的附加库。
注:USB主机和配件支持的模式最终都是取决于设备的硬件,与平台无关的水平。您可以筛选支持通过<用途特征>元素USB主机和附属设备。详情请参见USB附件和主机文件。
调试注意事项
调试时使用的USB附件或主机功能的应用,您很可能将有USB硬件连接到你的Android设备。这将阻止你通过USB到Android设备亚行连接。您仍然可以访问亚洲开发银行通过网络连接。为了使通过网络连接亚行:
通过USB将Android设备连接到您的计算机。
从你的SDK平台的工具/目录,请在命令提示符下输入ADB TCPIP 5555。
亚行输入连接<设备IP地址>:5555您现在应该可以连接到Android设备,并可以发出像亚行logcat通常ADB命令。
要将设备设置为监听USB输入ADB USB。
USB配件模式允许用户连接专为Android设备设计的USB主机硬件。配件必须遵守Android配件开发工具包文档中列出了Android附件协议。这允许不能作为一个USB主机仍与USB硬件交互的Android设备。当一个Android供电设备处于USB配件模式,附加的Android USB附件作为主机,提供电源的USB总线,并列举了连接的设备。 Android的3.1(API级别12)支持USB附件模式和功能也向后移植到Android 2.3.4(API 10级),以便为更广泛的设备支持。
选择合适的USB附件的API
尽管USB附件API是在Android版3.1中引入的平台,他们也是Android的2.3.4可使用谷歌API插件库。由于这些应用程序是使用外部库回迁,有你可以导入,支持USB附件模式的两个包。根据什么Android系统要支持的设备,你可能需要使用一个比其他:
com.android.future.usb:支持USB附件模式的Android中的2.3.4,谷歌的API插件库中包含回迁USB附件API和它们包含在这个命名空间。 Android的3.1也支持这个命名空间内导入和调用的类支持与附加库编写的应用程序。这个附加库是围绕android.hardware.usb附件API的瘦包装,不支持USB主机模式。如果你想支持那些支持USB附件模式的设备范围最广,使用附加库并导入这个包。要注意,并不要求所有的Android 2.3.4设备能够支持USB附件特征是重要的。每个单独的设备制造商决定是否支持此功能,这就是为什么你必须在你的清单文件中声明它。
android.hardware.usb:这个命名空间包含支持Android中3.1的USB附件模式的类。这个包是包含在框架API的一部分,因此Android 3.1支持USB附件模式,而无需使用附加库。如果你只关心有USB配件模式,您可以在清单文件中声明的硬件支持的Android 3.1或更高版本的设备,使用此包。
安装谷歌API插件库
如果你要安装的插件,您可以通过使用SDK管理器中安装谷歌的Android的API API 10封装这样做。请参阅安装谷歌API插件的详细信息,安装附加库。
API概述
由于附加库是为框架API的封装,支持USB附件功能的类是相似的。您可以使用参考文档,即使您正在使用的附加库android.hardware.usb。
注:然而,有,在附加库和框架的API,你应该知道之间的微小差别的使用。
下表介绍了支持USB附件API的类:
类说明
UsbManager允许您枚举和连接的USB配件沟通。
UsbAccessory表示一个USB配件,包含的方法来访问它的识别信息。
在附加库和平台API之间的差异用法
有使用谷歌API插件库和平台API之间两种使用差别。
如果您使用的是附加库,必须获得在以下方式UsbManager对象:
UsbManager经理= UsbManager.getInstance(本);
如果你不使用附加库,必须获得在以下方式UsbManager对象:
UsbManager经理=(UsbManager)getSystemService(Context.USB_SERVICE);
当您筛选与意图过滤器连接的配件,该UsbAccessory对象包含传递到您的应用程序的意图内。如果您使用的是附加库,必须获得在以下方式UsbAccessory对象:
UsbAccessory accessory = UsbManager.getAccessory(intent);如果你不使用附加库,必须获得在以下方式UsbManager对象:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);当您筛选与意图过滤器连接的配件,该UsbAccessory对象包含传递到您的应用程序的意图内。如果您使用的是附加库,必须获得在以下方式UsbAccessory对象:
UsbAccessory accessory = UsbManager.getAccessory(intent);如果你不使用附加库,必须获得在以下方式UsbAccessory对象:
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);Android清单要求
manufacturer
model
version
<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并指定具有相应的型号,制造商,和版本的任何附件应过滤。附件发送这些属性Android设备:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/> </resources>用配件工作
<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>下面的示例演示如何声明,它指定你感兴趣的USB配件相应的资源文件:
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /> </resources>在你的活动,你可以得到,它代表了这样的意图连接的附件(具有附加库)的UsbAccessory:
UsbAccessory accessory = UsbManager.getAccessory(intent);或者像这样(用平台API):
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);枚举配件
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); UsbAccessory[] accessoryList = manager.getAcccessoryList();注:目前,只有一个连接的配件在同一时间支持,但该API被设计为在未来支持多种配件。
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) { UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if(accessory != null){ //call method to set up accessory communication } } else { Log.d(TAG, "permission denied for accessory " + accessory); } } } } };要注册的BroadcastReceiver,把它放在你的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);若要显示要求用户进行权限连接到附件的对话框中,调用请求许可()方法:
UsbAccessory accessory; ... mUsbManager.requestPermission(accessory, mPermissionIntent);当用户回复的对话框中,你的广播接收器接收到包含PERMISSION_GRANTED额外多余的,这是代表回答一个布尔的意图。连接附件之前,请检查该额外值true。
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配件协议支持数据包缓存高达16384字节,这样你就可以选择始终申报您的缓冲区是这个大小为简单。
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 } } } };在应用程序中创建广播接收器,并没有清单,让您的应用程序只处理分离的事件在运行时。通过这种方式,分离的事件仅发送到当前正在运行,而不是广播到所有的应用程序的应用程序。
USB Host
当你的Android设备处于USB主机模式,它作为USB主机,权力总线,并枚举连接的USB设备。 USB主机模式采用的是Android 3.1或更高版本支持。
API概述
在开始之前,一定要明白,你需要使用的类是很重要的。下表描述了android.hardware.usb包中的USB主机的API。
表1. USB主机的API
类说明
UsbManager让您列举并与连接的USB设备进行通信。
UsbDevice表示一个连接的USB设备和包含的方法访问其识别信息,接口和端点。
的UsbInterface表示USB设备,它定义一组功能的设备的接口。一个设备可以具有在其上进行通信的一个或多个接口。
UsbEndpoint表示的接口的端点,这是该接口的通信信道。接口可以有一个或多个端点,并且通常具有输入和输出的端点用于与设备的双向通信。
UsbDeviceConnection代表的设备,该设备上传输数据的端点连接。这个类可以发送数据来回sychronously或异步。
UsbRequest表示异步请求通过UsbDeviceConnection与设备进行通信。
UsbConstants定义对应于Linux内核Linux的/ USB / ch9.h定义USB常数。
在大多数情况下,你需要使用USB设备通信时使用所有这些类(UsbRequest只需要如果你正在做异步通信)。一般情况下,你获得UsbManager以检索所需的UsbDevice。当你有设备,你需要找到合适的UsbInterface和接口上进行通信的UsbEndpoint。一旦你获得了正确的终点,打开一个UsbDeviceConnection与USB设备进行通信。
Android清单要求
下面的列表说明你需要与USB主机API之前添加到您的应用程序的清单文件的内容:
因为不是所有的Android设备都保证支持USB主机的API,包括声明应用程序使用android.hardware.usb.host功能的<使用特征>元素。
设置应用程序以API级别12或更高的最低SDK。 USB主机API是不存在于早期的API级别。
如果你希望你的应用程序被通知连接的USB设备,指定<意向filter>和用于主要活动android.hardware.usb.action.USB_DEVICE_ATTACHED意图<元数据>元素对。在<元数据>元素指向声明确定有关您要检测的设备信息的外部XML资源文件。
在XML资源文件,声明<USB设备>为您想要过滤的USB设备的元素。下面的列表描述<USB设备>的属性。一般情况下,利用供应商和产品ID,如果你想,如果你要筛选一组USB设备,如大容量存储设备或数码相机到特定设备和使用类,子类和协议进行过滤。您可以指定none或所有这些属性。指定没有属性相匹配的所有USB设备,只有这样做,如果你的应用程序需要:
厂商ID
产品编号
类
子类
协议(设备或接口)
保存在res / XML /目录下的资源文件。资源文件名(不带.xml扩展名)必须是一样的,你在<元数据>元素中指定的。为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>与器件工作
<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>在你的活动,你可以得到,它代表了这样的意图连接的设备USB设备:
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);设备枚举
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 }获得许可与设备进行通信
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); } } } } };要注册的BroadcastReceiver,在你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);当用户回复的对话框中,你的广播接收器收到包含EXTRA_PERMISSION_GRANTED多余的,这是代表回答一个布尔的意图。连接到设备前,请检查该额外值true。
当用户回复的对话框中,你的广播接收器收到包含EXTRA_PERMISSION_GRANTED多余的,这是代表回答一个布尔的意图。连接到设备前,请检查该额外值true。
当用户回复的对话框中,你的广播接收器收到包含EXTRA_PERMISSION_GRANTED多余的,这是代表回答一个布尔的意图。连接到设备前,请检查该额外值true。
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()的结果。
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 } } } };在应用程序中创建广播接收器,并没有清单,让您的应用程序只处理分离的事件在运行时。通过这种方式,分离的事件仅发送到当前正在运行,而不是广播到所有的应用程序的应用程序。