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 cancelReply.waitForFinished();
173 delete d_ptr->pairingTarget;
174 d_ptr->pairingTarget = nullptr;
175 }
176 }
177 QMetaObject::invokeMethod(obj: this, member: "pairingFinished", c: Qt::QueuedConnection,
178 Q_ARG(QBluetoothAddress, address),
179 Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
180 return;
181 }
182
183 d_ptr->requestPairing(address, targetPairing: pairing);
184}
185
186void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &targetAddress,
187 QBluetoothLocalDevice::Pairing targetPairing)
188{
189 if (!isValid())
190 return;
191
192 //are we already discovering something? -> abort those attempts
193 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
194 pairingDiscoveryTimer->stop();
195 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
196 }
197
198 if (pairingTarget) {
199 delete pairingTarget;
200 pairingTarget = nullptr;
201 }
202
203 // pairing implies that the device was found
204 // if we cannot find it we may have to turn on Discovery mode for a limited amount of time
205
206 // check device doesn't already exist
207 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
208 reply.waitForFinished();
209 if (reply.isError()) {
210 emit q_ptr->errorOccurred(error: QBluetoothLocalDevice::PairingError);
211 return;
212 }
213
214 ManagedObjectList managedObjectList = reply.value();
215 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
216 const QDBusObjectPath &path = it.key();
217 const InterfaceList &ifaceList = it.value();
218
219 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
220 const QString &iface = jt.key();
221
222 if (iface == QStringLiteral("org.bluez.Device1")) {
223
224 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
225 path.path(),
226 QDBusConnection::systemBus());
227 if (targetAddress == QBluetoothAddress(device.address())) {
228 qCDebug(QT_BT_BLUEZ) << "Initiating direct pair to" << targetAddress.toString();
229 //device exist -> directly work with it
230 processPairing(objectPath: path.path(), target: targetPairing);
231 return;
232 }
233 }
234 }
235 }
236
237 //no device matching -> turn on discovery
238 QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapterPath: adapter->path());
239
240 address = targetAddress;
241 pairing = targetPairing;
242 if (!pairingDiscoveryTimer) {
243 pairingDiscoveryTimer = new QTimer(this);
244 pairingDiscoveryTimer->setSingleShot(true);
245 pairingDiscoveryTimer->setInterval(20000); //20s
246 connect(sender: pairingDiscoveryTimer, signal: &QTimer::timeout,
247 context: this, slot: &QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut);
248 }
249
250 qCDebug(QT_BT_BLUEZ) << "Initiating discovery for pairing on" << targetAddress.toString();
251 pairingDiscoveryTimer->start();
252}
253
254/*!
255 * \internal
256 *
257 * Found a matching device. Now we must ensure its pairing/trusted state is as desired.
258 * If it has to be paired then we need another roundtrip through the event loop
259 * while we wait for the user to accept the pairing dialogs.
260 */
261void QBluetoothLocalDevicePrivate::processPairing(const QString &objectPath,
262 QBluetoothLocalDevice::Pairing target)
263{
264 if (pairingTarget)
265 delete pairingTarget;
266
267 //stop possibly running discovery
268 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
269 pairingDiscoveryTimer->stop();
270
271 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
272 }
273
274 pairingTarget = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"), objectPath,
275 QDBusConnection::systemBus(), this);
276 const QBluetoothAddress targetAddress(pairingTarget->address());
277
278 Q_Q(QBluetoothLocalDevice);
279
280 switch (target) {
281 case QBluetoothLocalDevice::Unpaired: {
282 delete pairingTarget;
283 pairingTarget = nullptr;
284
285 QDBusPendingReply<> removeReply = adapter->RemoveDevice(device: QDBusObjectPath(objectPath));
286 auto watcher = new QDBusPendingCallWatcher(removeReply, this);
287 connect(sender: watcher, signal: &QDBusPendingCallWatcher::finished,
288 context: this, slot: [q, targetAddress](QDBusPendingCallWatcher* watcher){
289 QDBusPendingReply<> reply = *watcher;
290 if (reply.isError())
291 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
292 else
293 emit q->pairingFinished(address: targetAddress, pairing: QBluetoothLocalDevice::Unpaired);
294
295 watcher->deleteLater();
296 });
297 break;
298 }
299 case QBluetoothLocalDevice::Paired:
300 case QBluetoothLocalDevice::AuthorizedPaired:
301 pairing = target;
302
303 if (!pairingTarget->paired()) {
304 qCDebug(QT_BT_BLUEZ) << "Sending pairing request to" << pairingTarget->address();
305 //initiate the pairing
306 QDBusPendingReply<> pairReply = pairingTarget->Pair();
307 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pairReply, this);
308 connect(sender: watcher, signal: &QDBusPendingCallWatcher::finished,
309 context: this, slot: &QBluetoothLocalDevicePrivate::pairingCompleted);
310 return;
311 }
312
313 //already paired but Trust level must be adjusted
314 if (target == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
315 pairingTarget->setTrusted(true);
316 else if (target == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
317 pairingTarget->setTrusted(false);
318
319 delete pairingTarget;
320 pairingTarget = nullptr;
321
322 emit q->pairingFinished(address: targetAddress, pairing: target);
323
324 break;
325 default:
326 break;
327 }
328}
329
330void QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut()
331{
332 qCWarning(QT_BT_BLUEZ) << "Discovery for pairing purposes failed. Cannot find parable device.";
333
334 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapterPath: adapter->path());
335
336 emit q_ptr->errorOccurred(error: QBluetoothLocalDevice::PairingError);
337}
338
339QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
340 const QBluetoothAddress &address) const
341{
342 if (address.isNull())
343 return Unpaired;
344
345 if (isValid())
346 {
347 QDBusPendingReply<ManagedObjectList> reply = d_ptr->manager->GetManagedObjects();
348 reply.waitForFinished();
349 if (reply.isError())
350 return Unpaired;
351
352 ManagedObjectList managedObjectList = reply.value();
353 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
354 const QDBusObjectPath &path = it.key();
355 const InterfaceList &ifaceList = it.value();
356
357 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
358 const QString &iface = jt.key();
359
360 if (iface == QStringLiteral("org.bluez.Device1")) {
361
362 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
363 path.path(),
364 QDBusConnection::systemBus());
365
366 if (address == QBluetoothAddress(device.address())) {
367 if (device.trusted() && device.paired())
368 return AuthorizedPaired;
369 else if (device.paired())
370 return Paired;
371 else
372 return Unpaired;
373 }
374 }
375 }
376 }
377 }
378
379 return Unpaired;
380}
381
382QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
383 QBluetoothAddress address) :
384 localAddress(address),
385 pendingHostModeChange(-1),
386 q_ptr(q)
387{
388 registerQBluetoothLocalDeviceMetaType();
389 initializeBluez5();
390 initializeAdapter();
391
392 connectDeviceChanges();
393}
394
395bool objectPathIsForThisDevice(const QString &adapterPath, const QString &objectPath)
396{
397 return (!adapterPath.isEmpty() && objectPath.startsWith(s: adapterPath));
398}
399
400void QBluetoothLocalDevicePrivate::connectDeviceChanges()
401{
402 if (isValid()) {
403 //setup property change notifications for all existing devices
404 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
405 reply.waitForFinished();
406 if (reply.isError())
407 return;
408
409 OrgFreedesktopDBusPropertiesInterface *monitor = nullptr;
410
411 ManagedObjectList managedObjectList = reply.value();
412 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
413 const QDBusObjectPath &path = it.key();
414 const InterfaceList &ifaceList = it.value();
415
416 // don't track connected devices from other adapters but the current
417 if (!objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: path.path()))
418 continue;
419
420 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
421 const QString &iface = jt.key();
422 const QVariantMap &ifaceValues = jt.value();
423
424 if (iface == QStringLiteral("org.bluez.Device1")) {
425 monitor = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.bluez"),
426 path.path(),
427 QDBusConnection::systemBus(), this);
428 connect(sender: monitor, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
429 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
430 deviceChangeMonitors.insert(key: path.path(), value: monitor);
431
432 if (ifaceValues.value(QStringLiteral("Connected"), defaultValue: false).toBool()) {
433 QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
434 connectedDevicesSet.insert(value: address);
435 }
436 }
437 }
438 }
439 }
440}
441
442QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
443{
444 delete adapter;
445 delete adapterProperties;
446 delete manager;
447 delete pairingTarget;
448
449 qDeleteAll(c: deviceChangeMonitors);
450}
451
452void QBluetoothLocalDevicePrivate::initializeAdapter()
453{
454 if (adapter)
455 return;
456
457 //get all local adapters
458 if (!manager)
459 manager = new OrgFreedesktopDBusObjectManagerInterface(
460 QStringLiteral("org.bluez"),
461 QStringLiteral("/"),
462 QDBusConnection::systemBus(), this);
463
464 connect(sender: manager, signal: &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
465 context: this, slot: &QBluetoothLocalDevicePrivate::InterfacesAdded);
466 connect(sender: manager, signal: &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
467 context: this, slot: &QBluetoothLocalDevicePrivate::InterfacesRemoved);
468
469 bool ok = true;
470 const QString adapterPath = findAdapterForAddress(wantedAddress: localAddress, ok: &ok);
471 if (!ok || adapterPath.isEmpty())
472 return;
473
474 deviceAdapterPath = adapterPath;
475 adapter = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), adapterPath,
476 QDBusConnection::systemBus(), this);
477
478 if (adapter) {
479 //hook up propertiesChanged for current adapter
480 adapterProperties = new OrgFreedesktopDBusPropertiesInterface(
481 QStringLiteral("org.bluez"), adapter->path(),
482 QDBusConnection::systemBus(), this);
483 connect(sender: adapterProperties, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
484 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
485 }
486}
487
488void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
489 const QVariantMap &changed_properties,
490 const QStringList &/*invalidated_properties*/,
491 const QDBusMessage &)
492{
493 //qDebug() << "Change" << interface << changed_properties;
494 if (interface == QStringLiteral("org.bluez.Adapter1")) {
495 //update host mode
496 if (changed_properties.contains(QStringLiteral("Discoverable"))
497 || changed_properties.contains(QStringLiteral("Powered"))) {
498
499 QBluetoothLocalDevice::HostMode mode;
500
501 if (!adapter->powered()) {
502 mode = QBluetoothLocalDevice::HostPoweredOff;
503 } else {
504 if (adapter->discoverable())
505 mode = QBluetoothLocalDevice::HostDiscoverable;
506 else
507 mode = QBluetoothLocalDevice::HostConnectable;
508
509 if (pendingHostModeChange != -1) {
510
511 if (static_cast<int>(mode) != pendingHostModeChange) {
512 adapter->setDiscoverable(
513 pendingHostModeChange
514 == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable));
515 pendingHostModeChange = -1;
516 return;
517 }
518 pendingHostModeChange = -1;
519 }
520 }
521
522 if (mode != currentMode)
523 emit q_ptr->hostModeStateChanged(state: mode);
524
525 currentMode = mode;
526 }
527 } else if (interface == QStringLiteral("org.bluez.Device1")
528 && changed_properties.contains(QStringLiteral("Connected"))) {
529 // update list of connected devices
530 OrgFreedesktopDBusPropertiesInterface *senderIface =
531 qobject_cast<OrgFreedesktopDBusPropertiesInterface*>(object: sender());
532 if (!senderIface)
533 return;
534
535 const QString currentPath = senderIface->path();
536 bool isConnected = changed_properties.value(QStringLiteral("Connected"), defaultValue: false).toBool();
537 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), currentPath,
538 QDBusConnection::systemBus());
539 const QBluetoothAddress changedAddress(device.address());
540 bool isInSet = connectedDevicesSet.contains(value: changedAddress);
541 if (isConnected && !isInSet) {
542 connectedDevicesSet.insert(value: changedAddress);
543 emit q_ptr->deviceConnected(address: changedAddress);
544 } else if (!isConnected && isInSet) {
545 connectedDevicesSet.remove(value: changedAddress);
546 emit q_ptr->deviceDisconnected(address: changedAddress);
547 }
548 }
549}
550
551void QBluetoothLocalDevicePrivate::InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties)
552{
553 if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))
554 && !deviceChangeMonitors.contains(key: object_path.path())) {
555 // a new device was added which we need to add to list of known devices
556
557 if (objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: object_path.path())) {
558 OrgFreedesktopDBusPropertiesInterface *monitor = new OrgFreedesktopDBusPropertiesInterface(
559 QStringLiteral("org.bluez"),
560 object_path.path(),
561 QDBusConnection::systemBus());
562 connect(sender: monitor, signal: &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
563 context: this, slot: &QBluetoothLocalDevicePrivate::PropertiesChanged);
564 deviceChangeMonitors.insert(key: object_path.path(), value: monitor);
565
566 const QVariantMap ifaceValues = interfaces_and_properties.value(QStringLiteral("org.bluez.Device1"));
567 if (ifaceValues.value(QStringLiteral("Connected"), defaultValue: false).toBool()) {
568 QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
569 connectedDevicesSet.insert(value: address);
570 emit q_ptr->deviceConnected(address);
571 }
572 }
573 }
574
575 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()
576 && interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) {
577 //device discovery for pairing found new remote device
578 OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
579 object_path.path(), QDBusConnection::systemBus());
580 if (!address.isNull() && address == QBluetoothAddress(device.address()))
581 processPairing(objectPath: object_path.path(), target: pairing);
582 }
583}
584
585void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &object_path,
586 const QStringList &interfaces)
587{
588 if (deviceChangeMonitors.contains(key: object_path.path())
589 && interfaces.contains(str: QLatin1String("org.bluez.Device1"))) {
590
591 if (objectPathIsForThisDevice(adapterPath: deviceAdapterPath, objectPath: object_path.path())) {
592 //a device was removed
593 delete deviceChangeMonitors.take(key: object_path.path());
594
595 //the path contains the address (e.g.: /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX)
596 //-> use it to update current list of connected devices
597 QString addressString = object_path.path().right(n: 17);
598 addressString.replace(QStringLiteral("_"), QStringLiteral(":"));
599 const QBluetoothAddress address(addressString);
600 bool found = connectedDevicesSet.remove(value: address);
601 if (found)
602 emit q_ptr->deviceDisconnected(address);
603 }
604 }
605
606 if (adapter && object_path.path() == adapter->path()
607 && interfaces.contains(str: QLatin1String("org.bluez.Adapter1"))) {
608 qCDebug(QT_BT_BLUEZ) << "Adapter" << adapter->path() << "was removed";
609 // current adapter was removed -> invalidate the instance
610 delete adapter;
611 adapter = nullptr;
612 manager->deleteLater();
613 manager = nullptr;
614 delete adapterProperties;
615 adapterProperties = nullptr;
616
617 delete pairingTarget;
618 pairingTarget = nullptr;
619
620 // turn off connectivity monitoring
621 qDeleteAll(c: deviceChangeMonitors);
622 deviceChangeMonitors.clear();
623 connectedDevicesSet.clear();
624 }
625}
626
627bool QBluetoothLocalDevicePrivate::isValid() const
628{
629 return adapter && manager;
630}
631
632QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
633{
634 return connectedDevicesSet.values();
635}
636
637void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *watcher)
638{
639 Q_Q(QBluetoothLocalDevice);
640 QDBusPendingReply<> reply = *watcher;
641
642 if (reply.isError()) {
643 qCWarning(QT_BT_BLUEZ) << "Failed to create pairing" << reply.error().name();
644 if (reply.error().name() != QStringLiteral("org.bluez.Error.AuthenticationCanceled"))
645 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
646 watcher->deleteLater();
647 return;
648 }
649
650 if (adapter) {
651 if (!pairingTarget) {
652 qCWarning(QT_BT_BLUEZ) << "Pairing target expected but found null pointer.";
653 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
654 watcher->deleteLater();
655 return;
656 }
657
658 if (!pairingTarget->paired()) {
659 qCWarning(QT_BT_BLUEZ) << "Device was not paired as requested";
660 emit q->errorOccurred(error: QBluetoothLocalDevice::PairingError);
661 watcher->deleteLater();
662 return;
663 }
664
665 const QBluetoothAddress targetAddress(pairingTarget->address());
666
667 if (pairing == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
668 pairingTarget->setTrusted(true);
669 else if (pairing == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
670 pairingTarget->setTrusted(false);
671
672 delete pairingTarget;
673 pairingTarget = nullptr;
674
675 emit q->pairingFinished(address: targetAddress, pairing);
676 }
677
678 watcher->deleteLater();
679}
680
681QT_END_NAMESPACE
682
683#include "moc_qbluetoothlocaldevice_p.cpp"
684

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