[Bluetooth] Ported old bluetooth code.
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Mon, 2 Feb 2015 17:21:33 +0000 (18:21 +0100)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Wed, 4 Feb 2015 08:19:52 +0000 (17:19 +0900)
Change-Id: I63a940295b3d80dffcadac60ef70e0cead3ffbdc
Signed-off-by: Pawel Andruszkiewicz <p.andruszkie@samsung.com>
26 files changed:
src/bluetooth/bluetooth.gyp [new file with mode: 0644]
src/bluetooth/bluetooth_adapter.cc [new file with mode: 0644]
src/bluetooth/bluetooth_adapter.h [new file with mode: 0644]
src/bluetooth/bluetooth_api.js [new file with mode: 0644]
src/bluetooth/bluetooth_class.cc [new file with mode: 0644]
src/bluetooth/bluetooth_class.h [new file with mode: 0644]
src/bluetooth/bluetooth_device.cc [new file with mode: 0644]
src/bluetooth/bluetooth_device.h [new file with mode: 0644]
src/bluetooth/bluetooth_extension.cc [new file with mode: 0644]
src/bluetooth/bluetooth_extension.h [new file with mode: 0644]
src/bluetooth/bluetooth_health_application.cc [new file with mode: 0644]
src/bluetooth/bluetooth_health_application.h [new file with mode: 0644]
src/bluetooth/bluetooth_health_channel.cc [new file with mode: 0644]
src/bluetooth/bluetooth_health_channel.h [new file with mode: 0644]
src/bluetooth/bluetooth_health_profile_handler.cc [new file with mode: 0644]
src/bluetooth/bluetooth_health_profile_handler.h [new file with mode: 0644]
src/bluetooth/bluetooth_instance.cc [new file with mode: 0644]
src/bluetooth/bluetooth_instance.h [new file with mode: 0644]
src/bluetooth/bluetooth_privilege.h [new file with mode: 0644]
src/bluetooth/bluetooth_service_handler.cc [new file with mode: 0644]
src/bluetooth/bluetooth_service_handler.h [new file with mode: 0644]
src/bluetooth/bluetooth_socket.cc [new file with mode: 0644]
src/bluetooth/bluetooth_socket.h [new file with mode: 0644]
src/bluetooth/bluetooth_util.cc [new file with mode: 0644]
src/bluetooth/bluetooth_util.h [new file with mode: 0644]
src/tizen-wrt.gyp

diff --git a/src/bluetooth/bluetooth.gyp b/src/bluetooth/bluetooth.gyp
new file mode 100644 (file)
index 0000000..4b6dea9
--- /dev/null
@@ -0,0 +1,51 @@
+{
+  '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',
+            ]
+          },
+        }],
+      ],
+    },
+  ],
+}
diff --git a/src/bluetooth/bluetooth_adapter.cc b/src/bluetooth/bluetooth_adapter.cc
new file mode 100644 (file)
index 0000000..9a90197
--- /dev/null
@@ -0,0 +1,1538 @@
+/*
+ * 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(&current , &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
diff --git a/src/bluetooth/bluetooth_adapter.h b/src/bluetooth/bluetooth_adapter.h
new file mode 100644 (file)
index 0000000..827668f
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_api.js b/src/bluetooth/bluetooth_api.js
new file mode 100644 (file)
index 0000000..5812834
--- /dev/null
@@ -0,0 +1,1425 @@
+//@ 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();
diff --git a/src/bluetooth/bluetooth_class.cc b/src/bluetooth/bluetooth_class.cc
new file mode 100644 (file)
index 0000000..3addc6a
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_class.h b/src/bluetooth/bluetooth_class.h
new file mode 100644 (file)
index 0000000..0445835
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_device.cc b/src/bluetooth/bluetooth_device.cc
new file mode 100644 (file)
index 0000000..6f05aa5
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_device.h b/src/bluetooth/bluetooth_device.h
new file mode 100644 (file)
index 0000000..30ae7ca
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_extension.cc b/src/bluetooth/bluetooth_extension.cc
new file mode 100644 (file)
index 0000000..62bf595
--- /dev/null
@@ -0,0 +1,31 @@
+// 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();
+}
diff --git a/src/bluetooth/bluetooth_extension.h b/src/bluetooth/bluetooth_extension.h
new file mode 100644 (file)
index 0000000..9f262d5
--- /dev/null
@@ -0,0 +1,20 @@
+// 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_
+
diff --git a/src/bluetooth/bluetooth_health_application.cc b/src/bluetooth/bluetooth_health_application.cc
new file mode 100644 (file)
index 0000000..811d346
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_health_application.h b/src/bluetooth/bluetooth_health_application.h
new file mode 100644 (file)
index 0000000..d0d28e0
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_health_channel.cc b/src/bluetooth/bluetooth_health_channel.cc
new file mode 100644 (file)
index 0000000..0923a0f
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_health_channel.h b/src/bluetooth/bluetooth_health_channel.h
new file mode 100644 (file)
index 0000000..482a71f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_health_profile_handler.cc b/src/bluetooth/bluetooth_health_profile_handler.cc
new file mode 100644 (file)
index 0000000..d19cec2
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_health_profile_handler.h b/src/bluetooth/bluetooth_health_profile_handler.h
new file mode 100644 (file)
index 0000000..672e111
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_instance.cc b/src/bluetooth/bluetooth_instance.cc
new file mode 100644 (file)
index 0000000..439c06d
--- /dev/null
@@ -0,0 +1,136 @@
+
+// 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
+
diff --git a/src/bluetooth/bluetooth_instance.h b/src/bluetooth/bluetooth_instance.h
new file mode 100644 (file)
index 0000000..22aded5
--- /dev/null
@@ -0,0 +1,24 @@
+// 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_
diff --git a/src/bluetooth/bluetooth_privilege.h b/src/bluetooth/bluetooth_privilege.h
new file mode 100644 (file)
index 0000000..9c81b1c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_service_handler.cc b/src/bluetooth/bluetooth_service_handler.cc
new file mode 100644 (file)
index 0000000..02deb1e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_service_handler.h b/src/bluetooth/bluetooth_service_handler.h
new file mode 100644 (file)
index 0000000..80da12f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_
diff --git a/src/bluetooth/bluetooth_socket.cc b/src/bluetooth/bluetooth_socket.cc
new file mode 100644 (file)
index 0000000..7925145
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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
diff --git a/src/bluetooth/bluetooth_socket.h b/src/bluetooth/bluetooth_socket.h
new file mode 100644 (file)
index 0000000..e8b0396
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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__
diff --git a/src/bluetooth/bluetooth_util.cc b/src/bluetooth/bluetooth_util.cc
new file mode 100644 (file)
index 0000000..670e993
--- /dev/null
@@ -0,0 +1,86 @@
+// 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
diff --git a/src/bluetooth/bluetooth_util.h b/src/bluetooth/bluetooth_util.h
new file mode 100644 (file)
index 0000000..97cbc74
--- /dev/null
@@ -0,0 +1,41 @@
+// 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_
index c7aa07526954f9592d99702b18c50fc67932a316..221e8296d797482dbf4c95a71245229edbaa9b93 100644 (file)
@@ -24,6 +24,7 @@
           'extension_host_os == "mobile"', {
             'dependencies': [
               'badge/badge.gyp:*',
+              'bluetooth/bluetooth.gyp:*',
               'callhistory/callhistory.gyp:*',
               'contact/contact.gyp:*',
               'calendar/calendar.gyp:*',