編輯:關於Android編程
原文地址: https://developer.android.com/guide/topics/connectivity/usb/host.html
Android 支持多種 USB 外設和 Android USB 配件(硬件實現 Android 配件協議),通過兩種模式: USB 配件和 USB 主機。在 USB 配件模式中,外部 USB 硬件擔當 USB 主機。在 USB 主機模式中,Android 設備擔當主機。這樣的設備包括數碼相機、鍵盤、鼠標和游戲控制器等。
USB 配件和主機模式在 Android 3.1(API 等級12) 或者更高的版本中支持。
注意: 對於支持 USB 主機和配件模式最終依賴於設備的硬件配置,不管平台的API等級是多少。你可以設置 元素過濾設備是否支持 USB 主機和配件的使用。
當你的 Android 設備在主機模式中,它擔當 USB 主機,提供電源,羅列連接的 USB 設備。 USB 主機模式在 Android 3.1 或更高的版本中支持。
在開發之前,去理解開發中將要用到的類是很重要的。下表描述了在 android.hardware.usb 包中的 USB 主機的 API。
在大多數情況下,和一個 USB 通信時你需要使用以上這些類。通常,你得到一個 UsbManager 去獲取一個期望的 UsbDevice 。你需要去尋找合適的 UsbInterface 以及通信接口的 UsbEndpoint 。一旦你獲得正確的endpoint,就可以打開一個 UsbDeviceConnection 去和 USB 設備通信。
下面的描述是你在使用 USB 主機 API 開發時需要在你的應用的 Manifest 文件中添加的內容:
因為不是所有的 Android 設備都保證支持 USB 主機 API ,在 元素中聲明你的應用使用 android.hardware.usb.host 特性。
設置應用的最小 SDK 的 API 等級為 12 或者更高。 USB 主機 API 在之前的版本中沒有提出。
如果你想要你的應用在連接上 USB 設備時進行提示,在你的主 activity 中的 和 元素對中添加 android.hardware.usb.action.USB_DEVICE_ATTACHED 意圖。 元素指向一個外部 XML 資源文件,它聲明了你想要監測的設備的識別信息。
在 XML 資源文件中,在 元素中聲明你想要過濾的 USB 設備。下面列表描述了 的屬性。通常,如果你想要過濾一個指定的設備可以使用供應商和產品編號,如果你想要過濾一類 USB 設備,如大量的存儲設備或者數碼相機,可以使用類、子類和協議。你可以不指定或者指定所有的屬性。沒有指定這些屬性會匹配每一個 USB 設備,如果你的應用有需要只要指定這些:
vendor-id product-id class subclass protocol(device or interface)在 res/xml 目錄中保存這個資源文件。資源文件的名字必須和你在 元素中只指定的一樣。
下面示例展示了一個 manifest 范例和它相應的資源文件:
... ...
在這種情況下,下面的資源文件應該保存為 res/xml/device-filter.xml ,指定要過濾設備的屬性:
當用戶的 USB 設備連接到 Android 設備時,Android 系統可以判定你的應用是否對連接的設備感興趣。如果是這樣,你可以和期望的設備建立通信。要這樣做,你的應用必須:
去發現已連接的 USB 設備,可以使用一個 intent 過濾器在用戶連接到一個 USB設備時進行通知,也可以通過枚舉已連接的 USB 設備。
對已連接的 USB 設備請求用戶權限,是否已獲得。
與 USB 設備通信,在合適的 interface 上的 endpoint 的進行數據讀寫。
你的應用可以使用 intent 過濾器在用戶連接上一個設備時進行通知或者枚舉已連接的 USB 設備去發現 USB設備。如果你想要你的應用自動去檢測期望的設備,那麼使用 intent 過濾器是非常有用的。如果你想要獲得已連接的設備列表或者如果你的應用沒有 intent 過濾器,則枚舉已連接的 USB 設備是游泳的。
想要你的應用發現一個指定的 USB 設備,你可以指定一個 intent 過濾器去進行過濾,添加 android.hardware.usb.action.USB_DEVICE_ATTACHED 。除了這個 intent 過濾器,你需要指定一個資源文件,這個文件指定 USB 設備設備的屬性,如產品和供應商的ID。當用戶連接一個設備匹配你的設備過濾器時,系統會出現一個提示框詢問是否啟動你的應用。如果用戶接受,你的應用自動擁有訪問設備的權限直到設備斷開連接。
下面示例展示如何聲明 intent 過濾器:
...
下面的示例展示了如何聲明相應的資源文件,指定你感興趣的 USB 設備:
在你的Activity中,你可以獲得 UsbDevice ,它代表從 intent 過濾器連接的設備,像這樣:
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
在你的應用運行期間,如果你的應用對當前所有連接的 USB 設備感興趣,它可以枚舉設備。使用 getDeviceList() 方法獲得一個所有已連接的 USB 設備的散列集合。這個集合的鍵是 USB 設備的名字,如果你想要從集合中獲取一個設備。
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMapdeviceList = manager.getDeviceList(); UsbDevice device = deviceList.get("deviceName");
如果有需要,你也可以從哈希集合中獲得一個迭代器然後一個一個列舉設備:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE); ... HashMapdeviceList = manager.getDeviceList(); Iterator deviceIterator = deviceList.values().iterator(); while(deviceIterator.hasNext()){ UsbDevice device = deviceIterator.next(); //your code }
在與 USB 設備進行通信之前,你的應用必須要有來自用戶的同意。
注意:如果你的應用使用 intent 過濾器發現設備作為他們的連接,如果用戶允許你的應用去處理 intent 他會自動接受許可。如果沒有,在連接設備前你必須在你的應用裡明確地請求許可。
明確請求許可在某些情況裡是必需的,如當你的應用枚舉已經連接的 USB 設備,然後想要與其中一個進行通信時。你必須在嘗試與其通信前檢查訪問設備設備的許可。如果沒有得到許可,如果用戶拒絕訪問設備的許可你將會接收到一個運行時錯誤。
為了明確地獲取許可,首先創建一個廣播接收器。當你調用 requestPermission() 方式時這個接收器監聽獲得的廣播的意圖。調用 requestPermission() 方法顯示一個對話框去詢問用戶是否同意連接設備。下面的示例代碼展示了如何創建廣播接收器:
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);
顯示對話框詢問用戶是否同意連接到設備,調用 requestPermisson() 方法:
UsbDevice device; ... mUsbManager.requestPermission(device, mPermissionIntent);
當用戶對窗口做出響應後,你的廣播接收器會接收到 intent 且包含 EXTRA_PERMISSION_GRANTED 的附加值,一個表示回復的布爾型的值。連接設備前檢查這個值是否為 true 。
和一個 USB 設備通信可以是同步的也可以是異步的。無論那種情況,你都應該創建一個新的線程去進行所有的數據傳輸,這樣就不會阻塞 UI 線程。要正確的和設備建立通信,你需要獲得你想要進行通信的設備的合適的 USBInterface 和 UsbEndpoint ,然後在這個 endpoint 上用一個 UsbDeviceConnection 發送請求。通常,你的編碼應該這樣:
檢查 UsbDevice 對象的屬性,如產品 ID ,供應商 ID ,或者設備類,關於是否想要進行通信的設備。
當你確定想要和一個設備通信時,找到合適的 UsbInterface ,並且在該 interface 中找到合適的 UsbEndpoint 。 interface 可以有一個或多個 endpoint ,通常,在雙向通信中會有一個輸入和出書的 endpoint 。
當你找到正確的 endpoint ,在這個 endpoint 上打開 一個 UsbDeviceConnection 。
提供你想要在 endpoint 上用 bulkTransfer() 或者 controlTransfer() 方法傳輸的數據。你應該在另一個線程中執行這個步驟,以避免阻塞 UI 主線程。
下面的代碼片段是做一個同步數據傳輸的一般方式。你的代碼應該有更多的邏輯去尋找適合通信的 interface 和 endpoint ,而且你做任何數據傳輸應該在其他的線程中執行而不是 UI 主線程:
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
發送異步數據使用 UsbRequest 類去初始化和排隊等候一個異步請求,然後在 requestWait() 中等待結果。
當你完成和設備的通信時或者設備已經斷開,應該調用 releaseInterface() 和 close() 方法去關閉 USsbInterface 和 UsbDeviceConnection 。要監聽分離事件,應該創建如下的廣播接收器:
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 } } } };
在應用裡創建廣播接收器,而不是在 manifest 中,僅僅允許你的應用在運行的時候去處理分離事件。這種方式,分離事件僅在應用運行的時候發送而不是對所有的應用廣播。
下面這張圖片是在google官網上下載的關於android系統的體系結構圖: 組件所使用的C、C++庫的集合,一般說來,android應用開發者不能直接調
仿微信5.2布局,本實例默認編碼GBK。需要的朋友可以研究一下。 【點擊下載】
簡介RecyclerView是Google在android-supportv7包中推出的一個新的控件,該控件的主要作用是用於替代ListView、GridView,相比較
前言本次主要是實現一個Android應用,實現靜態廣播、動態廣播兩種改變 widget內容的方法,即在上篇博文中實驗的基礎上進行修改,所以此次實驗的重點是AppWidge