2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
21 #include <JSWebAPIErrorFactory.h>
22 #include <system_info.h>
25 #include "BluetoothAdapter.h"
26 #include "BluetoothCallbackUtil.h"
27 #include "JSBluetoothDevice.h"
28 #include "JSBluetoothServiceHandler.h"
29 #include "JSBluetoothSocket.h"
30 #include "GlobalContextManager.h"
35 #define BLUEZ_PREFIX "org.bluez"
36 #define BLUEZ_SERVICE BLUEZ_PREFIX
37 #define BLUEZ_MANAGER_IFACE BLUEZ_PREFIX ".Manager"
38 #define BLUEZ_ADAPTER_IFACE BLUEZ_PREFIX ".Adapter"
39 #define BLUEZ_DEVICE_IFACE BLUEZ_PREFIX ".Device"
40 #define BLUEZ_AGENT_IFACE BLUEZ_PREFIX ".Agent"
42 #define AGENT_PATH "/org/bluez/agent_pairing"
43 #define AGENT_CAPABILITIES "KeyboardDisplay"
45 #define AGENT_INTERFACE_XML \
47 " <interface name='" BLUEZ_AGENT_IFACE "'>" \
48 " <method name='Release'>" \
50 " <method name='Authorize'>" \
51 " <arg type='o' name='device' direction='in'/>" \
52 " <arg type='s' name='uuid' direction='in'/>" \
54 " <method name='RequestPinCode'>" \
55 " <arg type='o' name='device' direction='in'/>" \
56 " <arg type='s' name='pincode' direction='out'/>" \
58 " <method name='RequestPasskey'>" \
59 " <arg type='o' name='device' direction='in'/>" \
60 " <arg type='u' name='passkey' direction='out'/>" \
62 " <method name='DisplayPasskey'>" \
63 " <arg type='o' name='device' direction='in'/>" \
64 " <arg type='u' name='passkey' direction='in'/>" \
66 " <method name='DisplayPinCode'>" \
67 " <arg type='o' name='device' direction='in'/>" \
68 " <arg type='s' name='pincode' direction='in'/>" \
70 " <method name='RequestConfirmation'>" \
71 " <arg type='o' name='device' direction='in'/>" \
72 " <arg type='u' name='passkey' direction='in'/>" \
74 " <method name='ConfirmModeChange'>" \
75 " <arg type='s' name='mode' direction='in'/>" \
77 " <method name='Cancel'>" \
82 #define PINCODE "123456"
83 #define PASSKEY 123456
85 #define CONNMAN_PREFIX "net.connman"
86 #define CONNMAN_SERVICE CONNMAN_PREFIX
87 #define CONNMAN_MANAGER_IFACE CONNMAN_PREFIX ".Manager"
88 #define CONNMAN_TECHNOLOGY_IFACE CONNMAN_PREFIX ".Technology"
91 using namespace DeviceAPI::Common;
96 bool BluetoothAdapter::foreachBondedDevicesCB(bt_device_info_s *deviceInfo, void *userData)
98 BluetoothAdapterPtr adapter = static_cast<BluetoothAdapterPtr>(userData);
100 LoggerW("userData is NULL");
104 if(deviceInfo == NULL) {
105 LoggerW("deviceInfo is NULL");
109 std::vector<BluetoothDeviceSharedPtr>::iterator iter;
110 for(iter = adapter->knownDevices.begin(); iter != adapter->knownDevices.end(); ++iter) {
111 BluetoothDeviceSharedPtr foundDevice = *iter;
113 if(!strcmp(foundDevice->getAddress().c_str(), deviceInfo->remote_address)) {
114 foundDevice->updateInfo(deviceInfo);
119 if(iter == adapter->knownDevices.end()) {
120 BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo));
121 adapter->knownDevices.push_back(device);
127 void BluetoothAdapter::onSocketConnected(int result, bt_socket_connection_state_e state, bt_socket_connection_s *connection, void *userData)
129 BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
131 LoggerW("userData is NULL");
136 LoggerW("connection is NULL");
140 if(connection->local_role == BT_SOCKET_SERVER) {
141 RegisteredUUIDMapT::iterator iter = object->mRegisteredUUID.find(connection->service_uuid);
142 if(iter == object->mRegisteredUUID.end()) {
143 LoggerW("Connection state is changed unexpectedly");
147 if(state == BT_SOCKET_CONNECTED) { // connected when Server
148 if(result == BT_ERROR_NONE) {
149 // Update BluetoothServiceHandler
150 BluetoothServiceHandlerPtr service = iter->second;
151 service->setConnectionState(true);
153 // Call BluetoothServiceHandler.onconnect
154 BluetoothSocketPtr socket = new BluetoothSocket(connection);
155 MultiCallbackUserDataPtr callback = service->getOnConnect();
156 JSContextRef context = callback->getContext();
157 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
159 callback->invokeCallback("onconnect", socketObj);
161 // Update mConnectedSocket
162 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
163 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
166 LoggerW("Establishing a connection failed");
170 else { // disconnected when Server
171 if(result == BT_ERROR_NONE) {
172 // Update BluetoothServiceHandler
173 BluetoothServiceHandlerPtr service = iter->second;
174 service->setConnectionState(false);
176 // call BluetoothSocket.onclose;
177 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
178 if(i == object->mConnectedSocket.end()) {
179 LoggerW("Unknown connected socket");
182 //BluetoothSocketSharedPtr socket = i->second;
183 BluetoothSocketPtr socket = i->second;
184 socket->setConnectionState(false);
185 MultiCallbackUserDataPtr callback = socket->getOnClose();
187 callback->invokeCallback("onclose");
189 // Update mConnectedSocket
190 object->mConnectedSocket.erase(i);
193 LoggerW("Disconnecting a connection failed");
197 else if(connection->local_role == BT_SOCKET_CLIENT) {
199 if(state == BT_SOCKET_CONNECTED) { // connected when Client
200 std::string remoteAddress(connection->remote_address);
201 ConnReqMultiMapT::iterator iter;
203 iter = object->mConnReqMap.find(remoteAddress);
204 if(iter != object->mConnReqMap.end() && !strcmp(iter->second->mUUID.c_str(), connection->service_uuid)) {
207 } while(iter != object->mConnReqMap.end());
209 if(iter == object->mConnReqMap.end()) {
210 LoggerW("Connection state is changed unexpectedly");
214 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(iter->second->mUserData);
216 if(result == BT_ERROR_NONE) {
217 // Update mConnectedSocket
218 BluetoothSocketPtr socket = new BluetoothSocket(connection);
219 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
220 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
222 // Call successcallback of connectToServiceByUUID
223 JSContextRef context = callback->getContext();
224 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
226 callback->invokeCallback("success", socketObj);
228 // Update mConnReqMap
229 object->mConnReqMap.erase(iter);
232 // Call errorcallback of connectToServiceByUUID
233 JSContextRef context = callback->getContext();
234 NotFoundException error("Not found");
236 callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
238 // Update mConnReqMap
239 object->mConnReqMap.erase(iter);
243 else { // disconnected when Client
244 if(result == BT_ERROR_NONE) {
245 // call BluetoothSocket.onclose;
246 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
247 if(i == object->mConnectedSocket.end()) {
248 LoggerW("Unknown connected socket");
252 BluetoothSocketPtr socket = i->second;
253 socket->setConnectionState(false);
254 MultiCallbackUserDataPtr callback = socket->getOnClose();
256 callback->invokeCallback("onclose");
258 // Update mConnectedSocket
259 object->mConnectedSocket.erase(i);
262 LoggerW("Disconnecting a connection failed");
267 LoggerW("Unknown role");
271 if(object->mConnectedSocket.size() == 0) {
272 bt_socket_unset_data_received_cb();
275 if(object->mRegisteredUUID.size() == 0 && object->mConnReqMap.size() == 0 && object->mConnectedSocket.size() == 0) {
276 bt_socket_unset_connection_state_changed_cb();
280 void BluetoothAdapter::onSocketReceivedCB(bt_socket_received_data_s *data, void *userData)
282 BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
284 LoggerW("userData is NULL");
289 LoggerW("data is NULL");
293 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(data->socket_fd);
294 if(i == object->mConnectedSocket.end()) {
295 LoggerW("Unknown connected socket");
299 // Store received data
300 BluetoothSocketPtr socket = i->second;
301 socket->storeRecivedData(data->data, static_cast<unsigned long>(data->data_size));
303 // Call BluetoothSocket.onmessage
304 MultiCallbackUserDataPtr callback = socket->getOnMessage();
306 callback->invokeCallback("onmessage");
309 BluetoothAdapter::BluetoothAdapter():
311 mAgentRegistrationId(-1),
312 mAgentIntrospectionData(NULL),
313 mBluetoothTechnology(NULL),
318 mBluetoothTechnology = getBluetoothTechnology();
319 if(!mBluetoothTechnology) {
320 LoggerE("Failed to get BT technology");
323 mAdapterPath = getDefaultAdapter();
325 LoggerE("Unable to get default adapter");
327 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
328 "/", "AdapterAdded", BluetoothAdapter::handleSignal,
330 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
331 "/", "AdapterRemoved", BluetoothAdapter::handleSignal,
333 memset(&mAgentIfaceVTable, 0, sizeof(mAgentIfaceVTable));
335 if(isAdapterPowered()) {
336 //LoggerD("Adapter is powered");
340 // LoggerD("Adapter is not powered");
344 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
345 mAdapterPath, "PropertyChanged", BluetoothAdapter::handleSignal,
350 BluetoothAdapter::~BluetoothAdapter()
352 // unset platform callback
353 bt_socket_unset_connection_state_changed_cb();
354 bt_socket_unset_data_received_cb();
356 for(int i = 0; i <= DESTROY_BONDING; i++) {
357 mUserDataList[i].reset();
359 mRegisteredUUID.clear();
361 mFoundDevices.clear();
362 mConnectedSocket.clear();
365 void BluetoothAdapter::unloadFrame(JSContextRef context)
367 LoggerD("Clean mUserDataList");
368 for(int i = 0; i <= DESTROY_BONDING; i++) {
369 if(mUserDataList[i]) {
370 MultiCallbackUserDataPtr callback = mUserDataList[i];
371 if(!GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext())) {
372 mUserDataList[i].reset();
377 LoggerD("Clean mConnReqMap");
378 for(ConnReqMultiMapT::iterator iter = mConnReqMap.begin(); iter != mConnReqMap.end(); ) {
379 ConnReqMultiMapT::iterator temp = iter++;
380 MultiCallbackUserDataPtr callback = temp->second->mUserData;
381 if(!callback && !GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext())) {
382 mConnReqMap.erase(temp);
387 void BluetoothAdapter::unregisterUUID(std::string &uuid)
389 mRegisteredUUID.erase(mRegisteredUUID.find(uuid));
390 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0) {
391 bt_socket_unset_connection_state_changed_cb();
395 bool BluetoothAdapter::closeConnectedSocket(int socket)
397 if(mEnabled == true) {
398 ConnectedSocketMapT::iterator iter = mConnectedSocket.find(socket);
399 if(iter == mConnectedSocket.end()) {
400 LoggerW("Already disconnected");
404 mConnectedSocket.erase(iter);
405 if(mConnectedSocket.size() == 0) {
406 bt_socket_unset_data_received_cb();
409 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0) {
410 bt_socket_unset_connection_state_changed_cb();
416 LoggerE("Bluetooth is not powered");
421 void BluetoothAdapter::removeConnReq(std::string &remoteAddress)
423 mConnReqMap.erase(remoteAddress);
425 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0) {
426 if(bt_socket_unset_connection_state_changed_cb() != BT_ERROR_NONE) {
427 LoggerW("Unsetting connection event callback failed");
432 BluetoothAdapter* BluetoothAdapter::getInstance()
434 static BluetoothAdapter instance;
438 bool BluetoothAdapter::isBluetoothSupported()
440 bool isSupported = false;
442 /* if(system_info_get_value_bool(SYSTEM_INFO_KEY_BLUETOOTH_SUPPORTED, &isSupported) != SYSTEM_INFO_ERROR_NONE) {
443 LoggerE("Can't know whether Bluetooth is supported or not");
449 bool BluetoothAdapter::isValidAddress(std::string &address)
451 pcrecpp::RE re("(([0-9a-zA-Z]+):)+([0-9a-zA-Z]+)");
452 std::string compareAddress = "00:12:47:08:9A:A6";
454 if (!re.FullMatch(address)) {
455 LoggerE("Invalid address");
459 if (address.size() != compareAddress.size())
461 LoggerE("Invalid size");
468 bool BluetoothAdapter::isValidUUID(std::string &uuid)
470 pcrecpp::RE re("(([0-9a-zA-Z]+)-)+([0-9a-zA-Z]+)");
471 std::string compareUUID = "00001101-0000-1000-8000-00805F9B34FB";
473 if (!re.FullMatch(uuid))
475 LoggerE("Invalid UUID");
479 if (uuid.size() != compareUUID.size())
481 LoggerE("Invalid size");
488 std::string BluetoothAdapter::getName() const
490 const char* name = NULL;
491 std::string str = "";
494 LoggerD("No BT adapter");
498 // get adapter properties and check Name property
500 GVariant *reply = NULL;
501 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
508 G_DBUS_CALL_FLAGS_NONE,
515 LoggerE("Failed to get 'Name' property");
520 g_variant_get(reply, "(a{sv})", &iter);
523 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
524 if(!strcmp(key, "Name")) {
525 name = g_variant_get_string(value, NULL);
532 g_variant_unref(reply);
537 void BluetoothAdapter::setName(std::string &name, MultiCallbackUserDataPtr userData)
539 if(mEnabled == true) {
540 std::string adapterName = getName();
541 if(adapterName == name) { // in case of same name
542 LoggerD("same name");
543 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
549 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
554 g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
556 g_variant_new("s", name.c_str()) // floating parameters are consumed, no cleanup/unref needed
559 G_DBUS_CALL_FLAGS_NONE,
565 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
566 UnknownException *error = new UnknownException(err->message);
567 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
573 userData->invokeCallback("success");
576 LoggerE("No BT adapter");
577 UnknownException *error = new UnknownException("No BT adapter");
578 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
584 std::string BluetoothAdapter::getAddress() const
586 const char* address = NULL;
587 std::string str = "";
590 LoggerD("No BT adapter");
594 // get adapter properties and check Address property
596 GVariant *reply = NULL;
597 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
604 G_DBUS_CALL_FLAGS_NONE,
611 LoggerE("Failed to get 'Address' property");
616 g_variant_get(reply, "(a{sv})", &iter);
619 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
620 if(!strcmp(key, "Address")) {
621 address = g_variant_get_string(value, NULL);
628 g_variant_unref(reply);
633 bool BluetoothAdapter::getPowered() const
638 void BluetoothAdapter::setPowered(bool powered, MultiCallbackUserDataPtr userData)
642 bool btTechnologyPowered = isBtTechnologyPowered();
643 if(!powered) { // Powering OFF BT. It is enough to take down BT technology - it will take down Adapter as well
644 if(!btTechnologyPowered) { // already powered OFF
645 LoggerD("BT already powered OFF ... calling success callback.");
646 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
650 if(setBluetoothPowered(powered)) { // BT powered OFF successfuly
651 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
654 LoggerD("Failed to Power OFF BT technology - trying to Power OFF the Adapter directly");
655 if(setAdapterPowered(powered)) {
656 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
659 LoggerE("Failed to Power OFF both, BT and adapter as well ... calling error callback");
660 UnknownException *error = new UnknownException("Failed to Power OFF BT/Adapter");
661 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
666 else { // Powering ON BT
667 if(btTechnologyPowered) { // already Powered ON
668 if(mEnabled) { // already Powered On
669 LoggerD("BT/Adapter already powered ON ... calling success callback.");
670 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
672 else { // BT powered, but Adapter is not - try to power it ON
673 LoggerD("BT technology is Powered ON, but adapter is not, trying to Power it ON");
674 if(setAdapterPowered(powered)) { // successfuly powered ON ... calling success callback
675 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
678 LoggerE("Failed to Power ON BT adapter ... calling error callback");
679 UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
680 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
685 if(!setBluetoothPowered(powered)) {
686 LoggerE("Failed to Power ON BT technology ... calling error callback");
687 UnknownException *error = new UnknownException("Failed to Power ON BT technology");
688 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
691 else { // BT technology powered ON (it should power ON adapter as well, but just in case, call Power ON on adapter as well)
692 if(setAdapterPowered(powered)) {
693 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
696 LoggerE("Failed to Power ON BT adapter ... calling error callback");
697 UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
698 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
703 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
708 mUserDataList[SET_POWERED].reset();
711 bool BluetoothAdapter::getVisible() const
714 LoggerD("No BT adapter");
718 // get adapter properties and check Discoverable property
720 GVariant *reply = NULL;
721 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
728 G_DBUS_CALL_FLAGS_NONE,
735 LoggerE("Failed to get 'Discoverable' property");
739 bool visible = false;
741 g_variant_get(reply, "(a{sv})", &iter);
744 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
745 if(!strcmp(key, "Discoverable")) {
746 visible = g_variant_get_boolean(value);
751 g_variant_unref(reply);
756 void BluetoothAdapter::setVisible(bool visible, unsigned int timeout, MultiCallbackUserDataPtr userData)
758 //TODO: implementation needed
759 UnknownException *error = new UnknownException("NOT IMPLEMENTED");
760 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
762 if(mEnabled == true) {
763 bt_adapter_visibility_mode_e discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
764 if(visible == true) {
766 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
768 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
771 bt_adapter_visibility_mode_e current = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
773 if(bt_adapter_get_visibility(¤t , &time) != BT_ERROR_NONE) {
774 LoggerE("bt_adapter_get_visibility() failed");
775 UnknownException *error = new UnknownException("Can't get current visibility");
776 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
780 if(discoverable_mode == current) {
781 if(discoverable_mode != BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE) {
782 LoggerD("same visibility");
783 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
786 else if((unsigned int)time == timeout) {
787 LoggerD("same visibility");
788 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
793 if(mUserDataList[SET_VISIBLE] == NULL) {
794 bt_adapter_set_visibility_mode_changed_cb(onVisibilityChangedCB, this);
795 mUserDataList[SET_VISIBLE] = userData;
797 UnknownException *error = new UnknownException("Already requested");
798 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
802 mRequestedVisibility = discoverable_mode;
803 int ret = bt_adapter_set_visibility(discoverable_mode, timeout);
807 LoggerD("bt_adapter_set_visibility() succeeded");
810 case BT_ERROR_INVALID_PARAMETER:
812 InvalidValuesException *error = new InvalidValuesException("Invalid value");
813 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
818 UnknownException *error = new UnknownException("Unknown error");
819 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
823 bt_adapter_unset_visibility_mode_changed_cb();
824 mUserDataList[SET_VISIBLE].reset();
825 } else { // Not enabled
826 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
827 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
832 void BluetoothAdapter::setChangeListener(MultiCallbackUserDataPtr userData)
834 if(mChangeListener == NULL)
835 mChangeListener = userData;
838 void BluetoothAdapter::unsetChangeListener()
840 if(mChangeListener != NULL)
841 mChangeListener.reset();
845 void BluetoothAdapter::discoverDevices(MultiCallbackUserDataPtr userData)
848 LoggerE("No BT adapter");
849 UnknownException *error = new UnknownException("No BT adapter");
850 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
854 if(mUserDataList[DISCOVER_DEVICES] == NULL) {
855 mUserDataList[DISCOVER_DEVICES] = userData;
857 LoggerE("Already requested");
858 UnknownException *error = new UnknownException("Already requested");
859 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
863 if(mEnabled == true) {
865 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
872 G_DBUS_CALL_FLAGS_NONE,
877 LoggerE("Failed to 'StartDiscovery' on adapter " << mAdapterPath << " : " << err->message);
878 UnknownException *error = new UnknownException(err->message);
879 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
881 mUserDataList[DISCOVER_DEVICES].reset();
884 LoggerD("Call to 'StartDiscovery' succeeded");
886 // store MAC address of previously found device into mDisappearedDevices
887 mDisappearedDevices.clear();
888 for(auto iter = mFoundDevices.begin();
889 iter != mFoundDevices.end(); iter++) {
890 BluetoothDeviceSharedPtr foundDevice = *iter;
891 mDisappearedDevices.push_back(foundDevice->getAddress());
894 mFoundDevices.clear();
896 // 'onstarted' callback is called after receiving 'Discovering' property changed to 'true' ... see handleSignal() method
898 // userData->invokeCallback("onstarted");
900 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
901 mAdapterPath, "DeviceFound", BluetoothAdapter::handleSignal,
906 } else { // Not enabled
907 LoggerE("Bluetooth device is turned off");
908 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
909 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
912 mUserDataList[DISCOVER_DEVICES].reset();
915 void BluetoothAdapter::stopDiscovery(MultiCallbackUserDataPtr userData)
917 if(mUserDataList[DISCOVER_DEVICES] == NULL) { // not doing discovery
918 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
923 LoggerE("No BT adapter");
924 UnknownException *error = new UnknownException("No BT adapter");
925 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
927 else if(mEnabled == true) {
929 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
936 G_DBUS_CALL_FLAGS_NONE,
941 LoggerE("Failed to 'StopDiscovery': " << err->message);
942 UnknownException *error = new UnknownException(err->message);
943 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
946 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
949 } else { // Not enabled
950 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
951 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
954 mUserDataList[DISCOVER_DEVICES].reset();
957 void BluetoothAdapter::getKnownDevices(MultiCallbackUserDataPtr userData)
959 BluetoothCallbackUtil::syncToAsyncDeviceArrayCallback(userData);
962 void BluetoothAdapter::getDevice(std::string &address, MultiCallbackUserDataPtr userData)
964 BluetoothCallbackUtil::syncToAsyncDeviceCallback(userData, address);
967 void BluetoothAdapter::createBonding(std::string &address, MultiCallbackUserDataPtr userData)
969 if(!isValidAddress(address)) {
970 LoggerE("Wrong address");
971 NotFoundException *error = new NotFoundException("Wrong address");
972 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
977 LoggerE("No BT adapter");
978 NotFoundException *error = new NotFoundException("No BT adapter");
979 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
983 if(mUserDataList[CREATE_BONDING] == NULL) {
984 mCreateBondingAddress = address;
985 mUserDataList[CREATE_BONDING] = userData;
987 LoggerE("Already requested");
988 UnknownException *error = new UnknownException("Already requested");
989 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
993 // remove the device first, so the pairing can be initiated, otherwise pairing will fail
994 bool ok = removeDevice(address.c_str());
996 LoggerD("Failed to remove device: " << address);
998 if(mEnabled == true) {
999 if(setupAgent(AGENT_PATH)) {
1000 // CreatePairedDevice has to be ASYNC DBUS call
1001 g_dbus_connection_call( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1004 BLUEZ_ADAPTER_IFACE,
1005 "CreatePairedDevice",
1006 g_variant_new("(sos)", address.c_str(), AGENT_PATH, AGENT_CAPABILITIES),
1008 G_DBUS_CALL_FLAGS_NONE,
1011 BluetoothAdapter::asyncCreatePairedDeviceCallback,
1013 LoggerD("Called 'CreatePairedDevice'");
1015 LoggerE("Failed to set-up Bluez Agent for pairing");
1016 ServiceNotAvailableException *error = new ServiceNotAvailableException("Failed to set-up Bluez Agent for pairing");
1017 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1019 } else { // Not enabled
1020 LoggerE("Bluetooth device is turned off");
1021 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
1022 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1026 void BluetoothAdapter::destroyBonding(std::string &address, MultiCallbackUserDataPtr userData)
1028 if(!isValidAddress(address)) {
1029 LoggerE("Wrong address");
1030 NotFoundException *error = new NotFoundException("Wrong address");
1031 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1035 // get device info before removing, 'cause after removing you loose access to it ('FindDevice' will not find it)
1036 bt_device_info_s deviceInfo;
1037 bool hasDeviceInfo = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1039 if(!removeDevice(address.c_str())) {
1041 JSContextRef context = userData->getContext();
1042 UnknownException error("Failed to remove device");
1043 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1051 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1052 JSContextRef context = userData->getContext();
1053 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1054 userData->invokeCallback("success", deviceObj);
1056 JSContextRef context = userData->getContext();
1057 UnknownException error("Failed to get device info");
1058 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1060 freeDeviceInfo(&deviceInfo);
1064 void BluetoothAdapter::registerRFCOMMServiceByUUID(std::string &uuid, std::string &name, MultiCallbackUserDataPtr userData)
1066 BluetoothCallbackUtil::syncToAsyncServiceCallback(userData, uuid, name);
1069 void BluetoothAdapter::connectToServiceByUUID(std::string &remoteAddress, std::string &uuid, Common::MultiCallbackUserDataPtr userData)
1071 if(!isValidUUID(uuid)) {
1072 LoggerE("Wrong UUID");
1073 InvalidValuesException *error = new InvalidValuesException("Wrong UUID");
1074 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1079 if(mEnabled == true) {
1080 int ret = bt_socket_connect_rfcomm(remoteAddress.c_str(), uuid.c_str());
1085 LoggerD("bt_socket_connect_rfcomm() succeeded");
1086 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1088 BluetoothConnReqPtr connReq = new BluetoothConnReq(uuid, userData);
1089 mConnReqMap.insert(std::pair<std::string, BluetoothConnReqPtr>(remoteAddress, connReq));
1092 case BT_ERROR_INVALID_PARAMETER:
1093 case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
1095 InvalidValuesException *error = new InvalidValuesException("Invalid value");
1096 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1101 UnknownException *error = new UnknownException("Unknown error");
1102 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1105 } else { // Not enabled
1106 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
1107 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1111 void BluetoothAdapter::returnKnownDevices(Common::MultiCallbackUserDataPtr userData)
1113 if(mEnabled == true) {
1114 knownDevices = mFoundDevices;
1116 // Get a list of paired/bonded devices
1118 GVariant *reply = NULL;
1119 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1122 BLUEZ_ADAPTER_IFACE,
1126 G_DBUS_CALL_FLAGS_NONE,
1135 g_variant_get(reply, "(a{sv})", &iter);
1138 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
1139 if(!strcmp(key, "Devices")) {
1140 g_variant_get(value, "ao", &iter);
1141 const char *device = NULL;
1142 while(g_variant_iter_next(iter, "o", &device)) {
1143 if(isDevicePaired(device)) {
1144 bt_device_info_s deviceInfo;
1145 if(getDeviceInfo(&deviceInfo, device))
1146 foreachBondedDevicesCB(&deviceInfo, this);
1147 freeDeviceInfo(&deviceInfo);
1154 g_variant_unref(reply);
1157 if(knownDevices.size() > 0) { // There are found devices
1158 //LoggerD("There are found devices");
1159 int num = knownDevices.size();
1160 JSObjectRef devices[num];
1161 for(int i = 0; i < num; i++) {
1162 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(userData->getContext(), knownDevices[i]);
1163 devices[i] = deviceObj;
1166 userData->invokeCallback("success", JSObjectMakeArray(userData->getContext(), num, devices, NULL));
1168 else { // There is no found device
1169 userData->invokeCallback("success", JSObjectMakeArray(userData->getContext(), 0, NULL, NULL) );
1171 } else { // Not enabled
1172 LoggerE("Bluetooth device is turned off");
1173 userData->invokeCallback(
1175 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1180 void BluetoothAdapter::returnDevice(std::string &address, Common::MultiCallbackUserDataPtr userData)
1182 if(!isValidAddress(address)) {
1183 LoggerE("Wrong address");
1184 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("Wrong address")));
1188 if(mEnabled == true) {
1189 bt_device_info_s deviceInfo;
1190 bool success = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1193 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1194 LoggerD("invoke successCallback");
1195 userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), device));
1198 JSContextRef context = userData->getContext();
1199 UnknownException error("Failed to get device info");
1200 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1202 freeDeviceInfo(&deviceInfo);
1204 std::vector<BluetoothDeviceSharedPtr>::iterator iter;
1205 for(iter = mFoundDevices.begin(); iter != mFoundDevices.end(); ++iter) {
1206 BluetoothDeviceSharedPtr foundDevice = *iter;
1207 if(!strcmp(foundDevice->getAddress().c_str(), address.c_str())) {
1208 LoggerD("Found in mFoundDevices");
1209 userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), foundDevice));
1214 if(iter == mFoundDevices.end()) {
1215 LoggerE("Can't find this device");
1217 userData->invokeCallback(
1219 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("There is no device with the given address"))
1222 } else { // Not enabled
1223 LoggerE("Bluetooth device is turned off");
1224 userData->invokeCallback(
1226 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1231 void BluetoothAdapter::returnRegisteredService(std::string &uuid, std::string &name, Common::MultiCallbackUserDataPtr userData)
1233 if(!isValidUUID(uuid)) {
1234 LoggerE("Wrong UUID");
1235 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Wrong UUID")));
1239 if(mEnabled == true) {
1242 if(bt_adapter_is_service_used(uuid.c_str(), &isRegistered) == BT_ERROR_NONE && isRegistered == true) {
1243 LoggerD("Already registered");
1244 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Already registered")));
1249 int ret = bt_socket_create_rfcomm(uuid.c_str(), &socket);
1254 LoggerD("bt_socket_create_rfcomm() succeeded");
1255 int ret = bt_socket_listen_and_accept_rfcomm(socket, 0);
1259 LoggerD("bt_socket_listen() succeeded");
1260 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1262 BluetoothServiceHandlerPtr serviceHandler = new BluetoothServiceHandler(uuid, name, socket);
1263 mRegisteredUUID.insert(std::pair<std::string, BluetoothServiceHandlerPtr>(uuid, serviceHandler));
1265 JSObjectRef serviceObj = JSBluetoothServiceHandler::createJSObject(userData->getContext(), serviceHandler);
1266 userData->invokeCallback("success", serviceObj);
1269 case BT_ERROR_INVALID_PARAMETER:
1271 LoggerD("Invalid value");
1272 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1277 LoggerD("Unknown exception");
1278 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1284 case BT_ERROR_INVALID_PARAMETER:
1286 LoggerD("Invalid value");
1287 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1292 LoggerD("Unknown exception");
1293 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1296 } else { // Not enabled
1297 LoggerE("Bluetooth device is turned off");
1298 userData->invokeCallback(
1300 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1305 bool BluetoothAdapter::isBtTechnologyPowered() {
1306 if(!mBluetoothTechnology) {
1307 LoggerE("Invalid BT technology to get 'Powered' state.");
1312 GVariant *reply = NULL;
1313 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1315 mBluetoothTechnology,
1316 CONNMAN_TECHNOLOGY_IFACE,
1320 G_DBUS_CALL_FLAGS_NONE,
1331 g_variant_get(reply, "(a{sv})", &iter);
1334 bool powered = false;
1335 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
1336 if(!strcmp(key, "Powered")) {
1337 powered = g_variant_get_boolean(value);
1342 g_variant_unref(reply);
1347 gchar* BluetoothAdapter::getDefaultAdapter() const
1350 GVariant *reply = NULL;
1351 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1354 BLUEZ_MANAGER_IFACE,
1358 G_DBUS_CALL_FLAGS_NONE,
1364 LoggerE("Failed to get default adapter: " << err->message);
1368 LoggerE("Reply from 'DefaultAdapter' is null");
1372 char *adapter = NULL;
1373 g_variant_get(reply, "(o)", &adapter);
1374 LoggerD("DefaultAdapter: " << adapter);
1376 // make a copy of adapter, 'cause it will be destroyed when 'reply' is un-refed
1377 char *result = adapter?strdup(adapter):NULL;
1379 g_variant_unref(reply);
1384 bool BluetoothAdapter::isAdapterPowered() {
1388 // get adapter properties and check if it's Powered
1390 GVariant *reply = NULL;
1391 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1394 BLUEZ_ADAPTER_IFACE,
1398 G_DBUS_CALL_FLAGS_NONE,
1409 g_variant_get(reply, "(a{sv})", &iter);
1412 bool powered = false;
1413 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
1414 if(!strcmp(key, "Powered")) {
1415 powered = g_variant_get_boolean(value);
1420 g_variant_unref(reply);
1425 void BluetoothAdapter::handleSignal(GDBusConnection *connection,
1426 const gchar *sender,
1427 const gchar *object_path,
1428 const gchar *interface_name,
1429 const gchar *signal_name,
1430 GVariant *parameters,
1433 LoggerD("signal received: '" << interface_name << "' -> '" << signal_name << "' -> '" << object_path << "'");
1435 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1437 LoggerD("Failed to cast to BluetoothAdapter");
1442 if(!strcmp(interface_name, BLUEZ_MANAGER_IFACE)) {
1443 if(!strcmp(signal_name, "AdapterAdded")) {
1444 const char *adapter = NULL;
1445 g_variant_get(parameters, "(o)", &adapter);
1447 LoggerD("Adapter added: " << adapter);
1448 gchar * adapterPath = ctx->getDefaultAdapter();
1449 free(ctx->mAdapterPath);
1450 ctx->mAdapterPath = adapterPath;
1452 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
1453 adapterPath, "PropertyChanged", BluetoothAdapter::handleSignal,
1458 else if(!strcmp(signal_name, "AdapterRemoved")) {
1459 const char *adapter = NULL;
1460 g_variant_get(parameters, "(o)", &adapter);
1462 LoggerD("Adapter removed: " << adapter);
1466 else if(!strcmp(interface_name, BLUEZ_ADAPTER_IFACE)) {
1467 if(!strcmp(signal_name, "PropertyChanged")) {
1470 g_variant_get(parameters, "(sv)", &name, &var);
1471 LoggerD("\tname=" << name);
1472 if(!strcmp(name, "Name")) {
1473 const char *_name = g_variant_get_string(var, NULL);
1474 ctx->onNameChanged(_name);
1476 else if(!strcmp(name, "Powered")) {
1477 bool powered = g_variant_get_boolean(var);
1478 ctx->onPoweredChanged(powered);
1480 else if(!strcmp(name, "Discoverable")) {
1481 bool visible = g_variant_get_boolean(var);
1482 ctx->onVisibilityChanged(visible);
1484 else if(!strcmp(name, "Discovering")) {
1485 bool discovering = g_variant_get_boolean(var);
1486 if(discovering) { // discovery started
1487 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1489 callback->invokeCallback("onstarted");
1492 else { // discovery completed
1493 LoggerD("Discovery completed");
1494 if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL) {
1495 MultiCallbackUserDataPtr callback =
1496 static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1499 if(ctx->mDisappearedDevices.size() > 0) {
1500 LoggerD("There are disappeared devices");
1501 for(auto iter = ctx->mDisappearedDevices.begin();
1502 iter != ctx->mDisappearedDevices.end(); iter++) {
1504 callback->invokeCallback("ondevicedisappeared",
1505 JSUtil::toJSValueRef(callback->getContext(), *iter));
1509 if(ctx->mFoundDevices.size() > 0) { // There are found devices
1510 LoggerD("There are found devices");
1511 int num = ctx->mFoundDevices.size();
1512 JSObjectRef devices[num];
1513 for(int i = 0; i < num; i++) {
1514 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(callback->getContext(), ctx->mFoundDevices[i]);
1515 devices[i] = deviceObj;
1518 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1520 callback->invokeCallback(
1522 JSObjectMakeArray(callback->getContext(), num, devices, NULL) );
1524 else { // There is no found device
1525 LoggerD("There is no found device");
1526 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1528 callback->invokeCallback(
1530 JSObjectMakeArray(callback->getContext(), 0, NULL, NULL) );
1534 Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE, object_path, "DeviceFound");
1537 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1540 BLUEZ_ADAPTER_IFACE,
1544 G_DBUS_CALL_FLAGS_NONE,
1554 else if(!strcmp(signal_name, "DeviceFound")) { // found remote BT device
1555 bt_adapter_device_discovery_info_s discoveryInfo;
1556 discoveryInfo.remote_name = NULL;
1557 discoveryInfo.remote_address = NULL;
1558 discoveryInfo.service_uuid = NULL;
1559 discoveryInfo.service_count = 0;
1561 const char *address;
1563 g_variant_get(parameters, "(sa{sv})", &address, &iter);
1564 discoveryInfo.remote_address = address?strdup(address):NULL;
1567 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
1568 //LoggerD("KEY: " << key);
1569 if(!strcmp(key, "Name")) {
1570 const char *name = g_variant_get_string(value, NULL);
1571 discoveryInfo.remote_name = name?strdup(name):NULL;
1573 else if(!strcmp(key, "Paired")) {
1574 discoveryInfo.is_bonded = g_variant_get_boolean(value);
1576 else if(!strcmp(key, "Class")) {
1577 guint32 _class = g_variant_get_uint32(value);
1578 uint8_t minor = _class & 0xff;
1579 uint8_t major = (_class >> 8) & 0xff;
1580 discoveryInfo.bt_class.minor_device_class = (bt_minor_device_class_e) minor;
1581 discoveryInfo.bt_class.major_device_class = (bt_major_device_class_e) major;
1582 //discoveryInfo.bt_class.major_service_class_mask =
1584 else if(!strcmp(key, "UUIDs")) {
1586 const char *uuid = NULL;
1587 g_variant_get(value, "as", &iter);
1588 discoveryInfo.service_count = g_variant_iter_n_children(iter);
1589 discoveryInfo.service_uuid = (char**)malloc(discoveryInfo.service_count*sizeof(char*));
1590 char **uuids = discoveryInfo.service_uuid; // make a copy of ptr, since we will modify the pointer
1591 while(g_variant_iter_next(iter, "s", &uuid)) {
1592 *uuids++ = uuid?strdup(uuid):NULL;
1597 if(!discoveryInfo.remote_address) {
1598 LoggerD("discovery info ... remote_address is null");
1599 ctx->freeDiscoveryInfo(&discoveryInfo);
1603 if(!discoveryInfo.remote_name) {
1604 LoggerD("discovery info ... remote_name is null for " << discoveryInfo.remote_address);
1605 discoveryInfo.remote_name = strdup("");
1608 LoggerD("Found BT device: " << discoveryInfo.remote_address << " ... " << (discoveryInfo.remote_name?discoveryInfo.remote_name:""));
1610 if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL) { // requested event
1611 MultiCallbackUserDataPtr callback =
1612 static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1615 if(!ctx->isDeviceInList(ctx->mFoundDevices, discoveryInfo.remote_address)) {
1616 // create BluetoothDevice
1617 BluetoothDeviceSharedPtr device(new BluetoothDevice(&discoveryInfo));
1618 JSContextRef context = callback->getContext();
1619 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1620 ctx->mFoundDevices.push_back(device);
1622 // remove MAC address of found device from mDisappearedDevices
1623 for(auto iter = ctx->mDisappearedDevices.begin(); iter != ctx->mDisappearedDevices.end(); iter++) {
1624 if(!strcmp(discoveryInfo.remote_address, (*iter).c_str())) {
1625 ctx->mDisappearedDevices.erase(iter);
1630 callback->invokeCallback("ondevicefound", deviceObj);
1635 ctx->freeDiscoveryInfo(&discoveryInfo);
1639 else if(!strcmp(interface_name, CONNMAN_TECHNOLOGY_IFACE)) {
1640 if(!strcmp(signal_name, "PropertyChanged")) {
1643 g_variant_get(parameters, "(sv)", &name, &value);
1644 if(!strcmp(name, "Powered")) {
1645 bool powered = g_variant_get_boolean(value);
1646 ctx->onPoweredChanged(powered);
1653 bool BluetoothAdapter::isDeviceInList(std::vector<BluetoothDeviceSharedPtr> list, const char *address) {
1654 bool exists = false;
1655 for(auto iter = list.begin(); iter != list.end(); iter++) {
1656 if(!strcmp((*iter)->getAddress().c_str(), address)) {
1665 bool BluetoothAdapter::setAdapterPowered(bool value)
1671 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1674 BLUEZ_ADAPTER_IFACE,
1676 g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
1678 //g_variant_new("b", &value)
1679 g_variant_new_boolean(value)
1682 G_DBUS_CALL_FLAGS_NONE,
1688 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
1699 void BluetoothAdapter::onPoweredChanged(bool powered)
1703 if(mChangeListener != NULL) {
1704 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1706 JSContextRef context = callback->getContext();
1707 JSValueRef value = JSValueMakeBoolean(context, powered);
1709 callback->invokeCallback("onstatechanged", value);
1713 if(!powered && mUserDataList[DISCOVER_DEVICES] != NULL)
1714 mUserDataList[DISCOVER_DEVICES].reset();
1717 void BluetoothAdapter::onNameChanged(const char *name)
1719 if(mUserDataList[SET_NAME] != NULL) { // requested event
1720 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mUserDataList[SET_NAME]);
1721 mUserDataList[SET_NAME].reset();
1723 callback->invokeCallback("success");
1725 else { // unexpected event
1726 LoggerW("Bluetooth name is changed unexpectedly");
1729 if(mChangeListener != NULL) {
1730 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1732 JSContextRef context = callback->getContext();
1733 JSStringRef nameRef = JSStringCreateWithUTF8CString(name);
1734 JSValueRef value = JSValueMakeString(context, nameRef);
1736 callback->invokeCallback("onnamechanged", value);
1741 void BluetoothAdapter::onVisibilityChanged(bool visible)
1743 if(mChangeListener != NULL) {
1744 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1746 JSContextRef context = callback->getContext();
1747 JSValueRef value = JSValueMakeBoolean(context, visible);
1749 callback->invokeCallback("onvisibilitychanged", value);
1754 void BluetoothAdapter::asyncCreatePairedDeviceCallback(GObject *source, GAsyncResult *result, gpointer user_data) {
1755 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1757 LoggerE("Failed to cast to BluetoothAdapter");
1763 reply = g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
1765 LoggerD("Failed to CreatePairedDevice: " << (err?err->message:"Invalid reply"));
1766 if(ctx->mUserDataList[CREATE_BONDING] != NULL) {
1767 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
1769 NotFoundException *error = new NotFoundException("Failed to CreatePairedDevice");
1770 BluetoothCallbackUtil::syncToAsyncErrorCallback(callback, error);
1776 LoggerD("Got reply from CreatePairedDevice");
1777 if(ctx->mUserDataList[CREATE_BONDING] != NULL) {
1778 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
1780 bt_device_info_s deviceInfo;
1781 if(ctx->getDeviceInfoByAddress(&deviceInfo, ctx->mCreateBondingAddress.c_str())) {
1782 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1783 JSContextRef context = callback->getContext();
1784 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1785 callback->invokeCallback("success", deviceObj);
1787 JSContextRef context = callback->getContext();
1788 UnknownException error("Failed to get device info");
1789 callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1791 ctx->freeDeviceInfo(&deviceInfo);
1796 ctx->mCreateBondingAddress.clear();
1797 ctx->mUserDataList[CREATE_BONDING].reset();
1799 g_variant_unref(reply);
1802 bool BluetoothAdapter::setupAgent(const char *agent)
1805 LoggerE("Invalid agent path");
1809 LoggerD("entered: registering agent " << agent);
1813 mAgentIfaceVTable.method_call = BluetoothAdapter::agentHandleMethodCall;
1814 mAgentIntrospectionData = g_dbus_node_info_new_for_xml(AGENT_INTERFACE_XML, NULL);
1816 if (mAgentIntrospectionData == NULL) {
1817 LoggerD("failed to create introspection data.");
1820 LoggerD("introspection data parsed OK");
1822 if(mAgentRegistrationId > 0) { // already registered
1823 LoggerD("Bluez agent for pairing already registered ... possibly not Released after previous pairing");
1826 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), mAgentRegistrationId);
1828 mAgentRegistrationId = -1;
1831 mAgentRegistrationId = g_dbus_connection_register_object( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1833 mAgentIntrospectionData->interfaces[0],
1834 &mAgentIfaceVTable, //const GDBusInterfaceVTable *vtable,
1836 NULL, //GDestroyNotify
1840 LoggerD("Failed to register object: " << agent << " : " << err->message);
1844 LoggerD("object registered with id=" << mAgentRegistrationId);
1849 void BluetoothAdapter::agentHandleMethodCall( GDBusConnection *connection,
1850 const gchar *sender,
1851 const gchar *object_path,
1852 const gchar *interface_name,
1853 const gchar *method_name,
1854 GVariant *parameters,
1855 GDBusMethodInvocation *invocation,
1858 LoggerD("entered\n\tsender=" << sender << "\n\tobject_path=" << object_path << "\n\tinterface_name=" << interface_name << "\n\tmethod_name=" << method_name);
1860 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1862 LoggerD("Failed to cast to BluetoothAdapter");
1863 g_dbus_method_invocation_return_value(invocation, NULL);
1867 if(!strcmp(method_name, "Authorize")) {
1868 g_dbus_method_invocation_return_value(invocation, NULL);
1870 else if(!strcmp(method_name, "RequestPinCode")) {
1871 g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", PINCODE));
1873 else if(!strcmp(method_name, "RequestPasskey")) {
1874 g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", PASSKEY));
1876 else if (!strcmp(method_name, "Release")) {
1877 if(!strcmp(object_path, AGENT_PATH)) { // released agent for pairing
1878 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), ctx->mAgentRegistrationId);
1880 ctx->mAgentRegistrationId = -1;
1882 g_dbus_method_invocation_return_value(invocation, NULL);
1885 // DisplayPasskey, DisplayPinCode, RequestConfirmation, ConfirmModeChange, Cancel
1886 g_dbus_method_invocation_return_value(invocation, NULL);
1890 bool BluetoothAdapter::isDevicePaired(const char *device) {
1894 // get device properties and check if it's Paired
1896 GVariant *reply = NULL;
1897 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1904 G_DBUS_CALL_FLAGS_NONE,
1915 g_variant_get(reply, "(a{sv})", &iter);
1918 bool paired = false;
1919 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
1920 if(!strcmp(key, "Paired")) {
1921 paired = g_variant_get_boolean(value);
1926 g_variant_unref(reply);
1931 bool BluetoothAdapter::getDeviceInfoByAddress(bt_device_info_s *deviceInfo, const char *address) {
1933 // to assure that when leaving the method, these fields
1934 // will be either set/allocated, or NULL
1935 deviceInfo->remote_name = NULL;
1936 deviceInfo->remote_address = NULL;
1937 deviceInfo->service_uuid = NULL;
1938 deviceInfo->service_count = 0;
1940 if(!deviceInfo || !address)
1947 GVariant *reply = NULL;
1948 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1951 BLUEZ_ADAPTER_IFACE,
1953 g_variant_new("(s)", address),
1955 G_DBUS_CALL_FLAGS_NONE,
1961 LoggerE("Failed to find " << address << " device: " << (err?err->message:"Invalid reply"));
1967 bool success = false;
1968 const char *device = NULL;
1969 g_variant_get(reply, "(o)", &device);
1971 success = getDeviceInfo(deviceInfo, device);
1974 g_variant_unref(reply);
1979 // don't forget to free memory of remote_name and remote_address
1980 bool BluetoothAdapter::getDeviceInfo(bt_device_info_s *deviceInfo, const char *device) {
1982 // to assure that when leaving the method, these fields
1983 // will be either set/allocated, or NULL
1984 deviceInfo->remote_name = NULL;
1985 deviceInfo->remote_address = NULL;
1986 deviceInfo->service_uuid = NULL;
1987 deviceInfo->service_count = 0;
1989 if(!deviceInfo || !device)
1993 GVariant *reply = NULL;
1994 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2001 G_DBUS_CALL_FLAGS_NONE,
2006 LoggerE("Failed to 'GetProperties': " << err->message);
2013 g_variant_get(reply, "(a{sv})", &iter);
2016 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
2017 //LoggerD("KEY: " << key);
2018 if(!strcmp(key, "Name")) {
2019 const char *name = g_variant_get_string(value, NULL);
2020 deviceInfo->remote_name = strdup(name);
2022 else if(!strcmp(key, "Address")) {
2023 const char *address = g_variant_get_string(value, NULL);
2024 deviceInfo->remote_address = strdup(address);
2026 else if(!strcmp(key, "Paired")) {
2027 deviceInfo->is_bonded = g_variant_get_boolean(value);
2029 else if(!strcmp(key, "Connected")) {
2030 deviceInfo->is_connected = g_variant_get_boolean(value);
2032 else if(!strcmp(key, "Trusted")) {
2033 deviceInfo->is_authorized = g_variant_get_boolean(value);
2035 else if(!strcmp(key, "Class")) {
2036 guint32 _class = g_variant_get_uint32(value);
2037 uint8_t minor = _class & 0xff;
2038 uint8_t major = (_class >> 8) & 0xff;
2039 deviceInfo->bt_class.minor_device_class = (bt_minor_device_class_e) minor;
2040 deviceInfo->bt_class.major_device_class = (bt_major_device_class_e) major;
2041 //deviceInfo->bt_class.major_service_class_mask =
2043 else if(!strcmp(key, "UUIDs")) {
2045 const char *uuid = NULL;
2046 g_variant_get(value, "as", &iter);
2047 deviceInfo->service_count = g_variant_iter_n_children(iter);
2048 deviceInfo->service_uuid = (char**)malloc(deviceInfo->service_count*sizeof(char*));
2049 char **uuids = deviceInfo->service_uuid; // make a copy of ptr, since we will modify the pointer
2050 while(g_variant_iter_next(iter, "s", &uuid)) {
2051 *uuids++ = uuid?strdup(uuid):NULL;
2056 g_variant_unref(reply);
2061 // frees allocated memory by its members
2062 // Doesn't free/delete deviceInfo itself
2063 void BluetoothAdapter::freeDeviceInfo(bt_device_info_s *deviceInfo) {
2067 free(deviceInfo->remote_address);
2068 free(deviceInfo->remote_name);
2069 for(int i=0; i<deviceInfo->service_count; i++) {
2070 free(deviceInfo->service_uuid[i]);
2072 free(deviceInfo->service_uuid);
2075 // frees allocated memory by its members
2076 // Doesn't free/delete discoveryInfo itself
2077 void BluetoothAdapter::freeDiscoveryInfo(bt_adapter_device_discovery_info_s *discoveryInfo) {
2081 free(discoveryInfo->remote_address);
2082 free(discoveryInfo->remote_name);
2083 for(int i=0; i<discoveryInfo->service_count; i++) {
2084 free(discoveryInfo->service_uuid[i]);
2086 free(discoveryInfo->service_uuid);
2089 bool BluetoothAdapter::removeDevice(const char *address) {
2097 GVariant *reply = NULL;
2098 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2101 BLUEZ_ADAPTER_IFACE,
2103 g_variant_new("(s)", address),
2105 G_DBUS_CALL_FLAGS_NONE,
2110 LoggerE("Failed to find " << address << " device: " << err->message);
2117 const char *device = NULL;
2118 g_variant_get(reply, "(o)", &device);
2120 // now we can remove the device
2121 bool success = true;
2123 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2126 BLUEZ_ADAPTER_IFACE,
2128 g_variant_new("(o)", device), // floating variants are consumed
2130 G_DBUS_CALL_FLAGS_NONE,
2135 LoggerE("Failed to 'RemoveDevice': " << err->message);
2141 g_variant_unref(reply);
2147 char *BluetoothAdapter::getBluetoothTechnology() {
2149 GVariant *reply = NULL;
2150 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2153 CONNMAN_MANAGER_IFACE,
2157 G_DBUS_CALL_FLAGS_NONE,
2163 LoggerE("Failed to call 'GetTechnologies' DBUS method: " << (err?err->message:"reply is null"));
2169 char *technology = NULL, *result = NULL;
2170 GVariantIter *props = NULL;
2171 GVariantIter *technologies = NULL;
2172 g_variant_get(reply, "(a(oa{sv}))", &technologies);
2173 while(g_variant_iter_next(technologies, "(oa{sv})", &technology, &props)) {
2174 if(technology && strstr(technology, "bluetooth")) {
2175 result = strdup(technology);
2177 // get the current Powered state
2180 while(g_variant_iter_next(props, "{sv}", &key, &value)) {
2181 if(!strcmp(key, "Powered")) {
2182 bool powered = g_variant_get_boolean(value);
2184 LoggerD("Bluetooth is initially Powered " << (powered?"ON":"OFF"));
2193 g_variant_unref(reply);
2197 bool BluetoothAdapter::setBluetoothPowered(bool value) {
2198 if(mBluetoothTechnology) {
2200 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2202 mBluetoothTechnology,
2203 CONNMAN_TECHNOLOGY_IFACE,
2205 g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
2207 g_variant_new_boolean(value)
2210 G_DBUS_CALL_FLAGS_NONE,
2216 if((value && strstr(err->message, "Already enabled")) || // it's not an error, 'casue the BT is already Powered ON
2217 (!value && strstr(err->message, "Already disabled"))) // it's not an error, 'cause the BT is already Powered OFF
2222 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);