NdefRecord.createMime bug in arguments

0 votes
asked Feb 13, 2016 by henrycjc

I have a method that writes data to a discovered NFC tag (the data comes from an array of records toWriteRecordsList).

// ... more up here ...
for (String record : toWriteRecordsList) {
     String[] recordArr = record.split(":");
     // I verified the recordArr contained the correct data
            try {
                // This line writes 'text/plain' as the message/payload
                //records[currentRecord] = NdefRecord.createMime("text/plain", recordArr[1].getBytes("US-ASCII"));
                // This line works as intended...¯\_(ツ)_/¯
                records[currentRecord] = NdefRecord.createMime(recordArr[1], "text/plain".getBytes());
            } catch (Exception e ) {
                e.printStackTrace();
            }
            currentRecord++;
        }
// ... actual writing down here ...

Bizarrely, when I use the NdefRecord.createMime method as the docs specify then the encoded message, when displayed in the Android default Tag app ("tag collector"), is whatever the first argument is (in this case the message the phone prints is "text/plain"!)

When createMime() definitely has this signature:

public static NdefRecord createMime (String mimeType, byte[] mimeData)

Because this seemed so bizarre to me, I swapped the arguments (including calling .getBytes() to satisfy the prototype) and it worked! I tried this on two different devices (Galaxy Nexus and Galaxy S4) and got the same behaviour.

I can't find any record of the Android bug so I figured I'm doing something wrong. What the hell is going on?

1 Answer

+1 vote
answered Feb 15, 2016 by michael-roland

There is nothing wrong with the NdefRecord.createMime(...) method. The Android default "Tag" app displays MIME type records by showing the name of the MIME type and not its payload. Hence, the app correctly shows the first argument of the createMime() method (i.e. the type name).

Showing the payload of the MIME type record would require the Tag app to decode the record payload based on the type name, which this app simply does not do. See the source code of the getView() method for MIME records in the Tag app: MimeRecord.java:59.

Note that if you would want the Tag app to display text stored inside an NDEF record, you would use the NFC Forum Text record type:

NdefRecord r = NdefRecord.createTextRecord("en", recordArr[1]);

Or for Android before API level 21:

public static NdefRecord createTextRecord(String language, String text) {
    byte[] languageBytes;
    byte[] textBytes;
    try {
        languageBytes = language.getBytes("US-ASCII");
        textBytes = text.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw new AssertionError(ex);
    }

    byte[] recordPayload = new byte[1 + (languageBytes.length & 0x03F) + textBytes.length];

    recordPayload[0] = (byte)(languageBytes.length & 0x03F);
    System.arraycopy(languageBytes, 0, recordPayload, 1, languageBytes.length & 0x03F);
    System.arraycopy(textBytes, 0, recordPayload, 1 + (languageBytes.length & 0x03F), textBytes.length);

    return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, null, recordPayload);
}

NdefRecord r = createTextRecord("en", recordArr[1]);
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...