| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtNfc module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qdeclarativenearfield_p.h" |
| #include "qdeclarativendeffilter_p.h" |
| #include "qdeclarativendeftextrecord_p.h" |
| #include "qdeclarativendefurirecord_p.h" |
| #include "qdeclarativendefmimerecord_p.h" |
| |
| #include <qndefmessage.h> |
| #include <qndefnfctextrecord.h> |
| #include <qndefnfcurirecord.h> |
| |
| #include <QtNfc/QNearFieldTarget> |
| |
| /*! |
| \qmltype NearField |
| \instantiates QDeclarativeNearField |
| \since 5.2 |
| \brief Provides access to NDEF messages stored on NFC Forum tags. |
| |
| \ingroup nfc-qml |
| \inqmlmodule QtNfc |
| |
| \sa NdefFilter |
| \sa NdefRecord |
| |
| \sa QNearFieldManager |
| \sa QNdefMessage |
| \sa QNdefRecord |
| |
| The NearField type can be used to read NDEF messages from NFC Forum tags. Set the \l filter |
| and \l orderMatch properties to match the required NDEF messages. Once an NDEF message is |
| successfully read from a tag the \l messageRecords property is updated. |
| |
| \note For platforms using neard, filtering is currently not implemented. For more information |
| on neard see \l QNearFieldManager. |
| |
| \snippet doc_src_qtnfc.qml QML register for messages |
| */ |
| |
| /*! |
| \qmlproperty list<NdefRecord> NearField::messageRecords |
| |
| This property contains the list of NDEF records in the last NDEF message read. |
| */ |
| |
| /*! |
| \qmlproperty list<NdefFilter> NearField::filter |
| |
| This property holds the NDEF filter constraints. The \l messageRecords property will only be |
| set to NDEF messages which match the filter. If no filter is set, a message handler for |
| all NDEF messages will be registered. |
| |
| \note Filtering is not supported when using neard. |
| |
| \l QNearFieldManager::registerNdefMessageHandler() |
| */ |
| |
| /*! |
| \qmlproperty bool NearField::orderMatch |
| |
| This property indicates whether the order of records should be taken into account when matching |
| messages. This is not supported when using neard. |
| |
| The default of orderMatch is false. |
| */ |
| |
| /*! |
| \qmlproperty bool NearField::polling |
| \since 5.5 |
| |
| This property indicates if the underlying adapter is currently in polling state. If set to \c true |
| the adapter will start polling and stop polling if set to \c false. |
| |
| \note On platforms using neard, the adapter will stop polling as soon as a tag has been detected. |
| For more information see \l QNearFieldManager. |
| */ |
| |
| /*! |
| \qmlsignal NearField::tagFound() |
| \since 5.5 |
| |
| This signal will be emitted when a tag has been detected. |
| */ |
| |
| /*! |
| \qmlsignal NearField::tagRemoved() |
| \since 5.5 |
| |
| This signal will be emitted when a tag has been removed. |
| */ |
| |
| QDeclarativeNearField::QDeclarativeNearField(QObject *parent) |
| : QObject(parent), |
| m_orderMatch(false), |
| m_componentCompleted(false), |
| m_messageUpdating(false), |
| m_manager(new QNearFieldManager(this)), |
| m_messageHandlerId(-1), |
| m_polling(false) |
| { |
| connect(m_manager, SIGNAL(targetDetected(QNearFieldTarget*)), |
| this, SLOT(_q_handleTargetDetected(QNearFieldTarget*))); |
| connect(m_manager, SIGNAL(targetLost(QNearFieldTarget*)), |
| this, SLOT(_q_handleTargetLost(QNearFieldTarget*))); |
| } |
| |
| QQmlListProperty<QQmlNdefRecord> QDeclarativeNearField::messageRecords() |
| { |
| return QQmlListProperty<QQmlNdefRecord>(this, 0, |
| &QDeclarativeNearField::append_messageRecord, |
| &QDeclarativeNearField::count_messageRecords, |
| &QDeclarativeNearField::at_messageRecord, |
| &QDeclarativeNearField::clear_messageRecords); |
| |
| } |
| |
| QQmlListProperty<QDeclarativeNdefFilter> QDeclarativeNearField::filter() |
| { |
| return QQmlListProperty<QDeclarativeNdefFilter>(this, 0, |
| &QDeclarativeNearField::append_filter, |
| &QDeclarativeNearField::count_filters, |
| &QDeclarativeNearField::at_filter, |
| &QDeclarativeNearField::clear_filter); |
| } |
| |
| bool QDeclarativeNearField::orderMatch() const |
| { |
| return m_orderMatch; |
| } |
| |
| void QDeclarativeNearField::setOrderMatch(bool on) |
| { |
| if (m_orderMatch == on) |
| return; |
| |
| m_orderMatch = on; |
| emit orderMatchChanged(); |
| } |
| |
| void QDeclarativeNearField::componentComplete() |
| { |
| m_componentCompleted = true; |
| |
| registerMessageHandler(); |
| } |
| |
| bool QDeclarativeNearField::polling() const |
| { |
| return m_polling; |
| } |
| |
| void QDeclarativeNearField::setPolling(bool on) |
| { |
| if (m_polling == on) |
| return; |
| |
| if (on) { |
| if (m_manager->startTargetDetection()) { |
| m_polling = true; |
| emit pollingChanged(); |
| } |
| } else { |
| m_manager->stopTargetDetection(); |
| m_polling = false; |
| emit pollingChanged(); |
| } |
| } |
| |
| void QDeclarativeNearField::registerMessageHandler() |
| { |
| if (m_messageHandlerId != -1) |
| m_manager->unregisterNdefMessageHandler(m_messageHandlerId); |
| |
| QNdefFilter ndefFilter; |
| ndefFilter.setOrderMatch(m_orderMatch); |
| for (const QDeclarativeNdefFilter *filter : qAsConst(m_filterList)) { |
| const QString type = filter->type(); |
| uint min = filter->minimum() < 0 ? UINT_MAX : filter->minimum(); |
| uint max = filter->maximum() < 0 ? UINT_MAX : filter->maximum(); |
| |
| ndefFilter.appendRecord(static_cast<QNdefRecord::TypeNameFormat>(filter->typeNameFormat()), type.toUtf8(), min, max); |
| } |
| |
| m_messageHandlerId = m_manager->registerNdefMessageHandler(ndefFilter, this, SLOT(_q_handleNdefMessage(QNdefMessage))); |
| |
| // FIXME: if a message handler has been registered we just assume that constant polling is done |
| if (m_messageHandlerId >= 0) { |
| m_polling = true; |
| emit pollingChanged(); |
| } |
| } |
| |
| void QDeclarativeNearField::_q_handleNdefMessage(const QNdefMessage &message) |
| { |
| m_messageUpdating = true; |
| |
| QQmlListReference listRef(this, "messageRecords"); |
| |
| listRef.clear(); |
| |
| for (const QNdefRecord &record : message) |
| listRef.append(qNewDeclarativeNdefRecordForNdefRecord(record)); |
| |
| m_messageUpdating = false; |
| |
| emit messageRecordsChanged(); |
| } |
| |
| void QDeclarativeNearField::_q_handleTargetLost(QNearFieldTarget *target) |
| { |
| Q_UNUSED(target); |
| // FIXME: only notify that polling stopped when there is no registered message handler |
| if (m_messageHandlerId == -1) { |
| m_polling = false; |
| emit pollingChanged(); |
| } |
| |
| emit tagRemoved(); |
| } |
| |
| void QDeclarativeNearField::_q_handleTargetDetected(QNearFieldTarget *target) |
| { |
| Q_UNUSED(target); |
| |
| if (m_messageHandlerId == -1) { |
| connect(target, SIGNAL(ndefMessageRead(QNdefMessage)), |
| this, SLOT(_q_handleNdefMessage(QNdefMessage))); |
| target->readNdefMessages(); |
| } |
| |
| emit tagFound(); |
| } |
| |
| void QDeclarativeNearField::append_messageRecord(QQmlListProperty<QQmlNdefRecord> *list, |
| QQmlNdefRecord *record) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return; |
| |
| record->setParent(nearField); |
| nearField->m_message.append(record); |
| if (!nearField->m_messageUpdating) |
| emit nearField->messageRecordsChanged(); |
| } |
| |
| int QDeclarativeNearField::count_messageRecords(QQmlListProperty<QQmlNdefRecord> *list) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return 0; |
| |
| return nearField->m_message.count(); |
| } |
| |
| QQmlNdefRecord *QDeclarativeNearField::at_messageRecord(QQmlListProperty<QQmlNdefRecord> *list, |
| int index) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return 0; |
| |
| return nearField->m_message.at(index); |
| } |
| |
| void QDeclarativeNearField::clear_messageRecords(QQmlListProperty<QQmlNdefRecord> *list) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (nearField) { |
| qDeleteAll(nearField->m_message); |
| nearField->m_message.clear(); |
| if (!nearField->m_messageUpdating) |
| emit nearField->messageRecordsChanged(); |
| } |
| } |
| |
| void QDeclarativeNearField::append_filter(QQmlListProperty<QDeclarativeNdefFilter> *list, |
| QDeclarativeNdefFilter *filter) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return; |
| |
| filter->setParent(nearField); |
| nearField->m_filterList.append(filter); |
| emit nearField->filterChanged(); |
| |
| if (nearField->m_componentCompleted) |
| nearField->registerMessageHandler(); |
| } |
| |
| int QDeclarativeNearField::count_filters(QQmlListProperty<QDeclarativeNdefFilter> *list) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return 0; |
| |
| return nearField->m_filterList.count(); |
| } |
| |
| QDeclarativeNdefFilter *QDeclarativeNearField::at_filter(QQmlListProperty<QDeclarativeNdefFilter> *list, |
| int index) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return 0; |
| |
| return nearField->m_filterList.at(index); |
| } |
| |
| void QDeclarativeNearField::clear_filter(QQmlListProperty<QDeclarativeNdefFilter> *list) |
| { |
| QDeclarativeNearField *nearField = qobject_cast<QDeclarativeNearField *>(list->object); |
| if (!nearField) |
| return; |
| |
| qDeleteAll(nearField->m_filterList); |
| nearField->m_filterList.clear(); |
| emit nearField->filterChanged(); |
| if (nearField->m_componentCompleted) |
| nearField->registerMessageHandler(); |
| } |