編輯:關於Android編程
目錄
[隱藏]
1USB主機
1.1文檔內容
1.2相關例子
1.3API概述
1.4Android中manifest文件的需求
1.4.1Manifest文件和資源文件的例子
1.5用配件工作
1.5.1發現設備
1.5.1.1使用一個意圖過濾器
1.5.1.2枚舉所有配件
1.5.2獲得使用一個配件的權限
1.5.3和設備之間的“交流”
1.5.4中止和設備的“交流”
USB主機
文檔內容
API概述
Android中manifest文件需求
工作的設備
發現設備
獲得和設備進行“交流”的權限
和設備進行“交流”
中止和設備的“交流”
相關例子
Adb測試用例
相關鏈接
當您搭載Android系統的設備處於USB主機模式時,它就像一個USB主機,為總線提供能源,並且列舉出所有已經連接上的設備。在Android 3.1或者更高的版本中支持USB主機模式。
API概述
在您開始之前,有個很重要的一點就是您必須對將要用到的類有個了解。下面的表格就向您描述了在android.hardware.usb這個包下USB主機APIs的一些特點。
表1.USB主機APIs
Class/Interface Description
UsbManager
允許您枚舉已連接的USB設備並且與其進行“交流”。
UsbDevice
代表了一個已連接的USB的設備並且包含具有該設備驗證信息,接口和接入點的方法。
UsbInterface
代表了一個USB設備的一個接口,該接口定義了一系列關於設備的函數。一個設備在進行“交流”的時候可以有一個或者多個接口。
UsbEndpoint
代表一個接口的接入點,該接入點就是這個接口的通信信道。一個接口可以有一個或者多個這樣的接入點,而且一般都是有輸入和輸出雙向通信的接入點。
UsbDeviceConnection
代表該設備的一個連接,用來在接入點上傳輸數據。這個類允許您能用同步或者異步的方式發送和返回數據。
UsbRequest
在通過UsbDeviceConnection和設備進行“交流”的一個異步請求。
UsbConstants
關於在linux內核中linux/usb/ch9.h的相關定義的USB常量。
在大多數的情況之下,在和一個USB設備進行“交流”時,上面這些類都需要用到(UsbRequest這個類只有在您做異步通信的時候才會用到)。一般來說,您可以通過查詢要操作的UsbDevice來獲得一個UsbManager。當您有這個設備時,您需要找到正確的UsbInterface以及和這個接口所對應的UsbEndpoint來進行和設備的“交流”。一旦您獲得了正確的接入點,打開UsbDeviceConnection來和該USB設備進行“交流”。
Android中manifest文件的需求
下面的列表就是描述您應該在用USB主機APIs之前應該在您的應用中的manifest文件中添加些什麼:
因為不是所有的搭載Android系統的設備都能保證支持USB主機的APIs,不能包含那個聲明您的應用使用android.hardware.usb.host這一特點的android.hardware.usb.host的這一元素。
設置您的應用的最低的SDK版本在12級或者更高。這個USB主機APIs不在更前面的版本之中。
如果您希望您的應用能夠被連接的USB設備所提示,只要在您的主activity中在<intent-filter>和<meta-data>元素對中添加一個android.hardware.usb.action.USB_DEVICE_ATTACHED意圖。<meta-data>元素指向一個額外的XML資源文件,該文件是用來聲明驗證您希望探測到的設備的驗證信息。
在這個XML資源文件中,為您希望過濾的USB設備聲明<usb-device>元素。下面的列表描述<usb-device>的屬性。一般來說,如果您想為一個特定的設備過濾就使用該產品的供應商和產品ID,如果您希望為一組USB設備,例如大量存儲設備或者是數碼相機來進行過濾那麼就應該用類,子類和協議。您可以不指定這些屬性,也可以指定所有的屬性。不為每個設備指定屬性,只有在您的應用需要它時才這麼做(這句話翻譯的一點問題^_^):
供應商ID
產品ID
類
子類
協議(設備或者借口)
將您的資源文件保存到res/xml/目錄下。資源文件名(不包含.xml的擴展名)必須和您在<meta-data>元素中指明的那個名字。在下面的例子中是這個XML資源文件的格式。
Manifest文件和資源文件的例子
下面的例子告訴您一個manifest文件以及與它相關資源文件的例子:
<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>
在這種情況下,下面的資源文件應該被保存在res/xml/device_filter.xml來確保找到那些特定符合您要求屬性的USB設備:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>
用配件工作
當用戶將USB配件連接到搭載Android系統的設備上面時,Android系統會判斷您的應用是否適用於已連接的該配件。如果適用,您就可以根據您的喜好為該設備建立連接。要這麼做,您的應用必須做下面這些動作:
您需要通過一個可以過濾USB設備附加事件的意圖過濾器或者枚舉已連接的USB設備來發現連接的配件來找到合適的接口。
尚未獲得許可的用戶在適用USB設備操作時需要驗證權限。
通過在接入的端點進行讀寫數據的操作達到和USB設備交互的目的。
發現設備
您的應用可以通過兩種方式來發現USB設備,一種是用一個意圖過濾器在用戶連接一個設備時對其進行通知,另一種則是通過枚舉您已經連接的所有USB設備。如果您希望您的應用能夠自動的探測到你想要的設備,請使用一個意圖過濾器來做。但是,如果您希望得到一個已連接設備的列表或者您不希望過濾意圖,枚舉所有的設備會是一個更好的選擇。
使用一個意圖過濾器
為了讓您的應用可以發現一個特定的USB設備,您可以為android.hardware.usb.action.USB_DEVICE_ATTACHED這個意圖指定一個意圖來進行過濾。伴隨著這個意圖過濾器,您需要指定一個資源文件來特別說明這個USB設備的屬性,例如供應商和產品ID。當用戶連接到一個符合您配件過濾條件的配件時,這個系統會談出一個對話框詢問他們是否希望開始您的應用。如果用戶同意,那麼您的應用在失去連接之前會自動獲取和設備連接的權限。
下面的例子告訴您該如何聲明這個意圖過濾器:
<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>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1234" product-id="5678" />
</resources>
在您的activity文件中,您可以從像這樣的意圖(有附加類的)中獲取UsbDevice來代表這個相關的配件:
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
枚舉所有配件
您可以使您的應用在運行時列舉出所有能夠被識別的USB設備。通過getDeviceList()方法來獲得一個包含所有已連接USB配件的數組:
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");
如果您喜歡,您也可以一個接一個的從每一個設備的哈希圖和過程中獲取一個迭代器:
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
}
獲得使用一個配件的權限
在您使用一個USB設備前,您的應用必須從用戶那裡獲得權限。
注意:如果您的應用在連接USB設備時通過一個意圖過濾器來發現它們,如果用戶允許您的應用來處理這個意圖,它將自動接收這個權限。如果用戶不允許,那麼您就必須在連接設備之前詳細在您的應用中寫明需要請求的權限。
在某些情況下很有必要明確權限的許可要求,例如當您的應用枚舉出所有已經連接的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);
當您需要展示征求用戶同意連接這個設備的權限的對話框時,調用requestPermission()這個方法:
UsbDevice device;
...
mUsbManager.requestPermission(device, mPermissionIntent);
當用戶回應這個對話框時,你的廣播接收器就會收到一個包含用一個boolean值來表示結果的EXTRA_PERMISSION_GRANTED字段的意圖。在您連接設備之前檢查這個字段的值是否為true。
和設備之間的“交流”
我們可以同步或者異步的和USB設備進行“交流”。在任意一種情況之下,您都應該創建一個新的線程來進行數據傳輸,這樣就不會阻塞您的主線程了。要想正確的設置好和一個設備之間的連接,您需要獲得該設備正確的UsbInterface和UsbEndpoint來和您進行“交流”以及通過UsbDeviceConnection在這個接入點上發送請求。一般來說,您的代碼應該這樣:
檢查一個UsbDevice對象的屬性,例如產品ID,供應商ID,或者是關於設備的類,以此來確認您是否希望和該設備進行“交流”。
當您確信您希望和該設備進行“交流”時,找到關於該設備正確的UsbInterface以及和該接口所對應的UsbEndpoint。接口可以有一個或者多個接入點,而且一般都會有一個雙向通信的輸入和輸出接入點。
當您找到正確的接入點時,在該接入點時打開一個UsbDeviceConnection。
您可以通過bulkTransfer()和controlTransfer()這兩個方法在接入點上傳輸您所需要傳遞的數據。您最好在另起一個新的線程來進行這個步驟以避免阻塞主線程。想要詳細地了解關於Android中使用線程的信息,詳見線程和進程。
下面的代碼段是做同步數據傳輸的一個簡單方式。您的代碼應該有更多的邏輯來准確地找到和設備“交流”的接口和接入點,而且應該能夠在不同於主線程的線程中能夠傳輸任何的數據傳輸。
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()方法的結果。
想要了解更多地信息,請您參考Adb Test sample,這個參考將會告訴您如何進行異步批量傳輸,還有MissleLauncher sample將會告訴您如何異步監聽一個中斷端點。
中止和設備的“交流”
當您在完成和設備的“交流”之後,又或者該設備被移除了,通過調用releaseInterface()和close()的方法來關閉UseInterface和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文件中,允許您的應用只能在它運行的時候處理這樣的設備分離事件。這樣的話,設備分離這個事件就只向正在運行的應用廣播,而不是向所有的應用進行廣播。
1. 前言安卓屬於小團隊開發,架構的重要性在很多公司其實不是那麼的明顯,加上現在的開源框架層出不窮,更好的幫助我們上手android項目的開發。我前兩年也在公司主導過項目
前言關於RecyclerView的使用這裡就不在贅述了,相信網上一搜一大把(本人之前的文章也有簡單的使用介紹),這次我們講的是RecyclerView在使用的過程中,有時
一、問題在哪裡?問題來源於app開發中一個很常見的場景——用戶頭像要展示成圓的: 二、怎麼搞?機智的我,第一想法就是,切一張中間圓形透明、四周與底色相同、尺寸與
View的Draw時序圖前面幾篇通過對View樹的measure和layout過程分析事,接下來將結合前兩步得到的測量值及在視圖中的位位置,開始進行繪制操作,一步比一步復