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 | |
56 | QT_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 | */ |
192 | QNearFieldManager::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 | */ |
213 | QNearFieldManager::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 | */ |
229 | QNearFieldManager::~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 | */ |
240 | bool 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 | */ |
254 | bool 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 | */ |
270 | bool 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 | */ |
280 | void QNearFieldManager::stopTargetDetection() |
281 | { |
282 | Q_D(QNearFieldManager); |
283 | |
284 | d->stopTargetDetection(); |
285 | } |
286 | |
287 | static 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 | |
336 | int 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 | */ |
370 | int 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 | */ |
392 | int 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 | */ |
409 | bool 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 | */ |
419 | void 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 | */ |
435 | QNearFieldManager::TargetAccessModes QNearFieldManager::targetAccessModes() const |
436 | { |
437 | Q_D(const QNearFieldManager); |
438 | |
439 | return d->m_requestedModes; |
440 | } |
441 | |
442 | QT_END_NAMESPACE |
443 | |