Near Field Communication

BlackBerry® devices that come equipped with a Near Field Communication (NFC) transceiver enable an application to interact with smart tags, smart accessories, and other NFC-enabled devices. Smart tags typically contain small amounts of data that describe an object in the world, or refers to another data channel where a user can get more information.

For example, a Bluetooth® speaker could have an embedded smart tag that contains Bluetooth pairing information. A media-player application that detects the smart tag could initiate pairing, then route the BlackBerry device audio output to the Bluetooth speakers.

NFC technology is designed to transfer small amounts of data over a short distance. Here are a few examples of what you can use smart tags to do:

  • Provide a web address where a BlackBerry device user can retrieve more information about an advertisement on a smart poster, such as a movie or a coupon
  • Provide pairing information for a Bluetooth accessory
  • Provide identification information for a smart dock

You can use the NFC API to read and write smart tags that are formatted according to the NDEF Technical Specification. The classes and interfaces in the net.rim.device.api.io.nfc.readerwriter and net.rim.device.api.io.nfc.ndef packages allow you to read and write NDEF-formatted smart tags. The NFC supports NDEF types 1 through 4. You can also communicate with ISO14443 smart tags by using the classes and interfaces in the net.rim.device.api.io.nfc.readerwriter package.

The NFC API also enables you to emulate a smart tag. You can use the classes and interfaces in the net.rim.device.api.io.nfc.emulation package to create a virtual NDEF type 4 tag, or a virtual ISO14443-4 tag.

Working with smart tags

The NFC feature on a BlackBerry® device is typically activated by a BlackBerry device user when the user taps a smart tag. If you registered a listener that matches the configuration of the smart tag that the user taps, the device can notify your application that a tag is available.

You can implement the net.rim.device.api.io.nfc.ndef.NDEFMessageListener interface to receive messages from a smart tag that is configured according to the NDEF Technical Specification. The BlackBerry device provides an NDEFMessage object that contains the data from the smart tag to an NDEFMessageListener. Applications that register an NDEFMessageListener object can restrict the Record Type Definition and record type that trigger the application.

You can implement the net.rim.device.api.io.nfc.readerwriter.DetectionListener interface to enable your application to receive notification of a connection to any smart tag that conforms to the ISO14443 standard. When invoked, a DetectionListener receives a Target object that contains the URI that is required to open a connection to the tag.

When a smart tag is detected, the device notifies any applications that registered a listener for that type of tag. Only one DetectionListener object can access a smart tag at a time while the smart tag is within the range of the NFC transceiver. When one DetectionListener finishes with the smart tag, another DetectionListener can open a connection to the smart tag if it is still in range.

Back To Top

Supported smart tags in BlackBerry 7

NFC Forum tag type

Supported tags

Type 1

  • Topaz 96
  • Topaz 512

Type 2

  • MiFare Ultra Light
  • MiFare Ultra Light C
  • Infineon my-D Move
  • Infineon my-D NFC

Type 3

FeliCa RC-S965

Type 4

MiFare DESFire EV1 (2k, 4k, 8k)

You can also communicate with smart tags using lower level protocols, such as ISO14443-3 and ISO 14443-4. For more information about communicating with smart tags using lower level protocols, see the API reference for the BlackBerry® Java® SDK and the manufacturer's documentation for the tag.

Back To Top

Create an NDEF tag writer

  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.NFCException;
    import net.rim.device.api.io.nfc.ndef.NDEFMessage;
    import net.rim.device.api.io.nfc.ndef.NDEFRecord;
    import net.rim.device.api.io.nfc.ndef.NDEFTagConnection;
    import net.rim.device.api.io.nfc.readerwriter.*;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.UiApplication;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.lang.String;
    
    import javax.microedition.io.Connector;
  2. Declare your application class and start your application.
    public class NDEFWriterDemo extends UiApplication
    {
    
        public static void main(String[] args)
        {
            new NDEFWriterDemo().enterEventDispatcher();
        }
  3. In your application's constructor, create an NDEFWriterScreen object to represent the status screen of your application, and create a new instance of your implementation of the DetectionListener interface. You create the NDEFWriterScreen class in step 25. You implement a DetectionListener in step 10.
        public NDEFWriterDemo()
        {
            NDEFWriterScreen screen = new NDEFWriterScreen();
            NDEFWriterListener listener = new NDEFWriterListener(screen);
  4. Invoke registerListener() to register your implementation of DetectionListener. You create registerListener() in step 6.
            registerListener(listener);
  5. Add your NDEFWriterScreen object to the display stack.
            pushScreen(screen);
        }
  6. Create registerListener().
        public void registerListener(NDEFWriterListener listener)
        {
  7. Retrieve the singleton instance of ReaderWriterManager.
            ReaderWriterManager nfc;
            try
            {
                nfc = ReaderWriterManager.getInstance();
  8. Register your implementation of DetectionListener. Indicate that you want to listen for the NDEF tag target type.
                nfc.addDetectionListener(listener, new int[]{Target.NDEF_TAG});
                // Save your registration state in persistent storage.
            }
  9. Process any errors that occur
            catch (NFCException e)
            {
                // error handling code
            }
        }
  10. Declare your implementation of DetectionListener.
        private class NDEFWriterListener implements DetectionListener
        {
  11. Create an instance variable to hold a reference to the status screen. In your constructor, assign a value to this variable.
            private NDEFWriterScreen display;
    
            public NDEFWriterListener(NDEFWriterScreen screen)
            {
                super();
                display = screen;
            }
  12. Implement the onTargetDetected() method.
            public void onTargetDetected(Target target)
            {
  13. Create a variable for the connection to the smart tag.
                NDEFTagConnection c = null;
  14. Invoke display.message() to update the message on the status screen. You create this method in step 27.
                display.message("Tag detected. Attempting to write data.");
  15. Create an NDEFMessage object to write to the smart tag.
                try
                {
                    NDEFMessage smartTag = createSmartTag();
  16. Open a connection to the smart tag. Cast the connection using the NDEFTagConnection interface. Retrieve the URI for the connection by invoking Target.getUri().
                    c = (NDEFTagConnection)Connector.open(
                    target.getUri(Target.NDEF_TAG));
                    c.write(smartTag);
  17. Update the message on the status screen.
                    display.message("Successfully wrote to tag.");
                }
  18. Process any errors that occur.
     catch (IOException e)
                {
                    display.message("Could not write to tag.");
                    // Process errors here.
                }
            }
  19. Create createSmartTag() to define the content to write to a smart tag.
            private NDEFMessage createSmartTag() throws IOException 
            {
  20. Create an NDEF record to write to the smart tag.
                NDEFRecord titleRec = new NDEFRecord();
                titleRec.setId("1");
                titleRec.setType(NDEFRecord.TNF_WELL_KNOWN, "T"); 
                
                ByteArrayOutputStream payload1 = new ByteArrayOutputStream();
                payload1.write((byte) 0x05);             // Status byte - length of encoding
                payload1.write("en-US".getBytes("UTF-8"));      // Encoding
                payload1.write("My Title".getBytes("UTF-8"));   // Title
                payload1.flush();
                
                titleRec.setPayload(payload1.toByteArray());
  21. Create a second NDEF record to write to the smart tag.
                NDEFRecord uriRec = new NDEFRecord();
                uriRec.setId("2");
                uriRec.setType(NDEFRecord.TNF_WELL_KNOWN, "U");
                
                ByteArrayOutputStream payload2 = new ByteArrayOutputStream();
                payload2.write((byte) 0x01);                 // Abbreviation: http://www.
                payload2.write("blackberry.com".getBytes("UTF-8")); // URI
                payload2.flush();
                
                uriRec.setPayload(payload2.toByteArray());
  22. Create an NDEFMessage object and populate it with your NDEF records.
                NDEFMessage ndefMessage = new NDEFMessage();
                ndefMessage.setRecords(new NDEFRecord[] {titleRec, uriRec});
  23. Set your NDEFMessage object to be the first message on the smart tag.
                NDEFMessage rootMessage = new NDEFMessage();
                byte[] rootPayload = ndefMessage.getBytes();
                NDEFRecord rootRec = new NDEFRecord();
                rootRec.setType(NDEFRecord.TNF_WELL_KNOWN, "Sp");
                rootRec.setPayload(rootPayload);
                rootMessage.setRecords(new NDEFRecord[] {rootRec});
  24. Return the NDEFMessage to the invoking method.
                return rootMessage;
            }
        }
  25. Create the NDEFWriterScreen class and create an instance variable to hold a reference to a LabelField object.
        private class NDEFWriterScreen extends MainScreen
        {
            private LabelField lbl;
    
  26. Create a constructor for your status screen. Initialize your label and add it to the screen.
            public NDEFWriterScreen()
            {
                lbl = new LabelField("Tap a smart tag to write data.", 
                                            Field.FIELD_HCENTER|Field.FIELD_VCENTER);
                add(lbl);
            }
    
  27. Create message() to update the text in the label when tag-related events occur.
            public void message(String msg)
            {
                lbl.setText(msg);
            }
        }
    }
Back To Top

Code sample: Creating an NDEF tag writer

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.String;

import javax.microedition.io.Connector;

import net.rim.device.api.io.nfc.NFCException;
import net.rim.device.api.io.nfc.ndef.NDEFMessage;
import net.rim.device.api.io.nfc.ndef.NDEFRecord;
import net.rim.device.api.io.nfc.ndef.NDEFTagConnection;
import net.rim.device.api.io.nfc.readerwriter.*;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;

public class NDEFWriterDemo extends UiApplication
{

    public static void main(String[] args)
    {
        new NDEFWriterDemo().enterEventDispatcher();
    }

    public NDEFWriterDemo()
    {
        // Detect whether or not you
        // registered a listener already.
        // If not, then register a listener.
        NDEFWriterScreen screen = new NDEFWriterScreen();
        NDEFWriterListener listener = new NDEFWriterListener(screen);
        registerListener(listener);
        pushScreen(screen);
    }

    public void registerListener(NDEFWriterListener listener)
    {
        ReaderWriterManager nfc;
        try
        {
            nfc = ReaderWriterManager.getInstance();
            nfc.addDetectionListener(listener, new int[]{Target.NDEF_TAG});
            // Save your registration state in persistent storage.
        } catch (NFCException e)
        {
            // Process error here.
        }
    }

    private class NDEFWriterListener implements DetectionListener
    {

        private NDEFWriterScreen display;

        public NDEFWriterListener(NDEFWriterScreen screen)
        {
            super();
            display = screen;
        }

        public void onTargetDetected(Target target)
        {
            NDEFTagConnection c = null;
            display.message("Tag detected. Attempting to write data.");

            try
            {
                NDEFMessage smartTag = createSmartTag();

                c = (NDEFTagConnection)Connector.open(
                target.getUri(Target.NDEF_TAG));
                c.write(smartTag);

                display.message("Successfully wrote to tag.");
            } catch (IOException e)
            {
                display.message("Could not write to tag.");
                // Process error here.
            }
        }
        
        private NDEFMessage createSmartTag() throws IOException 
        {
            NDEFRecord titleRec = new NDEFRecord();
            titleRec.setId("1");
            titleRec.setType(NDEFRecord.TNF_WELL_KNOWN, "T"); 
            
            ByteArrayOutputStream payload1 = new ByteArrayOutputStream();
            payload1.write((byte) 0x05);             // Status byte - length of encoding
            payload1.write("en-US".getBytes("UTF-8"));      // Encoding
            payload1.write("My Title".getBytes("UTF-8"));   // Title
            payload1.flush();
            
            titleRec.setPayload(payload1.toByteArray());
            
            NDEFRecord uriRec = new NDEFRecord();
            uriRec.setId("2");
            uriRec.setType(NDEFRecord.TNF_WELL_KNOWN, "U");
            
            ByteArrayOutputStream payload2 = new ByteArrayOutputStream();
            payload2.write((byte) 0x01);                 // Abbreviation: http://www.
            payload2.write("blackberry.com".getBytes("UTF-8")); // URI
            payload2.flush();
            
            uriRec.setPayload(payload2.toByteArray());

            NDEFMessage ndefMessage = new NDEFMessage();
            ndefMessage.setRecords(new NDEFRecord[] {titleRec, uriRec});
            
            // Root message with one record that has a nested 
            // message in the form of bytes.
            NDEFMessage rootMessage = new NDEFMessage();
            byte[] rootPayload = ndefMessage.getBytes();
            NDEFRecord rootRec = new NDEFRecord();
            rootRec.setType(NDEFRecord.TNF_WELL_KNOWN, "Sp");
            rootRec.setPayload(rootPayload);
            rootMessage.setRecords(new NDEFRecord[] {rootRec});
            
            return rootMessage;
        }
    }

    private class NDEFWriterScreen extends MainScreen
    {
        private LabelField lbl;

        public NDEFWriterScreen()
        {
            lbl = new LabelField("Tap a smart tag to write data.", 
                                        Field.FIELD_HCENTER|Field.FIELD_VCENTER);
            add(lbl);
        }

        public void message(String msg)
        {
            lbl.setText(msg);
        }
    }
}
Back To Top

Create an NDEF tag reader

  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.NFCException;
    import net.rim.device.api.io.nfc.readerwriter.*;
    import net.rim.device.api.io.nfc.ndef.*;
    import net.rim.device.api.ui.component.ButtonField;
    import net.rim.device.api.ui.component.Dialog;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.container.VerticalFieldManager;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.FieldChangeListener;
    import net.rim.device.api.ui.UiApplication;
    
    import java.lang.String;
  2. Declare your application class and start your application.
    public class NDEFReaderDemo extends UiApplication 
    {
        public static void main(String[] args)
        {
            new NDEFReaderDemo().enterEventDispatcher();
        }
  3. In the constructor for your application, add a screen to the display stack to allow a BlackBerry® device user to interact with your application. You create this screen in step 11.
        public NDEFReaderDemo()
        {
            pushScreen(new NDEFReaderScreen());
        }
  4. Create registerListener().
        public void registerListener(NDEFReaderListener listener)
        {
  5. Retrieve the singleton instance of ReaderWriterManager.
            try
            {
                ReaderWriterManager nfc = ReaderWriterManager.getInstance();
  6. Register your implementation of NDEFMessageListener. Indicate that you want to listen for a smart poster.
                nfc.addNDEFMessageListener(listener, NDEFRecord.TNF_WELL_KNOWN, "Sp", true);
            }
  7. Process any errors that occur
            catch(NFCException e)
            {
                Dialog.alert(e.toString());
            }
        }
  8. Create deregisterListener() to deregister the listener.
        public void deregisterListener()
        {
            try
            {
                ReaderWriterManager nfc = ReaderWriterManager.getInstance();
                
                nfc.removeNDEFMessageListener(NDEFRecord.TNF_WELL_KNOWN, "Sp");
            } catch(NFCException e)
            {
                Dialog.alert(e.toString());
            }
        }
  9. Implement the NDEFMessageListener interface. Create an instance variable to hold a reference to the screen. In your constructor, assign a value to this variable.
        private class NDEFReaderListener implements NDEFMessageListener
        {
            private NDEFReaderScreen display;
            private NDEFReaderListener(NDEFReaderScreen screen)
            {
                super();
                display = screen;
            }
  10. Implement onNDEFMessageDetected(). Pass the NDEF records as a parameter to the the constructor of the screen class.
            public void onNDEFMessageDetected(final NDEFMessage msg)
            {
                NDEFReaderDemo.this.invokeLater(new Runnable() {
                    public void run() {
                        display.displayRecs(msg.getRecords());
                    }
                });
            }
        }
  11. Create the NDEFReaderScreen class to display the NDEF records from the smart poster. Create instance variables to keep references to the ButtonField objects on the screen.
        private class NDEFReaderScreen extends MainScreen implements FieldChangeListener
        {
            ButtonField btn1, btn2;
  12. In the constructor, create your buttons and add them to the screen.
            private NDEFReaderScreen()
            {
                btn1 = new ButtonField("Register Persistent Listener",Field.FIELD_HCENTER|Field.FIELD_VCENTER);
                btn1.setChangeListener(this);
                add(btn1);
                
                btn2 = new ButtonField("Deregister Persistent Listener",Field.FIELD_HCENTER|Field.FIELD_VCENTER);
                btn2.setChangeListener(this);
                add(btn2);
            }
  13. Create displayRecs() to display any records that you receive from the smart tag. Determine whether any records were passed to this method.
            public void displayRecs(NDEFRecord[] records)
            {
                int numRecords = records.length;
                if (numRecords > 0)
                {
  14. If NDEF records exist, create an array of LabelField objects and add them to a vertical field manager. Add the vertical field manager to the screen to contain the labels.
                    VerticalFieldManager vfm = new VerticalFieldManager();
                    LabelField lbl[] = new LabelField[numRecords];
                    for (int j = numRecords - 1; j >= 0; j--)
                    {
                        lbl[j] = new LabelField();
                        lbl[j].setText(new String(records[j].getPayload(),“UTF-8”));
                        vfm.add(lbl[j]);
                    }
                    add(vfm);
                }
  15. If no NDEF records were read from the tag, add a label to the screen to inform the user.
                else
                {
                    LabelField lbl = new LabelField("This tag contains no records",
                                            Field.FIELD_HCENTER|Field.FIELD_VCENTER);
                    add(lbl);
                }
            }
    
  16. Implement fieldChanged to respond when the user presses the buttons on the screen.
            public void fieldChanged(Field field, int context)
            {
                if (field == btn1)
                {
                    registerListener(new NDEFReaderListener(this));
                } else if (field == btn2)
                {
                    deregisterListener();
                }
            }
        }
    }
Back To Top

Code sample: Creating an NDEF tag reader

import net.rim.device.api.io.nfc.NFCException;
import net.rim.device.api.io.nfc.readerwriter.*;
import net.rim.device.api.io.nfc.ndef.*;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.UiApplication;

import java.lang.String;

public class NDEFReaderDemo extends UiApplication 
{
    public static void main(String[] args)
    {
        new NDEFReaderDemo().enterEventDispatcher();
    }

    public NDEFReaderDemo()
    {
        pushScreen(new NDEFReaderScreen());
    }

    public void registerListener(NDEFReaderListener listener)
    {
        try
        {
            ReaderWriterManager nfc = ReaderWriterManager.getInstance();
            
            nfc.addNDEFMessageListener(listener, NDEFRecord.TNF_WELL_KNOWN, "Sp", true);
            // Save your registration state in persistent storage.
        } catch(NFCException e)
        {
            Dialog.alert(e.toString());
        }
    }
    
    public void deregisterListener()
    {
        try
        {
            ReaderWriterManager nfc = ReaderWriterManager.getInstance();
            
            nfc.removeNDEFMessageListener(NDEFRecord.TNF_WELL_KNOWN, "Sp");
        } catch(NFCException e)
        {
            Dialog.alert(e.toString());
        }
    }

    private class NDEFReaderListener implements NDEFMessageListener
    {
        private NDEFReaderScreen display;
        private NDEFReaderListener(NDEFReaderScreen screen)
        {
            super();
            display = screen;
        }

        public void onNDEFMessageDetected(final NDEFMessage msg)
        {
            NDEFReaderDemo.this.invokeLater(new Runnable() {
                public void run() {
                    display.displayRecs(msg.getRecords());
                }
            });
        }
    }

    private class NDEFReaderScreen extends MainScreen implements FieldChangeListener
    {
        ButtonField btn1, btn2;

        private NDEFReaderScreen()
        {
            btn1 = new ButtonField("Register Persistent Listener",Field.FIELD_HCENTER|Field.FIELD_VCENTER);
            btn1.setChangeListener(this);
            add(btn1);
            
            btn2 = new ButtonField("Deregister Persistent Listener",Field.FIELD_HCENTER|Field.FIELD_VCENTER);
            btn2.setChangeListener(this);
            add(btn2);
        }

        public void displayRecs(NDEFRecord[] records)
        {
            int numRecords = records.length;
            if (numRecords > 0)
            {
                VerticalFieldManager vfm = new VerticalFieldManager();
                LabelField lbl[] = new LabelField[numRecords];
                for (int j = numRecords - 1; j >= 0; j--)
                {
                    lbl[j] = new LabelField();
                    lbl[j].setText(new String(records[j].getPayload()));
                    vfm.add(lbl[j]);
                }
                add(vfm);
            } else
            {
                LabelField lbl = new LabelField("This tag contains no records",
                                        Field.FIELD_HCENTER|Field.FIELD_VCENTER);
                add(lbl);
            }
        }

        public void fieldChanged(Field field, int context)
        {
            if (field == btn1)
            {
                registerListener(new NDEFReaderListener(this));
            } else if (field == btn2)
            {
                deregisterListener();
            }
        }
    }
}
Back To Top

Communicate with an ISO14443 smart tag

  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.NFCException;
    import net.rim.device.api.io.nfc.readerwriter.*;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.UiApplication;
    
    import java.io.IOException;
    import java.lang.String;
    
    import javax.microedition.io.Connector;
  2. Declare your application class and start your application.
    public class ISO14443Demo extends UiApplication
    {
        public static void main(String[] args)
        {
            new ISO14443Demo().enterEventDispatcher();
        }
  3. In the constructor for your application, invoke a method to register your implementation of DetectionListener.
        public ISO14443Demo()
        {
            registerListener();
        }
  4. Create registerListener().
        public void registerListener()
        {
  5. Retrieve the singleton instance of ReaderWriterManager.
            ReaderWriterManager nfc;
            try
            {
                nfc = ReaderWriterManager.getInstance();
  6. Register your implementation of DetectionListener.
                nfc.addDetectionListener(new ISO14443Listener());
            }
  7. Process any errors that occur.
            catch (NFCException e)
            {
                // error handling code
            }
        }
  8. Declare your implementation of DetectionListener.
        private class ISO14443Listener implements DetectionListener
        {
  9. Implement onTargetDetected(). Create local variables to hold references to the following resources:
    • Connection to the smart tag
    • Command to send to the smart tag
    • Response from the smart tag
       public void onTargetDetected(Target target)
            {
                ISO14443Part3Connection c = null;
    
                // 0x30 - read command, 0x03 - starting from page 3
                byte[] ISO14443Command = {(byte) 0x30, (byte) 0x03};
                byte[] response = null;
  10. Invoke Connector.open() to open a connection to the smart tag. Cast the connection using the ISO14443Part3 interface. Retrieve the URI for the connection by invoking Target.getUri().
                try
                {
                    c = (ISO14443Part3Connection)Connector.open(
                    target.getUri(Target.ISO_14443_3));
  11. Send your command to the smart tag and retrieve the response.
                    response = c.transceive(ISO14443Command);
                }
  12. Process any errors that occur.
                catch (IOException e)
                {
                    // error handling code
                    // make sure to set a non-null value for response
                }
  13. Add a screen to the display stack to show the response from the smart tag. Pass the response variable as a parameter to the screen's constructor.
                pushScreen(new ISO14443DemoStatusScreen(response));
            }
        }
  14. Declare a screen class to display the response data from the smart tag. In the constructor, create a LabelField object. Populate the label with the smart tag response data, and add the label to the screen to display the data.
        private class ISO14443DemoStatusScreen extends MainScreen
        {
            public ISO14443DemoStatusScreen(byte[] response)
            {
                LabelField lbl = new LabelField(response, Field.FIELD_HCENTER);
                add(lbl);
            }
        }
    }
Back To Top

Code sample: Communicating with an ISO 14443 tag

import net.rim.device.api.io.nfc.NFCException;
import net.rim.device.api.io.nfc.readerwriter.*;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;

import java.io.IOException;
import java.lang.String;

import javax.microedition.io.Connector;

public class ISO14443Demo extends UiApplication
{

    public static void main(String[] args)
    {
        new ISO14443Demo().enterEventDispatcher();
    }

    public ISO14443Demo()
    {
        // Detect whether or not you
        // registered a listener already.
        // If not, then register a listener.
        registerListener();
    }

    public void registerListener()
    {
        ReaderWriterManager nfc;
        try
        {
            nfc = ReaderWriterManager.getInstance();
            nfc.addDetectionListener(new ISO14443Listener());
            // Save your registration state in persistent storage.
        } catch (NFCException e)
        {
            // Process error condition.
        }
    }

    private class ISO14443Listener implements DetectionListener
    {
        public void onTargetDetected(Target target)
        {
            ISO14443Part3Connection c = null;

            // 0x30 - read command, 0x03 - starting from page 3
            byte[] ISO14443Command = {(byte) 0x30, (byte) 0x03};
            byte[] response = null;
            try
            {
                c = (ISO14443Part3Connection)Connector.open(
                target.getUri(Target.ISO_14443_3));
                response = c.transceive(ISO14443Command);
            } catch (IOException e)
            {
                // Process error condition.
                // Make sure to set a non-null value for response.
            }
            pushScreen(new ISO14443DemoStatusScreen(response));
        }
    }

    private class ISO14443DemoStatusScreen extends MainScreen
    {
        public ISO14443DemoStatusScreen(byte[] response)
        {
            LabelField lbl = new LabelField(response, Field.FIELD_HCENTER);
            add(lbl);
        }
    }
}
Back To Top

Emulating smart tags

The NFC API allows you to create a virtual smart tag. The ability to dynamically create a smart tag enables your application to share small amounts of data between NFC-enabled smartphones and tag readers. Some examples of what your application can do using a virtual tag include:
  • Simple ticketing for an event
  • Sharing contact information
  • Rudimentary identification

You can create a virtual smart tag that conforms to the NDEF type 4 or ISO14443-4 standard. To create a tag, you need the following components:

Component

Description

Data

If you create a virtual NDEF tag, you need to provide the data for the tag by passing an NDEFMessage object when you create a VirtualNDEFTag.

For a virtual ISO14443-4 tag, you can return data from your implementation of the VirtualISO14443Part4TargetCallback.processCommand() method.

Virtual target object

You can instantiate one of the following classes to control virtual tag emulation:

Callback interface

If you create a virtual NDEF tag, you can implement the VirtualNDEFTagCallback interface to receive notifications when a tag reader interacts with the virtual smart tag.

If you create a virtual ISO14443-4 tag, you can interact with the tag reader by implementing VirtualISO14443Part4TargetCallback.processCommand() method.

Back To Top

Emulate an NDEF smart tag

The following tasks describe how to create a simple application that emulates an NDEF type 4 smart tag:
Back To Top
Create a BlackBerry application
  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.emulation.VirtualNDEFTag; 
    import net.rim.device.api.io.nfc.NFCException; 
    import net.rim.device.api.io.nfc.ndef.NDEFMessage; 
    import net.rim.device.api.ui.component.ButtonField; 
    import net.rim.device.api.ui.component.Dialog; 
    import net.rim.device.api.ui.container.MainScreen;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.FieldChangeListener; 
    import net.rim.device.api.ui.UiApplication;
  2. Declare your application class and start your application.
    public class TagEmulatorApp extends UiApplication
    {
        public static void main(String[] args)
        {
            TagEmulatorApp theApp = new TagEmulatorApp();       
            theApp.enterEventDispatcher();
        }
  3. In the constructor for your application, create a new screen object to control your virtual tag. Add your screen to the display stack.
        public TagEmulatorApp()
        {        
            pushScreen(new TagEmulatorScreen());
        }
  4. Declare the screen class you use to control your virtual tag. Implement the FieldChangeListener interface to respond to user interaction.
        private class TagEmulatorScreen extends MainScreen implements 
                                                              FieldChangeListener
        {
  5. Declare two instance variables:
    • A reference to a button that the user can use to start and stop tag emulation
    • A reference to your virtual tag
            private ButtonField _btnStartStop;
            private VirtualNDEFTag _tag;
  6. In the constructor for your screen, set the title for your screen, and initialize your button.
            public TagEmulatorScreen()
            {        
                setTitle("Smart Tag Emulator");
                _btnStartStop = new ButtonField("Start emulation", 
                                                    Field.FIELD_HCENTER);
  7. Specify your screen class as the FieldChangeListener for your button, and add the button to the screen.
                _btnStartStop.setChangeListener(this);
                add(_btnStartStop);
  8. Retrieve an NDEF message to write to your virtual NDEF tag.
                NDEFMessage msg = null;
                try {
                    msg = TagEmulatorData.getMessage();
                } catch (IOException e) {
                    // process error here
                }
  9. If the NDEF message was created succsesfully, create a new tag. Pass the NDEF message and a call-back object to the constructor for your tag.
                if(msg != null)
                {
                    _tag = new VirtualNDEFTag(msg, new TagEmulatorCallback());
                } else
                {
                    _tag = null;
                }
            }
  10. Implement the fieldChanged method from the FieldChangeListener interface. Check whether the virtual tag is valid, and if the user clicked a button.
    • If the virtual tag is active, then deactivate it and change the button label to indicate that the user can activate tag emulation.
    • If the virtual tag is inactive, activate it and change the button label to indicate to the user that they can deactivate the tag.
            public void fieldChanged(Field field, int arg1) {
                if(_tag != null)
                {
                    if(field == _btnStartStop)
                    {
                        try {
                            boolean blnEmulating = _tag.isEmulating();
                            if(blnEmulating)
                            {
                                _tag.stopEmulation();
                                _btnStartStop.setLabel("Start emulation");
                            } else
                            {
                                _tag.startEmulation();
                                _btnStartStop.setLabel("Stop emulation");
                            }
    • If the virtual tag is active, then deactivate it and change the button label to indicate that the user can activate tag emulation.
    • If the virtual tag is inactive, activate it and change the button label to indicate to the user that they can deactivate the tag.
  11. Process any errors that occur while communicating with the tag
                        } catch (NFCException e) 
                        {
                            Dialog.alert("Could not communicate with 
                                                          virtual tag.");
                        }
                    }
  12. If the tag is invalid, notify the user that emulation cannot be activated.
                } else
                {
                    Dialog.alert("Cannot create smart tag data for emulation.");
                }
            }
        }
    }
Back To Top
Create an NDEF message
  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.ndef.NDEFMessage;
    import net.rim.device.api.io.nfc.ndef.NDEFRecord;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
  2. Declare your data creation class.
    public class TagEmulatorData {
    
        public TagEmulatorData()
        {
        }
  3. Declare a static method named getMessage. By using the static keyword on this method, you can avoid the requirement to instantiate this class when you want retrieve data for your virtual tag. The methods invoked during the creation can cause an IOException. Specify that the method can throw an IOException.
        public static NDEFMessage getMessage() throws IOException
        {
            NDEFRecord titleRec = new NDEFRecord();
            titleRec.setId("1");
            titleRec.setType(NDEFRecord.TNF_WELL_KNOWN, "T"); 
            
            ByteArrayOutputStream payload1 = new ByteArrayOutputStream();
            payload1.write((byte) 0x05);             // Status byte - length of encoding
            payload1.write("en-US".getBytes("UTF-8"));      // Encoding
            payload1.write("My Title".getBytes("UTF-8"));   // Title
            payload1.flush();
            
            titleRec.setPayload(payload1.toByteArray());
            
            NDEFRecord uriRec = new NDEFRecord();
            uriRec.setId("2");
            uriRec.setType(NDEFRecord.TNF_WELL_KNOWN, "U");
            
            ByteArrayOutputStream payload2 = new ByteArrayOutputStream();
            payload2.write((byte) 0x01);                 // Abbreviation: http://www.
            payload2.write("blackberry.com".getBytes("UTF-8")); // uri
            payload2.flush();
            
            uriRec.setPayload(payload2.toByteArray());
    
            NDEFMessage ndefMessage = new NDEFMessage();
            ndefMessage.setRecords(new NDEFRecord[] {titleRec, uriRec});
            
            // Root message with one record that has in payload a nested message in the form of bytes
            NDEFMessage rootMessage = new NDEFMessage();
            byte[] rootPayload = ndefMessage.getBytes();
            NDEFRecord rootRec = new NDEFRecord();
            rootRec.setType(NDEFRecord.TNF_WELL_KNOWN, "Sp");
            rootRec.setPayload(rootPayload);
            rootMessage.setRecords(new NDEFRecord[] {rootRec});
            
            return rootMessage;
        }
    }
Back To Top
Implement the NDEF call-back interface
  1. Import the required classes and interfaces.
    import net.rim.device.api.io.nfc.emulation.VirtualNDEFTagCallback;
    import net.rim.device.api.ui.component.Dialog;
  2. Declare your implementation of the VirtualNDEFTagCallback interface.
    public class TagEmulatorCallback implements VirtualNDEFTagCallback
    {
  3. Implement the onVirtualTargetEvent() method. For each event, notifiy the user that the event occured.
        public void onVirtualTargetEvent(int event) {
            switch(event)
            {
                case VirtualNDEFTagCallback.EMULATION_STOPPED:
                    Dialog.alert("Emulation stopped.");
                    break;
                case VirtualNDEFTagCallback.READER_LEFT:
                    Dialog.alert("Smart tag reader moved out of range.");
                    break;
                case VirtualNDEFTagCallback.SELECTED:
                    Dialog.alert("This tag was selected by a smart tag reader.");
                    break;
                case VirtualNDEFTagCallback.TARGET_READ:
                    Dialog.alert("This tag was read by a smart tag reader.");
                    break;
                case VirtualNDEFTagCallback.TARGET_UPDATED:
                    Dialog.alert("A smart tag writer changed the contents of this tag.");				
                    break;
            }
        }
    }
Back To Top

Code sample: Emulating an NDEF smart tag

Create a BlackBerry® application

import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.io.nfc.NFCException;
import net.rim.device.api.io.nfc.emulation.VirtualNDEFTag;
import net.rim.device.api.io.nfc.ndef.NDEFMessage;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.container.MainScreen;

import java.io.IOException;

public class TagEmulatorApp extends UiApplication
{
    public static void main(String[] args)
    {
        TagEmulatorApp theApp = new TagEmulatorApp();       
        theApp.enterEventDispatcher();
    }

    public TagEmulatorApp()
    {        
        pushScreen(new TagEmulatorScreen());
    }
    
    private class TagEmulatorScreen extends MainScreen implements FieldChangeListener
    {
        private ButtonField _btnStartStop;
        private VirtualNDEFTag _tag;

        public TagEmulatorScreen()
        {        
            setTitle("Smart Tag Emulator");
            _btnStartStop = new ButtonField("Start emulation", Field.FIELD_HCENTER);
            _btnStartStop.setChangeListener(this);
            add(_btnStartStop);
           
            NDEFMessage msg = null;
            try {
                msg = TagEmulatorData.getMessage();
            } catch (IOException e) {
                // process error here
            }

            if(msg != null)
            {
                _tag = new VirtualNDEFTag(msg, new TagEmulatorCallback());
            } else
            {
                _tag = null;
            }
        }

        public void fieldChanged(Field field, int arg1) {
            if(_tag != null)
            {
                if(field == _btnStartStop)
                {
                    try {
                        boolean blnEmulating = _tag.isEmulating();
                        if(blnEmulating)
                        {
                            _tag.stopEmulation();
                            _btnStartStop.setLabel("Start emulation");
                        } else
                        {
                            _tag.startEmulation();
                            _btnStartStop.setLabel("Stop emulation");
                        }
                        
                    } catch (NFCException e) 
                    {
                        Dialog.alert("Could not communicate with virtual tag.");
                    }
                }
            } else
            {
                Dialog.alert("Cannot create smart tag data for emulation.");
            }
        }
    }
}

Create an NDEF message

import net.rim.device.api.io.nfc.ndef.NDEFMessage;
import net.rim.device.api.io.nfc.ndef.NDEFRecord;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class TagEmulatorData {

    public TagEmulatorData()
    {
    }

    public static NDEFMessage getMessage() throws IOException
    {
        NDEFRecord titleRec = new NDEFRecord();
        titleRec.setId("1");
        titleRec.setType(NDEFRecord.TNF_WELL_KNOWN, "T"); 
        
        ByteArrayOutputStream payload1 = new ByteArrayOutputStream();
        payload1.write((byte) 0x05);             // Status byte - length of encoding
        payload1.write("en-US".getBytes("UTF-8"));      // Encoding
        payload1.write("My Title".getBytes("UTF-8"));   // Title
        payload1.flush();
        
        titleRec.setPayload(payload1.toByteArray());
        
        NDEFRecord uriRec = new NDEFRecord();
        uriRec.setId("2");
        uriRec.setType(NDEFRecord.TNF_WELL_KNOWN, "U");
        
        ByteArrayOutputStream payload2 = new ByteArrayOutputStream();
        payload2.write((byte) 0x01);                 // Abbreviation: http://www.
        payload2.write("blackberry.com".getBytes("UTF-8")); // URI
        payload2.flush();
        
        uriRec.setPayload(payload2.toByteArray());

        NDEFMessage ndefMessage = new NDEFMessage();
        ndefMessage.setRecords(new NDEFRecord[] {titleRec, uriRec});
        
        // root message with one record that has in payload a nested message in the form of bytes
        NDEFMessage rootMessage = new NDEFMessage();
        byte[] rootPayload = ndefMessage.getBytes();
        NDEFRecord rootRec = new NDEFRecord();
        rootRec.setType(NDEFRecord.TNF_WELL_KNOWN, "Sp");
        rootRec.setPayload(rootPayload);
        rootMessage.setRecords(new NDEFRecord[] {rootRec});
        
        return rootMessage;
    }
}

Implement the NDEF call-back interface

import net.rim.device.api.io.nfc.emulation.VirtualNDEFTagCallback;
import net.rim.device.api.ui.component.Dialog;

public class TagEmulatorCallback implements VirtualNDEFTagCallback
{

    public void onVirtualTargetEvent(int event) {
        switch(event)
        {
            case VirtualNDEFTagCallback.EMULATION_STOPPED:
                Dialog.alert("Emulation stopped.");
                break;
            case VirtualNDEFTagCallback.READER_LEFT:
                Dialog.alert("Smart tag reader moved out of range.");
                break;
            case VirtualNDEFTagCallback.SELECTED:
                Dialog.alert("This tag was selected by a smart tag reader.");
                break;
            case VirtualNDEFTagCallback.TARGET_READ:
                Dialog.alert("This tag was read by a smart tag reader.");
                break;
            case VirtualNDEFTagCallback.TARGET_UPDATED:
                Dialog.alert("A smart tag writer changed the contents of this tag.");				
                break;
        }
    }
}
Back To Top

Detecting NFC capability

The DeviceCapability class can help you determine whether a BlackBerry® device has an NFC radio, and whether the NFC feature is available.

Some reasons that the NFC feature could be unavailable include:
  • The user turned off the NFC radio
  • The NFC feature is disabled by an IT policy
  • Another application is using the NFC radio

You can use the DeviceCapability.isNFCSupported() method to determine whether the device has an NFC radio. The DeviceCapability.isNFCAvailable() method indicates whether the NFC feature is available for your application to use.

Back To Top

Detect NFC capability

  1. Import the required classes and interfaces.
    import net.rim.device.api.system.capability.DeviceCapability;
    import net.rim.device.api.ui.*;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.container.*;
  2. Declare your application class and start your application.
    public class NFCDemo extends UiApplication
    {
    
        public static void main(String[] args)
        {
            NFCDemo theApp = new NFCDemo();
            theApp.enterEventDispatcher();
        }
  3. In the constructor for your application, create a new screen object to control your virtual tag. Add your screen to the display stack.
        public NFCDemo()
        {
            pushScreen(new NFCPropertiesScreen());
        }
  4. Declare the screen class you use to display the status of the NFC feature.
        private class NFCPropertiesScreen extends MainScreen
        {
  5. In the constructor for your screen, set the title for your screen, and initialize two labels.
            public NFCPropertiesScreen()
            {
                setTitle("NFC Capability Reporter");
                LabelField lbl[] = new LabelField[2];
                lbl[0] = new LabelField();
                lbl[1] = new LabelField();
  6. Test whether the BlackBerry® device has an NFC Radio. Report the result to the user by setting the appropriate text in the first label.
                if(DeviceCapability.isNFCSupported())
                {
                    lbl[0].setText("supported true");
                } else
                {
                    lbl[0].setText("supported false");
                }
  7. Test whether the NFC feature is available. Report the result to the user by setting the appropriate text in the second label.
                if(DeviceCapability.isNFCAvailable())
                {
                    lbl[1].setText("available true");
                } else
                {
                    lbl[1].setText("available false");
                }
  8. Add the labels to your screen.
                add(lbl[0]);
                add(lbl[1]);
            }
        }
    }
Back To Top

Code sample: Detecting NFC capability

import net.rim.device.api.system.capability.DeviceCapability;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.*;


public class NFCDemo extends UiApplication
{

    public static void main(String[] args)
    {
        new NFCDemo().enterEventDispatcher();
    }

    public NFCDemo()
    {
        pushScreen(new NFCPropertiesScreen());
    }

    private class NFCPropertiesScreen extends MainScreen
    {
        public NFCPropertiesScreen()
        {
            setTitle("NFC Capability Reporter");
            LabelField lbl[] = new LabelField[2];
            lbl[0] = new LabelField();
            lbl[1] = new LabelField();
            if(DeviceCapability.isNFCSupported())
            {
                lbl[0].setText("supported true");
            } else
            {
                lbl[0].setText("supported false");
            }
            if(DeviceCapability.isNFCAvailable())
            {
                lbl[1].setText("available true");
            } else
            {
                lbl[1].setText("available false");
            }
            add(lbl[0]);
            add(lbl[1]);
        }
    }
}
Back To Top
Next topic: Glossary

Was this information helpful? Send us your comments.