2011年5月15日日曜日

Android USB Host

USB Host

Android-powered デバイスが USB host mode の場合、USB host として振る舞い、バスに電力を供給し、接続された USB デバイスを列挙します。Usb host mode は Android 3.1 以上でサポートされています。

---

API Overview


まずはじめに、動かすために必要なクラスを理解しましょう。次の表は android.hardware.usb パッケージ内の USB host APIs を記述したものです。

ClassDescription
UsbManager接続している USB デバイスの列挙と通信を許可する
UsbDevice接続された USB デバイスを表し、それを識別するための情報、インタフェース、エンドポイントにアクセスするためのメソッドを含む
UsbInterfaceデバイスに対する functionality のセットを定義する USB デバイスのインタフェースを表す
UsbEndpointこのインタフェースへの通信チャネルであるインタフェースエンドポイントを表す。1つのインタフェースは1個以上のエンドポイントを持つことができ、通常はデバイスと two-way 通信するために入力と出力それぞれのエンドポイントを持つ
UsbDeviceConnectionエンドポイントでデータを転送する、デバイスへの接続を表す。このクラスによって送ったデータを戻したり、同期や非同期を forth することができる
UsbRequestUsbDeviceConnection を通してデバイスと通信するための非同期リクエストを表す
UsbConstansLinux kernel の linux/usb/ch9.h での定義に対応する USB 定数の定義


ほとんどの状況では、USB デバイスと通信するときにこれらのクラス全てを使う必要があります(UsbRequest は非同期通信を行う場合のみ必要です)。一般的には使いたい UsbDevice を取り出すために UsbManager を取得します。デバイスを取得したら、適切な UsbInterface と、そのインタフェースの UsbEndpoint を見つける必要があります。正しいエンドポイントが得られたら、UsbDeviceConnection を開いて、USB デバイスと通信します。

---

Android Manifest Requirements


次のリストは、USB host APIs と動作する前にアプリケーションのマニフェストに追加しなければならない項目です。

  • すべての Android-powered デバイスが USB accessory APIs をサポートする保証があるわけではないので、アプリケーションが android.hardware.usb.accessory 機能を使うことを宣言した <uses-feature> エレメントを含むようにする

  • アプリケーションの最小 SDK を API Level 12 もしくはそれ以上に設定する。USB host APIs は以前の API level では提供されない。

  • USB デバイスが取り付けられたときにアプリケーションに通知したい場合は、android.hardware.usb.action.USB_DEVICE_ATTACHED インテント用の <intent-filter><meta-data> エレメントのペアをメインの Activity に指定する
    <meta-data> エレメントでは、検出したデバイスの識別情報を宣言した外部の XML リソースを示す

    XML リソースファイルでは、フィルターしたいデバイス用の <usb-device> エレメント を宣言する
    <usb-device> は次の属性を持つことができる

     ・ vendor-id
     ・ product-id
     ・ class
     ・ subclass
     ・ protocol (デバイスもしくはインタフェース)

    一般的には、特定のデバイスに対して filter したい場合には vendor と product ID を使い、マスストレージデバイスやデジタルカメラなど USB デバイスのグループに対して filter したい場合には class, subclass, protocol を使う
    リソースファイルは /res/xml ディレクトリに保存する
    リソースファイルの名前 (.xml 拡張子を除いた部分) は <meta-data> エレメントで指定したものと同じでなければならない
    XML リソースファイルの形式も次の example にある



Manifest and resource file examples

次の例はサンプルマニフェストとそれに対応するリソースファイルです。

<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 に保存されているべきであり、vendor IDと product ID に応じてフィルターされるすべての USB デバイスを指定します。これらの ID はデバイス特有のもので、デバイスメーカーによって指定されます。

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

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


---

Working with Devices


ユーザーが USB デバイスを Android-powered デバイスに接続したとき、Android のシステムは接続されたデバイスにあなたのアプリケーションが反応したいかどうか決めることができます。その場合、望むのであればデバイスとの通信をセットアップすることができます。このようにするには、アプリケーションは

  • 1. USB デバイスが取り付けられたイベントをフィルターする intent filter を使うか、すでに接続されている USB デバイスを列挙して接続された USB デバイスを見つける

  • 2. USB デバイスと通信するためのパーミッションをユーザーに尋ねる(またパーミッションを得られていない場合)

  • 3. 適切なインタフェースエンドポイントでデータを読み書きすることで USB デバイスと通信する



Discovering a device

アプリケーションは、ユーザーが USB デバイスを接続したときに知らせてくれる intent filter を使うか、もしくはすでに接続されている USB デバイスを列挙するか、のいずれかの方法をつかって USB デバイスを見つけることができます。アプリケーションが意図している USB デバイス を自動的に検出したい場合、intent filter を使うことはとても便利です。intent をフィルターせず、すべての接続されているデバイスのリストを取得したい場合、接続されている USB デバイスの列挙は便利です。


Using an intent filter

アプリケーションで特定の USB デバイスを見つけるために、android.hardware.usb.action.USB_DEVICE_ATTACHED intent に対してフィルターする intent filter を指定することができます。この intent filter と一緒に USB デバイスのプロパティ(product ID, vendor ID)を宣言したリソースファイルを指定する必要があります。
あなたの設定したデバイスフィルターに一致するデバイスをユーザーが接続すると、システムはあなたのアプリケーションをスタートさせるかどうかを聞くダイアログを表示します。ユーザーが了承すると、あなたのアプリケーションは、デバイスが取り外されるまでデバイスにアクセスするパーミッションを自動的に与えられます。

intent filter の定義は、例えば次のようになります。


<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 を次のようにして intent から取得することができます。

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



Enumerating devices

アプリケーションが起動している間、現在接続されている USB デバイスの inspecting したい場合、バス上のデバイスを列挙することで実現できます。
getDeviceList() メソッドを使って、接続されている全ての USB デバイスのハッシュマップを取得することができます。ハッシュマップは USB デバイスの名前がキーに使われており、マップからデバイスを取得するには次のようにします。


UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap deviceList = manager.getDeviceList();
Iterator deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
// your code
}



Obtaining permission to communicate with a device

USB デバイスと通信する前に、アプリケーションはユーザーから許可を得る必要があります。

注意: アプリケーションが intent filter を使って接続された USB デバイスを見つける場合、アプリケーションがその intent を処理することをユーザーが許可すると、自動的にパーミッションを受信します。そうではない場合、デバイスに接続する前にアプリケーション内で明示的にパーミッションをリクエストしなければなりません。

アプリケーションですでに接続されている USB デバイスを列挙して、いずれかの1つと通信したい場合など、いくつかの状況で明示的にパーミッションを聞く必要があります。デバイスと通信を試みる前に、デバイスにアクセスするパーミッションをチェックしなければなりません。そうしないと、ユーザーが デバイスへのアクセスを拒否した場合にランタイムエラーを受信するでしょう。

明示的にパーミッションを得るために、まず broadcast receiver を作成します。この receiver では requestPermission() を呼んだときに broadcast を取得する intent を listen するようにします。requestPermission() を呼ぶとユーザーに デバイスに接続するかどうかのパーミッションを聞くダイアログが表示されます。
例えば、次のようにして broadcast receiver を作成します。


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


broadcast receiver を登録するには、これを 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(device, mPermissionIntent);


ユーザーがダイアログに返答すると、broadcast receiver は答えを表す boolean の EXTRA_PERMISSION_GRANTED extra を含む intent を受信します。デバイスに接続するまえに、この extra が true になっているかチェックします。


Communicating with a device

USB デバイスとは同期通信、非同期通信のいずれも可能です。どちらのケースでも、UI スレッドをブロックしないために、データを転送するための別のスレッドを作成するべきです。デバイスと正しく通信をセットアップするには、デバイスの適切な UsbInterfaceUsbEndpoint を取得し、UsbDeviceConnection でこのエンドポイントにリクエストを送信する必要があります。一般的にコードで行うべきことは、

  • UsbDevice オブジェクトの属性 (product ID, vendor ID など) もしくはデバイスクラスをチェックして、通信したいデバイスかどうか調べる

  • 通信したいデバイスかどうか確認したら、通信に使いたい適切な UsbInterface とそのインタフェースの適切な UsbEndpoint を見つける
    インタフェースは1つ以上のエンドポイントを持つことができ、通常はtwo-way通信用に入力と出力のエンドポイントを持ちます。

  • 正しいエンドポイントを見つけたら、そのエンドポイントで UsbDeviceConnection を開きます。

  • 転送したいデータをエンドポイント上で bulkTransfer()controlTransfer() メソッド使って供給します。
    メイン UI スレッドをブロックしないように、このステップは別のスレッドで行うべきです。Android でスレッドを使うためのより詳しい情報は Processes and Threads を参照してください。


次のコードスニペットは、同期データ転送を行う自明な方法です。あなたのコードは正しいインタフェースと通信用のエンドポイントを正しく見つけるためのロジックが必要ですし、データの転送をメイン 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 クラスを使って初期化(initializeと非同期リクエストをキューに入れます(queue。そして、requestWait() で結果を待ちます。

より詳しい情報は、非同期 bulk transfer を行う方法を示した AdbTest サンプルを見てください。また、エンドポイントでの非同期割り込みを listen する方法を示した MissleLauncher サンプルも見てください。


Terminating communication with a device

デバイスとの通信が完了した、もしくはデバイスが取り外されたときには、releaseInterface()close() を呼んで UsbInterfaceUsbDeviceConnection を閉じます。取り外されたイベントを察知するには、次のような broadcast receiver を作成します:


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


マニフェストではなく、アプリケーション内で broadcast receiver を作成することで、アプリケーションが起動している間だけ取り外しイベントを処理できるようになります。これにより、取り外しイベントが全てのアプリケーションに broadcast されることなく、現在起動しているアプリケーションにのみ送られます。



Related Samples

1. AdbTest
2. MissleLauncher

Android USB Accessory

USB Accessory

USB accessory モードによって、Android-powered デバイス向けにデザインされた USB host ハードウェアに接続することができます。accessory には Android Accessory Development Kit ドキュメントで説明されている Android accessory プロトコルが付いている必要があります。これにより、USB host として振舞うことができない Android-powered デバイスが USB ハードウェアとやりとりすることができます。Android-powered デバイスが USB accessory モードの場合、接続された Android USB accessory はホストして振る舞い、USB バスに電力を供給し、接続されているデバイスを列挙します。Android 3.1 (API level 12) は USB accessory mode をサポートします。より広い範囲のデバイスでサポートできるように、この機能は Android 2.3.4 (API level 10) にもバックポートされています。

---

Choosing the Right USB Accessory APIs


USB accessory APIs は Android 3.1 プラットフォームで紹介されましたが、Google APIs add-on library を使うことで Android 2.3.4 でも使うことができます。これらの API は外部ライブラリを使うようにバックポートされているため、USB accessory mode をサポートするためにインポートできるパッケージが2つ存在します。サポートしたい Android-powered デバイスに応じて、次のどちらかを使ってください。

  • com.android.future.usb: Android 2.3.4 で USB accessory mode をサポートするためのパッケージで、バックポートされた USB accessory API を含む Google APIs add-on library は、このネームスペース内に入っています。
    add-on library を使って書かれたアプリケーションをサポートするために、Android 3.1 でもこのネームスペース内のクラスのインポートと呼び出しはサポートされています。
    この add-on library は android.hardware.usb accessory API 周りの薄いラッパーで、USB host mode はサポートしていません。
    USB accessory mode をサポートするデバイスをもっとも広い範囲でサポートしたい場合、add-on library を使って、このパッケージをインポートしてください。重要な注意事項として、すべての Android 2.3.4 デバイスが USB accessory 機能をサポートするよう要求されているわけではない、ということがあります。個々のデバイスメーカーがこの機能をサポートするかどうか決定します。これがマニフェストファイルで宣言しなければならない理由です。

  • android.hardware.usb: このネームスペースには、Android 3.1 で USB accessory mode をサポートするためのクラスが含まれています。このパッケージはフレームワーク API の一部として含まれているため、Android 3.1 では USB accessory mode をサポートするのに add-on library を使う必要はありません。
    USB accessory mode をサポートするためのハードウェアを持った Android 3.1 以上のデバイスのみ対象とする場合(この条件はマニフェストファイルで宣言できます)、このパッケージを使ってください。



Installing the Google APIs add-on library

add-on をインストールするには、SDK Manager で Google APIs Android API 10 パッケージをインストールします。add-on library のインストールのより詳しい情報は Installing the Google APIs Add-on を参照してください。

---

API Overview


add-on library はフレームワーク API のラッパーなので、USB accessory 機能をサポートするクラスは似たものになります。そのため、add-on library を使っている場合でも android.hardware.usb のリファレンスドキュメントを使うことができます。

注意: しかし、add-on library とフレームワーク API の間には、気をつけておくべき使い方の違いがあります。

次の表は USB accessory API をサポートするクラスを表しています。

ClassDescription
UsbManager接続された USB accessory の列挙と通信を許可する
UsbAccessoryUSB accessory を表し(represents)、自身の識別情報にアクセスするメソッドを含む



Usage differences between the add-on library and platform APIs

Google APIs add-on library とプラットフォーム API の間の使い方の違いは2つあります。

add-on library を使っている場合、UsbManager オブジェクトは次の方法で取得します。

UsbManager manager = UsbManager.getInstance(this);


add-on library を使わない場合、次の方法で UsbManager オブジェクトを取得します。

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



intent filter を使って接続された accessory をフィルターする場合、UsbAccessory オブジェクトはインテント内に含まれた状態でアプリケーションに渡されます。add-on library を使う場合、次の方法で UsbAccessory オブジェクトを取得します。

UsbAccessory accessory = UsbManager.getAccessory(intent);


add-on library を使わない場合、次の方法で UsbAccessory オブジェクトを取得します。

UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);


---

Android Manifest requirements


次のリストは、USB accessory API 動かす前に、アプリケーションのマニフェストファイルに追加する必要がある項目です。これらのアイテムの宣言例は manifest and resource file examples にあります。

  • すべての Android-powered デバイスが USB accessory APIs をサポートする義務(guaranteed) があるわけではないので、アプリケーションが android.hardware.usb.accessory 機能を使うことを宣言した <uses-feature> エレメントを含むようにする

  • add-on library を使う場合は、com.android.feature.usb.accessory を指定した <uses-library> エレメントを追加する

  • アプリケーションの最小 SDK を、add-on library を使う場合は API Level 10 に、android.hardware.usb パッケージを使う場合は API Level 12 に設定する

  • USB accessory が取り付けられたときのアプリケーションに通知したい場合は、android.hardware.usb.action.USB_ACCESSORY_ATTACHED インテント用の <intent-filter><meta-data> エレメントのペアをメインの Activity に指定する
    <meta-data> エレメントでは、検出した accessory の識別情報を宣言した外部の XML リソースを示す

    XML リソースファイルでは、フィルターしたい accessory 用の <usb-accessory> エレメント を宣言する
    <ues-accessory> は次の属性を持つことができる

     ・ manufacturer
     ・ model
     ・ version

    リソースファイルは /res/xml ディレクトリに保存する
    リソースファイルの名前 (.xml 拡張子を除いた部分) は <meta-data> エレメントで指定したものと同じでなければならない
    XML リソースファイルの形式も次の example にある



Manifest and resource file examples

次の例はサンプルマニフェストとそれに対応するリソースファイルです。

<manifest ...>
<uses-feature android:name="android.hardware.usb.accessory" />

<uses-sdk android:minSdkVersion="<version>" />
...
<application>
<uses-library android:name="com.android.future.usb.accessory" />
<activity ...>
...
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>

<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" />
</activity>
</application>
</manifest>


この場合、次のリソースファイルは res/xml/accessory_filter.xml に保存されているべきであり、model, manifacturer, version に応じてフィルターされるすべての accessory を指定します。accessory はこれらの属性を Android-powered デバイスに送ります。

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

<resources>
<usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
</resources>


---

Working with accessories


ユーザーが USB accessory を Android-powered デバイスに接続したとき、Android のシステムは接続された accessory にあなたのアプリケーションが反応したいかどうか決めることができます。その場合、望むのであれば accessory との通信をセットアップすることができます。このようにするには、アプリケーションは

  • 1. accessory が取り付けられたイベントをフィルターする intent filter を使うか、接続された accessory を列挙して適切なものを選択するかして 接続された accessory を見つける

  • 2. accessory と通信するためのパーミッションをユーザーに尋ねる(まだパーミッションを得られていない場合)

  • 3. 適切なインタフェースエンドポイントでデータを読み書きすることで accessory と通信する



Discovering an accessory

アプリケーションは、ユーザーが accessory を接続したときに知らせてくれる intent filter を使うか、もしくはすでに接続されている accessory を列挙するか、のいずれかの方法をつかって accessory を見つけることができます。アプリケーションが意図している accessory を自動的に検出したい場合、intent filter を使うことはとても便利です。intent をフィルターせず、すべての接続されている accessory のリストを取得したい場合、接続されている accessory の列挙は便利です。


Using an intent filter

アプリケーションで特定の USB accessory を見つけるために、android.hardware.usb.action.USB_ACCESSORY_ATTACHED intent に対してフィルターする intent filter を指定することができます。この intent filter と一緒に USB accessory のプロパティ(manufacturer, model, version)を宣言したリソースファイルを指定する必要があります。

intent filter の定義は、例えば次のようになります。

<activity ...>
...
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>

<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" />
</activity>


対応するリソースファイルは、例えば次のようになります。

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

<resources>
<usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" />
</resources>


activity 内では、取り付けられた accessory を表す UsbAccessory を次のようにして intent から取得することができます。

add-on library を使う場合

UsbAccessory accessory = UsbManager.getAccessory(intent);


プラットフォーム API を使う場合

UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);



Enumerating accessories

アプリケーションが起動している間、自身の識別情報をもった accessory を列挙することができます。

getAccessoryList() メソッド使って、接続されている全ての USB accsessory の配列を取得するには次のようにします。

add-on library を使う場合

UsbManager manager = UsbManager.getInstance(this);
UsbAccessory[] accessoryList = manager.getAcccessoryList();


プラットフォーム API を使う場合

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbAccessory[] accessoryList = manager.getAcccessoryList();


注意: 現在は1回につき1個の接続された accessory のみサポートしていますが、API は将来的に複数の accessory をサポートするようにデザインされています。


Obtaining permission to communicate with an accessory

USB accessory と通信する前に、アプリケーションはユーザーから許可を得る必要があります。

注意: アプリケーションが intent filter を使って接続された accessory を見つける場合、アプリケーションがその intent を処理することをユーザーが許可すると、自動的にパーミッションを受信します。そうではない場合、accessory に接続する前にアプリケーション内で明示的にパーミッションをリクエストしなければなりません。

アプリケーションですでに接続されている accessory を enumarate して、いずれかの1つと通信したい場合など、いくつかの状況で明示的にパーミッションを聞く必要があります。accessory と通信を試みる前に、accessory にアクセスするパーミッションをチェックしなければなりません。そうしないと、ユーザーが accessory へのアクセスを拒否した場合にランタイムエラーを受信するでしょう。

明示的にパーミッションを得るために、まず broadcast receiver を作成します。この receiver では requestPermission() を呼んだときに broadcast を取得する intent を listen するようにします。requestPermission() を呼ぶとユーザーに accessory に接続するかどうかのパーミッションを聞くダイアログが表示されます。
例えば、次のようにして broadcast receiver を作成します。

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


broadcast receiver を登録するには、これを 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);


accessory への接続パーミッションを尋ねるダイアログを表示するには、requestPermission() メソッドを呼びます:

UsbAccessory accessory;
...
mUsbManager.requestPermission(accessory, mPermissionIntent);


ユーザーがダイアログに返答すると、broadcast receiver は答えを表す boolean の EXTRA_PERMISSION_GRANTED extra を含む intent を受信します。accessory に接続するまえに、この extra が true になっているかチェックします。


Communicating with an accessory

UsbManager を使って file descripter を取得することで accessory と通信することができます。この file descripter によって、データを読み書きするための input / ouput stream をセットアップすることができます。stream は accessory の input / output bulk endpoint を表します。メイン UI スレッドをロックしないために、デバイスと accessory 間の通信のセットアップは別のスレッドで行うべきです。
例えば、次のようにしてセットアップを行います。

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() メソッドで、FileInputStreamFileOutputStream オブジェクトを使って accessory へ読み書きすることができます。FileInputStream オブジェクトで accessory からデータを読み出すとき、USB パケットデータを保持するのに十分な大きさのバッファーを確保するようにしてください。Android accessory プロトコルは、最大で 16385 bytes までのパケットバッファーをサポートします。そのため、簡単化のための選択肢として、常にこのサイズのバッファーを宣言することもできます。

注意: lower level では、パケットは USB full-speed accessory に対して 64 bytes, USB high-speed accessory に対して 512 bytes です。Android accessory プロトコルは、簡単化のためにこれら両方の速度のパケットを合わせて1つのロジカルなパケットに bundle します。

Android でスレッドを使うためのより詳しい情報は Processes and Threads にあります。


Terminating communication with an accessory

accessory との通信が完了した、もしくは accessory が取り外されたときには、close() を呼んで開いた file descriptor を閉じます。取り外されたイベントを察知するには、次のような broadcast receiver を作成します:

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


マニフェストではなく、アプリケーション内で broadcast receiver を作成することで、アプリケーションが起動している間だけ取り外しイベントを処理できるようになります。これにより、取り外しイベントが全てのアプリケーションに broadcast されることなく、現在起動しているアプリケーションにのみ送られます。


 

2011年5月14日土曜日

Android USB Host and Accessory

USB Host and Accessory

Android はさまざまな USB 周辺機器と、Android USB accessories (Android accessory プロトコルを実装したハードウェア)を次の2つのモードでサポートします。
 ・USB Accessory mode
 ・USB host mode


USB Accessory mode

USB Accessory mode では、外部の USB ハードウェアが USB Host として振る舞います。accessory の例として、ロボットコントローラ、ドッキングステーション、医療装置、音楽機器、キオスク端末、カードリーダーなどいろいろあります。これにより、ホスト機能がない Andorid-powered デバイスが USB ハードウェアとやりとりすることができます。Android USB accessory は Android-powered デバイスで動作するようにデザインされていなければなりません。つまり、Android accessory communication protocol が付いていなければなりません。


USB Host mode

USB Host mode では、Android-powered デバイスはホストとして振る舞います。デバイスの例としては、デジタルカメラ、キーボード、マウス、ゲームコントローラなどがあります。広い範囲のアプリケーションや環境向けにデザインされた USB デバイスは、デバイスと正しく通信できる Android アプリケーションとやりとりすることができます。

以下の図は2つのモードの違いを示したものです。Android-powered デバイスがホストモードの場合、USB host として振る舞い、バスに電力を供給します。Android-powered デバイスが USB accessory モードの場合、接続された USB ハードウェア(この場合は Android USB Accessory)が USB host として振る舞い、電力を供給します。。




USB accessory と host モードは、Android 3.1 (API level 12) もしくはそれ以降のプラットフォームで直接サポートされます。より広い範囲のデバイスをサポートするために、USB accessory モードは add-on library として Android 2.3.4 (API level 10) にもバックポートされています。デバイスメーカーはデバイスのシステムイメージに add-on library を含むかどうか選ぶことができます。

注意: USB host と accessory モードのサポートは、プラットフォームのレベルに関係なく最終的にはデバイスのハードウェアに依存します。<uses-feature> エレメントを使って、USB host と accessory をサポートするデバイス向けにフィルターすることができます。詳しくは USB accessoryhost ドキュメントを参照してください。

-----

Debugging considerations

USB accessory もしくは host 機能を使っているアプリケーションをデバッグする場合、USB ハードウェアを Android-powered デバイスに接続していることがほとんどでしょう。この場合、USB を介して Android-powered デバイスと adb 接続することができません。しかし、ネットワーク接続を介して adb にアクセスすることができます。ネットワークを介して adb を有効にするには、

1. Android-powered デバイスとコンピュータを USB を介して接続する

2. コマンドプロンプトで

    > adb tcpip 5555

  と入力する (/platform-tools/ にパスを通しておく)

3. コマンドプロンプトで

    > adb connect <device-ip-address>:5555

  と入力する

  adb logcat などのコマンドで、Android-powered device が接続されているかどうか確かめる

---
*#*#4636#*#* に電話をかけるとWifiの情報がとれます。[Wifi information] - [Wi-Fi Status] に移動して Refresh Status ボタンを押すと IPaddr に ip address がでます。
おおいしさん、ありがとうございます!
---

4. コマンドプロンプトで

    > adb usb

  と入力して、USB を listen するようにセットする