Interact with the Application on the Android Device

The UI scenario of this sample application works as follows:
1. Send a Hello message from Galaxy Watch to a mobile device.

Figure: Galaxy Watch sends a Hello message

2. Send a message from the Android mobile device to Galaxy Watch.

Figure: Android sends a Hi Gear!! message

Before sending a message, initialize the connection as follows.

Figure: Initialize the connection

Figure: Send messages

1. Initialize SAP.

A. Create the service agent handle, and initialize it by calling the sap_agent_initialize() function:

static bool
_app_create(void *data)

{
	appdata_s *ad = data;
	_create_base_gui(ad);
	initialize_sap(ad);

	return true;
}
static void
_on_agent_initialized(sap_agent_h agent,
sap_agent_initialized_result_e result,
void *user_data)
{
	sap_info_s *priv =(sap_info_s*)user_data;

	switch (result)
	{
		case SAP_AGENT_INITIALIZED_RESULT_SUCCESS:
		priv->agent_created = true;
		g_idle_add(_find_peer_agent, priv);

		break;

		case SAP_AGENT_INITIALIZED_RESULT_DUPLICATED:
		break;

		case SAP_AGENT_INITIALIZED_RESULT_INVALID_ARGUMENTS:
		break;

		case SAP_AGENT_INITIALIZED_RESULT_INTERNAL_ERROR:

		break;

		default:
		break;
	}
}
void
initialize_sap(void *user_data)
{
	sap_agent_h agent = NULL;

	sap_agent_create(&agent);

	priv_info.agent = agent;
	priv_info.user_data = user_data;
	priv_info.agent_created = false;

	_initialize_agent(&priv_info);

	sap_set_device_status_changed_cb(_on_device_status_changed, &priv_info);
}
static bool
_initialize_agent(sap_info_s* priv)
{
	int result_agent = 0;

	do
	{
		result_agent = sap_agent_initialize(priv->agent,
		_MY_APPLICATION_ASPID,
		SAP_AGENT_ROLE_CONSUMER,
		_on_agent_initialized, priv);
	} while (result_agent != SAP_RESULT_SUCCESS);

	return true;
}

B. The _on_device_status_changed() callback function is triggered when the device status changes. All valid sap_peer_agent and sap_socket handles must be destroyed when the callback is called with the SAP_DEVICE_STATUS_DETACHED device disconnected status.

static void
_on_device_status_changed(sap_device_status_e status,
sap_transport_type_e transport_type,
void *user_data)
{
	sap_info_s *priv = (sap_info_s*)user_data;

	if (transport_type != SAP_TRANSPORT_TYPE_BT)
	{
		return;
	}

	switch (status)
	{
		case SAP_DEVICE_STATUS_DETACHED:
			if (priv->peer_agent)
			{
				sap_socket_destroy(priv->socket);
				priv->socket = NULL;
				sap_peer_agent_destroy(priv->peer_agent);
				priv->peer_agent = NULL;
			}
			show_message("Device detached", priv->user_data);
			break;

		case SAP_DEVICE_STATUS_ATTACHED:
			if (priv->agent_created)
			{
				g_idle_add(_find_peer_agent, priv);
			}
			break;

		default:
			break;
	}
}

2. Create a service connection.

A. Search for matching Accessory Peer Agents available for establishing a service connection by calling the sap_agent_find_peer_agent() function.

static gboolean
_find_peer_agent(gpointer user_data)
{
	sap_info_s *priv = (sap_info_s*)user_data;
	sap_agent_find_peer_agent(priv->agent, _on_peer_agent_updated, priv);

	return FALSE;
}
static void
_on_peer_agent_updated(sap_peer_agent_h peer_agent,
sap_peer_agent_status_e peer_status,
sap_peer_agent_found_result_e result,
void *user_data)
{
	sap_info_s *priv = (sap_info_s*)user_data;

	switch (result)
	{
		case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED:
			break;

		case SAP_PEER_AGENT_FOUND_RESULT_FOUND:
			if (peer_status == SAP_PEER_AGENT_STATUS_AVAILABLE)
			{
				priv->peer_agent = peer_agent;
				g_idle_add(_create_service_connection, priv);
			}
			else
			{
				sap_peer_agent_destroy(peer_agent);
			}
			break;

		case SAP_PEER_AGENT_FOUND_RESULT_SERVICE_NOT_FOUND:
			break;

		case SAP_PEER_AGENT_FOUND_RESULT_TIMEDOUT:
			break;

		case SAP_PEER_AGENT_FOUND_RESULT_INTERNAL_ERROR:
			break;

		default:
			break;

	}
}

B. Initiate a service connection with the Accessory Peer Agent by calling the sap_agent_request_service_connection() function when a matched Peer Agent is found.

static gboolean
_create_service_connection(gpointer user_data)
{
	sap_info_s *priv = (sap_info_s*)user_data;
	sap_result_e result = SAP_RESULT_FAILURE;

	result = sap_agent_request_service_connection(priv->agent,
	priv->peer_agent,
	_on_service_connection_created,
	priv);

	return FALSE;
}

C. When the service connection has been successfully established, the requesting Accessory Peer Agent gets a socket that can be used both to send and receive data to and from Accessory Peer Agents, and to handle service connection-related events.

D. Use the sap_socket_set_data_received_cb() function to register the on_data_received() callback that is triggered when data is received on the socket.

static void
_on_service_connection_created(sap_peer_agent_h peer_agent,
sap_socket_h socket,
sap_service_connection_result_e result,
void *user_data)
{
	sap_info_s* priv = (sap_info_s*)user_data;

	switch (result)
	{

		case SAP_CONNECTION_SUCCESS:
			sap_peer_agent_set_service_connection_terminated_cb(priv->peer_agent,

			_on_service_connection_terminated,
			priv);

			sap_socket_set_data_received_cb(socket, _on_data_received, priv);
			priv->socket = socket;
			show_message("Connection Established", priv->user_data);
			break;

		case SAP_CONNECTION_ALREADY_EXIST:
			priv->socket = socket;
			show_message("Connection Already Exist", priv->user_data);
			break;

		case SAP_CONNECTION_FAILURE_DEVICE_UNREACHABLE:
			break;

		case SAP_CONNECTION_FAILURE_INVALID_PEERAGENT:
			break;

		case SAP_CONNECTION_FAILURE_NETWORK:
			break;

		case SAP_CONNECTION_FAILURE_PEERAGENT_NO_RESPONSE:
			break;

		case SAP_CONNECTION_FAILURE_PEERAGENT_REJECTED:
			break;

		case SAP_CONNECTION_FAILURE_UNKNOWN:
			break;
	}
}

3. Disconnect the service.

Call the sap_peer_agent_terminate_service_connection() function to terminate the service connection with a remote Accessory Peer Agent. When the connection terminates, the on_service_connection_terminated() callback is triggered. Similarly, if the remote Accessory Peer Agent terminates the service connection, your application is notified through the same callback, and all established service channels of the service connection are closed by the Accessory Service Framework.

Other reasons, such as a network failure or 2 devices becoming out of range while on a wireless connection, can also result in the loss of the service connection. Your service provider and service consumer applications are expected to implement handling mechanisms in the callback for such cases.

void
deinitialize_sap()
{
if (priv_info.peer_agent)
{
	sap_peer_agent_terminate_service_connection(priv_info.peer_agent);

	sap_socket_destroy(priv_info.socket);
	priv_info.socket = NULL;
	sap_peer_agent_destroy(priv_info.peer_agent);
	priv_info.peer_agent = NULL;
}

if (priv_info.agent)
{
	sap_agent_destroy(priv_info.agent);
	priv_info.agent = NULL;
}
}
static void
_on_service_connection_terminated(sap_peer_agent_h peer_agent,
sap_socket_h socket,
sap_service_connection_terminated_reason_e result,
void *user_data)
{
	sap_info_s *priv = NULL;
	priv = (sap_info_s*)user_data;

	switch (result)
	{
		case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED:
			show_message("Peer Disconnected", priv->user_data);
			break;

		case SAP_CONNECTION_TERMINATED_REASON_DEVICE_DETACHED:
			show_message("Disconnected Device Detached", priv->user_data);
			break;

		case SAP_CONNECTION_TERMINATED_REASON_UNKNOWN:
			show_message("Disconnected Unknown Reason", priv->user_data);
			break;
	}
	sap_socket_destroy(priv->socket);
	priv->socket = NULL;
}

4. Send a message.

The service consumer or service provider can send data to its connected Accessory Peer Agent by simply calling the sap_socket_send_data() method with a socket handle (passed by the sap_service_connection_established_type callback) and a service channel ID. The data is sent on a selected service channel inside the established service connection.

bool
send_message(const char *message)
{
if (priv_info.socket)
{
	sap_socket_send_data(priv_info.socket, _MY_APPLICATION_CHANNELID, strlen(message),(void*) message);
}

return true;
}
#define MY_APPLICATION_ASPID "/org/example/myapp/my_message"
#define MY_APPLICATION_CHANNELID 110
<?xml version="1.0" encoding="UTF-8"?>
<resources>
	<application name="MyApplication">
		<serviceProfile id="/org/example/myapp/my_message" name="MyMessage"
		                role="consumer" version="1.0">
			<supportedTransports>
				<transport type="TRANSPORT_BT" />
				<transport type="TRANSPORT_WIFI" />
			</supportedTransports>
			<serviceChannel id="110" dataRate="low" priority="low"
			                reliability="enable">
			</serviceChannel>
		</serviceProfile>
	</application>
</resources>

5. Receive a message.

When data is received from a remote Accessory Peer Agent, your application is notified through the sap_socket_data_received_cb() callback.

sap_socket_set_data_received_cb(socket, _on_data_received, priv);

The _on_data_received() callback is set initially after the service connection is made using the sap_set_on_data_receive_cb() callback.

static void
	_on_data_received(sap_socket_h socket,
	unsigned short int channel_id,
	unsigned int payload_length,
	void *buffer,
	void *user_data)
{
	sap_info_s *priv = (sap_info_s*)user_data;
	show_message(buffer, priv->user_data);
}