Faster Data Transfer With Bluetooth and Contactless Communication

   
By Bruce Hopkins, July 2009  

Bluetooth technology allows two devices near each other to communicate at a maximum speed of 3 Mb per second. In the grand scheme of wireless communication, Bluetooth is roughly two times faster than the data throughput of a 3G wireless phone but still 10 to 20 times slower than today's Wi-Fi speeds.

More than one billion Bluetooth-enabled devices are currently on the market, and Bluetooth does a good job of transferring files that are smaller than 10 MB in size. However, due to the inherent nature of most wireless communication protocols, Bluetooth devices need to discover other Bluetooth devices, even if both devices are right next to each other. Finding a remote Bluetooth device is great, but what services does that remote Bluetooth device offer? If the remote device is a printer, does it offer the commonly used Basic Printing Profile (BPP) or the more advanced printing service known as the Hard Copy Cable Replacement Profile (HCRP)?

To find the available services on a remote Bluetooth device, you also need to search for a service. Bluetooth device-discovery and service-searching capabilities are great when you are trying to find any remote Bluetooth device in the vicinity that can suit your needs.

But device discovery and service searching are extremely time-consuming and frustrating to use when you're trying to communicate with a device that's right in front of you. This article shows you how to get Bluetooth applications to completely bypass the device-discovery and service-searching processes simply by using Near-Field Communication (NFC) technology and JSR 257: Contactless Communication API.

Contents
 
Introduction to NFC Technology
Introducing JSR 257: Contactless Communication API
Basic Bluetooth or NFC + Bluetooth: Which Is Faster?
Do Things Faster: Add NFC to the Picture
Conclusion
For More Information
 

Introduction to NFC Technology

What exactly is NFC technology? NFC is a radio communication standard that enables wireless data transfer between two devices at a very short distance -- less than 10 centimeters. NFC devices include a certain class of radio-frequency identification (RFID) tags and contactless smart cards. NFC devices operate within the 13.56 MHz frequency range, and they support extremely low data rates -- a maximum of 0.42 Mb per second.

Compared to Bluetooth and Wi-Fi, NFC technology operates at drastically reduced transfer rates and only within a very small proximity. If that's the case, why use NFC technology? Here are three reasons:

  • Setup time. NFC devices communicate instantly -- in less than 100 milliseconds -- when placed within range.
  • Power consumption. NFC tags and cards do not consume power, so their lifespan can be unlimited.
  • Cost. NFC tags and cards are inexpensive to manufacture compared to other wireless technologies.

NFC technology has easily met the need for certain use cases in the industry, such as the following:

  • Wireless payments. Traditional smart cards have been used for cashless payments for years. The short setup time for NFC devices allows mobile payments to be even easier.
  • Smart magazines and posters. Want to get more information about something you read in a magazine or see on a poster on the street? Just tap the page to get more information, or get the URL to store the bookmark for later use.
  • Transit tickets. When used in scenarios for mass transit, NFC-enabled phones are simple and convenient.
  • Business-card exchange. Because setup times for communication between NFC devices are very short, NFC devices are ideal for business-card exchanges.

Table 1 compares NFC with other wireless communication technologies.

Table 1: A Comparison of Wireless Communication Standards
 
International Standard
Operating Frequency
Maximum Data Rate
Maximum Distance
Power Consumption Rate
IEEE 802.15.1
2.4 GHz
22 Mb/s
100 m
hours/days
IEEE 802.15.1
2.4 GHz
3 Mb/s
100 m
days
NFC
ISO 14443
13.56 MHz
0.42 Mb/s
10 cm
Wi-Fi B
IEEE 802.11b
2.4 GHz
11 Mb/s
100 m
hours
Wi-Fi G
IEEE 802.11g
2.4 GHz
54 Mb/s
100 m
hours
Wi-Fi N
IEEE 802.11n
5 / 2.4 GHz
144 Mb/s
100 m
hours
IEEE 802.15.4
2.4 GHz
0.25 Mb/s
100-1200 m
months/years
 

As you can see, NFC technology is definitely not suited to transferring large amounts of data over long distances -- that is definitely a job for other wireless communication protocols such as any of the flavors of Wi-Fi.

But if you want to provide a small amount of information in a very short amount of time, then NFC may be for you. And a Java technology API is available that allows developers to interact with NFC devices: the JSR 257 API.

Introducing JSR 257: Contactless Communication API

JSR 257, the Contactless Communication API, is the Java ME API that allows mobile phones to communicate with a variety of devices within proximity. The Contactless Communication API allows your Java ME MIDlets to read and write data to the following entities:

  • External contactless smart cards
  • NFC tags
  • Generic RFIDs
  • 2D barcodes
  • Other NFC-capable phones
  • Internal secure element
 
Figure 1: Methods of Communication Through the JSR 257 API
 
 

The internal secure element pictured in Figure 1 is a secure device that allows an NFC-enabled mobile phone to behave as if it were a contactless smart card. For an in-depth explanation of the JSR 257 API and NFC technology, read the excellent article by C. Enrique Ortiz on this subject.

Basic Bluetooth or NFC + Bluetooth: Which Is Faster?

As stated in the introduction, the purpose of this article is to measure the performance improvement of Bluetooth file transfers by using NFC technology to bypass the lengthy processes of device discovery and service searching.

To compare the different approaches, look at the following two applications. Listing 1 is the code for a basic Bluetooth application called the BluetoothImageSender.java application, which reads an image from the MIDlet's own JAR file and sends the file to a Bluetooth device in the vicinity.

Listing 1. BluetoothImageSender.java Application
import java.util.*;
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.bluetooth.*;
import javax.microedition.io.file.FileConnection;
import javax.obex.*;

public class BluetoothImageSender extends MIDlet implements CommandListener{

        public Display display;
        public Form discoveryForm;
        public Form readyToConnectForm;
        public Form dataViewForm;
        public ImageItem mainImageItem;
        public Image mainImage;
        public Image bt_logo;
        public TextField addressTextField;
        public TextField subjectTextField;
        public TextField messageTextField;
        public Command selectCommand;
        public Command exitCommand;
        public Command connectCommand;
        public List devicesList;
        public Thread btUtility;
        public String btConnectionURL;
        public boolean readData = false;
        public long startTime = 0;
        public long endTime = 0;

        public BluetoothImageSender() {
        startTime = System.currentTimeMillis();

                display = Display.getDisplay(this);
                discoveryForm = new Form("Image Sender");

                try{
                        mainImage = Image.createImage("/btlogo.png");
            bt_logo = Image.createImage("/btlogo.png");
                } catch (java.io.IOException e){
                        e.printStackTrace();
                }
                mainImageItem = new ImageItem("Bluetooth Image Sender", mainImage, Item.LAYOUT_CENTER, "");
                discoveryForm.append(mainImageItem);
                discoveryForm.append("\nThis application will scan the area for Bluetooth devices and determine if any are offering OBEX services.\n\n");

                /// discoveryForm initialization

                exitCommand = new Command("Exit", Command.EXIT, 1);
                discoveryForm.addCommand(exitCommand);
                discoveryForm.setCommandListener(this);

                /// devicesList initialization

        devicesList = new List("Select a Bluetooth Device", Choice.IMPLICIT, new String[0], new Image[0]);
                selectCommand = new Command("Select", Command.ITEM, 1);
                devicesList.addCommand(selectCommand);
        devicesList.setCommandListener(this);
        devicesList.setSelectedFlags(new boolean[0]);

                /// readyToConnectForm initialization

                readyToConnectForm = new Form("Ready to Connect");
                readyToConnectForm.append("The selected Bluetooth device is currently offering a valid OPP service and is ready to connect. Please click on the 'Connect' button to connect and send the data.");
                connectCommand = new Command("Connect", Command.ITEM, 1);
                readyToConnectForm.addCommand(connectCommand);
                readyToConnectForm.setCommandListener(this);

                /// dataViewForm initialization

                dataViewForm = new Form("File Sending Progress");
                dataViewForm.append("Below is the status of the file sending process:\n\n");
                dataViewForm.addCommand(exitCommand);
                dataViewForm.setCommandListener(this);

    }


        public void commandAction(Command command, Displayable d) {
                if(command == selectCommand) {
                        btUtility.start();
                }
                if(command == exitCommand ) {
                        readData = false;
                        destroyApp(true);
                }
                if(command == connectCommand ) {
                        Thread filePusherThread = new FilePusher();
                        filePusherThread.start();
                        display.setCurrent(dataViewForm);
                }
        }


        public void startApp() {
        display.setCurrent(discoveryForm);
        btUtility = new BTUtility();

        }


        public void pauseApp() {

        }

        public void destroyApp(boolean b) {
                notifyDestroyed();
        }


////////////////

    /**
     * This is an inner class that is used for finding
     * Bluetooth devices in the vicinity.
     */
    class BTUtility extends Thread implements DiscoveryListener {

        Vector remoteDevices = new Vector();
        Vector deviceNames = new Vector();

        DiscoveryAgent discoveryAgent;

        // obviously, 0x1105 is the UUID for
        // the Object Push Profile
        UUID[] uuidSet = {new UUID(0x1105) };

        // 0x0100 is the attribute for the service name element
        // in the service record
        int[] attrSet = {0x0100};


        public BTUtility() {
            try {
                LocalDevice localDevice = LocalDevice.getLocalDevice();
                discoveryAgent = localDevice.getDiscoveryAgent();
                discoveryForm.append(" Searching for Bluetooth devices in the vicinity...\n");
                discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);

            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass cod) {
            try{
                   discoveryForm.append("found: " + remoteDevice.getFriendlyName(true));
            } catch(Exception e){
               discoveryForm.append("found: " + remoteDevice.getBluetoothAddress());
            } finally{
                   remoteDevices.addElement(remoteDevice);
                }
        }



        public void inquiryCompleted(int discType) {

            if (remoteDevices.size() > 0) {

                // the discovery process was a success
                // so out them in a List and display it to the user
                for (int i=0; i<remoteDevices.size(); i++){
                    try{
                       devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getFriendlyName(true), bt_logo);
                    } catch (Exception e){
                       devicesList.append(((RemoteDevice)remoteDevices.elementAt(i)).getBluetoothAddress(), bt_logo);
                    }
                }
                display.setCurrent(devicesList);
            } else {
                        // handle this
                }

        }


        public void run(){

            try {
                RemoteDevice remoteDevice = (RemoteDevice)remoteDevices.elementAt(devicesList.getSelectedIndex());
                discoveryAgent.searchServices(attrSet, uuidSet, remoteDevice , this);

            } catch(Exception e) {
                e.printStackTrace();
            }
        }



        public void servicesDiscovered(int transID, ServiceRecord[] servRecord){

            for(int i = 0; i < servRecord.length; i++) {

                DataElement serviceNameElement = servRecord[i].getAttributeValue(0x0100);
                String _serviceName = (String)serviceNameElement.getValue();
                String serviceName = _serviceName.trim();
                btConnectionURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                System.out.println(btConnectionURL);
            }
            display.setCurrent(readyToConnectForm);
            readyToConnectForm.append("\n\nNote: the connection URL is: " + btConnectionURL);

        }

        public void serviceSearchCompleted(int transID, int respCode) {

            if (respCode == DiscoveryListener.SERVICE_SEARCH_COMPLETED) {
                // the service search process was successful

            } else {
                // the service search process has failed
            }

        }

   }
////////////////

    /**
     * FilePusher is an inner class that
     * now gets the byte[] named file
     * to read the bytes of the file, and
     * then opens a connection to a remote
     * Bluetooth device to send the file.
     */

    class FilePusher extends Thread{

        FileConnection fileConn = null;
        String file_url = "/loginscreen.png";
        byte[] file = null;
        String file_name = "loginscreen.png";
        String mime_type = "image/png";

        // this is the connection object to be used for
        //  bluetooth i/o
        Connection connection = null;

        public FilePusher(){

        }



        public void run(){

            try{

                InputStream is = this.getClass().getResourceAsStream(file_url);
                ByteArrayOutputStream os = new ByteArrayOutputStream();

                // now read the file in into the byte[]
                int singleByte = 0;
                while(singleByte != -1){
                    singleByte = is.read();
                    os.write(singleByte);
                }

                System.out.println("file size: " + os.size());
                file = new byte[os.size()];
                file = os.toByteArray();

                dataViewForm.append("File name: " + file_url);
                dataViewForm.append("File size: " + file.length + " bytes");

                is.close();
                os.close();
            } catch (Exception e){
                e.printStackTrace();
                System.out.println("Error processing the file");
            }


            try{
                connection = Connector.open(btConnectionURL);
                // connection obtained

                // create a session and a headerset objects
                ClientSession cs = (ClientSession)connection;
                HeaderSet hs = cs.createHeaderSet();

                // establish the session
                cs.connect(hs);

                hs.setHeader(HeaderSet.NAME, file_name);
                hs.setHeader(HeaderSet.TYPE, mime_type); // be sure to note that this should be configurable
                hs.setHeader(HeaderSet.LENGTH, new Long(file.length));

                Operation putOperation = cs.put(hs);

                OutputStream outputStream = putOperation.openOutputStream();
                outputStream.write(file);
                // file push complete

                outputStream.close();
                putOperation.close();

                cs.disconnect(null);

                connection.close();

                dataViewForm.append("Operation complete. File transferred");

                endTime = System.currentTimeMillis();
                long diff = (endTime - startTime)/1000;
                System.out.println("Time to transfer file: " + diff);
                dataViewForm.append("Time to transfer file: " + diff);
            } catch (Exception e){
                System.out.println("Error sending the file");
                System.out.println(e);
                e.printStackTrace();
            }

        }

    }

}
       

Let's take a look at some features from the BluetoothImageSender.java application. First of all, the work and effort required to discover a remote Bluetooth device is contained in the inner class, BTUtility.

The Java Virtual Machine (JVM)* will call the deviceDiscovered() method to give you the details of each remote Bluetooth device that is near you. When the device-discovery process is completed, the JVM will invoke the inquiryCompleted() method to let you know that no other Bluetooth devices can be found.

For simplicity, the BluetoothImageSender.java application uses the inquiryCompleted() method to compose a List of Bluetooth devices found and to present that List to the user. Of course, if you're in a crowded area, and if everyone has set their mobile phones to be discoverable, then the device-discovery process will take a long time.

Once you've found the Bluetooth device that you want to communicate with, you also need to perform a service search on the device to see whether it supports the service or services that you need. Fortunately, the inner class BTUtility also handles that, so all of that functionality is wrapped up in a single class for you to use for your own projects. The result of the service-searching process is to determine the connection URL of the desired service. In this case, it's the Object Push Profile service.

Now that you've obtained the connection URL, you can use the other inner class, FilePusher, which allows you to send a file to any Bluetooth device that supports the Object Push Profile service -- that is, to nearly every Bluetooth-enabled phone on the planet.

Do Things Faster: Add NFC to the Picture

Let's take a look at the NFC-enabled file transfer application, NFCBluetoothImageSender.java. Because this application uses a majority of the functionality of BluetoothImageSender, let's look only at the differences between the applications.

Listing 2 shows the code for the inner class NFCDiscoveryUtility, which is used in place of BTUtility.

Listing 2. The Inner Class NFCDiscoveryUtility
    public class NFCDiscoveryUtility implements TargetListener, NDEFRecordListener {

        public NFCDiscoveryUtility() {

            try {
               DiscoveryManager discoveryManager = DiscoveryManager.getInstance();
               discoveryManager.addNDEFRecordListener(this, new NDEFRecordType(NDEFRecordType.MIME, "text/plain"));
            } catch (ContactlessException ce) {
                System.out.println("Error in adding listeners: " + ce.getMessage());
            } catch (Exception ce) {
                System.out.println("Error in adding listeners: " + ce.getMessage());
            }
        }


        public void targetDetected(TargetProperties[] targetProprties) {

            detectedTarget = targetProprties;
            discoveryForm.append("NFC target detected\n");
            System.out.println("NFC target detected");

        }


        public void recordDetected(NDEFMessage message) {

            System.out.println("NFC record detected");
            if (message != null) {

                NDEFRecord[] records = message.getRecords();
                if(records != null){
                    discoveryForm.append("NDEF Record Found\n");
                    btConnectionURL = new String(records[0].getPayload());
                    System.out.println("value: " + btConnectionURL);
                    display.setCurrent(readyToConnectForm);
                    readyToConnectForm.append("\n\nNote: the connection URL is: " + btConnectionURL);
                }else {
                    discoveryForm.append("No NDEF Record Found\n");
                }

            } else {
                discoveryForm.append("No NDEF message available\n");
            }

        }

    }
       

The NFCDiscoveryUtility is a simple helper class that abstracts and encapsulates some of the NFC-related functionality from the main MIDlet. As you can see, the application that I created will get a callback when the NFC radio detects an NFC RFID tag, but especially those with NFC Data Exchange Format (NDEF) records with text or plain MIME type.

The NFC classes in JSR 257 are very straightforward: When the handset detects a target -- whether it is a plain RFID tag, an NFC tag, a contactless smart card, or some other target type -- the JVM calls the targetDetected() method if you specified the appropriate target type with the DiscoveryManager. Additionally, you will get the recordDetected() callback when the NFC radio on this mobile device detects that the NFC tags are formatted with a text or plain MIME-typed NDEF record.

At this point, you have all the code need to detect an NFC tag and to be notified if that tag has the format that you are looking for. While you are in the recordDetected() callback, you can read the record from the NFC tag and get the Bluetooth connection URL.

Note: NFC tags require that the data on the tags be in NDEF format. The NFC tag can contain any binary data that you want. However, JSR 257 makes it easy for you if you want to leverage NDEF records to read and write data on NFC tags.

As you can see from Listing 2, NFCDiscoveryUtility reads the Bluetooth connection URL from the NFC tag. Now the NFC-enabled application is ready to send the image using the same FilePusher inner class that was used in Listing 1, the BluetoothImageSender.java application. Reading an NFC tag takes less than 100 milliseconds, so you've bypassed the lengthy setup process for Bluetooth nearly instantaneously.

Figure 2 shows the contents of the NFC tag for this example.

 
Figure 2: Contents of an NFC Tag Using the Nokia NFC Manager
 
 

Conclusion

This article has thoroughly established the fact that bypassing Bluetooth's setup time will save you a considerable amount of time when communicating with a device that's in your vicinity. However, what kind of performance improvements were we able to achieve?

In my testing, the total time to transfer a 50k file using standard Bluetooth device discovery and service searching is between 40 seconds, which is OK, and 90 seconds, which is terrible.

But the use of NFC technology reduced the total transfer time to 11 seconds -- that's roughly a 75 percent to 90 percent performance increase.

 

* As used on this web site, the terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform.

For More Information

An Introduction to Near-Field Communication and the Contactless Communication API, by C. Enrique Ortiz
Bluetooth for Java
Near-Field Communication (NFC)
JSR 257: Contactless Communication API

Rate This Article
 
 
Discussion

We welcome your participation in our community. Please keep your comments civil and on point. You can optionally provide your email address to be notified of replies—your information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.