Wearable Web

SAP

To establish connections and exchange data between mobile and accessory devices, you can use the SAP (Samsung Accessory Protocol) API. The SAP-enabled devices can share string messages and files.

The Samsung Accessory (SA) service consists of the following entities:

  • Samsung accessory agent

    The SA agent manages the connection set-up and the exchange of data with remote accessory peer agents. It is the main interface between the Samsung Accessory Service Framework and applications. The SA agent can be either a service provider or consumer, as defined in the accessory service profile specification.

  • Accessory peer agent

    The remote accessory peer agent communicates with the SA agent. It includes information about the peer agent and the accessory device on which the peer agent runs.

The main features of the SAP API include:

  • Defining the accessory service profile

    To use the SAP to communicate with other applications, you must define an accessory service profile in an XML file for your application. The profile specifies the communication details, such as the transport type, service channel, and application name.

  • Setting up a connection

    You can establish a connection with a remote accessory peer agent.

  • Enabling automatic launching

    You can enable your application to be automatically launched if a peer agent application requests a connection while your application is not running.

  • Exchanging simple data (string) messages

    You can exchange string messages between the service provider and consumer.

  • Exchanging files

    You can exchange files between the service provider and consumer.

  • Closing the connection

    You can close the connection between the service provider and consumer.

  • Exchanging Messages

    The Samsung Accessory Message Exchange Protocol service allows sending data without need of any service connection.

Accessory Service Profile

The accessory service profile information is provided in an XML file, such as /res/xml/<profile_name>.xml. You must declare the profile XML file path in the config.xml file of your Web application project:

  • In a Web application:
    <tizen:metadata key="AccessoryServicesLocation" value="res/xml/serviceprofile.xml"/>
    
  • In a Web widget application:
    <tizen:widget-metadata key="AccessoryServicesLocation" value="widget/res/xml/serviceprofile.xml"/>
    
    Note
    The Web widget applications are supported since Tizen 2.3.2.

The following example illustrates the content of the profile XML file, which specifies the accessory service profile details. For more information, see the SAAgent API.

<resources>
   <application name = "my application"> 
      <serviceProfile role = "provider" 
                      name = "smartview"  
                      id = "/sample/gallery" 
                      version = "1.0"
                      serviceLimit = "ONE_PEERAGENT"
                      serviceTimeout = "30">
         <supportedTransports>
            <transport type = "TRANSPORT_BT"/>
            <transport type = "TRANSPORT_WIFI"/>
         </supportedTransports>
         <serviceChannel id = "100"   
                         dataRate = "high"
                         priority = "low"
                         reliability = "enable"/>
      </serviceProfile>
      <serviceProfile role = "provider" 
                      name = "message_service_provider"  
                      id = "/sample/messages" 
                      version = "1.0"
                      autoLaunchAppId = "VcGvmQlo1i.HelloAccessory"
                      serviceLimit = "ANY">
         <supportedTransports>
            <transport type = "TRANSPORT_BT"/>
            <transport type = "TRANSPORT_WIFI"/>
         </supportedTransports>
         <serviceChannel id = "902"   
                         dataRate = "low"
                         priority = "low"
                         reliability = "disable"/>
      </serviceProfile>
   </application>
</resources>

The following attributes and elements are used in the profile XML file:

  • role attribute: provider or consumer.

    You can implement multiple service providers and consumers in 1 application. In that case, declare multiple <serviceProfile> elements inside the <application> element.

  • name attribute: Friendly name for the service provider or consumer.
  • id attribute: Service profile ID of the service provider or consumer.
  • version attribute: Service profile specification version that the service provider or consumer implements.
  • autoLaunchAppId attribute: Application ID of the application that is invoked by an incoming service connection request.

    If a peer agent requests a service connection to a service profile which is not running, the system launches this application. If the value is not specified, the system never launches the application even if the peer agent requests a service connection.

  • serviceLimit attribute: Number of peer agents you want to be connected with at the same time.

    If a peer agent requests a connection with your application after you have reached the limit, the Samsung Accessory Service Framework rejects the connection request. The value can be:

    • ONE_PEERAGENT: supports only 1 peer agent.
    • ONE_ACCESSORY: supports only 1 accessory device, but can have connections to multiple peer agents on that accessory device.
    • ANY (default): supports multiple peer agents on multiple devices.
  • serviceTimeout attribute: Timeout for handling incoming connection requests.

    The application can decide immediately whether to accept or reject an incoming connection request. Or the decision can take longer, for example, if you need to connect to a cloud server, ask for user permission, or ask for authentication. If the application takes a long time to make the decision, set this value accordingly. If the application exceeds the timeout, the requesting peer agent gets the response stating that the connection failed because your application gave no response.

  • <supportedTransports> element: Transports the service provider or consumer is able to operate on. Currently, the Samsung Accessory Service Framework supports the following transport types:
    • TRANSPORT_WIFI
    • TRANSPORT_BT
    • TRANSPORT_BLE
    • TRANSPORT_USB

    If the service provider or consumer supports multiple transport types, declare multiple <transport> elements.

  • <serviceChannel> element: Details of the channel used for the connection. It has the following attributes:
    • id attribute: Service channel ID.
    • dataRate attribute: low or high.
    • priority attribute: low, medium, or high.
    • reliability attribute: enable or disable.

    This attribute defines whether you want a reliable transfer. In case of a packet drop, a reliable transfer re-transmits the packet (but also creates additional overhead).

The following example illustrates the document type definition for the profile XML file.

<!DOCTYPE resources
[
   <!ELEMENT resources (application)>
   <!ELEMENT application (serviceProfile)+>
   <!ELEMENT serviceProfile (supportedTransports, serviceChannel+) >
   <!ELEMENT supportedTransports (transport)+>
   <!ELEMENT transport EMPTY> 
   <!ELEMENT serviceChannel EMPTY> 
   <!ATTLIST application name CDATA #REQUIRED>
   <!ATTLIST serviceProfile role (PROVIDER | CONSUMER | provider | consumer) #REQUIRED>
   <!ATTLIST serviceProfile name CDATA #REQUIRED>
   <!ATTLIST serviceProfile id CDATA #REQUIRED>
   <!ATTLIST serviceProfile version CDATA #REQUIRED>
   <!ATTLIST serviceProfile autoLaunchAppId CDATA #IMPLIED>
   <!ATTLIST serviceProfile serviceLimit (ANY | ONE_ACCESSORY | ONE_PEERAGENT | 
                                          any | one_accessory | one_peeragent) #IMPLIED>
   <!ATTLIST serviceProfile serviceTimeout CDATA #IMPLIED>
   <!ATTLIST transport type (TRANSPORT_WIFI | TRANSPORT_BT | TRANSPORT_BLE |  
                             TRANSPORT_USB | transport_wifi | transport_bt | transport_ble | 
                             transport_usb) #REQUIRED>
   <!ATTLIST serviceChannel id CDATA #REQUIRED>
   <!ATTLIST serviceChannel dataRate (LOW | HIGH | low | high) #REQUIRED>
   <!ATTLIST serviceChannel priority (LOW | MEDIUM | HIGH | low | medium | high) #REQUIRED>
   <!ATTLIST serviceChannel reliability (ENABLE | DISABLE | enable | disable) #REQUIRED>
]>

Setting up a Connection

Learning how to request Samsung Accessory (SA) agents and connect to remote peer agents is a basic SAP management skill:

  1. To get the SA agent specified in an accessory service profile, use the requestSAAgent() method:
    var SAAgent;
    function onsuccess(agents) 
    {
       SAAgent = agents[0];
       for (var i = 0; i < agents.length; i++) 
       {
          console.log(i + ". " + agents[i].name);
          /* Process the SA agents */
       }
    }
    
    webapis.sa.requestSAAgent(onsuccess, onerror);
    
  2. Define an event handler for peer device status notifications using the SADeviceStatusCallback listener interface, and set the listener to the SAAgent object. This handler is used to notify the user when the host and Tizen wearable devices are disconnected (DETACHED) or connected (ATTACHED).
    Note
    When the status changes to ATTACHED, you must call the findPeerAgents() method to establish a new SA socket connection.
    function ondevicestatus(type, status)
    {
       if (status == "ATTACHED")
       {
          console.log("Attached remote peer device: " + type);
          SAAgent.findPeerAgents();
       }
       else if (status == "DETACHED")
       {
          console.log("Detached remote peer device: " + type);
       }
    }
    
    webapis.sa.setDeviceStatusListener(ondevicestatus);
    
  3. Define an event handler for connection event notifications using the ServiceConnectionCallback listener interface:
    var SASocket;
    var connectioncallback = 
    {
       /* Remote peer agent requests a service connection */
       onrequest: function(peerAgent)
       {
          if (peerAgent.appName == "expected app name") 
          {
             SAAgent.acceptServiceConnectionRequest(peerAgent);
          } 
          else 
          {
             SAAgent.rejectServiceConnectionRequest(peerAgent);
          }
       },
    
  4. To authenticate the peer agent requesting a service connection, use the authenticatePeerAgent() method.

    The success event handler of the method receives the SAAuthenticationToken object containing an authentication key for the peer agent.

    Note
    The authenticatePeerAgent() method is provided since the SAP API version 2.2.1.1. To support the API version 2.2.1 or below, check the existence of the method before using it.
       onrequest: function(peerAgent)
       {
          if (typeof(SAAgent.authenticatePeerAgent) === 'function') 
          {
             SAAgent.authenticatePeerAgent(peerAgent, function(peerAgent, authToken) 
             {
                /* Authentication token of peer agent arrives */
                if (authToken.key == "expected key string (BASE64)") 
                {
                   SAAgent.acceptServiceConnectionRequest(peerAgent);
                } 
                else 
                {
                   SAAgent.rejectServiceConnectionRequest(peerAgent);
                }
             },
             function(e) 
             {
                /* Error handling */
                SAAgent.rejectServiceConnectionRequest(peerAgent);
             });
          } 
          else 
          {
             if (peerAgent.appName === 'expected app name') 
             {
                SAAgent.acceptServiceConnectionRequest(peerAgent);
             } 
             else 
             {
                SAAgent.rejectServiceConnectionRequest(peerAgent);
             }
          }
       },
       /* Connection between provider and consumer is established */
       onconnect: function(socket)
       {
          SASocket = socket;
       }
    }
       
    SAAgent.setServiceConnectionListener(connectioncallback);
    
  5. Define an event handler for finding the remote peer agent using the SAPeerAgentFindCallback listener interface. To establish a service connection with a remote peer agent, use the requestServiceConnection() method.

    The listener is invoked once for each found peer.

    Note
    The onpeeragentupdated() event listener is mostly used on the host SA to detect the availability of a Tizen wearable SA. The AVAILABLE status means that the corresponding Tizen wearable SA is installed.
    function onpeeragentfound(peerAgent) 
    {
       if (peerAgent.appName == "expected app name") 
       {
          SAAgent.requestServiceConnection(peerAgent);
       }
    }
    
    function onpeeragentupdated(peerAgent, status) 
    {
       if (status == "AVAILABLE") 
       {
          SAAgent.requestServiceConnection(peerAgent);
       }
       else if (status == "UNAVAILABLE") 
       {
          console.log("Uninstalled application package of peerAgent on remote device.");
       }
    }
    
    var peeragentfindcallback = 
    {
       onpeeragentfound: onpeeragentfound,
       onpeeragentupdated: onpeeragentupdated
    };
    
  6. To retrieve a list of peer agents, set the listener with the defined event handlers, and use the findPeerAgents() method of the SAAgent interface:
    SAAgent.setPeerAgentFindListener(peeragentfindcallback);
    SAAgent.findPeerAgents();
    

Enabling Auto Launching

Learning how to enable automatic launching is a basic SAP management skill:

  1. To let your application be automatically launched when a peer agent requests a connection while the application is not running, add the autoLaunchAppId attribute to the <serviceProfile> element in the accessory service profile.

    The value must be the application ID of the application to be launched.

    <serviceProfile role = "provider" 
                    name = "message_service_provider"  
                    id = "/system/messages" 
                    version = "2.0"
                    autoLaunchAppId = "VcGvmQlo1i.HelloAccessory"
                    serviceLimit = "ANY">
       <supportedTransports>
          <transport type = "TRANSPORT_BT"/>
          <transport type = "TRANSPORT_WIFI"/>
       </supportedTransports>
       <serviceChannel id = "902"
                       dataRate = "low"
                       priority = "low"
                       reliability = "disable"/>
    </serviceProfile>
    
    Note
    Be careful when using the automatic launching feature. If used improperly, it can have a negative impact on the user experience.
  2. To establish a connection with the peer agent after the launch, define an event handler for connection requests and register a ServiceConnectionCallback interface instance with the SAAgent.setServiceConnectionListener() method.

    Call the setServiceConnectionListener() method as soon as possible after the launch. Otherwise, the peer agent receives a timeout and the connection fails.

    var SASocket;
    var connectioncallback = 
    {
       onrequest: function(peerAgent) 
       {
          if (peerAgent.appName == "expected app name") 
          {
             SAAgent.acceptServiceConnectionRequest(peerAgent);
          } 
          else 
          {
             SAAgent.rejectServiceConnectionRequest(peerAgent);
          }
       },
    
       onconnect: function(socket) 
       {
          SASocket = socket;
       }
    }
    
    SAAgent.setServiceConnectionListener(connectioncallback);
    
    Note
    Do not call the requestServiceConnection() method of the SAAgent interface to connect to a peer agent who has already requested a connection to you. A collision can occur if the peer agent and your application simultaneously request a connection to each other.

Exchanging Data with Peer Agents

Learning how to exchange string data with peer agents is a basic SAP management skill:

  1. To send a string message to a remote peer agent, use the sendData() method of the SASocket interface with the channel ID:
    /* SAAgent object has been obtained using the requestSAAgent() method */
    var SASocket;
    var connectioncallback = 
    {
       /* Connection between provider and consumer is established */
       onconnect: function(socket) 
       {
          SASocket = socket;
          for (var i = 0; i < SAAgent.channelId.length; i++) 
          {
             SASocket.sendData(SAAgent.channelIds[i], "send message to " + i + "th channel.");
          }
       }
    }
    
    SAAgent.setServiceConnectionListener(connectioncallback);
    

    To send an encrypted string message to a remote accessory peer agent, use the sendSecureData() method instead of the sendData() method:

    SASocket.sendSecureData(SAAgent.channelIds[i], "send message to " + i + "th channel.");
    
  2. To receive a string message from a remote peer agent, use the setDataReceiveListener() method. This method registers the SADataReceiveCallback listener interface, which is invoked when a string message from a peer agent is received.
    function onreceive(channelId, data) 
    {
       console.log("Message received - " + channelId + " : " + data); 
    }
    
    SASocket.setDataReceiveListener(onreceive);
    

Exchanging Files with Peer Agents

Learning how to exchange files with peer agents is a basic SAP management skill:

  1. To get the SAFileTransfer object specified for the SA agent, use the getSAFileTransfer() method:
    /* SASocket object has been obtained using the setServiceConnectionListener() method */
    var filetransfer = SAAgent.getSAFileTransfer();
    
  2. To send a file to a remote peer agent:
    1. Define the event handlers for file transfer notifications using the SAFileSendCallback listener interface:
      var sendfilecallback = 
      {
         onprogress: function(transferId, progress)
         { 
            console.log("onprogress transferId: " + transferId + ", progress: " + progress);
         },
         oncomplete: function(transferId, localPath)
         { 
            console.log("File transfer complete.  transferId: " + transferId);
         },
         onerror: function(errorCode, transferId)
         { 
            console.log("FileSendError transferId: " + transferId + " code: " + errorCode);
         }
      }
      
    2. To send the file, use the sendFile() method:
      var filePath = "file:///opt/usr/media/Downloads/Image.jpg";
      var transferId = null;
      var filetransfer = null;
      
      var peeragentfindcallback = 
      {
         onpeeragentfound: function(peerAgent) 
         {
            if (peerAgent.appName == "expected app name") 
            {
               transferId = filetransfer.sendFile(peerAgent, filePath);
            } 
         }
      }
      
      filetransfer = agent.getSAFileTransfer();
      filetransfer.setFileSendListener(sendfilecallback);
      agent.setPeerAgentFindListener(peeragentfindcallback);
      agent.findPeerAgents();
      
  3. To receive a file from a remote peer agent:
    1. Define the event handlers for process notifications using the SAFileReceiveCallback listener interface:
      var receivefilecallback = 
      {
         onreceive: function(transferId, filePath)
         { 
            console.log("Incoming file transfer request from the remote peer agent. 
                        transferId: " + transferId + " file name: " + fileName); 
         },
         onprogress: function(transferId, progress)
         { 
            console.log("onprogress transferId: " + transferId + ", progress: " + progress);
         },
         oncomplete: function(transferId, localPath)
         { 
            console.log("File transfer complete.  transferId: " + transferId); 
         },
         onerror: function(errorCode, transferId)
         { 
            console.log("FileReceiveError transferId: " + transferId + " code: " + errorCode);
         } 
      }
      
      filetransfer.setFileReceiveListener(receivefilecallback);
      
    2. You can accept, reject, or cancel the file download:
      • To accept the download of the file, use the receiveFile() method:
        var newFilePath = "file:///opt/usr/media/Downloads/ReceivedImage.jpg";
        
        var receivefilecallback = 
        {
           onreceive: function(transferId, filePath) 
           {
              filetransfer.receiveFile(transferId, newFilePath);
           }
        }
        
      • To reject the incoming transfer request from a remote peer agent, use the rejectFile() method:
        var receivefilecallback = 
        {
           onreceive: function(transferId, fileName) 
           {
              if (1) /* User-defined condition */ 
              {
                 filetransfer.rejectFile(transferId);
              }
           },
        }
        
      • To cancel the download, use the cancelFile() method with the transfer ID:
        var receivefilecallback = 
        {
           onprogress: function(transferId, progress)
           { 
              filetransfer.cancelFile(transferId);
           }
        }
        

Closing the Service Connection

To close the service connection with remote peer agent, use the close() method:

/* Assume SAAgent object has been obtained by using requestSAAgent() method */
var callback = 
{
   onrequest: function(peerAgent) {},
   onconnect: function(socket)
   {
      if (socket.peerAgent.appName != "expected_appName") 
      {
         socket.close();
      }
   }
}

SAAgent.setServiceConnectionListener(callback);

Exchanging Messages

The Samsung Accessory Message Exchange Protocol service allows sending data without need of any service connection.

The sender application should know the peer to whom the message needs to be sent. Sender will also be acknowledged with message deliver status. Message Exchange protocol service internally uses a reserved channel for data transfers.

The application has to provide the Message feature description in the XML file.

Learning how to exchange message without connection :

  1. The following example illustrates the content of the profile XML file, which specifies the 'Supported Features' profile details.
    <resources>
       <application name="HelloMessageConsumer">
          <serviceProfile 
             id="/sample/hellomessage"
             name="hellomessage_consumer"
             role="consumer"
             version="1.0">
             <supportedTransports>
                <transport type="TRANSPORT_BT"/>
             </supportedTransports>
             <supportedFeatures>
                <feature type="message"/>
             </supportedFeatures>
          </serviceProfile>
       </application>
    </resources>
    
  2. To get the SAMessage object specified for the SA agent, use the getSAMessage() method and to receive a string message from a remote peer agent, use the setMessageReceiveListener() method. This method registers the SAMessageReceiveCallback listener interface, which is invoked when a string message from a remote peer agent is received.
       function messageReceivedCallback(peerAgent, data) {
          createHTML("Received message from the [" + peerAgent.peerId + "] : " + data);
       }
       
       SAMessage = SAAgent.getSAMessage();
       if(SAMessage)
       {
          console.log("setMessageReceiveListener");
          SAMessage.setMessageReceiveListener(messageReceivedCallback);
       }
        
  3. To send data, the application needs to know the peer agent it wants to send data to. This can be obtained by findPeerAgents() method. Application also has to check if the "MESSAGE" feature is enabled on both remote and local framework. If the "MESSAGE" is not include in SAPeerAgent.feature, using the socket should be send data.
    var peerAgentFindCallback = {
       onpeeragentfound : function(peerAgent) {
          try {
             if (peerAgent.appName == ProviderAppName) {
                SAPeerAgent = peerAgent;
                if (peerAgent.feature.filter(function(v){return v === "MESSAGE";}) == "MESSAGE")
                {
                   if(SAMessage) {
                      var id = SAMessage.sendData(SAPeerAgent, "Hello Message!", {
                         onsent : function(peerAgent, id) { console.log (id + " message is successfully sent to " + peerAgent.appName );},
                         onerror : function(code, peerAgent, id) { console.log (id + " message is sent fail... code :" + code); }
                      });
                   }
                } else {
                   console.log("Not Support MESSAGE");               
                }
             } else {
                console.log("Not expected app!! : " + peerAgent.appName);
             }
          } catch(err) {
             console.log("exception [" + err.name + "] msg[" + err.message + "]");
          }
       }
    }
       
    SAAgent.setPeerAgentFindListener(peerAgentFindCallback);
    SAAgent.findPeerAgents();
    
Go to top