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 "qdeclarativenearfield_p.h"
41#include "qdeclarativendeffilter_p.h"
42#include "qdeclarativendeftextrecord_p.h"
43#include "qdeclarativendefurirecord_p.h"
44#include "qdeclarativendefmimerecord_p.h"
45
46#include <qndefmessage.h>
47#include <qndefnfctextrecord.h>
48#include <qndefnfcurirecord.h>
49
50#include <QtNfc/QNearFieldTarget>
51
52/*!
53 \qmltype NearField
54 \instantiates QDeclarativeNearField
55 \since 5.2
56 \brief Provides access to NDEF messages stored on NFC Forum tags.
57
58 \ingroup nfc-qml
59 \inqmlmodule QtNfc
60
61 \sa NdefFilter
62 \sa NdefRecord
63
64 \sa QNearFieldManager
65 \sa QNdefMessage
66 \sa QNdefRecord
67
68 The NearField type can be used to read NDEF messages from NFC Forum tags. Set the \l filter
69 and \l orderMatch properties to match the required NDEF messages. Once an NDEF message is
70 successfully read from a tag the \l messageRecords property is updated.
71
72 \note For platforms using neard, filtering is currently not implemented. For more information
73 on neard see \l QNearFieldManager.
74
75 \snippet doc_src_qtnfc.qml QML register for messages
76*/
77
78/*!
79 \qmlproperty list<NdefRecord> NearField::messageRecords
80
81 This property contains the list of NDEF records in the last NDEF message read.
82*/
83
84/*!
85 \qmlproperty list<NdefFilter> NearField::filter
86
87 This property holds the NDEF filter constraints. The \l messageRecords property will only be
88 set to NDEF messages which match the filter. If no filter is set, a message handler for
89 all NDEF messages will be registered.
90
91 \note Filtering is not supported when using neard.
92
93 \l QNearFieldManager::registerNdefMessageHandler()
94*/
95
96/*!
97 \qmlproperty bool NearField::orderMatch
98
99 This property indicates whether the order of records should be taken into account when matching
100 messages. This is not supported when using neard.
101
102 The default of orderMatch is false.
103*/
104
105/*!
106 \qmlproperty bool NearField::polling
107 \since 5.5
108
109 This property indicates if the underlying adapter is currently in polling state. If set to \c true
110 the adapter will start polling and stop polling if set to \c false.
111
112 \note On platforms using neard, the adapter will stop polling as soon as a tag has been detected.
113 For more information see \l QNearFieldManager.
114*/
115
116/*!
117 \qmlsignal NearField::tagFound()
118 \since 5.5
119
120 This signal will be emitted when a tag has been detected.
121*/
122
123/*!
124 \qmlsignal NearField::tagRemoved()
125 \since 5.5
126
127 This signal will be emitted when a tag has been removed.
128*/
129
130QDeclarativeNearField::QDeclarativeNearField(QObject *parent)
131 : QObject(parent),
132 m_orderMatch(false),
133 m_componentCompleted(false),
134 m_messageUpdating(false),
135 m_manager(new QNearFieldManager(this)),
136 m_messageHandlerId(-1),
137 m_polling(false)
138{
139 connect(sender: m_manager, SIGNAL(targetDetected(QNearFieldTarget*)),
140 receiver: this, SLOT(_q_handleTargetDetected(QNearFieldTarget*)));
141 connect(sender: m_manager, SIGNAL(targetLost(QNearFieldTarget*)),
142 receiver: this, SLOT(_q_handleTargetLost(QNearFieldTarget*)));
143}
144
145QQmlListProperty<QQmlNdefRecord> QDeclarativeNearField::messageRecords()
146{
147 return QQmlListProperty<QQmlNdefRecord>(this, 0,
148 &QDeclarativeNearField::append_messageRecord,
149 &QDeclarativeNearField::count_messageRecords,
150 &QDeclarativeNearField::at_messageRecord,
151 &QDeclarativeNearField::clear_messageRecords);
152
153}
154
155QQmlListProperty<QDeclarativeNdefFilter> QDeclarativeNearField::filter()
156{
157 return QQmlListProperty<QDeclarativeNdefFilter>(this, 0,
158 &QDeclarativeNearField::append_filter,
159 &QDeclarativeNearField::count_filters,
160 &QDeclarativeNearField::at_filter,
161 &QDeclarativeNearField::clear_filter);
162}
163
164bool QDeclarativeNearField::orderMatch() const
165{
166 return m_orderMatch;
167}
168
169void QDeclarativeNearField::setOrderMatch(bool on)
170{
171 if (m_orderMatch == on)
172 return;
173
174 m_orderMatch = on;
175 emit orderMatchChanged();
176}
177
178void QDeclarativeNearField::componentComplete()
179{
180 m_componentCompleted = true;
181
182 registerMessageHandler();
183}
184
185bool QDeclarativeNearField::polling() const
186{
187 return m_polling;
188}
189
190void QDeclarativeNearField::setPolling(bool on)
191{
192 if (m_polling == on)
193 return;
194
195 if (on) {
196 if (m_manager->startTargetDetection()) {
197 m_polling = true;
198 emit pollingChanged();
199 }
200 } else {
201 m_manager->stopTargetDetection();
202 m_polling = false;
203 emit pollingChanged();
204 }
205}
206
207void QDeclarativeNearField::registerMessageHandler()
208{
209 if (m_messageHandlerId != -1)
210 m_manager->unregisterNdefMessageHandler(handlerId: m_messageHandlerId);
211
212 QNdefFilter ndefFilter;
213 ndefFilter.setOrderMatch(m_orderMatch);
214 for (const QDeclarativeNdefFilter *filter : qAsConst(t&: m_filterList)) {
215 const QString type = filter->type();
216 uint min = filter->minimum() < 0 ? UINT_MAX : filter->minimum();
217 uint max = filter->maximum() < 0 ? UINT_MAX : filter->maximum();
218
219 ndefFilter.appendRecord(typeNameFormat: static_cast<QNdefRecord::TypeNameFormat>(filter->typeNameFormat()), type: type.toUtf8(), min, max);
220 }
221
222 m_messageHandlerId = m_manager->registerNdefMessageHandler(filter: ndefFilter, object: this, SLOT(_q_handleNdefMessage(QNdefMessage)));
223
224 // FIXME: if a message handler has been registered we just assume that constant polling is done
225 if (m_messageHandlerId >= 0) {
226 m_polling = true;
227 emit pollingChanged();
228 }
229}
230
231void QDeclarativeNearField::_q_handleNdefMessage(const QNdefMessage &message)
232{
233 m_messageUpdating = true;
234
235 QQmlListReference listRef(this, "messageRecords");
236
237 listRef.clear();
238
239 for (const QNdefRecord &record : message)
240 listRef.append(qNewDeclarativeNdefRecordForNdefRecord(record));
241
242 m_messageUpdating = false;
243
244 emit messageRecordsChanged();
245}
246
247void QDeclarativeNearField::_q_handleTargetLost(QNearFieldTarget *target)
248{
249 Q_UNUSED(target);
250 // FIXME: only notify that polling stopped when there is no registered message handler
251 if (m_messageHandlerId == -1) {
252 m_polling = false;
253 emit pollingChanged();
254 }
255
256 emit tagRemoved();
257}
258
259void QDeclarativeNearField::_q_handleTargetDetected(QNearFieldTarget *target)
260{
261 Q_UNUSED(target);
262
263 if (m_messageHandlerId == -1) {
264 connect(sender: target, SIGNAL(ndefMessageRead(QNdefMessage)),
265 receiver: this, SLOT(_q_handleNdefMessage(QNdefMessage)));
266 target->readNdefMessages();
267 }
268
269 emit tagFound();
270}
271
272void QDeclarativeNearField::append_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
273 QQmlNdefRecord *record)
274{
275 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
276 if (!nearField)
277 return;
278
279 record->setParent(nearField);
280 nearField->m_message.append(t: record);
281 if (!nearField->m_messageUpdating)
282 emit nearField->messageRecordsChanged();
283}
284
285int QDeclarativeNearField::count_messageRecords(QQmlListProperty<QQmlNdefRecord> *list)
286{
287 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
288 if (!nearField)
289 return 0;
290
291 return nearField->m_message.count();
292}
293
294QQmlNdefRecord *QDeclarativeNearField::at_messageRecord(QQmlListProperty<QQmlNdefRecord> *list,
295 int index)
296{
297 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
298 if (!nearField)
299 return 0;
300
301 return nearField->m_message.at(i: index);
302}
303
304void QDeclarativeNearField::clear_messageRecords(QQmlListProperty<QQmlNdefRecord> *list)
305{
306 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
307 if (nearField) {
308 qDeleteAll(c: nearField->m_message);
309 nearField->m_message.clear();
310 if (!nearField->m_messageUpdating)
311 emit nearField->messageRecordsChanged();
312 }
313}
314
315void QDeclarativeNearField::append_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
316 QDeclarativeNdefFilter *filter)
317{
318 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
319 if (!nearField)
320 return;
321
322 filter->setParent(nearField);
323 nearField->m_filterList.append(t: filter);
324 emit nearField->filterChanged();
325
326 if (nearField->m_componentCompleted)
327 nearField->registerMessageHandler();
328}
329
330int QDeclarativeNearField::count_filters(QQmlListProperty<QDeclarativeNdefFilter> *list)
331{
332 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
333 if (!nearField)
334 return 0;
335
336 return nearField->m_filterList.count();
337}
338
339QDeclarativeNdefFilter *QDeclarativeNearField::at_filter(QQmlListProperty<QDeclarativeNdefFilter> *list,
340 int index)
341{
342 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
343 if (!nearField)
344 return 0;
345
346 return nearField->m_filterList.at(i: index);
347}
348
349void QDeclarativeNearField::clear_filter(QQmlListProperty<QDeclarativeNdefFilter> *list)
350{
351 QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(object: list->object);
352 if (!nearField)
353 return;
354
355 qDeleteAll(c: nearField->m_filterList);
356 nearField->m_filterList.clear();
357 emit nearField->filterChanged();
358 if (nearField->m_componentCompleted)
359 nearField->registerMessageHandler();
360}
361

source code of qtconnectivity/src/imports/nfc/qdeclarativenearfield.cpp