Page Example

Bluetooth Chat Sample Overview

The Bluetooth Chat sample application demonstrates how you can create a chat application that uses a Bluetooth connection for sending messages.

The following figure illustrates the main screens of the Bluetooth Chat.

Figure: Bluetooth Chat screens

Bluetooth Chat screens

The application opens with the Bluetooth chat main screen. If Bluetooth is disabled, the Turn bluetooth on button appears and you must click it before you can create or join a server.

On the main screen:

  • To use your device as a chat server, click Create server. Enter the server name and click OK to start the server. When a client wants to join your chat, accept their passkey by clicking Yes, and then allow their connection by clicking Yes again.

    Remember that to be a server, you must make your Bluetooth radio visible.

  • To join a chat as a client, click Join server. Enter your client name, select the correct server from the list, and click OK to accept the passkey to confirm the connection to the server.

On the chat screen, you can see the messages from other participants. To write your own messages, enter the message and click Send.

Prerequisites

  • Target device (the Emulator does not support Bluetooth functions)
  • Peer device with which to connect

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.
js/app.client.js This file contains the code for handling the client functionality of the application.
js/app.client.model.js This file handles the data used by the client part of the application.
js/app.config.js This file allows storing the configuration values.
js/app.helpers.js This file contains the helper functions used by the application.
js/app.js This file defines the main application class.
js/app.model.js This file handles the data used by the common part of the application.
js/app.server.js This file contains the code for handling the server functionality of the application.
js/app.server.model.js This file handles the data used by the server part of the application.
js/app.ui.events.js This file handles the user interface events.
js/app.ui.js This file handles the application UI.
js/app.ui.templateManager.js This file contains the TemplateManager class, which manages, caches, and provides HTML templates.
js/main.js This file starts the application.
lib/tau/ This directory contains the external libraries (TAU library).

Implementation

The implementation of Bluetooth communication can be split into three parts:

  1. Bluetooth device management implementation
  2. Server side implementation
  3. Client side implementation

Bluetooth Device Management Implementation

The functionality of the Bluetooth device management module can be implemented as a JavaScript class:

/* app.model.js */
function Model() 
{
   'use strict';
   this.adapter = null;
   this.serviceUUID = '5BCE9431-6C75-32AB-AFE0-2EC108A30860';
}

(function strict() 
{
   'use strict';
   Model.prototype = 
   { 
      init: function Model_init(callback) 
      {
         (...)
      },

      powerOn: function Model_powerOn(callback) 
      {
         (...)
      },

      powerOff: function Model_powerOff(callback) 
      {
         (...)
      },

      setAdapterName: function Model_setAdapterName(changeName, callback) 
      {
         (...)
      }
   };
}());

The prototype of the class has the following functions:

  • init – initializes the bluetooth module.
  • powerOn – turns on the module.
  • powerOff – turns off the module.
  • setAdapterName – sets bluetooth device name.

There are also defined two private variables:

  • adapter – a reference to the Bluetooth adapter object obtained from Bluetooth API.
  • serviceUUID – a unique string identifying the Bluetooth service.

The constructor of this class defines the serviceUUID string variable that is a unique Bluetooth service identifier.

The init function obtains the default Bluetooth adapter and registers a state change listener on it. The listener gives a notification that the connection is lost by calling app.connectionLost() when the adapter is powered off and there is no operation in progress.

If initialization fails, the suitable alert appears and the application closes.

/* app.model.js */
init: function Model_init(callback) 
{
   try 
   {
      if (tizen.bluetooth === undefined) 
      {
         throw new ReferenceError('tizen.bluetooth is not available');
      }
      this.adapter = tizen.bluetooth.getDefaultAdapter();

      this.adapter.setChangeListener(
      {
         onstatechanged: function onAdapterStateChanged(powered) 
         {
            if (!powered) 
            {
               /* Notify that the connection is lost */
            }
         }
      });

      callback();
   } 
   catch (error) 
   {
      /* Shows the caught error */
      tizen.application.getCurrentApplication().exit();
   }
}

The powerOn function turns on the Bluetooth device if it is turned off. After that the callback function is executed.

/* app.model.js */
powerOn: function Model_powerOn(callback) 
{
   if (!this.adapter.powered) 
   {
      try 
      {
         this.adapter.setPowered(true, function onAdapterPowerOnSuccess() 
         {
            /* Notify UI that the adapter is on */
            callback();
         },

         function onAdapterPowerOnError() 
         {
            this.operationInProgress = false;
         });
      } 
      catch (error) 
      {
          /* Handle the error */
      }
   } else 
   {
      callback();
   }
}

The powerOff function turns off the Bluetooth device if it was turned on. After that the given callback is called.

/* app.model.js */
powerOff: function Model_powerOff(callback) 
{
   if (this.adapter.powered) 
   {
      this.adapter.setPowered(false, function onAdapterPowerOffSuccess() 
      {
         callback();
      },

      function onAdapterPowerOffError() 
      {
         callback();
      });
   } 
   else 
   {
      callback();
   }
}

The setAdapterName function sets the Bluetooth device name as provided by the input parameter.

/* app.model.js */
setAdapterName: function setAdapterName(name, onSuccess) 
{
   this.adapter.setName(name, onSuccess);
}

Server Side Implementation

The server side functionality can be implemented as a JavaScript class:

/* app.server.model.js */
/* Constructor */
function ServerModel(parent) 
{
   'use strict';
}

(function strict() 
{
   'use strict';
   ServerModel.prototype = 
   {
      registerServer: function ServerModel_registerServer(adapter, serviceUUID, callback) {},

      unregisterChatServer: function ServerModel_unregisterChatServer(globalRecordHandler, successCallback, 
                                                                      errorCallback, showButtonsCallback) {},

      sendMessage: function ServerModel_sendMessage(name, socket, message, callback) {}
   };

}());

The prototype of the class has the following functions:

  • registerServer – turns on the server and makes it visible.
  • unregisterChatServer – turns off the server.
  • sendMessage – sends a message to the client.

The registerServer function calls the registerRFCOMMServiceByUUID method from the Bluetooth API in order to register a service record in the device service record database. After this method is successfully executed, the callback function is called with the service handler as an input parameter.

/* app.server.model.js */
registerServer: function ServerModel_registerServer(adapter, serviceUUID, callback) 
{
   try 
   {
      adapter.registerRFCOMMServiceByUUID(serviceUUID, 'Chat service', callback,

      function onregisterRFCOMMServiceError(error) 
      {
         console.error(error.message);
      });
   } 
   catch (error) 
   {
      console.error(error.message);
   }
}

If any remote device tries to connect to this service, the onconnect function held in the service handler object is called. Therefore, the onconnect function needs to be implemented to handle the connections. The following code illustrates the implementation of the registerServer function.

As shown below, the onconnect function is a callback that gets a socket object as an input parameter. There are several callback functions that can be added to the socket object to handle socket events. The following code demonstrates how to add functions to receive a message from the client (onmessage), to handle connection errors (onerror), and to handle closing the socket (onclose).

/* app.server.js */
registerServerSuccess: function Server_registerServerSuccess(recordHandler) 
{
   recordHandler.onconnect = function onServerSocketConnect(socket) 
   {
      socket.onmessage = function onServerSocketMessage() 
      {
         var data, (...);
         data = socket.readData();
         /* Here is code parsing a client message and handling it */
      };
      socket.onerror = function onServerSocketError() 
      {
         /* Handle error event */
      };
      socket.onclose = function onServerSocketClose() 
      {
         /* Handle close socket event */
      };
   };
}

The unregisterChatServer function unregisters the service identified by the record handler.

/* app.server.model.js */
unregisterChatServer: function ServerModel_unregisterChatServer(globalRecordHandler, successCallback, errorCallback) 
{
   try 
   {
      globalRecordHandler.unregister(successCallback, errorCallback);
   } 
   catch (error) 
   {
      errorCallback(error);
   }
}

The sendMessage function encodes the specified message and writes it to the socket.

/* app.server.model.js */
sendMessage: function ServerModel_sendMessage(name, socket, message, callback) 
{
   /* Create a JSON message from input parameters, encode it */
   /* and change to an array of chars - sendTextMsg */
   
   try 
   {
      if (socket !== null && socket.state === 'OPEN') 
      {
         socket.writeData(sendTextMsg);
         callback(message);
      }
   } 
   catch (error) 
   {
      console.error('sendMessage: ' + error.message);
   }
}

Client Side Implementation

The client side functionality can be implemented as a JavaScript class:

/* app.client.model.js */
function ClientModel(parent) 
{
   'use strict';

   /* Allows communicating with other models of the application */
   this.client = parent;
}

(function strict() 
{
   'use strict';

   ClientModel.prototype = 
   {
      searchServer: function ClientModel_searchServer() {},
      stopServerSearching: function ClientModel_stopServerSearching(callback) {},
      startBonding: function ClientModel_startBonding(address, callback) {},
      destroyBonding: function ClientModel_destroyBonding(device, restartCallback) {},
      connectToService: function ClientModel_connectToService(device, serviceUUID,
                                                              successCallback, errorCallback) {},
      sendMessage: function ClientModel_sendMessage(name, socket, message, callback) {}
   };
}());

Prototype of the class has the following functions:

  • searchServer – Searches Bluetooth devices.
  • stopServerSearching – Stops searching.
  • startBonding – Ask the specified Bluetooth device to bond.
  • destroyBonding – Destroys bonding.
  • connectToService – Connects to the service on the bonded device.
  • sendMessage – Sends a message to the connected server.

The constructor of this class gets the parent object as an input parameter. This object allows communicating with other modules of the application. The full implementation of the object is in the app.client.js file. For the purposes of this guide there is only needed to show the initialization of the adapter variable in the controller class:

/* app.model.js */
this.adapter = tizen.bluetooth.getDefaultAdapter();

This is the adapter variable from the app.model.js. This variable is passed to app.client.js after initialization.

The searchServer function defines the set of callback functions and passes it to the adapter.discoverDevices function of the Bluetooth API.

/* app.client.model.js */
/* Starts server searching */
searchServer: function ClientModel_searchServer() 
{
   var discoverDevicesSuccessCallback = 
   {
      onstarted: function onDevicesDiscoverStarted() 
      {
         /* Handle searching started event */
      },
      ondevicefound: function onDeviceFound(device) 
      {
         /* Handle device found event */
      },
      ondevicedisappeared: function onDeviceDisappeared() 
      {
         /* Handle device disappeared event */

         return;
      },
      onfinished: function onDevicesDiscoverFinished() 
      {
         /* Handle searching finished event */
      }
   };
   this.client.adapter.discoverDevices(discoverDevicesSuccessCallback, function onDiscoverDevicesError() 
   {
      /* Handle searching error */
   });
}

The stopServerSearchings stops the searching by calling the adapter.stopDiscovery function of the Bluetooth API. When operation succeeds the given callback is executed.

/* app.client.model.js */
stopServerSearching: function ClientModel_stopServerSearching(callback) 
{
   this.client.adapter.stopDiscovery(function onStopDiscovery() 
   {
      /* Handle stop searching succeeded */
      callback();
   }
   .bind(this), function onStopDiscoveryError(e) 
   {
      console.error('Error while stopDiscovery:' + e.message);
   });
}

To connect to a found Bluetooth device it is necessary to bond with this device. Bonding is implemented in the following function. The function gets an address of the device and a success callback as input parameters. The address can be obtained by calling the searchServer function described above.

/* app.client.model.js */
startBonding: function ClientModel_startBonding(address, callback) 
{
   this.client.adapter.createBonding(address, function onCreateBondingSuccess(device) 
   {
      callback(device);
   },

   function onCreateBondingError(error) 
   {
      console.error('bondError: ' + error.message);
   });
}

The destroyBonding function gets a device object and a success callback as input parameters. It destroys bonding by executing the adapter.destroyBonding function from the Bluetooth API and executes the given success callback when the operation succeeds.

/* app.client.model.js */
destroyBonding: function ClientModel_destroyBonding(device, successCallback) 
{
   if (device.isBonded) 
   {
      this.client.adapter.destroyBonding(device.address, successCallback, function onDestroyBondingError(error) 
      {
         console.error('ClientModel_destroyBonding: ' + error);
      });
   } 
   else 
   {
      successCallback();
   }
}

When the devices are bonded, it is possible to make a connection with a service identified by the UUID string. The connectToService function makes such connection. The function takes a device object, UUID string and callbacks as input parameters. In order to make a connection the connectToServiceByUUID method is called on the device object.

When the operation succeeds, the success callback is executed with a socket object passed as an input parameter. Otherwise an error callback is executed.

/* app.client.model.js */
connectToService: function ClientModel_connectToService(device, serviceUUID, successCallback, errorCallback) 
{
   try 
   {
      device.connectToServiceByUUID(serviceUUID, successCallback, errorCallback);
   } 
   catch (error) 
   {
      console.error('connectToServiceByUUID ERROR: ' + error.message);
      errorCallback();
   }
}

After executing the connection to the service, the socket element can be accessed. It is possible to send and receive messages using this socket. The following function illustrates how to send a message to the server:

/* app.client.model.js */
sendMessage: function ClientModel_sendMessage(name,  socket, message, callback) 
{
   /* Create a JSON message from input parameters, encode it */
   /* and change to an array of chars - sendTextMsg */
   try 
   {
      if (socket !== null && socket.state === 'OPEN') 
      {
         socket.writeData(sendTextMsg);
         callback(message);
      }
   } 
   catch (error) 
   {
      console.error('sendMessage: ' + error.message);
   }
}

In order to receive events from the socket, a bunch of callbacks need to be implemented. These callbacks must be added to the socket element as its fields. The following code illustrates a success callback function passed to the connectToService function discussed above. This function gets a socket element and adds three callbacks to it:

  • onmessage, receiving a message from the server.
  • onerror, handling errors.
  • onclose, handling socket close event.
/* app.client.js */
connectToServiceSuccess:
function Client_connectToServiceSuccess(device, socket) 
{
   /* Callback function receiving a message */
   socket.onmessage = function onSocketMessage() 
   {
      var data, recvmsg = '', i, len, messageObj;
      data = socket.readData();
      len = data.length;
      for (i = 0; i < len; i += 1) 
      {
         recvmsg += String.fromCharCode(data[i]);
      }
      messageObj = JSON.parse(recvmsg);
      /* Utilize received and parsed JSON message */
   };
    
   /* Callback function handling errors */
   socket.onerror = function onSocketError() 
   {
      console.error('Client onerror');
      socket.close();
   };
    
   /* Callback function handling socket close event */
   socket.onclose = function onSocketClose() 
   {
      /* Handle event */
   };
}

The onmessage callback reads and parses messages received from the socket using the socket.readData() function provided by the Bluetooth API.

The onerror callback closes the socket using the socket.close() function provided by the Bluetooth API.