Revision control

++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include <QtCore/QLoggingCategory>
++ #include <QtCore/QRandomGenerator>
++ #include <QtDBus/QDBusContext>
++
++ #include "qbluetoothlocaldevice.h"
++ #include "qbluetoothaddress.h"
++ #include "qbluetoothlocaldevice_p.h"
++
++ #include "bluez/bluez5_helper_p.h"
++ #include "bluez/objectmanager_p.h"
++ #include "bluez/properties_p.h"
++ #include "bluez/adapter1_bluez5_p.h"
++ #include "bluez/device1_bluez5_p.h"
++
++ QT_BEGIN_NAMESPACE
++
++ Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
++
++ using namespace QtBluetoothPrivate; // for D-Bus wrappers
++
++ QBluetoothLocalDevice::QBluetoothLocalDevice(QObject *parent) :
++ QObject(parent),
++ d_ptr(new QBluetoothLocalDevicePrivate(this))
++ {
++ d_ptr->currentMode = hostMode();
++ }
++
++ QBluetoothLocalDevice::QBluetoothLocalDevice(const QBluetoothAddress &address, QObject *parent) :
++ QObject(parent),
++ d_ptr(new QBluetoothLocalDevicePrivate(this, address))
++ {
++ d_ptr->currentMode = hostMode();
++ }
++
++ QString QBluetoothLocalDevice::name() const
++ {
++ if (d_ptr->adapter)
++ return d_ptr->adapter->alias();
++
++ return QString();
++ }
++
++ QBluetoothAddress QBluetoothLocalDevice::address() const
++ {
++ if (d_ptr->adapter)
++ return QBluetoothAddress(d_ptr->adapter->address());
++
++ return QBluetoothAddress();
++ }
++
++ void QBluetoothLocalDevice::powerOn()
++ {
++ if (d_ptr->adapter)
++ d_ptr->adapter->setPowered(true);
++ }
++
++ void QBluetoothLocalDevice::setHostMode(QBluetoothLocalDevice::HostMode mode)
++ {
++ if (!isValid())
++ return;
++
++ Q_D(QBluetoothLocalDevice);
++
++ if (d->pendingHostModeChange != -1) {
++ qCWarning(QT_BT_BLUEZ) << "setHostMode() ignored due to already pending mode change";
++ return;
++ }
++
++ switch (mode) {
++ case HostDiscoverableLimitedInquiry:
++ case HostDiscoverable:
++ if (hostMode() == HostPoweredOff) {
++ // We first have to wait for BT to be powered on,
++ // then we can set the host mode correctly
++ d->pendingHostModeChange = static_cast<int>(HostDiscoverable);
++ d->adapter->setPowered(true);
++ } else {
++ d->adapter->setDiscoverable(true);
++ }
++ break;
++ case HostConnectable:
++ if (hostMode() == HostPoweredOff) {
++ d->pendingHostModeChange = static_cast<int>(HostConnectable);
++ d->adapter->setPowered(true);
++ } else {
++ d->adapter->setDiscoverable(false);
++ }
++ break;
++ case HostPoweredOff:
++ d->adapter->setPowered(false);
++ break;
++ }
++ }
++
++ QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
++ {
++ if (d_ptr->adapter) {
++ if (!d_ptr->adapter->powered())
++ return HostPoweredOff;
++ else if (d_ptr->adapter->discoverable())
++ return HostDiscoverable;
++ else if (d_ptr->adapter->powered())
++ return HostConnectable;
++ }
++
++ return HostPoweredOff;
++ }
++
++ QList<QBluetoothAddress> QBluetoothLocalDevice::connectedDevices() const
++ {
++ return d_ptr->connectedDevices();
++ }
++
++ QList<QBluetoothHostInfo> QBluetoothLocalDevice::allDevices()
++ {
++ QList<QBluetoothHostInfo> localDevices;
++
++ initializeBluez5();
++ OrgFreedesktopDBusObjectManagerInterface manager(
++ QStringLiteral("org.bluez"), QStringLiteral("/"), QDBusConnection::systemBus());
++ QDBusPendingReply<ManagedObjectList> reply = manager.GetManagedObjects();
++ reply.waitForFinished();
++ if (reply.isError())
++ return localDevices;
++
++ ManagedObjectList managedObjectList = reply.value();
++ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin();
++ it != managedObjectList.constEnd(); ++it) {
++ const InterfaceList &ifaceList = it.value();
++
++ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd();
++ ++jt) {
++ const QString &iface = jt.key();
++ const QVariantMap &ifaceValues = jt.value();
++
++ if (iface == QStringLiteral("org.bluez.Adapter1")) {
++ QBluetoothHostInfo hostInfo;
++ const QString temp = ifaceValues.value(QStringLiteral("Address")).toString();
++
++ hostInfo.setAddress(QBluetoothAddress(temp));
++ if (hostInfo.address().isNull())
++ continue;
++ hostInfo.setName(ifaceValues.value(QStringLiteral("Name")).toString());
++ localDevices.append(hostInfo);
++ }
++ }
++ }
++ return localDevices;
++ }
++
++ void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, Pairing pairing)
++ {
++ if (!isValid() || address.isNull()) {
++ QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
++ Q_ARG(QBluetoothLocalDevice::Error,
++ QBluetoothLocalDevice::PairingError));
++ return;
++ }
++
++ const Pairing current_pairing = pairingStatus(address);
++ if (current_pairing == pairing) {
++ if (d_ptr->adapter) {
++ // A possibly running discovery or pending pairing request should be canceled
++ if (d_ptr->pairingDiscoveryTimer && d_ptr->pairingDiscoveryTimer->isActive()) {
++ d_ptr->pairingDiscoveryTimer->stop();
++ }
++
++ if (d_ptr->pairingTarget) {
++ qCDebug(QT_BT_BLUEZ) << "Cancelling pending pairing request to" << d_ptr->pairingTarget->address();
++ QDBusPendingReply<> cancelReply = d_ptr->pairingTarget->CancelPairing();
++ d_ptr->pairingRequestCanceled = true;
++ cancelReply.waitForFinished();
++ delete d_ptr->pairingTarget;
++ d_ptr->pairingTarget = nullptr;
++ }
++ }
++ QMetaObject::invokeMethod(this, "pairingFinished", Qt::QueuedConnection,
++ Q_ARG(QBluetoothAddress, address),
++ Q_ARG(QBluetoothLocalDevice::Pairing, pairing));
++ return;
++ }
++
++ d_ptr->requestPairing(address, pairing);
++ }
++
++ void QBluetoothLocalDevicePrivate::requestPairing(const QBluetoothAddress &targetAddress,
++ QBluetoothLocalDevice::Pairing targetPairing)
++ {
++ if (!isValid())
++ return;
++
++ //are we already discovering something? -> abort those attempts
++ if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
++ pairingDiscoveryTimer->stop();
++ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
++ }
++
++ if (pairingTarget) {
++ delete pairingTarget;
++ pairingTarget = nullptr;
++ }
++
++ // pairing implies that the device was found
++ // if we cannot find it we may have to turn on Discovery mode for a limited amount of time
++
++ // check device doesn't already exist
++ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
++ reply.waitForFinished();
++ if (reply.isError()) {
++ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
++ return;
++ }
++
++ ManagedObjectList managedObjectList = reply.value();
++ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
++ const QDBusObjectPath &path = it.key();
++ const InterfaceList &ifaceList = it.value();
++
++ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
++ const QString &iface = jt.key();
++
++ if (iface == QStringLiteral("org.bluez.Device1")) {
++
++ OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
++ path.path(),
++ QDBusConnection::systemBus());
++ if (targetAddress == QBluetoothAddress(device.address())) {
++ qCDebug(QT_BT_BLUEZ) << "Initiating direct pair to" << targetAddress.toString();
++ //device exist -> directly work with it
++ processPairing(path.path(), targetPairing);
++ return;
++ }
++ }
++ }
++ }
++
++ //no device matching -> turn on discovery
++ QtBluezDiscoveryManager::instance()->registerDiscoveryInterest(adapter->path());
++
++ address = targetAddress;
++ pairing = targetPairing;
++ if (!pairingDiscoveryTimer) {
++ pairingDiscoveryTimer = new QTimer(this);
++ pairingDiscoveryTimer->setSingleShot(true);
++ pairingDiscoveryTimer->setInterval(20000); //20s
++ connect(pairingDiscoveryTimer, &QTimer::timeout,
++ this, &QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut);
++ }
++
++ qCDebug(QT_BT_BLUEZ) << "Initiating discovery for pairing on" << targetAddress.toString();
++ pairingDiscoveryTimer->start();
++ }
++
++ /*!
++ * \internal
++ *
++ * Found a matching device. Now we must ensure its pairing/trusted state is as desired.
++ * If it has to be paired then we need another roundtrip through the event loop
++ * while we wait for the user to accept the pairing dialogs.
++ */
++ void QBluetoothLocalDevicePrivate::processPairing(const QString &objectPath,
++ QBluetoothLocalDevice::Pairing target)
++ {
++ if (pairingTarget)
++ delete pairingTarget;
++
++ //stop possibly running discovery
++ if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()) {
++ pairingDiscoveryTimer->stop();
++
++ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
++ }
++
++ pairingTarget = new OrgBluezDevice1Interface(QStringLiteral("org.bluez"), objectPath,
++ QDBusConnection::systemBus(), this);
++ const QBluetoothAddress targetAddress(pairingTarget->address());
++
++ Q_Q(QBluetoothLocalDevice);
++
++ switch (target) {
++ case QBluetoothLocalDevice::Unpaired: {
++ delete pairingTarget;
++ pairingTarget = nullptr;
++
++ QDBusPendingReply<> removeReply = adapter->RemoveDevice(QDBusObjectPath(objectPath));
++ auto watcher = new QDBusPendingCallWatcher(removeReply, this);
++ connect(watcher, &QDBusPendingCallWatcher::finished,
++ this, [q, targetAddress](QDBusPendingCallWatcher* watcher){
++ QDBusPendingReply<> reply = *watcher;
++ if (reply.isError())
++ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
++ else
++ emit q->pairingFinished(targetAddress, QBluetoothLocalDevice::Unpaired);
++
++ watcher->deleteLater();
++ });
++ break;
++ }
++ case QBluetoothLocalDevice::Paired:
++ case QBluetoothLocalDevice::AuthorizedPaired:
++ pairing = target;
++
++ if (!pairingTarget->paired()) {
++ qCDebug(QT_BT_BLUEZ) << "Sending pairing request to" << pairingTarget->address();
++ //initiate the pairing
++ QDBusPendingReply<> pairReply = pairingTarget->Pair();
++ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pairReply, this);
++ connect(watcher, &QDBusPendingCallWatcher::finished,
++ this, &QBluetoothLocalDevicePrivate::pairingCompleted);
++ return;
++ }
++
++ //already paired but Trust level must be adjusted
++ if (target == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
++ pairingTarget->setTrusted(true);
++ else if (target == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
++ pairingTarget->setTrusted(false);
++
++ delete pairingTarget;
++ pairingTarget = nullptr;
++
++ emit q->pairingFinished(targetAddress, target);
++
++ break;
++ default:
++ break;
++ }
++ }
++
++ void QBluetoothLocalDevicePrivate::pairingDiscoveryTimedOut()
++ {
++ qCWarning(QT_BT_BLUEZ) << "Discovery for pairing purposes failed. Cannot find parable device.";
++
++ QtBluezDiscoveryManager::instance()->unregisterDiscoveryInterest(adapter->path());
++
++ emit q_ptr->errorOccurred(QBluetoothLocalDevice::PairingError);
++ }
++
++ QBluetoothLocalDevice::Pairing QBluetoothLocalDevice::pairingStatus(
++ const QBluetoothAddress &address) const
++ {
++ if (address.isNull())
++ return Unpaired;
++
++ if (isValid())
++ {
++ QDBusPendingReply<ManagedObjectList> reply = d_ptr->manager->GetManagedObjects();
++ reply.waitForFinished();
++ if (reply.isError())
++ return Unpaired;
++
++ ManagedObjectList managedObjectList = reply.value();
++ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
++ const QDBusObjectPath &path = it.key();
++ const InterfaceList &ifaceList = it.value();
++
++ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
++ const QString &iface = jt.key();
++
++ if (iface == QStringLiteral("org.bluez.Device1")) {
++
++ OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
++ path.path(),
++ QDBusConnection::systemBus());
++
++ if (address == QBluetoothAddress(device.address())) {
++ if (device.trusted() && device.paired())
++ return AuthorizedPaired;
++ else if (device.paired())
++ return Paired;
++ else
++ return Unpaired;
++ }
++ }
++ }
++ }
++ }
++
++ return Unpaired;
++ }
++
++ QBluetoothLocalDevicePrivate::QBluetoothLocalDevicePrivate(QBluetoothLocalDevice *q,
++ QBluetoothAddress address) :
++ localAddress(address),
++ pendingHostModeChange(-1),
++ q_ptr(q)
++ {
++ registerQBluetoothLocalDeviceMetaType();
++ initializeBluez5();
++ initializeAdapter();
++
++ connectDeviceChanges();
++ }
++
++ bool objectPathIsForThisDevice(const QString &adapterPath, const QString &objectPath)
++ {
++ return (!adapterPath.isEmpty() && objectPath.startsWith(adapterPath));
++ }
++
++ void QBluetoothLocalDevicePrivate::connectDeviceChanges()
++ {
++ if (isValid()) {
++ //setup property change notifications for all existing devices
++ QDBusPendingReply<ManagedObjectList> reply = manager->GetManagedObjects();
++ reply.waitForFinished();
++ if (reply.isError())
++ return;
++
++ OrgFreedesktopDBusPropertiesInterface *monitor = nullptr;
++
++ ManagedObjectList managedObjectList = reply.value();
++ for (ManagedObjectList::const_iterator it = managedObjectList.constBegin(); it != managedObjectList.constEnd(); ++it) {
++ const QDBusObjectPath &path = it.key();
++ const InterfaceList &ifaceList = it.value();
++
++ // don't track connected devices from other adapters but the current
++ if (!objectPathIsForThisDevice(deviceAdapterPath, path.path()))
++ continue;
++
++ for (InterfaceList::const_iterator jt = ifaceList.constBegin(); jt != ifaceList.constEnd(); ++jt) {
++ const QString &iface = jt.key();
++ const QVariantMap &ifaceValues = jt.value();
++
++ if (iface == QStringLiteral("org.bluez.Device1")) {
++ monitor = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.bluez"),
++ path.path(),
++ QDBusConnection::systemBus(), this);
++ connect(monitor, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
++ this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
++ deviceChangeMonitors.insert(path.path(), monitor);
++
++ if (ifaceValues.value(QStringLiteral("Connected"), false).toBool()) {
++ QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
++ connectedDevicesSet.insert(address);
++ }
++ }
++ }
++ }
++ }
++ }
++
++ QBluetoothLocalDevicePrivate::~QBluetoothLocalDevicePrivate()
++ {
++ delete adapter;
++ delete adapterProperties;
++ delete manager;
++ delete pairingTarget;
++
++ qDeleteAll(deviceChangeMonitors);
++ }
++
++ void QBluetoothLocalDevicePrivate::initializeAdapter()
++ {
++ if (adapter)
++ return;
++
++ //get all local adapters
++ if (!manager)
++ manager = new OrgFreedesktopDBusObjectManagerInterface(
++ QStringLiteral("org.bluez"),
++ QStringLiteral("/"),
++ QDBusConnection::systemBus(), this);
++
++ connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesAdded,
++ this, &QBluetoothLocalDevicePrivate::InterfacesAdded);
++ connect(manager, &OrgFreedesktopDBusObjectManagerInterface::InterfacesRemoved,
++ this, &QBluetoothLocalDevicePrivate::InterfacesRemoved);
++
++ bool ok = true;
++ const QString adapterPath = findAdapterForAddress(localAddress, &ok);
++ if (!ok || adapterPath.isEmpty())
++ return;
++
++ deviceAdapterPath = adapterPath;
++ adapter = new OrgBluezAdapter1Interface(QStringLiteral("org.bluez"), adapterPath,
++ QDBusConnection::systemBus(), this);
++
++ if (adapter) {
++ //hook up propertiesChanged for current adapter
++ adapterProperties = new OrgFreedesktopDBusPropertiesInterface(
++ QStringLiteral("org.bluez"), adapter->path(),
++ QDBusConnection::systemBus(), this);
++ connect(adapterProperties, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
++ this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
++ }
++ }
++
++ void QBluetoothLocalDevicePrivate::PropertiesChanged(const QString &interface,
++ const QVariantMap &changed_properties,
++ const QStringList &/*invalidated_properties*/,
++ const QDBusMessage &)
++ {
++ //qDebug() << "Change" << interface << changed_properties;
++ if (interface == QStringLiteral("org.bluez.Adapter1")) {
++ //update host mode
++ if (changed_properties.contains(QStringLiteral("Discoverable"))
++ || changed_properties.contains(QStringLiteral("Powered"))) {
++
++ QBluetoothLocalDevice::HostMode mode;
++
++ if (!adapter->powered()) {
++ mode = QBluetoothLocalDevice::HostPoweredOff;
++ } else {
++ if (adapter->discoverable())
++ mode = QBluetoothLocalDevice::HostDiscoverable;
++ else
++ mode = QBluetoothLocalDevice::HostConnectable;
++
++ if (pendingHostModeChange != -1) {
++
++ if (static_cast<int>(mode) != pendingHostModeChange) {
++ adapter->setDiscoverable(
++ pendingHostModeChange
++ == static_cast<int>(QBluetoothLocalDevice::HostDiscoverable));
++ pendingHostModeChange = -1;
++ return;
++ }
++ pendingHostModeChange = -1;
++ }
++ }
++
++ if (mode != currentMode)
++ emit q_ptr->hostModeStateChanged(mode);
++
++ currentMode = mode;
++ }
++ } else if (interface == QStringLiteral("org.bluez.Device1")
++ && changed_properties.contains(QStringLiteral("Connected"))) {
++ // update list of connected devices
++ OrgFreedesktopDBusPropertiesInterface *senderIface =
++ qobject_cast<OrgFreedesktopDBusPropertiesInterface*>(sender());
++ if (!senderIface)
++ return;
++
++ const QString currentPath = senderIface->path();
++ bool isConnected = changed_properties.value(QStringLiteral("Connected"), false).toBool();
++ OrgBluezDevice1Interface device(QStringLiteral("org.bluez"), currentPath,
++ QDBusConnection::systemBus());
++ const QBluetoothAddress changedAddress(device.address());
++ bool isInSet = connectedDevicesSet.contains(changedAddress);
++ if (isConnected && !isInSet) {
++ connectedDevicesSet.insert(changedAddress);
++ emit q_ptr->deviceConnected(changedAddress);
++ } else if (!isConnected && isInSet) {
++ connectedDevicesSet.remove(changedAddress);
++ emit q_ptr->deviceDisconnected(changedAddress);
++ }
++ }
++ }
++
++ void QBluetoothLocalDevicePrivate::InterfacesAdded(const QDBusObjectPath &object_path, InterfaceList interfaces_and_properties)
++ {
++ if (interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))
++ && !deviceChangeMonitors.contains(object_path.path())) {
++ // a new device was added which we need to add to list of known devices
++
++ if (objectPathIsForThisDevice(deviceAdapterPath, object_path.path())) {
++ OrgFreedesktopDBusPropertiesInterface *monitor = new OrgFreedesktopDBusPropertiesInterface(
++ QStringLiteral("org.bluez"),
++ object_path.path(),
++ QDBusConnection::systemBus());
++ connect(monitor, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged,
++ this, &QBluetoothLocalDevicePrivate::PropertiesChanged);
++ deviceChangeMonitors.insert(object_path.path(), monitor);
++
++ const QVariantMap ifaceValues = interfaces_and_properties.value(QStringLiteral("org.bluez.Device1"));
++ if (ifaceValues.value(QStringLiteral("Connected"), false).toBool()) {
++ QBluetoothAddress address(ifaceValues.value(QStringLiteral("Address")).toString());
++ connectedDevicesSet.insert(address);
++ emit q_ptr->deviceConnected(address);
++ }
++ }
++ }
++
++ if (pairingDiscoveryTimer && pairingDiscoveryTimer->isActive()
++ && interfaces_and_properties.contains(QStringLiteral("org.bluez.Device1"))) {
++ //device discovery for pairing found new remote device
++ OrgBluezDevice1Interface device(QStringLiteral("org.bluez"),
++ object_path.path(), QDBusConnection::systemBus());
++ if (!address.isNull() && address == QBluetoothAddress(device.address()))
++ processPairing(object_path.path(), pairing);
++ }
++ }
++
++ void QBluetoothLocalDevicePrivate::InterfacesRemoved(const QDBusObjectPath &object_path,
++ const QStringList &interfaces)
++ {
++ if (deviceChangeMonitors.contains(object_path.path())
++ && interfaces.contains(QLatin1String("org.bluez.Device1"))) {
++
++ if (objectPathIsForThisDevice(deviceAdapterPath, object_path.path())) {
++ //a device was removed
++ delete deviceChangeMonitors.take(object_path.path());
++
++ //the path contains the address (e.g.: /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX)
++ //-> use it to update current list of connected devices
++ QString addressString = object_path.path().right(17);
++ addressString.replace(QStringLiteral("_"), QStringLiteral(":"));
++ const QBluetoothAddress address(addressString);
++ bool found = connectedDevicesSet.remove(address);
++ if (found)
++ emit q_ptr->deviceDisconnected(address);
++ }
++ }
++
++ if (adapter && object_path.path() == adapter->path()
++ && interfaces.contains(QLatin1String("org.bluez.Adapter1"))) {
++ qCDebug(QT_BT_BLUEZ) << "Adapter" << adapter->path() << "was removed";
++ // current adapter was removed -> invalidate the instance
++ delete adapter;
++ adapter = nullptr;
++ manager->deleteLater();
++ manager = nullptr;
++ delete adapterProperties;
++ adapterProperties = nullptr;
++
++ delete pairingTarget;
++ pairingTarget = nullptr;
++
++ // turn off connectivity monitoring
++ qDeleteAll(deviceChangeMonitors);
++ deviceChangeMonitors.clear();
++ connectedDevicesSet.clear();
++ }
++ }
++
++ bool QBluetoothLocalDevicePrivate::isValid() const
++ {
++ return adapter && manager;
++ }
++
++ QList<QBluetoothAddress> QBluetoothLocalDevicePrivate::connectedDevices() const
++ {
++ return connectedDevicesSet.values();
++ }
++
++ void QBluetoothLocalDevicePrivate::pairingCompleted(QDBusPendingCallWatcher *watcher)
++ {
++ Q_Q(QBluetoothLocalDevice);
++ QDBusPendingReply<> reply = *watcher;
++
++ if (reply.isError()) {
++ qCWarning(QT_BT_BLUEZ) << "Failed to create pairing" << reply.error().name();
++ const bool canceledByUs =
++ (reply.error().name() == QStringLiteral("org.bluez.Error.AuthenticationCanceled"))
++ && pairingRequestCanceled;
++ if (!canceledByUs)
++ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
++
++ pairingRequestCanceled = false;
++ watcher->deleteLater();
++ return;
++ }
++
++ pairingRequestCanceled = false;
++
++ if (adapter) {
++ if (!pairingTarget) {
++ qCWarning(QT_BT_BLUEZ) << "Pairing target expected but found null pointer.";
++ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
++ watcher->deleteLater();
++ return;
++ }
++
++ if (!pairingTarget->paired()) {
++ qCWarning(QT_BT_BLUEZ) << "Device was not paired as requested";
++ emit q->errorOccurred(QBluetoothLocalDevice::PairingError);
++ watcher->deleteLater();
++ return;
++ }
++
++ const QBluetoothAddress targetAddress(pairingTarget->address());
++
++ if (pairing == QBluetoothLocalDevice::AuthorizedPaired && !pairingTarget->trusted())
++ pairingTarget->setTrusted(true);
++ else if (pairing == QBluetoothLocalDevice::Paired && pairingTarget->trusted())
++ pairingTarget->setTrusted(false);
++
++ delete pairingTarget;
++ pairingTarget = nullptr;
++
++ emit q->pairingFinished(targetAddress, pairing);
++ }
++
++ watcher->deleteLater();
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qbluetoothlocaldevice_p.cpp"