1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNfc module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qnearfieldmanager.h"
41#include "qnearfieldmanager_p.h"
42
43#if defined(QT_SIMULATOR)
44#include "qnearfieldmanager_simulator_p.h"
45#elif defined(NEARD_NFC)
46#include "qnearfieldmanager_neard_p.h"
47#elif defined(ANDROID_NFC)
48#include "qnearfieldmanager_android_p.h"
49#else
50#include "qnearfieldmanagerimpl_p.h"
51#endif
52
53#include <QtCore/QMetaType>
54#include <QtCore/QMetaMethod>
55
56QT_BEGIN_NAMESPACE
57
58/*!
59 \class QNearFieldManager
60 \brief The QNearFieldManager class provides access to notifications for NFC events.
61
62 \ingroup connectivity-nfc
63 \inmodule QtNfc
64 \since 5.2
65
66 NFC Forum devices support two modes of communications. The first mode, peer-to-peer
67 communications, is used to communicate between two NFC Forum devices. The second mode,
68 master/slave communications, is used to communicate between an NFC Forum device and an NFC
69 Forum Tag or Contactless Card. The targetDetected() signal is emitted when a target device
70 enters communications range. Communications can be initiated from the slot connected to this
71 signal.
72
73 NFC Forum devices generally operate as the master in master/slave communications. Some devices
74 are also capable of operating as the slave, so called Card Emulation mode. In this mode the
75 local NFC device emulates a NFC Forum Tag or Contactless Card.
76
77 NFC Forum Tags can contain one or more messages in a standardized format. These messages are
78 encapsulated by the QNdefMessage class. Use the registerNdefMessageHandler() functions to
79 register message handlers with particular criteria. Handlers can be unregistered with the
80 unregisterNdefMessageHandler() function.
81
82 Applications can connect to the targetDetected() and targetLost() signals to get notified when
83 an NFC Forum Tag enters or leaves proximity. Before these signals are
84 emitted target detection must be started with the startTargetDetection() function.
85 Target detection can be stopped with
86 the stopTargetDetection() function. Before a detected target can be accessed it is necessary to
87 request access rights. This must be done before the target device is touched. The
88 setTargetAccessModes() function is used to set the types of access the application wants to
89 perform on the detected target. When access is no longer required the target access modes
90 should be set to NoTargetAccess as other applications may be blocked from accessing targets.
91 The current target access modes can be retried with the targetAccessModes() function.
92
93
94 \section2 Automatically launching NDEF message handlers
95
96 On some platforms it is possible to pre-register an application to receive NDEF messages
97 matching a given criteria. This is useful to get the system to automatically launch your
98 application when a matching NDEF message is received. This removes the need to have the user
99 manually launch NDEF handling applications, prior to touching a tag, or to have those
100 applications always running and using system resources.
101
102 The process of registering the handler is different for each platform. Please refer to the
103 platform documentation on how such a registration may be done.
104 If the application has been registered as an NDEF message handler, the application only needs
105 to call the registerNdefMessageHandler() function:
106
107 \snippet doc_src_qtnfc.cpp handleNdefMessage
108
109 Automatically launching NDEF message handlers is supported on
110 \l{nfc-android.html}{Android}.
111
112 \section3 NFC on Linux
113 The \l{https://01.org/linux-nfc}{Linux NFC project} provides software to support NFC on Linux platforms.
114 The neard daemon will allow access to the supported hardware via DBus interfaces. QtNfc requires neard
115 version 0.14 which can be built from source or installed via the appropriate Linux package manager. Not
116 all API features are currently supported.
117 To allow QtNfc to access the DBus interfaces the neard daemon has to be running. In case of problems
118 debug output can be enabled by enabling categorized logging for 'qt.nfc.neard'.
119*/
120
121/*!
122 \enum QNearFieldManager::AdapterState
123
124 \since 5.12
125
126 This enum describes the different states a NFC adapter can have.
127
128 \value Offline The nfc adapter is offline.
129 \value TurningOn The nfc adapter is turning on.
130 \value Online The nfc adapter is online.
131 \value TurningOff The nfc adapter is turning off.
132*/
133
134/*!
135 \enum QNearFieldManager::TargetAccessMode
136
137 This enum describes the different access modes an application can have.
138
139 \value NoTargetAccess The application cannot access NFC capabilities.
140 \value NdefReadTargetAccess The application can read NDEF messages from targets by calling
141 QNearFieldTarget::readNdefMessages().
142 \value NdefWriteTargetAccess The application can write NDEF messages to targets by calling
143 QNearFieldTarget::writeNdefMessages().
144 \value TagTypeSpecificTargetAccess The application can access targets using raw commands by
145 calling QNearFieldTarget::sendCommand().
146*/
147
148/*!
149 \fn void QNearFieldManager::adapterStateChanged(AdapterState state)
150
151 \since 5.12
152
153 This signal is emitted whenever the \a state of the NFC adapter changed.
154
155 \note Currently, this signal is only emitted on Android.
156*/
157
158/*!
159 \fn void QNearFieldManager::targetDetected(QNearFieldTarget *target)
160
161 This signal is emitted whenever a target is detected. The \a target parameter represents the
162 detected target.
163
164 This signal will be emitted for all detected targets.
165
166 QNearFieldManager maintains ownership of \a target, however, it will not be destroyed until
167 the QNearFieldManager destructor is called. Ownership may be transferred by calling
168 setParent().
169
170 Do not delete \a target from the slot connected to this signal, instead call deleteLater().
171
172 \note that if \a target is deleted before it moves out of proximity the targetLost() signal
173 will not be emitted.
174
175 \sa targetLost()
176*/
177
178/*!
179 \fn void QNearFieldManager::targetLost(QNearFieldTarget *target)
180
181 This signal is emitted whenever a target moves out of proximity. The \a target parameter
182 represents the lost target.
183
184 Do not delete \a target from the slot connected to this signal, instead use deleteLater().
185
186 \sa QNearFieldTarget::disconnected()
187*/
188
189/*!
190 Constructs a new near field manager with \a parent.
191*/
192QNearFieldManager::QNearFieldManager(QObject *parent)
193: QObject(parent), d_ptr(new QNearFieldManagerPrivateImpl)
194{
195 qRegisterMetaType<AdapterState>();
196
197 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::adapterStateChanged,
198 receiver: this, slot: &QNearFieldManager::adapterStateChanged);
199 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::targetDetected,
200 receiver: this, slot: &QNearFieldManager::targetDetected);
201 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::targetLost,
202 receiver: this, slot: &QNearFieldManager::targetLost);
203}
204
205/*!
206 \internal
207
208 Constructs a new near field manager with the specified \a backend and with \a parent.
209
210 \note: This constructor is only enable for internal builds and is used for testing the
211 simulator backend.
212*/
213QNearFieldManager::QNearFieldManager(QNearFieldManagerPrivate *backend, QObject *parent)
214: QObject(parent), d_ptr(backend)
215{
216 qRegisterMetaType<AdapterState>();
217
218 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::adapterStateChanged,
219 receiver: this, slot: &QNearFieldManager::adapterStateChanged);
220 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::targetDetected,
221 receiver: this, slot: &QNearFieldManager::targetDetected);
222 connect(sender: d_ptr, signal: &QNearFieldManagerPrivate::targetLost,
223 receiver: this, slot: &QNearFieldManager::targetLost);
224}
225
226/*!
227 Destroys the near field manager.
228*/
229QNearFieldManager::~QNearFieldManager()
230{
231 delete d_ptr;
232}
233
234/*!
235 Returns \c true if the device has a NFC adapter and
236 it is turned on; otherwise returns \c false.
237
238 \sa isSupported()
239*/
240bool QNearFieldManager::isAvailable() const
241{
242 Q_D(const QNearFieldManager);
243
244 return d->isAvailable();
245}
246
247/*!
248 \since 5.12
249
250 Returns \c true if the underlying device has a NFC adapter; otherwise returns \c false.
251
252 \sa isAvailable()
253*/
254bool QNearFieldManager::isSupported() const
255{
256 Q_D(const QNearFieldManager);
257
258 return d->isSupported();
259}
260/*!
261 \fn bool QNearFieldManager::startTargetDetection()
262
263 Starts detecting targets and returns true if target detection is
264 successfully started; otherwise returns false. Causes the targetDetected() signal to be emitted
265 when a target is within proximity.
266 \sa stopTargetDetection()
267
268 \note For platforms using neard: target detection will stop as soon as a tag has been detected.
269*/
270bool QNearFieldManager::startTargetDetection()
271{
272 Q_D(QNearFieldManager);
273 return d->startTargetDetection();
274}
275
276/*!
277 Stops detecting targets. The targetDetected() signal will no longer be emitted until another
278 call to startTargetDetection() is made.
279*/
280void QNearFieldManager::stopTargetDetection()
281{
282 Q_D(QNearFieldManager);
283
284 d->stopTargetDetection();
285}
286
287static QMetaMethod methodForSignature(QObject *object, const char *method)
288{
289 QByteArray normalizedMethod = QMetaObject::normalizedSignature(method);
290
291 if (!QMetaObject::checkConnectArgs(SIGNAL(targetDetected(QNdefMessage,QNearFieldTarget*)),
292 method: normalizedMethod)) {
293 qWarning(msg: "Signatures do not match: %s:%d\n", __FILE__, __LINE__);
294 return QMetaMethod();
295 }
296
297 quint8 memcode = (normalizedMethod.at(i: 0) - '0') & 0x03;
298 normalizedMethod = normalizedMethod.mid(index: 1);
299
300 int index;
301 switch (memcode) {
302 case QSLOT_CODE:
303 index = object->metaObject()->indexOfSlot(slot: normalizedMethod.constData());
304 break;
305 case QSIGNAL_CODE:
306 index = object->metaObject()->indexOfSignal(signal: normalizedMethod.constData());
307 break;
308 case QMETHOD_CODE:
309 index = object->metaObject()->indexOfMethod(method: normalizedMethod.constData());
310 break;
311 default:
312 index = -1;
313 }
314
315 if (index == -1)
316 return QMetaMethod();
317
318 return object->metaObject()->method(index);
319}
320
321/*!
322 Registers \a object to receive notifications on \a method when a tag has been detected and has
323 an NDEF record that matches \a typeNameFormat and \a type. The \a method on \a object should
324 have the prototype
325 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
326
327 Returns an identifier, which can be used to unregister the handler, on success; otherwise
328 returns -1.
329
330 \note The \e target parameter of \a method may not be available on all platforms, in which case
331 \e target will be 0.
332
333 \note On platforms using neard registering message handlers is not supported.
334*/
335
336int QNearFieldManager::registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat,
337 const QByteArray &type,
338 QObject *object, const char *method)
339{
340 QMetaMethod metaMethod = methodForSignature(object, method);
341 if (!metaMethod.enclosingMetaObject())
342 return -1;
343
344 QNdefFilter filter;
345 filter.appendRecord(typeNameFormat, type);
346
347 Q_D(QNearFieldManager);
348
349 return d->registerNdefMessageHandler(filter, object, metaMethod);
350}
351
352/*!
353 \fn int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)
354
355 Registers \a object to receive notifications on \a method when a tag has been detected and has
356 an NDEF message that matches a pre-registered message format. The \a method on \a object should
357 have the prototype
358 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
359
360 Returns an identifier, which can be used to unregister the handler, on success; otherwise
361 returns -1.
362
363 This function is used to register a QNearFieldManager instance to receive notifications when a
364 NDEF message matching a pre-registered message format is received. See the section on
365 \l {Automatically launching NDEF message handlers}.
366
367 \note The \e target parameter of \a method may not be available on all platforms, in which case
368 \e target will be 0.
369*/
370int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)
371{
372 QMetaMethod metaMethod = methodForSignature(object, method);
373 if (!metaMethod.enclosingMetaObject())
374 return -1;
375
376 Q_D(QNearFieldManager);
377
378 return d->registerNdefMessageHandler(object, metaMethod);
379}
380
381/*!
382 Registers \a object to receive notifications on \a method when a tag has been detected and has
383 an NDEF message that matches \a filter is detected. The \a method on \a object should have the
384 prototype 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.
385
386 Returns an identifier, which can be used to unregister the handler, on success; otherwise
387 returns -1.
388
389 \note The \e target parameter of \a method may not be available on all platforms, in which case
390 \e target will be 0.
391*/
392int QNearFieldManager::registerNdefMessageHandler(const QNdefFilter &filter,
393 QObject *object, const char *method)
394{
395 QMetaMethod metaMethod = methodForSignature(object, method);
396 if (!metaMethod.enclosingMetaObject())
397 return -1;
398
399 Q_D(QNearFieldManager);
400
401 return d->registerNdefMessageHandler(filter, object, metaMethod);
402}
403
404/*!
405 Unregisters the target detect handler identified by \a handlerId.
406
407 Returns true on success; otherwise returns false.
408*/
409bool QNearFieldManager::unregisterNdefMessageHandler(int handlerId)
410{
411 Q_D(QNearFieldManager);
412
413 return d->unregisterNdefMessageHandler(handlerId);
414}
415
416/*!
417 Sets the requested target access modes to \a accessModes.
418*/
419void QNearFieldManager::setTargetAccessModes(TargetAccessModes accessModes)
420{
421 Q_D(QNearFieldManager);
422
423 TargetAccessModes removedModes = ~accessModes & d->m_requestedModes;
424 if (removedModes)
425 d->releaseAccess(accessModes: removedModes);
426
427 TargetAccessModes newModes = accessModes & ~d->m_requestedModes;
428 if (newModes)
429 d->requestAccess(accessModes: newModes);
430}
431
432/*!
433 Returns current requested target access modes.
434*/
435QNearFieldManager::TargetAccessModes QNearFieldManager::targetAccessModes() const
436{
437 Q_D(const QNearFieldManager);
438
439 return d->m_requestedModes;
440}
441
442QT_END_NAMESPACE
443

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