As said by Google CEO Eric Schmidt two month ago, the operating system Android 2.3 includes support for near field communication. But, at least in terms of the API and the sample code they supply, this version only includes tag reading capability. However, the PN544 NFC chip inside the Nexus S supports read and write operations so, at the hardware level, all the functionality you need to support a full range of NFC services is in the handset. At the software level, there will be updates to the SDK rolled out on a phased basis that will enable developers to write NFC applications for mobile payments, p2p and other applications on Android Gingerbread devices.
We’ve been analyzing the Android kernel source code and we found a lot of “@hide” tags in the NFC java classes. These are in:
packages/apps/Nfc (the android service running in the background)
packages/apps/Tag (the application used to read and store tags)
And the hardware abstraction layer from NXP is in:
Let’s see an example, the publised API for the class NCFAdapter has only two public methods:
getDefaultAdapter(): Get a handle to the default NFC Adapter on this Android device.
isEnabled(): Return true if this NFC Adapter has any features enabled.
But also has this public methods with the @hide tag:
enable(): Enable NFC hardware.
disable(): Disable NFC hardware.
createRawTagConnection(): Create a raw tag connection to the default Target.
createNdefTagConnection(): Create an NDEF tag connection to the default Target .
Interesting, isn’t it?
The “@hide” tag is used to mark public APIs that are not to be exported in the SDK. This is used by the Android team to have APIs accessible across packages without having them available to applications. APIs marked with @hide are considered private to the Android platform and can change at any time, so you cannot rely on them. So, with this in mind, we can confirm that there is some extended NFC functionality hidden in Android 2.3 that can be accessed, i.e. with reflection techniques. Let’s see how we can do this.
To write tags we’ll use the write() method from the INfcTag interface, so lets dive from NfcAdapter to the INfcTag. First we need a handle to the NFC adapter within the Nexus S:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter();
Then we need a handle to the actually detected tag, this is done by getting the the data within the intent received when tag was discovered:
Parcelable nfcTag = intent.getParcelableExtra("android.nfc.extra.TAG");
Field f = nfcTag.getClass().getDeclaredField("mServiceHandle");
Object mServiceHandle = f.get(nfcTag);
Now, we can create a raw connection to the tag, this is a low-level connection to a tag target. We’ll use this object to get later a handle to the INfcTag
Class tag = Class.forName("android.nfc.Tag");
Method createRawTagConnection = nfcAdapter.getClass().getMethod("createRawTagConnection", tag);
Object rawTagConnection = createRawTagConnection.invoke(nfcAdapter, nfcTag);
Now we can get the handle to the INfcTag interface (mTagService).
Field f = rawTagConnection.getClass().getDeclaredField("mTagService");
Object mTagService = f.get(rawTagConnection);
Before we can write to the tag we connect our interface to it.
Method connect = mTagService.getClass().getMethod("connect", Integer.TYPE);
Finally, we create the NdefTagRecord, this could be a smart poster, an uri, simple text or whatever record we want to write into the tag. This record will be encapsulated into an NdefMessage, so when we invoke the write() method we use this ndefMessage as parameter:
Method write = mTagService.getClass().getMethod("write", Integer.TYPE, NdefMessage.class);
write.invoke(mTagService, mServiceHandle, ndefMessage);
… and that’s it!
The write() method will work as long as you use a tag pre-formatted with any NFC Forum type tag with default public keys.
We developed an application using this code to write tags. Below you can see a demo of this app writing an URI type tag: