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