Usage¶
ADK 2012 is the latest version that can be used during accessories development. This library works as a wrapper of ADK capabilities so your application development will be smoothest. If you want to see how ADK 2012 works, follow the official documentation.
Note
Even if ADK is supported since Android API level 10, I will only target API level 12 in this library as stated in cutting down backward support issue.
Installing the library¶
This library is available in MavenCentral and JCenter repositories. Adding the library dependency is pretty easy and you can configure your Gradle or Maven dependency file as follows:
Gradle¶
dependencies {
compile 'me.palazzetti:adktoolkit:0.3.0'
}
Maven¶
<dependency>
<groupId>me.palazzetti</groupId>
<artifactId>adktoolkit</artifactId>
<version>0.3.0</version>
<type>aar</type>
</dependency>
Eclipse users¶
All published libraries in MavenCentral or JCenter are in AAR format. Unfortunately, Eclipse seems to have a bug and AAR import will not work as expected. I’ve created an assemble task in the gradle build script to produce a JAR library that you can easily import manually in your project. The pre-assembled libraries are available in the repository release section.
Note
If you are using Eclipse with ADT, be aware that Android Studio is now the official IDE for Android, so it’s a good idea to migrate your projects to Android Studio. For help moving projects, see Migrating to Android Studio. Despite that, ADKToolkit library will continue to support JAR library releases.
Configuring the Android application¶
Android Manifest¶
Create res/xml/usb_accessory_filter.xml
configuration file to identify your accessory:
<resources>
<usb-accessory
version="0.1.0"
model="External-Droid"
manufacturer="Example, Inc."/>
</resources>
Declare in your manifest that your application requires USB accessory support:
<manifest>
<uses-feature android:name="android.hardware.usb.accessory" android:required="true"/>
<!-- ... -->
</manifest>
Then add in your activity block this ADK intent filter:
<manifest ...>
<application ...>
<activity ...>
<!-- ... -->
<!-- Adk Intent Filter -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/usb_accessory_filter"/>
</activity>
</application>
</manifest>
Starting the ADK listener¶
To use this library, initialize the AdkManager
in your Activity
onCreate()
callback
like you can see in the following snippet:
private AdkManager mAdkManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdkManager = new AdkManager(this);
}
If you need to register a BroadcastReceiver
to catch UsbManager.ACTION_USB_ACCESSORY_DETACHED
action, you can use the library default implementations as follows:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAdkManager = new AdkManager(this);
registerReceiver(mAdkManager.getUsbReceiver(), mAdkManager.getDetachedFilter());
}
When you initialize an AdkManager
, it just create a connection object between your device and
your accessory. You need to start/stop AOA communication when you open/close your activity. Add
the following calls in your onResume()
and onPause()
callbacks to open and close ADK
communication, when your Activity is resumed or paused:
@Override
protected void onResume() {
super.onResume();
mAdkManager.open();
}
@Override
protected void onPause() {
super.onPause();
mAdkManager.close();
}
Warning
Because of an internal ADK bug that is still not fixed, it’s not possible to open the ADK
again when the channel has been closed. This means that if you need to use the ADK between
activities, you should not call the close()
method otherwise the only way to open the
communication again is to restart your hardware accessory.
Using the toolkit¶
The ADKToolkit library exposes an interface to write and read bytes in/from the internal ADK buffer. If you need to send some values to your accessory, you can use the following methods within your application code:
byte[] byteArray = {4, 2};
byte byteValue = 42;
int intValue = 42
float floatValue = 42.0f;
String stringValue = "Answer to The Ultimate Question of Life, the Universe, and Everything"
adkManager.write(byteArray);
adkManager.write(byteValue);
adkManager.write(intValue);
adkManager.write(floatValue);
adkManager.write(stringValue);
On the other hand if you need to read a value from your accessory (for instance, a sensor value),
you can use the read()
method that returns an AdkMessage
instance. This class, wraps the
returned byte[]
array from the buffer and exposes an API to parse retrieved value. The following
is an example how to read accessory data from your Android application:
AdkMessage response = mAdkManager.read();
Then you can call the following methods according to sent data:
response.getBytes()
: returns the raw bytes array so you can manipulate it on your ownresponse.getString()
: returns a string applying a(char)
typecasting for each byteresponse.getByte()
: returns the first byte of the bytes array bufferresponse.getFloat()
: expects that the content of the bytes array buffer is a string; it calls thegetString()
method and tries to parse the string in a float valueresponse.getInt()
: expects that the content of the bytes array buffer is a string; it calls thegetString()
method and tries to parse the string in an integer valueresponse.isEmpty()
: returnstrue
if the received buffer is empty or not initialized
If for any reasons the parsing causes an exceptions, it will be caught from the AdkResponse’s
methods and the returned value will be null
.
Note
The read()
method could be a long-running task, in particular if you want to read
continuously data from a your accessory. In this case, call the read()
method outside your
main thread otherwise it will cause the Application Not Responding (ANR) error. A good approach
is to use an IntentService, an AsyncTask, or a Runnable implementation together
with an ExecutorService.