Google官方usb開發(fā)教程理解

一.概念

Android 開放配件 (AOA) 支持功能可讓外部 USB 硬件(Android USB 配件)與處于配件模式下的 Android 設(shè)備進(jìn)行交互。當(dāng)某臺 Android 設(shè)備處于配件模式時,所連接的配件會充當(dāng) USB 主機(jī)(為總線供電并列舉設(shè)備),而 Android 設(shè)備則充當(dāng) USB 配件。

AOA 有兩個支持不同通信類型的版本:

  • AOAv1。支持通用配件通信和 adb 調(diào)試。適用于 Android 3.1(API 級別 12)及更高版本,在 Android 2.3.4(API 級別10)及更高版本中通過插件庫獲得支持。
  • AOAv2。支持音頻流式傳輸和人機(jī)接口設(shè)備 (HID) 功能。適用于 Android 4.1(API 級別 16)。

如果使用通用配件協(xié)議(而不是使用 adb 或音頻協(xié)議)與配件通信,則必須提供可以檢測 USB 配件連接并建立通信的 Android 應(yīng)用。

二.android usb通信模式

Android通過兩種模式,來支持各種USB外圍設(shè)備和Android USB附件(硬件實(shí)現(xiàn)了Android的附件協(xié)議):USB附件模式(accessory)和USB主機(jī)模式(host)。在USB附件模式下,外部 USB 硬件充當(dāng)USB主機(jī)。Android設(shè)備作為附件的例子,包括機(jī)器人控制器、擴(kuò)展插座(docking stations)、診斷和音樂設(shè)備、電子報亭(kiosks)、讀卡器等其他設(shè)備。這種模式給予不具備主機(jī)功能的Android設(shè)備,與USB硬件通信的能力。Android USB附件,必須被設(shè)計為與裝有Android的設(shè)備一起工作,并且必須遵循Android附件通訊協(xié)議。在USB主機(jī)模式下,裝有Android的設(shè)備扮演著主機(jī)的角色。Android設(shè)備充當(dāng)主機(jī)的例子,包括數(shù)碼像機(jī),鍵盤,鼠標(biāo)和游戲控制器。那些適應(yīng)面很廣的USB設(shè)備,仍可以與Android應(yīng)用交互,前提是這些Android應(yīng)用可以正確的與這些設(shè)備通訊。

圖1展示了兩種模式的異同。當(dāng)Android設(shè)備處于主機(jī)模式時,它扮演USB主機(jī)角色并為總線供電。當(dāng)Android設(shè)備處于附件模式時,被連接的USB硬件(在這種情況下是一個Android USB附件)扮演主機(jī)角色并給總線供電。


圖1. USB主從模式

三.相關(guān)API

1.兩個相關(guān)的類

First Header Second Header
UsbManager 允許枚舉已連接的USB設(shè)備并與其通信
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);
來獲取這兩個類的實(shí)例

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資源文件,該文件聲明有關(guān)要檢測的附件的標(biāo)識信息。
在XML資源文件中,聲明要過濾的附件的<usb-accessory>元素。每個<usb-accessory>都可以具有以下屬性:manufacturer,model,version,將資源文件保存在res / xml /目錄中。資源文件名(不帶.xml擴(kuò)展名)必須與在<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.監(jiān)聽usb設(shè)備attach

先注冊監(jiān)聽usb設(shè)備attach的廣播,然后通過

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

拿到輔助設(shè)備UsbAccessory的對象

2.授權(quán)

注冊監(jiān)聽授權(quán)的廣播,可以和監(jiān)聽usb設(shè)備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設(shè)備attach后請求權(quán)限

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

3.通信

授權(quán)成功后可以通過文件描述符進(jìn)行通信

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.設(shè)備退出后關(guān)閉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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容