1/***************************************************************************
2**
3** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
4** Copyright (C) 2016 BasysKom GmbH.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtNfc module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qnearfieldmanager_neard_p.h"
42#include "qnearfieldtarget_neard_p.h"
43
44#include "neard/adapter_p.h"
45#include "neard/dbusproperties_p.h"
46#include "neard/dbusobjectmanager_p.h"
47
48QT_BEGIN_NAMESPACE
49
50Q_DECLARE_LOGGING_CATEGORY(QT_NFC_NEARD)
51
52// TODO We need a constructor that lets us select an adapter
53QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl()
54 : QNearFieldManagerPrivate(),
55 m_neardHelper(NeardHelper::instance())
56{
57 QDBusPendingReply<ManagedObjectList> reply = m_neardHelper->dbusObjectManager()->GetManagedObjects();
58 reply.waitForFinished();
59 if (reply.isError()) {
60 qCWarning(QT_NFC_NEARD) << "Error getting managed objects";
61 return;
62 }
63
64 bool found = false;
65 const QList<QDBusObjectPath> paths = reply.value().keys();
66 for (const QDBusObjectPath &path : paths) {
67 const InterfaceList ifaceList = reply.value().value(akey: path);
68 const QStringList ifaces = ifaceList.keys();
69 for (const QString &iface : ifaces) {
70 if (iface == QStringLiteral("org.neard.Adapter")) {
71 found = true;
72 m_adapterPath = path.path();
73 qCDebug(QT_NFC_NEARD) << "org.neard.Adapter found for path" << m_adapterPath;
74 break;
75 }
76 }
77
78 if (found)
79 break;
80 }
81
82 if (!found) {
83 qCWarning(QT_NFC_NEARD) << "no adapter found, neard daemon running?";
84 } else {
85 connect(sender: m_neardHelper, signal: &NeardHelper::tagFound,
86 receiver: this, slot: &QNearFieldManagerPrivateImpl::handleTagFound);
87 connect(sender: m_neardHelper, signal: &NeardHelper::tagRemoved,
88 receiver: this, slot: &QNearFieldManagerPrivateImpl::handleTagRemoved);
89 }
90}
91
92QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
93{
94 stopTargetDetection();
95}
96
97bool QNearFieldManagerPrivateImpl::isAvailable() const
98{
99 if (!m_neardHelper->dbusObjectManager()->isValid() || m_adapterPath.isNull()) {
100 qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid";
101 return false;
102 }
103
104 QDBusPendingReply<ManagedObjectList> reply = m_neardHelper->dbusObjectManager()->GetManagedObjects();
105 reply.waitForFinished();
106 if (reply.isError()) {
107 qCWarning(QT_NFC_NEARD) << "error getting managed objects";
108 return false;
109 }
110
111 const QList<QDBusObjectPath> paths = reply.value().keys();
112 for (const QDBusObjectPath &path : paths) {
113 if (m_adapterPath == path.path())
114 return true;
115 }
116
117 return false;
118}
119
120bool QNearFieldManagerPrivateImpl::isSupported() const
121{
122 if (m_adapterPath.isEmpty()) {
123 qCWarning(QT_NFC_NEARD) << "no adapter found, neard daemon running?";
124 return false;
125 }
126
127 if (!m_neardHelper->dbusObjectManager()->isValid() || m_adapterPath.isNull()) {
128 qCWarning(QT_NFC_NEARD) << "dbus object manager invalid or adapter path invalid";
129 return false;
130 }
131
132 return true;
133}
134
135bool QNearFieldManagerPrivateImpl::startTargetDetection()
136{
137 qCDebug(QT_NFC_NEARD) << "starting target detection";
138 if (!isAvailable())
139 return false;
140
141 OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard"),
142 m_adapterPath,
143 QDBusConnection::systemBus());
144
145 if (!dbusProperties.isValid()) {
146 qCWarning(QT_NFC_NEARD) << "dbus property interface invalid";
147 return false;
148 }
149
150 // check if the adapter is currently polling
151 QDBusPendingReply<QDBusVariant> replyPolling = dbusProperties.Get(QStringLiteral("org.neard.Adapter"),
152 QStringLiteral("Polling"));
153 replyPolling.waitForFinished();
154 if (!replyPolling.isError()) {
155 if (replyPolling.value().variant().toBool()) {
156 qCDebug(QT_NFC_NEARD) << "adapter is already polling";
157 return true;
158 }
159 } else {
160 qCWarning(QT_NFC_NEARD) << "error getting 'Polling' state from property interface";
161 return false;
162 }
163
164 // check if the adapter it powered
165 QDBusPendingReply<QDBusVariant> replyPowered = dbusProperties.Get(QStringLiteral("org.neard.Adapter"),
166 QStringLiteral("Powered"));
167 replyPowered.waitForFinished();
168 if (!replyPowered.isError()) {
169 if (replyPowered.value().variant().toBool()) {
170 qCDebug(QT_NFC_NEARD) << "adapter is already powered";
171 } else {
172 QDBusPendingReply<QDBusVariant> replyTryPowering = dbusProperties.Set(QStringLiteral("org.neard.Adapter"),
173 QStringLiteral("Powered"),
174 value: QDBusVariant(true));
175 replyTryPowering.waitForFinished();
176 if (!replyTryPowering.isError()) {
177 qCDebug(QT_NFC_NEARD) << "powering adapter";
178 }
179 }
180 } else {
181 qCWarning(QT_NFC_NEARD) << "error getting 'Powered' state from property interface";
182 return false;
183 }
184
185 // create adapter and start poll loop
186 OrgNeardAdapterInterface neardAdapter(QStringLiteral("org.neard"),
187 m_adapterPath,
188 QDBusConnection::systemBus());
189
190 // possible modes: "Target", "Initiator", "Dual"
191 QDBusPendingReply<> replyPollLoop = neardAdapter.StartPollLoop(QStringLiteral("Dual"));
192 replyPollLoop.waitForFinished();
193 if (replyPollLoop.isError()) {
194 qCWarning(QT_NFC_NEARD) << "error when starting polling";
195 return false;
196 } else {
197 qCDebug(QT_NFC_NEARD) << "successfully started polling";
198 }
199
200 return true;
201}
202
203void QNearFieldManagerPrivateImpl::stopTargetDetection()
204{
205 qCDebug(QT_NFC_NEARD) << "stopping target detection";
206 if (!isAvailable())
207 return;
208
209 OrgFreedesktopDBusPropertiesInterface dbusProperties(QStringLiteral("org.neard"),
210 m_adapterPath,
211 QDBusConnection::systemBus());
212
213 if (!dbusProperties.isValid()) {
214 qCWarning(QT_NFC_NEARD) << "dbus property interface invalid";
215 return;
216 }
217
218 // check if the adapter is currently polling
219 QDBusPendingReply<QDBusVariant> replyPolling = dbusProperties.Get(QStringLiteral("org.neard.Adapter"),
220 QStringLiteral("Polling"));
221 replyPolling.waitForFinished();
222 if (!replyPolling.isError()) {
223 if (replyPolling.value().variant().toBool()) {
224 // create adapter and stop poll loop
225 OrgNeardAdapterInterface neardAdapter(QStringLiteral("org.neard"),
226 m_adapterPath,
227 QDBusConnection::systemBus());
228
229 QDBusPendingReply<> replyStopPolling = neardAdapter.StopPollLoop();
230 replyStopPolling.waitForFinished();
231 if (replyStopPolling.isError())
232 qCWarning(QT_NFC_NEARD) << "error when stopping polling";
233 else
234 qCDebug(QT_NFC_NEARD) << "successfully stopped polling";
235 } else {
236 qCDebug(QT_NFC_NEARD) << "already stopped polling";
237 }
238 } else {
239 qCWarning(QT_NFC_NEARD) << "error getting 'Polling' state from property interface";
240 }
241}
242
243int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, const QMetaMethod &method)
244{
245 Q_UNUSED(object);
246 Q_UNUSED(method);
247 return -1;
248}
249
250int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter, QObject *object, const QMetaMethod &method)
251{
252 Q_UNUSED(filter);
253 Q_UNUSED(object);
254 Q_UNUSED(method);
255 return -1;
256}
257
258bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int handlerId)
259{
260 Q_UNUSED(handlerId);
261 return false;
262}
263
264void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes)
265{
266 Q_UNUSED(accessModes);
267}
268
269void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes)
270{
271 Q_UNUSED(accessModes);
272}
273
274void QNearFieldManagerPrivateImpl::handleTagFound(const QDBusObjectPath &path)
275{
276 NearFieldTarget<QNearFieldTarget> *nfTag = new NearFieldTarget<QNearFieldTarget>(this, path);
277 m_activeTags.insert(akey: path.path(), avalue: nfTag);
278 emit targetDetected(target: nfTag);
279}
280
281void QNearFieldManagerPrivateImpl::handleTagRemoved(const QDBusObjectPath &path)
282{
283 const QString adapterPath = path.path();
284 if (m_activeTags.contains(akey: adapterPath)) {
285 QNearFieldTarget *nfTag = m_activeTags.value(akey: adapterPath);
286 m_activeTags.remove(akey: adapterPath);
287 emit targetLost(target: nfTag);
288 }
289}
290
291QT_END_NAMESPACE
292

source code of qtconnectivity/src/nfc/qnearfieldmanager_neard.cpp