Google官方usb开发教程理解

作者: CharlesYale | 来源:发表于2018-07-13 11:54 被阅读13次

一.概念

Android 开放配件 (AOA) 支持功能可让外部 USB 硬件(Android USB 配件)与处于配件模式下的 Android 设备进行交互。当某台 Android 设备处于配件模式时,所连接的配件会充当 USB 主机(为总线供电并列举设备),而 Android 设备则充当 USB 配件。

AOA 有两个支持不同通信类型的版本:

  • AOAv1。支持通用配件通信和 adb 调试。适用于 Android 3.1(API 级别 12)及更高版本,在 Android 2.3.4(API 级别10)及更高版本中通过插件库获得支持。
  • AOAv2。支持音频流式传输和人机接口设备 (HID) 功能。适用于 Android 4.1(API 级别 16)。

如果使用通用配件协议(而不是使用 adb 或音频协议)与配件通信,则必须提供可以检测 USB 配件连接并建立通信的 Android 应用。

二.android usb通信模式

Android通过两种模式,来支持各种USB外围设备和Android USB附件(硬件实现了Android的附件协议):USB附件模式(accessory)和USB主机模式(host)。在USB附件模式下,外部 USB 硬件充当USB主机。Android设备作为附件的例子,包括机器人控制器、扩展插座(docking stations)、诊断和音乐设备、电子报亭(kiosks)、读卡器等其他设备。这种模式给予不具备主机功能的Android设备,与USB硬件通信的能力。Android USB附件,必须被设计为与装有Android的设备一起工作,并且必须遵循Android附件通讯协议。在USB主机模式下,装有Android的设备扮演着主机的角色。Android设备充当主机的例子,包括数码像机,键盘,鼠标和游戏控制器。那些适应面很广的USB设备,仍可以与Android应用交互,前提是这些Android应用可以正确的与这些设备通讯。

图1展示了两种模式的异同。当Android设备处于主机模式时,它扮演USB主机角色并为总线供电。当Android设备处于附件模式时,被连接的USB硬件(在这种情况下是一个Android USB附件)扮演主机角色并给总线供电。


图1. USB主从模式

三.相关API

1.两个相关的类

First Header Second Header
UsbManager 允许枚举已连接的USB设备并与其通信
UsbAccessory 是代表USB配件的类,该类提供了方法访问配件的信息

通过
UsbManager manager = UsbManager.getInstance(this);
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

UsbAccessory accessory = UsbManager.getAccessory(intent);
UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
来获取这两个类的实例

2.Android manifest

声明<uses-feature android:name="android.hardware.usb.accessory" />
为主活动中的 android.hardware.usb.action.USB_ACCESSORY_ATTACHED意图指定<intent-filter><meta-data>元素对。<meta-data>元素指向外部XML资源文件,该文件声明有关要检测的附件的标识信息。
在XML资源文件中,声明要过滤的附件的<usb-accessory>元素。每个<usb-accessory>都可以具有以下属性:manufacturer,model,version,将资源文件保存在res / xml /目录中。资源文件名(不带.xml扩展名)必须与在<meta-data>元素中指定的名称相同。
示例:
AndroidManifest.xml

<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.监听usb设备attach

先注册监听usb设备attach的广播,然后通过

list = usbManager.getAccessoryList();
accessory = list[0];

拿到辅助设备UsbAccessory的对象

2.授权

注册监听授权的广播,可以和监听usb设备attach的receiver合并

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

在Activity onCreat()注册此receiver

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

在检测到usb设备attach后请求权限

UsbAccessory accessory;
...
mUsbManager.requestPermission(accessory, mPermissionIntent);

3.通信

授权成功后可以通过文件描述符进行通信

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

4.设备退出后关闭fd,清理

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
                mFileDescriptor.close()
                ...
            }
        }
    }
};

五.参考

http://scottmaxiao.github.io/AOA.html

https://source.android.com/devices/accessories/protocol

官方文档https://developer.android.com/guide/topics/connectivity/usb/accessory

https://source.android.com/devices/accessories/custom

https://blog.csdn.net/gaojinshan/article/details/12012363

https://blog.csdn.net/yingzhao80/article/details/45511351

相关文章

网友评论

    本文标题:Google官方usb开发教程理解

    本文链接:https://www.haomeiwen.com/subject/fkddpftx.html