獲得跟附件通訊的許可權
在跟USB附件裝置進行通訊之前,你的應用程式必須要從使用者那裡獲得許可。
注意:如果你的應用程式使用Intent過濾器來發現那些被接入的附件裝置,而且使用者允許你的應用程式處理該Intent對象,那麼會自動的接收許可。否則,在串連附件裝置之前,你必須明確的申請接入許可。
明確的申請接入許可,在有些情況下是必須的,如在你的應用程式列舉出了已經接入的附件裝置,並要跟其中之一進行通訊時。在試圖跟其通訊之前,你必須檢查訪問該附件裝置的許可權。否則,如果使用者拒絕了你訪問該附件裝置的請求,你會收到一個執行階段錯誤。
要明確的獲得許可,首先就要建立一個廣播接收器。這個接收器會監聽在調用requestPermission()方法時獲得的用於廣播的Intent對象。調用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) {
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);
調用requestPermission()方法來顯示申請接入附件裝置許可權的對話方塊:
UsbAccessory accessory;
...
mUsbManager.requestPermission(accessory, mPermissionIntent);
當使用者應答了該對話方塊,你的廣播接收器會收到一個包含了EXTRA_PERMISSION_GRANTED類型附件的Intent對象,它用一個布爾值來代表回答結果。在串連該附件裝置之前,要檢查該附件的值是否是true。
跟一個附件裝置通訊
通過使用UsbManagerd對象擷取一個檔案描述符來跟附件裝置通訊,你能夠使用這個檔案描述符建立讀寫資料的輸入和輸出資料流。該流代表了附件裝置的輸入和資料區塊端點。你應該在另外一個線程中建立裝置和附件之間的通訊,以便不至於阻塞主UI線程。下例顯示了如何開啟跟附件裝置的通訊:
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();
}
}
線上程的run()方法中,你可以使用FileInputStream和FileOutputStream對象來讀寫附件裝置。在使用FileInputStream對象從附件裝置中讀取資料時,要確保有足夠大的緩衝來儲存USB包資料。Android從屬模式協議支援的最大包緩衝是16384個位元組,因此你可以簡單的始終把你的緩衝聲明成這個尺寸。
注意:在底層,對於全速USB附件裝置的64位元組包和高速USB附件裝置的512位元組包,Android從屬模式協議會簡單的把這個兩個資料打包成一個邏輯包。
終止跟附件裝置的通訊
在完成跟附件裝置的通訊或附件裝置被拔出時,你要調用close()方法來關閉被開啟的檔案描述符。建立以下廣播接收器,來監聽分離事件:
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
}
}
}
};
在應用程式中建立的廣播接收器,而且不在資訊清單檔中,這樣的廣播接收器允許你的應用程式只在運行時處理分離事件。這種方式,分離事件只發送給當前正在啟動並執行應用程式,並不會廣播給所有的應用程式。