4#include <QtCore/QLoggingCategory>
5#include <QtCore/QRandomGenerator>
6#include <QtDBus/QDBusContext>
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"
20Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
22using namespace QtBluetoothPrivate;
24QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
26 d_ptr(
new QBluetoothLocalDevicePrivate(
this))
28 d_ptr->currentMode = hostMode();
31QBluetoothLocalDevice::QBluetoothLocalDevice(
const QBluetoothAddress &address, QObject *parent) :
33 d_ptr(
new QBluetoothLocalDevicePrivate(
this, address))
35 d_ptr->currentMode = hostMode();
38QString QBluetoothLocalDevice::name()
const
41 return d_ptr->adapter->alias();
46QBluetoothAddress QBluetoothLocalDevice::address()
const
49 return QBluetoothAddress(d_ptr->adapter->address());
51 return QBluetoothAddress();
54void QBluetoothLocalDevice::powerOn()
57 d_ptr->adapter->setPowered(
true);
60void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
65 Q_D(QBluetoothLocalDevice);
67 if (d->pendingHostModeChange != -1) {
68 qCWarning(QT_BT_BLUEZ) <<
"setHostMode() ignored due to already pending mode change";
73 case HostDiscoverableLimitedInquiry:
74 case HostDiscoverable:
75 if (hostMode() == HostPoweredOff) {
78 d->pendingHostModeChange =
static_cast<
int>(HostDiscoverable);
79 d->adapter->setPowered(
true);
81 d->adapter->setDiscoverable(
true);
85 if (hostMode() == HostPoweredOff) {
86 d->pendingHostModeChange =
static_cast<
int>(HostConnectable);
87 d->adapter->setPowered(
true);
89 d->adapter->setDiscoverable(
false);
93 d->adapter->setPowered(
false);
98QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode()
const
100 if (d_ptr->adapter) {
101 if (!d_ptr->adapter->powered())
102 return HostPoweredOff;
103 else if (d_ptr->adapter->discoverable())
104 return HostDiscoverable;
105 else if (d_ptr->adapter->powered())
106 return HostConnectable;
109 return HostPoweredOff;
112QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices()
const
114 return d_ptr->connectedDevices();
117QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
119 QList<QBluetoothHostInfo> localDevices;
122 OrgFreedesktopDBusObjectManagerInterface manager(
123 QStringLiteral(
"org.bluez"), QStringLiteral(
"/"), QDBusConnection::systemBus());
124 QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
125 reply.waitForFinished();
129 ManagedObjectList managedObjectList = reply.value();
130 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
131 it != managedObjectList.constEnd(); ++it) {
132 const InterfaceList &ifaceList = it.value();
134 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
136 const QString &iface = jt.key();
137 const QVariantMap &ifaceValues = jt.value();
139 if (iface == QStringLiteral(
"org.bluez.Adapter1")) {
140 QBluetoothHostInfo hostInfo;
141 const QString temp = ifaceValues.value(QStringLiteral(
"Address")).toString();
143 hostInfo.setAddress(QBluetoothAddress(temp));
144 if (hostInfo.address().isNull())
146 hostInfo.setName(ifaceValues.value(QStringLiteral(
"Name")).toString());
147 localDevices.append(hostInfo);
154void QBluetoothLocalDevice::requestPairing(
const QBluetoothAddress &address, Pairing pairing)
156 if (!isValid() || address.isNull()) {
157 QMetaObject::invokeMethod(
this,
"errorOccurred", Qt::QueuedConnection,
158 Q_ARG(QBluetoothLocalDevice::Error,
159 QBluetoothLocalDevice::PairingError));
163 const Pairing current_pairing = pairingStatus(address);
164 if (current_pairing == pairing) {
165 if (d_ptr->adapter) {
167 if (d_ptr->pairingDiscoveryTimer && d_ptr->pairingDiscoveryTimer->isActive()) {
168 d_ptr->pairingDiscoveryTimer->stop();
171 if (d_ptr->pairingTarget) {
172 qCDebug(QT_BT_BLUEZ) <<
"Cancelling pending pairing request to" << d_ptr->pairingTarget->address();
173 QDBusPendingReply<> cancelReply = d_ptr->pairingTarget->CancelPairing();
174 d_ptr->pairingRequestCanceled =
true;
175 cancelReply.waitForFinished();
176 delete d_ptr->pairingTarget;
177 d_ptr->pairingTarget =
nullptr;
180 QMetaObject::invokeMethod(
this,
"pairingFinished", Qt::QueuedConnection,
181 Q_ARG(QBluetoothAddress, address),
182 Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
186 d_ptr->requestPairing(address, pairing);
190 QBluetoothLocalDevice::Pairing targetPairing)
196 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
197 pairingDiscoveryTimer->stop();
198 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
202 delete pairingTarget;
203 pairingTarget =
nullptr;
210 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
211 reply.waitForFinished();
212 if (reply.isError()) {
213 emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
218 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
219 const QDBusObjectPath &path = it.key();
220 const InterfaceList &ifaceList = it.value();
222 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
223 const QString &iface = jt.key();
225 if (iface == QStringLiteral(
"org.bluez.Device1")) {
227 OrgBluezDevice1Interface device(QStringLiteral(
"org.bluez"),
229 QDBusConnection::systemBus());
230 if (targetAddress == QBluetoothAddress(device.address())) {
231 qCDebug(QT_BT_BLUEZ) <<
"Initiating direct pair to" << targetAddress.toString();
233 processPairing(path.path(), targetPairing);
241 QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapter->path());
243 address = targetAddress;
244 pairing = targetPairing;
245 if (!pairingDiscoveryTimer) {
246 pairingDiscoveryTimer =
new QTimer(
this);
247 pairingDiscoveryTimer->setSingleShot(
true);
248 pairingDiscoveryTimer->setInterval(20000);
249 connect(pairingDiscoveryTimer, &QTimer::timeout,
250 this, &QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut);
253 qCDebug(QT_BT_BLUEZ) <<
"Initiating discovery for pairing on" << targetAddress.toString();
254 pairingDiscoveryTimer->start();
258
259
260
261
262
263
265 QBluetoothLocalDevice::Pairing target)
268 delete pairingTarget;
271 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
272 pairingDiscoveryTimer->stop();
274 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
277 pairingTarget =
new OrgBluezDevice1Interface(QStringLiteral(
"org.bluez"), objectPath,
278 QDBusConnection::systemBus(),
this);
279 const QBluetoothAddress targetAddress(pairingTarget->address());
281 Q_Q(QBluetoothLocalDevice);
284 case QBluetoothLocalDevice::Unpaired: {
285 delete pairingTarget;
286 pairingTarget =
nullptr;
288 QDBusPendingReply<> removeReply = adapter->RemoveDevice(QDBusObjectPath(objectPath));
289 auto watcher =
new QDBusPendingCallWatcher(removeReply,
this);
290 connect(watcher, &QDBusPendingCallWatcher::finished,
291 this, [q, targetAddress](QDBusPendingCallWatcher* watcher){
292 QDBusPendingReply<> reply = *watcher;
294 emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
296 emit q->pairingFinished(targetAddress, QBluetoothLocalDevice::Unpaired);
298 watcher->deleteLater();
302 case QBluetoothLocalDevice::Paired:
303 case QBluetoothLocalDevice::AuthorizedPaired:
306 if (!pairingTarget->paired()) {
307 qCDebug(QT_BT_BLUEZ) <<
"Sending pairing request to" << pairingTarget->address();
309 QDBusPendingReply<> pairReply = pairingTarget->Pair();
310 QDBusPendingCallWatcher *watcher =
new QDBusPendingCallWatcher(pairReply,
this);
311 connect(watcher, &QDBusPendingCallWatcher::finished,
312 this, &QBluetoothLocalDevicePrivate::pairingCompleted);
317 if (target == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
318 pairingTarget->setTrusted(
true);
319 else if (target == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
320 pairingTarget->setTrusted(
false);
322 delete pairingTarget;
323 pairingTarget =
nullptr;
325 emit q->pairingFinished(targetAddress, target);
335 qCWarning(QT_BT_BLUEZ) <<
"Discovery for pairing purposes failed. Cannot find parable device.";
337 QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
339 emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
342QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
343 const QBluetoothAddress &address)
const
345 if (address.isNull())
350 QDBusPendingReply<ManagedObjectList> reply = d_ptr->manager->GetManagedObjects();
351 reply.waitForFinished();
355 ManagedObjectList managedObjectList = reply.value();
356 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
357 const QDBusObjectPath &path = it.key();
358 const InterfaceList &ifaceList = it.value();
360 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
361 const QString &iface = jt.key();
363 if (iface == QStringLiteral(
"org.bluez.Device1")) {
365 OrgBluezDevice1Interface device(QStringLiteral(
"org.bluez"),
367 QDBusConnection::systemBus());
369 if (address == QBluetoothAddress(device.address())) {
370 if (device.trusted() && device.paired())
371 return AuthorizedPaired;
372 else if (device.paired())
386 QBluetoothAddress address) :
391 registerQBluetoothLocalDeviceMetaType();
395 connectDeviceChanges();
400 return (!adapterPath.isEmpty() && objectPath.startsWith(adapterPath));
407 QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
408 reply.waitForFinished();
412 OrgFreedesktopDBusPropertiesInterface *monitor =
nullptr;
415 for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
416 const QDBusObjectPath &path = it.key();
417 const InterfaceList &ifaceList = it.value();
420 if (!objectPathIsForThisDevice(deviceAdapterPath, path.path()))
423 for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
424 const QString &iface = jt.key();
425 const QVariantMap &ifaceValues = jt.value();
427 if (iface == QStringLiteral(
"org.bluez.Device1")) {
428 monitor =
new OrgFreedesktopDBusPropertiesInterface(QStringLiteral(
"org.bluez"),
430 QDBusConnection::systemBus(),
this);
431 connect(monitor, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
432 this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
433 deviceChangeMonitors.insert(path.path(), monitor);
435 if (ifaceValues.value(QStringLiteral(
"Connected"),
false).toBool()) {
436 QBluetoothAddress address(ifaceValues.value(QStringLiteral(
"Address")).toString());
437 connectedDevicesSet.insert(address);
448 delete adapterProperties;
450 delete pairingTarget;
452 qDeleteAll(deviceChangeMonitors);
462 manager =
new OrgFreedesktopDBusObjectManagerInterface(
463 QStringLiteral(
"org.bluez"),
465 QDBusConnection::systemBus(),
this);
467 connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
468 this, &QBluetoothLocalDevicePrivate::InterfacesAdded);
469 connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
470 this, &QBluetoothLocalDevicePrivate::InterfacesRemoved);
473 const QString adapterPath = findAdapterForAddress(localAddress, &ok);
474 if (!ok || adapterPath.isEmpty())
477 deviceAdapterPath = adapterPath;
478 adapter =
new OrgBluezAdapter1Interface(QStringLiteral(
"org.bluez"), adapterPath,
479 QDBusConnection::systemBus(),
this);
483 adapterProperties =
new OrgFreedesktopDBusPropertiesInterface(
484 QStringLiteral(
"org.bluez"), adapter->path(),
485 QDBusConnection::systemBus(),
this);
486 connect(adapterProperties, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
487 this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
492 const QVariantMap &changed_properties,
494 const QDBusMessage &)
497 if (interface == QStringLiteral(
"org.bluez.Adapter1")) {
499 if (changed_properties.contains(QStringLiteral(
"Discoverable"))
500 || changed_properties.contains(QStringLiteral(
"Powered"))) {
502 QBluetoothLocalDevice::HostMode mode;
504 if (!adapter->powered()) {
505 mode = QBluetoothLocalDevice::HostPoweredOff;
507 if (adapter->discoverable())
508 mode = QBluetoothLocalDevice::HostDiscoverable;
510 mode = QBluetoothLocalDevice::HostConnectable;
512 if (pendingHostModeChange != -1) {
514 if (
static_cast<
int>(mode) != pendingHostModeChange) {
515 adapter->setDiscoverable(
516 pendingHostModeChange
517 ==
static_cast<
int>(QBluetoothLocalDevice::HostDiscoverable));
518 pendingHostModeChange = -1;
521 pendingHostModeChange = -1;
525 if (mode != currentMode)
526 emit q_ptr->hostModeStateChanged(mode);
530 }
else if (interface == QStringLiteral(
"org.bluez.Device1")
531 && changed_properties.contains(QStringLiteral(
"Connected"))) {
533 OrgFreedesktopDBusPropertiesInterface *senderIface =
534 qobject_cast<OrgFreedesktopDBusPropertiesInterface*>(sender());
538 const QString currentPath = senderIface->path();
539 bool isConnected = changed_properties.value(QStringLiteral(
"Connected"),
false).toBool();
540 OrgBluezDevice1Interface device(QStringLiteral(
"org.bluez"), currentPath,
541 QDBusConnection::systemBus());
542 const QBluetoothAddress changedAddress(device.address());
543 bool isInSet = connectedDevicesSet.contains(changedAddress);
544 if (isConnected && !isInSet) {
545 connectedDevicesSet.insert(changedAddress);
546 emit q_ptr->deviceConnected(changedAddress);
547 }
else if (!isConnected && isInSet) {
548 connectedDevicesSet.remove(changedAddress);
549 emit q_ptr->deviceDisconnected(changedAddress);
556 if (interfaces_and_properties.contains(QStringLiteral(
"org.bluez.Device1"))
557 && !deviceChangeMonitors.contains(object_path.path())) {
560 if (objectPathIsForThisDevice(deviceAdapterPath, object_path.path())) {
561 OrgFreedesktopDBusPropertiesInterface *monitor =
new OrgFreedesktopDBusPropertiesInterface(
562 QStringLiteral(
"org.bluez"),
564 QDBusConnection::systemBus());
565 connect(monitor, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
566 this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
567 deviceChangeMonitors.insert(object_path.path(), monitor);
569 const QVariantMap ifaceValues = interfaces_and_properties.value(QStringLiteral(
"org.bluez.Device1"));
570 if (ifaceValues.value(QStringLiteral(
"Connected"),
false).toBool()) {
571 QBluetoothAddress address(ifaceValues.value(QStringLiteral(
"Address")).toString());
572 connectedDevicesSet.insert(address);
573 emit q_ptr->deviceConnected(address);
578 if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()
579 && interfaces_and_properties.contains(QStringLiteral(
"org.bluez.Device1"))) {
581 OrgBluezDevice1Interface device(QStringLiteral(
"org.bluez"),
582 object_path.path(), QDBusConnection::systemBus());
583 if (!address.isNull() && address == QBluetoothAddress(device.address()))
584 processPairing(object_path.path(), pairing);
589 const QStringList &interfaces)
591 if (deviceChangeMonitors.contains(object_path.path())
592 && interfaces.contains(QLatin1String(
"org.bluez.Device1"))) {
594 if (objectPathIsForThisDevice(deviceAdapterPath, object_path.path())) {
596 delete deviceChangeMonitors.take(object_path.path());
600 QString addressString = object_path.path().right(17);
601 addressString.replace(QStringLiteral(
"_"), QStringLiteral(
":"));
602 const QBluetoothAddress address(addressString);
603 bool found = connectedDevicesSet.remove(address);
605 emit q_ptr->deviceDisconnected(address);
609 if (adapter && object_path.path() == adapter->path()
610 && interfaces.contains(QLatin1String(
"org.bluez.Adapter1"))) {
611 qCDebug(QT_BT_BLUEZ) <<
"Adapter" << adapter->path() <<
"was removed";
615 manager->deleteLater();
617 delete adapterProperties;
618 adapterProperties =
nullptr;
620 delete pairingTarget;
621 pairingTarget =
nullptr;
624 qDeleteAll(deviceChangeMonitors);
625 deviceChangeMonitors.clear();
626 connectedDevicesSet.clear();
632 return adapter && manager;
637 return connectedDevicesSet.values();
642 Q_Q(QBluetoothLocalDevice);
643 QDBusPendingReply<> reply = *watcher;
645 if (reply.isError()) {
646 qCWarning(QT_BT_BLUEZ) <<
"Failed to create pairing" << reply.error().name();
647 const bool canceledByUs =
648 (reply.error().name() == QStringLiteral(
"org.bluez.Error.AuthenticationCanceled"))
649 && pairingRequestCanceled;
651 emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
653 pairingRequestCanceled =
false;
654 watcher->deleteLater();
658 pairingRequestCanceled =
false;
661 if (!pairingTarget) {
662 qCWarning(QT_BT_BLUEZ) <<
"Pairing target expected but found null pointer.";
663 emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
664 watcher->deleteLater();
668 if (!pairingTarget->paired()) {
669 qCWarning(QT_BT_BLUEZ) <<
"Device was not paired as requested";
670 emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
671 watcher->deleteLater();
675 const QBluetoothAddress targetAddress(pairingTarget->address());
677 if (pairing == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
678 pairingTarget->setTrusted(
true);
679 else if (pairing == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
680 pairingTarget->setTrusted(
false);
682 delete pairingTarget;
683 pairingTarget =
nullptr;
685 emit q->pairingFinished(targetAddress, pairing);
688 watcher->deleteLater();
693#include "moc_qbluetoothlocaldevice_p.cpp"
QMap< QDBusObjectPath, InterfaceList > ManagedObjectList
QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *=nullptr, QBluetoothAddress=QBluetoothAddress())
bool objectPathIsForThisDevice(const QString &adapterPath, const QString &objectPath)