this.isReady = false;
this.service_handlers = [];
this.sockets = [];
- this.change_listener = null;
+ this.change_listener = {};
+ this.health_apps = {};
+ this.health_channel_listener = {};
}
function validateAddress(address) {
};
BluetoothAdapter.prototype.unsetChangeListener = function() {
- adapter.change_listener = null;
+ adapter.change_listener = {};
};
+function BluetoothProfileHandler(profileType) {
+ _addConstProperty(this, 'profileType', profileType);
+}
+
+// BluetoothHealthProfileHandler class inherits from BluetoothProfileHandler class
+function BluetoothHealthProfileHandler() {
+ BluetoothProfileHandler.call(this, 'HEALTH');
+}
+BluetoothHealthProfileHandler.prototype = Object.create(BluetoothProfileHandler.prototype);
+BluetoothHealthProfileHandler.prototype.constructor = BluetoothHealthProfileHandler;
+
+BluetoothAdapter.prototype.getBluetoothProfileHandler = function(profile_type) {
+ if (!xwalk.utils.validateArguments('s', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ if (profile_type === 'HEALTH')
+ var profile_handler = new BluetoothHealthProfileHandler();
+ else
+ var profile_handler = new BluetoothProfileHandler(profile_type);
+
+ return profile_handler;
+}
+
var _deviceClassMask = {
'MINOR': 0x3F,
'MAJOR': 0x1F,
successCallback();
});
};
+
+function BluetoothHealthApplication(data_type, app_name, msg) {
+ _addConstProperty(this, 'dataType', data_type);
+ _addConstProperty(this, 'name', app_name);
+ this.onconnect = null;
+
+ if (msg)
+ this.app_id = msg.app_id;
+}
+
+BluetoothHealthApplication.prototype.unregister =
+ function(successCallback, errorCallback) {
+ if (!xwalk.utils.validateArguments('?ff', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ if (adapter.checkServiceAvailability(errorCallback))
+ return;
+
+ var msg = {
+ 'cmd': 'UnregisterSinkApp',
+ 'app_id': this.app_id
+ };
+
+ var app = this;
+
+ postMessage(msg, function(result) {
+ if (result.error != 0) {
+ if (errorCallback) {
+ var error = new tizen.WebAPIError(tizen.WebAPIException.UNKNOWN_ERR);
+ errorCallback(error);
+ }
+ }
+ if (app.app_id)
+ delete adapter.health_apps[app.app_id];
+
+ if (successCallback)
+ successCallback();
+ });
+}
+
+BluetoothHealthProfileHandler.prototype.registerSinkApplication =
+ function(dataType, name, successCallback, errorCallback) {
+ if (!xwalk.utils.validateArguments('nsf?f', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ if (adapter.checkServiceAvailability(errorCallback))
+ return;
+
+ var msg = {
+ 'cmd': 'RegisterSinkApp',
+ 'datatype': dataType
+ };
+
+ postMessage(msg, function(result) {
+ if (result.error != 0) {
+ if (errorCallback) {
+ var error = new tizen.WebAPIError(tizen.WebAPIException.UNKNOWN_ERR);
+ errorCallback(error);
+ }
+ return;
+ }
+
+ if (successCallback) {
+ var application = new BluetoothHealthApplication(dataType, name, result);
+ adapter.health_apps[result.app_id] = application;
+ successCallback(application);
+ }
+ });
+}
+
+BluetoothHealthProfileHandler.prototype.connectToSource =
+ function(peer, application, successCallback, errorCallback) {
+ if (!xwalk.utils.validateArguments('oof?f', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ if (adapter.checkServiceAvailability(errorCallback))
+ return;
+
+ var msg = {
+ 'cmd': 'ConnectToSource',
+ 'address': peer.address,
+ 'app_id': application.app_id
+ };
+
+ postMessage(msg, function(result) {
+ if (result.error != 0) {
+ if (errorCallback) {
+ var error = new tizen.WebAPIError(tizen.WebAPIException.UNKNOWN_ERR);
+ if(result.error == 1)
+ error = new tizen.WebAPIError(tizen.WebAPIException.INVALID_VALUES_ERR);
+ errorCallback(error);
+ }
+ return;
+ }
+
+ if (successCallback) {
+ var i = adapter.indexOfDevice(adapter.known_devices, result.address);
+ var channel = new BluetoothHealthChannel(adapter.known_devices[i],
+ adapter.health_apps[result.app_id], result);
+ successCallback(channel);
+ }
+ });
+}
+
+function BluetoothHealthChannel(device, application, msg) {
+ _addConstProperty(this, 'peer', device);
+ _addConstProperty(this, 'channelType', (msg.channel_type == 1) ? 'RELIABLE' : 'STREAMING');
+ _addConstProperty(this, 'application', application);
+ _addConstProperty(this, 'isConnected', (msg.connected == 'true') ? true : false);
+ this.channel = msg.channel;
+ this.data = [];
+}
+
+BluetoothHealthChannel.prototype.close = function() {
+ if (adapter.checkServiceAvailability(errorCallback))
+ return;
+
+ var msg = {
+ 'cmd': 'DisconnectSource',
+ 'address': this.peer.address,
+ 'channel': this.channel
+ };
+
+ var channel = this;
+
+ postMessage(msg, function(result) {
+ if (result.error != 0) {
+ if (errorCallback) {
+ var error = new tizen.WebAPIError(tizen.WebAPIException.UNKNOWN_ERR);
+ errorCallback(error);
+ }
+ return;
+ }
+
+ _addConstProperty(channel, 'isConnected', false);
+ if (adapter.health_channel_listener.onclose)
+ adapter.health_channel_listener.onclose();
+ });
+}
+
+BluetoothHealthChannel.prototype.sendData = function(data) {
+ if (adapter.checkServiceAvailability(errorCallback))
+ return;
+
+ if (!xwalk.utils.validateArguments('o', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ var msg = {
+ 'cmd': 'SendHealthData',
+ 'data': data,
+ 'channel' : this.channel
+ };
+
+ postMessage(msg, function(result) {
+ if (result.error != 0) {
+ var error = new tizen.WebAPIError(tizen.WebAPIException.UNKNOWN_ERR);
+ return 0;
+ }
+
+ return result.size;
+ });
+}
+
+BluetoothHealthChannel.prototype.setListener = function(listener) {
+ if (!xwalk.utils.validateArguments('o', arguments)) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ if (!xwalk.utils.validateObject(listener, 'ff', ['onmessage', 'onclose'])) {
+ throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
+ }
+
+ adapter.health_channel_listener = listener;
+}
+
+BluetoothHealthChannel.prototype.unsetListener = function() {
+ adapter.health_channel_listener = {};
+}
adapter_enabled_(false),
js_reply_needed_(false),
stop_discovery_from_js_(false) {
-
- CAPI(bt_initialize());
- InitializeAdapter();
}
BluetoothInstance::~BluetoothInstance() {
CAPI(bt_deinitialize());
}
+ CAPI(bt_initialize());
+ InitializeAdapter();
+}
+
void BluetoothInstance::HandleMessage(const char* message) {
picojson::value v;
HandleCloseSocket(v);
else if (cmd == "UnregisterServer")
HandleUnregisterServer(v);
+ else if (cmd == "RegisterSinkApp")
+ HandleRegisterSinkApp(v);
+ else if (cmd == "UnregisterSinkApp")
+ HandleUnregisterSinkApp(v);
+ else if (cmd == "ConnectToSource")
+ HandleConnectToSource(v);
+ else if (cmd == "DisconnectSource")
+ HandleDisconnectSource(v);
+ else if (cmd == "SendHealthData")
+ HandleSendHealthData(v);
}
void BluetoothInstance::HandleSyncMessage(const char* message) {
return;
}
-
LOG_DBG("");
picojson::value::object o;
o["cmd"] = picojson::value("");
obj->InternalPostMessage(picojson::value(o));
}
+void BluetoothInstance::OnHdpConnected(int result, const char* remote_address,
+ const char* app_id, bt_hdp_channel_type_e type, unsigned int channel,
+ void* user_data) {
+ BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
+ if (!obj) {
+ LOG_ERR("user_data is NULL");
+ return;
+ }
+
+ LOG_DBG("");
+ picojson::value::object o;
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = picojson::value(obj->callbacks_id_map_["ConnectToSource"]);
+ obj->callbacks_id_map_.erase("ConnectToSource");
+
+ o["address"] = picojson::value(remote_address);
+ o["app_id"] = picojson::value(app_id);
+ o["channel_type"] = picojson::value(static_cast<double>(type));
+ o["channel"] = picojson::value(static_cast<double>(channel));
+ o["connected"] = picojson::value("true");
+ obj->InternalPostMessage(picojson::value(o));
+}
+
+void BluetoothInstance::OnHdpDisconnected(int result, const char* remote_address,
+ unsigned int channel, void* user_data) {
+ BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
+ if (!obj) {
+ LOG_ERR("user_data is NULL");
+ return;
+ }
+
+ LOG_DBG("");
+ picojson::value::object o;
+ if (result)
+ o["error"] = picojson::value(static_cast<double>(1));
+ else
+ o["error"] = picojson::value(static_cast<double>(0));
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = picojson::value(obj->callbacks_id_map_["DisconnectSource"]);
+ obj->callbacks_id_map_.erase("DisconnectSource");
+ o["address"] = picojson::value(remote_address);
+ o["channel"] = picojson::value(static_cast<double>(channel));
+ o["connected"] = picojson::value("false");
+ obj->InternalPostMessage(picojson::value(o));
+}
+
+void BluetoothInstance::OnHdpDataReceived(unsigned int channel, const char* data,
+ unsigned int size, void* user_data) {
+ BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
+ if (!obj) {
+ LOG_ERR("user_data is NULL");
+ return;
+ }
+
+ LOG_DBG("");
+ picojson::value::object o;
+ o["reply_id"] = picojson::value(obj->callbacks_id_map_["SendHealthData"]);
+ obj->callbacks_id_map_.erase("SendHealthData");
+ o["channel"] = picojson::value(static_cast<double>(channel));
+ o["data"] = picojson::value(data);
+ o["size"] = picojson::value(static_cast<double>(size));
+ obj->InternalPostMessage(picojson::value(o));
+}
+
+
gboolean BluetoothInstance::GetDefaultAdapter(gpointer user_data) {
BluetoothInstance* obj = static_cast<BluetoothInstance*>(user_data);
if (!obj) {
CAPI(bt_device_set_bond_created_cb(OnBondCreated, this));
CAPI(bt_device_set_bond_destroyed_cb(OnBondDestroyed, this));
+ // Should also be socket_connected_cb...
+
+ CAPI(bt_hdp_set_connection_state_changed_cb(OnHdpConnected, OnHdpDisconnected, this));
+ CAPI(bt_hdp_set_data_received_cb(OnHdpDataReceived, this));
+
bt_adapter_state_e state = BT_ADAPTER_DISABLED;
CAPI(bt_adapter_get_state(&state));
CAPI(bt_device_unset_bond_destroyed_cb());
CAPI(bt_socket_unset_connection_state_changed_cb());
CAPI(bt_socket_unset_data_received_cb());
+
+ CAPI(bt_hdp_unset_connection_state_changed_cb());
+ CAPI(bt_hdp_unset_data_received_cb());
}
void BluetoothInstance::HandleGetDefaultAdapter(const picojson::value& msg) {
else
o["error"] = picojson::value(static_cast<double>(1));
-
o["cmd"] = picojson::value("");
o["reply_id"] = msg.get("reply_id");
o["capi"] = picojson::value(static_cast<double>(1));
CAPI(bt_socket_destroy_rfcomm(socket));
}
+void BluetoothInstance::HandleRegisterSinkApp(const picojson::value& msg) {
+ picojson::value::object o;
+ int error = 0;
+
+ unsigned short data_type =
+ static_cast<unsigned short>(msg.get("datatype").get<double>());
+
+ LOG_DBG(data_type);
+
+ char* app_id = NULL;
+ CAPI_ERR(bt_hdp_register_sink_app(data_type, &app_id), error);
+ LOG_DBG(app_id);
+ if (!error) {
+ o["error"] = picojson::value(static_cast<double>(0));
+ o["app_id"] = picojson::value(app_id);
+ } else {
+ o["error"] = picojson::value(static_cast<double>(1));
+ }
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = msg.get("reply_id");
+ InternalPostMessage(picojson::value(o));
+}
+
+void BluetoothInstance::HandleUnregisterSinkApp(const picojson::value& msg) {
+ picojson::value::object o;
+ int error = 0;
+
+ LOG_DBG(msg.get("app_id").to_str());
+
+ CAPI_ERR(bt_hdp_unregister_sink_app(msg.get("app_id").to_str().c_str()), error);
+ if (!error)
+ o["error"] = picojson::value(static_cast<double>(0));
+ else
+ o["error"] = picojson::value(static_cast<double>(1));
+
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = msg.get("reply_id");
+ InternalPostMessage(picojson::value(o));
+}
+
+void BluetoothInstance::HandleConnectToSource(const picojson::value& msg) {
+ picojson::value::object o;
+ int error = 0;
+
+ CAPI_ERR(
+ bt_hdp_connect_to_source(msg.get("address").to_str().c_str(),
+ msg.get("app_id").to_str().c_str()),
+ error);
+ if (error != BT_ERROR_NONE) {
+ o["error"] = picojson::value(static_cast<double>(2));
+ if (error == BT_ERROR_INVALID_PARAMETER)
+ o["error"] = picojson::value(static_cast<double>(1));
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = msg.get("reply_id");
+ InternalPostMessage(picojson::value(o));
+ } else {
+ callbacks_id_map_["ConnectToSource"] = msg.get("reply_id").to_str();
+ }
+}
+
+void BluetoothInstance::HandleDisconnectSource(const picojson::value& msg) {
+ picojson::value::object o;
+ int error = 0;
+
+ int channel = static_cast<int>(msg.get("channel").get<double>());
+
+ CAPI_ERR(bt_hdp_disconnect(msg.get("address").to_str().c_str(), channel),
+ error);
+ if (error != BT_ERROR_NONE) {
+ o["error"] = picojson::value(static_cast<double>(1));
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = msg.get("reply_id");
+ InternalPostMessage(picojson::value(o));
+ } else {
+ callbacks_id_map_["DisconnectSource"] = msg.get("reply_id").to_str();
+ }
+}
+
+void BluetoothInstance::HandleSendHealthData(const picojson::value& msg) {
+ picojson::value::object o;
+ int error = 0;
+
+ std::string data = msg.get("data").to_str();
+ int channel = static_cast<int>(msg.get("channel").get<double>());
+
+ CAPI_ERR(
+ bt_hdp_send_data(channel, data.c_str(), static_cast<int>(data.size())),
+ error);
+ if (error != BT_ERROR_NONE) {
+ o["error"] = picojson::value(static_cast<double>(1));
+ o["cmd"] = picojson::value("");
+ o["reply_id"] = msg.get("reply_id");
+ InternalPostMessage(picojson::value(o));
+ } else {
+ callbacks_id_map_["SendHealthData"] = msg.get("reply_id").to_str();
+ }
+}
+
void BluetoothInstance::FlushPendingMessages() {
// Flush previous pending messages.
if (queue_.empty())
~BluetoothInstance();
private:
+ virtual void Initialize();
virtual void HandleMessage(const char* msg);
virtual void HandleSyncMessage(const char* msg);
void HandleSocketWriteData(const picojson::value& msg);
void HandleCloseSocket(const picojson::value& msg);
void HandleUnregisterServer(const picojson::value& msg);
+ void HandleRegisterSinkApp(const picojson::value& msg);
+ void HandleUnregisterSinkApp(const picojson::value& msg);
+ void HandleConnectToSource(const picojson::value& msg);
+ void HandleDisconnectSource(const picojson::value& msg);
+ void HandleSendHealthData(const picojson::value& msg);
void InternalPostMessage(picojson::value v);
void InternalSetSyncReply(picojson::value v);
static void OnSocketHasData(bt_socket_received_data_s* data, void* user_data);
+ static void OnHdpConnected(int result, const char* remote_address,
+ const char* app_id, bt_hdp_channel_type_e type, unsigned int channel,
+ void* user_data);
+
+ static void OnHdpDisconnected(int result, const char* remote_address,
+ unsigned int channel, void* user_data);
+
+ static void OnHdpDataReceived(unsigned int channel, const char* data,
+ unsigned int size, void* user_data);
+
// Map JS reply_id to a C API callback
std::map<std::string, std::string> callbacks_id_map_;
<button id="button12">Click 12</button>
<button id="button13">Click 13</button>
<button id="button14">Click 14</button>
+<button id="button15">Click 15</button>
+<button id="button16">Click 16</button>
+<button id="button17">Click 17</button>
<pre id="console"></pre>
<script src="js/js-test-pre.js"></script>
var chatServiceHandler = null;
var clientSocket = null;
+var healthProfileHandler = null;
+var healthApp = null;
+
function validateAddress(address) {
if (typeof address !== 'string')
return false;
}
}
+function healthRegisterSuccess(app) {
+ output.value += '\nRegistered application: ' + app.name;
+ healthApp = app;
+}
+
+function healthRegisterError(e) {
+ output.value += '\nFailed to register application: ' + e.message;
+};
+
+function healthUnregisterSuccess() {
+ output.value += '\nApplication: ' + healthApp.name + ' is unregistered';
+ healthApp = null;
+}
+
var onErrorCallback = function(e) {
output.value += '\n [ERROR] Failed: ' + e.message;
};
sendMessage(message);
});
+
+handle("button15", "getBluetoothProfileHandler", function() {
+ output.value += '\n\n## get Health profile handler ##';
+ healthProfileHandler = adapter.getBluetoothProfileHandler("HEALTH");
+ output.value += '\n profile handler returns: ' + healthProfileHandler.profileType;
+});
+
+handle("button16", "Register Sink App", function() {
+ output.value += '\n\n## register Sink Application: testSinkApp ##';
+ if (!healthProfileHandler) {
+ output.value += '\nPlease get profile handler first !!!';
+ return;
+ }
+ healthProfileHandler.registerSinkApplication(4100, "testSinkApp", healthRegisterSuccess, healthRegisterError);
+});
+
+handle("button17", "Unregister Sink App", function() {
+ output.value += '\n\n## Unregister Sink Application: testSinkApp ##';
+ if (!healthProfileHandler) {
+ output.value += '\nPlease get profile handler first !!!';
+ return;
+ }
+ if (!healthApp) {
+ output.value += '\nNo sink app registered: nothing to do...';
+ return;
+ }
+ healthApp.unregister(healthUnregisterSuccess);
+});
+
</script>