Android Open Accessory プロトコル 1.0

Android USB アクセサリは、Android Open Accessory(AOA)プロトコルに準拠する必要があります。AOA プロトコルは、アクセサリによる Android 搭載デバイスとの通信の検出方法と設定方法を定義したものです。アクセサリは次の手順に従う必要があります。

  1. デバイスとの接続を待ち、検出します。
  2. デバイスがアクセサリ モードをサポートしているか判別します。
  3. 必要に応じて、デバイスをアクセサリ モードで起動させます。
  4. デバイスが AOA をサポートしていれば、デバイスとの通信を確立します。

以降のセクションでは、これらの手順の実装方法について説明します。

デバイス接続を待機して検出する

アクセサリは、Android 搭載デバイスとの接続を継続的に確認する必要があります。デバイスが接続されたら、デバイスがアクセサリ モードをサポートしているかどうかを判別します。

アクセサリ モードのサポートを判別する

Android 搭載デバイスが接続されると、次の 3 つの状態のいずれかになります。

  • Android アクセサリ モードをサポートしており、アクセサリ モードになっている。
  • Android アクセサリ モードをサポートしているが、アクセサリ モードにはなっていない。
  • Android アクセサリ モードをサポートしていない。

アクセサリは、最初の接続時に、接続されたデバイスの USB デバイス記述子に含まれているバージョン、ベンダー ID、プロダクト ID を確認します。ベンダー ID は Google の ID(0x18D1)と一致する必要があります。デバイスがすでにアクセサリ モードになっている場合、プロダクト ID は 0x2D00 または 0x2D01 でなければなりません。アクセサリは独自の通信プロトコルを使用して、一括転送エンドポイント経由でデバイスとの通信を確立できます(デバイスをアクセサリ モードで起動する必要はありません)。

注: 0x2D00 は、アクセサリ モードをサポートする Android 搭載デバイス用に予約された ID です。0x2D01 は、アクセサリ モードと Android Debug Bridge(ADB)プロトコルをサポートするデバイス用に予約された ID です。このプロトコルは、ADB 用の 2 つの一括エンドポイントを持つ第 2 のインターフェースを公開します。パソコンでアクセサリをシミュレートする場合は、これらのエンドポイントを使用してアクセサリ アプリをデバッグできます。一般的に、アクセサリがデバイス上で ADB へのパススルーを実装していない限り、このインターフェースは使用しません。

USB デバイス記述子のバージョン、ベンダー ID、プロダクト ID が予想される値と一致しない場合、デバイスが Android アクセサリ モードをサポートしているかどうかをアクセサリが判別することはできません。アクセサリは、デバイスのサポートを判別するためにデバイスをアクセサリ モードで起動しようと試みます(詳細は下記を参照)。

重要なポイント: USB アクセサリは、最初の handshake 時にヘッダーを送信する必要があります。ヘッダーには、メーカー、モデル、バージョンが含まれています。バージョンは省略可能なフィールドですが、バージョンのみで一致する Android アプリをインストールしても、アクセサリがバージョンを送信しない場合、Android 10 以前を搭載した Android デバイスは、システム プロセスでスローされている例外により再起動します。

アクセサリ モードで起動を試みる

バージョン、ベンダー ID、プロダクト ID がアクセサリ モードの Android 搭載デバイスに対応していない場合、デバイスがアクセサリ モードをサポートしている(ただし、そのモードになっていない)のかサポートしていないのかをアクセサリが判別することはできません。これは、アクセサリ モードをサポートする(ただし、そのモードになっていない)デバイスが最初に報告するのはデバイス メーカーのベンダー ID とプロダクト ID であり、AOA のベンダー ID とプロダクト ID ではないためです。

アクセサリは、デバイスがアクセサリ モードをサポートしているかどうかを判別するため、デバイスをアクセサリ モードで起動しようと試みます。

  1. デバイスが Android アクセサリ プロトコルをサポートしているかどうかを判別するには、コントロール リクエスト 51(GET プロトコル)を送信します。デバイスがこのプロトコルをサポートしていれば、サポートしているプロトコル バージョンを表すゼロ以外の数値を返します。コントロール リクエストはエンドポイント 0 にあり、次の特性を持ちます。
    requestType:    USB_DIR_IN | USB_TYPE_VENDOR
    request:        51
    value:          0
    index:          0
    data:           protocol version number (16 bits little endian sent from the
                    device to the accessory)
    
  2. デバイスからサポートされているプロトコル バージョンが返された場合は、識別文字列の情報を含むコントロール リクエストをデバイスに送信します。この情報により、デバイスはアクセサリに適したアプリを決定できます(適切なアプリが存在しない場合は、URL をユーザーに提示します)。コントロール リクエストは各文字列 ID ごとにエンドポイント 0 にあり、次の特性を持ちます。
    requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
    request:        52
    value:          0
    index:          string ID
    data            zero terminated UTF8 string sent from accessory to device
    

    次の文字列 ID がサポートされます。各文字列の最大サイズは 256 バイトです(\0 によりゼロで終わる必要があります)。

    manufacturer name:  0
    model name:         1
    description:        2
    version:            3
    URI:                4
    serial number:      5
    
  3. コントロール リクエストを送信して、アクセサリ モードで起動するようにデバイスに要求します。コントロール リクエストはエンドポイント 0 にあり、次の特性を持ちます。
    requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
    request:        53
    value:          0
    index:          0
    data:           none
    

以上のステップを完了した後、アクセサリは、接続された USB デバイスがアクセサリ モードでバスに再登録され、接続されたデバイスとして再び列挙されるのを待ちます。このアルゴリズムでは、ベンダー ID とプロダクト ID を確認することでアクセサリ モードのサポートを判別しています。デバイスがアクセサリ モードへの切り替えに成功した場合、これらの ID は正しい(デバイス メーカーの ID ではなく、Google のベンダー ID とプロダクト ID に対応している)はずです。ID とバージョンが正しければ、アクセサリはデバイスとの通信を確立するステップに進みます。

注: 現在、AOA は AOA と MTP の同時接続をサポートしていません。AOA から MTP に切り替えるには、USB デバイスを物理的に取り外すか電源を切断してから、MTP を使用して再接続します。

いずれかのステップが失敗した場合、アクセサリはデバイスが Android アクセサリ モードをサポートしていないと判断し、別のデバイスが接続されるのを待ちます。

デバイスとの通信を確立する

アクセサリは、アクセサリ モードの Android 搭載デバイスを検出すると、デバイスのインターフェース記述子とエンドポイント記述子をクエリして、デバイスと通信するための一括エンドポイントを取得します。

インターフェースと一括エンドポイントの数は、次に示すように、Android 搭載デバイスのプロダクト ID によって異なります。

  • プロダクト ID が 0x2D00 の場合、インターフェースは 1 つで、入力および出力通信用に 2 つの一括エンドポイントがあります。
  • プロダクト ID が 0x2D01 の場合、インターフェースは 2 つで、入力および出力通信用にそれぞれ 2 つの一括エンドポイントがあります。第 1 のインターフェースは標準の通信を処理し、第 2 のインターフェースは ADB 通信を処理します。インターフェースを使用するには、第 1 の一括入力 / 出力エンドポイントを見つけて、SET_CONFIGURATION0x09)デバイス リクエストによりデバイス設定の値を 1 に設定し、エンドポイントを使用して通信を行います。