IOIO Over OpenAccessory
Clone this wiki locally
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
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
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.
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.accessoryin the "name" box on the right, and
falsein 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_ATTACHEDin 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_ATTACHEDand 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
resdirectory of your project, create a directory called
xml. Create a file called
accessory_filter.xmlin this directory. Edit it to include the contents below.
<?xml version="1.0" encoding="utf-8"?> <resources> <usb-accessory model="IOIO" /> </resources>
<?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.