usb附件连接方式
Android通過兩種模式來支持各種USB外設(shè)和Android USB配件(指那些符合Android附件協(xié)議的硬件):USB配件和USB主機(jī)。在USB配件的模式之下,外部的USB配件就像USB主機(jī)那樣。這種配件可以包括機(jī)器人控制器,基站連接器,醫(yī)療和音樂設(shè)備,電話亭以及讀卡器這樣很多的設(shè)備。這樣就使得那些搭載Android系統(tǒng)的設(shè)備不需要具備主機(jī)的特性就可以和USB硬件進(jìn)行交互。Android USB配件是指那些專門用來為搭載Android系統(tǒng)的設(shè)備工作以及符合Android附件通信協(xié)議的設(shè)備。在USB主機(jī)的模式之下,搭載Android的設(shè)備就像主機(jī)那樣工作。這些設(shè)備包括數(shù)碼相機(jī),鍵盤,鼠標(biāo)以及游戲控制器。Android USB設(shè)備被設(shè)計(jì)成具有廣泛的應(yīng)用領(lǐng)域,可以很好的完成人機(jī)互動應(yīng)用的通信設(shè)備。
圖1就顯示了這兩種模式的區(qū)別。當(dāng)搭載Android系統(tǒng)的設(shè)備處于主機(jī)的模式下,它就充當(dāng)USB主機(jī)并且為總線提供能源。而當(dāng)搭載Android系統(tǒng)的設(shè)備處于USB配件的模式下時(shí),連接的USB硬件(這種情況下,指的是一個(gè)Android USB配件)作為主機(jī)一樣并且為總線提供能源。
在Android3.1(API12級)或較新的平臺直接支持USB配件和主機(jī)模式。USB配件模式以一個(gè)附加的類庫的方式支持范圍更廣的設(shè)備 被移植到Android 2.3.4(API10級)。設(shè)備生產(chǎn)商可以決定是否在系統(tǒng)鏡像上附加這個(gè)類庫。
注意:支持USB主機(jī)和配件模式主要取決于設(shè)備的硬件,而不是平臺的等級。你可以通過一個(gè)[[<uses-feature>]]元素來為設(shè)備進(jìn)行過濾以支持USB主機(jī)和配件。 看這個(gè)USB配件和主機(jī)文檔來了解更多的詳情。
調(diào)試注意事項(xiàng)
當(dāng)用USB主機(jī)或者配件調(diào)試應(yīng)用程序時(shí),你最好有連接到搭載Android程序的設(shè)備的USB硬件。這樣可以避免你要通過USB來為搭載Android的設(shè)備建立一個(gè)adb的連接。你可以在一個(gè)網(wǎng)絡(luò)連接中一直連著adb。確保adb在一個(gè)網(wǎng)絡(luò)連接的方式:
1.通過USB連接搭載Android系統(tǒng)的設(shè)備和你的電腦
2.在命令提示符中找到你的SDK platform_tools/ 目錄,輸入 adb tcpip 5555
3.輸入 adb connect <device-ip-address>: 5555 你應(yīng)該已經(jīng)連接到了搭載Android程序的設(shè)備并且能夠發(fā)出像 adb logcat這樣一般 的adb命令
4.在USB上為你的設(shè)備設(shè)置一個(gè)監(jiān)聽,輸入 adb usb
USB配件
USB配件模式允許用戶連接那些專門搭載Android設(shè)備的USB主機(jī)硬件。這些配件必須遵守Android配件開發(fā)工具包文檔中所列出的Android附件協(xié)議。這使得搭載Android系統(tǒng)的設(shè)備在不充當(dāng)USB主機(jī)的情況之下,仍然可以和USB硬件進(jìn)行交互。當(dāng)一臺搭載Android系統(tǒng)的設(shè)備處于USB配件模式時(shí),所依附的Android USB配件作為主機(jī)為USB總線提供能源以及列舉出相連的設(shè)備。Android3.1(API12級)提供了USB配件模式并且這一特點(diǎn)也繼承了Android2.3.4(API10級)以此來支持更多設(shè)備。
選擇正確的USB附件APIs
盡管USB附件API在Android3.1平臺才開始介紹,但是也可以在Android2.3.4API中通過附加類庫使用。因?yàn)檫@些APIs都是通過額外的類庫來使用的,你可以導(dǎo)入兩個(gè)包來支持USB配件模式。取決于你想支持什么樣的搭載Android系統(tǒng)的設(shè)備,你也許不得不在一個(gè)的基礎(chǔ)上使用另外一個(gè):
com.android.feature.usb:為了支持Android2.3.4的USB配件模式,Google APIs附加類庫包括了USB外設(shè)APIs并且它們就是包含在這個(gè)命名空間的后面。Android3.1還支持導(dǎo)入和調(diào)用這個(gè)命名空間的類來支持附加類庫編寫的應(yīng)用程序。這個(gè)附加的類庫只是關(guān)于android.hardware.usb外設(shè)APIs的一個(gè)簡單的封裝并且它不支持USB主機(jī)模式。如果你希望更大范圍支持USB配件模式的設(shè)備,使用附加類庫并且導(dǎo)入改包就行。需要注意的是,并不是所有搭載Android2.3.4的設(shè)備都需要擁有USB外設(shè)這一特色。每個(gè)設(shè)備生產(chǎn)商在決定是否具有這個(gè)特色,這也就是為什么你必須要在manifest文件中聲明的原因了。
android.hardware.usb:這個(gè)命名空間包含在Android3.1版本中支持USB附件模式的類。因?yàn)檫@個(gè)包是框架APIs中的一部分,所以Android3.1版本可以在不用附加類庫的前提之下支持USB附件模式。使用這個(gè)包時(shí),如果你只關(guān)心Android3.1或者更新的支持USB附件模式的硬件的設(shè)備,你可以在mainfest文件中進(jìn)行聲明。
安裝谷歌APIs的附加類庫
如果你想安裝這個(gè)附加類庫,你可以通過在SDK管理器上面安裝谷歌APIs中的Android API10包的方式來做。更多關(guān)于安裝附加類庫的信息請參見安裝谷歌APIs附加元件。
API 概述
因?yàn)楦郊宇悗焓且粋€(gè)框架APIs的封裝,和那些支持USB附件功能的類是相似的。即使你在用附加類庫的時(shí)候,你也可以用android.hardware.usb參考文檔作為參考。
注意:然而,你要注意在附加類庫和框架APIs之間還是有一些細(xì)微的使用差別的。
下面的表格為您描述了那些支持USB外設(shè)APIs的類:
| 類 | 詳細(xì)描述 |
| UsbManager | 允許您用已連接的USB配件直接進(jìn)行枚舉和交流 |
| UsbAccessory | 可以表示一個(gè)USB配件并且包含來連接識別信息的方法 |
關(guān)于平臺APIs和附加類庫之間的用法差異
在分別使用谷歌APIs附加類庫和平臺APIs的時(shí)候,通常會有兩種差異。
如果您正在使用附加類庫,則肯定會通過下列方式來創(chuàng)建UsbManager對象:
???UsbManager manager = UsbManager.getInstance(this);
如果您不是用的附加類,則必須通過下列方式來創(chuàng)建UsbManager對象:
???UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
當(dāng)您通過一個(gè)意圖過濾器來過濾一個(gè)已經(jīng)連接的配件,那么這個(gè)UsbAccessory對象就必須包含在傳給您應(yīng)用的這個(gè)意圖中。如果您正在使用附加類庫,您就必須通過下列方式來聲明UsbAccessory對象:
??UsbAccessory accessory = UsbManager.getAccessory(intent);
如果您不是用的附加類,則必須通過下列方式來聲明UsbAccessory對象:
?UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
Android ManiFest 需求
?
下面的列表向您描述了在用USB配件APIs工作前需要在您應(yīng)用中的manifest文件里面添加什么。下面的清單和資源文件例子將教您如何聲明這些項(xiàng):
- 因?yàn)椴⒉皇撬写钶dAndroid系統(tǒng)的設(shè)備都保證支持USB配件APIs,包括一個(gè)<uses-feature>元素來聲明您的應(yīng)用具有
android.hardware.usb.accessory這個(gè)特色。
- 如果你正在使用附加類庫,添加<uses-library>這個(gè)元素用來為類庫特定說明com.android.future.usb.accessory。
- 如果您使用附加類庫,那么您所設(shè)置的最低SDK版本是10級;如果您使用android.harware.usb這個(gè)類的話,您所設(shè)置最低版本的SDK就應(yīng)該為12級。
- 如果您希望您的應(yīng)用帶有一個(gè)附加USB配件的通知,在您的主activity中為android.hardware.usb.action.USB_ACCESSORY_ATTACHED這個(gè)意圖指定一對<intent-filter>和<meta-data>元素。這個(gè)<meta-data>元素指向一個(gè)額外的聲明關(guān)于你希望探測到的配件的識別信息的XML資源文件。
???在這個(gè)XML資源文件中,為您希望過濾的配件聲明<usb-accessory>元素。每一個(gè)<usb-accessory>都有下面的屬性:
- 制造商
- 模式
- 版本
在res/xml/這個(gè)目錄下保存資源文件。這個(gè)資源文件的名字(沒有 .xml的拓展名)必須和你在<meta-data>元素指定的一樣。這個(gè)XML資源文件的格式在下面的例子中給出。
清單和資源文件例子
下面的例子就為您展示了一個(gè)簡單的manifest以及與之相關(guān)的資源文件:
?
??<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文件中,并且指定那些只有與其相關(guān)的模式,制造商和版本的配件能夠被選擇。這個(gè)配件把這些屬性傳遞給搭載Android系統(tǒng)的設(shè)備:
?
<?xml?version="1.0"?encoding="utf-8"?>
?
<resources>
????<usb-accessory?model="DemoKit"?manufacturer="Google"?version="1.0"/>
</resources>
?
用配件工作
?
當(dāng)用戶將USB配件連接到搭載Android系統(tǒng)的設(shè)備上面時(shí),Android系統(tǒng)會判斷您的應(yīng)用是否適用于已連接的該配件。如果適用,您就可以根據(jù)您的喜好為該設(shè)備建立連接。要這么做,您的應(yīng)用必須做下面這些動作:
發(fā)現(xiàn)配件
您的應(yīng)用可以通過兩種方式來發(fā)現(xiàn)配件,一種是用一個(gè)意圖過濾器在用戶連接一個(gè)配件時(shí)對其進(jìn)行通知,另一種則是通過枚舉您已經(jīng)連接的所有配件。如果您希望您的應(yīng)用能夠自動的探測到你想要的配件,請使用一個(gè)意圖過濾器來做。但是,如果您希望得到一個(gè)已連接配件的列表或者您不希望過濾意圖,枚舉所有的配件會是一個(gè)更好的選擇。
使用一個(gè)意圖過濾器
為了讓您的應(yīng)用可以發(fā)現(xiàn)一個(gè)特定的USB配件,您可以為android.hardware.usb.action.USB_ACCESSORY_ATTACHED這個(gè)意圖指定一個(gè)意圖來進(jìn)行過濾。伴隨著這個(gè)意圖過濾器,您需要指定一個(gè)資源文件來特別說明這個(gè)USB配件的屬性,例如制造商,模式和版本。當(dāng)用戶連接到一個(gè)符合您配件過濾條件的配件時(shí),
下面的例子告訴您該如何聲明這個(gè)意圖過濾器:
?
<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配件的相關(guān)資源文件:
?
<?xml?version="1.0"?encoding="utf-8"?>
?
<resources>
????<usb-accessory?manufacturer="Google, Inc."?model="DemoKit"?version="1.0"?/>
</resources>
?
在您的activity文件中,您可以從像這樣的意圖(有附加類的)中獲取UsbAccessory來代表這個(gè)相關(guān)的配件:
?
UsbAccessory accessory = UsbManager.getAccessory(intent);
?
或者像這樣(用平臺APIs的):
?
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
?
枚舉所有配件
您可以使您的應(yīng)用在運(yùn)行時(shí)列舉出所有能夠被識別的配件。
通過getAccessoryList()方法來獲得一個(gè)包含所有已連接USB配件的數(shù)組:
?
UsbManager manager = (UsbManager)?getSystemService(Context.USB_SERVICE);
UsbAccessory[]?accessoryList = manager.getAcccessoryList();
?
注意:現(xiàn)在,只能一次連接一個(gè)USB配件操作,但是在以后的API中會支持多配件的操作的。
獲得使用一個(gè)配件的權(quán)限
在您使用一個(gè)配件前,您的應(yīng)用必須從用戶那里獲得權(quán)限。
注意:如果您的應(yīng)用在連接配件時(shí)通過一個(gè)意圖過濾器來發(fā)現(xiàn)它們,如果用戶允許您的應(yīng)用來處理這個(gè)意圖,它將自動接收這個(gè)權(quán)限。如果用戶不允許,那么您就必須在連接配件之前詳細(xì)在您的應(yīng)用中寫明需要請求的權(quán)限。
在某些情況下很有必要明確權(quán)限的許可要求,例如當(dāng)您的應(yīng)用枚舉出所有已經(jīng)連接的配件并且您希望和其中的一個(gè)進(jìn)行“交流”。您必須在和該配件“交流”前檢查是否有連接該配件的權(quán)限。如果不是這樣,您的應(yīng)用將在用戶拒絕您連接該配件的權(quán)限之后收到個(gè)運(yùn)行錯(cuò)誤。
為了確切地獲得權(quán)限,首先需要?jiǎng)?chuàng)建個(gè)廣播接收器。這個(gè)接收器在您調(diào)用requestPermission()這個(gè)方法時(shí)從您得到的廣播中艦艇這個(gè)意圖。通過調(diào)用requestPermission()這個(gè)方法為用戶跳出一個(gè)是否連接配件的對話框。下面的例子告訴您如何創(chuàng)建一個(gè)廣播接收器:
?
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中的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);
?
當(dāng)您需要展示征求用戶同意連接這個(gè)配件的權(quán)限的對話框時(shí),調(diào)用requestPermission()這個(gè)方法:
?
UsbAccessory accessory;
...
mUsbManager.requestPermission(accessory, mPermissionIntent);
?
當(dāng)用戶回應(yīng)這個(gè)對話框時(shí),你的廣播接收器就會收到一個(gè)包含用一個(gè)boolean值來表示結(jié)果的EXTRA_PERMISSION_GRANTED字段的意圖。在您連接配件之前檢查這個(gè)字段的值是否為true。
和配件之間的“交流”
您可以通過使用UsbManager這個(gè)類和配件進(jìn)行“交流”,通過這個(gè)類可以獲得一個(gè)文件描述符,然后您可以利用這個(gè)描述符來設(shè)置輸入和輸出流來讀取和寫入數(shù)據(jù)。這些流用來代表輸入和輸出的批量端點(diǎn)。您最好另起一個(gè)線程來讓您的設(shè)備和配件進(jìn)行“交流”,因?yàn)檫@樣您就可以不需要將主線程鎖起來了。下面的例子告訴您該如何和一個(gè)配件進(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();
????}
}
?
在這個(gè)線程的run()方法中,您可以通過FileInputStream或者FileOutputStream對象來對配件進(jìn)行讀取和寫出數(shù)據(jù)操作。當(dāng)您通過FileInputStream對象讀取配件中的數(shù)據(jù)時(shí),請確保您所使用的緩存能夠存儲下USB數(shù)據(jù)包數(shù)據(jù)。Android配件協(xié)議支持?jǐn)?shù)據(jù)包支持高達(dá)16384字節(jié)的數(shù)據(jù)包緩存區(qū),所以您可以選擇一直讓您的緩存區(qū)是這個(gè)簡單的大小。
注意:在一個(gè)比較低的水平下,64字節(jié)的數(shù)據(jù)包是全速配件以及512字節(jié)的數(shù)據(jù)包是高速配件。Android配件協(xié)議將這兩種速度捆綁成一個(gè)簡單的邏輯數(shù)據(jù)包。
想要知道更多如何使用Android中多線程的信息,請參見進(jìn)程和線程。
中止和配件的“交流”
當(dāng)您在完成和配件的“交流”之后,又或者該配件被移除了,通過調(diào)用close()方法來關(guān)閉你已經(jīng)打開的文件描述符。為了監(jiān)聽分離這樣的事件,您需要?jiǎng)?chuàng)建一個(gè)如下的廣播接收器:
?
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主機(jī)
文檔內(nèi)容
- API概述
- Android中manifest文件需求
- 工作的設(shè)備
- 發(fā)現(xiàn)設(shè)備
- 獲得和設(shè)備進(jìn)行“交流”的權(quán)限
- 和設(shè)備進(jìn)行“交流”
- 中止和設(shè)備的“交流”
相關(guān)例子
- Adb測試用例
- 相關(guān)鏈接
當(dāng)您搭載Android系統(tǒng)的設(shè)備處于USB主機(jī)模式時(shí),它就像一個(gè)USB主機(jī),為總線提供能源,并且列舉出所有已經(jīng)連接上的設(shè)備。在Android 3.1或者更高的版本中支持USB主機(jī)模式。
API概述
在您開始之前,有個(gè)很重要的一點(diǎn)就是您必須對將要用到的類有個(gè)了解。下面的表格就向您描述了在android.hardware.usb這個(gè)包下USB主機(jī)APIs的一些特點(diǎn)。
表1.USB主機(jī)APIs
| Class/Interface | Description |
| UsbManager | 允許您枚舉已連接的USB設(shè)備并且與其進(jìn)行“交流”。 |
| UsbDevice | 代表了一個(gè)已連接的USB的設(shè)備并且包含具有該設(shè)備驗(yàn)證信息,接口和接入點(diǎn)的方法。 |
| UsbInterface | 代表了一個(gè)USB設(shè)備的一個(gè)接口,該接口定義了一系列關(guān)于設(shè)備的函數(shù)。一個(gè)設(shè)備在進(jìn)行“交流”的時(shí)候可以有一個(gè)或者多個(gè)接口。 |
| UsbEndpoint | 代表一個(gè)接口的接入點(diǎn),該接入點(diǎn)就是這個(gè)接口的通信信道。一個(gè)接口可以有一個(gè)或者多個(gè)這樣的接入點(diǎn),而且一般都是有輸入和輸出雙向通信的接入點(diǎn)。 |
| UsbDeviceConnection | 代表該設(shè)備的一個(gè)連接,用來在接入點(diǎn)上傳輸數(shù)據(jù)。這個(gè)類允許您能用同步或者異步的方式發(fā)送和返回?cái)?shù)據(jù)。 |
| UsbRequest | 在通過UsbDeviceConnection和設(shè)備進(jìn)行“交流”的一個(gè)異步請求。 |
| UsbConstants | 關(guān)于在linux內(nèi)核中linux/usb/ch9.h的相關(guān)定義的USB常量。 |
在大多數(shù)的情況之下,在和一個(gè)USB設(shè)備進(jìn)行“交流”時(shí),上面這些類都需要用到(UsbRequest這個(gè)類只有在您做異步通信的時(shí)候才會用到)。一般來說,您可以通過查詢要操作的UsbDevice來獲得一個(gè)UsbManager。當(dāng)您有這個(gè)設(shè)備時(shí),您需要找到正確的UsbInterface以及和這個(gè)接口所對應(yīng)的UsbEndpoint來進(jìn)行和設(shè)備的“交流”。一旦您獲得了正確的接入點(diǎn),打開UsbDeviceConnection來和該USB設(shè)備進(jìn)行“交流”。
Android中manifest文件的需求
下面的列表就是描述您應(yīng)該在用USB主機(jī)APIs之前應(yīng)該在您的應(yīng)用中的manifest文件中添加些什么:
- 因?yàn)椴皇撬械拇钶dAndroid系統(tǒng)的設(shè)備都能保證支持USB主機(jī)的APIs,不能包含那個(gè)聲明您的應(yīng)用使用android.hardware.usb.host這一特點(diǎn)的android.hardware.usb.host的這一元素。
- 設(shè)置您的應(yīng)用的最低的SDK版本在12級或者更高。這個(gè)USB主機(jī)APIs不在更前面的版本之中。
- 如果您希望您的應(yīng)用能夠被連接的USB設(shè)備所提示,只要在您的主activity中在<intent-filter>和<meta-data>元素對中添加一個(gè)android.hardware.usb.action.USB_DEVICE_ATTACHED意圖。<meta-data>元素指向一個(gè)額外的XML資源文件,該文件是用來聲明驗(yàn)證您希望探測到的設(shè)備的驗(yàn)證信息。
???在這個(gè)XML資源文件中,為您希望過濾的USB設(shè)備聲明<usb-device>元素。下面的列表描述<usb-device>的屬性。一般來說,如果您想為一個(gè)特定的設(shè)備過濾就使用該產(chǎn)品的供應(yīng)商和產(chǎn)品ID,如果您希望為一組USB設(shè)備,例如大量存儲設(shè)備或者是數(shù)碼相機(jī)來進(jìn)行過濾那么就應(yīng)該用類,子類和協(xié)議。您可以不指定這些屬性,也可以指定所有的屬性。不為每個(gè)設(shè)備指定屬性,只有在您的應(yīng)用需要它時(shí)才這么做(這句話翻譯的一點(diǎn)問題^_^):
- 供應(yīng)商ID
- 產(chǎn)品ID
- 類
- 子類
- 協(xié)議(設(shè)備或者借口)
???將您的資源文件保存到res/xml/目錄下。資源文件名(不包含.xml的擴(kuò)展名)必須和您在<meta-data>元素中指明的那個(gè)名字。在下面的例子中是這個(gè)XML資源文件的格式。
Manifest文件和資源文件的例子
下面的例子告訴您一個(gè)manifest文件以及與它相關(guān)資源文件的例子:
?
<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>
?
在這種情況下,下面的資源文件應(yīng)該被保存在res/xml/device_filter.xml來確保找到那些特定符合您要求屬性的USB設(shè)備:
?
<?xml?version="1.0"?encoding="utf-8"?>
?
<resources>
????<usb-device?vendor-id="1234"?product-id="5678"?class="255"?subclass="66"?protocol="1"?/>
</resources>
?
用配件工作
當(dāng)用戶將USB配件連接到搭載Android系統(tǒng)的設(shè)備上面時(shí),Android系統(tǒng)會判斷您的應(yīng)用是否適用于已連接的該配件。如果適用,您就可以根據(jù)您的喜好為該設(shè)備建立連接。要這么做,您的應(yīng)用必須做下面這些動作:
發(fā)現(xiàn)設(shè)備
您的應(yīng)用可以通過兩種方式來發(fā)現(xiàn)USB設(shè)備,一種是用一個(gè)意圖過濾器在用戶連接一個(gè)設(shè)備時(shí)對其進(jìn)行通知,另一種則是通過枚舉您已經(jīng)連接的所有USB設(shè)備。如果您希望您的應(yīng)用能夠自動的探測到你想要的設(shè)備,請使用一個(gè)意圖過濾器來做。但是,如果您希望得到一個(gè)已連接設(shè)備的列表或者您不希望過濾意圖,枚舉所有的設(shè)備會是一個(gè)更好的選擇。
使用一個(gè)意圖過濾器
為了讓您的應(yīng)用可以發(fā)現(xiàn)一個(gè)特定的USB設(shè)備,您可以為android.hardware.usb.action.USB_DEVICE_ATTACHED這個(gè)意圖指定一個(gè)意圖來進(jìn)行過濾。伴隨著這個(gè)意圖過濾器,您需要指定一個(gè)資源文件來特別說明這個(gè)USB設(shè)備的屬性,例如供應(yīng)商和產(chǎn)品ID。當(dāng)用戶連接到一個(gè)符合您配件過濾條件的配件時(shí),這個(gè)系統(tǒng)會談出一個(gè)對話框詢問他們是否希望開始您的應(yīng)用。如果用戶同意,那么您的應(yīng)用在失去連接之前會自動獲取和設(shè)備連接的權(quán)限。
下面的例子告訴您該如何聲明這個(gè)意圖過濾器:
?
<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設(shè)備的相關(guān)資源文件:
?
<?xml?version="1.0"?encoding="utf-8"?>
?
<resources>
????<usb-device?vendor-id="1234"?product-id="5678"?/>
</resources>
?
在您的activity文件中,您可以從像這樣的意圖(有附加類的)中獲取UsbDevice來代表這個(gè)相關(guān)的配件:
?
UsbDevice device = (UsbDevice)?intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
?
枚舉所有配件
您可以使您的應(yīng)用在運(yùn)行時(shí)列舉出所有能夠被識別的USB設(shè)備。通過getDeviceList()方法來獲得一個(gè)包含所有已連接USB配件的數(shù)組:
?
UsbManager manager = (UsbManager)?getSystemService(Context.USB_SERVICE);
... ?
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");
?
如果您喜歡,您也可以一個(gè)接一個(gè)的從每一個(gè)設(shè)備的哈希圖和過程中獲取一個(gè)迭代器:
?
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
}
?
獲得使用一個(gè)配件的權(quán)限
在您使用一個(gè)USB設(shè)備前,您的應(yīng)用必須從用戶那里獲得權(quán)限。
注意:如果您的應(yīng)用在連接USB設(shè)備時(shí)通過一個(gè)意圖過濾器來發(fā)現(xiàn)它們,如果用戶允許您的應(yīng)用來處理這個(gè)意圖,它將自動接收這個(gè)權(quán)限。如果用戶不允許,那么您就必須在連接設(shè)備之前詳細(xì)在您的應(yīng)用中寫明需要請求的權(quán)限。
在某些情況下很有必要明確權(quán)限的許可要求,例如當(dāng)您的應(yīng)用枚舉出所有已經(jīng)連接的USB設(shè)備并且您希望和其中的一個(gè)進(jìn)行“交流”。您必須在和該設(shè)備“交流”前檢查是否有連接該設(shè)備的權(quán)限。如果不是這樣,您的應(yīng)用將在用戶拒絕您連接該設(shè)備的權(quán)限之后收到個(gè)運(yùn)行錯(cuò)誤。
為了確切地獲得權(quán)限,首先需要?jiǎng)?chuàng)建個(gè)廣播接收器。這個(gè)接收器在您調(diào)用requestPermission()這個(gè)方法時(shí)從您得到的廣播中監(jiān)聽這個(gè)意圖。通過調(diào)用requestPermission()這個(gè)方法為用戶跳出一個(gè)是否連接該設(shè)備的對話框。下面的例子告訴您如何創(chuàng)建一個(gè)廣播接收器:
?
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);
????????????????}
????????????}
????????}
????}
};
?
為了注冊您的廣播接收器,將其放在您activity中的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);
?
當(dāng)您需要展示征求用戶同意連接這個(gè)設(shè)備的權(quán)限的對話框時(shí),調(diào)用requestPermission()這個(gè)方法:
?
UsbDevice device;
...
mUsbManager.requestPermission(device, mPermissionIntent);
?
當(dāng)用戶回應(yīng)這個(gè)對話框時(shí),你的廣播接收器就會收到一個(gè)包含用一個(gè)boolean值來表示結(jié)果的EXTRA_PERMISSION_GRANTED字段的意圖。在您連接設(shè)備之前檢查這個(gè)字段的值是否為true。
和設(shè)備之間的“交流”
我們可以同步或者異步的和USB設(shè)備進(jìn)行“交流”。在任意一種情況之下,您都應(yīng)該創(chuàng)建一個(gè)新的線程來進(jìn)行數(shù)據(jù)傳輸,這樣就不會阻塞您的主線程了。要想正確的設(shè)置好和一個(gè)設(shè)備之間的連接,您需要獲得該設(shè)備正確的UsbInterface和UsbEndpoint來和您進(jìn)行“交流”以及通過UsbDeviceConnection在這個(gè)接入點(diǎn)上發(fā)送請求。一般來說,您的代碼應(yīng)該這樣:
- 檢查一個(gè)UsbDevice對象的屬性,例如產(chǎn)品ID,供應(yīng)商ID,或者是關(guān)于設(shè)備的類,以此來確認(rèn)您是否希望和該設(shè)備進(jìn)行“交流”。
- 當(dāng)您確信您希望和該設(shè)備進(jìn)行“交流”時(shí),找到關(guān)于該設(shè)備正確的UsbInterface以及和該接口所對應(yīng)的UsbEndpoint。接口可以有一個(gè)或者多個(gè)接入點(diǎn),而且一般都會有一個(gè)雙向通信的輸入和輸出接入點(diǎn)。
- 當(dāng)您找到正確的接入點(diǎn)時(shí),在該接入點(diǎn)時(shí)打開一個(gè)UsbDeviceConnection。
- 您可以通過bulkTransfer()和controlTransfer()這兩個(gè)方法在接入點(diǎn)上傳輸您所需要傳遞的數(shù)據(jù)。您最好在另起一個(gè)新的線程來進(jìn)行這個(gè)步驟以避免阻塞主線程。想要詳細(xì)地了解關(guān)于Android中使用線程的信息,詳見線程和進(jìn)程。
下面的代碼段是做同步數(shù)據(jù)傳輸?shù)囊粋€(gè)簡單方式。您的代碼應(yīng)該有更多的邏輯來準(zhǔn)確地找到和設(shè)備“交流”的接口和接入點(diǎn),而且應(yīng)該能夠在不同于主線程的線程中能夠傳輸任何的數(shù)據(jù)傳輸。
?
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
?
為了能夠異步傳輸數(shù)據(jù),使用UsbRequest類來初始和隊(duì)列化一個(gè)異步請求,然后等待requestWait()方法的結(jié)果。
想要了解更多地信息,請您參考Adb Test sample,這個(gè)參考將會告訴您如何進(jìn)行異步批量傳輸,還有MissleLauncher sample將會告訴您如何異步監(jiān)聽一個(gè)中斷端點(diǎn)。
中止和設(shè)備的“交流”
當(dāng)您在完成和設(shè)備的“交流”之后,又或者該設(shè)備被移除了,通過調(diào)用releaseInterface()和close()的方法來關(guān)閉UseInterface和UsbDeviceConnection。為了監(jiān)聽分離這樣的事件,您需要?jiǎng)?chuàng)建一個(gè)如下的廣播接收器:
?
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
????????????}
????????}
????}
};
?
轉(zhuǎn)載于:https://www.cnblogs.com/lsy-2016/p/7286127.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
- 上一篇: linux addr2line
- 下一篇: mac下webstorm 安装