USB ホストの概要

Android 搭載デバイスを USB ホストモードに設定すると、USB ホストとして動作し、バスに電力を供給します。 接続されている USB デバイスを列挙します。USB ホストモードは Android 3.1 以降でサポートされています。

API の概要

まず、使用する必要のあるクラスを理解することが重要です。「 次の表に、android.hardware.usb パッケージ内の USB ホスト API を示します。

表 1. USB ホスト API

クラス 説明
UsbManager 接続された USB デバイスの列挙と通信を可能にします。
UsbDevice 接続されている USB デバイスを表し、デバイスの識別にアクセスするメソッドが含まれます インターフェース、エンドポイントです。
UsbInterface USB デバイスのインターフェースを表し、 ダウンロードしますデバイスは、通信するインターフェースを 1 つ以上持つことができます。
UsbEndpoint このインターフェースの通信チャネルである、インターフェースのエンドポイントを表します。「 インターフェースには 1 つ以上のエンドポイントを含めることができ、通常は、 双方向通信を行えます。
UsbDeviceConnection エンドポイントのデータを転送する、デバイスへの接続を表します。このクラス を使用すると、同期的または非同期的にデータを送受信できます。
UsbRequest UsbDeviceConnection を通じてデバイスと通信する非同期リクエストを表します。
UsbConstants Linux の linux/usb/ch9.h 定義に対応する USB 定数を定義します。 提供します。

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

Android マニフェストの要件

次のリストに、事前にアプリケーションのマニフェスト ファイルに追加する必要があるものを 操作する方法を紹介します。

  • すべての Android 搭載デバイスで USB ホスト API のサポートを 保証しているわけではないため アプリが使用することを宣言する <uses-feature> 要素が含まれている android.hardware.usb.host 機能を使用します。
  • アプリの最小 SDK を API レベル 12 以上に設定します。USB ホスト API は、 存在していました。
  • 接続された USB デバイスがアプリケーションに通知されるようにするには、 次の要素の <intent-filter> 要素と <meta-data> 要素のペア android.hardware.usb.action.USB_DEVICE_ATTACHED インテントをメイン アクティビティで使用できます。「 <meta-data> 要素は、宣言する外部 XML リソース ファイルを指します。 対象デバイスに関する識別情報を指定します。

    XML リソース ファイルで、USB の <usb-device> 要素を宣言します。 選択します。次のリストは、Terraform の <usb-device>。通常はベンダーとプロダクト ID を使用して クラス、サブクラス、プロトコルを使用してグループをフィルタできます。 大容量ストレージ デバイスやデジタルカメラなどの USB デバイスの「なし」または すべての属性が含まれます。属性を指定しないと、すべての USB デバイスに一致するため、次のように指定します。 アプリケーションで必要な場合は、次の手順を実施します。

    • vendor-id
    • product-id
    • class
    • subclass
    • 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 です。これにより、指定した フィルタする必要があります。

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

<resources>
    <usb-device vendor-id="1234" product-id="5678" class="255" subclass="66" protocol="1" />
</resources>

デバイスと連携する

Android 搭載デバイスにユーザーが USB デバイスを接続すると、Android システムが アプリが接続済みデバイスに関心があるかどうか。そのような場合は デバイスと通信することもできます。そのためには、アプリで次の処理を行う必要があります。

  1. インテント フィルタを使用して、接続中の USB デバイスを検出し、ユーザーがいるときに通知を受け取る 接続するか、すでに接続されている USB デバイスを列挙します。
  2. USB デバイスへの接続を許可するようユーザーに求めます(まだ許可を取得していない場合)。
  3. 適切なインターフェースでデータの読み書きを行い、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>

次の例は、対応するリソース ファイルを宣言する方法を示しています。 関心のある USB デバイス:

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

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

アクティビティでは、以下を表す UsbDevice を取得できます。 アタッチしたデバイスをインテントから取り出せます。

Kotlin

val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

Java

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

デバイスを列挙する

現在接続されている USB デバイスをすべて検査する必要がある場合 アプリケーションの実行中に、バス上のデバイスを列挙できます。getDeviceList() メソッドを使用して、すべてのハッシュマップを取得する 接続されています。ハッシュマップは、USB デバイスの名前がキーになります。 マップからデバイスを取得します。

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager
...
val deviceList = manager.getDeviceList()
val device = deviceList.get("deviceName")

Java

UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
...
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
UsbDevice device = deviceList.get("deviceName");

必要に応じて、ハッシュマップからイテレータを取得して、各デバイスを処理することもできます。 を 1 つにまとめます。

Kotlin

val manager = getSystemService(Context.USB_SERVICE) as UsbManager
..
val deviceList: HashMap<String, UsbDevice> = manager.deviceList
deviceList.values.forEach { device ->
    // your code
}

Java

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 デバイスを列挙します。 1 です。デバイスと通信する前に、デバイスへのアクセス権限があるかを確認する必要があります。条件 それ以外の場合、ユーザーがデバイスへのアクセス権限を拒否した場合、ランタイム エラーが発生します。

明示的に権限を取得するには、まずブロードキャスト レシーバを作成します。このレシーバは requestPermission() を呼び出したときにブロードキャストされるインテントです。requestPermission() を呼び出すと、ダイアログが表示され、 ユーザーがデバイスに接続する許可を求めているとき。次のサンプルコードは、 ブロードキャスト レシーバを作成します。

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"

private val usbReceiver = object : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (ACTION_USB_PERMISSION == intent.action) {
            synchronized(this) {
                val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)

                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                    device?.apply {
                        // call method to set up device communication
                    }
                } else {
                    Log.d(TAG, "permission denied for device $device")
                }
            }
        }
    }
}

Java

private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
private final BroadcastReceiver usbReceiver = 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);
                }
            }
        }
    }
};

ブロードキャスト レシーバを登録するには、以下を onCreate() メソッドの アクティビティ:

Kotlin

private const val ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION"
...
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
...
permissionIntent = PendingIntent.getBroadcast(this, 0,
                  Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE)
val filter = IntentFilter(ACTION_USB_PERMISSION)
registerReceiver(usbReceiver, filter)

Java

UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
private static final String ACTION_USB_PERMISSION =
    "com.android.example.USB_PERMISSION";
...
permissionIntent = PendingIntent.getBroadcast(this, 0,
              new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(usbReceiver, filter);

ユーザーにデバイスへの接続の権限を求めるダイアログを表示するには、次のように requestPermission() メソッドを呼び出します。

Kotlin

lateinit var device: UsbDevice
...
usbManager.requestPermission(device, permissionIntent)

Java

UsbDevice device;
...
usbManager.requestPermission(device, permissionIntent);

ユーザーがダイアログに返信すると、ブロードキャスト レシーバは EXTRA_PERMISSION_GRANTED エクストラ(ブール値) 回答を表現します。接続する前に、このエクストラ値が true であるかどうかを ダウンロードします

デバイスと通信する

USB デバイスとの通信は、同期または非同期のいずれかになります。いずれの場合も、 すべてのデータ転送を実行する新しいスレッドを作成する必要があるため、 UI スレッド。デバイスとの通信を適切に設定するには、 UsbInterfaceUsbEndpoint の このエンドポイントで通信するデバイスを指定し、UsbDeviceConnection を使用してリクエストを送信します。通常、コードは次のようになります。

  • UsbDevice オブジェクトの属性(商品 ID など)を確認します。 ベンダー ID、またはデバイス クラスを使用して、 ダウンロードします
  • デバイスと通信する必要がある場合、 UsbInterface を指定します。 そのインターフェースの適切な UsbEndpoint。インターフェースには 1 つの エンドポイントがあり、通常は双方向通信のための入出力エンドポイントが 通信に使用できます。
  • 正しいエンドポイントが見つかったら、UsbDeviceConnection を開きます。 そのエンドポイントでホストされます。
  • そのエンドポイントで送信するデータを bulkTransfer() または controlTransfer() メソッドで提供します。すべきこと メイン UI スレッドがブロックされないように、このステップを別のスレッドで実行してください。詳細 Android でのスレッドの使用について詳しくは、プロセスと スレッドをご覧ください。

同期データ転送の実行方法を、次のコード スニペットで示します。コード 通信する適切なインターフェースとエンドポイントを正しく見つけるためのロジックが増加する必要がある メイン UI スレッドとは別のスレッドでデータの転送も行う必要があります。

Kotlin

private lateinit var bytes: ByteArray
private val TIMEOUT = 0
private val forceClaim = true

...

device?.getInterface(0)?.also { intf ->
    intf.getEndpoint(0)?.also { endpoint ->
        usbManager.openDevice(device)?.apply {
            claimInterface(intf, forceClaim)
            bulkTransfer(endpoint, bytes, bytes.size, TIMEOUT) //do in another thread
        }
    }
}

Java

private Byte[] bytes;
private static int TIMEOUT = 0;
private boolean forceClaim = true;

...

UsbInterface intf = device.getInterface(0);
UsbEndpoint endpoint = intf.getEndpoint(0);
UsbDeviceConnection connection = usbManager.openDevice(device);
connection.claimInterface(intf, forceClaim);
connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread

非同期でデータを送信するには、UsbRequest クラスを使用して非同期リクエストを initialize し、queue を送信し、その結果を待ちます。 requestWait() で。

デバイスとの通信の終了

デバイスとの通信が終了した場合、またはデバイスが取り外された場合は、次の方法で UsbInterfaceUsbDeviceConnection を閉じます。 releaseInterface() を呼び出し、 close()。接続解除されたイベントをリッスンするには 次のようなブロードキャスト レシーバを作成します。

Kotlin

var usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        if (UsbManager.ACTION_USB_DEVICE_DETACHED == intent.action) {
            val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
            device?.apply {
                // call your method that cleans up and closes communication with the device
            }
        }
    }
}

Java

BroadcastReceiver usbReceiver = 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
            }
        }
    }
};

マニフェストではなくアプリ内にブロードキャスト レシーバを作成すると、 切断されたイベントのみを処理するようにできます。これにより、分離されたイベントは すべてのアプリケーションにブロードキャストするのではなく、現在実行中のアプリケーションにのみ送信する場合。