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_ADAPTER_IFACE BLUEZ_PREFIX ".Adapter1"
38 #define BLUEZ_DEVICE_IFACE BLUEZ_PREFIX ".Device1"
39 #define BLUEZ_AGENT_IFACE BLUEZ_PREFIX ".Agent1"
40 #define BLUEZ_OBJECT_IFACE "org.freedesktop.DBus.ObjectManager"
42 #define AGENT_PATH "/org/bluez/agent_pairing"
43 #define AGENT_CAPABILITIES "KeyboardDisplay"
45 #define PINCODE "123456"
46 #define PASSKEY 123456
48 #define CONNMAN_PREFIX "net.connman"
49 #define CONNMAN_SERVICE CONNMAN_PREFIX
50 #define CONNMAN_MANAGER_IFACE CONNMAN_PREFIX ".Manager"
51 #define CONNMAN_TECHNOLOGY_IFACE CONNMAN_PREFIX ".Technology"
54 using namespace DeviceAPI::Common;
61 bool BluetoothAdapter::foreachBondedDevicesCB(bt_device_info_s *deviceInfo, void *userData, char *devicePath)
63 BluetoothAdapterPtr adapter = static_cast<BluetoothAdapterPtr>(userData);
66 LoggerW("userData is NULL");
70 if(deviceInfo == NULL)
72 LoggerW("deviceInfo is NULL");
76 std::vector<BluetoothDeviceSharedPtr>::iterator iter;
77 for(iter = adapter->knownDevices.begin(); iter != adapter->knownDevices.end(); ++iter)
79 BluetoothDeviceSharedPtr foundDevice = *iter;
81 if(!strcmp(foundDevice->getAddress().c_str(), deviceInfo->remote_address))
83 foundDevice->updateInfo(deviceInfo);
88 if(iter == adapter->knownDevices.end())
90 BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo, devicePath));
91 adapter->knownDevices.push_back(device);
97 void BluetoothAdapter::onSocketConnected(int result, bt_socket_connection_state_e state, bt_socket_connection_s *connection, void *userData)
99 BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
102 LoggerW("userData is NULL");
108 LoggerW("connection is NULL");
112 if(connection->local_role == BT_SOCKET_SERVER)
114 RegisteredUUIDMapT::iterator iter = object->mRegisteredUUID.find(connection->service_uuid);
116 if(iter == object->mRegisteredUUID.end())
118 LoggerW("Connection state is changed unexpectedly");
122 if(state == BT_SOCKET_CONNECTED) // connected when Server
124 if(result == BT_ERROR_NONE)
126 // Update BluetoothServiceHandler
127 BluetoothServiceHandlerPtr service = iter->second;
128 service->setConnectionState(true);
130 // Call BluetoothServiceHandler.onconnect
131 BluetoothSocketPtr socket = new BluetoothSocket(connection);
132 MultiCallbackUserDataPtr callback = service->getOnConnect();
133 JSContextRef context = callback->getContext();
134 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
136 callback->invokeCallback("onconnect", socketObj);
138 // Update mConnectedSocket
139 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
140 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
144 LoggerW("Establishing a connection failed");
148 else // disconnected when Server
150 if(result == BT_ERROR_NONE)
152 // Update BluetoothServiceHandler
153 BluetoothServiceHandlerPtr service = iter->second;
154 service->setConnectionState(false);
156 // call BluetoothSocket.onclose;
157 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
158 if(i == object->mConnectedSocket.end())
160 LoggerW("Unknown connected socket");
163 //BluetoothSocketSharedPtr socket = i->second;
164 BluetoothSocketPtr socket = i->second;
165 socket->setConnectionState(false);
166 MultiCallbackUserDataPtr callback = socket->getOnClose();
168 callback->invokeCallback("onclose");
170 // Update mConnectedSocket
171 object->mConnectedSocket.erase(i);
175 LoggerW("Disconnecting a connection failed");
179 else if(connection->local_role == BT_SOCKET_CLIENT)
182 if(state == BT_SOCKET_CONNECTED) // connected when Client
184 std::string remoteAddress(connection->remote_address);
185 ConnReqMultiMapT::iterator iter;
188 iter = object->mConnReqMap.find(remoteAddress);
189 if(iter != object->mConnReqMap.end() && !strcmp(iter->second->mUUID.c_str(), connection->service_uuid))
194 while(iter != object->mConnReqMap.end());
196 if(iter == object->mConnReqMap.end())
198 LoggerW("Connection state is changed unexpectedly");
202 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(iter->second->mUserData);
204 if(result == BT_ERROR_NONE)
206 // Update mConnectedSocket
207 BluetoothSocketPtr socket = new BluetoothSocket(connection);
208 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
209 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
211 // Call successcallback of connectToServiceByUUID
212 JSContextRef context = callback->getContext();
213 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
215 callback->invokeCallback("success", socketObj);
217 // Update mConnReqMap
218 object->mConnReqMap.erase(iter);
222 // Call errorcallback of connectToServiceByUUID
223 JSContextRef context = callback->getContext();
224 NotFoundException error("Not found");
226 callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
228 // Update mConnReqMap
229 object->mConnReqMap.erase(iter);
233 else // disconnected when Client
235 if(result == BT_ERROR_NONE)
237 // call BluetoothSocket.onclose;
238 ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(connection->socket_fd);
239 if(i == object->mConnectedSocket.end())
241 LoggerW("Unknown connected socket");
245 BluetoothSocketPtr socket = i->second;
246 socket->setConnectionState(false);
247 MultiCallbackUserDataPtr callback = socket->getOnClose();
249 callback->invokeCallback("onclose");
251 // Update mConnectedSocket
252 object->mConnectedSocket.erase(i);
256 LoggerW("Disconnecting a connection failed");
262 LoggerW("Unknown role");
266 if(object->mConnectedSocket.size() == 0)
268 bt_socket_unset_data_received_cb();
271 if(object->mRegisteredUUID.size() == 0 && object->mConnReqMap.size() == 0 && object->mConnectedSocket.size() == 0)
273 bt_socket_unset_connection_state_changed_cb();
277 void BluetoothAdapter::onSocketReceivedCB(bt_socket_received_data_s *data, void *userData)
279 BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
283 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())
296 LoggerW("Unknown connected socket");
300 // Store received data
301 BluetoothSocketPtr socket = i->second;
302 socket->storeRecivedData(data->data, static_cast<unsigned long>(data->data_size));
304 // Call BluetoothSocket.onmessage
305 MultiCallbackUserDataPtr callback = socket->getOnMessage();
307 callback->invokeCallback("onmessage");
310 BluetoothAdapter::BluetoothAdapter():
312 mAgentRegistrationId(-1),
313 mAgentIntrospectionData(NULL),
314 mBluetoothTechnology(NULL),
318 mBluetoothTechnology = getBluetoothTechnology();
319 if(!mBluetoothTechnology)
321 LoggerE("Failed to get BT technology");
324 mAdapterPath = getDefaultAdapter();
327 LoggerE("Unable to get default adapter");
331 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
332 "/", "InterfacesAdded", BluetoothAdapter::handleSignal,
334 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
335 "/", "InterfacesRemoved", BluetoothAdapter::handleSignal,
337 memset(&mAgentIfaceVTable, 0, sizeof(mAgentIfaceVTable));
339 if(isAdapterPowered())
341 LoggerD("Adapter is powered");
346 LoggerD("Adapter is not powered");
351 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.ObjectManager",
352 mAdapterPath, "InterfacesAdded", BluetoothAdapter::handleSignal,
357 BluetoothAdapter::~BluetoothAdapter()
359 // unset platform callback
360 bt_socket_unset_connection_state_changed_cb();
361 bt_socket_unset_data_received_cb();
363 for(int i = 0; i <= DESTROY_BONDING; i++)
365 mUserDataList[i].reset();
367 mRegisteredUUID.clear();
369 mFoundDevices.clear();
370 mConnectedSocket.clear();
373 void BluetoothAdapter::unloadFrame(JSContextRef context)
375 LoggerD("Clean mUserDataList");
376 for(int i = 0; i <= DESTROY_BONDING; i++)
380 MultiCallbackUserDataPtr callback = mUserDataList[i];
381 if(!GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext()))
383 mUserDataList[i].reset();
388 LoggerD("Clean mConnReqMap");
389 for(ConnReqMultiMapT::iterator iter = mConnReqMap.begin(); iter != mConnReqMap.end(); )
391 ConnReqMultiMapT::iterator temp = iter++;
392 MultiCallbackUserDataPtr callback = temp->second->mUserData;
393 if(!callback && !GlobalContextManager::getInstance()->isAliveGlobalContext(callback->getContext()))
395 mConnReqMap.erase(temp);
400 void BluetoothAdapter::unregisterUUID(std::string &uuid)
402 mRegisteredUUID.erase(mRegisteredUUID.find(uuid));
403 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
405 bt_socket_unset_connection_state_changed_cb();
409 bool BluetoothAdapter::closeConnectedSocket(int socket)
413 ConnectedSocketMapT::iterator iter = mConnectedSocket.find(socket);
414 if(iter == mConnectedSocket.end())
416 LoggerW("Already disconnected");
420 mConnectedSocket.erase(iter);
421 if(mConnectedSocket.size() == 0)
423 bt_socket_unset_data_received_cb();
426 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
428 bt_socket_unset_connection_state_changed_cb();
435 LoggerE("Bluetooth is not powered");
440 void BluetoothAdapter::removeConnReq(std::string &remoteAddress)
442 mConnReqMap.erase(remoteAddress);
444 if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0)
446 if(bt_socket_unset_connection_state_changed_cb() != BT_ERROR_NONE)
448 LoggerW("Unsetting connection event callback failed");
453 BluetoothAdapter* BluetoothAdapter::getInstance()
455 static BluetoothAdapter instance;
459 bool BluetoothAdapter::isBluetoothSupported()
461 bool isSupported = true;
463 /* if(system_info_get_value_bool(SYSTEM_INFO_KEY_BLUETOOTH_SUPPORTED, &isSupported) != SYSTEM_INFO_ERROR_NONE) {
464 LoggerE("Can't know whether Bluetooth is supported or not");
470 bool BluetoothAdapter::isValidAddress(std::string &address)
472 pcrecpp::RE re("(([0-9a-zA-Z]+):)+([0-9a-zA-Z]+)");
473 std::string compareAddress = "00:12:47:08:9A:A6";
475 if (!re.FullMatch(address))
477 LoggerE("Invalid address");
481 if (address.size() != compareAddress.size())
483 LoggerE("Invalid size");
490 bool BluetoothAdapter::isValidUUID(std::string &uuid)
492 pcrecpp::RE re("(([0-9a-zA-Z]+)-)+([0-9a-zA-Z]+)");
493 std::string compareUUID = "00001101-0000-1000-8000-00805F9B34FB";
495 if (!re.FullMatch(uuid))
497 LoggerE("Invalid UUID");
501 if (uuid.size() != compareUUID.size())
503 LoggerE("Invalid size");
510 std::string BluetoothAdapter::getName() const
512 const char* name = NULL;
513 std::string str = "";
517 LoggerD("No BT adapter");
521 // get adapter properties and check Name property
523 GVariant *reply = NULL;
524 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
527 "org.freedesktop.DBus.Properties",
529 g_variant_new("(ss)", "org.bluez.Adapter1", "Name"),
531 G_DBUS_CALL_FLAGS_NONE,
539 LoggerE("Failed to get 'Name' property");
544 g_variant_get(reply, "(v)", &value);
545 name = g_variant_get_string(value, NULL);
548 g_variant_unref(reply);
553 void BluetoothAdapter::setName(std::string &name, MultiCallbackUserDataPtr userData)
557 std::string adapterName = getName();
558 if(adapterName == name) // in case of same name
560 LoggerD("same name");
561 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
569 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
572 "org.freedesktop.DBus.Properties",
574 g_variant_new("(ssv)", "org.bluez.Adapter1", "Name", g_variant_new_string(name.c_str())),
576 G_DBUS_CALL_FLAGS_NONE,
583 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
584 UnknownException *error = new UnknownException(err->message);
585 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
591 userData->invokeCallback("success");
595 LoggerE("No BT adapter");
596 UnknownException *error = new UnknownException("No BT adapter");
597 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
603 std::string BluetoothAdapter::getAddress() const
605 const char* address = NULL;
606 std::string str = "";
610 LoggerD("No BT adapter");
614 // get adapter properties and check Address property
616 GVariant *reply = NULL;
617 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
620 "org.freedesktop.DBus.Properties",
622 g_variant_new("(ss)", "org.bluez.Adapter1", "Address"),
624 G_DBUS_CALL_FLAGS_NONE,
632 LoggerE("Failed to get 'Address' property");
636 //GVariantIter *iter;
638 g_variant_get(reply, "(v)", &value);
639 address = g_variant_get_string(value, NULL);
643 while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
644 if(!strcmp(key, "Address")) {
645 address = g_variant_get_string(value, NULL);
652 g_variant_unref(reply);
657 bool BluetoothAdapter::getPowered() const
662 void BluetoothAdapter::setPowered(bool powered, MultiCallbackUserDataPtr userData)
664 bool btTechnologyPowered = isBtTechnologyPowered();
665 if(!powered) // Powering OFF BT. It is enough to take down BT technology - it will take down Adapter as well
667 if(!btTechnologyPowered) // already powered OFF
669 LoggerE("BT already powered OFF ... calling success callback.");
670 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
675 if(setBluetoothPowered(powered)) // BT powered OFF successfuly
677 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
681 LoggerE("Failed to Power OFF BT technology - trying to Power OFF the Adapter directly");
682 if(setAdapterPowered(powered))
684 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
688 LoggerE("Failed to Power OFF both, BT and adapter as well ... calling error callback");
689 UnknownException *error = new UnknownException("Failed to Power OFF BT/Adapter");
690 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
695 else // Powering ON BT
697 if(btTechnologyPowered) // already Powered ON
699 if(mEnabled) // already Powered On
701 LoggerD("BT/Adapter already powered ON ... calling success callback.");
702 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
704 else // BT powered, but Adapter is not - try to power it ON
706 LoggerE("BT technology is Powered ON, but adapter is not, trying to Power it ON");
707 if(setAdapterPowered(powered)) // successfuly powered ON ... calling success callback
709 LoggerE("successfull power on.... sending syncToAsyncSuccess");
710 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
714 LoggerE("Failed to Power ON BT adapter ... calling error callback");
715 UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
716 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
722 if(!setBluetoothPowered(powered))
724 LoggerE("Failed to Power ON BT technology ... calling error callback");
725 UnknownException *error = new UnknownException("Failed to Power ON BT technology");
726 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
729 else { // BT technology powered ON (it should power ON adapter as well, but just in case, call Power ON on adapter as well)
730 if(setAdapterPowered(powered)) {
731 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
734 LoggerE("Failed to Power ON BT adapter ... calling error callback");
735 UnknownException *error = new UnknownException("Failed to Power ON BT adapter");
736 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
742 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
747 mUserDataList[SET_POWERED].reset();
750 bool BluetoothAdapter::getVisible() const
754 LoggerD("No BT adapter");
758 // get adapter properties and check Discoverable property
760 GVariant *reply = NULL;
761 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
764 "org.freedesktop.DBus.Properties",
766 g_variant_new("(ss)", "org.bluez.Adapter1", "Discoverable"),
768 G_DBUS_CALL_FLAGS_NONE,
776 LoggerE("Failed to get 'Discoverable' property");
780 bool visible = false;
782 g_variant_get(reply, "(v)", &value);
783 visible = g_variant_get_boolean(value);
785 g_variant_unref(reply);
790 void BluetoothAdapter::setVisible(bool visible, unsigned int timeout, MultiCallbackUserDataPtr userData)
792 UnknownException *error = new UnknownException("NOT IMPLEMENTED");
793 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
795 if(mEnabled == true) {
796 bt_adapter_visibility_mode_e discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
797 if(visible == true) {
799 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
801 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
804 bt_adapter_visibility_mode_e current = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
806 if(bt_adapter_get_visibility(¤t , &time) != BT_ERROR_NONE) {
807 LoggerE("bt_adapter_get_visibility() failed");
808 UnknownException *error = new UnknownException("Can't get current visibility");
809 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
813 if(discoverable_mode == current) {
814 if(discoverable_mode != BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE) {
815 LoggerD("same visibility");
816 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
819 else if((unsigned int)time == timeout) {
820 LoggerD("same visibility");
821 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
826 if(mUserDataList[SET_VISIBLE] == NULL) {
827 bt_adapter_set_visibility_mode_changed_cb(onVisibilityChangedCB, this);
828 mUserDataList[SET_VISIBLE] = userData;
830 UnknownException *error = new UnknownException("Already requested");
831 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
835 mRequestedVisibility = discoverable_mode;
836 int ret = bt_adapter_set_visibility(discoverable_mode, timeout);
840 LoggerD("bt_adapter_set_visibility() succeeded");
843 case BT_ERROR_INVALID_PARAMETER:
845 InvalidValuesException *error = new InvalidValuesException("Invalid value");
846 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
851 UnknownException *error = new UnknownException("Unknown error");
852 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
856 bt_adapter_unset_visibility_mode_changed_cb();
857 mUserDataList[SET_VISIBLE].reset();
858 } else { // Not enabled
859 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
860 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
865 void BluetoothAdapter::setChangeListener(MultiCallbackUserDataPtr userData)
867 if(mChangeListener == NULL)
868 mChangeListener = userData;
871 void BluetoothAdapter::unsetChangeListener()
873 if(mChangeListener != NULL)
874 mChangeListener.reset();
878 void BluetoothAdapter::discoverDevices(MultiCallbackUserDataPtr userData)
882 LoggerE("No BT adapter");
883 UnknownException *error = new UnknownException("No BT adapter");
884 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
888 if(mUserDataList[DISCOVER_DEVICES] == NULL)
890 mUserDataList[DISCOVER_DEVICES] = userData;
894 LoggerE("Already requested");
895 UnknownException *error = new UnknownException("Already requested");
896 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
903 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
910 G_DBUS_CALL_FLAGS_NONE,
916 LoggerE("Failed to 'StartDiscovery' on adapter " << mAdapterPath << " : " << err->message);
917 UnknownException *error = new UnknownException(err->message);
918 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
920 mUserDataList[DISCOVER_DEVICES].reset();
924 LoggerD("Call to 'StartDiscovery' succeeded");
926 // store MAC address of previously found device into mDisappearedDevices
927 mDisappearedDevices.clear();
928 for(auto iter = mFoundDevices.begin();
929 iter != mFoundDevices.end(); iter++)
931 BluetoothDeviceSharedPtr foundDevice = *iter;
932 mDisappearedDevices.push_back(foundDevice->getAddress());
935 mFoundDevices.clear();
937 // 'onstarted' callback is called after receiving 'Discovering' property changed to 'true' ... see handleSignal() method
939 // userData->invokeCallback("onstarted");
941 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.Properties",
942 mAdapterPath, "PropertiesChanged", BluetoothAdapter::handleSignal,
950 LoggerE("Bluetooth device is turned off");
951 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
952 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
955 mUserDataList[DISCOVER_DEVICES].reset();
958 void BluetoothAdapter::stopDiscovery(MultiCallbackUserDataPtr userData)
960 if(mUserDataList[DISCOVER_DEVICES] == NULL) // not doing discovery
962 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
968 LoggerE("No BT adapter");
969 UnknownException *error = new UnknownException("No BT adapter");
970 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
972 else if(mEnabled == true)
975 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
982 G_DBUS_CALL_FLAGS_NONE,
988 LoggerE("Failed to 'StopDiscovery': " << err->message);
989 UnknownException *error = new UnknownException(err->message);
990 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
995 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
1001 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
1002 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1005 mUserDataList[DISCOVER_DEVICES].reset();
1008 void BluetoothAdapter::getKnownDevices(MultiCallbackUserDataPtr userData)
1010 BluetoothCallbackUtil::syncToAsyncDeviceArrayCallback(userData);
1013 void BluetoothAdapter::getDevice(std::string &address, MultiCallbackUserDataPtr userData)
1015 BluetoothCallbackUtil::syncToAsyncDeviceCallback(userData, address);
1018 void BluetoothAdapter::createBonding(std::string &address, MultiCallbackUserDataPtr userData)
1020 if(!isValidAddress(address))
1022 LoggerE("Wrong address");
1023 NotFoundException *error = new NotFoundException("Wrong address");
1024 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1030 LoggerE("No BT adapter");
1031 NotFoundException *error = new NotFoundException("No BT adapter");
1032 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1036 if(mUserDataList[CREATE_BONDING] == NULL)
1038 mCreateBondingAddress = address;
1039 mUserDataList[CREATE_BONDING] = userData;
1043 LoggerE("Already requested");
1044 UnknownException *error = new UnknownException("Already requested");
1045 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1049 char* devicePath = NULL;
1051 for (int i = 0; i < mFoundDevices.size(); i++)
1053 if (mFoundDevices[i]->getAddress() == address)
1055 LoggerE("checking mFoundDevices -> " << mFoundDevices[i]->getAddress());
1056 devicePath = mFoundDevices[i]->getDevicePath();
1062 devicePath = getDeviceFromAddress(address);
1064 if(mEnabled == true)
1066 // if(setupAgent(AGENT_PATH)) {
1069 LoggerE("devicePath was null, setting to empty string");
1073 if (devicePath != NULL)
1076 // CreatePairedDevice has to be ASYNC DBUS call
1077 g_dbus_connection_call( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1084 G_DBUS_CALL_FLAGS_NONE,
1087 BluetoothAdapter::asyncCreatePairedDeviceCallback,
1092 LoggerE("No bluetooth device path found!");
1097 LoggerE("Failed to set-up Bluez Agent for pairing");
1098 ServiceNotAvailableException *error = new ServiceNotAvailableException("Failed to set-up Bluez Agent for pairing");
1099 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1107 LoggerE("BLUEZ Bluetooth device is turned off");
1108 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
1109 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1111 LoggerD("done with createPairedDevice");
1114 void BluetoothAdapter::destroyBonding(std::string &address, MultiCallbackUserDataPtr userData)
1116 if(!isValidAddress(address))
1118 LoggerE("Wrong address");
1119 NotFoundException *error = new NotFoundException("Wrong address");
1120 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1124 // get device info before removing, 'cause after removing you loose access to it ('FindDevice' will not find it)
1125 bt_device_info_s deviceInfo;
1126 bool hasDeviceInfo = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1128 if(!removeDevice(address.c_str()))
1132 JSContextRef context = userData->getContext();
1133 UnknownException error("Failed to remove device");
1134 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1144 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1145 JSContextRef context = userData->getContext();
1146 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1147 userData->invokeCallback("success", deviceObj);
1151 JSContextRef context = userData->getContext();
1152 UnknownException error("Failed to get device info");
1153 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1155 freeDeviceInfo(&deviceInfo);
1159 void BluetoothAdapter::registerRFCOMMServiceByUUID(std::string &uuid, std::string &name, MultiCallbackUserDataPtr userData)
1161 BluetoothCallbackUtil::syncToAsyncServiceCallback(userData, uuid, name);
1164 void BluetoothAdapter::connectToServiceByUUID(std::string &remoteAddress, std::string &uuid, Common::MultiCallbackUserDataPtr userData)
1166 if(!isValidUUID(uuid))
1168 LoggerE("Wrong UUID");
1169 InvalidValuesException *error = new InvalidValuesException("Wrong UUID");
1170 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1175 if(mEnabled == true)
1177 int ret = bt_socket_connect_rfcomm(remoteAddress.c_str(), uuid.c_str());
1183 LoggerD("bt_socket_connect_rfcomm() succeeded");
1184 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1186 BluetoothConnReqPtr connReq = new BluetoothConnReq(uuid, userData);
1187 mConnReqMap.insert(std::pair<std::string, BluetoothConnReqPtr>(remoteAddress, connReq));
1190 case BT_ERROR_INVALID_PARAMETER:
1191 case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
1193 InvalidValuesException *error = new InvalidValuesException("Invalid value");
1194 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1199 UnknownException *error = new UnknownException("Unknown error");
1200 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1206 ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off");
1207 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1211 void BluetoothAdapter::returnKnownDevices(Common::MultiCallbackUserDataPtr userData)
1216 GError * error = nullptr;
1217 GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1220 "org.freedesktop.DBus.ObjectManager",
1224 LoggerE("could not create ObjManager proxy");
1225 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1226 g_error_free(error);
1229 GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1233 LoggerE("failed to get GetManagedObj");
1234 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1235 g_object_unref(managerProxy);
1236 g_error_free(error);
1241 GVariantIter* level2Dict;
1243 g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1245 while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1247 char * interfaceName;
1248 GVariantIter* innerDict;
1250 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1252 if(!strcmp(interfaceName, "org.bluez.Device1"))
1257 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1260 if(!strcmp(propertyName, "Paired"))
1262 bool paired = false;
1264 g_variant_get(value,"b",&paired);
1268 bt_device_info_s deviceInfo;
1270 if(getDeviceInfo(&deviceInfo, objPath))
1271 foreachBondedDevicesCB(&deviceInfo, this, objPath);
1273 freeDeviceInfo(&deviceInfo);
1276 g_free(propertyName);
1277 g_variant_unref(value);
1280 g_free(interfaceName);
1281 g_variant_iter_free(innerDict);
1284 g_variant_iter_free(level2Dict);
1286 g_variant_iter_free(iter);
1290 void BluetoothAdapter::returnDevice(std::string &address, Common::MultiCallbackUserDataPtr userData)
1292 if(!isValidAddress(address))
1294 LoggerE("Wrong address");
1295 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("Wrong address")));
1299 if(mEnabled == true)
1301 bt_device_info_s deviceInfo;
1302 bool success = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1306 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1307 LoggerD("invoke successCallback");
1308 userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), device));
1313 JSContextRef context = userData->getContext();
1314 UnknownException error("Failed to get device info");
1315 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1317 freeDeviceInfo(&deviceInfo);
1319 std::vector<BluetoothDeviceSharedPtr>::iterator iter;
1320 for(iter = mFoundDevices.begin(); iter != mFoundDevices.end(); ++iter)
1322 BluetoothDeviceSharedPtr foundDevice = *iter;
1323 if(!strcmp(foundDevice->getAddress().c_str(), address.c_str()))
1325 LoggerD("Found in mFoundDevices");
1326 userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), foundDevice));
1331 if(iter == mFoundDevices.end())
1333 LoggerE("Can't find this device");
1335 userData->invokeCallback(
1337 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("There is no device with the given address"))
1343 LoggerE("Bluetooth device is turned off");
1344 userData->invokeCallback(
1346 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1351 void BluetoothAdapter::returnRegisteredService(std::string &uuid, std::string &name, Common::MultiCallbackUserDataPtr userData)
1353 if(!isValidUUID(uuid))
1355 LoggerE("Wrong UUID");
1356 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Wrong UUID")));
1360 if(mEnabled == true)
1364 if(bt_adapter_is_service_used(uuid.c_str(), &isRegistered) == BT_ERROR_NONE && isRegistered == true)
1366 LoggerD("Already registered");
1367 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Already registered")));
1372 int ret = bt_socket_create_rfcomm(uuid.c_str(), &socket);
1378 LoggerD("bt_socket_create_rfcomm() succeeded");
1379 int ret = bt_socket_listen_and_accept_rfcomm(socket, 0);
1384 LoggerD("bt_socket_listen() succeeded");
1385 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1387 BluetoothServiceHandlerPtr serviceHandler = new BluetoothServiceHandler(uuid, name, socket);
1388 mRegisteredUUID.insert(std::pair<std::string, BluetoothServiceHandlerPtr>(uuid, serviceHandler));
1390 JSObjectRef serviceObj = JSBluetoothServiceHandler::createJSObject(userData->getContext(), serviceHandler);
1391 userData->invokeCallback("success", serviceObj);
1394 case BT_ERROR_INVALID_PARAMETER:
1396 LoggerD("Invalid value");
1397 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1402 LoggerD("Unknown exception");
1403 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1409 case BT_ERROR_INVALID_PARAMETER:
1411 LoggerD("Invalid value");
1412 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1417 LoggerD("Unknown exception");
1418 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1424 LoggerE("Bluetooth device is turned off");
1425 userData->invokeCallback(
1427 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1432 bool BluetoothAdapter::isBtTechnologyPowered()
1435 if(!mBluetoothTechnology)
1437 LoggerE("Invalid BT technology to get 'Powered' state.");
1442 GVariant *reply = NULL;
1443 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1445 mBluetoothTechnology,
1446 CONNMAN_TECHNOLOGY_IFACE,
1450 G_DBUS_CALL_FLAGS_NONE,
1462 g_variant_get(reply, "(a{sv})", &iter);
1465 bool powered = false;
1466 while(g_variant_iter_next(iter, "{sv}", &key, &value))
1468 if(!strcmp(key, "Powered"))
1470 powered = g_variant_get_boolean(value);
1475 g_variant_unref(reply);
1482 gchar* BluetoothAdapter::getDefaultAdapter() const
1487 GError * error = nullptr;
1488 GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1491 "org.freedesktop.DBus.ObjectManager",
1495 LoggerE("could not create ObjManager proxy");
1496 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1497 g_error_free(error);
1501 GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1505 LoggerE("failed to get GetManagedObj");
1506 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1507 g_object_unref(managerProxy);
1508 g_error_free(error);
1514 GVariantIter* level2Dict;
1516 g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1518 while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1520 char * interfaceName;
1521 GVariantIter* innerDict;
1522 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1524 if(!strcmp(interfaceName, "org.bluez.Adapter1"))
1529 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1531 if(!strcmp(propertyName, "Address"))
1534 g_variant_get(value,"s",&addr);
1536 result = objPath?strdup(objPath):NULL;
1541 g_free(propertyName);
1542 g_variant_unref(value);
1545 g_free(interfaceName);
1546 g_variant_iter_free(innerDict);
1549 g_variant_iter_free(level2Dict);
1551 g_variant_iter_free(iter);
1556 gchar* BluetoothAdapter::getDeviceFromAddress(std::string &address) const
1558 char *result = NULL;
1561 GError * error = nullptr;
1562 GDBusProxy * managerProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL,
1565 "org.freedesktop.DBus.ObjectManager",
1569 LoggerE("could not create ObjManager proxy");
1570 // DebugOut(DebugOut::Error)<<"Could not create ObjectManager proxy for Bluez: "<<error->message<<endl;
1571 g_error_free(error);
1575 GVariant * objectMap = g_dbus_proxy_call_sync(managerProxy, "GetManagedObjects",nullptr, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
1579 LoggerE("failed to get GetManagedObj");
1580 //DebugOut(DebugOut::Error)<<"Failed call to GetManagedObjects: "<<error->message<<endl;
1581 g_object_unref(managerProxy);
1582 g_error_free(error);
1588 GVariantIter* level2Dict;
1590 g_variant_get(objectMap, "(a{oa{sa{sv}}})",&iter);
1592 while(g_variant_iter_next(iter, "{oa{sa{sv}}}",&objPath, &level2Dict))
1594 char * interfaceName;
1595 GVariantIter* innerDict;
1596 while(g_variant_iter_next(level2Dict, "{sa{sv}}", &interfaceName, &innerDict))
1598 if(!strcmp(interfaceName, "org.bluez.Device1"))
1603 while(done == false && g_variant_iter_next(innerDict,"{sv}", &propertyName, &value))
1605 if(!strcmp(propertyName, "Address"))
1608 g_variant_get(value,"s",&addr);
1609 if(addr && std::string(addr) == address)
1612 result = objPath?strdup(objPath):NULL;
1614 LoggerD("getDeviceFromAddress found : " << result);
1619 g_free(propertyName);
1620 g_variant_unref(value);
1623 g_free(interfaceName);
1624 g_variant_iter_free(innerDict);
1627 g_variant_iter_free(level2Dict);
1629 g_variant_iter_free(iter);
1634 bool BluetoothAdapter::isAdapterPowered()
1640 // get adapter properties and check if it's Powered
1642 GVariant *reply = NULL;
1643 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1646 "org.freedesktop.DBus.Properties",
1648 g_variant_new("(ss)", "org.bluez.Adapter1", "Powered"),
1650 G_DBUS_CALL_FLAGS_NONE,
1662 bool powered = false;
1664 g_variant_get(reply, "(v)", &value);
1665 powered = g_variant_get_boolean(value);
1667 g_variant_unref(reply);
1672 void BluetoothAdapter::handleSignal(GDBusConnection *connection,
1673 const gchar *sender,
1674 const gchar *object_path,
1675 const gchar *interface_name,
1676 const gchar *signal_name,
1677 GVariant *parameters,
1680 LoggerE("signal received: '" << interface_name << "' -> '" << signal_name << "' -> '" << object_path << "'");
1682 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1685 LoggerD("Failed to cast to BluetoothAdapter");
1690 if(!strcmp(interface_name, "org.freedesktop.DBus.ObjectManager"))
1692 if(!strcmp(signal_name, "InterfacesAdded"))
1695 char *objPath = NULL;
1698 g_variant_get(parameters, "(oa{sa{sv}})", &objPath, &iter);
1703 GVariantIter* iter2;
1704 char *interface = NULL;
1706 while(g_variant_iter_next(iter, "{sa{sv}}",&interface, &iter2))
1709 if(!strcmp(interface, "org.bluez.Adapter1"))
1711 gchar * adapterPath = ctx->getDefaultAdapter();
1712 free(ctx->mAdapterPath);
1713 ctx->mAdapterPath = adapterPath;
1717 Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, "org.freedesktop.DBus.Properties",
1718 adapterPath, "PropertiesChanged", BluetoothAdapter::handleSignal,
1723 else if(!strcmp(interface, "org.bluez.Device1"))
1725 bt_adapter_device_discovery_info_s discoveryInfo;
1726 discoveryInfo.remote_name = NULL;
1727 discoveryInfo.remote_address = NULL;
1728 discoveryInfo.service_uuid = NULL;
1729 discoveryInfo.service_count = 0;
1734 while(g_variant_iter_next(iter2, "{sv}", &key, &value))
1736 if(!strcmp(key, "Address"))
1738 const char *address = g_variant_get_string(value, NULL);
1739 discoveryInfo.remote_address = address?strdup(address):NULL;
1742 else if(!strcmp(key, "Name"))
1744 const char *name = g_variant_get_string(value, NULL);
1745 discoveryInfo.remote_name = name?strdup(name):NULL;
1748 else if(!strcmp(key, "Paired"))
1750 discoveryInfo.is_bonded = g_variant_get_boolean(value);
1753 else if(!strcmp(key, "Class"))
1755 guint32 _class = g_variant_get_uint32(value);
1756 uint8_t minor = _class & 0xff;
1757 uint8_t major = (_class >> 8) & 0xff;
1758 discoveryInfo.bt_class.minor_device_class = (bt_minor_device_class_e) minor;
1759 discoveryInfo.bt_class.major_device_class = (bt_major_device_class_e) major;
1760 //discoveryInfo.bt_class.major_service_class_mask =
1763 else if(!strcmp(key, "UUIDs"))
1766 const char *uuid = NULL;
1767 g_variant_get(value, "as", &iter);
1768 discoveryInfo.service_count = g_variant_iter_n_children(iter);
1769 discoveryInfo.service_uuid = (char**)malloc(discoveryInfo.service_count*sizeof(char*));
1770 char **uuids = discoveryInfo.service_uuid; // make a copy of ptr, since we will modify the pointer
1771 while(g_variant_iter_next(iter, "s", &uuid))
1773 *uuids++ = uuid?strdup(uuid):NULL;
1778 if(!discoveryInfo.remote_address)
1780 ctx->freeDiscoveryInfo(&discoveryInfo);
1784 if(!discoveryInfo.remote_name)
1786 LoggerD("discovery info ... remote_name is null for " << discoveryInfo.remote_address);
1787 discoveryInfo.remote_name = strdup("");
1790 LoggerD("Found BT device: " << discoveryInfo.remote_address << " ... " << (discoveryInfo.remote_name?discoveryInfo.remote_name:""));
1792 if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL)
1795 MultiCallbackUserDataPtr callback =
1796 static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1800 if(!ctx->isDeviceInList(ctx->mFoundDevices, discoveryInfo.remote_address))
1802 // create BluetoothDevice
1803 BluetoothDeviceSharedPtr device(new BluetoothDevice(&discoveryInfo, objPath));
1804 JSContextRef context = callback->getContext();
1805 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1806 ctx->mFoundDevices.push_back(device);
1808 // remove MAC address of found device from mDisappearedDevices
1809 for(auto iter = ctx->mDisappearedDevices.begin(); iter != ctx->mDisappearedDevices.end(); iter++)
1811 if(!strcmp(discoveryInfo.remote_address, (*iter).c_str()))
1813 ctx->mDisappearedDevices.erase(iter);
1818 callback->invokeCallback("ondevicefound", deviceObj);
1823 ctx->freeDiscoveryInfo(&discoveryInfo);
1828 else if(!strcmp(signal_name, "AdapterRemoved"))
1830 const char *adapter = NULL;
1831 g_variant_get(parameters, "(o)", &adapter);
1834 LoggerD("Adapter removed: " << adapter);
1838 else if(!strcmp(interface_name, BLUEZ_ADAPTER_IFACE))
1840 if(!strcmp(signal_name, "PropertyChanged"))
1844 g_variant_get(parameters, "(sv)", &name, &var);
1845 LoggerD("\tname=" << name);
1846 if(!strcmp(name, "Name"))
1848 const char *_name = g_variant_get_string(var, NULL);
1849 ctx->onNameChanged(_name);
1851 else if(!strcmp(name, "Powered"))
1853 bool powered = g_variant_get_boolean(var);
1854 ctx->onPoweredChanged(powered);
1856 else if(!strcmp(name, "Discoverable"))
1858 bool visible = g_variant_get_boolean(var);
1859 ctx->onVisibilityChanged(visible);
1861 else if(!strcmp(name, "Discovering"))
1863 bool discovering = g_variant_get_boolean(var);
1864 if(discovering) // discovery started
1866 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1869 callback->invokeCallback("onstarted");
1872 else // discovery completed
1874 LoggerD("Discovery completed");
1875 if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL)
1877 MultiCallbackUserDataPtr callback =
1878 static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1882 if(ctx->mDisappearedDevices.size() > 0)
1884 LoggerD("There are disappeared devices");
1885 for(auto iter = ctx->mDisappearedDevices.begin();
1886 iter != ctx->mDisappearedDevices.end(); iter++)
1889 callback->invokeCallback("ondevicedisappeared",
1890 JSUtil::toJSValueRef(callback->getContext(), *iter));
1894 if(ctx->mFoundDevices.size() > 0) // There are found devices
1896 LoggerD("There are found devices");
1897 int num = ctx->mFoundDevices.size();
1898 JSObjectRef devices[num];
1899 for(int i = 0; i < num; i++)
1901 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(callback->getContext(), ctx->mFoundDevices[i]);
1902 devices[i] = deviceObj;
1905 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1907 callback->invokeCallback(
1909 JSObjectMakeArray(callback->getContext(), num, devices, NULL) );
1911 else // There is no found device
1913 LoggerD("There is no found device");
1914 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1916 callback->invokeCallback(
1918 JSObjectMakeArray(callback->getContext(), 0, NULL, NULL) );
1922 Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE, object_path, "DeviceFound");
1925 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1928 BLUEZ_ADAPTER_IFACE,
1932 G_DBUS_CALL_FLAGS_NONE,
1944 else if(!strcmp(interface_name, CONNMAN_TECHNOLOGY_IFACE)) {
1945 if(!strcmp(signal_name, "PropertyChanged")) {
1948 g_variant_get(parameters, "(sv)", &name, &value);
1949 if(!strcmp(name, "Powered")) {
1950 bool powered = g_variant_get_boolean(value);
1951 ctx->onPoweredChanged(powered);
1958 bool BluetoothAdapter::isDeviceInList(std::vector<BluetoothDeviceSharedPtr> list, const char *address)
1961 bool exists = false;
1962 for(auto iter = list.begin(); iter != list.end(); iter++)
1964 if(!strcmp((*iter)->getAddress().c_str(), address))
1974 bool BluetoothAdapter::setAdapterPowered(bool value)
1980 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1983 "org.freedesktop.DBus.Properties",
1985 g_variant_new("(ssv)", "org.bluez.Adapter1", "Powered", g_variant_new_boolean(value)),
1987 G_DBUS_CALL_FLAGS_NONE,
1994 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
2005 void BluetoothAdapter::onPoweredChanged(bool powered)
2009 if(mChangeListener != NULL)
2011 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2014 JSContextRef context = callback->getContext();
2015 JSValueRef value = JSValueMakeBoolean(context, powered);
2017 callback->invokeCallback("onstatechanged", value);
2021 if(!powered && mUserDataList[DISCOVER_DEVICES] != NULL)
2022 mUserDataList[DISCOVER_DEVICES].reset();
2025 void BluetoothAdapter::onNameChanged(const char *name)
2027 if(mUserDataList[SET_NAME] != NULL) // requested event
2029 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mUserDataList[SET_NAME]);
2030 mUserDataList[SET_NAME].reset();
2032 callback->invokeCallback("success");
2034 else // unexpected event
2036 LoggerW("Bluetooth name is changed unexpectedly");
2039 if(mChangeListener != NULL)
2041 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2044 JSContextRef context = callback->getContext();
2045 JSStringRef nameRef = JSStringCreateWithUTF8CString(name);
2046 JSValueRef value = JSValueMakeString(context, nameRef);
2048 callback->invokeCallback("onnamechanged", value);
2053 void BluetoothAdapter::onVisibilityChanged(bool visible)
2055 if(mChangeListener != NULL)
2057 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
2060 JSContextRef context = callback->getContext();
2061 JSValueRef value = JSValueMakeBoolean(context, visible);
2063 callback->invokeCallback("onvisibilitychanged", value);
2068 void BluetoothAdapter::asyncCreatePairedDeviceCallback(GObject *source, GAsyncResult *result, gpointer user_data)
2071 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
2074 LoggerE("Failed to cast to BluetoothAdapter");
2080 reply = g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
2083 LoggerE("Failed to CreatePairedDevice: " << (err?err->message:"Invalid reply"));
2084 if(ctx->mUserDataList[CREATE_BONDING] != NULL)
2086 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
2089 NotFoundException *error = new NotFoundException("Failed to CreatePairedDevice");
2090 BluetoothCallbackUtil::syncToAsyncErrorCallback(callback, error);
2099 LoggerE("Got reply from CreatePairedDevice");
2100 if(ctx->mUserDataList[CREATE_BONDING] != NULL)
2102 MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
2105 bt_device_info_s deviceInfo;
2106 if(ctx->getDeviceInfoByAddress(&deviceInfo, ctx->mCreateBondingAddress.c_str()))
2108 BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
2109 JSContextRef context = callback->getContext();
2110 JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
2111 callback->invokeCallback("success", deviceObj);
2115 LoggerE("CreatePairedDevice failed to get device info");
2116 JSContextRef context = callback->getContext();
2117 UnknownException error("Failed to get device info");
2118 callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
2120 ctx->freeDeviceInfo(&deviceInfo);
2125 ctx->mCreateBondingAddress.clear();
2126 ctx->mUserDataList[CREATE_BONDING].reset();
2128 g_variant_unref(reply);
2131 bool BluetoothAdapter::setupAgent(const char *agent)
2137 LoggerE("Invalid agent path");
2143 if(mAgentRegistrationId > 0) // already registered
2145 LoggerE("Bluez agent for pairing already registered ... possibly not Released after previous pairing");
2148 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), mAgentRegistrationId);
2150 mAgentRegistrationId = -1;
2153 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2156 "org.bluez.AgentManager1",
2158 g_variant_new("(ss)", agent, ""),
2160 G_DBUS_CALL_FLAGS_NONE,
2167 LoggerE("Failed to register object: " << agent << " : " << err->message);
2174 g_variant_get(reply, "(i)", &value);
2175 mAgentRegistrationId = g_variant_get_int16(value);
2177 LoggerE("object registered with id=" << mAgentRegistrationId);
2182 void BluetoothAdapter::agentHandleMethodCall( GDBusConnection *connection,
2183 const gchar *sender,
2184 const gchar *object_path,
2185 const gchar *interface_name,
2186 const gchar *method_name,
2187 GVariant *parameters,
2188 GDBusMethodInvocation *invocation,
2192 LoggerD("entered\n\tsender=" << sender << "\n\tobject_path=" << object_path << "\n\tinterface_name=" << interface_name << "\n\tmethod_name=" << method_name);
2194 BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
2197 LoggerD("Failed to cast to BluetoothAdapter");
2198 g_dbus_method_invocation_return_value(invocation, NULL);
2202 if(!strcmp(method_name, "Authorize"))
2204 g_dbus_method_invocation_return_value(invocation, NULL);
2206 else if(!strcmp(method_name, "RequestPinCode"))
2208 g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", PINCODE));
2210 else if(!strcmp(method_name, "RequestPasskey"))
2212 g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", PASSKEY));
2214 else if (!strcmp(method_name, "Release"))
2216 if(!strcmp(object_path, AGENT_PATH)) // released agent for pairing
2218 bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), ctx->mAgentRegistrationId);
2220 ctx->mAgentRegistrationId = -1;
2222 g_dbus_method_invocation_return_value(invocation, NULL);
2226 // DisplayPasskey, DisplayPinCode, RequestConfirmation, ConfirmModeChange, Cancel
2227 g_dbus_method_invocation_return_value(invocation, NULL);
2231 bool BluetoothAdapter::isDevicePaired(const char *device)
2237 // get device properties and check if it's Paired
2239 GVariant *reply = NULL;
2240 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2243 "org.freedesktop.DBus.Properties",
2245 g_variant_new("(ss)", "org.bluez.Device1", "Paired"),
2247 G_DBUS_CALL_FLAGS_NONE,
2259 bool paired = false;
2261 g_variant_get(reply, "(v)", &value);
2262 paired = g_variant_get_boolean(value);
2264 g_variant_unref(reply);
2269 bool BluetoothAdapter::getDeviceInfoByAddress(bt_device_info_s *deviceInfo, const char *address)
2272 // to assure that when leaving the method, these fields
2273 // will be either set/allocated, or NULL
2274 deviceInfo->remote_name = NULL;
2275 deviceInfo->remote_address = NULL;
2276 deviceInfo->service_uuid = NULL;
2277 deviceInfo->service_count = 0;
2279 if(!deviceInfo || !address)
2285 std::string addressStr = std::string(address);
2286 char* device = getDeviceFromAddress(addressStr);
2290 LoggerE("Failed to find " << address << " device: trying again");
2294 bool success = false;
2298 success = getDeviceInfo(deviceInfo, device);
2304 // don't forget to free memory of remote_name and remote_address
2305 bool BluetoothAdapter::getDeviceInfo(bt_device_info_s *deviceInfo, const char *device)
2308 // to assure that when leaving the method, these fields
2309 // will be either set/allocated, or NULL
2310 deviceInfo->remote_name = NULL;
2311 deviceInfo->remote_address = NULL;
2312 deviceInfo->service_uuid = NULL;
2313 deviceInfo->service_count = 0;
2315 if(!deviceInfo || !device)
2319 GVariant *reply = NULL;
2320 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2323 "org.freedesktop.DBus.Properties",
2325 g_variant_new("(s)", "org.bluez.Device1"),
2327 G_DBUS_CALL_FLAGS_NONE,
2334 LoggerE("Failed to 'GetAll': " << err->message);
2341 g_variant_get(reply, "(a{sv})", &iter);
2344 while(g_variant_iter_next(iter, "{sv}", &key, &value))
2346 //LoggerD("KEY: " << key);
2347 if(!strcmp(key, "Name"))
2349 const char *name = g_variant_get_string(value, NULL);
2350 deviceInfo->remote_name = strdup(name);
2352 else if(!strcmp(key, "Address"))
2354 const char *address = g_variant_get_string(value, NULL);
2355 deviceInfo->remote_address = strdup(address);
2357 else if(!strcmp(key, "Paired"))
2359 deviceInfo->is_bonded = g_variant_get_boolean(value);
2361 else if(!strcmp(key, "Connected"))
2363 deviceInfo->is_connected = g_variant_get_boolean(value);
2365 else if(!strcmp(key, "Trusted"))
2367 deviceInfo->is_authorized = g_variant_get_boolean(value);
2369 else if(!strcmp(key, "Class"))
2371 guint32 _class = g_variant_get_uint32(value);
2372 uint8_t minor = _class & 0xff;
2373 uint8_t major = (_class >> 8) & 0xff;
2374 deviceInfo->bt_class.minor_device_class = (bt_minor_device_class_e) minor;
2375 deviceInfo->bt_class.major_device_class = (bt_major_device_class_e) major;
2376 //deviceInfo->bt_class.major_service_class_mask =
2378 else if(!strcmp(key, "UUIDs"))
2381 const char *uuid = NULL;
2382 g_variant_get(value, "as", &iter);
2383 deviceInfo->service_count = g_variant_iter_n_children(iter);
2384 deviceInfo->service_uuid = (char**)malloc(deviceInfo->service_count*sizeof(char*));
2385 char **uuids = deviceInfo->service_uuid; // make a copy of ptr, since we will modify the pointer
2386 while(g_variant_iter_next(iter, "s", &uuid))
2388 *uuids++ = uuid?strdup(uuid):NULL;
2393 g_variant_unref(reply);
2398 // frees allocated memory by its members
2399 // Doesn't free/delete deviceInfo itself
2400 void BluetoothAdapter::freeDeviceInfo(bt_device_info_s *deviceInfo)
2406 free(deviceInfo->remote_address);
2407 free(deviceInfo->remote_name);
2408 for(int i=0; i<deviceInfo->service_count; i++)
2410 free(deviceInfo->service_uuid[i]);
2412 free(deviceInfo->service_uuid);
2415 // frees allocated memory by its members
2416 // Doesn't free/delete discoveryInfo itself
2417 void BluetoothAdapter::freeDiscoveryInfo(bt_adapter_device_discovery_info_s *discoveryInfo)
2423 free(discoveryInfo->remote_address);
2424 free(discoveryInfo->remote_name);
2425 for(int i=0; i<discoveryInfo->service_count; i++)
2427 free(discoveryInfo->service_uuid[i]);
2429 free(discoveryInfo->service_uuid);
2432 bool BluetoothAdapter::removeDevice(const char *address)
2441 std::string addressStr = std::string(address);
2442 char* device = getDeviceFromAddress(addressStr);
2446 LoggerE("Failed to find " << address << " device:");
2450 // now we can remove the device
2453 bool success = true;
2456 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2459 BLUEZ_ADAPTER_IFACE,
2461 g_variant_new("(o)", device), // floating variants are consumed
2463 G_DBUS_CALL_FLAGS_NONE,
2469 LoggerE("Failed to 'RemoveDevice': " << err->message);
2475 LoggerD("removed device : " << device);
2481 char *BluetoothAdapter::getBluetoothTechnology()
2485 GVariant *reply = NULL;
2486 reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2489 CONNMAN_MANAGER_IFACE,
2493 G_DBUS_CALL_FLAGS_NONE,
2500 LoggerE("Failed to call 'GetTechnologies' DBUS method: " << (err?err->message:"reply is null"));
2506 char *technology = NULL, *result = NULL;
2507 GVariantIter *props = NULL;
2508 GVariantIter *technologies = NULL;
2509 g_variant_get(reply, "(a(oa{sv}))", &technologies);
2510 while(g_variant_iter_next(technologies, "(oa{sv})", &technology, &props))
2512 if(technology && strstr(technology, "bluetooth"))
2514 result = strdup(technology);
2516 // get the current Powered state
2519 while(g_variant_iter_next(props, "{sv}", &key, &value)) {
2520 if(!strcmp(key, "Powered")) {
2521 bool powered = g_variant_get_boolean(value);
2523 LoggerD("Bluetooth is initially Powered " << (powered?"ON":"OFF"));
2532 g_variant_unref(reply);
2533 LoggerD("getTech result = " << result);
2537 bool BluetoothAdapter::setBluetoothPowered(bool value)
2540 if(mBluetoothTechnology)
2543 g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2545 mBluetoothTechnology,
2546 CONNMAN_TECHNOLOGY_IFACE,
2548 g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
2550 g_variant_new_boolean(value)
2553 G_DBUS_CALL_FLAGS_NONE,
2560 if((value && strstr(err->message, "Already enabled")) || // it's not an error, 'casue the BT is already Powered ON
2561 (!value && strstr(err->message, "Already disabled"))) // it's not an error, 'cause the BT is already Powered OFF
2566 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);