USB 主机概述

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

API概述

开始之前,了解你需要使用的类非常重要,下列表格描述USB主机接口文档,它在android.hardware.usb 包下。

Table 1. USB Host APIs

class Description
UsbManager 枚举设备或和设备通信
UsbDevice 表示连接的USB设备,包含访问其标识信息,接口和端点的方法。
UsbInterface 表示USB设备的接口,它定义了设备的一组功能。 设备可以具有一个或多个要在其上进行通信的接口。
UsbEndpoint 表示usb接口端点,它是接口的通信通道。 接口可以具有一个或多个端点,并且通常具有用于与设备进行双向通信的输入和输出端点。
UsbDeviceConnection 表示与设备的连接,该设备在端点上传输数据。 此类允许您以异步方式或异步方式来回发送数据。
UsbRequest 表示一个通过UsbDeviceConnection与设备通信的异步请求。
UsbConstants 定义与Linux内核的linux / usb / ch9.h中的定义相对应的USB常量。
在大多数情况下,您需要在与USB设备通信时使用所有这些类(仅在进行异步通信时才需要UsbRequest)。 通常,您获取UsbManager以检索所需的UsbDevice。 拥有设备时,需要找到相应的UsbInterface和该接口的UsbEndpoint进行通信。 获得正确的端点后,打开UsbDeviceConnection以与USB设备通信。

usb设备通信流程

当用户将USB设备连接到Android设备时,Android系统可以确定您的应用程序是否对连接的设备感兴趣。 如果是这样,您可以和目标设备建立通信,为此,您的应用程序必须:

1、发现已连接的USB设备,可通过使用意图过滤器自动收到usb设备连接的通知,或者通过枚举当前所有已连接的usb设备。

2、如果尚未获得,请询问用户是否允许连接USB设备。

3、通过在适当的接口端点上读取和写入数据来与USB设备通信。

发现设备

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

  • 使用意图过滤器

可以简单快捷地发现特定的USB设备。

通过指定一个响应USB设备插入的intent-filter,和声明具体USB设备特征的meta-data(指定一个xml文件,声明要检测的目标usb设备的相关属性,包括vendor-id、product-id、class、subclass、protocol (device or interface) )


// AndroidManifest

<manifest ...>

    //声明需要的硬件功能, Because not all Android-powered devices are guaranteed to support the USB host APIs,

    <uses-feature android:name="android.hardware.usb.host" />

    //设定最低API Level 12 (基本不需要了),The USB host APIs are not present on earlier API levels.

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

//使用供应商编号、产品编号过来特定设备,使用类class, 子类subclass, 和协议protocol 过滤一组设备

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

</resources>

//In your activity, you can obtain the UsbDevice that represents the attached device from the intent like this:

UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
  • 使用枚举

在应用程序运行时检查当前连接的所有USB设备,它可以枚举总线上的设备。


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



// If desired, you can also just obtain an iterator from the hash map and process each device one by one:

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设备时,系统会出现一个弹框,在用户允许您的应用程序处理意图时,它会自动获得通信权限。 如果没有,您必须在与设备通信连接之前在应用程序中明确请求权限,否则会抛出运行时异常。


//首先创建一个广播接收者,用于监听用户对通信权限的审批情况,UsbManager.EXTRA_PERMISSION_GRANTED字段值代表审批结果。当你调用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){
                         //进行通信相关的操作

                        UsbDeviceConnection connection = mUsbManager.openDevice(device);//打开设备

                         ....
                   }
                }
                else {
                    Log.d(TAG, "permission denied for device " + device);
                }
            }
        }
    }
};

//在Activity的onCreate()中注册广播,

private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";

IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);

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

mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);

//在通信前,检查通信权限

UsbDevice device;
...

if (mUsbManager.hasPermission(device)) {
    //进行通信相关的操作

   UsbDeviceConnection connection = mUsbManager.openDevice(device);//打开设备
    ...

} else {
    mUsbManager.requestPermission(device, mPermissionIntent);
}
与设备通信

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

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

2、如果您确定要与设备通信,请找到要用于与该接口的相应UsbEndpoint进行通信的相应UsbInterface。 接口可以有一个或多个端点,通常具有用于双向通信的输入和输出端点。

3、找到正确的端点后,在该端点上打开UsbDeviceConnection。

4、使用bulkTransfer()或controlTransfer()方法提交要在端点上传输的数据。 应该在另一个线程中执行此步骤以防止阻止主UI线程。

以下代码段是以同步的方式执行数据传输的一种简单方法(如果要异步地发送数据,请使用UsbRequest类初始化并排队异步请求,然后使用requestWait()等待结果。)。 您的代码应该有更多的逻辑来正确地找到正确的接口和端点进行通信,并且还应该在与主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
断开与设备的通信

完成与设备的通信或设备已分离后,通过调用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
            }
        }
    }
};

在应用程序中创建广播接收器而不是清单,允许您的应用程序仅在其运行时处理分离的事件。 这样,分离事件仅发送到当前正在运行的应用程序,而不是广播到所有应用程序。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值