Android Open Accessory 2.0

This document describes changes in the Android Open Accessory (AOA) protocol since its initial release and supplements AOA 1.0 documentation. AOAv2 adds the following features:

  • Audio output (deprecated in Android 8.0).
  • Support for the accessory acting as one or more human interface devices (HIDs) to the Android device.

Android SDK APIs available to Android app developers are unchanged.

Detect AOAv2 support

To determine if a connected Android device supports accessories and the supported protocol version, an accessory must send a getProtocol() command and check the result. Android devices that support only the features in AOAv1 must return 1 as the protocol version; devices that support the additional feautres in AOAv2 must return 2 as the protocol version. AOAv2 is backward-compatible with AOAv1, so accessories designed for the original accessory protocol continue to work with newer Android devices.

The following example from the Accessory Development Kit 2011 source code (<adk-src>/adk1/board/AndroidAccessory/AndroidAccessory.cpp) library demonstrates this protocol check:

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 includes new USB product IDs for each combination of USB interfaces available in accessory mode:

Version Product ID Communication Description
AOAv1 0x2D00 accessory Provides two bulk endpoints for communicating with an Android app.
0x2D01 accessory + adb For debugging purposes during accessory development. Available only if the user has enabled USB Debugging in the Android device settings.
AOAv2 0x2D02 audio For streaming audio from an Android device to an accessory.
0x2D03 audio + adb
0x2D04 accessory + audio
0x2D05 accessory + audio + adb

Product IDs used in AOAv1 (0x2D00 and 0x2D01) continue to be supported in AOAv2.

Audio support

AOAv2 includes support for audio output from an Android device to an accessory via a standard USB audio class interface capable of 2 channel, 16-bit PCM audio with a bit rate of 44100 Khz (additional audio modes may be added in the future).

To enable audio support, the accessory must send a new USB control request:

**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

This command must be sent before sending the ACCESSORY_START command for entering accessory mode.

HID support

AOAv2 allows accessories to register one or more USB Human Interface Devices (HID) with an Android device. This approach reverses the direction of communication for typical USB HID devices such as USB mice and keyboards. Normally, the HID device is a peripheral connected to a USB host (i.e. a personal computer), but in AOA the USB host can act as one or more input devices to a USB peripheral.

HID support is a proxy for standard HID events; the implementation makes no assumptions about the content or type of events and simply passes it through to the input system, enabling an AOAv2 accessory to act as any HID device (mouse, keyboard, game controller, etc.). You can use HID support to provide basic functionality, such as a play/pause button on a media dock, or for advanced functionality such as a docking station with a mouse and full QWERTY keyboard.

AOAv2 adds new USB control requests that allow the accessory to act as one or more HID input devices to the Android device. HID support is handled entirely through control requests on endpoint zero, so no new USB interface is needed. The four new control requests are:

  • ACCESSORY_REGISTER_HID registers a new HID device with the Android device. The accessory provides an ID used to identify the HID device for the other three calls. This ID is valid until USB disconnects or until the accessory sends ACCESSORY_UNREGISTER_HID to unregister the HID device.
  • ACCESSORY_UNREGISTER_HID unregisters a HID device previously registered with ACCESSORY_REGISTER_HID.
  • ACCESSORY_SET_HID_REPORT_DESC sends a report descriptor for a HID device to the Android device. This request is used to describe the capabilities of the HID device and must be sent before reporting any HID events to the Android device. If the report descriptor is larger than the maximum packet size for endpoint zero, multiple ACCESSORY_SET_HID_REPORT_DESC commands are sent to transfer the entire descriptor.
  • ACCESSORY_SEND_HID_EVENT sends input events from the accessory to the Android device.

The code definitions for the new control requests are:

/* 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

Interoperability with AOAv1

The original protocol (AOAv1) provides support for an Android app to communicate directly with a USB host (accessory) over USB. AOAv2 continues this support and adds new features to allow the accessory to communicate with the Android operating system itself (specifically the audio and input systems). The design of AOAv2 makes it possible to build an accessory that uses the new audio and HID support in addition to the original feature set. Simply use the new features along with the original features.

Connect AOAv2 without an Android app

You can design an accessory (such as an audio dock) that uses audio and HID support but doesn't communicate with an app on the Android device. For these accessories, users don't need to receive dialog prompts for finding and associating the newly attached accessory with an Android app that can communicate with it.

To suppress such dialogs after an accessory connects, the accessory can choose not to send the manufacturer and model names to the Android device. When these strings aren't provided to the Android device:

  • The system doesn't attempt to find an app to communicate with the accessory.
  • The accessory USB interface isn't present in the Android device USB configuration after the device enters accessory mode.