--- /dev/null
+{
+ 'includes':[
+ '../common/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'tizen_bluetooth',
+ 'type': 'loadable_module',
+ 'sources': [
+ 'bluetooth_api.js',
+ 'bluetooth_adapter.cc',
+ 'bluetooth_adapter.h',
+ 'bluetooth_class.cc',
+ 'bluetooth_class.h',
+ 'bluetooth_device.cc',
+ 'bluetooth_device.h',
+ 'bluetooth_extension.cc',
+ 'bluetooth_extension.h',
+ 'bluetooth_health_application.cc',
+ 'bluetooth_health_application.h',
+ 'bluetooth_health_channel.cc',
+ 'bluetooth_health_channel.h',
+ 'bluetooth_health_profile_handler.cc',
+ 'bluetooth_health_profile_handler.h',
+ 'bluetooth_instance.cc',
+ 'bluetooth_instance.h',
+ 'bluetooth_privilege.h',
+ 'bluetooth_service_handler.cc',
+ 'bluetooth_service_handler.h',
+ 'bluetooth_socket.cc',
+ 'bluetooth_socket.h',
+ 'bluetooth_util.cc',
+ 'bluetooth_util.h',
+ ],
+ 'includes': [
+ '../common/pkg-config.gypi',
+ ],
+ 'conditions': [
+ ['tizen == 1', {
+ 'variables': {
+ 'packages': [
+ 'capi-network-bluetooth',
+ 'capi-system-info',
+ 'libpcrecpp',
+ ]
+ },
+ }],
+ ],
+ },
+ ],
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_adapter.h"
+
+#include <algorithm>
+#include <memory>
+
+#include <pcrecpp.h>
+#include <system_info.h>
+#include <bluetooth.h>
+
+#include "common/converter.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "common/task-queue.h"
+
+#include "bluetooth_class.h"
+#include "bluetooth_device.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_socket.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+namespace {
+const std::string kAction = "action";
+const std::string kData = "data";
+const std::string kName = "name";
+//adapter
+const std::string kAdapterPowered = "powered";
+const std::string kAdapterVisible = "visible";
+//AdapterChangeCallback
+const std::string kOnStateChanged = "onstatechanged";
+const std::string kOnNameChanged = "onnamechanged";
+const std::string kOnVisibilityChanged = "onvisibilitychanged";
+const std::string kAdapterChangeCallbackEvent = "BluetoothAdapterChangeCallback";
+// BluetoothProfileHandler
+const std::string kBluetoothProfileHealth = "HEALTH";
+const std::string kFeatureBluetoothHealth = "tizen.org/feature/network.bluetooth.health";
+//DiscoverDevicesCallback
+const std::string kOnDiscoverStarted = "onstarted";
+const std::string kOnDiscoverFound = "ondevicefound";
+const std::string kOnDiscoverDisappeared = "ondevicedisappeared";
+const std::string kOnDiscoverFinished = "onfinished";
+const std::string kAdapterDiscoverSuccessEvent = "BluetoothDiscoverDevicesSuccessCallback";
+const std::string kAdapterDiscoverErrorEvent = "BluetoothDiscoverDevicesErrorCallback";
+//device
+const std::string kDeviceAddress = "address";
+const unsigned short kTimeout = 180;
+}
+
+static bool IsValidAddress(const std::string& address) {
+ static pcrecpp::RE re("(([0-9a-zA-Z]+):)+([0-9a-zA-Z]+)");
+ static std::string compare_address = "00:12:47:08:9A:A6";
+
+ if (!re.FullMatch(address)) {
+ LoggerE("Invalid address");
+ return false;
+ }
+ if (address.size() != compare_address.size()) {
+ LoggerE("Invalid size");
+ return false;
+ }
+ return true;
+}
+
+static bool IsValidUUID(const std::string& uuid) {
+ static pcrecpp::RE re("(([0-9a-zA-Z]+)-)+([0-9a-zA-Z]+)");
+ static std::string compare_uuid = "00001101-0000-1000-8000-00805F9B34FB";
+
+ if (!re.FullMatch(uuid)) {
+ LoggerE("Invalid UUID: %s", uuid.c_str());
+ return false;
+ }
+
+ if (uuid.size() != compare_uuid.size()) {
+ LoggerE("Invalid size: %s", uuid.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+void BluetoothAdapter::StateChangedCB(int result, bt_adapter_state_e state, void *user_data) {
+ LoggerD("Entered");
+
+ BluetoothAdapter* adapter = static_cast<BluetoothAdapter*>(user_data);
+ if (!adapter) {
+ LoggerD("User data is NULL");
+ return;
+ }
+
+ const bool powered = BT_ADAPTER_ENABLED == state;
+ bool previous_powered = adapter->is_powered_;
+ adapter->is_powered_ = powered;
+
+ if (powered) {
+ //update visible state if bluetooth device has been turned on
+ adapter->is_visible_ = adapter->get_visible();
+ }
+
+ if (previous_powered != powered && BT_ERROR_NONE == result) {
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnStateChanged)));
+ data_obj->insert(std::make_pair(kAdapterPowered, picojson::value(powered)));
+
+ util::FireEvent(kAdapterChangeCallbackEvent, value);
+ }
+
+ if (adapter->user_request_list_[SET_POWERED]) {
+ if (adapter->requested_powered_ != powered) {
+ return;
+ }
+
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ try {
+ switch(result) {
+ case BT_ERROR_NONE:
+ case BT_ERROR_ALREADY_DONE:
+ case BT_ERROR_NOT_ENABLED:
+ util::ReportSuccess(response->get<picojson::object>());
+ break;
+ case BT_ERROR_NOW_IN_PROGRESS:
+ throw ServiceNotAvailableException("Bluetooth device is busy");
+ default:
+ throw UnknownException("Unknown exception");
+ }
+ } catch (const PlatformException& err) {
+ util::ReportError(err, response->get<picojson::object>());
+ }
+
+ util::AsyncResponse(
+ adapter->user_request_callback_[SET_POWERED], response);
+ adapter->user_request_list_[SET_POWERED] = false;
+ }
+}
+
+void BluetoothAdapter::NameChangedCB(char *name, void *user_data) {
+ LoggerD("Entered");
+
+ BluetoothAdapter* adapter = static_cast<BluetoothAdapter*>(user_data);
+ if (!adapter) {
+ LoggerD("User data is NULL");
+ return;
+ }
+
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnNameChanged)));
+ data_obj->insert(std::make_pair(kName, picojson::value(name)));
+
+ util::FireEvent(kAdapterChangeCallbackEvent, value);
+
+ if (adapter->user_request_list_[SET_NAME] && name == adapter->requested_name_) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::AsyncResponse(adapter->user_request_callback_[SET_NAME], response);
+ adapter->user_request_list_[SET_NAME] = false;
+ }
+}
+
+void BluetoothAdapter::VisibilityChangedCB(int result, bt_adapter_visibility_mode_e mode, void *user_data) {
+ LoggerD("Entered");
+
+ BluetoothAdapter* adapter = static_cast<BluetoothAdapter*>(user_data);
+ if (!adapter) {
+ LoggerD("User data is NULL");
+ return;
+ }
+
+ bool visible = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE != mode;
+ bool previous_visible = adapter->is_visible_;
+ adapter->is_visible_ = visible;
+
+ if (previous_visible != visible) {
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnVisibilityChanged)));
+ data_obj->insert(std::make_pair(kAdapterVisible, picojson::value(visible)));
+
+ util::FireEvent(kAdapterChangeCallbackEvent, value);
+ }
+
+ if (adapter->user_request_list_[SET_VISIBLE] && adapter->requested_visibility_ == mode) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+ if (BT_ERROR_NONE == result) {
+ util::ReportSuccess(response->get<picojson::object>());
+ } else {
+ util::ReportError(UnknownException("Unknown exception"),
+ response->get<picojson::object>());
+ }
+
+ util::AsyncResponse(
+ adapter->user_request_callback_[SET_VISIBLE], response);
+ adapter->user_request_list_[SET_VISIBLE] = false;
+ }
+}
+
+static bool ForeachBondedDevicesCB(bt_device_info_s *device_info, void *user_data)
+{
+ LoggerD("Entered");
+ if (nullptr == user_data) {
+ LoggerD("user data is NULL.");
+ return false;
+ }
+
+ if (nullptr == device_info) {
+ LoggerD("Device info is not valid.");
+ return false;
+ }
+
+ picojson::array* array = static_cast<picojson::array*>(user_data);
+ for (auto iter = array->begin(); iter != array->end(); iter++) {
+ if (!strcmp(device_info->remote_address, ((*iter).get<picojson::object>())
+ .find(kDeviceAddress)->second.get<std::string>().c_str())) {
+ BluetoothDevice::ToJson(device_info, &iter->get<picojson::object>());
+ return true;
+ }
+ }
+
+ array->push_back(picojson::value(picojson::object()));
+
+ BluetoothDevice::ToJson(device_info, &array->back().get<picojson::object>());
+ return true;
+}
+
+void BluetoothAdapter::DiscoveryStateChangedCB(
+ int result,
+ bt_adapter_device_discovery_state_e discovery_state,
+ bt_adapter_device_discovery_info_s *discovery_info,
+ void *user_data)
+{
+ LoggerD("Entered");
+
+ BluetoothAdapter* adapter = static_cast<BluetoothAdapter*>(user_data);
+ if (!adapter) {
+ LoggerD("User data is NULL");
+ return;
+ }
+
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ switch(discovery_state) {
+ case BT_ADAPTER_DEVICE_DISCOVERY_STARTED: {
+ if (adapter->user_request_list_[DISCOVER_DEVICES]) {
+ if (BT_ERROR_NONE == result) {
+ //store addresses of previously found devices into disappeared_addresses
+ adapter->disappeared_addresses_ = adapter->discovered_addresses_;
+ adapter->discovered_addresses_.clear();
+ adapter->discovered_devices_.clear();
+
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnDiscoverStarted)));
+ util::FireEvent(kAdapterDiscoverSuccessEvent, value);
+ } else {
+ util::ReportError(UnknownException("Unknown error"), *data_obj);
+ util::FireEvent(kAdapterDiscoverErrorEvent, value);
+ adapter->user_request_list_[DISCOVER_DEVICES] = false;
+ }
+ }
+ break;
+ }
+ case BT_ADAPTER_DEVICE_DISCOVERY_FINISHED: {
+ if (BT_ERROR_NONE == result || BT_ERROR_CANCELLED == result) {
+ if (adapter->user_request_list_[DISCOVER_DEVICES]) {
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnDiscoverFinished)));
+
+ for (auto it : adapter->disappeared_addresses_) {
+ picojson::value disapeared_val = picojson::value(picojson::object());
+ picojson::object* disapeared_obj = &disapeared_val.get<picojson::object>();
+
+ disapeared_obj->insert(std::make_pair(kAction,
+ picojson::value(kOnDiscoverDisappeared)));
+ disapeared_obj->insert(std::make_pair(kData, picojson::value(it)));
+
+ util::FireEvent(kAdapterDiscoverSuccessEvent, disapeared_val);
+ }
+
+ data_obj->insert(std::make_pair(kData,
+ picojson::value(adapter->discovered_devices_)));
+ util::FireEvent(kAdapterDiscoverSuccessEvent, value);
+
+ adapter->user_request_list_[DISCOVER_DEVICES] = false;
+ }
+
+ if (adapter->user_request_list_[STOP_DISCOVERY]) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+ util::ReportSuccess(response->get<picojson::object>());
+ util::AsyncResponse(
+ adapter->user_request_callback_[STOP_DISCOVERY], response);
+
+ adapter->user_request_list_[STOP_DISCOVERY] = false;
+ }
+ }
+ break;
+ }
+ case BT_ADAPTER_DEVICE_DISCOVERY_FOUND: {
+ if (adapter->user_request_list_[DISCOVER_DEVICES]) {
+ if (BT_ERROR_NONE == result &&
+ adapter->discovered_addresses_.insert(
+ discovery_info->remote_address).second) {
+ adapter->disappeared_addresses_.erase(discovery_info->remote_address);
+
+ data_obj->insert(std::make_pair(kAction, picojson::value(kOnDiscoverFound)));
+ picojson::value& data = data_obj->insert(std::make_pair(kData,
+ picojson::value(picojson::object()))).first->second;
+
+ BluetoothDevice::ToJson(discovery_info, &data.get<picojson::object>());
+ adapter->discovered_devices_.push_back(data);
+
+ util::FireEvent(kAdapterDiscoverSuccessEvent, value);
+ }
+ }
+ break;
+ }
+ default:
+ LoggerD("Unknown state");
+ break;
+ }
+}
+
+BluetoothAdapter::BluetoothAdapter() :
+ is_visible_(false),
+ is_powered_(false),
+ is_initialized_(false)
+{
+ LoggerD("Entered");
+ if (BT_ERROR_NONE == bt_initialize()) {
+ LoggerD("Bluetooth service is initialized.");
+ is_initialized_ = true;
+
+ int ret = BT_ERROR_NONE;
+ ret |= bt_adapter_set_device_discovery_state_changed_cb(DiscoveryStateChangedCB, this);
+ ret |= bt_adapter_set_state_changed_cb(StateChangedCB, this);
+ ret |= bt_adapter_set_name_changed_cb(NameChangedCB, this);
+ ret |= bt_adapter_set_visibility_mode_changed_cb(VisibilityChangedCB, this);
+
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("Setting listeners function failed.");
+ }
+ } else {
+ LoggerE("Bluetooth service initialization failed.");
+ }
+
+ bt_adapter_state_e state;
+ if (BT_ERROR_NONE == bt_adapter_get_state(&state)) {
+ is_powered_ = BT_ADAPTER_ENABLED == state;
+ }
+
+ bt_adapter_visibility_mode_e mode;
+ if (BT_ERROR_NONE == bt_adapter_get_visibility(&mode, nullptr)) {
+ is_visible_ = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE != mode;
+ }
+}
+
+BluetoothAdapter::~BluetoothAdapter() {
+ bt_socket_unset_data_received_cb();
+ bt_socket_unset_connection_state_changed_cb();
+
+ for (auto it : connected_sockets_) {
+ bt_socket_disconnect_rfcomm(it);
+ }
+
+ for (auto it : registered_uuids_) {
+ bt_socket_destroy_rfcomm(it.second.first);
+ }
+
+ bt_adapter_unset_state_changed_cb();
+ bt_adapter_unset_name_changed_cb();
+ bt_adapter_unset_visibility_mode_changed_cb();
+ bt_adapter_unset_device_discovery_state_changed_cb();
+
+ if (is_initialized_) {
+ if (BT_ERROR_NONE == bt_deinitialize()) {
+ LoggerD("Bluetooth service is deinitialized.");
+ } else {
+ LoggerE("Bluetooth service deinitialization failed.");
+ }
+ }
+}
+
+BluetoothAdapter& BluetoothAdapter::GetInstance() {
+ static BluetoothAdapter instance;
+ return instance;
+}
+
+std::string BluetoothAdapter::get_name() const {
+ char* name = nullptr;
+ std::string str_name = "";
+ if (BT_ERROR_NONE == bt_adapter_get_name(&name)) {
+ if (name) {
+ str_name = name;
+ free(name);
+ }
+ }
+
+ return str_name;
+}
+
+bool BluetoothAdapter::get_visible() const {
+ bt_adapter_visibility_mode_e mode;
+
+ if (BT_ERROR_NONE == bt_adapter_get_visibility(&mode, NULL)) {
+ return mode != BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
+ }
+
+ return false;
+}
+
+void BluetoothAdapter::set_visible(bool visible) {
+ is_visible_ = visible;
+}
+
+bool BluetoothAdapter::get_powered() {
+ return is_powered_;
+}
+
+void BluetoothAdapter::set_powered(bool powered) {
+ is_powered_ = powered;
+}
+
+bool BluetoothAdapter::is_initialized() const {
+ return is_initialized_;
+}
+
+void BluetoothAdapter::SetName(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothAdmin);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+ const auto name = FromJson<std::string>(args, "name");
+
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->get_powered()) {
+ if (get_name() == name) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportSuccess(response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+
+ if (this->user_request_list_[SET_NAME]) {
+ throw ServiceNotAvailableException("Already requested");
+ }
+
+ this->user_request_list_[SET_NAME] = true;
+ this->user_request_callback_[SET_NAME] = callback_handle;
+
+ int ret = bt_adapter_set_name(name.c_str());
+ switch(ret) {
+ case BT_ERROR_NONE:
+ //bt_adapter_name_changed_cb() will be invoked
+ //if this function returns #BT_ERROR_NONE
+ this->requested_name_ = name;
+ break;
+ case BT_ERROR_INVALID_PARAMETER:
+ throw InvalidValuesException("Invalid value");
+ default:
+ throw UnknownException("Unknown exception");
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ this->user_request_list_[SET_NAME] = false;
+ return;
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::SetPowered(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothAdmin);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+ const auto new_powered = FromJson<bool>(args, "powered");
+
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->user_request_list_[SET_POWERED]) {
+ throw ServiceNotAvailableException("Already requested");
+ }
+
+ bool cur_powered = this->get_powered();
+
+ if (new_powered != cur_powered) {
+ this->requested_powered_ = new_powered;
+ this->user_request_list_[SET_POWERED] = true;
+ this->user_request_callback_[SET_POWERED] = callback_handle;
+
+ if (new_powered) {
+ bt_adapter_enable();
+ } else {
+ bt_adapter_disable();
+ }
+ } else {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportSuccess(response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::SetVisible(const picojson::value& data, picojson::object& out)
+{
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothManager);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+ const auto visible = FromJson<bool>(args, "visible");
+
+ unsigned short timeout = kTimeout;
+ if (visible) {
+ timeout = static_cast<unsigned short>(FromJson<double>(args, "timeout"));
+ }
+
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->user_request_list_[SET_VISIBLE]) {
+ throw ServiceNotAvailableException("Already requested");
+ }
+
+ if (this->get_powered()) {
+ bt_adapter_visibility_mode_e mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
+ if (visible) {
+ if (0 == timeout) {
+ mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
+ } else {
+ mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
+ }
+ }
+
+ bt_adapter_visibility_mode_e current = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
+ int time = 0;
+ if (BT_ERROR_NONE != bt_adapter_get_visibility(¤t , &time)) {
+ throw UnknownException("Unknown exception");
+ }
+
+ if (mode == current) {
+ if (BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE != mode ||
+ (unsigned int)time != timeout) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportSuccess(response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+ }
+
+ this->requested_visibility_ = mode;
+ this->user_request_list_[SET_VISIBLE] = true;
+ this->user_request_callback_[SET_VISIBLE] = callback_handle;
+ int ret = bt_adapter_set_visibility(mode, timeout);
+
+ switch(ret) {
+ case BT_ERROR_NONE:
+ //bt_adapter_visibility_mode_changed_cb() will be invoked
+ //if this function returns #BT_ERROR_NONE
+ break;
+ case BT_ERROR_INVALID_PARAMETER:
+ throw InvalidValuesException("Invalid value");
+ default:
+ throw UnknownException("Unknown exception");
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::DiscoverDevices(const picojson::value& /* data */, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ try {
+ if (!is_initialized_) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->user_request_list_[DISCOVER_DEVICES]) {
+ throw ServiceNotAvailableException("Already requested");
+ }
+
+ if (!get_powered()) {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+
+ this->user_request_list_[DISCOVER_DEVICES] = true;
+ bt_adapter_start_device_discovery();
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ TaskQueue::GetInstance().Async<picojson::value>([](const std::shared_ptr<picojson::value>& result) {
+ util::FireEvent(kAdapterDiscoverErrorEvent, result);
+ }, response);
+ return;
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::StopDiscovery(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->user_request_list_[STOP_DISCOVERY]) {
+ throw ServiceNotAvailableException("Already requested");
+ }
+
+ if (this->get_powered()) {
+ bool is_discovering = false;
+ bt_adapter_is_discovering(&is_discovering);
+
+ if (!is_discovering) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportSuccess(response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+
+ this->user_request_list_[STOP_DISCOVERY] = true;
+ this->user_request_callback_[STOP_DISCOVERY] = callback_handle;
+ int ret = bt_adapter_stop_device_discovery();
+ switch(ret) {
+ case BT_ERROR_NONE: {
+ //This function invokes bt_adapter_device_discovery_state_changed_cb().
+ break;
+ }
+ default: {
+ this->user_request_list_[STOP_DISCOVERY] = false;
+ throw UnknownException("Unknown error");
+ }
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ return;
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::GetKnownDevices(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+
+ auto get_known_devices = [this](const std::shared_ptr<picojson::value>& response) -> void {
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+ if (this->get_powered()) {
+ picojson::object& response_obj = response->get<picojson::object>();
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get<picojson::object>();
+ picojson::array& array = result_obj.insert(
+ std::make_pair("devices", picojson::value(
+ picojson::array()))).first->second.get<picojson::array>();
+
+ array = discovered_devices_;
+
+ if (BT_ERROR_NONE == bt_adapter_foreach_bonded_device(
+ ForeachBondedDevicesCB, &array)) {
+ util::ReportSuccess(result, response_obj);
+ } else {
+ throw UnknownException("Unknown exception");
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ util::ReportError(err, response->get<picojson::object>());
+ }
+ };
+ auto get_known_devices_response = [callback_handle](
+ const std::shared_ptr<picojson::value>& response) -> void {
+ util::SyncResponse(callback_handle, response);
+ };
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ get_known_devices,
+ get_known_devices_response,
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::GetDevice(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+
+ const auto& address = FromJson<std::string>(args, "address");
+
+ auto get_device = [this, address](const std::shared_ptr<picojson::value>& response) -> void {
+ try {
+ if (!IsValidAddress(address)) {
+ throw NotFoundException("Wrong address");
+ }
+
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+ if (this->get_powered()) {
+ picojson::object& response_obj = response->get<picojson::object>();
+ bt_device_info_s *info = nullptr;
+
+ if (bt_adapter_get_bonded_device_info(address.c_str(), &info) == BT_ERROR_NONE &&
+ info != nullptr) {
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get<picojson::object>();
+
+ BluetoothDevice::ToJson(info, &result_obj);
+ util::ReportSuccess(result, response_obj);
+ bt_adapter_free_device_info(info);
+ return;
+ }
+
+ auto is_address = discovered_addresses_.find(address);
+ if (is_address != discovered_addresses_.end()) {
+ for (auto iter = discovered_devices_.begin();
+ iter != discovered_devices_.end(); iter++) {
+ if (!strcmp(address.c_str(), ((*iter).get<picojson::object>())
+ .find(kDeviceAddress)->second.get<std::string>().c_str())) {
+ util::ReportSuccess(*iter, response_obj);
+ return;
+ }
+ }
+ } else {
+ throw NotFoundException("There is no device with the given address");
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ util::ReportError(err, response->get<picojson::object>());
+ }
+ };
+
+ auto get_device_response = [callback_handle](
+ const std::shared_ptr<picojson::value>& response) -> void {
+ util::SyncResponse(callback_handle, response);
+ };
+
+ TaskQueue::GetInstance().Queue<picojson::value>(
+ get_device,
+ get_device_response,
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+
+ util::ReportSuccess(out);
+}
+
+class BondingHandler {
+public:
+ BondingHandler(double callback_handle, const std::string& address) :
+ callback_handle_(callback_handle), address_(address) {}
+
+ void set_address(const std::string& address) {
+ address_ = address;
+ }
+
+ const std::string& address() const {
+ return address_;
+ }
+
+ void Invoke(const std::shared_ptr<picojson::value>& response) {
+ LoggerD("Entered");
+ util::AsyncResponse(callback_handle_, response);
+ }
+
+private:
+ double callback_handle_;
+ std::string address_;
+};
+
+void BluetoothAdapter::CreateBonding(const picojson::value& data, picojson::object& out)
+{
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+
+ const auto& address = FromJson<std::string>(args, "address");
+
+ auto create_bonding = [address, callback_handle, this]() -> void {
+ try {
+ if(!IsValidAddress(address)) {
+ throw InvalidValuesException("Wrong address");
+ }
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->get_powered()) {
+
+ auto bond_create_callback = [](int callback_result,
+ bt_device_info_s *device_info,
+ void *user_data) {
+ LoggerD("bond_create_callback");
+
+ BondingHandler* handler = static_cast<BondingHandler*>(user_data);
+ if (!handler) {
+ LoggerW("user_data is nullptr");
+ return;
+ }
+ if (!device_info) {
+ LoggerW("device_info is nullptr");
+ return;
+ }
+
+ if (!strcmp(handler->address().c_str(), device_info->remote_address)) { // requested event
+ try {
+ if (BT_ERROR_NONE == callback_result && nullptr != device_info ) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ picojson::object& response_obj = response->get<picojson::object>();
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get<picojson::object>();
+
+ BluetoothDevice::ToJson(device_info, &result_obj);
+ util::ReportSuccess(result, response_obj);
+ handler->Invoke(response);
+ } else if (BT_ERROR_REMOTE_DEVICE_NOT_FOUND == callback_result) {
+ LoggerE("Not found");
+ throw ServiceNotAvailableException("Not found");
+ } else {
+ LoggerE("Unknown exception");
+ throw UnknownException("Unknown exception");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ handler->Invoke(response);
+ }
+ delete handler;
+ bt_device_unset_bond_created_cb();
+ } else { // unexpected event
+ LoggerD("An unexpected bonding detected");
+ }
+ };
+
+ BondingHandler* handler = new BondingHandler(callback_handle, address);
+ bt_device_set_bond_created_cb(bond_create_callback, handler);
+ int ret = bt_device_create_bond(address.c_str());
+
+ switch(ret) {
+ case BT_ERROR_NONE:
+ {
+ LoggerD("bt_device_create_bond() succeeded");
+ break;
+ }
+ case BT_ERROR_INVALID_PARAMETER:
+ {
+ LoggerE("Not found");
+ bt_device_unset_bond_created_cb();
+ delete handler;
+ throw InvalidValuesException("Invalid value");
+ }
+ default:
+ {
+ LoggerE("Unknown exception");
+ bt_device_unset_bond_created_cb();
+ delete handler;
+ throw UnknownException("Unknown exception");
+ }
+ }
+ } else { // Not powered
+ LoggerE("Bluetooth device is turned off");
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ }
+ };
+ TaskQueue::GetInstance().Queue(create_bonding);
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::DestroyBonding(const picojson::value& data, picojson::object& out)
+{
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothGap);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+
+ const auto& address = FromJson<std::string>(args, "address");
+
+ auto destroy_bonding = [address, callback_handle, this]() -> void {
+ try {
+ if(!IsValidAddress(address)) {
+ throw InvalidValuesException("Wrong address");
+ }
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (this->get_powered()) {
+ bt_device_info_s *device_info = nullptr;
+ int ret = bt_adapter_get_bonded_device_info(address.c_str(), &device_info);
+
+ if (BT_ERROR_NONE != ret || nullptr == device_info) {
+ LoggerD("There is no bonding");
+ throw NotFoundException("Not found");
+ } else {
+ bt_adapter_free_device_info(device_info);
+
+ auto bond_destroy_callback = [](int callback_result,
+ char *remote_address,
+ void *user_data) {
+ LoggerD("bond_destroy_callback");
+
+ BondingHandler* handler = static_cast<BondingHandler*>(user_data);
+ if (!handler) {
+ LoggerW("user_data is nullptr");
+ return;
+ }
+
+ if (!strcmp(handler->address().c_str(), remote_address)) { // requested event
+ try {
+ if (BT_ERROR_NONE == callback_result) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportSuccess(response->get<picojson::object>());
+ handler->Invoke(response);
+ } else {
+ LoggerE("Unknown exception");
+ throw UnknownException("Unknown exception");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ handler->Invoke(response);
+ }
+ delete handler;
+ bt_device_unset_bond_destroyed_cb();
+ } else { // unexpected event
+ LoggerD("An unexpected bonding detected");
+ }
+ };
+
+ BondingHandler* handler = new BondingHandler(callback_handle, address);
+ bt_device_set_bond_destroyed_cb(bond_destroy_callback, handler);
+
+ int ret = bt_device_destroy_bond(address.c_str());
+
+ switch(ret) {
+ case BT_ERROR_NONE:
+ {
+ LoggerD("bt_device_destroy_bond() succeeded");
+ break;
+ }
+ case BT_ERROR_INVALID_PARAMETER:
+ {
+ LoggerE("Not found");
+ bt_device_unset_bond_destroyed_cb();
+ delete handler;
+ throw InvalidValuesException("Invalid value");
+ }
+ default:
+ {
+ LoggerE("Unknown exception");
+ bt_device_unset_bond_destroyed_cb();
+ delete handler;
+ throw UnknownException("Unknown exception");
+ }
+ }
+ }
+ } else { // Not powered
+ LoggerE("Bluetooth device is turned off");
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(err, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ }
+ };
+ TaskQueue::GetInstance().Queue(destroy_bonding);
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::RegisterRFCOMMServiceByUUID(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+ const auto& args = util::GetArguments(data);
+
+ const auto& uuid = FromJson<std::string>(args, "uuid");
+ const auto& name = FromJson<std::string>(args, "name");
+
+ auto rfcomm = [this, uuid, name](const std::shared_ptr<picojson::value>& response) -> void {
+ try {
+ if (!this->is_initialized()) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ if (!IsValidUUID(uuid)) {
+ throw InvalidValuesException("Wrong UUID");
+ }
+
+ if (this->get_powered()) {
+ bool is_registered = false;
+ int ret = bt_adapter_is_service_used(uuid.c_str(), &is_registered);
+
+ if (BT_ERROR_NONE == ret && is_registered) {
+ throw InvalidValuesException("Already registered");
+ }
+
+ int socket = -1;
+ ret = bt_socket_create_rfcomm(uuid.c_str(), &socket);
+
+ switch (ret) {
+ case BT_ERROR_NONE: {
+ int ret_in = bt_socket_listen_and_accept_rfcomm(socket, 0);
+ switch(ret_in) {
+ case BT_ERROR_NONE: {
+ LoggerD("bt_socket_listen() succeeded");
+ bt_socket_set_connection_state_changed_cb(OnSocketConnected, this);
+
+ registered_uuids_.insert(std::make_pair(uuid,
+ std::make_pair(socket, false)));
+
+ util::ReportSuccess(response->get<picojson::object>());
+ break;
+ }
+
+ case BT_ERROR_INVALID_PARAMETER: {
+ throw InvalidValuesException("Invalid value");
+ break;
+ }
+
+ default: {
+ throw UnknownException("Unknown error");
+ break;
+ }
+ }
+ break;
+ }
+
+ case BT_ERROR_INVALID_PARAMETER:
+ throw InvalidValuesException("Invalid value");
+ break;
+
+ default:
+ throw UnknownException("Unknown error");
+ break;
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& err) {
+ util::ReportError(err, response->get<picojson::object>());
+ }
+ };
+
+ auto rfcomm_response = [callback_handle](const std::shared_ptr<picojson::value>& response) -> void {
+ util::SyncResponse(callback_handle, response);
+ };
+
+ TaskQueue::GetInstance().Queue<picojson::value>(rfcomm, rfcomm_response,
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::UnregisterUUID(const std::string& uuid, int callback_handle) {
+ LoggerD("Entered");
+
+ if (!IsValidUUID(uuid)) {
+ throw InvalidValuesException("Wrong UUID");
+ }
+
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+ try {
+ if (is_powered_) {
+ auto iter = registered_uuids_.find(uuid);
+ if (iter != registered_uuids_.end()) {
+ if (BT_ERROR_NONE == bt_socket_destroy_rfcomm(iter->second.first)) {
+ registered_uuids_.erase(iter);
+ } else {
+ throw UnknownException("Unknown error");
+ }
+ }
+
+ if (registered_uuids_.size() == 0 &&
+ connection_requests_.size() == 0 &&
+ connected_sockets_.size() == 0) {
+ bt_socket_unset_connection_state_changed_cb();
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+
+ util::ReportSuccess(response->get<picojson::object>());
+ } catch (const PlatformException& err) {
+ util::ReportError(err, response->get<picojson::object>());
+ }
+
+ util::AsyncResponse(callback_handle, response);
+}
+
+void BluetoothAdapter::GetBluetoothProfileHandler(const picojson::value& data,
+ picojson::object& out) {
+ LoggerD("Entered");
+
+ const auto& args = util::GetArguments(data);
+ auto profile = FromJson<std::string>(args, "profileType");
+
+ if (kBluetoothProfileHealth == profile) {
+ bool supported = false;
+ if (SYSTEM_INFO_ERROR_NONE != system_info_get_platform_bool(kFeatureBluetoothHealth.c_str(),
+ &supported)) {
+ LoggerW("Can't check if BT health profile is supported or not");
+ }
+
+ if (!supported) {
+ throw NotSupportedException("Bluetooth health profile is not supported");
+ } else {
+ LoggerD("BT health profile is supported");
+ }
+ } else {
+ throw TypeMismatchException("Wrong profile type.");
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothAdapter::GetName(const picojson::value& /* data */, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::ReportSuccess(picojson::value(get_name()), out);
+}
+
+void BluetoothAdapter::GetAddress(const picojson::value& /* data */, picojson::object& out) {
+ LoggerD("Entered");
+
+ if (!is_initialized_) {
+ throw UnknownException("Bluetooth service is not initialized.");
+ }
+
+ std::string str_address = "";
+ char* address = nullptr;
+ if (BT_ERROR_NONE == bt_adapter_get_address(&address)) {
+ if (address) {
+ str_address = address;
+ free(address);
+ }
+ }
+
+ util::ReportSuccess(picojson::value(str_address), out);
+}
+
+void BluetoothAdapter::GetPowered(const picojson::value& /* data */, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::ReportSuccess(picojson::value(is_powered_), out);
+}
+
+void BluetoothAdapter::GetVisible(const picojson::value& /* data */, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::ReportSuccess(picojson::value(get_visible()), out);
+}
+
+void BluetoothAdapter::OnSocketConnected(int result,
+ bt_socket_connection_state_e state,
+ bt_socket_connection_s* connection,
+ void* user_data) {
+ LoggerD("Entered");
+
+ BluetoothAdapter* object = static_cast<BluetoothAdapter*>(user_data);
+
+ if (!object) {
+ LoggerW("user_data is NULL");
+ return;
+ }
+
+ if (!connection) {
+ LoggerW("connection is NULL");
+ return;
+ }
+
+ if (BT_SOCKET_SERVER == connection->local_role) {
+ LoggerD("Server");
+
+ const auto iter = object->registered_uuids_.find(connection->service_uuid);
+ if (iter == object->registered_uuids_.end()) {
+ LoggerW("Connection state has changed unexpectedly");
+ return;
+ }
+
+ if (BT_SOCKET_CONNECTED == state) { // connected when Server
+ if (BT_ERROR_NONE == result) {
+ // Update registered_uuids_ state
+ iter->second.second = true;
+
+ // Call BluetoothServiceHandler.onconnect
+ util::FireEvent("BLUETOOTH_SERVICE_ONCONNECT", BluetoothSocket::ToJson(connection));
+
+ // Update connected_sockets_
+ object->connected_sockets_.push_back(connection->socket_fd);
+ bt_socket_set_data_received_cb(OnSocketReceivedData, user_data);
+ } else {
+ LoggerW("Establishing a connection failed");
+ }
+ return;
+ } else { // disconnected when Server
+ if (BT_ERROR_NONE == result) {
+ // Update registered_uuids_ state
+ iter->second.second = false;
+
+ object->RemoveSocket(connection->socket_fd);
+ }
+ else {
+ LoggerW("Disconnecting a connection failed");
+ }
+ }
+ } else if (BT_SOCKET_CLIENT == connection->local_role) {
+ LoggerD("Client");
+
+ if (BT_SOCKET_CONNECTED == state) { // connected when Client
+ const auto range = object->connection_requests_.equal_range(connection->remote_address);
+ const auto end = object->connection_requests_.end();
+ auto request = end;
+
+ for (auto it = range.first; it != range.second; ++it) {
+ if (strcmp(it->second->uuid_.c_str(), connection->service_uuid) == 0) {
+ request = it;
+ break;
+ }
+ }
+
+ if (end == request) {
+ LoggerW("Connection state has changed unexpectedly");
+ return;
+ }
+
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
+ if (BT_ERROR_NONE == result) {
+ object->connected_sockets_.push_back(connection->socket_fd);
+ bt_socket_set_data_received_cb(OnSocketReceivedData, user_data);
+
+ util::ReportSuccess(BluetoothSocket::ToJson(connection),
+ response->get<picojson::object>());
+ } else {
+ util::ReportError(NotFoundException("Not found"),
+ response->get<picojson::object>());
+ }
+
+ util::AsyncResponse(request->second->callback_handle_, response);
+
+ // request has been handled, can be safely removed
+ object->connection_requests_.erase(request);
+ } else { // disconnected when Client
+ if (result == BT_ERROR_NONE) {
+ object->RemoveSocket(connection->socket_fd);
+ } else {
+ LoggerW("Disconnecting a connection failed");
+ }
+ }
+ } else {
+ LoggerW("Unknown role");
+ return;
+ }
+
+ if (object->connected_sockets_.size() == 0) {
+ bt_socket_unset_data_received_cb();
+ }
+
+ if (object->registered_uuids_.size() == 0 &&
+ object->connection_requests_.size() == 0 &&
+ object->connected_sockets_.size() == 0) {
+ bt_socket_unset_connection_state_changed_cb();
+ }
+}
+
+void BluetoothAdapter::OnSocketReceivedData(bt_socket_received_data_s* data, void* user_data) {
+ LoggerD("Entered");
+
+ BluetoothAdapter* object = static_cast<BluetoothAdapter*>(user_data);
+
+ if (!object) {
+ LoggerW("user_data is NULL");
+ return;
+ }
+
+ if (!data) {
+ LoggerW("data is NULL");
+ return;
+ }
+
+ const auto it = std::find(object->connected_sockets_.begin(),
+ object->connected_sockets_.end(),
+ data->socket_fd);
+
+ if (it == object->connected_sockets_.end()) {
+ LoggerW("Unknown connected socket: %d", data->socket_fd);
+ return;
+ }
+
+ // Store received data
+ object->StoreSocketData(data);
+
+ InvokeSocketOnMessageEvent(*it);
+}
+
+void BluetoothAdapter::ConnectToServiceByUUID(const std::string& address,
+ const std::string& uuid,
+ double callback_handle) {
+ LoggerD("Entered");
+
+ if (!IsValidUUID(uuid)) {
+ throw InvalidValuesException("Wrong UUID");
+ }
+
+ try {
+ if (is_powered_) {
+ int ret = bt_socket_connect_rfcomm(address.c_str(), uuid.c_str());
+
+ switch (ret) {
+ case BT_ERROR_NONE: {
+ LoggerD("bt_socket_connect_rfcomm() succeeded");
+
+ ConnectionRequestPtr request{new ConnectionRequest()};
+ request->uuid_ = uuid;
+ request->callback_handle_ = callback_handle;
+ connection_requests_.insert(std::make_pair(address, request));
+
+ bt_socket_set_connection_state_changed_cb(OnSocketConnected, this);
+ break;
+ }
+
+ case BT_ERROR_INVALID_PARAMETER:
+ case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
+ throw InvalidValuesException("Invalid value");
+ break;
+
+ default:
+ throw UnknownException("Unknown error");
+ break;
+ }
+ } else {
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ }
+ } catch (const PlatformException& e) {
+ std::shared_ptr<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ util::ReportError(e, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ }
+}
+
+
+static void InvokeSocketEvent(int id, const char* event) {
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object& value_obj = value.get<picojson::object>();
+ value_obj.insert(std::make_pair("id", picojson::value(std::to_string(id))));
+ value_obj.insert(std::make_pair("event", picojson::value(event)));
+ util::FireEvent("BLUETOOTH_SOCKET_STATE_CHANGED", value);
+}
+
+void BluetoothAdapter::InvokeSocketOnMessageEvent(int id) {
+ InvokeSocketEvent(id, "onmessage");
+}
+
+void BluetoothAdapter::InvokeSocketOnCloseEvent(int id) {
+ InvokeSocketEvent(id, "onclose");
+}
+
+void BluetoothAdapter::RemoveSocket(int socket) {
+ const auto data_it = socket_data_.find(socket);
+
+ if (data_it != socket_data_.end()) {
+ socket_data_.erase(data_it);
+ } else {
+ LoggerD("No stored data for socket: %d", socket);
+ }
+
+ const auto it = std::find(connected_sockets_.begin(),
+ connected_sockets_.end(),
+ socket);
+
+ if (it == connected_sockets_.end()) {
+ LoggerW("Unknown connected socket: %d", socket);
+ return;
+ }
+
+ connected_sockets_.erase(it);
+
+ BluetoothAdapter::InvokeSocketOnCloseEvent(*it);
+}
+
+void BluetoothAdapter::StoreSocketData(bt_socket_received_data_s* data) {
+ LoggerD("Entered");
+
+ auto data_store = socket_data_[data->socket_fd];
+
+ for (int i = 0; i < data->data_size; ++i) {
+ data_store.push_back(data->data[i]);
+ }
+}
+
+const std::list<char>& BluetoothAdapter::ReadSocketData(int socket) {
+ LoggerD("Entered");
+
+ return socket_data_[socket];
+}
+
+void BluetoothAdapter::ClearSocketData(int socket) {
+ LoggerD("Entered");
+
+ const auto data_it = socket_data_.find(socket);
+
+ if (data_it != socket_data_.end()) {
+ data_it->second.clear();
+ }
+}
+
+void BluetoothAdapter::IsServiceConnected(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ const auto& args = util::GetArguments(data);
+ const auto& uuid = FromJson<std::string>(args, "uuid");
+
+ auto iter = registered_uuids_.find(uuid);
+ if (iter == registered_uuids_.end()) {
+ throw InvalidValuesException("Invalid parameter was passed.");
+ }
+
+ util::ReportSuccess(picojson::value(iter->second.second), out);
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_ADAPTER_H_
+#define BLUETOOTH_BLUETOOTH_ADAPTER_H_
+
+#include <set>
+#include <list>
+#include <memory>
+#include <unordered_map>
+#include <map>
+
+#include <bluetooth.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+enum AdapterAsyncEvent {
+ SET_POWERED = 0,
+ SET_NAME,
+ SET_VISIBLE,
+ DISCOVER_DEVICES,
+ STOP_DISCOVERY
+};
+
+class BluetoothAdapter {
+public:
+ /**
+ * Signature: @code void setName(name, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_setName', args: {name: name}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void SetName(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void setPowered(state, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_setPowered', args: {state: state}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void SetPowered(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void setVisible(mode, successCallback, errorCallback, timeout); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_setVisible', args: {mode: mode, timeout: timeout}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void SetVisible(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void discoverDevices(discoveryCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_discoverDevices', args: {discoveryCallbackId: id}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Discovery callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {event, eventData}}
+ * @endcode
+ */
+ void DiscoverDevices(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void stopDiscovery(successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_stopDiscovery', args: {}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void StopDiscovery(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void getKnownDevices(successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getKnownDevices', args: {}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {devices[]}}
+ * @endcode
+ */
+ void GetKnownDevices(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void getDevice(address, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getDevice', args: {address: address}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {device}}
+ * @endcode
+ */
+ void GetDevice(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void createBonding(address, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_createBonding', args: {address: address}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {device}}
+ * @endcode
+ */
+ void CreateBonding(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void destroyBonding(address, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_destroyBonding', args: {address: address}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void DestroyBonding(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void registerRFCOMMServiceByUUID(uuid, name, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_registerRFCOMMServiceByUUID',
+ * args: {uuid: uuid, name: name}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {handler}}
+ * @endcode
+ */
+ void RegisterRFCOMMServiceByUUID(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothProfileHandler getBluetoothProfileHandler(profileType); @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getBluetoothProfileHandler',
+ * args: {profileType: profileType}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {BluetoothProfileHandler}}
+ * @endcode
+ */
+ void GetBluetoothProfileHandler(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothAdapter.name; @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getName', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: name}
+ * @endcode
+ */
+ void GetName(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothAdapter.address; @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getAddress', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: address}
+ * @endcode
+ */
+ void GetAddress(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothAdapter.powered; @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getPowered', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: powered}
+ * @endcode
+ */
+ void GetPowered(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothAdapter.visible; @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_getVisible', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: visible}
+ * @endcode
+ */
+ void GetVisible(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothServiceHandler.isConnected; @endcode
+ * JSON: @code data: {method: 'BluetoothAdapter_isConnected', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: isConnected}
+ * @endcode
+ */
+ void IsServiceConnected(const picojson::value& data, picojson::object& out);
+
+ static BluetoothAdapter& GetInstance();
+ virtual ~BluetoothAdapter();
+
+ std::string get_name() const;
+ bool get_visible() const;
+ void set_visible(bool visible);
+ bool get_powered();
+ void set_powered(bool powered);
+ bool is_initialized() const;
+
+ void ConnectToServiceByUUID(const std::string& address,
+ const std::string& uuid,
+ double callback_handle);
+
+ const std::list<char>& ReadSocketData(int socket);
+
+ void ClearSocketData(int socket);
+
+ void UnregisterUUID(const std::string& uuid, int callback_handle);
+
+private:
+ BluetoothAdapter();
+ BluetoothAdapter(const BluetoothAdapter&) = delete;
+ BluetoothAdapter& operator=(const BluetoothAdapter&) = delete;
+
+ static void StateChangedCB(int result,
+ bt_adapter_state_e state,
+ void *user_data);
+ static void NameChangedCB(char *name,
+ void *user_data);
+ static void VisibilityChangedCB(int result,
+ bt_adapter_visibility_mode_e mode,
+ void *user_data);
+ static void DiscoveryStateChangedCB(int result,
+ bt_adapter_device_discovery_state_e discovery_state,
+ bt_adapter_device_discovery_info_s *discovery_info,
+ void *user_data);
+
+ void StoreSocketData(bt_socket_received_data_s* data);
+
+ void RemoveSocket(int socket);
+
+ static void OnSocketConnected(int result,
+ bt_socket_connection_state_e state,
+ bt_socket_connection_s* connection,
+ void* user_data);
+
+ static void OnSocketReceivedData(bt_socket_received_data_s* data,
+ void* user_data);
+
+ static void InvokeSocketOnMessageEvent(int id);
+
+ static void InvokeSocketOnCloseEvent(int id);
+
+ bool is_visible_;
+ bool is_powered_;
+ bool is_initialized_;
+ bool user_request_list_ [STOP_DISCOVERY + 1];
+ double user_request_callback_ [STOP_DISCOVERY + 1];
+
+ bool requested_powered_;
+ bt_adapter_visibility_mode_e requested_visibility_;
+ std::string requested_name_;
+
+ picojson::array discovered_devices_;
+ std::set<std::string> discovered_addresses_;
+ std::set<std::string> disappeared_addresses_;
+
+ struct ConnectionRequest {
+ std::string uuid_;
+ double callback_handle_;
+ };
+
+ typedef std::shared_ptr<ConnectionRequest> ConnectionRequestPtr;
+ typedef std::multimap<std::string, ConnectionRequestPtr> ConnectionRequestMap;
+
+ ConnectionRequestMap connection_requests_;
+
+ typedef std::list<int> ConnectedSocketList;
+
+ ConnectedSocketList connected_sockets_;
+
+ typedef std::pair<int, bool> BluetoothServicePair; //registered socket - connection state
+ typedef std::map<std::string, BluetoothServicePair> RegisteredUuidMap;
+
+ RegisteredUuidMap registered_uuids_;
+
+ std::unordered_map<int, std::list<char>> socket_data_;
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_ADAPTER_H_
--- /dev/null
+//@ sourceURL=bluetooth_api.js
+
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var T = xwalk.utils.type;
+var Converter = xwalk.utils.converter;
+var AV = xwalk.utils.validator;
+
+var native = new xwalk.utils.NativeManager(extension);
+
+// class BluetoothClassDeviceMajor /////////////////////////////////////////
+var BluetoothClassDeviceMajor = function() {
+ Object.defineProperties(this, {
+ MISC: {value: 0x00, writable: false, enumerable: true},
+ COMPUTER: {value: 0x01, writable: false, enumerable: true},
+ PHONE: {value: 0x02, writable: false, enumerable: true},
+ NETWORK: {value: 0x03, writable: false, enumerable: true},
+ AUDIO_VIDEO: {value: 0x04, writable: false, enumerable: true},
+ PERIPHERAL: {value: 0x05, writable: false, enumerable: true},
+ IMAGING: {value: 0x06, writable: false, enumerable: true},
+ WEARABLE: {value: 0x07, writable: false, enumerable: true},
+ TOY: {value: 0x08, writable: false, enumerable: true},
+ HEALTH: {value: 0x09, writable: false, enumerable: true},
+ UNCATEGORIZED: {value: 0x1F, writable: false, enumerable: true}
+ });
+};
+
+// class BluetoothClassDeviceMinor /////////////////////////////////////////
+var BluetoothClassDeviceMinor = function() {
+ Object.defineProperties(this, {
+ COMPUTER_UNCATEGORIZED: {value: 0x00, writable: false, enumerable: true},
+ COMPUTER_DESKTOP: {value: 0x01, writable: false, enumerable: true},
+ COMPUTER_SERVER: {value: 0x02, writable: false, enumerable: true},
+ COMPUTER_LAPTOP: {value: 0x03, writable: false, enumerable: true},
+ COMPUTER_HANDHELD_PC_OR_PDA: {value: 0x04, writable: false, enumerable: true},
+ COMPUTER_PALM_PC_OR_PDA: {value: 0x05, writable: false, enumerable: true},
+ COMPUTER_WEARABLE: {value: 0x06, writable: false, enumerable: true},
+
+ PHONE_UNCATEGORIZED: {value: 0x00, writable: false, enumerable: true},
+ PHONE_CELLULAR: {value: 0x01, writable: false, enumerable: true},
+ PHONE_CORDLESS: {value: 0x02, writable: false, enumerable: true},
+ PHONE_SMARTPHONE: {value: 0x03, writable: false, enumerable: true},
+ PHONE_MODEM_OR_GATEWAY: {value: 0x04, writable: false, enumerable: true},
+ PHONE_ISDN: {value: 0x05, writable: false, enumerable: true},
+
+ AV_UNRECOGNIZED: {value: 0x00, writable: false, enumerable: true},
+ AV_WEARABLE_HEADSET: {value: 0x01, writable: false, enumerable: true},
+ AV_HANDSFREE: {value: 0x02, writable: false, enumerable: true},
+ AV_MICROPHONE: {value: 0x04, writable: false, enumerable: true},
+ AV_LOUDSPEAKER: {value: 0x05, writable: false, enumerable: true},
+ AV_HEADPHONES: {value: 0x06, writable: false, enumerable: true},
+ AV_PORTABLE_AUDIO: {value: 0x07, writable: false, enumerable: true},
+ AV_CAR_AUDIO: {value: 0x08, writable: false, enumerable: true},
+ AV_SETTOP_BOX: {value: 0x09, writable: false, enumerable: true},
+ AV_HIFI: {value: 0x0A, writable: false, enumerable: true},
+ AV_VCR: {value: 0x0B, writable: false, enumerable: true},
+ AV_VIDEO_CAMERA: {value: 0x0C, writable: false, enumerable: true},
+ AV_CAMCORDER: {value: 0x0D, writable: false, enumerable: true},
+ AV_MONITOR: {value: 0x0E, writable: false, enumerable: true},
+ AV_DISPLAY_AND_LOUDSPEAKER: {value: 0x0F, writable: false, enumerable: true},
+ AV_VIDEO_CONFERENCING: {value: 0x10, writable: false, enumerable: true},
+ AV_GAMING_TOY: {value: 0x12, writable: false, enumerable: true},
+
+ PERIPHERAL_UNCATEGORIZED: {value: 0x00, writable: false, enumerable: true},
+ PERIPHERAL_KEYBOARD: {value: 0x10, writable: false, enumerable: true},
+ PERIPHERAL_POINTING_DEVICE: {value: 0x20, writable: false, enumerable: true},
+ PERIPHERAL_KEYBOARD_AND_POINTING_DEVICE: {
+ value: 0x30,
+ writable: false,
+ enumerable: true
+ },
+ PERIPHERAL_JOYSTICK: {value: 0x01, writable: false, enumerable: true},
+ PERIPHERAL_GAMEPAD: {value: 0x02, writable: false, enumerable: true},
+ PERIPHERAL_REMOTE_CONTROL: {value: 0x03, writable: false, enumerable: true},
+ PERIPHERAL_SENSING_DEVICE: {value: 0x04, writable: false, enumerable: true},
+ PERIPHERAL_DEGITIZER_TABLET: {value: 0x05, writable: false, enumerable: true},
+ PERIPHERAL_CARD_READER: {value: 0x06, writable: false, enumerable: true},
+ PERIPHERAL_DIGITAL_PEN: {value: 0x07, writable: false, enumerable: true},
+ PERIPHERAL_HANDHELD_SCANNER: {value: 0x08, writable: false, enumerable: true},
+ PERIPHERAL_HANDHELD_INPUT_DEVICE: {value: 0x09, writable: false, enumerable: true},
+
+ IMAGING_UNCATEGORIZED: {value: 0x00, writable: false, enumerable: true},
+ IMAGING_DISPLAY: {value: 0x04, writable: false, enumerable: true},
+ IMAGING_CAMERA: {value: 0x08, writable: false, enumerable: true},
+ IMAGING_SCANNER: {value: 0x10, writable: false, enumerable: true},
+ IMAGING_PRINTER: {value: 0x20, writable: false, enumerable: true},
+
+ WEARABLE_WRITST_WATCH: {value: 0x01, writable: false, enumerable: true},
+ WEARABLE_PAGER: {value: 0x02, writable: false, enumerable: true},
+ WEARABLE_JACKET: {value: 0x03, writable: false, enumerable: true},
+ WEARABLE_HELMET: {value: 0x04, writable: false, enumerable: true},
+ WEARABLE_GLASSES: {value: 0x05, writable: false, enumerable: true},
+
+ TOY_ROBOT: {value: 0x01, writable: false, enumerable: true},
+ TOY_VEHICLE: {value: 0x02, writable: false, enumerable: true},
+ TOY_DOLL: {value: 0x03, writable: false, enumerable: true},
+ TOY_CONTROLLER: {value: 0x04, writable: false, enumerable: true},
+ TOY_GAME: {value: 0x05, writable: false, enumerable: true},
+
+ HEALTH_UNDEFINED: {value: 0x00, writable: false, enumerable: true},
+ HEALTH_BLOOD_PRESSURE_MONITOR: {value: 0x01, writable: false, enumerable: true},
+ HEALTH_THERMOMETER: {value: 0x02, writable: false, enumerable: true},
+ HEALTH_WEIGHING_SCALE: {value: 0x03, writable: false, enumerable: true},
+ HEALTH_GLUCOSE_METER: {value: 0x04, writable: false, enumerable: true},
+ HEALTH_PULSE_OXIMETER: {value: 0x05, writable: false, enumerable: true},
+ HEALTH_PULSE_RATE_MONITOR: {value: 0x06, writable: false, enumerable: true},
+ HEALTH_DATA_DISPLAY: {value: 0x07, writable: false, enumerable: true},
+ HEALTH_STEP_COUNTER: {value: 0x08, writable: false, enumerable: true},
+ HEALTH_BODY_COMPOSITION_ANALYZER: {value: 0x09, writable: false, enumerable: true},
+ HEALTH_PEAK_FLOW_MONITOR: {value: 0x0A, writable: false, enumerable: true},
+ HEALTH_MEDICATION_MONITOR: {value: 0x0B, writable: false, enumerable: true},
+ HEALTH_KNEE_PROSTHESIS: {value: 0x0C, writable: false, enumerable: true},
+ HEALTH_ANKLE_PROSTHESIS: {value: 0x0D, writable: false, enumerable: true}
+ });
+};
+
+// class BluetoothClassDeviceService ///////////////////////////////////////
+var BluetoothClassDeviceService = function() {
+ Object.defineProperties(this, {
+ LIMITED_DISCOVERABILITY: {value: 0x0001, writable: false, enumerable: true},
+ POSITIONING: {value: 0x0008, writable: false, enumerable: true},
+ NETWORKING: {value: 0x0010, writable: false, enumerable: true},
+ RENDERING: {value: 0x0020, writable: false, enumerable: true},
+ CAPTURING: {value: 0x0040, writable: false, enumerable: true},
+ OBJECT_TRANSFER: {value: 0x0080, writable: false, enumerable: true},
+ AUDIO: {value: 0x0100, writable: false, enumerable: true},
+ TELEPHONY: {value: 0x0200, writable: false, enumerable: true},
+ INFORMATION: {value: 0x0400, writable: false, enumerable: true}
+ });
+};
+
+// class BluetoothClass ////////////////////////////////////////////////////
+var BluetoothClass = function(data) {
+ Object.defineProperties(this, {
+ major : {value: data.major, writable: false, enumerable: true},
+ minor : {value: data.minor, writable: false, enumerable: true},
+ services : {value: data.services, writable: false, enumerable: true}
+ });
+};
+
+var _PRIVILEGE_BLUETOOTH_GAP = 'http://tizen.org/privilege/bluetooth.gap';
+
+BluetoothClass.prototype.hasService = function() {
+ console.log('Entered BluetoothClass.hasService()');
+
+ var result = native.callSync('Bluetooth_checkPrivilege', {privilege : _PRIVILEGE_BLUETOOTH_GAP});
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'service',
+ type : AV.Types.UNSIGNED_LONG
+ }
+ ]);
+
+ var size = this.services.length;
+ for (var i = 0; i < size; i++) {
+ if (this.services[i] === args.service) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+// class BluetoothSocket ////////////////////////////////////////////////////
+var _BLUETOOTH_SOCKET_STATE_CLOSED = 'CLOSED';
+
+function BluetoothSocketListeners() {
+ var that = this;
+ this.socketCallback = function (data) {
+ var event = data;
+ var socket = that.sockets[event.id];
+
+ if (socket) {
+ if ('onclose' === event.event) {
+ // no more events
+ that.removeListener(event.id);
+ // change state
+ Object.defineProperty(socket, 'state', {value : _BLUETOOTH_SOCKET_STATE_CLOSED});
+ }
+
+ var callback = socket[event.event];
+ if (T.isFunction(callback)) {
+ callback();
+ }
+ } else {
+ console.log('Received event for an unknown socket: ' + event.id);
+ }
+ };
+}
+
+BluetoothSocketListeners.prototype.sockets = {};
+
+BluetoothSocketListeners.prototype.addListener = function(socket) {
+ if (T.isEmptyObject(this.sockets)) {
+ native.addListener('BLUETOOTH_SOCKET_STATE_CHANGED', this.socketCallback);
+ }
+
+ this.sockets[socket._id] = socket;
+};
+
+BluetoothSocketListeners.prototype.removeListener = function(id) {
+ delete this.sockets[id];
+
+ if (T.isEmptyObject(this.sockets)) {
+ native.removeListener('BLUETOOTH_SOCKET_STATE_CHANGED', this.socketCallback);
+ }
+};
+
+var _bluetoothSocketListeners = new BluetoothSocketListeners();
+
+var BluetoothSocket = function(data) {
+ Object.defineProperties(this, {
+ uuid : {value: data.uuid, writable: false, enumerable: true},
+ state : {value: data.state, writable: false, enumerable: true, configurable: true},
+ peer : {value: new BluetoothDevice(data.peer), writable: false, enumerable: true},
+ onmessage : {value: null, writable: true, enumerable: true},
+ onclose : {value: null, writable: true, enumerable: true},
+ _id : {value: data.id, writable: false, enumerable: false}
+ });
+
+ _bluetoothSocketListeners.addListener(this);
+};
+
+BluetoothSocket.prototype.writeData = function() {
+ console.log('Entered BluetoothSocket.writeData()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'data',
+ type : AV.Types.ARRAY,
+ values : AV.Types.BYTE
+ }
+ ]);
+
+ var callArgs = {
+ id : this._id,
+ data : args.data
+ };
+
+ var result = native.callSync('BluetoothSocket_writeData', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ return native.getResultObject(result);
+ }
+};
+
+BluetoothSocket.prototype.readData = function() {
+ console.log('Entered BluetoothSocket.readData()');
+
+ var callArgs = {
+ id : this._id
+ };
+
+ var result = native.callSync('BluetoothSocket_readData', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ return native.getResultObject(result);
+ }
+};
+
+BluetoothSocket.prototype.close = function() {
+ console.log('Entered BluetoothSocket.close()');
+
+ if (_BLUETOOTH_SOCKET_STATE_CLOSED !== this.state) {
+ var callArgs = {
+ id : this._id
+ };
+
+ var result = native.callSync('BluetoothSocket_close', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+
+ // change state
+ Object.defineProperty(this, 'state', { value : _BLUETOOTH_SOCKET_STATE_CLOSED });
+ }
+};
+
+// class BluetoothDevice ////////////////////////////////////////////////////
+var BluetoothDevice = function(data) {
+ var self = this;
+ function _getter(field) {
+ var callArgs = {};
+
+ callArgs.address = self.address;
+ callArgs.field = field;
+
+ var result = native.callSync('BluetoothDevice_getBoolValue', callArgs);
+
+ if (native.isFailure(result)) {
+ return false;
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ function isBondedGetter() {
+ return _getter('isBonded');
+ }
+
+ function isTrustedGetter() {
+ return _getter('isTrusted');
+ }
+
+ function isConnectedGetter() {
+ return _getter('isConnected');
+ }
+
+ Object.defineProperties(this, {
+ name : {value: data.name, writable: false, enumerable: true},
+ address : {value: data.address, writable: false, enumerable: true},
+ deviceClass : {value: new BluetoothClass(data.deviceClass),
+ writable: false,
+ enumerable: true},
+ isBonded : {
+ enumerable: true,
+ set : function(){},
+ get : isBondedGetter
+ },
+ isTrusted : {
+ enumerable: true,
+ set : function(){},
+ get : isTrustedGetter
+ },
+ isConnected : {
+ enumerable: true,
+ set : function(){},
+ get : isConnectedGetter
+ },
+ uuids : {value: data.uuids, writable: false, enumerable: true}
+ });
+};
+
+BluetoothDevice.prototype.connectToServiceByUUID = function() {
+ console.log('Entered BluetoothDevice.connectToServiceByUUID()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'uuid',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ address : this.address,
+ uuid : args.uuid
+ };
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ args.successCallback(new BluetoothSocket(native.getResultObject(result)));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothDevice_connectToServiceByUUID', callArgs, callback);
+};
+
+// class BluetoothServiceHandler ////////////////////////////////////////////////////
+function BluetoothServiceListeners() {
+ var that = this;
+ this.serviceCallback = function (data) {
+ var e = data;
+ var service = that.services[e.uuid];
+ var result = new BluetoothSocket(e);
+
+ if (service) {
+ console.log(service);
+ service.onconnect(result);
+ }
+ };
+}
+
+BluetoothServiceListeners.prototype.services = {};
+
+BluetoothServiceListeners.prototype.addListener = function(service) {
+ if (T.isEmptyObject(this.services)) {
+ native.addListener('BLUETOOTH_SERVICE_ONCONNECT', this.serviceCallback);
+ }
+
+ this.services[service.uuid] = service;
+};
+
+BluetoothServiceListeners.prototype.removeListener = function(uuid) {
+ delete this.services[uuid];
+
+ if (T.isEmptyObject(this.services)) {
+ native.removeListener('BLUETOOTH_SERVICE_ONCONNECT', this.serviceCallback);
+ }
+};
+
+var _bluetoothServiceListeners = new BluetoothServiceListeners();
+
+var BluetoothServiceHandler = function(data) {
+ function isConnectedGetter() {
+ var callArgs = {
+ uuid : this.uuid
+ };
+
+ var result = native.callSync('BluetoothAdapter_isServiceConnected', { uuid : this.uuid });
+
+ if (native.isFailure(result)) {
+ return false;
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ Object.defineProperties(this, {
+ uuid : {value: data.uuid, writable: false, enumerable: true},
+ name : {value: data.name, writable: false, enumerable: true},
+ isConnected : {
+ enumerable: true,
+ set : function(){},
+ get : isConnectedGetter
+ },
+ onconnect : {value: null, writable: true, enumerable: true}
+ });
+
+ _bluetoothServiceListeners.addListener(this);
+};
+
+BluetoothServiceHandler.prototype.unregister = function() {
+ console.log('Entered BluetoothServiceHandler.unregister()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ uuid : this.uuid
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothServiceHandler_unregister', callArgs, callback);
+
+ _bluetoothServiceListeners.removeListener(this.uuid);
+};
+
+// class BluetoothHealthApplication ////////////////////////////////////////////////////
+function BluetoothHealthApplicationListeners() {
+ var that = this;
+ this.appCallback = function (data) {
+ var event = data;
+ var app = that.apps[event.id];
+
+ if (app) {
+ var callback = app[event.event];
+ if (T.isFunction(callback)) {
+ var param;
+ switch (event.event) {
+ case 'onconnect':
+ param = new BluetoothHealthChannel(native.getResultObject(event));
+ break;
+
+ default:
+ console.log('Unknown event: ' + event.event);
+ break;
+ }
+ callback(param);
+ }
+ } else {
+ console.log('Received event for an unknown application: ' + event.id);
+ }
+ };
+}
+
+BluetoothHealthApplicationListeners.prototype.apps = {};
+
+BluetoothHealthApplicationListeners.prototype.addListener = function(app) {
+ if (T.isEmptyObject(this.apps)) {
+ native.addListener('BLUETOOTH_HEALTH_APPLICATION_CHANGED', this.appCallback);
+ }
+
+ this.apps[app._id] = app;
+};
+
+BluetoothHealthApplicationListeners.prototype.removeListener = function(id) {
+ delete this.apps[id];
+
+ if (T.isEmptyObject(this.apps)) {
+ native.removeListener('BLUETOOTH_HEALTH_APPLICATION_CHANGED', this.appCallback);
+ }
+};
+
+var _bluetoothHealthApplicationListeners = new BluetoothHealthApplicationListeners();
+
+var BluetoothHealthApplication = function(data) {
+ Object.defineProperties(this, {
+ dataType : {value: data.dataType, writable: false, enumerable: true},
+ name : {value: data.name, writable: false, enumerable: true},
+ onconnect : {value: null, writable: true, enumerable: true},
+ _id : {value: data._id, writable: false, enumerable: false}
+ });
+
+ _bluetoothHealthApplicationListeners.addListener(this);
+};
+
+BluetoothHealthApplication.prototype.unregister = function() {
+ console.log('Entered BluetoothHealthApplication.unregister()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {id : this._id};
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothHealthApplication_unregister', callArgs, callback);
+
+ _bluetoothHealthApplicationListeners.removeListener(this._id);
+};
+
+// class BluetoothProfileHandler ////////////////////////////////////////////////////
+var _BluetoothProfileType = {
+ HEALTH : 'HEALTH'
+};
+
+var BluetoothProfileHandler = function(data) {
+ if (data) {
+ Object.defineProperties(this, {
+ profileType : {value: data.profileType, writable: false, enumerable: true}
+ });
+ }
+};
+
+// class BluetoothHealthProfileHandler ////////////////////////////////////////////////////
+var BluetoothHealthProfileHandler = function(data) {
+ BluetoothProfileHandler.call(this, data);
+};
+
+BluetoothHealthProfileHandler.prototype = new BluetoothProfileHandler();
+
+BluetoothHealthProfileHandler.prototype.constructor = BluetoothProfileHandler;
+
+BluetoothHealthProfileHandler.prototype.registerSinkApplication = function() {
+ console.log('Entered BluetoothHealthProfileHandler.registerSinkApplication()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'dataType',
+ type : AV.Types.LONG // there's no short type
+ },
+ {
+ name : 'name',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ dataType : args.dataType,
+ name : args.name
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ args.successCallback(new BluetoothHealthApplication(native.getResultObject(result)));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothHealthProfileHandler_registerSinkApp', callArgs, callback);
+};
+
+BluetoothHealthProfileHandler.prototype.connectToSource = function() {
+ console.log('Entered BluetoothHealthProfileHandler.connectToSource()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'peer',
+ type : AV.Types.PLATFORM_OBJECT,
+ values : BluetoothDevice
+ },
+ {
+ name : 'application',
+ type : AV.Types.PLATFORM_OBJECT,
+ values : BluetoothHealthApplication
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ address : args.peer.address,
+ appId : args.application._id
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ var channel = native.getResultObject(result);
+ channel.peer = args.peer;
+ channel.appId = args.application._id;
+ args.successCallback(new BluetoothHealthChannel(channel));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothHealthProfileHandler_connectToSource', callArgs, callback);
+};
+
+// class BluetoothHealthChannel ////////////////////////////////////////////////////
+var BluetoothHealthChannel = function(data) {
+ Object.defineProperties(this, {
+ peer : {value: data.peer, writable: false, enumerable: true},
+ channelType : {value: data.channelType, writable: false, enumerable: true},
+ application : {
+ value: _bluetoothHealthApplicationListeners.apps[data.appId],
+ writable: false,
+ enumerable: true
+ },
+ isConnected : {
+ value: data.isConnected,
+ writable: false,
+ enumerable: true,
+ configurable: true},
+ _id : {value: data._id, writable: false, enumerable: false}
+ });
+};
+
+BluetoothHealthChannel.prototype.close = function() {
+ console.log('Entered BluetoothHealthChannel.close()');
+
+ if (this.isConnected) {
+ var callArgs = {
+ channel : this._id,
+ address : this.peer.address
+ };
+
+ var result = native.callSync('BluetoothHealthChannel_close', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+
+ Object.defineProperty(this, 'isConnected', { value : false });
+ }
+};
+
+BluetoothHealthChannel.prototype.sendData = function() {
+ console.log('Entered BluetoothHealthChannel.sendData()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'data',
+ type : AV.Types.ARRAY,
+ values : AV.Types.BYTE
+ }
+ ]);
+
+ var callArgs = {
+ channel : this._id,
+ data : args.data
+ };
+
+ var result = native.callSync('BluetoothHealthChannel_sendData', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ return native.getResultObject(result);
+ }
+};
+
+var _healthListeners = {};
+
+function _BluetoothHealthChannelChangeCallback(event) {
+ var e = event;
+ var callback = _healthListeners[e.id];
+ var d;
+
+ switch (e.event) {
+ case 'onmessage':
+ d = e.data;
+ break;
+
+ case 'onclose':
+ break;
+
+ default:
+ console.log('Unknown mode: ' + e.event);
+ return;
+ }
+
+ if (callback[e.event]) {
+ callback[e.event](d);
+ }
+}
+
+var _PRIVILEGE_BLUETOOTH_HEALTH = 'http://tizen.org/privilege/bluetooth.health';
+
+BluetoothHealthChannel.prototype.setListener = function() {
+ console.log('Entered BluetoothHealthChannel.setListener()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'changeCallback',
+ type : AV.Types.LISTENER,
+ values : ['onmessage', 'onclose']
+ }
+ ]);
+
+ var result = native.callSync('Bluetooth_checkPrivilege', {privilege : _PRIVILEGE_BLUETOOTH_HEALTH});
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ if (T.isEmptyObject(_healthListeners)) {
+ native.addListener('BluetoothHealthChannelChangeCallback',
+ _BluetoothHealthChannelChangeCallback);
+ }
+ _healthListeners[this._id] = args.changeCallback;
+ }
+};
+
+BluetoothHealthChannel.prototype.unsetListener = function() {
+ console.log('Entered BluetoothHealthChannel.unsetListener ()');
+
+ var result = native.callSync('Bluetooth_checkPrivilege', {privilege : _PRIVILEGE_BLUETOOTH_HEALTH});
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ delete _healthListeners[this._id];
+
+ if (T.isEmptyObject(_healthListeners)) {
+ native.removeListener('BluetoothHealthChannelChangeCallback',
+ _BluetoothHealthChannelChangeCallback);
+ }
+ }
+};
+
+// class BluetoothAdapter ////////////////////////////////////////////////////
+var BluetoothAdapter = function() {
+ function nameGetter() {
+ var result = native.callSync('BluetoothAdapter_getName', {});
+
+ if (native.isFailure(result)) {
+ return '';
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ function addressGetter() {
+ var result = native.callSync('BluetoothAdapter_getAddress', {});
+
+ if (native.isFailure(result)) {
+ return '';
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ function poweredGetter() {
+ var result = native.callSync('BluetoothAdapter_getPowered', {});
+
+ if (native.isFailure(result)) {
+ return false;
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ function visibleGetter() {
+ var result = native.callSync('BluetoothAdapter_getVisible', {});
+
+ if (native.isFailure(result)) {
+ return false;
+ } else {
+ return native.getResultObject(result);
+ }
+ }
+
+ Object.defineProperties(this, {
+ name : {
+ enumerable: true,
+ set : function(){},
+ get : nameGetter
+ },
+ address : {
+ enumerable: true,
+ set : function(){},
+ get : addressGetter
+ },
+ powered : {
+ enumerable: true,
+ set : function(){},
+ get : poweredGetter
+ },
+ visible : {
+ enumerable: true,
+ set : function(){},
+ get : visibleGetter
+ }
+ });
+};
+
+BluetoothAdapter.prototype.setName = function() {
+ console.log('Entered BluetoothAdapter.setName()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'name',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ name : args.name
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_setName', callArgs, callback);
+};
+
+BluetoothAdapter.prototype.setPowered = function() {
+ console.log('Entered BluetoothAdapter.setPowered()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'powered',
+ type : AV.Types.BOOLEAN
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ powered : args.powered
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_setPowered', callArgs, callback);
+};
+
+BluetoothAdapter.prototype.setVisible = function() {
+ console.log('Entered BluetoothAdapter.setVisible()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'visible',
+ type : AV.Types.BOOLEAN
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'timeout',
+ type : AV.Types.UNSIGNED_LONG,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ visible : args.visible,
+ };
+
+ if (args.visible === true) {
+ if (T.isNullOrUndefined(args.timeout)) {
+ callArgs.timeout = 0;
+ } else {
+ callArgs.timeout = args.timeout > 65535 ? 180 : args.timeout;
+ }
+ }
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_setVisible', callArgs, callback);
+};
+
+var _listener;
+
+function _BluetoothAdapterChangeCallback(event) {
+ console.log('_BluetoothAdapterChangeCallback');
+
+ var e = event;
+ var d;
+
+ switch (e.action) {
+ case 'onstatechanged':
+ d = e.powered;
+ break;
+
+ case 'onnamechanged':
+ d = e.name;
+ break;
+
+ case 'onvisibilitychanged':
+ d = e.visible;
+ break;
+
+ default:
+ console.log('Unknown mode: ' + e.action);
+ return;
+ }
+
+ if (_listener[e.action]) {
+ _listener[e.action](d);
+ }
+}
+
+BluetoothAdapter.prototype.setChangeListener = function() {
+ console.log('Entered BluetoothAdapter.setChangeListener()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'changeCallback',
+ type : AV.Types.LISTENER,
+ values : ['onstatechanged', 'onnamechanged', 'onvisibilitychanged']
+ }
+ ]);
+
+ if (T.isNullOrUndefined(_listener)) {
+ native.addListener('BluetoothAdapterChangeCallback', _BluetoothAdapterChangeCallback);
+ }
+ _listener = args.changeCallback;
+};
+
+BluetoothAdapter.prototype.unsetChangeListener = function() {
+ console.log('Entered BluetoothAdapter.unsetChangeListener()');
+ if (!T.isNullOrUndefined(_listener)) {
+ native.removeListener('BluetoothAdapterChangeCallback', _BluetoothAdapterChangeCallback);
+ _listener = undefined;
+ }
+};
+
+var _discoverDevicesSuccessCallback;
+var _discoverDevicesErrorCallback;
+
+function _BluetoothDiscoverDevicesSuccessCallback(event) {
+ var e = event;
+ var d = null;
+
+ switch (e.action) {
+ case 'onstarted':
+ break;
+
+ case 'ondevicefound':
+ d = new BluetoothDevice(e.data);
+ break;
+
+ case 'ondevicedisappeared':
+ d = e.data;
+ break;
+
+ case 'onfinished':
+ var result = e.data;
+ d = [];
+ result.forEach(function (data) {
+ d.push(new BluetoothDevice(data));
+ });
+
+ //remove listeners after discovering
+ native.removeListener('BluetoothDiscoverDevicesSuccessCallback',
+ _BluetoothDiscoverDevicesSuccessCallback);
+ native.removeListener('BluetoothDiscoverDevicesErrorCallback',
+ _BluetoothDiscoverDevicesErrorCallback);
+ break;
+
+ default:
+ console.log('Unknown mode: ' + e.action);
+ return;
+ }
+
+ if (_discoverDevicesSuccessCallback[e.action]) {
+ _discoverDevicesSuccessCallback[e.action](d);
+ }
+}
+
+function _BluetoothDiscoverDevicesErrorCallback(event) {
+ var e = event;
+ setTimeout(function() {
+ native.callIfPossible(_discoverDevicesErrorCallback, native.getErrorObject(e));
+ }, 0);
+}
+
+BluetoothAdapter.prototype.discoverDevices = function() {
+ console.log('Entered BluetoothAdapter.discoverDevices()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'successCallback',
+ type : AV.Types.LISTENER,
+ values : ['onstarted', 'ondevicefound', 'ondevicedisappeared', 'onfinished']
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ _discoverDevicesSuccessCallback = args.successCallback;
+ _discoverDevicesErrorCallback = args.errorCallback;
+ native.addListener('BluetoothDiscoverDevicesSuccessCallback',
+ _BluetoothDiscoverDevicesSuccessCallback);
+ native.addListener('BluetoothDiscoverDevicesErrorCallback',
+ _BluetoothDiscoverDevicesErrorCallback);
+
+ var result = native.callSync('BluetoothAdapter_discoverDevices', {});
+
+ if (native.isFailure(result)) {
+ native.removeListener('BluetoothDiscoverDevicesSuccessCallback',
+ _BluetoothDiscoverDevicesSuccessCallback);
+ native.removeListener('BluetoothDiscoverDevicesErrorCallback',
+ _BluetoothDiscoverDevicesErrorCallback);
+ throw native.getErrorObject(result);
+ }
+};
+
+BluetoothAdapter.prototype.stopDiscovery = function() {
+ console.log('Entered BluetoothAdapter.stopDiscovery()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_stopDiscovery', {}, callback);
+};
+
+BluetoothAdapter.prototype.getKnownDevices = function() {
+ console.log('Entered BluetoothAdapter.getKnownDevices()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ var r = native.getResultObject(result).devices;
+ var devices = [];
+ r.forEach(function (data) {
+ devices.push(new BluetoothDevice(data));
+ });
+ args.successCallback(devices);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_getKnownDevices', {}, callback);
+};
+
+BluetoothAdapter.prototype.getDevice = function() {
+ console.log('Entered BluetoothAdapter.getDevice()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'address',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ args.successCallback(new BluetoothDevice(native.getResultObject(result)));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_getDevice', {address : args.address}, callback);
+};
+
+BluetoothAdapter.prototype.createBonding = function() {
+ console.log('Entered BluetoothAdapter.createBonding()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'address',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : false,
+ nullable : false
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ address : args.address
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ args.successCallback(new BluetoothDevice(native.getResultObject(result)));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_createBonding', callArgs, callback);
+};
+
+BluetoothAdapter.prototype.destroyBonding = function() {
+ console.log('Entered BluetoothAdapter.destroyBonding()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'address',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ address : args.address
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ native.callIfPossible(args.successCallback);
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_destroyBonding', callArgs, callback);
+};
+
+BluetoothAdapter.prototype.registerRFCOMMServiceByUUID = function() {
+ console.log('Entered BluetoothAdapter.registerRFCOMMServiceByUUID()');
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'uuid',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'name',
+ type : AV.Types.STRING
+ },
+ {
+ name : 'successCallback',
+ type : AV.Types.FUNCTION,
+ },
+ {
+ name : 'errorCallback',
+ type : AV.Types.FUNCTION,
+ optional : true,
+ nullable : true
+ }
+ ]);
+
+ var callArgs = {
+ uuid : args.uuid,
+ name : args.name
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ // if registration was finished with success create BluetoothServiceHandler
+ // with parameters passed to this function (uuid and name).
+ args.successCallback(new BluetoothServiceHandler(callArgs));
+ }
+ };
+
+ // native.call does not inform if call results in failure
+ // TODO: what to do in this case?
+ native.call('BluetoothAdapter_registerRFCOMMServiceByUUID', callArgs, callback);
+};
+
+BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
+ console.log('Entered BluetoothAdapter.getBluetoothProfileHandler()');
+
+ var args = AV.validateMethod(arguments, [
+ {
+ name : 'profileType',
+ type : AV.Types.ENUM,
+ values : T.getValues(_BluetoothProfileType)
+ }
+ ]);
+
+ var callArgs = {profileType : args.profileType};
+
+ var result = native.callSync('BluetoothAdapter_getBluetoothProfileHandler', callArgs);
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ switch (args.profileType) {
+ case _BluetoothProfileType.HEALTH:
+ return new BluetoothHealthProfileHandler(callArgs);
+
+ default:
+ throw new tizen.WebAPIException('NotSupportedError', 'Profile ' + args.profileType + ' is not supported.');
+ }
+ }
+};
+
+// class BluetoothManager ////////////////////////////////////////////////////
+var BluetoothManager = function() {
+ Object.defineProperties(this, {
+ deviceMajor : {
+ value: new BluetoothClassDeviceMajor(),
+ writable: false,
+ enumerable: true
+ },
+ deviceMinor : {
+ value: new BluetoothClassDeviceMinor(),
+ writable: false,
+ enumerable: true
+ },
+ deviceService : {
+ value: new BluetoothClassDeviceService(),
+ writable: false,
+ enumerable: true
+ }
+ });
+};
+
+BluetoothManager.prototype.getDefaultAdapter = function() {
+ console.log('Entered BluetoothManager.getDefaultAdapter()');
+
+ var result = native.callSync('Bluetooth_checkPrivilege', {privilege : _PRIVILEGE_BLUETOOTH_GAP});
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ } else {
+ return new BluetoothAdapter();
+ }
+};
+
+// exports ///////////////////////////////////////////////////////////////////
+exports = new BluetoothManager();
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_class.h"
+
+#include <map>
+
+namespace extension {
+namespace bluetooth {
+
+std::map<bt_major_device_class_e, unsigned long> g_major_enum_map = {
+ {BT_MAJOR_DEVICE_CLASS_MISC, 0x00},
+ {BT_MAJOR_DEVICE_CLASS_COMPUTER, 0x01},
+ {BT_MAJOR_DEVICE_CLASS_PHONE, 0x02},
+ {BT_MAJOR_DEVICE_CLASS_LAN_NETWORK_ACCESS_POINT, 0x03},
+ {BT_MAJOR_DEVICE_CLASS_AUDIO_VIDEO, 0x04},
+ {BT_MAJOR_DEVICE_CLASS_PERIPHERAL, 0x05},
+ {BT_MAJOR_DEVICE_CLASS_IMAGING, 0x06},
+ {BT_MAJOR_DEVICE_CLASS_WEARABLE, 0x07},
+ {BT_MAJOR_DEVICE_CLASS_TOY, 0x08},
+ {BT_MAJOR_DEVICE_CLASS_HEALTH, 0x09},
+ {BT_MAJOR_DEVICE_CLASS_UNCATEGORIZED, 0x1F}
+};
+
+std::map<bt_minor_device_class_e, unsigned long> g_minor_enum_map = {
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_UNCATEGORIZED, 0x00},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_DESKTOP_WORKSTATION , 0x01},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_SERVER_CLASS , 0x02},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_LAPTOP , 0x03},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_HANDHELD_PC_OR_PDA , 0x04},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_PALM_SIZED_PC_OR_PDA, 0x5},
+ {BT_MINOR_DEVICE_CLASS_COMPUTER_WEARABLE_COMPUTER , 0x06},
+ {BT_MINOR_DEVICE_CLASS_PHONE_UNCATEGORIZED , 0x00},
+ {BT_MINOR_DEVICE_CLASS_PHONE_CELLULAR , 0x01},
+ {BT_MINOR_DEVICE_CLASS_PHONE_CORDLESS , 0x02},
+ {BT_MINOR_DEVICE_CLASS_PHONE_SMART_PHONE , 0x03},
+ {BT_MINOR_DEVICE_CLASS_PHONE_WIRED_MODEM_OR_VOICE_GATEWAY , 0x04},
+ {BT_MINOR_DEVICE_CLASS_PHONE_COMMON_ISDN_ACCESS , 0x05},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_UNCATEGORIZED , 0x00},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_WEARABLE_HEADSET , 0x01},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_HANDS_FREE , 0x02},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_MICROPHONE , 0x04},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_LOUDSPEAKER , 0x05},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_HEADPHONES , 0x06},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_PORTABLE_AUDIO , 0x07},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_CAR_AUDIO , 0x08},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_SET_TOP_BOX , 0x09},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_HIFI_AUDIO_DEVICE , 0x0a},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_VCR , 0x0b},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_VIDEO_CAMERA , 0x0c},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_CAMCORDER , 0x0d},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_VIDEO_MONITOR , 0x0e},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_VIDEO_DISPLAY_LOUDSPEAKER , 0x0f},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_VIDEO_CONFERENCING , 0x10},
+ {BT_MINOR_DEVICE_CLASS_AUDIO_VIDEO_GAMING_TOY , 0x12},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERA_UNCATEGORIZED , 0},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_KEY_BOARD , 0x10},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_POINTING_DEVICE , 0x20},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_COMBO_KEYBOARD_POINTING_DEVICE , 0x30},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_JOYSTICK , 0x01},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_GAME_PAD , 0x02},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_REMOTE_CONTROL , 0x03},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_SENSING_DEVICE , 0x04},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_DIGITIZER_TABLET , 0x05},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_CARD_READER , 0x06},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_DIGITAL_PEN , 0x07},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_HANDHELD_SCANNER , 0x08},
+ {BT_MINOR_DEVICE_CLASS_PERIPHERAL_HANDHELD_GESTURAL_INPUT_DEVICE , 0x09},
+ {BT_MINOR_DEVICE_CLASS_IMAGING_DISPLAY , 0x04},
+ {BT_MINOR_DEVICE_CLASS_IMAGING_CAMERA , 0x08},
+ {BT_MINOR_DEVICE_CLASS_IMAGING_SCANNER , 0x10},
+ {BT_MINOR_DEVICE_CLASS_IMAGING_PRINTER, 0x20},
+ {BT_MINOR_DEVICE_CLASS_WEARABLE_WRIST_WATCH , 0x01},
+ {BT_MINOR_DEVICE_CLASS_WEARABLE_PAGER , 0x02},
+ {BT_MINOR_DEVICE_CLASS_WEARABLE_JACKET , 0x03},
+ {BT_MINOR_DEVICE_CLASS_WEARABLE_HELMET , 0x04},
+ {BT_MINOR_DEVICE_CLASS_WEARABLE_GLASSES , 0x05},
+ {BT_MINOR_DEVICE_CLASS_TOY_ROBOT , 0x01},
+ {BT_MINOR_DEVICE_CLASS_TOY_VEHICLE , 0x02},
+ {BT_MINOR_DEVICE_CLASS_TOY_DOLL_ACTION , 0x03},
+ {BT_MINOR_DEVICE_CLASS_TOY_CONTROLLER , 0x04},
+ {BT_MINOR_DEVICE_CLASS_TOY_GAME , 0x05},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_UNCATEGORIZED , 0x00},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_BLOOD_PRESSURE_MONITOR , 0x01},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_THERMOMETER , 0x02},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_WEIGHING_SCALE , 0x03},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_GLUCOSE_METER , 0x04},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_PULSE_OXIMETER , 0x05},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_HEART_PULSE_RATE_MONITOR , 0x06},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_DATA_DISPLAY , 0x07},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_STEP_COUNTER , 0x08},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_BODY_COMPOSITION_ANALYZER , 0x09},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_PEAK_FLOW_MONITOR , 0x0a},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_MEDICATION_MONITOR , 0x0b},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_KNEE_PROSTHESIS , 0x0c},
+ {BT_MINOR_DEVICE_CLASS_HEALTH_ANKLE_PROSTHESIS , 0x0d}
+};
+
+std::map<bt_major_service_class_e, unsigned long> g_service_enum_map = {
+ {BT_MAJOR_SERVICE_CLASS_LIMITED_DISCOVERABLE_MODE, 0x0001},
+ {BT_MAJOR_SERVICE_CLASS_POSITIONING, 0x0008},
+ {BT_MAJOR_SERVICE_CLASS_NETWORKING, 0x0010},
+ {BT_MAJOR_SERVICE_CLASS_RENDERING, 0x0020},
+ {BT_MAJOR_SERVICE_CLASS_CAPTURING, 0x0040},
+ {BT_MAJOR_SERVICE_CLASS_OBJECT_TRANSFER, 0x0080},
+ {BT_MAJOR_SERVICE_CLASS_AUDIO, 0x0100},
+ {BT_MAJOR_SERVICE_CLASS_TELEPHONY, 0x0200},
+ {BT_MAJOR_SERVICE_CLASS_INFORMATION, 0x0400}
+};
+
+unsigned long BluetoothClass::GetMajorValue(bt_major_device_class_e major)
+{
+ auto iter = g_major_enum_map.find(major);
+ if (iter != g_major_enum_map.end()) {
+ return iter->second;
+ }
+
+ return 0;
+}
+
+unsigned long BluetoothClass::GetMinorValue(bt_minor_device_class_e minor)
+{
+ auto iter = g_minor_enum_map.find(minor);
+ if (iter != g_minor_enum_map.end()) {
+ return iter->second;
+ }
+
+ return 0;
+}
+
+std::vector<unsigned long> BluetoothClass::getServiceValues(int serviceMask)
+{
+ std::vector<unsigned long> ret;
+ for (auto iter = g_service_enum_map.begin(); iter != g_service_enum_map.end(); iter++) {
+ if (iter->first & serviceMask) {
+ ret.push_back(iter->second);
+ }
+ }
+
+ return ret;
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_CLASS_H_
+#define BLUETOOTH_BLUETOOTH_CLASS_H_
+
+#include <vector>
+
+#include <bluetooth.h>
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothClass {
+public:
+ static unsigned long GetMajorValue(bt_major_device_class_e major);
+ static unsigned long GetMinorValue(bt_minor_device_class_e minor);
+ static std::vector<unsigned long> getServiceValues(int serviceMask);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_CLASS_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_device.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+
+#include "bluetooth_adapter.h"
+#include "bluetooth_class.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+namespace {
+//device
+const std::string kDeviceName = "name";
+const std::string kDeviceAddress = "address";
+const std::string kDeviceClass = "deviceClass";
+const std::string kDeviceClassMajor = "major";
+const std::string kDeviceClassMinor = "minor";
+const std::string kDeviceClassService = "services";
+const std::string kDeviceUuids = "uuids";
+const std::string kDeviceIsBonded = "isBonded";
+const std::string kDeviceIsTrusted = "isTrusted";
+const std::string kDeviceIsConnected = "isConnected";
+}
+
+static void ToJsonFromBTClass(bt_class_s bluetooth_class, picojson::object* device) {
+ LoggerD("Entered");
+
+ picojson::object& bt = device->insert(std::make_pair(kDeviceClass, picojson::value(picojson::object())))
+ .first->second.get<picojson::object>();
+
+ bt.insert(std::make_pair(kDeviceClassMajor, picojson::value(static_cast<double>(
+ BluetoothClass::GetMajorValue(bluetooth_class.major_device_class)))));
+ bt.insert(std::make_pair(kDeviceClassMinor, picojson::value(static_cast<double>(
+ BluetoothClass::GetMinorValue(bluetooth_class.minor_device_class)))));
+
+ picojson::array& array = bt.insert(std::make_pair(kDeviceClassService,
+ picojson::value(picojson::array()))).first->second.get<picojson::array>();
+
+ std::vector<unsigned long> services_vector = BluetoothClass::getServiceValues(
+ bluetooth_class.major_service_class_mask);
+
+ for (auto v : services_vector) {
+ array.push_back(picojson::value(static_cast<double>(v)));
+ }
+}
+
+static void ToJsonFromUUID(char **service_uuid, int service_count, picojson::object* device) {
+ LoggerD("Entered");
+
+ picojson::array& array = device->insert(std::make_pair(kDeviceUuids, picojson::value(picojson::array())))
+ .first->second.get<picojson::array>();
+
+ for (int i = 0; i < service_count; i++) {
+ array.push_back(picojson::value(service_uuid[i]));
+ }
+}
+
+void BluetoothDevice::ToJson(bt_device_info_s* info, picojson::object* device) {
+ LoggerD("Entered");
+ device->insert(std::make_pair(kDeviceName, picojson::value(std::string(info->remote_name))));
+ device->insert(std::make_pair(kDeviceAddress, picojson::value(std::string(info->remote_address))));
+
+ ToJsonFromBTClass(info->bt_class, device);
+ ToJsonFromUUID(info->service_uuid, info->service_count, device);
+}
+
+void BluetoothDevice::ToJson(bt_adapter_device_discovery_info_s *info, picojson::object* device) {
+ LoggerD("Entered");
+
+ device->insert(std::make_pair(kDeviceName, picojson::value(info->remote_name)));
+ device->insert(std::make_pair(kDeviceAddress, picojson::value(info->remote_address)));
+
+ ToJsonFromBTClass(info->bt_class, device);
+ ToJsonFromUUID(info->service_uuid, info->service_count, device);
+}
+
+void BluetoothDevice::ConnectToServiceByUUID(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto& args = util::GetArguments(data);
+
+ BluetoothAdapter::GetInstance().ConnectToServiceByUUID(
+ FromJson<std::string>(args, "address"),
+ FromJson<std::string>(args, "uuid"),
+ util::GetAsyncCallbackHandle(data));
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothDevice::GetBoolValue(const picojson::value& data, picojson::object& out)
+{
+ LoggerD("Entered");
+
+ const auto& args = util::GetArguments(data);
+ const auto& address = FromJson<std::string>(args, "address");
+ const auto& field = FromJson<std::string>(args, "field");
+
+ bool value = false;
+ bt_device_info_s *info = nullptr;
+ if (bt_adapter_get_bonded_device_info(address.c_str(), &info) == BT_ERROR_NONE &&
+ info != nullptr) {
+ if (kDeviceIsBonded == field) {
+ value = info->is_bonded;
+ } else if (kDeviceIsTrusted == field) {
+ value = info->is_authorized;
+ } else if (kDeviceIsConnected == field) {
+ value = info->is_connected;
+ } else {
+ bt_adapter_free_device_info(info);
+ throw UnknownException("Wrong field passed.");
+ }
+ bt_adapter_free_device_info(info);
+ } else {
+ throw UnknownException("Unknown error");
+ }
+
+ util::ReportSuccess(picojson::value(value), out);
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_DEVICE_H_
+#define BLUETOOTH_BLUETOOTH_DEVICE_H_
+
+#include <bluetooth.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothDevice {
+public:
+ /**
+ * Signature: @code void connectToServiceByUUID(uuid, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothDevice_connectToServiceByUUID', args: {uuid: uuid}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {socket}}
+ * @endcode
+ */
+ void ConnectToServiceByUUID(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code BluetoothDevice.is(Bonded, Trusted, Connected); @endcode
+ * JSON: @code data: {method: 'BluetoothDevice_GetBoolValue', args: {address: address,
+ * field: field}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: name}
+ * @endcode
+ */
+ void GetBoolValue(const picojson::value& data, picojson::object& out);
+
+ static void ToJson(bt_device_info_s* info,
+ picojson::object* device);
+ static void ToJson(bt_adapter_device_discovery_info_s *info,
+ picojson::object* device);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_DEVICE_H_
--- /dev/null
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bluetooth_extension.h"
+#include "bluetooth_instance.h"
+
+namespace {
+ const char* kBluetooth = "tizen.bluetooth";
+}
+// This will be generated from bluetooth_api.js.
+extern const char kSource_bluetooth_api[];
+
+common::Extension* CreateExtension() {
+ return new BluetoothExtension;
+}
+
+BluetoothExtension::BluetoothExtension() {
+ SetExtensionName(kBluetooth);
+ SetJavaScriptAPI(kSource_bluetooth_api);
+ const char* entry_points[] = {
+ NULL
+ };
+ SetExtraJSEntryPoints(entry_points);
+}
+
+BluetoothExtension::~BluetoothExtension() {}
+
+common::Instance* BluetoothExtension::CreateInstance() {
+ return &extension::bluetooth::BluetoothInstance::GetInstance();
+}
--- /dev/null
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLUETOOTH_BLUETOOTH_EXTENSION_H_
+#define BLUETOOTH_BLUETOOTH_EXTENSION_H_
+
+#include "common/extension.h"
+
+class BluetoothExtension : public common::Extension {
+ public:
+ BluetoothExtension();
+ virtual ~BluetoothExtension();
+
+ private:
+ virtual common::Instance* CreateInstance();
+};
+
+#endif // BLUETOOTH_BLUETOOTH_EXTENSION_H_
+
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_health_application.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+
+#include "bluetooth_health_profile_handler.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+namespace {
+const std::string kDataType = "dataType";
+const std::string kName = "name";
+const std::string kId = "_id";
+} // namespace
+
+using namespace common;
+
+void BluetoothHealthApplication::Unregister(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothHealth);
+
+ const auto& args = util::GetArguments(data);
+
+ BluetoothHealthProfileHandler::GetInstance().UnregisterSinkAppAsync(
+ FromJson<std::string>(args, "id"),
+ util::GetAsyncCallbackHandle(data));
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothHealthApplication::ToJson(short data_type,
+ const std::string& name,
+ const char* id,
+ picojson::object* out) {
+ out->insert(std::make_pair(kDataType, picojson::value(static_cast<double>(data_type))));
+ out->insert(std::make_pair(kName, picojson::value(name)));
+ out->insert(std::make_pair(kId, picojson::value(id)));
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_HEALTH_APPLICATION_H_
+#define BLUETOOTH_BLUETOOTH_HEALTH_APPLICATION_H_
+
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothHealthApplication {
+public:
+ /**
+ * Signature: @code void unregister(successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothHealthApplication_unregister', args: {}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void Unregister(const picojson::value& data, picojson::object& out);
+
+ static void ToJson(short data_type,
+ const std::string& name,
+ const char* id,
+ picojson::object* out);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_HEALTH_APPLICATION_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_health_channel.h"
+
+#include <memory>
+
+#include "common/converter.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+
+#include "bluetooth_device.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+namespace {
+const std::string kPeer = "peer";
+const std::string kChannelType = "channelType";
+const std::string kApplication = "appId";
+const std::string kIsConnected = "isConnected";
+const std::string kId = "_id";
+} // namespace
+
+void BluetoothHealthChannel::Close(const picojson::value& data , picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothHealth);
+
+ const auto& args = util::GetArguments(data);
+
+ unsigned int channel = common::stol(FromJson<std::string>(args, "channel"));
+ const auto& address = FromJson<std::string>(args, "address");
+
+ if (BT_ERROR_NONE != bt_hdp_disconnect(address.c_str(), channel)) {
+ throw UnknownException("Unknown error");
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothHealthChannel::SendData(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothHealth);
+
+ const auto& args = util::GetArguments(data);
+
+ unsigned int channel = common::stol(FromJson<std::string>(args, "channel"));
+ const auto& binary_data = FromJson<picojson::array>(args, "data");
+ const auto data_size = binary_data.size();
+
+ std::unique_ptr<char[]> data_ptr{new char[data_size]};
+
+ for (std::size_t i = 0; i < data_size; ++i) {
+ data_ptr[i] = static_cast<char>(binary_data[i].get<double>());
+ }
+
+ if (BT_ERROR_NONE != bt_hdp_send_data(channel, data_ptr.get(), data_size)) {
+ LoggerE("bt_hdp_send_data() failed");
+ throw UnknownException("Unknown error");
+ }
+
+ util::ReportSuccess(picojson::value(static_cast<double>(data_size)), out);
+}
+
+void BluetoothHealthChannel::ToJson(unsigned int channel,
+ bt_hdp_channel_type_e type,
+ picojson::object* out) {
+ const char* type_str = "UNKNOWN";
+
+ switch (type) {
+ case BT_HDP_CHANNEL_TYPE_RELIABLE:
+ type_str = "RELIABLE";
+ break;
+
+ case BT_HDP_CHANNEL_TYPE_STREAMING:
+ type_str = "STREAMING";
+ break;
+
+ default:
+ LoggerE("Unknown HDP channel type: %d", type);
+ break;
+ }
+
+ out->insert(std::make_pair(kId, picojson::value(std::to_string(channel))));
+ out->insert(std::make_pair(kChannelType, picojson::value(type_str)));
+ out->insert(std::make_pair(kIsConnected, picojson::value(true)));
+}
+
+void BluetoothHealthChannel::ToJson(unsigned int channel,
+ bt_hdp_channel_type_e type,
+ bt_device_info_s* device_info,
+ const char* app_id,
+ picojson::object* out) {
+ ToJson(channel, type, out);
+ auto& device = out->insert(std::make_pair(kPeer, picojson::value(picojson::object())))
+ .first->second.get<picojson::object>();
+ BluetoothDevice::ToJson(device_info, &device);
+ out->insert(std::make_pair(kApplication, picojson::value(app_id)));
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_HEALTH_CHANNEL_H_
+#define BLUETOOTH_BLUETOOTH_HEALTH_CHANNEL_H_
+
+#include <bluetooth.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothHealthChannel {
+public:
+ /**
+ * Signature: @code void close(); @endcode
+ * JSON: @code data: {method: 'BluetoothHealthChannel_close', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void Close(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code unsigned long sendData(data[]); @endcode
+ * JSON: @code data: {method: 'BluetoothHealthChannel_sendData', args: {data: data}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {bytes_sent}}
+ */
+ void SendData(const picojson::value& data, picojson::object& out);
+
+ static void ToJson(unsigned int channel,
+ bt_hdp_channel_type_e type,
+ picojson::object* out);
+
+ static void ToJson(unsigned int channel,
+ bt_hdp_channel_type_e type,
+ bt_device_info_s* device_info,
+ const char* app_id,
+ picojson::object* out);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_HEALTH_CHANNEL_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_health_profile_handler.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "common/task-queue.h"
+
+#include "bluetooth_adapter.h"
+#include "bluetooth_health_application.h"
+#include "bluetooth_health_channel.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+namespace {
+const std::string kId = "id";
+const std::string kEvent = "event";
+const std::string kData = "data";
+const std::string kOnConnect = "onconnect";
+const std::string kOnClose = "onclose";
+const std::string kOnMessage = "onmessage";
+const std::string kChangeCallback = "BluetoothHealthChannelChangeCallback";
+} //namespace
+
+BluetoothHealthProfileHandler& BluetoothHealthProfileHandler::GetInstance() {
+ static BluetoothHealthProfileHandler instance;
+ return instance;
+}
+
+BluetoothHealthProfileHandler::BluetoothHealthProfileHandler() {
+ // initialize listeners
+ if (BT_ERROR_NONE != bt_hdp_set_connection_state_changed_cb(OnConnected,
+ OnDisconnected,
+ this)) {
+ LoggerE("bt_hdp_set_connection_state_changed_cb() failed");
+ }
+
+ if (BT_ERROR_NONE != bt_hdp_set_data_received_cb(OnDataReceived, this)) {
+ LoggerE("bt_hdp_set_data_received_cb() failed");
+ }
+}
+
+BluetoothHealthProfileHandler::~BluetoothHealthProfileHandler() {
+ bt_hdp_unset_connection_state_changed_cb();
+ bt_hdp_unset_data_received_cb();
+
+ for (auto& it : registered_health_apps_) {
+ bt_hdp_unregister_sink_app(it.c_str());
+ }
+}
+
+void BluetoothHealthProfileHandler::OnConnected(int result,
+ const char* remote_address,
+ const char* app_id,
+ bt_hdp_channel_type_e type,
+ unsigned int channel,
+ void* user_data) {
+ LoggerD("Entered");
+
+ BluetoothHealthProfileHandler* object = static_cast<BluetoothHealthProfileHandler*>(user_data);
+
+ if (!object) {
+ LoggerW("user_data is NULL");
+ return;
+ }
+
+ if (BT_ERROR_NONE != result) {
+ LoggerD("Not BT_ERROR_NONE: %d", result);
+ }
+
+ LoggerD("Connected app: %s", app_id);
+ LoggerD("Connected channel: %u", channel);
+
+ const auto iter = object->registered_health_apps_.find(app_id);
+
+ if (iter == object->registered_health_apps_.end()) {
+ LoggerW("This app is not registered: %s", app_id);
+ return;
+ }
+
+ bool channel_added = false;
+
+ if (BT_ERROR_NONE == result) {
+ // send BluetoothHealthApplication.onconnect notification
+ bt_device_info_s* device_info = nullptr;
+
+ if (BT_ERROR_NONE == bt_adapter_get_bonded_device_info(remote_address, &device_info) &&
+ nullptr != device_info) {
+ LoggerD("invoke BluetoothHealthApplication.onconnect");
+
+ object->connected_channels_.insert(channel);
+ channel_added = true;
+
+ picojson::value response{picojson::object()};
+ picojson::object& response_obj = response.get<picojson::object>();
+ response_obj.insert(std::make_pair(kId, picojson::value(app_id)));
+ response_obj.insert(std::make_pair(kEvent, picojson::value(kOnConnect)));
+
+ picojson::value result = picojson::value(picojson::object());
+
+ BluetoothHealthChannel::ToJson(channel,
+ type,
+ device_info,
+ app_id,
+ &result.get<picojson::object>());
+
+ util::ReportSuccess(result, response_obj);
+ bt_adapter_free_device_info(device_info);
+
+ util::FireEvent("BLUETOOTH_HEALTH_APPLICATION_CHANGED", response);
+ } else {
+ LoggerE("Failed to get device info");
+ }
+ }
+
+ // Handle requests from BluetoothHealthProfileHandler.connectToSource()
+ const auto request = object->connection_requests_.find(app_id);
+
+ if (request != object->connection_requests_.end()) {
+ LoggerD("Requested connection");
+
+ std::shared_ptr<picojson::value> response{new picojson::value(picojson::object())};
+
+ if (BT_ERROR_NONE == result) {
+ if (!channel_added) {
+ object->connected_channels_.insert(channel);
+ }
+
+ picojson::value result = picojson::value(picojson::object());
+
+ BluetoothHealthChannel::ToJson(channel,
+ type,
+ &result.get<picojson::object>());
+
+ util::ReportSuccess(result, response->get<picojson::object>());
+ } else {
+ LoggerE("Failed to establish a connection with health profile");
+ util::ReportError(UnknownException("Failed to establish a connection with health profile"),
+ response->get<picojson::object>());
+ }
+
+ util::AsyncResponse(request->second, response);
+
+ // request was handled, remove
+ object->connection_requests_.erase(request);
+ }
+ else {
+ LoggerD("This connection was not requested.");
+ }
+}
+
+void BluetoothHealthProfileHandler::OnDisconnected(int result,
+ const char* /* remote_address */,
+ unsigned int channel,
+ void* user_data) {
+ LoggerD("Entered");
+
+ BluetoothHealthProfileHandler* object = static_cast<BluetoothHealthProfileHandler*>(user_data);
+
+ if (!object) {
+ LoggerW("user_data is NULL");
+ return;
+ }
+
+ auto it = object->connected_channels_.find(channel);
+ if (BT_ERROR_NONE == result && object->connected_channels_.end() != it) {
+ object->connected_channels_.erase(it);
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ data_obj->insert(std::make_pair(kEvent, picojson::value(kOnClose)));
+ data_obj->insert(std::make_pair(kId, picojson::value(std::to_string(channel))));
+ util::FireEvent(kChangeCallback, value);
+ }
+}
+
+void BluetoothHealthProfileHandler::OnDataReceived(unsigned int channel,
+ const char* data,
+ unsigned int size,
+ void* user_data) {
+ LoggerD("Entered");
+
+ BluetoothHealthProfileHandler* object = static_cast<BluetoothHealthProfileHandler*>(user_data);
+
+ if (!object) {
+ LoggerW("user_data is NULL");
+ return;
+ }
+
+ auto it = object->connected_channels_.find(channel);
+ if (object->connected_channels_.end() != it) {
+ picojson::value value = picojson::value(picojson::object());
+ picojson::object* data_obj = &value.get<picojson::object>();
+
+ data_obj->insert(std::make_pair(kEvent, picojson::value(kOnMessage)));
+ data_obj->insert(std::make_pair(kId, picojson::value(std::to_string(channel))));
+
+ picojson::array& array = data_obj->insert(std::make_pair(kData, picojson::value(
+ picojson::array()))).first->second.get<picojson::array>();
+
+ for (unsigned int i = 0; i < size; i++) {
+ array.push_back(picojson::value(static_cast<double>(data[i])));
+ }
+
+ util::FireEvent(kChangeCallback, value);
+ }
+}
+
+void BluetoothHealthProfileHandler::RegisterSinkApp(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothHealth);
+
+ const auto& args = util::GetArguments(data);
+ const auto data_type = static_cast<short>(FromJson<double>(args, "dataType"));
+ const auto& name = FromJson<std::string>(args, "name");
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+
+ auto register_app = [data_type, name, this](const std::shared_ptr<picojson::value>& response) -> void {
+ LoggerD("Entered");
+
+ try {
+ char* app_id = nullptr;
+ const int ret = bt_hdp_register_sink_app(data_type, &app_id);
+
+ switch (ret) {
+ case BT_ERROR_NONE:
+ {
+ LoggerD("Registered app: %s", app_id);
+
+ this->registered_health_apps_.insert(app_id);
+
+ picojson::value result = picojson::value(picojson::object());
+ BluetoothHealthApplication::ToJson(data_type,
+ name,
+ app_id,
+ &result.get<picojson::object>());
+ util::ReportSuccess(result, response->get<picojson::object>());
+ }
+ break;
+
+ case BT_ERROR_NOT_ENABLED:
+ LoggerE("Bluetooth device is turned off");
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ break;
+
+ default:
+ LoggerE("bt_hdp_register_sink_app() failed: %d", ret);
+ throw UnknownException("Unknown error");
+ break;
+ }
+ } catch (const PlatformException& e) {
+ util::ReportError(e, response->get<picojson::object>());
+ }
+ };
+
+ auto register_app_response = [callback_handle](const std::shared_ptr<picojson::value>& response) -> void {
+ util::SyncResponse(callback_handle, response);
+ };
+
+ TaskQueue::GetInstance().Queue<picojson::value>(register_app,
+ register_app_response,
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothHealthProfileHandler::ConnectToSource(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothHealth);
+
+ const auto& args = util::GetArguments(data);
+ const auto& address = FromJson<std::string>(args, "address");
+ const auto& app_id = FromJson<std::string>(args, "appId");
+
+ LoggerD("address: %s", address.c_str());
+ LoggerD("app ID: %s", app_id.c_str());
+
+ const auto callback_handle = util::GetAsyncCallbackHandle(data);
+
+ try {
+ const int ret = bt_hdp_connect_to_source(address.c_str(), app_id.c_str());
+
+ switch (ret) {
+ case BT_ERROR_NONE: {
+ LoggerD("bt_hdp_connect_to_source() succeeded");
+
+ connection_requests_.insert(std::make_pair(app_id, callback_handle));
+ break;
+ }
+
+ case BT_ERROR_NOT_ENABLED:
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ break;
+
+ case BT_ERROR_INVALID_PARAMETER:
+ case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
+ throw InvalidValuesException("Invalid value");
+ break;
+
+ default:
+ throw UnknownException("Unknown error");
+ break;
+ }
+ } catch (const PlatformException& e) {
+ LoggerD("Exception: %s", e.message().c_str());
+ std::shared_ptr<picojson::value> response{new picojson::value(picojson::object())};
+ util::ReportError(e, response->get<picojson::object>());
+ util::AsyncResponse(callback_handle, response);
+ }
+
+ util::ReportSuccess(out);
+}
+
+void BluetoothHealthProfileHandler::UnregisterSinkAppAsync(const std::string& app_id,
+ int callback_handle) {
+ LoggerD("Entered");
+
+ auto unregister_app = [app_id, this](const std::shared_ptr<picojson::value>& response) -> void {
+ LoggerD("Entered");
+
+ auto iter = this->registered_health_apps_.find(app_id);
+
+ if (iter != this->registered_health_apps_.end()) {
+ LoggerD("Found registered Health Application: %s", app_id.c_str());
+
+ try {
+ const int ret = bt_hdp_unregister_sink_app(app_id.c_str());
+
+ switch(ret) {
+ case BT_ERROR_NONE:
+ this->registered_health_apps_.erase(iter);
+ break;
+
+ case BT_ERROR_NOT_ENABLED:
+ LoggerE("Bluetooth device is turned off");
+ throw ServiceNotAvailableException("Bluetooth device is turned off");
+ break;
+
+ default:
+ LoggerE("bt_hdp_unregister_sink_app() failed: %d", ret);
+ throw UnknownException("Unknown error");
+ break;
+ }
+ } catch (const PlatformException& e) {
+ util::ReportError(e, response->get<picojson::object>());
+ return;
+ }
+ } else {
+ LoggerD("Already unregistered");
+ }
+
+ util::ReportSuccess(response->get<picojson::object>());
+ };
+
+ auto unregister_app_response = [callback_handle](const std::shared_ptr<picojson::value>& response) -> void {
+ util::SyncResponse(callback_handle, response);
+ };
+
+ TaskQueue::GetInstance().Queue<picojson::value>(unregister_app,
+ unregister_app_response,
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_HEALTH_PROFILE_HANDLER_H_
+#define BLUETOOTH_BLUETOOTH_HEALTH_PROFILE_HANDLER_H_
+
+#include <set>
+
+#include <bluetooth.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothHealthProfileHandler {
+public:
+ /**
+ * Signature: @code void registerSinkApp(dataType, name, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothHealthProfileHandler_registerSinkApp',
+ * args: {dataType: dataType, name: name}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {application}}
+ * @endcode
+ */
+ void RegisterSinkApp(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void connectToSource(peer, application, successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothHealthProfileHandler_connectToSource',
+ * args: {peer: peer, application: application}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {channel}}
+ * @endcode
+ */
+ void ConnectToSource(const picojson::value& data, picojson::object& out);
+
+ static BluetoothHealthProfileHandler& GetInstance();
+
+ ~BluetoothHealthProfileHandler();
+
+ void UnregisterSinkAppAsync(const std::string& app_id, int callback_handle);
+
+private:
+ BluetoothHealthProfileHandler();
+ BluetoothHealthProfileHandler(const BluetoothHealthProfileHandler&) = delete;
+ BluetoothHealthProfileHandler& operator=(const BluetoothHealthProfileHandler&) = delete;
+
+ static void OnConnected(int result,
+ const char* remote_address,
+ const char* app_id,
+ bt_hdp_channel_type_e type,
+ unsigned int channel,
+ void* user_data);
+
+ static void OnDisconnected(int result,
+ const char* remote_address,
+ unsigned int channel,
+ void* user_data);
+
+ static void OnDataReceived(unsigned int channel,
+ const char* data,
+ unsigned int size,
+ void* user_data);
+
+ std::set<std::string> registered_health_apps_;
+ std::map<std::string, double> connection_requests_;
+ std::set<unsigned int> connected_channels_;
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_HEALTH_PROFILE_HANDLER_H_
--- /dev/null
+
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bluetooth_instance.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+
+#include "bluetooth_adapter.h"
+#include "bluetooth_device.h"
+#include "bluetooth_health_application.h"
+#include "bluetooth_health_channel.h"
+#include "bluetooth_health_profile_handler.h"
+#include "bluetooth_service_handler.h"
+#include "bluetooth_socket.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+namespace {
+
+BluetoothAdapter* bluetooth_adapter = &BluetoothAdapter::GetInstance();
+BluetoothDevice bluetooth_device;
+BluetoothHealthApplication bluetooth_health_application;
+BluetoothHealthChannel bluetooth_health_channel;
+BluetoothHealthProfileHandler* bluetooth_health_profile_handler = &BluetoothHealthProfileHandler::GetInstance();
+BluetoothServiceHandler bluetooth_service_handler;
+BluetoothSocket bluetooth_socket;
+
+void CheckPrivilege(const picojson::value& data, picojson::object& out)
+{
+ const auto& args = util::GetArguments(data);
+ const auto& privilege = FromJson<std::string>(args, "privilege");
+ util::CheckAccess(privilege);
+
+ util::ReportSuccess(out);
+}
+
+} // namespace
+
+BluetoothInstance& BluetoothInstance::GetInstance()
+{
+ static BluetoothInstance instance;
+ return instance;
+}
+
+BluetoothInstance::BluetoothInstance()
+{
+ LoggerD("Entered");
+ using namespace std::placeholders;
+
+ // BluetoothAdapter
+ RegisterHandler("BluetoothAdapter_setName",
+ std::bind(&BluetoothAdapter::SetName, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_setPowered",
+ std::bind(&BluetoothAdapter::SetPowered, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_setVisible",
+ std::bind(&BluetoothAdapter::SetVisible, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_discoverDevices",
+ std::bind(&BluetoothAdapter::DiscoverDevices, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_stopDiscovery",
+ std::bind(&BluetoothAdapter::StopDiscovery, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_getKnownDevices",
+ std::bind(&BluetoothAdapter::GetKnownDevices, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_getDevice",
+ std::bind(&BluetoothAdapter::GetDevice, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_createBonding",
+ std::bind(&BluetoothAdapter::CreateBonding, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_destroyBonding",
+ std::bind(&BluetoothAdapter::DestroyBonding, bluetooth_adapter, _1, _2));
+ RegisterHandler("BluetoothAdapter_registerRFCOMMServiceByUUID",
+ std::bind(&BluetoothAdapter::RegisterRFCOMMServiceByUUID, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_getBluetoothProfileHandler",
+ std::bind(&BluetoothAdapter::GetBluetoothProfileHandler, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_getName",
+ std::bind(&BluetoothAdapter::GetName, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_getAddress",
+ std::bind(&BluetoothAdapter::GetAddress, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_getPowered",
+ std::bind(&BluetoothAdapter::GetPowered, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_getVisible",
+ std::bind(&BluetoothAdapter::GetVisible, bluetooth_adapter, _1, _2));
+ RegisterSyncHandler("BluetoothAdapter_isServiceConnected",
+ std::bind(&BluetoothAdapter::IsServiceConnected, bluetooth_adapter, _1, _2));
+
+ // BluetoothDevice
+ RegisterHandler("BluetoothDevice_connectToServiceByUUID",
+ std::bind(&BluetoothDevice::ConnectToServiceByUUID, &bluetooth_device, _1, _2));
+ RegisterSyncHandler("BluetoothDevice_getBoolValue",
+ std::bind(&BluetoothDevice::GetBoolValue, &bluetooth_device, _1, _2));
+
+ // BluetoothHealthApplication
+ RegisterHandler("BluetoothHealthApplication_unregister",
+ std::bind(&BluetoothHealthApplication::Unregister, &bluetooth_health_application, _1, _2));
+
+ // BluetoothHealthChannel
+ RegisterSyncHandler("BluetoothHealthChannel_close",
+ std::bind(&BluetoothHealthChannel::Close, &bluetooth_health_channel, _1, _2));
+ RegisterSyncHandler("BluetoothHealthChannel_sendData",
+ std::bind(&BluetoothHealthChannel::SendData, &bluetooth_health_channel, _1, _2));
+
+ // BluetoothHealthProfileHandler
+ RegisterHandler("BluetoothHealthProfileHandler_registerSinkApp",
+ std::bind(&BluetoothHealthProfileHandler::RegisterSinkApp, bluetooth_health_profile_handler, _1, _2));
+ RegisterHandler("BluetoothHealthProfileHandler_connectToSource",
+ std::bind(&BluetoothHealthProfileHandler::ConnectToSource, bluetooth_health_profile_handler, _1, _2));
+
+ // BluetoothServiceHandler
+ RegisterHandler("BluetoothServiceHandler_unregister",
+ std::bind(&BluetoothServiceHandler::Unregister, &bluetooth_service_handler, _1, _2));
+
+ // BluetoothSocket
+ RegisterSyncHandler("BluetoothSocket_writeData",
+ std::bind(&BluetoothSocket::WriteData, &bluetooth_socket, _1, _2));
+ RegisterSyncHandler("BluetoothSocket_readData",
+ std::bind(&BluetoothSocket::ReadData, &bluetooth_socket, _1, _2));
+ RegisterSyncHandler("BluetoothSocket_close",
+ std::bind(&BluetoothSocket::Close, &bluetooth_socket, _1, _2));
+
+ // other
+ RegisterSyncHandler("Bluetooth_checkPrivilege", CheckPrivilege);
+}
+
+BluetoothInstance::~BluetoothInstance()
+{
+ LoggerD("Entered");
+}
+
+} // namespace bluetooth
+} // namespace extension
+
--- /dev/null
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLUETOOTH_BLUETOOTH_INSTANCE_H_
+#define BLUETOOTH_BLUETOOTH_INSTANCE_H_
+
+#include "common/extension.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothInstance: public common::ParsedInstance {
+public:
+ static BluetoothInstance& GetInstance();
+private:
+ BluetoothInstance();
+ virtual ~BluetoothInstance();
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_INSTANCE_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_PRIVILEGE_H_
+#define BLUETOOTH_BLUETOOTH_PRIVILEGE_H_
+
+#include <string>
+
+namespace extension {
+namespace bluetooth {
+
+namespace Privilege {
+const std::string kBluetoothAdmin = "http://tizen.org/privilege/bluetooth.admin";
+const std::string kBluetoothManager = "http://tizen.org/privilege/bluetoothmanager";
+const std::string kBluetoothGap = "http://tizen.org/privilege/bluetooth.gap";
+const std::string kBluetoothSpp = "http://tizen.org/privilege/bluetooth.spp";
+const std::string kBluetoothHealth = "http://tizen.org/privilege/bluetooth.health";
+} // namespace Privilege
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_PRIVILEGE_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_service_handler.h"
+
+#include "common/converter.h"
+#include "common/logger.h"
+
+#include "bluetooth_adapter.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+using namespace common;
+
+void BluetoothServiceHandler::Unregister(const picojson::value& data, picojson::object& out) {
+ LoggerD("Entered");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto& args = util::GetArguments(data);
+
+ BluetoothAdapter::GetInstance().UnregisterUUID(
+ FromJson<std::string>(args, "uuid"),
+ util::GetAsyncCallbackHandle(data));
+
+ util::ReportSuccess(out);
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_SERVICE_HANDLER_H_
+#define BLUETOOTH_BLUETOOTH_SERVICE_HANDLER_H_
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothServiceHandler {
+public:
+ /**
+ * Signature: @code void unregister(successCallback, errorCallback); @endcode
+ * JSON: @code data: {method: 'BluetoothServiceHandler_unregister', args: {}} @endcode
+ * Invocation: @code native.call(request, result_callback); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ * Result callback:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void Unregister(const picojson::value& data, picojson::object& out);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_SERVICE_HANDLER_H_
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bluetooth_socket.h"
+
+#include <memory>
+
+#include "common/converter.h"
+#include "common/logger.h"
+
+#include "bluetooth_adapter.h"
+#include "bluetooth_device.h"
+#include "bluetooth_privilege.h"
+#include "bluetooth_util.h"
+
+namespace extension {
+namespace bluetooth {
+
+namespace {
+const std::string kBluetoothSocketId = "id";
+const std::string kBluetoothSocketUuid = "uuid";
+const std::string kBluetoothSocketState = "state";
+const std::string kBluetoothSocketPeer = "peer";
+const std::string kBluetoothSocketStateOpen = "OPEN";
+// error
+const int kBluetoothError = -1;
+}
+
+using namespace common;
+
+void BluetoothSocket::WriteData(const picojson::value& data, picojson::object& out) {
+ LoggerD("Enter");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto& args = util::GetArguments(data);
+
+ int socket = common::stol(FromJson<std::string>(args, "id"));
+ const auto& binary_data = FromJson<picojson::array>(args, "data");
+ const auto data_size = binary_data.size();
+
+ std::unique_ptr<char[]> data_ptr{new char[data_size]};
+
+ for (std::size_t i = 0; i < data_size; ++i) {
+ data_ptr[i] = static_cast<char>(binary_data[i].get<double>());
+ }
+
+ if (kBluetoothError == bt_socket_send_data(socket, data_ptr.get(), data_size)) {
+ LoggerE("bt_socket_send_data() failed");
+ throw UnknownException("Unknown error");
+ }
+
+ util::ReportSuccess(picojson::value(static_cast<double>(data_size)), out);
+}
+
+void BluetoothSocket::ReadData(const picojson::value& data, picojson::object& out) {
+ LoggerD("Enter");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto& args = util::GetArguments(data);
+
+ int socket = common::stol(FromJson<std::string>(args, "id"));
+
+ auto binary_data = BluetoothAdapter::GetInstance().ReadSocketData(socket);
+ picojson::value ret = picojson::value(picojson::array());
+ picojson::array& array = ret.get<picojson::array>();
+
+ for (auto val : binary_data) {
+ array.push_back(picojson::value(static_cast<double>(val)));
+ }
+
+ BluetoothAdapter::GetInstance().ClearSocketData(socket);
+
+ util::ReportSuccess(ret, out);
+}
+
+void BluetoothSocket::Close(const picojson::value& data, picojson::object& out) {
+ LoggerD("Enter");
+
+ util::CheckAccess(Privilege::kBluetoothSpp);
+
+ const auto& args = util::GetArguments(data);
+
+ int socket = common::stol(FromJson<std::string>(args, "id"));
+
+ if (BT_ERROR_NONE != bt_socket_disconnect_rfcomm(socket)) {
+ LoggerE("bt_socket_disconnect_rfcomm() failed");
+ throw UnknownException("Unknown error");
+ }
+
+ util::ReportSuccess(out);
+}
+
+picojson::value BluetoothSocket::ToJson(bt_socket_connection_s* connection) {
+ LoggerD("Enter");
+
+ picojson::value ret = picojson::value(picojson::object());
+ auto& ret_obj = ret.get<picojson::object>();
+
+ ret_obj.insert(std::make_pair(kBluetoothSocketId,
+ picojson::value(std::to_string(connection->socket_fd))));
+ ret_obj.insert(std::make_pair(kBluetoothSocketUuid,
+ picojson::value(connection->service_uuid)));
+ ret_obj.insert(std::make_pair(kBluetoothSocketState,
+ picojson::value(kBluetoothSocketStateOpen)));
+
+ bt_device_info_s* device_info = nullptr;
+
+ if (BT_ERROR_NONE == bt_adapter_get_bonded_device_info(connection->remote_address, &device_info) &&
+ nullptr != device_info) {
+ picojson::value& device = ret_obj.insert(std::make_pair(kBluetoothSocketPeer,
+ picojson::value(picojson::object()))).first->second;
+ BluetoothDevice::ToJson(device_info, &device.get<picojson::object>());
+ bt_adapter_free_device_info(device_info);
+ } else {
+ LoggerE("Peer not found");
+ }
+
+ return ret;
+}
+
+} // namespace bluetooth
+} // namespace extension
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BLUETOOTH_BLUETOOTH_SOCKET_H__
+#define BLUETOOTH_BLUETOOTH_SOCKET_H__
+
+#include <bluetooth.h>
+
+#include "common/picojson.h"
+
+namespace extension {
+namespace bluetooth {
+
+class BluetoothSocket {
+public:
+ /**
+ * Signature: @code unsigned long writeData(data[]); @endcode
+ * JSON: @code data: {method: 'BluetoothSocket_writeData', args: {data: data}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {bytes_sent}}
+ * @endcode
+ */
+ void WriteData(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code byte[] readData(); @endcode
+ * JSON: @code data: {method: 'BluetoothSocket_readData', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success', result: {bytes_read}}
+ * @endcode
+ */
+ void ReadData(const picojson::value& data, picojson::object& out);
+
+ /**
+ * Signature: @code void close(); @endcode
+ * JSON: @code data: {method: 'BluetoothSocket_close', args: {}} @endcode
+ * Invocation: @code native.callSync(request); @endcode
+ * Return:
+ * @code
+ * {status: 'error', error: {name, message}}
+ * {status: 'success'}
+ * @endcode
+ */
+ void Close(const picojson::value& data, picojson::object& out);
+
+ static picojson::value ToJson(bt_socket_connection_s* connection);
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_SOCKET_H__
--- /dev/null
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "bluetooth_util.h"
+
+#include "common/logger.h"
+#include "common/task-queue.h"
+
+#include "bluetooth_instance.h"
+
+namespace extension {
+namespace bluetooth {
+namespace util {
+
+namespace {
+const char* JSON_CALLBACK_ID = "callbackId";
+const char* JSON_LISTENER_ID = "listenerId";
+const char* JSON_STATUS = "status";
+const char* JSON_RESULT = "result";
+const char* JSON_CALLBACK_SUCCCESS = "success";
+const char* JSON_CALLBACK_ERROR = "error";
+const char* JSON_DATA = "args";
+} // namespace
+
+
+void CheckAccess(const std::string& privilege) {
+ // TODO: check access to privilege, throw exception on failure
+}
+
+void AsyncResponse(double callback_handle, const std::shared_ptr<picojson::value>& response) {
+ common::TaskQueue::GetInstance().Async<picojson::value>([callback_handle](const std::shared_ptr<picojson::value>& response) {
+ SyncResponse(callback_handle, response);
+ }, response);
+}
+
+void SyncResponse(double callback_handle, const std::shared_ptr<picojson::value>& response) {
+ auto& obj = response->get<picojson::object>();
+ obj[JSON_CALLBACK_ID] = picojson::value(callback_handle);
+ BluetoothInstance::GetInstance().PostMessage(response->serialize().c_str());
+}
+
+void FireEvent(const std::string& event, picojson::value& value) {
+ auto& obj = value.get<picojson::object>();
+ obj[JSON_LISTENER_ID] = picojson::value(event);
+ BluetoothInstance::GetInstance().PostMessage(value.serialize().c_str());
+}
+
+void FireEvent(const std::string& event, const picojson::value& value) {
+ picojson::value v{value};
+ FireEvent(event, v);
+}
+
+void FireEvent(const std::string& event, const std::shared_ptr<picojson::value>& value) {
+ FireEvent(event, *value.get());
+}
+
+void ReportSuccess(picojson::object& out) {
+ out.insert(std::make_pair(JSON_STATUS, picojson::value(JSON_CALLBACK_SUCCCESS)));
+}
+
+void ReportSuccess(const picojson::value& result, picojson::object& out) {
+ ReportSuccess(out);
+ out.insert(std::make_pair(JSON_RESULT, result));
+}
+
+void ReportError(picojson::object& out) {
+ out.insert(std::make_pair(JSON_STATUS, picojson::value(JSON_CALLBACK_ERROR)));
+}
+
+void ReportError(const common::PlatformException& ex, picojson::object& out) {
+ ReportError(out);
+ out.insert(std::make_pair(JSON_CALLBACK_ERROR, ex.ToJSON()));
+}
+
+double GetAsyncCallbackHandle(const picojson::value& data) {
+ return data.get(JSON_CALLBACK_ID).get<double>();
+}
+
+const picojson::object& GetArguments(const picojson::value& data) {
+ return data.get<picojson::object>();
+}
+
+} // util
+} // bluetooth
+} // extension
--- /dev/null
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLUETOOTH_BLUETOOTH_UTIL_H_
+#define BLUETOOTH_BLUETOOTH_UTIL_H_
+
+#include <memory>
+#include <string>
+
+#include "common/picojson.h"
+#include "common/platform_exception.h"
+
+namespace extension {
+namespace bluetooth {
+namespace util {
+
+void CheckAccess(const std::string& privilege);
+
+void AsyncResponse(double callback_handle, const std::shared_ptr<picojson::value>& response);
+void SyncResponse(double callback_handle, const std::shared_ptr<picojson::value>& response);
+
+void FireEvent(const std::string& event, picojson::value& value);
+void FireEvent(const std::string& event, const picojson::value& value);
+void FireEvent(const std::string& event, const std::shared_ptr<picojson::value>& value);
+
+void ReportSuccess(picojson::object& out);
+void ReportSuccess(const picojson::value& result, picojson::object& out);
+
+void ReportError(picojson::object& out);
+void ReportError(const common::PlatformException& ex, picojson::object& out);
+
+double GetAsyncCallbackHandle(const picojson::value& data);
+
+const picojson::object& GetArguments(const picojson::value& data);
+
+} // util
+} // bluetooth
+} // extension
+
+#endif // BLUETOOTH_BLUETOOTH_UTIL_H_
'extension_host_os == "mobile"', {
'dependencies': [
'badge/badge.gyp:*',
+ 'bluetooth/bluetooth.gyp:*',
'callhistory/callhistory.gyp:*',
'contact/contact.gyp:*',
'calendar/calendar.gyp:*',