Android 开放配件协议 2.0

本文介绍了 Android 开放配件 (AOA) 协议自初始版本以来的变化,并对 AOA 1.0 文档进行补充。AOAv2 增加了以下功能:

  • 音频输出(在 Android 8.0 中已被弃用)。
  • 支持配件充当 Android 设备的一个或多个人机接口设备 (HID)。

提供给 Android 应用开发者的 Android SDK API 保持不变。

检测 AOAv2 支持

如需确定连接的 Android 设备是否支持配件和支持的协议版本,该配件必须发送 getProtocol() 命令并检查结果。仅支持 AOAv1 功能的 Android 设备必须返回 1 作为协议版本;支持 AOAv2 的额外功能的设备必须返回 2 作为协议版本。AOAv2 向后兼容 AOAv1,因此基于原始配件协议设计的配件将可以兼容更高版本的 Android 设备。

以下示例来自配件开发工具包 2011 源代码 (<adk-src>/adk1/board/AndroidAccessory/AndroidAccessory.cpp) 库,该示例演示了此协议的检查过程:

bool AndroidAccessory::switchDevice(byte addr)
{
    int protocol = getProtocol(addr);
    if (protocol >= 1) {
        Serial.print("device supports protocol 1 or higher\n");
    } else {
        Serial.print("could not read device protocol version\n");
        return false;
    }

    sendString(addr, ACCESSORY_STRING_MANUFACTURER, manufacturer);
    sendString(addr, ACCESSORY_STRING_MODEL, model);
    sendString(addr, ACCESSORY_STRING_DESCRIPTION, description);
    sendString(addr, ACCESSORY_STRING_VERSION, version);
    sendString(addr, ACCESSORY_STRING_URI, uri);
    sendString(addr, ACCESSORY_STRING_SERIAL, serial);

    usb.ctrlReq(addr, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_VENDOR |
                USB_SETUP_RECIPIENT_DEVICE, ACCESSORY_START, 0, 0, 0, 0, NULL);
    return true;
}

AOAv2 包含了新的 USB 产品 ID,以用于配件模式下每种可能的 USB 接口组合。

版本 产品 ID 通信 说明
AOAv1 0x2D00 配件 提供两个批量端点,用于与 Android 应用通信。
0x2D01 配件 + adb 在配件开发过程中用于调试。仅当用户在 Android 设备设置中启用了“USB 调试”时才可用。
AOAv2 0x2D02 音频 将音频从 Android 设备流式传输至配件。
0x2D03 音频 + adb
0x2D04 配件 + 音频
0x2D05 配件 + 音频 + adb

AOAv1 中使用的产品 ID(0x2D000x2D01)在 AOAv2 中仍然受支持。

音频支持

AOAv2 支持通过标准的 USB 音频类接口,将音频从 Android 设备输出到配件。该音频类接口支持比特率为 44100Khz 的 2 声道 16 位 PCM 音频(未来可能会添加其他音频模式)。

如需启用音频支持,配件必须发送新的 USB 控制请求:

**SET_AUDIO_MODE**
requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
request:        58
value:          0 for no audio (default),
                1 for 2 channel, 16-bit PCM at 44100 KHz
index:          0
data            none

此命令必须在发送用于进入配件模式的 ACCESSORY_START 命令之前发送。

HID 支持功能

AOAv2 允许配件向 Android 设备注册一个或多个 USB 人机接口设备 (HID)。这种方式反转了典型 USB HID 设备(如 USB 鼠标和键盘)的通信方向。通常情况下,HID 设备是连接到 USB 主机(即个人计算机)的外围设备,但在 AOA 中,USB 主机可以充当 USB 外围设备的一个或多个输入设备。

HID 支持功能是标准 HID 事件的代理;该实现不会对事件内容或类型做出假设,而是直接将其传递给输入系统,从而使 AOAv2 配件能够充当任何 HID 设备(如鼠标、键盘、游戏控制器等)。您可以利用 HID 支持功能来提供基本功能(如媒体扩充基座上的播放/暂停按钮),也可提供高级功能(如带有鼠标和完整 QWERTY 键盘的扩展坞)。

AOAv2 增加了新的 USB 控制请求,允许配件充当 Android 设备的一个或多个 HID 输入设备。HID 支持功能完全由端点 0 上的控制请求处理,因而不需要新的 USB 接口。这四个新控制请求为:

  • ACCESSORY_REGISTER_HID 向 Android 设备注册新的 HID 设备。配件提供 ID,以供其他三个调用用来识别该 HID 设备。在 USB 断开连接或配件发送 ACCESSORY_UNREGISTER_HID 以取消注册 HID 设备前,此 ID 将一直有效。
  • ACCESSORY_UNREGISTER_HID 取消注册之前通过 ACCESSORY_REGISTER_HID 注册的 HID 设备。
  • ACCESSORY_SET_HID_REPORT_DESC 将 HID 设备的报告描述符发送至 Android 设备。该请求用于描述 HID 设备的功能,且必须在向 Android 设备报告任何 HID 事件之前发送。如果报告描述符大于端点 0 的最大数据包大小,将会发送多个 ACCESSORY_SET_HID_REPORT_DESC 命令来传输整个描述符。
  • ACCESSORY_SEND_HID_EVENT 将配件中的输入事件发送至 Android 设备。

新控制请求的代码定义如下:

/* Control request for registering a HID device.
 * Upon registering, a unique ID is sent by the accessory in the
 * value parameter. This ID will be used for future commands for
 * the device
 *
 *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
 *  request:        ACCESSORY_REGISTER_HID_DEVICE
 *  value:          Accessory assigned ID for the HID device
 *  index:          total length of the HID report descriptor
 *  data            none
 */
#define ACCESSORY_REGISTER_HID         54

/* Control request for unregistering a HID device.
 *
 *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
 *  request:        ACCESSORY_REGISTER_HID
 *  value:          Accessory assigned ID for the HID device
 *  index:          0
 *  data            none
 */
#define ACCESSORY_UNREGISTER_HID         55

/* Control request for sending the HID report descriptor.
 * If the HID descriptor is longer than the endpoint zero max packet size,
 * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
 * commands. The data for the descriptor must be sent sequentially
 * if multiple packets are needed.
 *
 *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
 *  request:        ACCESSORY_SET_HID_REPORT_DESC
 *  value:          Accessory assigned ID for the HID device
 *  index:          offset of data in descriptor
 *                      (needed when HID descriptor is too big for one packet)
 *  data            the HID report descriptor
 */
#define ACCESSORY_SET_HID_REPORT_DESC         56

/* Control request for sending HID events.
 *
 *  requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
 *  request:        ACCESSORY_SEND_HID_EVENT
 *  value:          Accessory assigned ID for the HID device
 *  index:          0
 *  data            the HID report for the event
 */
#define ACCESSORY_SEND_HID_EVENT         57

与 AOAv1 的互操作性

原始协议 (AOAv1) 支持 Android 应用通过 USB 直接与 USB 主机(配件)通信。AOAv2 在提供此支持的基础上增加了新的功能,使配件本身就能与 Android 操作系统(特别是音频和输入系统)通信。除了原有的功能集外,AOAv2 还可以构建使用新的音频和 HID 支持功能的配件。在保留已有功能的同时,让您畅享新功能。

在不使用 Android 应用的情况下连接 AOAv2

您可以设计这样一种配件,它可以使用音频和 HID 支持功能,但不与 Android 设备上的应用通信,例如音频基座。对于这些配件,用户无需接收对话框提示(告知他们发现了新连接的配件并请他们将配件与可与之通信的 Android 应用关联)。

如需在配件连接后阻止系统显示此类对话框,配件可选择不将制造商和型号名称发送至 Android 设备。当这些字符串未提供给 Android 设备时:

  • 系统不会尝试查找可与配件通信的应用。
  • 当设备进入配件模式后,配件 USB 接口不会出现在 Android 设备的 USB 配置中。