1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtCore/QLoggingCategory>
5#include <QtCore/QRandomGenerator>
6#include <QtDBus/QDBusContext>
7
8#include "qbluetoothlocaldevice.h"
9#include "qbluetoothaddress.h"
10#include "qbluetoothlocaldevice_p.h"
11
12#include "bluez/bluez5_helper_p.h"
13#include "bluez/objectmanager_p.h"
14#include "bluez/properties_p.h"
15#include "bluez/adapter1_bluez5_p.h"
16#include "bluez/device1_bluez5_p.h"
17
18QT_BEGIN_NAMESPACE
19
20Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
21
22QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
23 QObject(parent),
24 d_ptr(new QBluetoothLocalDevicePrivate(this))
25{
26 d_ptr->currentMode = hostMode();
27}
28
29QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent) :
30 QObject(parent),
31 d_ptr(new QBluetoothLocalDevicePrivate(this, address))
32{
33 d_ptr->currentMode = hostMode();
34}
35
36QString QBluetoothLocalDevice::name() const
37{
38 if (d_ptr->adapter)
39 return d_ptr->adapter->alias();
40
41 return QString();
42}
43
44QBluetoothAddress QBluetoothLocalDevice::address() const
45{
46 if (d_ptr->adapter)
47 return QBluetoothAddress(d_ptr->adapter->address());
48
49 return QBluetoothAddress();
50}
51
52void QBluetoothLocalDevice::powerOn()
53{
54 if (d_ptr->adapter)
55 d_ptr->adapter->setPowered(true);
56}
57
58void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
59{
60 if (!isValid())
61 return;
62
63 Q_D(QBluetoothLocalDevice);
64
65 if (d->pendingHostModeChange != -1) {
66 qCWarning(QT_BT_BLUEZ) << "setHostMode() ignored due to already pending mode change";
67 return;
68 }
69
70 switch (mode) {
71 case HostDiscoverableLimitedInquiry:
72 case HostDiscoverable:
73 if (hostMode() == HostPoweredOff) {
74 // We first have to wait for BT to be powered on,
75 // then we can set the host mode correctly
76 d->pendingHostModeChange = static_cast<int>(HostDiscoverable);
77 d->adapter->setPowered(true);
78 } else {
79 d->adapter->setDiscoverable(true);
80 }
81 break;
82 case HostConnectable:
83 if (hostMode() == HostPoweredOff) {
84 d->pendingHostModeChange = static_cast<int>(HostConnectable);
85 d->adapter->setPowered(true);
86 } else {
87 d->adapter->setDiscoverable(false);
88 }
89 break;
90 case HostPoweredOff:
91 d->adapter->setPowered(false);
92 break;
93 }
94}
95
96QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
97{
98 if (d_ptr->adapter) {
99 if (!d_ptr->adapter->powered())
100 return HostPoweredOff;
101 else if (d_ptr->adapter->discoverable())
102 return HostDiscoverable;
103 else if (d_ptr->adapter->powered())
104 return HostConnectable;
105 }
106
107 return HostPoweredOff;
108}
109
110QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
111{
112 return d_ptr->connectedDevices();
113}
114
115QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
116{
117 QList<QBluetoothHostInfo> localDevices;
118
119 initializeBluez5();
120 OrgFreedesktopDBusObjectManagerInterface manager(
121 QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
122 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
123 reply.waitForFinished();
124 if (reply.isError())
125 return localDevices;
126
127 ManagedObjectList managedObjectList = reply.value();
128 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
129 it != managedObjectList.constEnd(); ++it) {
130 const InterfaceList &ifaceList = it.value();
131
132 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
133 ++jt) {
134 const QString &iface = jt.key();
135 const QVariantMap &ifaceValues = jt.value();
136
137 if (iface == QStringLiteral("org.bluez.Adapter1")) {
138 QBluetoothHostInfo hostInfo;
139 const QString temp = ifaceValues.value(QStringLiteral("Address")).toString();
140
141 hostInfo.setAddress(QBluetoothAddress(temp));
142 if (hostInfo.address().isNull())
143 continue;
144 hostInfo.setName(ifaceValues.value(QStringLiteral("Name")).toString());
145 localDevices.append(t: hostInfo);
146 }
147 }
148 }
149 return localDevices;
150}
151
152void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
153{
154 if (!isValid() || address.isNull()) {
155 QMetaObject::invokeMethod(obj: this, member: "errorOccurred", c: Qt::QueuedConnection,
156 Q_ARG(QBluetoothLocalDevice::Error,
157 QBluetoothLocalDevice::PairingError));
158 return;
159 }
160
161 const Pairing current_pairing = pairingStatus(address);
162 if (current_pairing == pairing) {
163 if (d_ptr->adapter) {
164 // A possibly running discovery or pending pairing request should be canceled
165 if (d_ptr->pairingDiscoveryTimer && d_ptr->pairingDiscoveryTimer->isActive()) {
166 d_ptr->pairingDiscoveryTimer->stop();
167 }
168
169 if (d_ptr->pairingTarget) {
170 qCDebug(QT_BT_BLUEZ) << "Cancelling pending pairing request to" << d_ptr->pairingTarget->address();
171 QDBusPendingReply<> cancelReply = d_ptr->pairingTarget->CancelPairing();
172 d_ptr->pairingRequestCanceled = true;
173 cancelReply.waitForFinished();
174 delete d_ptr->pairingTarget;
175 d_ptr->pairingTarget = nullptr;
176 }
177 }
178 QMetaObject::invokeMethod(obj: this, member: "pairingFinished", c: Qt::QueuedConnection,
179 Q_ARG(QBluetoothAddress, address),
180 Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
181 return;
182 }
183
184 d_ptr->requestPairing(address, targetPairing: pairing);
185}
186
187void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &targetAddress,
188 QBluetoothLocalDevice::Pairing targetPairing)
189{
190 if (!isValid())
191 return;
192
193 //are we already discovering something? -> abort those attempts
194 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
195 pairingDiscoveryTimer->stop();
196 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
197 }
198
199 if (pairingTarget) {
200 delete pairingTarget;
201 pairingTarget = nullptr;
202 }
203
204 // pairing implies that the device was found
205 // if we cannot find it we may have to turn on Discovery mode for a limited amount of time
206
207 // check device doesn't already exist
208 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
209 reply.waitForFinished();
210 if (reply.isError()) {
211 emit q_ptr->errorOccurred(error: QBluetoothLocalDevice::PairingError);
212 return;
213 }
214
215 ManagedObjectList managedObjectList = reply.value();
216 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
217 const QDBusObjectPath &path = it.key();
218 const InterfaceList &ifaceList = it.value();
219
220 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
221 const QString &iface = jt.key();
222
223 if (iface == QStringLiteral("org.bluez.Device1")) {
224
225 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
226 path.path(),
227 QDBusConnection::systemBus());
228 if (targetAddress == QBluetoothAddress(device.address())) {
229 qCDebug(QT_BT_BLUEZ) << "Initiating direct pair to" << targetAddress.toString();
230 //device exist -> directly work with it
231 processPairing(objectPath: path.path(), target: targetPairing);
232 return;
233 }
234 }
235 }
236 }
237
238 //no device matching -> turn on discovery
239 QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapterPath: adapter->path());
240
241 address = targetAddress;
242 pairing = targetPairing;
243 if (!pairingDiscoveryTimer) {
244 pairingDiscoveryTimer = new QTimer(this);
245 pairingDiscoveryTimer->setSingleShot(true);
246 pairingDiscoveryTimer->setInterval(20000); //20s
247 connect(sender: pairingDiscoveryTimer, signal: &QTimer::timeout,
248 context: this, slot: &QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut);
249 }
250
251 qCDebug(QT_BT_BLUEZ) << "Initiating discovery for pairing on" << targetAddress.toString();
252 pairingDiscoveryTimer->start();
253}
254
255/*!
256 * \internal
257 *
258 * Found a matching device. Now we must ensure its pairing/trusted state is as desired.
259 * If it has to be paired then we need another roundtrip through the event loop
260 * while we wait for the user to accept the pairing dialogs.
261 */
262void QBluetoothLocalDevicePrivate::processPairing(const QString &objectPath,
263 QBluetoothLocalDevice::Pairing target)
264{
265 if (pairingTarget)
266 delete pairingTarget;
267
268 //stop possibly running discovery
269 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
270 pairingDiscoveryTimer->stop();
271
272 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
273 }
274
275 pairingTarget = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"), objectPath,
276 QDBusConnection::systemBus(), this);
277 const QBluetoothAddress targetAddress(pairingTarget->address());
278
279 Q_Q(QBluetoothLocalDevice);
280
281 switch (target) {
282 case QBluetoothLocalDevice::Unpaired: {
283 delete pairingTarget;
284 pairingTarget = nullptr;
285
286 QDBusPendingReply<> removeReply = adapter->RemoveDevice(device: QDBusObjectPath(objectPath));
287 auto watcher = new QDBusPendingCallWatcher(removeReply, this);
288 connect(sender: watcher, signal: &QDBusPendingCallWatcher::finished,
289 context: this, slot: [q, targetAddress](QDBusPendingCallWatcher* watcher){
290 QDBusPendingReply<> reply = *watcher;
291 if (reply.isError())
292 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
293 else
294 emit q->pairingFinished(address: targetAddress, pairing: QBluetoothLocalDevice::Unpaired);
295
296 watcher->deleteLater();
297 });
298 break;
299 }
300 case QBluetoothLocalDevice::Paired:
301 case QBluetoothLocalDevice::AuthorizedPaired:
302 pairing = target;
303
304 if (!pairingTarget->paired()) {
305 qCDebug(QT_BT_BLUEZ) << "Sending pairing request to" << pairingTarget->address();
306 //initiate the pairing
307 QDBusPendingReply<> pairReply = pairingTarget->Pair();
308 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pairReply, this);
309 connect(sender: watcher, signal: &QDBusPendingCallWatcher::finished,
310 context: this, slot: &QBluetoothLocalDevicePrivate::pairingCompleted);
311 return;
312 }
313
314 //already paired but Trust level must be adjusted
315 if (target == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
316 pairingTarget->setTrusted(true);
317 else if (target == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
318 pairingTarget->setTrusted(false);
319
320 delete pairingTarget;
321 pairingTarget = nullptr;
322
323 emit q->pairingFinished(address: targetAddress, pairing: target);
324
325 break;
326 default:
327 break;
328 }
329}
330
331void QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut()
332{
333 qCWarning(QT_BT_BLUEZ) << "Discovery for pairing purposes failed. Cannot find parable device.";
334
335 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
336
337 emit q_ptr->errorOccurred(error: QBluetoothLocalDevice::PairingError);
338}
339
340QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
341 const QBluetoothAddress &address) const
342{
343 if (address.isNull())
344 return Unpaired;
345
346 if (isValid())
347 {
348 QDBusPendingReply<ManagedObjectList> reply = d_ptr->manager->GetManagedObjects();
349 reply.waitForFinished();
350 if (reply.isError())
351 return Unpaired;
352
353 ManagedObjectList managedObjectList = reply.value();
354 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
355 const QDBusObjectPath &path = it.key();
356 const InterfaceList &ifaceList = it.value();
357
358 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
359 const QString &iface = jt.key();
360
361 if (iface == QStringLiteral("org.bluez.Device1")) {
362
363 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
364 path.path(),
365 QDBusConnection::systemBus());
366
367 if (address == QBluetoothAddress(device.address())) {
368 if (device.trusted() && device.paired())
369 return AuthorizedPaired;
370 else if (device.paired())
371 return Paired;
372 else
373 return Unpaired;
374 }
375 }
376 }
377 }
378 }
379
380 return Unpaired;
381}
382
383QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
384 QBluetoothAddress address) :
385 localAddress(address),
386 pendingHostModeChange(-1),
387 q_ptr(q)
388{
389 registerQBluetoothLocalDeviceMetaType();
390 initializeBluez5();
391 initializeAdapter();
392
393 connectDeviceChanges();
394}
395
396bool objectPathIsForThisDevice(const QString &adapterPath, const QString &objectPath)
397{
398 return (!adapterPath.isEmpty() && objectPath.startsWith(s: adapterPath));
399}
400
401void QBluetoothLocalDevicePrivate::connectDeviceChanges()
402{
403 if (isValid()) {
404 //setup property change notifications for all existing devices
405 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
406 reply.waitForFinished();
407 if (reply.isError())
408 return;
409
410 OrgFreedesktopDBusPropertiesInterface *monitor = nullptr;
411
412 ManagedObjectList managedObjectList = reply.value();
413 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
414 const QDBusObjectPath &path = it.key();
415 const InterfaceList &ifaceList = it.value();
416
417 // don't track connected devices from other adapters but the current
418 if (!objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: path.path()))
419 continue;
420
421 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
422 const QString &iface = jt.key();
423 const QVariantMap &ifaceValues = jt.value();
424
425 if (iface == QStringLiteral("org.bluez.Device1")) {
426 monitor = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.bluez"),
427 path.path(),
428 QDBusConnection::systemBus(), this);
429 connect(sender: monitor, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
430 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
431 deviceChangeMonitors.insert(key: path.path(), value: monitor);
432
433 if (ifaceValues.value(QStringLiteral("Connected"), defaultValue: false).toBool()) {
434 QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
435 connectedDevicesSet.insert(value: address);
436 }
437 }
438 }
439 }
440 }
441}
442
443QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
444{
445 delete adapter;
446 delete adapterProperties;
447 delete manager;
448 delete pairingTarget;
449
450 qDeleteAll(c: deviceChangeMonitors);
451}
452
453void QBluetoothLocalDevicePrivate::initializeAdapter()
454{
455 if (adapter)
456 return;
457
458 //get all local adapters
459 if (!manager)
460 manager = new OrgFreedesktopDBusObjectManagerInterface(
461 QStringLiteral("org.bluez"),
462 QStringLiteral("/"),
463 QDBusConnection::systemBus(), this);
464
465 connect(sender: manager, signal: &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
466 context: this, slot: &QBluetoothLocalDevicePrivate::InterfacesAdded);
467 connect(sender: manager, signal: &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
468 context: this, slot: &QBluetoothLocalDevicePrivate::InterfacesRemoved);
469
470 bool ok = true;
471 const QString adapterPath = findAdapterForAddress(wantedAddress: localAddress, ok: &ok);
472 if (!ok || adapterPath.isEmpty())
473 return;
474
475 deviceAdapterPath = adapterPath;
476 adapter = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), adapterPath,
477 QDBusConnection::systemBus(), this);
478
479 if (adapter) {
480 //hook up propertiesChanged for current adapter
481 adapterProperties = new OrgFreedesktopDBusPropertiesInterface(
482 QStringLiteral("org.bluez"), adapter->path(),
483 QDBusConnection::systemBus(), this);
484 connect(sender: adapterProperties, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
485 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
486 }
487}
488
489void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
490 const QVariantMap &changed_properties,
491 const QStringList &/*invalidated_properties*/,
492 const QDBusMessage &)
493{
494 //qDebug() << "Change" << interface << changed_properties;
495 if (interface == QStringLiteral("org.bluez.Adapter1")) {
496 //update host mode
497 if (changed_properties.contains(QStringLiteral("Discoverable"))
498 || changed_properties.contains(QStringLiteral("Powered"))) {
499
500 QBluetoothLocalDevice::HostMode mode;
501
502 if (!adapter->powered()) {
503 mode = QBluetoothLocalDevice::HostPoweredOff;
504 } else {
505 if (adapter->discoverable())
506 mode = QBluetoothLocalDevice::HostDiscoverable;
507 else
508 mode = QBluetoothLocalDevice::HostConnectable;
509
510 if (pendingHostModeChange != -1) {
511
512 if (static_cast<int>(mode) != pendingHostModeChange) {
513 adapter->setDiscoverable(
514 pendingHostModeChange
515 == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable));
516 pendingHostModeChange = -1;
517 return;
518 }
519 pendingHostModeChange = -1;
520 }
521 }
522
523 if (mode != currentMode)
524 emit q_ptr->hostModeStateChanged(state: mode);
525
526 currentMode = mode;
527 }
528 } else if (interface == QStringLiteral("org.bluez.Device1")
529 && changed_properties.contains(QStringLiteral("Connected"))) {
530 // update list of connected devices
531 OrgFreedesktopDBusPropertiesInterface *senderIface =
532 qobject_cast<OrgFreedesktopDBusPropertiesInterface*>(object: sender());
533 if (!senderIface)
534 return;
535
536 const QString currentPath = senderIface->path();
537 bool isConnected = changed_properties.value(QStringLiteral("Connected"), defaultValue: false).toBool();
538 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), currentPath,
539 QDBusConnection::systemBus());
540 const QBluetoothAddress changedAddress(device.address());
541 bool isInSet = connectedDevicesSet.contains(value: changedAddress);
542 if (isConnected && !isInSet) {
543 connectedDevicesSet.insert(value: changedAddress);
544 emit q_ptr->deviceConnected(address: changedAddress);
545 } else if (!isConnected && isInSet) {
546 connectedDevicesSet.remove(value: changedAddress);
547 emit q_ptr->deviceDisconnected(address: changedAddress);
548 }
549 }
550}
551
552void QBluetoothLocalDevicePrivate::InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties)
553{
554 if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))
555 && !deviceChangeMonitors.contains(key: object_path.path())) {
556 // a new device was added which we need to add to list of known devices
557
558 if (objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: object_path.path())) {
559 OrgFreedesktopDBusPropertiesInterface *monitor = new OrgFreedesktopDBusPropertiesInterface(
560 QStringLiteral("org.bluez"),
561 object_path.path(),
562 QDBusConnection::systemBus());
563 connect(sender: monitor, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
564 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
565 deviceChangeMonitors.insert(key: object_path.path(), value: monitor);
566
567 const QVariantMap ifaceValues = interfaces_and_properties.value(QStringLiteral("org.bluez.Device1"));
568 if (ifaceValues.value(QStringLiteral("Connected"), defaultValue: false).toBool()) {
569 QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
570 connectedDevicesSet.insert(value: address);
571 emit q_ptr->deviceConnected(address);
572 }
573 }
574 }
575
576 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()
577 && interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) {
578 //device discovery for pairing found new remote device
579 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
580 object_path.path(), QDBusConnection::systemBus());
581 if (!address.isNull() && address == QBluetoothAddress(device.address()))
582 processPairing(objectPath: object_path.path(), target: pairing);
583 }
584}
585
586void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &object_path,
587 const QStringList &interfaces)
588{
589 if (deviceChangeMonitors.contains(key: object_path.path())
590 && interfaces.contains(str: QLatin1String("org.bluez.Device1"))) {
591
592 if (objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: object_path.path())) {
593 //a device was removed
594 delete deviceChangeMonitors.take(key: object_path.path());
595
596 //the path contains the address (e.g.: /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX)
597 //-> use it to update current list of connected devices
598 QString addressString = object_path.path().right(n: 17);
599 addressString.replace(QStringLiteral("_"), QStringLiteral(":"));
600 const QBluetoothAddress address(addressString);
601 bool found = connectedDevicesSet.remove(value: address);
602 if (found)
603 emit q_ptr->deviceDisconnected(address);
604 }
605 }
606
607 if (adapter && object_path.path() == adapter->path()
608 && interfaces.contains(str: QLatin1String("org.bluez.Adapter1"))) {
609 qCDebug(QT_BT_BLUEZ) << "Adapter" << adapter->path() << "was removed";
610 // current adapter was removed -> invalidate the instance
611 delete adapter;
612 adapter = nullptr;
613 manager->deleteLater();
614 manager = nullptr;
615 delete adapterProperties;
616 adapterProperties = nullptr;
617
618 delete pairingTarget;
619 pairingTarget = nullptr;
620
621 // turn off connectivity monitoring
622 qDeleteAll(c: deviceChangeMonitors);
623 deviceChangeMonitors.clear();
624 connectedDevicesSet.clear();
625 }
626}
627
628bool QBluetoothLocalDevicePrivate::isValid() const
629{
630 return adapter && manager;
631}
632
633QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
634{
635 return connectedDevicesSet.values();
636}
637
638void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *watcher)
639{
640 Q_Q(QBluetoothLocalDevice);
641 QDBusPendingReply<> reply = *watcher;
642
643 if (reply.isError()) {
644 qCWarning(QT_BT_BLUEZ) << "Failed to create pairing" << reply.error().name();
645 const bool canceledByUs =
646 (reply.error().name() == QStringLiteral("org.bluez.Error.AuthenticationCanceled"))
647 && pairingRequestCanceled;
648 if (!canceledByUs)
649 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
650
651 pairingRequestCanceled = false;
652 watcher->deleteLater();
653 return;
654 }
655
656 pairingRequestCanceled = false;
657
658 if (adapter) {
659 if (!pairingTarget) {
660 qCWarning(QT_BT_BLUEZ) << "Pairing target expected but found null pointer.";
661 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
662 watcher->deleteLater();
663 return;
664 }
665
666 if (!pairingTarget->paired()) {
667 qCWarning(QT_BT_BLUEZ) << "Device was not paired as requested";
668 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
669 watcher->deleteLater();
670 return;
671 }
672
673 const QBluetoothAddress targetAddress(pairingTarget->address());
674
675 if (pairing == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
676 pairingTarget->setTrusted(true);
677 else if (pairing == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
678 pairingTarget->setTrusted(false);
679
680 delete pairingTarget;
681 pairingTarget = nullptr;
682
683 emit q->pairingFinished(address: targetAddress, pairing);
684 }
685
686 watcher->deleteLater();
687}
688
689QT_END_NAMESPACE
690
691#include "moc_qbluetoothlocaldevice_p.cpp"
692

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtconnectivity/src/bluetooth/qbluetoothlocaldevice_bluez.cpp