e1a4e8ea99984bed147d3e0b1f81a3378538000f
[profile/ivi/wrt-plugins-ivi-bt.git] / src / BluetoothAdapter.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18 #include <pcrecpp.h>
19
20 #include <Logger.h>
21 #include <JSWebAPIErrorFactory.h>
22 #include <system_info.h>
23 #include <JSUtil.h>
24
25 #include "BluetoothAdapter.h"
26 #include "BluetoothCallbackUtil.h"
27 #include "JSBluetoothDevice.h"
28 #include "JSBluetoothServiceHandler.h"
29 #include "JSBluetoothSocket.h"
30 #include "GlobalContextManager.h"
31
32 // BLUEZ
33 #include "utils.h"
34
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"
41
42 #define AGENT_PATH              "/org/bluez/agent_pairing"
43 #define AGENT_CAPABILITIES      "KeyboardDisplay"
44
45 #define AGENT_INTERFACE_XML                                 \
46     "<node>"                                                \
47     "  <interface name='" BLUEZ_AGENT_IFACE "'>"            \
48     "    <method name='Release'>"                           \
49     "    </method>"                                         \
50     "    <method name='Authorize'>"                         \
51     "      <arg type='o' name='device' direction='in'/>"    \
52     "      <arg type='s' name='uuid' direction='in'/>"      \
53     "    </method>"                                         \
54     "    <method name='RequestPinCode'>"                    \
55     "      <arg type='o' name='device' direction='in'/>"    \
56     "      <arg type='s' name='pincode' direction='out'/>"  \
57     "    </method>"                                         \
58     "    <method name='RequestPasskey'>"                    \
59     "      <arg type='o' name='device' direction='in'/>"    \
60     "      <arg type='u' name='passkey' direction='out'/>"  \
61     "    </method>"                                         \
62     "    <method name='DisplayPasskey'>"                    \
63     "      <arg type='o' name='device' direction='in'/>"    \
64     "      <arg type='u' name='passkey' direction='in'/>"   \
65     "    </method>"                                         \
66     "    <method name='DisplayPinCode'>"                    \
67     "      <arg type='o' name='device' direction='in'/>"    \
68     "      <arg type='s' name='pincode' direction='in'/>"   \
69     "    </method>"                                         \
70     "    <method name='RequestConfirmation'>"               \
71     "      <arg type='o' name='device' direction='in'/>"    \
72     "      <arg type='u' name='passkey' direction='in'/>"   \
73     "    </method>"                                         \
74     "    <method name='ConfirmModeChange'>"                 \
75     "      <arg type='s' name='mode' direction='in'/>"      \
76     "    </method>"                                         \
77     "    <method name='Cancel'>"                            \
78     "    </method>"                                         \
79     "  </interface>"                                        \
80     "</node>"
81
82 #define PINCODE        "123456"
83 #define PASSKEY         123456
84
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"
89 // BLUEZ
90
91 using namespace DeviceAPI::Common;
92
93 namespace DeviceAPI {
94 namespace Bluetooth {
95
96 bool BluetoothAdapter::foreachBondedDevicesCB(bt_device_info_s *deviceInfo, void *userData)
97 {
98     BluetoothAdapterPtr adapter = static_cast<BluetoothAdapterPtr>(userData);
99     if(!adapter) {
100         LoggerW("userData is NULL");
101         return true;
102     }
103
104     if(deviceInfo == NULL) {
105         LoggerW("deviceInfo is NULL");
106         return true;
107     }
108
109     std::vector<BluetoothDeviceSharedPtr>::iterator iter;
110     for(iter = adapter->knownDevices.begin(); iter != adapter->knownDevices.end(); ++iter) {
111         BluetoothDeviceSharedPtr foundDevice = *iter;
112
113         if(!strcmp(foundDevice->getAddress().c_str(), deviceInfo->remote_address)) {
114             foundDevice->updateInfo(deviceInfo);
115             break;
116         }
117     }
118
119     if(iter == adapter->knownDevices.end()) {
120         BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo));
121         adapter->knownDevices.push_back(device);
122     }
123
124     return true;
125 }
126
127 void BluetoothAdapter::onSocketConnected(int result, bt_socket_connection_state_e state, bt_socket_connection_s *connection, void *userData)
128 {
129     BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
130     if(!object) {
131         LoggerW("userData is NULL");
132         return;
133     }
134
135     if(!connection) {
136         LoggerW("connection is NULL");
137         return;
138     }
139
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");
144             return;
145         }
146
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);
152
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);
158                 if(callback)
159                     callback->invokeCallback("onconnect", socketObj);
160
161                 // Update mConnectedSocket
162                 object->mConnectedSocket.insert(std::pair<int, BluetoothSocketPtr>(connection->socket_fd, socket));
163                 bt_socket_set_data_received_cb(onSocketReceivedCB, userData);
164             }
165             else {
166                 LoggerW("Establishing a connection failed");
167             }
168             return;
169         }
170         else {  // disconnected when Server
171             if(result == BT_ERROR_NONE) {
172                 // Update BluetoothServiceHandler
173                 BluetoothServiceHandlerPtr service = iter->second;
174                 service->setConnectionState(false);
175
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");
180                     return;
181                 }
182                 //BluetoothSocketSharedPtr socket = i->second;
183                 BluetoothSocketPtr socket = i->second;
184                 socket->setConnectionState(false);
185                 MultiCallbackUserDataPtr callback = socket->getOnClose();
186                 if(callback)
187                     callback->invokeCallback("onclose");
188
189                 // Update mConnectedSocket
190                 object->mConnectedSocket.erase(i);
191             }
192             else {
193                 LoggerW("Disconnecting a connection failed");
194             }
195         }
196     }
197     else if(connection->local_role == BT_SOCKET_CLIENT) {
198
199         if(state == BT_SOCKET_CONNECTED) {  // connected when Client
200             std::string remoteAddress(connection->remote_address);
201             ConnReqMultiMapT::iterator iter;
202             do {
203                 iter = object->mConnReqMap.find(remoteAddress);
204                 if(iter != object->mConnReqMap.end() && !strcmp(iter->second->mUUID.c_str(), connection->service_uuid)) {
205                     break;
206                 }
207             } while(iter != object->mConnReqMap.end());
208
209             if(iter == object->mConnReqMap.end()) {
210                 LoggerW("Connection state is changed unexpectedly");
211                 return;
212             }
213
214             MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(iter->second->mUserData);
215
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);
221
222                 // Call successcallback of connectToServiceByUUID
223                 JSContextRef context = callback->getContext();
224                 JSObjectRef socketObj = JSBluetoothSocket::createJSObject(context, socket);
225                 if(callback)
226                     callback->invokeCallback("success", socketObj);
227
228                 // Update mConnReqMap
229                 object->mConnReqMap.erase(iter);
230             }
231             else {
232                 // Call errorcallback of connectToServiceByUUID
233                 JSContextRef context = callback->getContext();
234                 NotFoundException error("Not found");
235                 if(callback)
236                     callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
237
238                 // Update mConnReqMap
239                 object->mConnReqMap.erase(iter);
240             }
241             return;
242         }
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");
249                     return;
250                 }
251
252                 BluetoothSocketPtr socket = i->second;
253                 socket->setConnectionState(false);
254                 MultiCallbackUserDataPtr callback = socket->getOnClose();
255                 if(callback)
256                     callback->invokeCallback("onclose");
257
258                 // Update mConnectedSocket
259                 object->mConnectedSocket.erase(i);
260             }
261             else {
262                 LoggerW("Disconnecting a connection failed");
263             }
264         }
265     }
266     else {
267         LoggerW("Unknown role");
268         return;
269     }
270
271     if(object->mConnectedSocket.size() == 0) {
272         bt_socket_unset_data_received_cb();
273     }
274
275     if(object->mRegisteredUUID.size() == 0 && object->mConnReqMap.size() == 0 && object->mConnectedSocket.size() == 0) {
276         bt_socket_unset_connection_state_changed_cb();
277     }
278 }
279
280 void BluetoothAdapter::onSocketReceivedCB(bt_socket_received_data_s *data, void *userData)
281 {
282     BluetoothAdapterPtr object = static_cast<BluetoothAdapterPtr>(userData);
283     if(!object) {
284         LoggerW("userData is NULL");
285         return;
286     }
287
288     if(!data) {
289         LoggerW("data is NULL");
290         return;
291     }
292
293     ConnectedSocketMapT::iterator i = object->mConnectedSocket.find(data->socket_fd);
294     if(i == object->mConnectedSocket.end()) {
295         LoggerW("Unknown connected socket");
296         return;
297     }
298
299     // Store received data
300     BluetoothSocketPtr socket = i->second;
301     socket->storeRecivedData(data->data, static_cast<unsigned long>(data->data_size));
302
303     // Call BluetoothSocket.onmessage
304     MultiCallbackUserDataPtr callback = socket->getOnMessage();
305     if(callback)
306         callback->invokeCallback("onmessage");
307 }
308
309 BluetoothAdapter::BluetoothAdapter():
310     mAdapterPath(NULL),
311     mAgentRegistrationId(-1),
312     mAgentIntrospectionData(NULL),
313     mBluetoothTechnology(NULL),
314     mEnabled(false)
315 {
316
317
318     mBluetoothTechnology = getBluetoothTechnology();
319     if(!mBluetoothTechnology) {
320         LoggerE("Failed to get BT technology");
321     }
322
323     mAdapterPath = getDefaultAdapter();
324     if(!mAdapterPath) {
325         LoggerE("Unable to get default adapter");
326     }
327     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
328                              "/", "AdapterAdded", BluetoothAdapter::handleSignal,
329                              this);
330     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_MANAGER_IFACE,
331                              "/", "AdapterRemoved", BluetoothAdapter::handleSignal,
332                              this);
333     memset(&mAgentIfaceVTable, 0, sizeof(mAgentIfaceVTable));
334
335     if(isAdapterPowered()) {
336         //LoggerD("Adapter is powered");
337         mEnabled = true;
338     }
339     //else {
340     //    LoggerD("Adapter is not powered");
341     //}
342
343     if(mAdapterPath) {
344         Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
345                                  mAdapterPath, "PropertyChanged", BluetoothAdapter::handleSignal,
346                                  this);
347     }
348 }
349
350 BluetoothAdapter::~BluetoothAdapter()
351 {
352     // unset platform callback
353     bt_socket_unset_connection_state_changed_cb();
354     bt_socket_unset_data_received_cb();
355
356     for(int i = 0; i <= DESTROY_BONDING; i++) {
357         mUserDataList[i].reset();
358     }
359     mRegisteredUUID.clear();
360     mConnReqMap.clear();
361     mFoundDevices.clear();
362     mConnectedSocket.clear();
363 }
364
365 void BluetoothAdapter::unloadFrame(JSContextRef context)
366 {
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();
373             }
374         }
375     }
376
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);
383         }
384     }
385 }
386
387 void BluetoothAdapter::unregisterUUID(std::string &uuid)
388 {
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();
392     }
393 }
394
395 bool BluetoothAdapter::closeConnectedSocket(int socket)
396 {
397     if(mEnabled == true) {
398         ConnectedSocketMapT::iterator iter = mConnectedSocket.find(socket);
399         if(iter == mConnectedSocket.end()) {
400             LoggerW("Already disconnected");
401             return true;
402         }
403
404         mConnectedSocket.erase(iter);
405         if(mConnectedSocket.size() == 0) {
406             bt_socket_unset_data_received_cb();
407         }
408
409         if(mRegisteredUUID.size() == 0 && mConnReqMap.size() == 0 && mConnectedSocket.size() == 0) {
410             bt_socket_unset_connection_state_changed_cb();
411         }
412
413         return true;
414     }
415     else {
416         LoggerE("Bluetooth is not powered");
417         return false;
418     }
419 }
420
421 void BluetoothAdapter::removeConnReq(std::string &remoteAddress)
422 {
423     mConnReqMap.erase(remoteAddress);
424
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");
428         }
429     }
430 }
431
432 BluetoothAdapter* BluetoothAdapter::getInstance()
433 {
434     static BluetoothAdapter instance;
435     return &instance;
436 }
437
438 bool BluetoothAdapter::isBluetoothSupported()
439 {
440     bool isSupported = false;
441
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");
444     }
445 */
446     return isSupported;
447 }
448
449 bool BluetoothAdapter::isValidAddress(std::string &address)
450 {
451     pcrecpp::RE re("(([0-9a-zA-Z]+):)+([0-9a-zA-Z]+)");
452     std::string compareAddress = "00:12:47:08:9A:A6";
453
454     if (!re.FullMatch(address)) {
455         LoggerE("Invalid address");
456         return false;
457     }
458
459     if (address.size() != compareAddress.size())
460     {
461         LoggerE("Invalid size");
462         return false;
463     }
464
465     return true;
466 }
467
468 bool BluetoothAdapter::isValidUUID(std::string &uuid)
469 {
470     pcrecpp::RE re("(([0-9a-zA-Z]+)-)+([0-9a-zA-Z]+)");
471     std::string compareUUID = "00001101-0000-1000-8000-00805F9B34FB";
472
473     if (!re.FullMatch(uuid))
474     {
475         LoggerE("Invalid UUID");
476         return false;
477     }
478
479     if (uuid.size() != compareUUID.size())
480     {
481         LoggerE("Invalid size");
482         return false;
483     }
484
485     return true;
486 }
487
488 std::string BluetoothAdapter::getName() const
489 {
490     const char* name = NULL;
491     std::string str = "";
492
493     if(!mAdapterPath) {
494         LoggerD("No BT adapter");
495         return str;
496     }
497
498     // get adapter properties and check Name property
499     GError *err = NULL;
500     GVariant *reply = NULL;
501     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
502                                          BLUEZ_SERVICE,
503                                          mAdapterPath,
504                                          BLUEZ_ADAPTER_IFACE,
505                                          "GetProperties",
506                                          NULL,
507                                          NULL,
508                                          G_DBUS_CALL_FLAGS_NONE,
509                                          -1,
510                                          NULL,
511                                          &err);
512     if(err || !reply) {
513         if(err)
514             g_error_free(err);
515         LoggerE("Failed to get 'Name' property");
516         return str;
517     }
518
519     GVariantIter *iter;
520     g_variant_get(reply, "(a{sv})", &iter);
521     const char *key;
522     GVariant *value;
523     while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
524         if(!strcmp(key, "Name")) {
525             name = g_variant_get_string(value, NULL);
526             if(name)
527                 str = name;
528             break;
529         }
530     }
531
532     g_variant_unref(reply);
533
534     return str;
535 }
536
537 void BluetoothAdapter::setName(std::string &name, MultiCallbackUserDataPtr userData)
538 {
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);
544             return;
545         }
546
547         if(mAdapterPath) {
548             GError *err = NULL;
549             g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
550                                          BLUEZ_SERVICE,
551                                          mAdapterPath,
552                                          BLUEZ_ADAPTER_IFACE,
553                                          "SetProperty",
554                                          g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
555                                              "Name",
556                                              g_variant_new("s", name.c_str()) // floating parameters are consumed, no cleanup/unref needed
557                                          ),
558                                          NULL,
559                                          G_DBUS_CALL_FLAGS_NONE,
560                                          -1,
561                                          NULL,
562                                          &err);
563
564             if(err) {
565                 LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
566                 UnknownException *error = new UnknownException(err->message);
567                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
568                 g_error_free(err);
569                 return;
570             }
571
572             if(userData)
573                 userData->invokeCallback("success");
574         }
575         else {
576             LoggerE("No BT adapter");
577             UnknownException *error = new UnknownException("No BT adapter");
578             BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
579             return;
580         }
581     }
582 }
583
584 std::string BluetoothAdapter::getAddress() const
585 {
586     const char* address = NULL;
587     std::string str = "";
588
589     if(!mAdapterPath) {
590         LoggerD("No BT adapter");
591         return str;
592     }
593
594     // get adapter properties and check Address property
595     GError *err = NULL;
596     GVariant *reply = NULL;
597     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
598                                          BLUEZ_SERVICE,
599                                          mAdapterPath,
600                                          BLUEZ_ADAPTER_IFACE,
601                                          "GetProperties",
602                                          NULL,
603                                          NULL,
604                                          G_DBUS_CALL_FLAGS_NONE,
605                                          -1,
606                                          NULL,
607                                          &err);
608     if(err || !reply) {
609         if(err)
610             g_error_free(err);
611         LoggerE("Failed to get 'Address' property");
612         return str;
613     }
614
615     GVariantIter *iter;
616     g_variant_get(reply, "(a{sv})", &iter);
617     const char *key;
618     GVariant *value;
619     while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
620         if(!strcmp(key, "Address")) {
621             address = g_variant_get_string(value, NULL);
622             if(address)
623                 str = address;
624             break;
625         }
626     }
627
628     g_variant_unref(reply);
629
630     return str;
631 }
632
633 bool BluetoothAdapter::getPowered() const
634 {
635     return mEnabled;
636 }
637
638 void BluetoothAdapter::setPowered(bool powered, MultiCallbackUserDataPtr userData)
639 {
640     LoggerD("entered");
641
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);
647             return;
648         }
649         else {
650             if(setBluetoothPowered(powered)) { // BT powered OFF successfuly
651                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
652             }
653             else {
654                 LoggerD("Failed to Power OFF BT technology - trying to Power OFF the Adapter directly");
655                 if(setAdapterPowered(powered)) {
656                     BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
657                 }
658                 else {
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);
662                 }
663             }
664         }
665     }
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);
671             }
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);
676                 }
677                 else {
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);
681                 }
682             }
683         }
684         else {
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);
689             }
690             /*
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);
694                 }
695                 else {
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);
699                 }
700             }
701             */
702             else {
703                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
704             }
705         }
706     }
707
708     mUserDataList[SET_POWERED].reset();
709 }
710
711 bool BluetoothAdapter::getVisible() const
712 {
713     if(!mAdapterPath) {
714         LoggerD("No BT adapter");
715         return false;
716     }
717
718     // get adapter properties and check Discoverable property
719     GError *err = NULL;
720     GVariant *reply = NULL;
721     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
722                                          BLUEZ_SERVICE,
723                                          mAdapterPath,
724                                          BLUEZ_ADAPTER_IFACE,
725                                          "GetProperties",
726                                          NULL,
727                                          NULL,
728                                          G_DBUS_CALL_FLAGS_NONE,
729                                          -1,
730                                          NULL,
731                                          &err);
732     if(err || !reply) {
733         if(err)
734             g_error_free(err);
735         LoggerE("Failed to get 'Discoverable' property");
736         return false;
737     }
738
739     bool visible = false;
740     GVariantIter *iter;
741     g_variant_get(reply, "(a{sv})", &iter);
742     const char *key;
743     GVariant *value;
744     while(g_variant_iter_next(iter, "{sv}", &key, &value)) {
745         if(!strcmp(key, "Discoverable")) {
746             visible = g_variant_get_boolean(value);
747             break;
748         }
749     }
750
751     g_variant_unref(reply);
752
753     return visible;
754 }
755
756 void BluetoothAdapter::setVisible(bool visible, unsigned int timeout, MultiCallbackUserDataPtr userData)
757 {
758     //TODO: implementation needed
759     UnknownException *error = new UnknownException("NOT IMPLEMENTED");
760     BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
761     /*
762     if(mEnabled == true) {
763         bt_adapter_visibility_mode_e discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
764         if(visible == true) {
765             if(timeout == 0)
766                 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE;
767             else
768                 discoverable_mode = BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE;
769         }
770
771         bt_adapter_visibility_mode_e current = BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE;
772         int time = 0;
773         if(bt_adapter_get_visibility(&current , &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);
777             return;
778         }
779
780         if(discoverable_mode == current) {
781             if(discoverable_mode != BT_ADAPTER_VISIBILITY_MODE_LIMITED_DISCOVERABLE) {
782                 LoggerD("same visibility");
783                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
784                 return;
785             }
786             else if((unsigned int)time == timeout) {
787                 LoggerD("same visibility");
788                 BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
789                 return;
790             }
791         }
792
793         if(mUserDataList[SET_VISIBLE] == NULL) {
794             bt_adapter_set_visibility_mode_changed_cb(onVisibilityChangedCB, this);
795             mUserDataList[SET_VISIBLE] = userData;
796         } else {
797             UnknownException *error = new UnknownException("Already requested");
798             BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
799             return;
800         }
801
802         mRequestedVisibility = discoverable_mode;
803         int ret = bt_adapter_set_visibility(discoverable_mode, timeout);
804         switch(ret) {
805             case BT_ERROR_NONE:
806             {
807                 LoggerD("bt_adapter_set_visibility() succeeded");
808                 return;
809             }
810             case BT_ERROR_INVALID_PARAMETER:
811             {
812                 InvalidValuesException *error = new InvalidValuesException("Invalid value");
813                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
814                 break;
815             }
816             default:
817             {
818                 UnknownException *error = new UnknownException("Unknown error");
819                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
820             }
821         }
822
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);
828     }
829 */
830 }
831
832 void BluetoothAdapter::setChangeListener(MultiCallbackUserDataPtr userData)
833 {
834     if(mChangeListener == NULL)
835         mChangeListener = userData;
836 }
837
838 void BluetoothAdapter::unsetChangeListener()
839 {
840     if(mChangeListener != NULL)
841         mChangeListener.reset();
842 }
843
844
845 void BluetoothAdapter::discoverDevices(MultiCallbackUserDataPtr userData)
846 {
847     if(!mAdapterPath) {
848         LoggerE("No BT adapter");
849         UnknownException *error = new UnknownException("No BT adapter");
850         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
851         return;
852     }
853
854     if(mUserDataList[DISCOVER_DEVICES] == NULL) {
855         mUserDataList[DISCOVER_DEVICES] = userData;
856     } else {
857         LoggerE("Already requested");
858         UnknownException *error = new UnknownException("Already requested");
859         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
860         return;
861     }
862
863     if(mEnabled == true) {
864         GError *err = NULL;
865         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
866                                      BLUEZ_SERVICE,
867                                      mAdapterPath,
868                                      BLUEZ_ADAPTER_IFACE,
869                                      "StartDiscovery",
870                                      NULL,
871                                      NULL,
872                                      G_DBUS_CALL_FLAGS_NONE,
873                                      -1,
874                                      NULL,
875                                      &err);
876         if(err) {
877             LoggerE("Failed to 'StartDiscovery' on adapter " << mAdapterPath << " : " << err->message);
878             UnknownException *error = new UnknownException(err->message);
879             BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
880             g_error_free(err);
881             mUserDataList[DISCOVER_DEVICES].reset();
882         }
883         else {
884             LoggerD("Call to 'StartDiscovery' succeeded");
885
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());
892             }
893
894             mFoundDevices.clear();
895
896             // 'onstarted' callback is called after receiving 'Discovering' property changed to 'true' ... see handleSignal() method
897             //if(userData)
898             //    userData->invokeCallback("onstarted");
899
900             Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
901                                      mAdapterPath, "DeviceFound", BluetoothAdapter::handleSignal,
902                                      this);
903
904             return;
905         }
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);
910     }
911
912     mUserDataList[DISCOVER_DEVICES].reset();
913 }
914
915 void BluetoothAdapter::stopDiscovery(MultiCallbackUserDataPtr userData)
916 {
917     if(mUserDataList[DISCOVER_DEVICES] == NULL) { // not doing discovery
918         BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
919         return;
920     }
921
922     if(!mAdapterPath) {
923         LoggerE("No BT adapter");
924         UnknownException *error = new UnknownException("No BT adapter");
925         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
926     }
927     else if(mEnabled == true) {
928         GError *err = NULL;
929         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
930                                      BLUEZ_SERVICE,
931                                      mAdapterPath,
932                                      BLUEZ_ADAPTER_IFACE,
933                                      "StopDiscovery",
934                                      NULL,
935                                      NULL,
936                                      G_DBUS_CALL_FLAGS_NONE,
937                                      -1,
938                                      NULL,
939                                      &err);
940         if(err) {
941             LoggerE("Failed to 'StopDiscovery': " << err->message);
942             UnknownException *error = new UnknownException(err->message);
943             BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
944             g_error_free(err);
945         } else {
946             BluetoothCallbackUtil::syncToAsyncSuccessCallback(userData);
947             return;
948         }
949     } else {   // Not enabled
950         ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
951         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
952     }
953
954     mUserDataList[DISCOVER_DEVICES].reset();
955 }
956
957 void BluetoothAdapter::getKnownDevices(MultiCallbackUserDataPtr userData)
958 {
959     BluetoothCallbackUtil::syncToAsyncDeviceArrayCallback(userData);
960 }
961
962 void BluetoothAdapter::getDevice(std::string &address, MultiCallbackUserDataPtr userData)
963 {
964     BluetoothCallbackUtil::syncToAsyncDeviceCallback(userData, address);
965 }
966
967 void BluetoothAdapter::createBonding(std::string &address, MultiCallbackUserDataPtr userData)
968 {
969     if(!isValidAddress(address)) {
970         LoggerE("Wrong address");
971         NotFoundException *error = new NotFoundException("Wrong address");
972         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
973         return;
974     }
975
976     if(!mAdapterPath) {
977         LoggerE("No BT adapter");
978         NotFoundException *error = new NotFoundException("No BT adapter");
979         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
980         return;
981     }
982
983     if(mUserDataList[CREATE_BONDING] == NULL) {
984         mCreateBondingAddress = address;
985         mUserDataList[CREATE_BONDING] = userData;
986     } else {
987         LoggerE("Already requested");
988         UnknownException *error = new UnknownException("Already requested");
989         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
990         return;
991     }
992
993     // remove the device first, so the pairing can be initiated, otherwise pairing will fail
994     bool ok = removeDevice(address.c_str());
995     if(!ok)
996         LoggerD("Failed to remove device: " << address);
997
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),
1002                                     BLUEZ_SERVICE,
1003                                     mAdapterPath,
1004                                     BLUEZ_ADAPTER_IFACE,
1005                                     "CreatePairedDevice",
1006                                     g_variant_new("(sos)", address.c_str(), AGENT_PATH, AGENT_CAPABILITIES),
1007                                     NULL,
1008                                     G_DBUS_CALL_FLAGS_NONE,
1009                                     -1,
1010                                     NULL,
1011                                     BluetoothAdapter::asyncCreatePairedDeviceCallback,
1012                                     this);
1013             LoggerD("Called 'CreatePairedDevice'");
1014         } else {
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);
1018         }
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);
1023     }
1024 }
1025
1026 void BluetoothAdapter::destroyBonding(std::string &address, MultiCallbackUserDataPtr userData)
1027 {
1028     if(!isValidAddress(address)) {
1029         LoggerE("Wrong address");
1030         NotFoundException *error = new NotFoundException("Wrong address");
1031         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1032         return;
1033     }
1034
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());
1038
1039     if(!removeDevice(address.c_str())) {
1040         if(userData) {
1041             JSContextRef context = userData->getContext();
1042             UnknownException error("Failed to remove device");
1043             userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1044         }
1045
1046         return;
1047     }
1048
1049     if(userData) {
1050         if(hasDeviceInfo) {
1051             BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1052             JSContextRef context = userData->getContext();
1053             JSObjectRef deviceObj = JSBluetoothDevice::createJSObject(context, device);
1054             userData->invokeCallback("success", deviceObj);
1055         } else {
1056             JSContextRef context = userData->getContext();
1057             UnknownException error("Failed to get device info");
1058             userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1059         }
1060         freeDeviceInfo(&deviceInfo);
1061     }
1062 }
1063
1064 void BluetoothAdapter::registerRFCOMMServiceByUUID(std::string &uuid, std::string &name, MultiCallbackUserDataPtr userData)
1065 {
1066     BluetoothCallbackUtil::syncToAsyncServiceCallback(userData, uuid, name);
1067 }
1068
1069 void BluetoothAdapter::connectToServiceByUUID(std::string &remoteAddress, std::string &uuid, Common::MultiCallbackUserDataPtr userData)
1070 {
1071     if(!isValidUUID(uuid)) {
1072         LoggerE("Wrong UUID");
1073         InvalidValuesException *error = new InvalidValuesException("Wrong UUID");
1074         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1075         return;
1076     }
1077
1078
1079     if(mEnabled == true) {
1080         int ret = bt_socket_connect_rfcomm(remoteAddress.c_str(), uuid.c_str());
1081
1082         switch(ret) {
1083             case BT_ERROR_NONE:
1084             {
1085                 LoggerD("bt_socket_connect_rfcomm() succeeded");
1086                 bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1087
1088                 BluetoothConnReqPtr connReq = new BluetoothConnReq(uuid, userData);
1089                 mConnReqMap.insert(std::pair<std::string, BluetoothConnReqPtr>(remoteAddress, connReq));
1090                 break;
1091             }
1092             case BT_ERROR_INVALID_PARAMETER:
1093             case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
1094             {
1095                 InvalidValuesException *error = new InvalidValuesException("Invalid value");
1096                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1097                 break;
1098             }
1099             default:
1100             {
1101                 UnknownException *error = new UnknownException("Unknown error");
1102                 BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1103             }
1104         }
1105     } else {   // Not enabled
1106         ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
1107         BluetoothCallbackUtil::syncToAsyncErrorCallback(userData, error);
1108     }
1109 }
1110
1111 void BluetoothAdapter::returnKnownDevices(Common::MultiCallbackUserDataPtr userData)
1112 {
1113     if(mEnabled == true) {
1114         knownDevices = mFoundDevices;
1115
1116         // Get a list of paired/bonded devices
1117         GError *err = NULL;
1118         GVariant *reply = NULL;
1119         reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1120                                              BLUEZ_SERVICE,
1121                                              mAdapterPath,
1122                                              BLUEZ_ADAPTER_IFACE,
1123                                              "GetProperties",
1124                                              NULL,
1125                                              NULL,
1126                                              G_DBUS_CALL_FLAGS_NONE,
1127                                              -1,
1128                                              NULL,
1129                                              &err);
1130         if(err || !reply) {
1131             if(err)
1132                 g_error_free(err);
1133         } else {
1134             GVariantIter *iter;
1135             g_variant_get(reply, "(a{sv})", &iter);
1136             const char *key;
1137             GVariant *value;
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);
1148                         }
1149                     }
1150                     break;
1151                 }
1152             }
1153
1154             g_variant_unref(reply);
1155         }
1156
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;
1164             }
1165
1166             userData->invokeCallback("success", JSObjectMakeArray(userData->getContext(), num, devices, NULL));
1167         }
1168         else {  // There is no found device
1169             userData->invokeCallback("success", JSObjectMakeArray(userData->getContext(), 0, NULL, NULL) );
1170         }
1171     } else {   // Not enabled
1172         LoggerE("Bluetooth device is turned off");
1173         userData->invokeCallback(
1174                 "error",
1175                 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1176         );
1177     }
1178 }
1179
1180 void BluetoothAdapter::returnDevice(std::string &address, Common::MultiCallbackUserDataPtr userData)
1181 {
1182     if(!isValidAddress(address)) {
1183         LoggerE("Wrong address");
1184         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("Wrong address")));
1185         return;
1186     }
1187
1188     if(mEnabled == true) {
1189         bt_device_info_s deviceInfo;
1190         bool success = getDeviceInfoByAddress(&deviceInfo, address.c_str());
1191
1192         if(success) {
1193             BluetoothDeviceSharedPtr device(new BluetoothDevice(&deviceInfo));
1194             LoggerD("invoke successCallback");
1195             userData->invokeCallback("success", JSBluetoothDevice::createJSObject(userData->getContext(), device));
1196             return;
1197         } else {
1198             JSContextRef context = userData->getContext();
1199             UnknownException error("Failed to get device info");
1200             userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1201         }
1202         freeDeviceInfo(&deviceInfo);
1203
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));
1210                 break;
1211             }
1212         }
1213
1214         if(iter == mFoundDevices.end()) {
1215             LoggerE("Can't find this device");
1216
1217             userData->invokeCallback(
1218                     "error",
1219                     JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), NotFoundException("There is no device with the given address"))
1220             );
1221         }
1222     } else {   // Not enabled
1223         LoggerE("Bluetooth device is turned off");
1224         userData->invokeCallback(
1225                 "error",
1226                 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1227         );
1228     }
1229 }
1230
1231 void BluetoothAdapter::returnRegisteredService(std::string &uuid, std::string &name, Common::MultiCallbackUserDataPtr userData)
1232 {
1233     if(!isValidUUID(uuid)) {
1234         LoggerE("Wrong UUID");
1235         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Wrong UUID")));
1236         return;
1237     }
1238
1239     if(mEnabled == true) {
1240
1241         bool isRegistered;
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")));
1245             return;
1246         }
1247
1248         int socket = -1;
1249         int ret = bt_socket_create_rfcomm(uuid.c_str(), &socket);
1250
1251         switch(ret) {
1252             case BT_ERROR_NONE:
1253             {
1254                 LoggerD("bt_socket_create_rfcomm() succeeded");
1255                 int ret = bt_socket_listen_and_accept_rfcomm(socket, 0);
1256                 switch(ret) {
1257                     case BT_ERROR_NONE:
1258                     {
1259                         LoggerD("bt_socket_listen() succeeded");
1260                         bt_socket_set_connection_state_changed_cb(onSocketConnected, this);
1261
1262                         BluetoothServiceHandlerPtr serviceHandler = new BluetoothServiceHandler(uuid, name, socket);
1263                         mRegisteredUUID.insert(std::pair<std::string, BluetoothServiceHandlerPtr>(uuid, serviceHandler));
1264
1265                         JSObjectRef serviceObj = JSBluetoothServiceHandler::createJSObject(userData->getContext(), serviceHandler);
1266                         userData->invokeCallback("success", serviceObj);
1267                         break;
1268                     }
1269                     case BT_ERROR_INVALID_PARAMETER:
1270                     {
1271                         LoggerD("Invalid value");
1272                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1273                         break;
1274                     }
1275                     default:
1276                     {
1277                         LoggerD("Unknown exception");
1278                         userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1279                     }
1280                 }
1281
1282                 break;
1283             }
1284             case BT_ERROR_INVALID_PARAMETER:
1285             {
1286                 LoggerD("Invalid value");
1287                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), InvalidValuesException("Invalid value")));
1288                 break;
1289             }
1290             default:
1291             {
1292                 LoggerD("Unknown exception");
1293                 userData->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), UnknownException("Unknown exception")));
1294             }
1295         }
1296     } else {   // Not enabled
1297         LoggerE("Bluetooth device is turned off");
1298         userData->invokeCallback(
1299                 "error",
1300                 JSWebAPIErrorFactory::makeErrorObject(userData->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))
1301         );
1302     }
1303 }
1304
1305 bool BluetoothAdapter::isBtTechnologyPowered() {
1306     if(!mBluetoothTechnology) {
1307         LoggerE("Invalid BT technology to get 'Powered' state.");
1308         return false;
1309     }
1310
1311     GError *err = NULL;
1312     GVariant *reply = NULL;
1313     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1314                                          CONNMAN_SERVICE,
1315                                          mBluetoothTechnology,
1316                                          CONNMAN_TECHNOLOGY_IFACE,
1317                                          "GetProperties",
1318                                          NULL,
1319                                          NULL,
1320                                          G_DBUS_CALL_FLAGS_NONE,
1321                                          -1,
1322                                          NULL,
1323                                          &err);
1324     if(err || !reply) {
1325         if(err)
1326             g_error_free(err);
1327         return false;
1328     }
1329
1330     GVariantIter *iter;
1331     g_variant_get(reply, "(a{sv})", &iter);
1332     const char *key;
1333     GVariant *value;
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);
1338             break;
1339         }
1340     }
1341
1342     g_variant_unref(reply);
1343
1344     return powered;
1345 }
1346
1347 gchar* BluetoothAdapter::getDefaultAdapter() const
1348 {
1349     GError *err = NULL;
1350     GVariant *reply = NULL;
1351     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1352                                          BLUEZ_SERVICE,
1353                                          "/",
1354                                          BLUEZ_MANAGER_IFACE,
1355                                          "DefaultAdapter",
1356                                          NULL,
1357                                          NULL,
1358                                          G_DBUS_CALL_FLAGS_NONE,
1359                                          -1,
1360                                          NULL,
1361                                          &err);
1362     if(err || !reply) {
1363         if(err) {
1364             LoggerE("Failed to get default adapter: " << err->message);
1365             g_error_free(err);
1366         }
1367         if(!reply)
1368             LoggerE("Reply from 'DefaultAdapter' is null");
1369         return NULL;
1370     }
1371
1372     char *adapter = NULL;
1373     g_variant_get(reply, "(o)", &adapter);
1374     LoggerD("DefaultAdapter: " << adapter);
1375
1376     // make a copy of adapter, 'cause it will be destroyed when 'reply' is un-refed
1377     char *result = adapter?strdup(adapter):NULL;
1378
1379     g_variant_unref(reply);
1380
1381     return result;
1382 }
1383
1384 bool BluetoothAdapter::isAdapterPowered() {
1385     if(!mAdapterPath)
1386         return false;
1387
1388     // get adapter properties and check if it's Powered
1389     GError *err = NULL;
1390     GVariant *reply = NULL;
1391     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1392                                          BLUEZ_SERVICE,
1393                                          mAdapterPath,
1394                                          BLUEZ_ADAPTER_IFACE,
1395                                          "GetProperties",
1396                                          NULL,
1397                                          NULL,
1398                                          G_DBUS_CALL_FLAGS_NONE,
1399                                          -1,
1400                                          NULL,
1401                                          &err);
1402     if(err || !reply) {
1403         if(err)
1404             g_error_free(err);
1405         return false;
1406     }
1407
1408     GVariantIter *iter;
1409     g_variant_get(reply, "(a{sv})", &iter);
1410     const char *key;
1411     GVariant *value;
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);
1416             break;
1417         }
1418     }
1419
1420     g_variant_unref(reply);
1421
1422     return powered;
1423 }
1424
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,
1431                          gpointer          user_data)
1432 {
1433     LoggerD("signal received: '" << interface_name << "' -> '" << signal_name << "' -> '" << object_path << "'");
1434
1435     BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1436     if(!ctx) {
1437         LoggerD("Failed to cast to BluetoothAdapter");
1438         return;
1439     }
1440
1441
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);
1446             if(adapter) {
1447                 LoggerD("Adapter added: " << adapter);
1448                 gchar * adapterPath = ctx->getDefaultAdapter();
1449                 free(ctx->mAdapterPath);
1450                 ctx->mAdapterPath = adapterPath;
1451                 if(adapterPath) {
1452                     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE,
1453                             adapterPath, "PropertyChanged", BluetoothAdapter::handleSignal,
1454                             ctx);
1455                 }
1456             }
1457         }
1458         else if(!strcmp(signal_name, "AdapterRemoved")) {
1459             const char *adapter = NULL;
1460             g_variant_get(parameters, "(o)", &adapter);
1461             if(adapter) {
1462                 LoggerD("Adapter removed: " << adapter);
1463             }
1464         }
1465     }
1466     else if(!strcmp(interface_name, BLUEZ_ADAPTER_IFACE)) {
1467         if(!strcmp(signal_name, "PropertyChanged")) {
1468             const char *name;
1469             GVariant *var;
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);
1475             }
1476             else if(!strcmp(name, "Powered")) {
1477                 bool powered = g_variant_get_boolean(var);
1478                 ctx->onPoweredChanged(powered);
1479             }
1480             else if(!strcmp(name, "Discoverable")) {
1481                 bool visible = g_variant_get_boolean(var);
1482                 ctx->onVisibilityChanged(visible);
1483             }
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]);
1488                         if(callback) {
1489                             callback->invokeCallback("onstarted");
1490                         }
1491                 }
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]);
1497
1498                         if(callback) {
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++) {
1503
1504                                     callback->invokeCallback("ondevicedisappeared",
1505                                             JSUtil::toJSValueRef(callback->getContext(), *iter));
1506                                 }
1507                             }
1508
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;
1516                                 }
1517
1518                                 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1519
1520                                 callback->invokeCallback(
1521                                         "onfinished",
1522                                         JSObjectMakeArray(callback->getContext(), num, devices, NULL) );
1523                             }
1524                             else {  // There is no found device
1525                                 LoggerD("There is no found device");
1526                                 ctx->mUserDataList[DISCOVER_DEVICES].reset();
1527
1528                                 callback->invokeCallback(
1529                                         "onfinished",
1530                                         JSObjectMakeArray(callback->getContext(), 0, NULL, NULL) );
1531                             }
1532                         }
1533
1534                         Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, BLUEZ_SERVICE, BLUEZ_ADAPTER_IFACE, object_path, "DeviceFound");
1535
1536                         GError *err = NULL;
1537                         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1538                                                      BLUEZ_SERVICE,
1539                                                      ctx->mAdapterPath,
1540                                                      BLUEZ_ADAPTER_IFACE,
1541                                                      "StopDiscovery",
1542                                                      NULL,
1543                                                      NULL,
1544                                                      G_DBUS_CALL_FLAGS_NONE,
1545                                                      -1,
1546                                                      NULL,
1547                                                      &err);
1548                         if(err)
1549                             g_error_free(err);
1550                     }
1551                 }
1552             }
1553         }
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;
1560
1561             const char *address;
1562             GVariantIter *iter;
1563             g_variant_get(parameters, "(sa{sv})", &address, &iter);
1564             discoveryInfo.remote_address = address?strdup(address):NULL;
1565             const char *key;
1566             GVariant *value;
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;
1572                 }
1573                 else if(!strcmp(key, "Paired")) {
1574                     discoveryInfo.is_bonded = g_variant_get_boolean(value);
1575                 }
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 =
1583                 }
1584                 else if(!strcmp(key, "UUIDs")) {
1585                     GVariantIter *iter;
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;
1593                     }
1594                 }
1595             }
1596
1597             if(!discoveryInfo.remote_address) {
1598                 LoggerD("discovery info ... remote_address is null");
1599                 ctx->freeDiscoveryInfo(&discoveryInfo);
1600                 return;
1601             }
1602
1603             if(!discoveryInfo.remote_name) {
1604                 LoggerD("discovery info ... remote_name is null for " << discoveryInfo.remote_address);
1605                 discoveryInfo.remote_name = strdup("");
1606             }
1607
1608             LoggerD("Found BT device: " << discoveryInfo.remote_address << " ... " << (discoveryInfo.remote_name?discoveryInfo.remote_name:""));
1609
1610             if(ctx->mUserDataList[DISCOVER_DEVICES] != NULL) {  // requested event
1611                 MultiCallbackUserDataPtr callback =
1612                         static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[DISCOVER_DEVICES]);
1613
1614                 if(callback) {
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);
1621
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);
1626                                 break;
1627                             }
1628                         }
1629
1630                         callback->invokeCallback("ondevicefound", deviceObj);
1631                     }
1632                 }
1633             }
1634
1635             ctx->freeDiscoveryInfo(&discoveryInfo);
1636         }
1637     }
1638     /*
1639     else if(!strcmp(interface_name, CONNMAN_TECHNOLOGY_IFACE)) {
1640         if(!strcmp(signal_name, "PropertyChanged")) {
1641             const char *name;
1642             GVariant *value;
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);
1647             }
1648         }
1649     }
1650     */
1651 }
1652
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)) {
1657             exists = true;
1658             break;
1659         }
1660     }
1661
1662     return exists;
1663 }
1664
1665 bool BluetoothAdapter::setAdapterPowered(bool value)
1666 {
1667     LoggerD("entered");
1668
1669     if(mAdapterPath) {
1670         GError *err = NULL;
1671         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
1672                                      BLUEZ_SERVICE,
1673                                      mAdapterPath,
1674                                      BLUEZ_ADAPTER_IFACE,
1675                                      "SetProperty",
1676                                      g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
1677                                          "Powered",
1678                                          //g_variant_new("b", &value)
1679                                          g_variant_new_boolean(value)
1680                                      ),
1681                                      NULL,
1682                                      G_DBUS_CALL_FLAGS_NONE,
1683                                      -1,
1684                                      NULL,
1685                                      &err);
1686
1687         if(err) {
1688             LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
1689             g_error_free(err);
1690             return false;
1691         }
1692
1693         return true;
1694     }
1695
1696     return false;
1697 }
1698
1699 void BluetoothAdapter::onPoweredChanged(bool powered)
1700 {
1701     mEnabled = powered;
1702
1703     if(mChangeListener != NULL) {
1704         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1705         if(callback) {
1706             JSContextRef context = callback->getContext();
1707             JSValueRef value =  JSValueMakeBoolean(context, powered);
1708
1709             callback->invokeCallback("onstatechanged", value);
1710         }
1711     }
1712
1713     if(!powered && mUserDataList[DISCOVER_DEVICES] != NULL)
1714         mUserDataList[DISCOVER_DEVICES].reset();
1715 }
1716
1717 void BluetoothAdapter::onNameChanged(const char *name)
1718 {
1719     if(mUserDataList[SET_NAME] != NULL) {  // requested event
1720         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mUserDataList[SET_NAME]);
1721         mUserDataList[SET_NAME].reset();
1722         if(callback)
1723             callback->invokeCallback("success");
1724     }
1725     else {  // unexpected event
1726         LoggerW("Bluetooth name is changed unexpectedly");
1727     }
1728
1729     if(mChangeListener != NULL) {
1730         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1731         if(callback) {
1732             JSContextRef context = callback->getContext();
1733             JSStringRef nameRef = JSStringCreateWithUTF8CString(name);
1734             JSValueRef value = JSValueMakeString(context, nameRef);
1735
1736             callback->invokeCallback("onnamechanged", value);
1737         }
1738     }
1739 }
1740
1741 void BluetoothAdapter::onVisibilityChanged(bool visible)
1742 {
1743     if(mChangeListener != NULL) {
1744         MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(mChangeListener);
1745         if(callback) {
1746             JSContextRef context = callback->getContext();
1747             JSValueRef value =  JSValueMakeBoolean(context, visible);
1748
1749             callback->invokeCallback("onvisibilitychanged", value);
1750         }
1751     }
1752 }
1753
1754 void BluetoothAdapter::asyncCreatePairedDeviceCallback(GObject *source, GAsyncResult *result, gpointer user_data) {
1755     BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1756     if(!ctx) {
1757         LoggerE("Failed to cast to BluetoothAdapter");
1758         return;
1759     }
1760
1761     GError *err = NULL;
1762     GVariant *reply;
1763     reply = g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
1764     if(err || !reply) {
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]);
1768             if(callback) {
1769                 NotFoundException *error = new NotFoundException("Failed to CreatePairedDevice");
1770                 BluetoothCallbackUtil::syncToAsyncErrorCallback(callback, error);
1771             }
1772         }
1773         if(err)
1774             g_error_free(err);
1775     } else {
1776         LoggerD("Got reply from CreatePairedDevice");
1777         if(ctx->mUserDataList[CREATE_BONDING] != NULL) {
1778             MultiCallbackUserDataPtr callback = static_cast<MultiCallbackUserDataPtr>(ctx->mUserDataList[CREATE_BONDING]);
1779             if(callback) {
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);
1786                 } else {
1787                     JSContextRef context = callback->getContext();
1788                     UnknownException error("Failed to get device info");
1789                     callback->invokeCallback("error", JSWebAPIErrorFactory::makeErrorObject(context, error));
1790                 }
1791                 ctx->freeDeviceInfo(&deviceInfo);
1792             }
1793         }
1794     }
1795
1796     ctx->mCreateBondingAddress.clear();
1797     ctx->mUserDataList[CREATE_BONDING].reset();
1798
1799     g_variant_unref(reply);
1800 }
1801
1802 bool BluetoothAdapter::setupAgent(const char *agent)
1803 {
1804     if(!agent) {
1805         LoggerE("Invalid agent path");
1806         return false;
1807     }
1808
1809     LoggerD("entered: registering agent " << agent);
1810
1811     GError *err = NULL;
1812
1813     mAgentIfaceVTable.method_call = BluetoothAdapter::agentHandleMethodCall;
1814     mAgentIntrospectionData = g_dbus_node_info_new_for_xml(AGENT_INTERFACE_XML, NULL);
1815
1816     if (mAgentIntrospectionData == NULL) {
1817         LoggerD("failed to create introspection data.");
1818         return false;
1819     }
1820     LoggerD("introspection data parsed OK");
1821
1822     if(mAgentRegistrationId > 0) { // already registered
1823         LoggerD("Bluez agent for pairing already registered ... possibly not Released after previous pairing");
1824
1825         // unregister Agent
1826         bool unregistered = g_dbus_connection_unregister_object(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), mAgentRegistrationId);
1827         if(unregistered)
1828             mAgentRegistrationId = -1;
1829     }
1830
1831     mAgentRegistrationId = g_dbus_connection_register_object( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1832                                                   agent,
1833                                                   mAgentIntrospectionData->interfaces[0],
1834                                                   &mAgentIfaceVTable, //const GDBusInterfaceVTable *vtable,
1835                                                   this, //user_data
1836                                                   NULL, //GDestroyNotify
1837                                                   &err);
1838
1839     if(err) {
1840         LoggerD("Failed to register object: " << agent << " : " << err->message);
1841         g_error_free(err);
1842         return false;
1843     }
1844     LoggerD("object registered with id=" << mAgentRegistrationId);
1845
1846     return true;
1847 }
1848
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,
1856                                               gpointer               user_data)
1857 {
1858     LoggerD("entered\n\tsender=" << sender << "\n\tobject_path=" << object_path << "\n\tinterface_name=" << interface_name << "\n\tmethod_name=" << method_name);
1859
1860     BluetoothAdapter *ctx = static_cast<BluetoothAdapter*>(user_data);
1861     if(!ctx) {
1862         LoggerD("Failed to cast to BluetoothAdapter");
1863         g_dbus_method_invocation_return_value(invocation, NULL);
1864         return;
1865     }
1866
1867     if(!strcmp(method_name, "Authorize")) {
1868         g_dbus_method_invocation_return_value(invocation, NULL);
1869     }
1870     else if(!strcmp(method_name, "RequestPinCode")) {
1871         g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", PINCODE));
1872     }
1873     else if(!strcmp(method_name, "RequestPasskey")) {
1874         g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", PASSKEY));
1875     }
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);
1879             if(unregistered)
1880                 ctx->mAgentRegistrationId = -1;
1881         }
1882         g_dbus_method_invocation_return_value(invocation, NULL);
1883     }
1884     else {
1885         // DisplayPasskey, DisplayPinCode, RequestConfirmation, ConfirmModeChange, Cancel
1886         g_dbus_method_invocation_return_value(invocation, NULL);
1887     }
1888 }
1889
1890 bool BluetoothAdapter::isDevicePaired(const char *device) {
1891     if(!device)
1892         return false;
1893
1894     // get device properties and check if it's Paired
1895     GError *err = NULL;
1896     GVariant *reply = NULL;
1897     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1898                                          BLUEZ_SERVICE,
1899                                          device,
1900                                          BLUEZ_DEVICE_IFACE,
1901                                          "GetProperties",
1902                                          NULL,
1903                                          NULL,
1904                                          G_DBUS_CALL_FLAGS_NONE,
1905                                          -1,
1906                                          NULL,
1907                                          &err);
1908     if(err || !reply) {
1909         if(err)
1910             g_error_free(err);
1911         return false;
1912     }
1913
1914     GVariantIter *iter;
1915     g_variant_get(reply, "(a{sv})", &iter);
1916     const char *key;
1917     GVariant *value;
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);
1922             break;
1923         }
1924     }
1925
1926     g_variant_unref(reply);
1927
1928     return paired;
1929 }
1930
1931 bool BluetoothAdapter::getDeviceInfoByAddress(bt_device_info_s *deviceInfo, const char *address) {
1932
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;
1939
1940     if(!deviceInfo || !address)
1941         return false;
1942
1943     if(!mAdapterPath)
1944         return false;
1945
1946     GError *err = NULL;
1947     GVariant *reply = NULL;
1948     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1949             BLUEZ_SERVICE,
1950             mAdapterPath,
1951             BLUEZ_ADAPTER_IFACE,
1952             "FindDevice",
1953             g_variant_new("(s)", address),
1954             NULL,
1955             G_DBUS_CALL_FLAGS_NONE,
1956             -1,
1957             NULL,
1958             &err);
1959
1960     if(err || !reply) {
1961         LoggerE("Failed to find " << address << " device: " << (err?err->message:"Invalid reply"));
1962         if(err)
1963             g_error_free(err);
1964         return false;
1965     }
1966
1967     bool success = false;
1968     const char *device = NULL;
1969     g_variant_get(reply, "(o)", &device);
1970     if(device) {
1971         success = getDeviceInfo(deviceInfo, device);
1972     }
1973
1974     g_variant_unref(reply);
1975
1976     return success;
1977 }
1978
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) {
1981
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;
1988
1989     if(!deviceInfo || !device)
1990         return false;
1991
1992     GError *err = NULL;
1993     GVariant *reply = NULL;
1994     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
1995             BLUEZ_SERVICE,
1996             device,
1997             BLUEZ_DEVICE_IFACE,
1998             "GetProperties",
1999             NULL,
2000             NULL,
2001             G_DBUS_CALL_FLAGS_NONE,
2002             -1,
2003             NULL,
2004             &err);
2005     if(err || !reply) {
2006         LoggerE("Failed to 'GetProperties': " << err->message);
2007         if(err)
2008             g_error_free(err);
2009         return false;
2010     }
2011
2012     GVariantIter *iter;
2013     g_variant_get(reply, "(a{sv})", &iter);
2014     const char *key;
2015     GVariant *value;
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);
2021         }
2022         else if(!strcmp(key, "Address")) {
2023             const char *address = g_variant_get_string(value, NULL);
2024             deviceInfo->remote_address = strdup(address);
2025         }
2026         else if(!strcmp(key, "Paired")) {
2027             deviceInfo->is_bonded = g_variant_get_boolean(value);
2028         }
2029         else if(!strcmp(key, "Connected")) {
2030             deviceInfo->is_connected = g_variant_get_boolean(value);
2031         }
2032         else if(!strcmp(key, "Trusted")) {
2033             deviceInfo->is_authorized = g_variant_get_boolean(value);
2034         }
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 =
2042         }
2043         else if(!strcmp(key, "UUIDs")) {
2044             GVariantIter *iter;
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;
2052             }
2053         }
2054     }
2055
2056     g_variant_unref(reply);
2057
2058     return true;
2059 }
2060
2061 // frees allocated memory by its members
2062 // Doesn't free/delete deviceInfo itself
2063 void BluetoothAdapter::freeDeviceInfo(bt_device_info_s *deviceInfo) {
2064     if(!deviceInfo)
2065         return;
2066
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]);
2071     }
2072     free(deviceInfo->service_uuid);
2073 }
2074
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) {
2078     if(!discoveryInfo)
2079         return;
2080
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]);
2085     }
2086     free(discoveryInfo->service_uuid);
2087 }
2088
2089 bool BluetoothAdapter::removeDevice(const char *address) {
2090     if(!address)
2091         return false;
2092
2093     if(!mAdapterPath)
2094         return false;
2095
2096     GError *err = NULL;
2097     GVariant *reply = NULL;
2098     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2099                                          BLUEZ_SERVICE,
2100                                          mAdapterPath,
2101                                          BLUEZ_ADAPTER_IFACE,
2102                                          "FindDevice",
2103                                          g_variant_new("(s)", address),
2104                                          NULL,
2105                                          G_DBUS_CALL_FLAGS_NONE,
2106                                          -1,
2107                                          NULL,
2108                                          &err);
2109     if(err || !reply) {
2110         LoggerE("Failed to find " << address << " device: " << err->message);
2111         if(err)
2112             g_error_free(err);
2113
2114         return false;
2115     }
2116
2117     const char *device = NULL;
2118     g_variant_get(reply, "(o)", &device);
2119
2120     // now we can remove the device
2121     bool success = true;
2122     if(device) {
2123         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
2124                 BLUEZ_SERVICE,
2125                 mAdapterPath,
2126                 BLUEZ_ADAPTER_IFACE,
2127                 "RemoveDevice",
2128                 g_variant_new("(o)", device), // floating variants are consumed
2129                 NULL,
2130                 G_DBUS_CALL_FLAGS_NONE,
2131                 -1,
2132                 NULL,
2133                 &err);
2134         if(err) {
2135             LoggerE("Failed to 'RemoveDevice': " << err->message);
2136             g_error_free(err);
2137             success = false;
2138         }
2139     }
2140
2141     g_variant_unref(reply);
2142
2143     return success;
2144 }
2145
2146 // CONNMAN
2147 char *BluetoothAdapter::getBluetoothTechnology() {
2148     GError *err = NULL;
2149     GVariant *reply = NULL;
2150     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2151                                          CONNMAN_SERVICE,
2152                                          "/",
2153                                          CONNMAN_MANAGER_IFACE,
2154                                          "GetTechnologies",
2155                                          NULL,
2156                                          NULL,
2157                                          G_DBUS_CALL_FLAGS_NONE,
2158                                          -1,
2159                                          NULL,
2160                                          &err);
2161
2162     if(err || !reply) {
2163         LoggerE("Failed to call 'GetTechnologies' DBUS method: " << (err?err->message:"reply is null"));
2164         if(err)
2165             g_error_free(err);
2166         return NULL;
2167     }
2168
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);
2176             /*
2177             // get the current Powered state
2178             const char *key;
2179             GVariant *value;
2180             while(g_variant_iter_next(props, "{sv}", &key, &value)) {
2181                 if(!strcmp(key, "Powered")) {
2182                     bool powered = g_variant_get_boolean(value);
2183                     mEnabled = powered;
2184                     LoggerD("Bluetooth is initially Powered " << (powered?"ON":"OFF"));
2185                     break;
2186                 }
2187             }
2188             */
2189             break;
2190         }
2191     }
2192
2193     g_variant_unref(reply);
2194     return result;
2195 }
2196
2197 bool BluetoothAdapter::setBluetoothPowered(bool value) {
2198     if(mBluetoothTechnology) {
2199         GError *err = NULL;
2200         g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
2201                                      CONNMAN_SERVICE,
2202                                      mBluetoothTechnology,
2203                                      CONNMAN_TECHNOLOGY_IFACE,
2204                                      "SetProperty",
2205                                      g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
2206                                          "Powered",
2207                                          g_variant_new_boolean(value)
2208                                      ),
2209                                      NULL,
2210                                      G_DBUS_CALL_FLAGS_NONE,
2211                                      -1,
2212                                      NULL,
2213                                      &err);
2214
2215         if(err) {
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
2218             {
2219                 g_error_free(err);
2220                 return true;
2221             }
2222             LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
2223             g_error_free(err);
2224             return false;
2225         }
2226
2227         return true;
2228     }
2229
2230     return false;
2231 }
2232
2233 } // Bluetooth
2234 } // DeviceAPI
2235