Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android]聯通性 -- USB主機模式

[Android]聯通性 -- USB主機模式

編輯:關於Android編程

當你的Android設備在USB主機模式中時,它作為USB主機給從屬設備供電,並會列舉被連接的USB設備。USB主機模式在Android3.1以後開始被支持。

一,API概要

        在開始之前,重要的是要理解工作中所需要的類。下表介紹了在android.hardware.usb包中的USB主機模式API。 


        表1    USB主機模式API


 介紹
 
UsbManager
 用於列舉被連接的USB設備,並跟其通信。
 
UsbDevice
 代表了一個被連接的USB設備,並且包含了訪問它的識別信息、接口、和端點的方法。
 
UsbInterface
 代表了一個USB設備的接口,該接口定義了設備的一組功能。一個設備可以有一個或多個用於通信的接口。
 
UsbEndpoint
 代表一個接口端點,它是跟接口通信的通道。一個接口可以有一個或多個端點,通常會有跟設備進行雙工通信的輸入和輸出端點。
 
UsbDeviceConnection
 代表一個設備連接,它在端點之上傳輸數據。這個類用於在連接的兩個設備間使用同步或異步的方式來回發送數據。
 
UsbRequest
 代表一個通過UsbDeviceConnection對象跟設備通信的異步請求。
 
UsbConstants
 定義了跟Linux內核中linux/usb/ch9.h文件定義對應的USB常量。
 

        在大多數情況中,跟USB設備通信時,需要使用所有這些類(如果你是在使用異步通信,那麼只需要使用UsbRequest類)。通常,要使用UsbManager對象來獲取期望的UsbDevice對象。當你有了這個UsbDevice對象時,就需要查找對應的UsbInterface對象和基於該接口通信的UsbEndpoint對象。一旦獲取了正確的端點,就可以打開UsbDeviceConnect對象來跟USB設備進行通信了。

二,Android清單要求

        在使用USB主機模式API工作之前,你需要把以下介紹的內容添加到你的應用程序清單中:

        1.   因為不是所有的Android設備都保證支持USB主機模式,所以要在你的應用程序聲明中包含<uses-feature>元素,以聲明你的應用程序要使用android.hardware.usb.host功能。

        2.   把應用程序的最小SDK設置為API Level 12或更高的版本。在較早的API版本中不存在USB主機模式API。

        3.   如果你希望你的應用程序能夠獲得接入USB設備時的通知,那麼還要在你的主Activity中指定用android.hardware.usb.action.USB_DEVICE_ATTACHED類型的Intent來配對的<intent-filter>和<meta-data>元素。<meta-data>元素要指向一個外部的XML資源文件,該文件聲明了希望檢測的設備的識別信息(對方設備發過來的信息)。

        在這個XML資源文件中,要用<usb-device>元素來聲明你想要過濾的USB設備。以下列出了<usb-device>元素的屬性。通常,使用vendor-id和product-id來指定你所希望過濾的特定的設備,並且使用class、subclass和protocol來指定你所希望過濾的USB設備組,如大容量存儲設備或數碼相機。你可以不指定任何屬性,或所有全部屬性。不指定任何屬性,就會跟所有USB設備匹配,如果應用程序需要,就可以這樣做:

A. vendor-id

B. product-id

C. class

D. subclass

E.  protocol(設備或接口)

在res/xml目錄中保存這個資源文件。該資源文件的名稱(不含.xml擴展名)必須跟<meta-data>元素中指定的名稱相同。XML資源文件的格式請看下例。

三,清單和資源文件的示例

以下是一個簡單的清單文件和它所對應的資源文件:

<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系統能夠判斷你的應用程序是否對接入的設備感興趣。如果是你的應用程序感興趣的設備,你就可以跟你期望的設備建立通信。以下是你的應用程序必須要做的工作:

     1. 使用以下兩種方法之一來發現接入的UDB設備:

              A. 使用Intent過濾器,過濾用戶接入USB設備時所發出的通知;

              B. 列舉已經接入的USB設備。

     2. 如果沒獲取接入USB設備的權限,會向用戶請求接入USB設備的權限。

     3. 通過讀寫對應接口端點上的數據來跟USB設備通信。

五,發現設備

        用戶既可以通過使用


              1.用戶接入USB設備時所發出Intent過濾通知


              2.也可以通過列舉已經接入的USB設備


        來發現USB設備。

        如果你希望你的應用程序能夠自動的檢測到你所期望的USB設備,那麼要使用Intent過濾器。

        如果你想要過的接入的所有的已經接入的設備列表,或者是你的應用程序沒有過濾對應的Intent對象,那麼要使用列舉的方法。

六,使用Intent過濾器

         為了讓你的應用程序發現一個特殊的USB設備,你可以指定一個android.hardware.usb.action.USB_DEVICE_ATTACHED類型的Intent過濾器。跟這個Intent過濾器一起,你還需要指定一個指定了USB設備屬性的資源文件,如果產品和供應商ID。當用戶接入的設備跟你的設備過濾器匹配的時候,系統會顯示一個對話框,詢問你是否允許它們啟動你的應用程序。如果用戶接收,應用程序會自動的被授予訪問設備的權限,一直到設備斷開連接。

以下示例演示了如何聲明Intent過濾器:

<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設備的資源文件:

<?xml version="1.0" encoding="utf-8"?>

<resources>

   <usb-device vendor-id="1234" product-id="5678" />

</resources>

在你的Activity中,按照如下的方法,你可以從Intent對象中獲得一個代表接入的設備的UsbDevice對象:

UsbDevice device=(UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);

七,列舉設備

        當你的應用程序要在運行時檢測當前接入的所有的USB設備時,它可以列舉總線上的設備。使用getDeviceList()方法來獲取已經接入的所有的USB設備的hash map。該hash map使用USB設備的名稱做key:

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);

...

HashMap<String, UsbDevice> deviceList = manager.getDeviceList();

UsbDevice device = deviceList.get("deviceName");

如果你願意,也可以使用hash map的迭代器來處理每個設備:

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設備進行通信之前,你的應用程序必須要獲取用戶的許可。

       注意:如果你的應用程序使用Intent過濾器來發現接入的USB設備,而且用戶允許你的應用程序處理該Intent,那麼它會自動的接收權限,否則,在你的應用程序接入該設備之前,必須明確的申請權限。

         明確的申請權限在某些情況下是必須的,如你的應用程序列舉已經接入的USB設備並想要跟其中的一個設備通信的時候。在試圖跟一個設備通信之前,你必須要檢查是否有訪問設備的權限。否則,如果用戶拒絕了你訪問該設備的請求,你會收到一個運行時錯誤。

         要明確的獲取這個權限,首先要創建一個廣播接收器。這個接收器用於監聽你調用requestPermission()方法時,系統所發出的Intent對象。調用requestPermission()方法時,系統會顯示一個對話框,詢問用戶是否允許跟該USB設備進行連接。下列代碼演示如何創建這個廣播接收器:

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);

        當用戶應答了該對話框時,你的廣播接收器就會收到一個包含EXTRA_PERMISSINO_GRANTED類型附加字段的Intent對象,該字段用一個布爾值來代表回答結果。在連接該設備之前,要檢查這個字段的值是否是true。

九,跟設備進行通信

         跟USB設備的通信既可以是異步的,也可以是同步的。在異步的情況下,你應該創建一個線程來執行所有的數據傳輸,以便不至於阻塞UI線程。要正確的建立跟設備的通信,你需要獲得准備與其通信的設備所對應的UsbInterface和UsbEndpoint對象,並且使用UsbDeviceConnection對象把請求發送給這個端點。通常步驟如下:

          1.       檢查UsbDevice對象的屬性,如產品ID、供應商ID、或者設備的分類,判斷該設備是否是你所想要的設備;

          2.       當你確認它是你想要與其通信的設備時,就要找到該設備對應的UsbInterface對象以及跟該接口對象一起的UsbEndpoint對象。接口可以有一個或多個端點,通常會有用於雙工通信的輸入和輸出端點;

          3.       當你找正確的端點時,就可以打開一個該端點上的UsbDeviceConnection對象;

          4.       使用bulkTransfer()或controlTransfer()方法,把你想要傳輸的數據提供給端點。你應該在另外一個線程中執行本步驟的操作,以便防止阻塞主UI線程。

          以下代碼片段是一個普通的同步傳輸數據的方法。你的代碼應該有更多的邏輯用於查找用來通信的正確的接口和端點,並且還應該在一個不同於主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()方法等待結果。

更多的信息請看Adb test sample,它顯示了怎樣進行異步塊數據數據傳輸,MissleLauncher sample顯示了如何監聽異步的中斷端點。

十,中斷跟設備的通信

         在你完成跟設備的通信,或者設備被分離時,就要調用releaseInterface()方法和close()方法來關閉UsbInterface和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

           }

       }

   }

};

如果在應用程序中創建廣播接收器,但沒有在清單中注冊,那麼就允許你的應用程序只在運行時處理分離事件。這種情況下,分離事件只會發送給當前運行的應用程序,並且不是廣播給所有的應用程序

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved