USB主機(jī)當(dāng)您搭載Android系統(tǒng)的設(shè)備處于USB主機(jī)模式時,它就像一個USB主機(jī),,為總線提供能源,,并且列舉出所有已經(jīng)連接上的設(shè)備。在Android 3.1或者更高的版本中支持USB主機(jī)模式,。 API概述在您開始之前,,有個很重要的一點就是您必須對將要用到的類有個了解,。下面的表格就向您描述了在android.hardware.usb這個包下USB主機(jī)APIs的一些特點。 表1.USB主機(jī)APIs
在大多數(shù)的情況之下,,在和一個USB設(shè)備進(jìn)行“交流”時,,上面這些類都需要用到(UsbRequest這個類只有在您做異步通信的時候才會用到)。一般來說,,您可以通過查詢要操作的UsbDevice來獲得一個UsbManager,。當(dāng)您有這個設(shè)備時,您需要找到正確的UsbInterface以及和這個接口所對應(yīng)的UsbEndpoint來進(jìn)行和設(shè)備的“交流”,。一旦您獲得了正確的接入點,,打開UsbDeviceConnection來和該USB設(shè)備進(jìn)行“交流”。 Android中manifest文件的需求下面的列表就是描述您應(yīng)該在用USB主機(jī)APIs之前應(yīng)該在您的應(yīng)用中的manifest文件中添加些什么:
在這個XML資源文件中,為您希望過濾的USB設(shè)備聲明<usb-device>元素,。下面的列表描述<usb-device>的屬性,。一般來說,如果您想為一個特定的設(shè)備過濾就使用該產(chǎn)品的供應(yīng)商和產(chǎn)品ID,如果您希望為一組USB設(shè)備,,例如大量存儲設(shè)備或者是數(shù)碼相機(jī)來進(jìn)行過濾那么就應(yīng)該用類,,子類和協(xié)議。您可以不指定這些屬性,,也可以指定所有的屬性,。不為每個設(shè)備指定屬性,只有在您的應(yīng)用需要它時才這么做(這句話翻譯的一點問題^_^):
將您的資源文件保存到res/xml/目錄下,。資源文件名(不包含.xml的擴(kuò)展名)必須和您在<meta-data>元素中指明的那個名字,。在下面的例子中是這個XML資源文件的格式。 Manifest文件和資源文件的例子下面的例子告訴您一個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è)備上面時,,Android系統(tǒng)會判斷您的應(yīng)用是否適用于已連接的該配件。如果適用,,您就可以根據(jù)您的喜好為該設(shè)備建立連接,。要這么做,您的應(yīng)用必須做下面這些動作:
發(fā)現(xiàn)設(shè)備您的應(yīng)用可以通過兩種方式來發(fā)現(xiàn)USB設(shè)備,,一種是用一個意圖過濾器在用戶連接一個設(shè)備時對其進(jìn)行通知,,另一種則是通過枚舉您已經(jīng)連接的所有USB設(shè)備。如果您希望您的應(yīng)用能夠自動的探測到你想要的設(shè)備,,請使用一個意圖過濾器來做,。但是,,如果您希望得到一個已連接設(shè)備的列表或者您不希望過濾意圖,,枚舉所有的設(shè)備會是一個更好的選擇。 使用一個意圖過濾器為了讓您的應(yīng)用可以發(fā)現(xiàn)一個特定的USB設(shè)備,,您可以為android.hardware.usb.action.USB_DEVICE_ATTACHED這個意圖指定一個意圖來進(jìn)行過濾,。伴隨著這個意圖過濾器,您需要指定一個資源文件來特別說明這個USB設(shè)備的屬性,,例如供應(yīng)商和產(chǎn)品ID,。當(dāng)用戶連接到一個符合您配件過濾條件的配件時,這個系統(tǒng)會談出一個對話框詢問他們是否希望開始您的應(yīng)用,。如果用戶同意,,那么您的應(yīng)用在失去連接之前會自動獲取和設(shè)備連接的權(quán)限。 下面的例子告訴您該如何聲明這個意圖過濾器: <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來代表這個相關(guān)的配件: UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 枚舉所有配件您可以使您的應(yīng)用在運(yùn)行時列舉出所有能夠被識別的USB設(shè)備,。通過getDeviceList()方法來獲得一個包含所有已連接USB配件的數(shù)組: UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);... HashMap<String, UsbDevice> deviceList = manager.getDeviceList();UsbDevice device = deviceList.get('deviceName'); 如果您喜歡,您也可以一個接一個的從每一個設(shè)備的哈希圖和過程中獲取一個迭代器: 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} 獲得使用一個配件的權(quán)限在您使用一個USB設(shè)備前,您的應(yīng)用必須從用戶那里獲得權(quán)限,。 注意:如果您的應(yīng)用在連接USB設(shè)備時通過一個意圖過濾器來發(fā)現(xiàn)它們,,如果用戶允許您的應(yīng)用來處理這個意圖,它將自動接收這個權(quán)限,。如果用戶不允許,,那么您就必須在連接設(shè)備之前詳細(xì)在您的應(yīng)用中寫明需要請求的權(quán)限。 在某些情況下很有必要明確權(quán)限的許可要求,,例如當(dāng)您的應(yīng)用枚舉出所有已經(jīng)連接的USB設(shè)備并且您希望和其中的一個進(jìn)行“交流”,。您必須在和該設(shè)備“交流”前檢查是否有連接該設(shè)備的權(quán)限。如果不是這樣,,您的應(yīng)用將在用戶拒絕您連接該設(shè)備的權(quán)限之后收到個運(yùn)行錯誤,。 為了確切地獲得權(quán)限,首先需要創(chuàng)建個廣播接收器,。這個接收器在您調(diào)用requestPermission()這個方法時從您得到的廣播中監(jiān)聽這個意圖,。通過調(diào)用requestPermission()這個方法為用戶跳出一個是否連接該設(shè)備的對話框。下面的例子告訴您如何創(chuàng)建一個廣播接收器: 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)您需要展示征求用戶同意連接這個設(shè)備的權(quán)限的對話框時,,調(diào)用requestPermission()這個方法: UsbDevice device;...mUsbManager.requestPermission(device, mPermissionIntent); 當(dāng)用戶回應(yīng)這個對話框時,你的廣播接收器就會收到一個包含用一個boolean值來表示結(jié)果的EXTRA_PERMISSION_GRANTED字段的意圖,。在您連接設(shè)備之前檢查這個字段的值是否為true,。 和設(shè)備之間的“交流”我們可以同步或者異步的和USB設(shè)備進(jìn)行“交流”。在任意一種情況之下,,您都應(yīng)該創(chuàng)建一個新的線程來進(jìn)行數(shù)據(jù)傳輸,,這樣就不會阻塞您的主線程了。要想正確的設(shè)置好和一個設(shè)備之間的連接,,您需要獲得該設(shè)備正確的UsbInterface和UsbEndpoint來和您進(jìn)行“交流”以及通過UsbDeviceConnection在這個接入點上發(fā)送請求,。一般來說,您的代碼應(yīng)該這樣:
下面的代碼段是做同步數(shù)據(jù)傳輸?shù)囊粋€簡單方式。您的代碼應(yīng)該有更多的邏輯來準(zhǔn)確地找到和設(shè)備“交流”的接口和接入點,,而且應(yīng)該能夠在不同于主線程的線程中能夠傳輸任何的數(shù)據(jù)傳輸,。 private Byte[] bytesprivate 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類來初始和隊列化一個異步請求,,然后等待requestWait()方法的結(jié)果,。 想要了解更多地信息,請您參考Adb Test sample,,這個參考將會告訴您如何進(jìn)行異步批量傳輸,,還有MissleLauncher sample將會告訴您如何異步監(jiān)聽一個中斷端點。 中止和設(shè)備的“交流”當(dāng)您在完成和設(shè)備的“交流”之后,,又或者該設(shè)備被移除了,,通過調(diào)用releaseInterface()和close()的方法來關(guān)閉UseInterface和UsbDeviceConnection。為了監(jiān)聽分離這樣的事件,,您需要創(chuàng)建一個如下的廣播接收器: 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 } } }}; 在您的應(yīng)用中創(chuàng)建這個廣播接收器,,不是在manifest文件中,允許您的應(yīng)用只能在它運(yùn)行的時候處理這樣的設(shè)備分離事件,。這樣的話,,設(shè)備分離這個事件就只向正在運(yùn)行的應(yīng)用廣播,而不是向所有的應(yīng)用進(jìn)行廣播,。 |
|