Skip to content

IOIO Over OpenAccessory

Ytai Ben-Tsvi edited this page Apr 24, 2014 · 3 revisions

IOIO Over OpenAccessory

Android OpenAccessory (AOA) is a protocol developed by Google (introduced on May 2011), which enables a hack-free connection of peripherals to Android devices. The protocol is supported in Android 2.3.4 and higher, and on a limited number of devices. Android 4.x devices generally support AOA.

Naturally, it makes sense for IOIO to communicate with the Android device using this protocol whenever it is available, avoiding the need for running the Android device with USB debugging enabled. In addition, the OpenAccessory connection also has some performance gains over ADB.

Behavior of an OpenAccessory-Enabled IOIO

The OpenAccessory-enabled firmware and software support OpenAccessory in addition to ADB. Both will know how to "do the right thing" and use ADB whenever appropriate.

Both ADB and OpenAccessory are based on a USB connection. The IOIO firmware is built in such a way that if an Android device is connected, on which ADB is enabled, ADB will be used. If OpenAccessory is supported, OpenAccessory will be used. If both are available, ADB wins, and the Android-IOIO communication will use ADB. So you should be aware that in order to use OpenAccessory you should switch USB debugging off.

As you'll see below, your Android application also needs to be built in a certain way in order to be able to use OpenAccessory. Luckily, changing an existing IOIO application to use OpenAccessory a technical and very simple process.

Another important aspect is that your application has to be based on IOIOActivity, IOIOService, or IOIOAndroidApplicationHelper for this to work. These classes take care of all the gory details (and believe me, they are gory) of communicating with an Android accessory.

Advantages of Using OpenAccessory over ADB

Using OpenAccessory gives some nice improvements in comparison to ADB:

  • One-way average latency improves from ~4ms to ~1ms.
  • Jitter (i.e. variance in latency) is much smaller.
  • Effective throughput increases from ~300KB/s to ~600KB/s.
  • You can have the connecting of the IOIO automatically trigger your app of choice.
  • IOIO is not using ADB. So you can leave it off, or use ADB over WiFi and debug your app while it is connected to the IOIO (may require rooting on certain Android devices).

Downloading the Required Software

Simply use the software / firmware with versions 3.21 or greater, from the Downloads page. You may use the IOIO Manager Application to upgrade the firmware. Note that this firmware requires a V3.x bootloader, so very old IOIO's that haven't had their bootloader upgraded may need a bootloader upgrade in order to install this firmware.

Notice that the examples shipped with the software bundle have OpenAccessory support, so you can use them as reference or just modify them to your needs.

Adding OpenAccessory Support to Your Application

IOIOLibAccessory

In the software zip file, you'll find the IOIOLibAccessory library.

  • Import it to your Eclipse workspace (File > Import > Existing Projects Into Workspace).
  • Link it into your application by right-clicking the application's project > Properties > Android > click "Add..." in the library pane and choose the IOIOLibAccessory project.
  • The IOIOLibAccessory library itself must be built against an Android target that supports OpenAccessory (e.g. API-10 + Google APIs). Otherwise, it won't compile. However, your application can be built against any Android API, 7 or higher. It will use OpenAccessory whenever it is available, and gracefully avoid it, if the runtime environment doesn't support it.

AndroidManifest.xml Requirements

Some changes are required to the AndroidManifest.xml file of your application in order to utilize OpenAccessory. This file is found under the root directory of your project. Double-click it to edit inside Eclipse, using a specialized editor.

  • If you prefer manually editing the xml file, click on the tab called "AndroidManifest.xml" at the bottom of the editor pane, and see an example file below.
  • In the Manifest tab, "Manifest Extras" pane: if you don't have a "Uses Sdk" node, add one. Set "Min SDK Version" on the right to 7 or later. Setting it to a smaller number will cause the application to fail in run-time (see compatibility notes below).
  • In the application tab, "application nodes" pane: "Add..." > "Create a new element..." > Users Library > Enter com.android.future.usb.accessory in the "name" box on the right, and false in the "required" box (to enable graceful degradation). This tells Android that your application would like to use the OpenAccessory system library, if it's available.
  • In the application tab, "application nodes" pane: select activity > "Add..." > Intent Filter > "Add..." again > Action > Enter android.hardware.usb.action.USB_ACCESSORY_ATTACHED in the "name" box on the right. This tells Android that your application would like to register itself as one that can work with an accessory.
  • In the application tab, "application nodes" pane: select your activity > on the right, find the "Launch mode" setting (might need to scroll down) and set it to singleTask. This will make sure that no two instances of your application will be running at the same time (which would cause lots of problems with regards to communicating with the IOIO).
  • In the application tab, "application nodes" pane: select your activity > "Add..." > Meta Data > set Name to android.hardware.usb.action.USB_ACCESSORY_ATTACHED and Resource to @xml/accessory_filter. This tells Android that your application works with a specific kind of accessories, as described in an XML resource file.
  • Under the res directory of your project, create a directory called xml. Create a file called accessory_filter.xml in this directory. Edit it to include the contents below.

The accessory_filter.xml file:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <usb-accessory model="IOIO" />
 </resources>

An example AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
      package="ioio.examples.hello"
      a:versionCode="1"
      a:versionName="1.0">
    <uses-sdk a:minSdkVersion="7" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
   <application a:icon="@drawable/icon" a:label="@string/app_name">
        <uses-library a:name="com.android.future.usb.accessory" a:required="false" />
        <activity a:name="MainActivity"
                  a:label="@string/app_name" a:launchMode="singleTask">
            <intent-filter>
                <action a:name="android.intent.action.MAIN" />
                <category a:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action a:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
            </intent-filter>
                <meta-data a:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
                                  a:resource="@xml/accessory_filter" />
        </activity>
    </application>
</manifest>

Compatibility of Application With Older Android Versions

Ideally, you'd want a single .apk file that would be compatible with any Android version, possibly taking advantage of later features, if they exist. The IOIO libraries are all built with that property in mind. Unfortunately, the Android libraries aren't...

If you look above, you'll see that we declared that our application would like to use the com.android.future.usb.accessory library. It also mentions that it doesn't require it. So far so good. But the required attribute itself was only added in API-7 (Android 2.1). So earlier versions of Android won't let your application run as result of the library not being available, and thus there is no known way of having a single .apk that will work both with OpenAccessory AND with API < 7. If anyone knows of a workaround, please report it. Converting your application to work on API < 7 (without OpenAccessory, of course), is a simple matter of removing the <uses-library> element, changing minSdkVersion to 3 and rebuilding.