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

一.概念

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

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

  • AOAv1婚苹。支持通用配件通信和 adb 調(diào)試澎粟。適用于 Android 3.1(API 級別 12)及更高版本扎谎,在 Android 2.3.4(API 級別10)及更高版本中通過插件庫獲得支持晃琳。
  • AOAv2帽哑。支持音頻流式傳輸和人機接口設(shè)備 (HID) 功能供置。適用于 Android 4.1(API 級別 16)柳爽。

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

二.android usb通信模式

Android通過兩種模式,來支持各種USB外圍設(shè)備和Android USB附件(硬件實現(xiàn)了Android的附件協(xié)議):USB附件模式(accessory)和USB主機模式(host)客年。在USB附件模式下霞幅,外部 USB 硬件充當USB主機。Android設(shè)備作為附件的例子量瓜,包括機器人控制器司恳、擴展插座(docking stations)、診斷和音樂設(shè)備绍傲、電子報亭(kiosks)扔傅、讀卡器等其他設(shè)備。這種模式給予不具備主機功能的Android設(shè)備烫饼,與USB硬件通信的能力猎塞。Android USB附件,必須被設(shè)計為與裝有Android的設(shè)備一起工作枫弟,并且必須遵循Android附件通訊協(xié)議邢享。在USB主機模式下,裝有Android的設(shè)備扮演著主機的角色淡诗。Android設(shè)備充當主機的例子骇塘,包括數(shù)碼像機伊履,鍵盤,鼠標和游戲控制器款违。那些適應(yīng)面很廣的USB設(shè)備唐瀑,仍可以與Android應(yīng)用交互,前提是這些Android應(yīng)用可以正確的與這些設(shè)備通訊插爹。

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


圖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);
來獲取這兩個類的實例

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)要檢測的附件的標識信息寸宵。
在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.監(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)成功后可以通過文件描述符進行通信

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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市唱遭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呈驶,老刑警劉巖拷泽,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異袖瞻,居然都是意外死亡司致,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門聋迎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脂矫,“玉大人,你說我怎么就攤上這事霉晕⊥ピ伲” “怎么了捞奕?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拄轻。 經(jīng)常有香客問我颅围,道長,這世上最難降的妖魔是什么恨搓? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任院促,我火速辦了婚禮,結(jié)果婚禮上斧抱,老公的妹妹穿的比我還像新娘常拓。我一直安慰自己,他們只是感情好辉浦,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布弄抬。 她就那樣靜靜地躺著,像睡著了一般盏浙。 火紅的嫁衣襯著肌膚如雪眉睹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天废膘,我揣著相機與錄音竹海,去河邊找鬼。 笑死丐黄,一個胖子當著我的面吹牛斋配,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灌闺,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼艰争,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桂对?” 一聲冷哼從身側(cè)響起甩卓,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蕉斜,沒想到半個月后逾柿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡宅此,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年机错,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片父腕。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡弱匪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出璧亮,到底是詐尸還是另有隱情萧诫,我是刑警寧澤斥难,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站财搁,受9級特大地震影響蘸炸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尖奔,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一搭儒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧提茁,春花似錦淹禾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至峭火,卻和暖如春毁习,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卖丸。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工纺且, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稍浆。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓载碌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衅枫。 傳聞我的和親對象是個殘疾皇子嫁艇,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

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