| 1 | // Copyright (C) 2016 BlackBerry Limited, Copyright (C) 2016 BasysKom GmbH |
| 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 "qnearfieldmanager_neard_p.h" |
| 5 | #include "qnearfieldtarget_neard_p.h" |
| 6 | |
| 7 | #include "adapter_interface.h" |
| 8 | #include "properties_interface.h" |
| 9 | #include "objectmanager_interface.h" |
| 10 | |
| 11 | QT_BEGIN_NAMESPACE |
| 12 | |
| 13 | Q_DECLARE_LOGGING_CATEGORY(QT_NFC_NEARD) |
| 14 | Q_LOGGING_CATEGORY(QT_NFC_NEARD, "qt.nfc.neard" ) |
| 15 | |
| 16 | using namespace QtNfcPrivate; // for D-Bus wrappers |
| 17 | |
| 18 | // TODO We need a constructor that lets us select an adapter |
| 19 | QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() |
| 20 | : QNearFieldManagerPrivate(), |
| 21 | m_neardHelper(NeardHelper::instance()) |
| 22 | { |
| 23 | QDBusPendingReply<ManagedObjectList> reply = m_neardHelper->dbusObjectManager()->GetManagedObjects(); |
| 24 | reply.waitForFinished(); |
| 25 | if (reply.isError()) { |
| 26 | qCWarning(QT_NFC_NEARD) << "Error getting managed objects" ; |
| 27 | return; |
| 28 | } |
| 29 | |
| 30 | bool found = false; |
| 31 | const QList<QDBusObjectPath> paths = reply.value().keys(); |
| 32 | for (const QDBusObjectPath &path : paths) { |
| 33 | const InterfaceList ifaceList = reply.value().value(path); |
| 34 | const QStringList ifaces = ifaceList.keys(); |
| 35 | for (const QString &iface : ifaces) { |
| 36 | if (iface == QStringLiteral("org.neard.Adapter" )) { |
| 37 | found = true; |
| 38 | m_adapterPath = path.path(); |
| 39 | qCDebug(QT_NFC_NEARD) << "org.neard.Adapter found for path" << m_adapterPath; |
| 40 | break; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | if (found) |
| 45 | break; |
| 46 | } |
| 47 | |
| 48 | if (!found) { |
| 49 | qCWarning(QT_NFC_NEARD) << "no adapter found, neard daemon running?" ; |
| 50 | } else { |
| 51 | connect(sender: m_neardHelper, signal: &NeardHelper::tagFound, |
| 52 | context: this, slot: &QNearFieldManagerPrivateImpl::handleTagFound); |
| 53 | connect(sender: m_neardHelper, signal: &NeardHelper::tagRemoved, |
| 54 | context: this, slot: &QNearFieldManagerPrivateImpl::handleTagRemoved); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() |
| 59 | { |
| 60 | stopTargetDetection(); |
| 61 | } |
| 62 | |
| 63 | bool QNearFieldManagerPrivateImpl::isEnabled() const |
| 64 | { |
| 65 | if (!m_neardHelper->dbusObjectManager()->isValid() || m_adapterPath.isNull()) { |
| 66 | qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid" ; |
| 67 | return false; |
| 68 | } |
| 69 | |
| 70 | QDBusPendingReply<ManagedObjectList> reply = m_neardHelper->dbusObjectManager()->GetManagedObjects(); |
| 71 | reply.waitForFinished(); |
| 72 | if (reply.isError()) { |
| 73 | qCWarning(QT_NFC_NEARD) << "error getting managed objects" ; |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | const QList<QDBusObjectPath> paths = reply.value().keys(); |
| 78 | for (const QDBusObjectPath &path : paths) { |
| 79 | if (m_adapterPath == path.path()) |
| 80 | return true; |
| 81 | } |
| 82 | |
| 83 | return false; |
| 84 | } |
| 85 | |
| 86 | bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const |
| 87 | { |
| 88 | if (m_adapterPath.isEmpty()) { |
| 89 | qCWarning(QT_NFC_NEARD) << "no adapter found, neard daemon running?" ; |
| 90 | return false; |
| 91 | } |
| 92 | |
| 93 | if (!m_neardHelper->dbusObjectManager()->isValid()) { |
| 94 | qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid" ; |
| 95 | return false; |
| 96 | } |
| 97 | |
| 98 | return accessMethod == QNearFieldTarget::NdefAccess; |
| 99 | } |
| 100 | |
| 101 | bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) |
| 102 | { |
| 103 | qCDebug(QT_NFC_NEARD) << "starting target detection" ; |
| 104 | if (!isEnabled() || accessMethod != QNearFieldTarget::NdefAccess) |
| 105 | return false; |
| 106 | |
| 107 | OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard" ), |
| 108 | m_adapterPath, |
| 109 | QDBusConnection::systemBus()); |
| 110 | |
| 111 | if (!dbusProperties.isValid()) { |
| 112 | qCWarning(QT_NFC_NEARD) << "dbus property interface invalid" ; |
| 113 | return false; |
| 114 | } |
| 115 | |
| 116 | // check if the adapter is currently polling |
| 117 | QDBusPendingReply<QDBusVariant> replyPolling = dbusProperties.Get(QStringLiteral("org.neard.Adapter" ), |
| 118 | QStringLiteral("Polling" )); |
| 119 | replyPolling.waitForFinished(); |
| 120 | if (!replyPolling.isError()) { |
| 121 | if (replyPolling.value().variant().toBool()) { |
| 122 | qCDebug(QT_NFC_NEARD) << "adapter is already polling" ; |
| 123 | return true; |
| 124 | } |
| 125 | } else { |
| 126 | qCWarning(QT_NFC_NEARD) << "error getting 'Polling' state from property interface" ; |
| 127 | return false; |
| 128 | } |
| 129 | |
| 130 | // check if the adapter it powered |
| 131 | QDBusPendingReply<QDBusVariant> replyPowered = dbusProperties.Get(QStringLiteral("org.neard.Adapter" ), |
| 132 | QStringLiteral("Powered" )); |
| 133 | replyPowered.waitForFinished(); |
| 134 | if (!replyPowered.isError()) { |
| 135 | if (replyPowered.value().variant().toBool()) { |
| 136 | qCDebug(QT_NFC_NEARD) << "adapter is already powered" ; |
| 137 | } else { |
| 138 | QDBusPendingReply<QDBusVariant> replyTryPowering = dbusProperties.Set(QStringLiteral("org.neard.Adapter" ), |
| 139 | QStringLiteral("Powered" ), |
| 140 | QDBusVariant(true)); |
| 141 | replyTryPowering.waitForFinished(); |
| 142 | if (!replyTryPowering.isError()) { |
| 143 | qCDebug(QT_NFC_NEARD) << "powering adapter" ; |
| 144 | } |
| 145 | } |
| 146 | } else { |
| 147 | qCWarning(QT_NFC_NEARD) << "error getting 'Powered' state from property interface" ; |
| 148 | return false; |
| 149 | } |
| 150 | |
| 151 | // create adapter and start poll loop |
| 152 | OrgNeardAdapterInterface neardAdapter(QStringLiteral("org.neard" ), |
| 153 | m_adapterPath, |
| 154 | QDBusConnection::systemBus()); |
| 155 | |
| 156 | // possible modes: "Target", "Initiator", "Dual" |
| 157 | QDBusPendingReply<> replyPollLoop = neardAdapter.StartPollLoop(QStringLiteral("Initiator" )); |
| 158 | replyPollLoop.waitForFinished(); |
| 159 | if (replyPollLoop.isError()) { |
| 160 | qCWarning(QT_NFC_NEARD) << "error when starting polling" ; |
| 161 | return false; |
| 162 | } else { |
| 163 | qCDebug(QT_NFC_NEARD) << "successfully started polling" ; |
| 164 | } |
| 165 | |
| 166 | return true; |
| 167 | } |
| 168 | |
| 169 | void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString&) |
| 170 | { |
| 171 | qCDebug(QT_NFC_NEARD) << "stopping target detection" ; |
| 172 | if (!isEnabled()) |
| 173 | return; |
| 174 | |
| 175 | OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard" ), |
| 176 | m_adapterPath, |
| 177 | QDBusConnection::systemBus()); |
| 178 | |
| 179 | if (!dbusProperties.isValid()) { |
| 180 | qCWarning(QT_NFC_NEARD) << "dbus property interface invalid" ; |
| 181 | return; |
| 182 | } |
| 183 | |
| 184 | // check if the adapter is currently polling |
| 185 | QDBusPendingReply<QDBusVariant> replyPolling = dbusProperties.Get(QStringLiteral("org.neard.Adapter" ), |
| 186 | QStringLiteral("Polling" )); |
| 187 | replyPolling.waitForFinished(); |
| 188 | if (!replyPolling.isError()) { |
| 189 | if (replyPolling.value().variant().toBool()) { |
| 190 | // create adapter and stop poll loop |
| 191 | OrgNeardAdapterInterface neardAdapter(QStringLiteral("org.neard" ), |
| 192 | m_adapterPath, |
| 193 | QDBusConnection::systemBus()); |
| 194 | |
| 195 | QDBusPendingReply<> replyStopPolling = neardAdapter.StopPollLoop(); |
| 196 | replyStopPolling.waitForFinished(); |
| 197 | if (replyStopPolling.isError()) |
| 198 | qCWarning(QT_NFC_NEARD) << "error when stopping polling" ; |
| 199 | else |
| 200 | qCDebug(QT_NFC_NEARD) << "successfully stopped polling" ; |
| 201 | } else { |
| 202 | qCDebug(QT_NFC_NEARD) << "already stopped polling" ; |
| 203 | } |
| 204 | } else { |
| 205 | qCWarning(QT_NFC_NEARD) << "error getting 'Polling' state from property interface" ; |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | void QNearFieldManagerPrivateImpl::handleTagFound(const QDBusObjectPath &path) |
| 210 | { |
| 211 | auto priv = new QNearFieldTargetPrivateImpl(this, path); |
| 212 | auto nfTag = new QNearFieldTarget(priv, this); |
| 213 | m_activeTags.insert(path.path(), nfTag); |
| 214 | emit targetDetected(target: nfTag); |
| 215 | } |
| 216 | |
| 217 | void QNearFieldManagerPrivateImpl::handleTagRemoved(const QDBusObjectPath &path) |
| 218 | { |
| 219 | const QString adapterPath = path.path(); |
| 220 | if (m_activeTags.contains(key: adapterPath)) { |
| 221 | QNearFieldTarget *nfTag = m_activeTags.value(key: adapterPath); |
| 222 | m_activeTags.remove(key: adapterPath); |
| 223 | emit targetLost(target: nfTag); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | QT_END_NAMESPACE |
| 228 | |