Page Example

Contacts Exchanger Sample Overview

The Contacts Exchanger sample application demonstrates how you can share contact card details between 2 NFC (Near Field Communication) devices or through an NFC tag.

The following figure illustrates the main screens of the Contacts Exchanger.

Figure: Contacts Exchanger screens

Contacts Exchanger screens

The application opens with the main screen that shows your default contact card if you have already created one. To create a default contact card, click Create default card and select the default contact from your address book.

When the default contact card has been created, the following tasks are available:

  • To change the default contact, click Change your default contact and select a new contact form the address book.
  • To read contact data from an NFC tag, click Read from card and within 10 seconds place the device next to an NFC tag.
  • To write contact data to an NFC tag, click Write to card and within 10 seconds place the device next to an NFC tag.
  • To share the default contacts between 2 devices running the Contacts Exchanger application, click Communicate with another device on both devices, and within 10 seconds, place the devices next to each other.

Prerequisites

  • 2 NFC-enabled devices or 1 NFC-enabled device and 1 NFC tag

Source Files

You can create and view the sample application project including the source files in the IDE.

File name Description
config.xml This file contains the application information for the platform to install and launch the application, including the view mode and the icon to be used in the device menu.
index.html This is a starting file from which the application starts loading. It contains the layout of the application screens.
css/style.css This file contains the CSS styling for the application UI.
js/app.js This file defines the main application class.
js/app.ui.js This file handles the application UI.
js/app.config.js This file allows storing the configuration values.
js/app.ui.templateManager.js This file contains the TemplateManager class that manages, caches, and provides HTML templates.
js/app.nfc.js This file is the main controller for NFC communication.
js/app.nfc.card.js This file handles communication with the NFC tags.
js/app.nfc.peer.js This file handles communication between two peers with NFC on board.
lib/tau/ This directory contains the external libraries (TAU library).

Implementation

The Contacts Exchanger sample application defines the App class. The instance is created after the application starts.

/* app.js */
var App = null,
    app = null; /* App instance */

(function strict() 
{
   'use strict';

   App = function App() 
   {
      return;
   };
}());
app = new App();

When the whole DOM content is loaded, the init() method of the App class is called. It is responsible for the application initialization. The init() method:

  • Creates an object of the Config class which provides some important configuration data.
  • Creates an object of the App.Ui class which is responsible for the UI appearance and behavior.
  • Creates an object of the App.NFCControl class which provides the NFC API functionality for the application.
  • Calls the defineEvents() method of the App.Ui class to define the UI events and its handlers.
  • Calls the initAdressBook() of the App class which uses the Contact API to obtain information about the contacts defined on the device database.
/* app.js */
(function strict() 
{
   'use strict';

   App.prototype = 
   {
      init: function appInit() 
      {
         this.config = new Config();
         this.ui = new App.Ui(this);
         this.nfc = new App.NFCControl(this);
         this.ui.defineEvents();
         this.initAddressBook(this.nfc.turnOnNFC.bind(this.nfc));
      },
   }
}());

$(document).ready(app.init.bind(app));

The constructor of the App.NFCControl class calls its init() method. At the beginning the init() method calls the checkNfcCapabilities() method to check whether the NFC functionality is supported by device. Most importantly, the init() method creates the objects of App.NFCCard and App.NFCPeer class. They provide the key functionality related to NFC communication.

/* app.nfc.js */
(function strict() 
{
   'use strict';

   App.NFCControl = function NFCControl(app) 
   {
      this.app = app;
      this.init();
   };

   App.NFCControl.prototype = 
   {
      init: function nfc_init() 
      {
         this.checkNfcCapabilities();
         this.card = new App.NFCCard(this);
         this.peer = new App.NFCPeer(this);
         this.endOfText = String.fromCharCode(3);
      },
   }
}());

The checkNfcCapabilities() method of App.NFCControl class uses the System Information API to check whether the NFC functionality is supported by device. If NFC is not supported, the application displays a warning and after confirmation closes automatically.

/* app.nfc.js */
(function strict() 
{
   'use strict';

   App.NFCControl.prototype = 
   {
      checkNfcCapabilities: function nfc_checkNfcCapabilities() 
      {
         var isNfcSupported,
             self = this;

         try 
         {
            isNfcSupported = tizen.systeminfo.getCapabilities().nfc;
         } 
         catch (err) 
         {
            console.error('nfc_checkNfcCapabilities: ', err.message);
            isNfcSupported = false;
         }
         if (!isNfcSupported) 
         {
            setTimeout(function notSupportedWarning() 
            {
               self.app.ui.showPopupWarning('NFC is not supported on ' +
               'your device. Application will be closed.');
            }, 500);
         }
      },
   }
}());

The App.NFCCard class provides functionality that allows application to exchange contacts data between the NFC device and the NFC tag. The details of the functionality are described in the following code snippets.

/* app.nfc.card.js */
(function strict() 
{
   'use strict';

    App.NFCCard = function nfc_NFCCard(nfc) 
   {
      this.nfc = nfc;
   };
}());

When the user clicks the Read from card button, the application calls the setTagDetectRead() method from the App.NFCCards class. This method uses the setTagListener() method from the NFC API to define what should be done when the NFC tag is placed next to the NFC device. In this case, the sucTagReadAttach() method from the App.NFCCard class is called. The sucTagReadAttach() method takes the NFCTag type parameter and uses it to call the readNDEF() method from the NFC API. The readNDEF() method takes two callbacks (in case of success or failure) as parameters. In case of success the application calls the readMessage() function from the App.NFCControl class. Depending on the results, the interface of the application is updated accordingly.

/* app.nfc.card.js */
(function strict() 
{
   'use strict';

   App.NFCCard.prototype = 
   {
      sucTagReadAttach: function nfc_card_sucTagReadAttach(tag) 
      {
         try 
         {
            if (!tag.isSupportedNDEF) 
            {
               throw 
               {
                  message: 'This tag doesn\'t support NDEF'
               };
            }
            tag.readNDEF(this.nfc.readMessage.bind(this.nfc),
                         this.readMessageErr.bind(this));
         } 
         catch (e) 
         {
            this.readMessageErr(e);
         }
      },

       setTagDetectRead: function nfc_card_setTagDetectRead() 
      {
         try 
         {
            this.nfc.nfcAdapter.unsetTagListener();
            this.nfc.nfcAdapter.setTagListener(
            {
               onattach: this.sucTagReadAttach.bind(this),
               ondetach: this.nfc.sucDetach.bind(this.nfc)
            });
         } 
         catch (error) 
         {
            this.readMessageErr(error);
         }
      },
   }
}());

The readMessage() function from the App.NFCControl class takes the NDEFMessages type parameter and uses it to update the application data and the UI.

/*app.nfc.js */
(function strict() 
{
   'use strict';

   App.NFCControl.prototype = 
   {
      readMessage: function nfc_readMessage(message) 
      {
         try 
         {
            this.fillRecordInfo(message.records[0]);
         } 
         catch (err) 
         {
            console.error('nfc_readMessage: ', err.message);
         }
      },
   };
}());

When the user clicks the Write to card button, the application calls the setTagDetectWrite() method from the App.NFCCard class. This method uses the setTagListener() method from the NFC API to define what should be done when the NFC tag is placed next to the NFC device. In this case, the sucTagWriteAttach() method from the App.NFCCard class is called. The sucTagWriteAttach() method takes the NFCTag type parameter and uses it to call the writeNDEF() method from the NFC API. The writeNDEF() method takes as parameters the previously prepared message (with contacts data) and two callbacks (in case of success or failure). Depending on the results, the interface of the application is updated accordingly.

/* app.nfc.card.js */
(function strict() 
{
   'use strict';

   App.NFCCard.prototype = 
   {
      sucTagWriteAttach: function nfc_card_sucTagWriteAttach(tag) 
      {
         var newMessage = null,
             fullContact = '';

         try 
         {
            fullContact = this.nfc.prepareForNFC(localStorage);
            newMessage = this.nfc.phoneNumber2NDEF(fullContact);
            if (!tag.isSupportedNDEF) 
            {
               throw 
               {
                  message: 'This tag doesn\'t support NDEF'
               };
            }
            tag.writeNDEF(newMessage, this.sucSend.bind(this), this.errSend.bind(this));
         } 
         catch (e) 
         {
            this.errSend(e);
         }
      },

      setTagDetectWrite: function nfc_card_setTagDetectWrite() 
      {
         var suc = 
         {
            onattach: this.sucTagWriteAttach.bind(this),
            ondetach: this.nfc.sucDetach.bind(this.nfc)
         };

         try 
         {
            this.nfc.nfcAdapter.unsetTagListener();
            this.nfc.nfcAdapter.setTagListener(suc);
         } 
         catch (error) 
         {
         console.error(error);
         }
      }
   }
}());

The App.NFCPeer class provides functionality that allows the application to exchange contacts data between two NFC devices. The details of the functionality are described in the following code snippets.

/* app.nfc.peer.js */
(function strict() 
{
   'use strict';

   App.NFCPeer = function NFCPeer(nfc) 
   {
      this.nfc = nfc;
   };
}());

When the user clicks the Communicate with another device button, the application calls the setTargetDetect() method from the App.NFCPeer class. This method uses setPeerListener() method from the NFC API to define what should be done when the NFC device is placed next to the other NFC device. In this case, the sucTargetAttach() method from the App.NFCPeer class is called. The sucTargetAttach() method takes the NFCPeer type parameter and uses it to call two other methods from the NFC API (sendNDEF() and setReceiveNDEFListener()). The sendNDEF() method takes as parameters the previously prepared message (with contacts data) and two callbacks (in case of success or failure). Depending on the results of the sendNDEF() method, the interface of the application is updated accordingly. The setReceiveNDEFListener() method allows the application to read the message (with contacts data) sent by another device. It takes the readMessage() method from the App.NFCControl class to update application UI (this method was previously mentioned).

/* app.nfc.peer.js */
(function strict() 
{
   'use strict';

   App.NFCPeer.prototype = 
   {
      setReceiveFromTarget: function nfc_peer_setReceiveFromTarget() 
      {
         try 
         {
            if (!this.nfc.nfcTarget)
            {
               console.warn('app.nfc.nfcTarget not set');

               return;
            }
            this.nfc.nfcTarget.unsetReceiveNDEFListener();
            this.nfc.nfcTarget.setReceiveNDEFListener(
            this.nfc.readMessage.bind(this.nfc));
         } 
         catch (error) 
         {
            console.error('setReceiveFromTarget error: ' + error.message);
         }
      },

      sucTargetAttach: function nfc_peer_sucTargetAttach(target) 
      {
         var newMessage = null,
             fullContact = this.nfc.prepareForNFC(localStorage);
         this.nfc.nfcTarget = target;
         this.setReceiveFromTarget();

         try 
         {
            newMessage = this.nfc.phoneNumber2NDEF(fullContact);
            target.sendNDEF(newMessage, this.sucSendToTarget.bind(this), this.errSendToTarget.bind(this));
         } 
         catch (e) 
         {
            console.error('NDEFMessage problem: ' + e.message);
         }
      },

      setTargetDetect: function nfc_peer_setTargetDetect() 
      {
         var successCallbacks = 
         {
            onattach: this.sucTargetAttach.bind(this),
            ondetach: this.nfc.sucDetach.bind(this.nfc)
         };

         try 
         {
            this.nfc.nfcAdapter.unsetPeerListener();
            this.nfc.nfcAdapter.setPeerListener(successCallbacks);
         } 
         catch (error) 
         {
            console.error(error.message);
         }
      }
   }
}());