Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnearfieldtarget_neard_p.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 BlackBerry Limited, Copyright (C) 2016 BasysKom GmbH
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
8#include <qndefnfcurirecord.h>
9
11
13
16 m_tagPath(interfacePath),
17 m_readRequested(false)
18{
19 m_readErrorTimer.setSingleShot(true);
20 m_recordPathsCollectedTimer.setSingleShot(true);
21 m_delayedWriteTimer.setSingleShot(true);
22
23 qCDebug(QT_NFC_NEARD) << "tag found at path" << interfacePath.path();
24 m_dbusProperties = new OrgFreedesktopDBusPropertiesInterface(QStringLiteral("org.neard"),
25 interfacePath.path(), QDBusConnection::systemBus(), this);
26 if (!m_dbusProperties->isValid()) {
27 qCWarning(QT_NFC_NEARD) << "Could not connect to dbus property interface at path"
28 << interfacePath.path();
29 return;
30 }
31
32 QDBusPendingReply<QVariantMap> reply = m_dbusProperties->GetAll(QStringLiteral("org.neard.Tag"));
33 reply.waitForFinished();
34 if (reply.isError()) {
35 qCWarning(QT_NFC_NEARD) << "Could not get properties of org.neard.Tag dbus interface";
36 return;
37 }
38
39 const QString &type = reply.value().value(QStringLiteral("Type")).toString();
41
42 if (type == QStringLiteral("Type 1"))
44 else if (type == QStringLiteral("Type 2"))
46 else if (type == QStringLiteral("Type 3"))
48 else if (type == QStringLiteral("Type 4"))
50
51 qCDebug(QT_NFC_NEARD) << "tag type" << type;
52
53 connect(&m_recordPathsCollectedTimer, &QTimer::timeout,
54 this, &QNearFieldTargetPrivateImpl::createNdefMessage);
55 connect(&m_readErrorTimer, &QTimer::timeout,
56 this, &QNearFieldTargetPrivateImpl::handleReadError);
57 connect(&m_delayedWriteTimer, &QTimer::timeout,
58 this, &QNearFieldTargetPrivateImpl::handleWriteRequest);
60 this, &QNearFieldTargetPrivateImpl::handleRecordFound);
61}
62
64{
65}
66
68{
69 return m_dbusProperties->isValid() && NeardHelper::instance()->dbusObjectManager()->isValid();
70}
71
73{
74 return QByteArray(); // TODO figure out a workaround because neard does not offer
75 // this property
76}
77
79{
80 return m_type;
81}
82
83QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
84{
86}
87
89{
90 return !m_recordPaths.isEmpty();
91}
92
94{
95 if (isValid()) {
96 // if the user calls readNdefMessages before the previous request has been completed
97 // return the current request id.
98 if (m_currentReadRequestId.isValid())
99 return m_currentReadRequestId;
100
102 // save the id so it can be passed along with requestCompleted
103 m_currentReadRequestId = requestId;
104 // since the triggering of interfaceAdded will ultimately lead to createNdefMessage being called
105 // we need to make sure that ndefMessagesRead will only be triggered when readNdefMessages has
106 // been called before. In case readNdefMessages is called again after that we can directly call
107 // call createNdefMessage.
108 m_readRequested = true;
109 if (hasNdefMessage())
110 createNdefMessage();
111 else
112 m_readErrorTimer.start(1000);
113
114 return requestId;
115 } else {
117 }
118}
119
121{
122 Q_UNUSED(command);
124}
125
127{
128 // disabling write due to neard crash (see QTBUG-43802)
129 qWarning("QNearFieldTarget::WriteNdefMessages() disabled. See QTBUG-43802\n");
131
132
133 // return old request id when previous write request hasn't completed
134 if (m_currentWriteRequestId.isValid())
135 return m_currentWriteRequestId;
136
137 qCDebug(QT_NFC_NEARD) << "writing messages";
138 if (messages.isEmpty() || messages.first().isEmpty()) {
139 qCWarning(QT_NFC_NEARD) << "No record specified";
141 }
142 if (messages.count() > 1 || messages.first().count() > 1) {
143 // neard only supports one ndef record per tag
144 qCWarning(QT_NFC_NEARD) << "Writing of only one NDEF record and message is supported";
146 }
147 QNdefRecord record = messages.first().first();
148
149 if (record.typeNameFormat() == QNdefRecord::NfcRtd) {
150 m_currentWriteRequestData.clear();
151 if (record.isRecordType<QNdefNfcUriRecord>()) {
152 m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("URI"));
153 QNdefNfcUriRecord uriRecord = static_cast<QNdefNfcUriRecord>(record);
154 m_currentWriteRequestData.insert(QStringLiteral("URI"), uriRecord.uri().toString());
155 } else if (record.isRecordType<QNdefNfcSmartPosterRecord>()) {
156 m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("SmartPoster"));
158 m_currentWriteRequestData.insert(QStringLiteral("URI"), spRecord.uri().toString());
159 // Currently neard only supports the uri property for writing
160 } else if (record.isRecordType<QNdefNfcTextRecord>()) {
161 m_currentWriteRequestData.insert(QStringLiteral("Type"), QStringLiteral("Text"));
162 QNdefNfcTextRecord textRecord = static_cast<QNdefNfcTextRecord>(record);
163 m_currentWriteRequestData.insert(QStringLiteral("Representation"), textRecord.text());
164 m_currentWriteRequestData.insert(QStringLiteral("Encoding"),
165 textRecord.encoding() == QNdefNfcTextRecord::Utf8 ?
166 QStringLiteral("UTF-8") : QStringLiteral("UTF-16") );
167 m_currentWriteRequestData.insert(QStringLiteral("Language"), textRecord.locale());
168 } else {
169 qCWarning(QT_NFC_NEARD) << "Record type not supported for writing";
171 }
172
174 // trigger delayed write
175 m_delayedWriteTimer.start(100);
176
177 return m_currentWriteRequestId;
178 }
179
181}
182
183QNdefRecord QNearFieldTargetPrivateImpl::readRecord(const QDBusObjectPath &path)
184{
185 qCDebug(QT_NFC_NEARD) << "reading record for path" << path.path();
186 OrgFreedesktopDBusPropertiesInterface recordInterface(QStringLiteral("org.neard"), path.path(),
188 if (!recordInterface.isValid())
189 return QNdefRecord();
190
191 QDBusPendingReply<QVariantMap> reply = recordInterface.GetAll(QStringLiteral("org.neard.Record"));
192 reply.waitForFinished();
193 if (reply.isError())
194 return QNdefRecord();
195
196 const QString &value = reply.value().value(QStringLiteral("Representation")).toString();
197 const QString &locale = reply.value().value(QStringLiteral("Language")).toString();
198 const QString &encoding = reply.value().value(QStringLiteral("Encoding")).toString();
199 const QString &uri = reply.value().value(QStringLiteral("URI")).toString();
200
201 //const QString &mime = reply.value().value(QStringLiteral("MIME")).toString();
202 //const QString &arr = reply.value().value(QStringLiteral("ARR")).toString();
203
204 const QString type = reply.value().value(QStringLiteral("Type")).toString();
205 if (type == QStringLiteral("Text")) {
206 QNdefNfcTextRecord textRecord;
207 textRecord.setText(value);
208 textRecord.setLocale(locale);
209 textRecord.setEncoding((encoding == QStringLiteral("UTF-8")) ? QNdefNfcTextRecord::Utf8
210 : QNdefNfcTextRecord::Utf16);
211 return textRecord;
212 } else if (type == QStringLiteral("SmartPoster")) {
214 if (!value.isEmpty()) {
215 spRecord.addTitle(value, locale, (encoding == QStringLiteral("UTF-8"))
217 : QNdefNfcTextRecord::Utf16);
218 }
219
220 if (!uri.isEmpty())
221 spRecord.setUri(QUrl(uri));
222
223 const QString &action = reply.value().value(QStringLiteral("Action")).toString();
224 if (!action.isEmpty()) {
225 if (action == QStringLiteral("Do"))
226 spRecord.setAction(QNdefNfcSmartPosterRecord::DoAction);
227 else if (action == QStringLiteral("Save"))
228 spRecord.setAction(QNdefNfcSmartPosterRecord::SaveAction);
229 else if (action == QStringLiteral("Edit"))
230 spRecord.setAction(QNdefNfcSmartPosterRecord::EditAction);
231 }
232
233 if (reply.value().contains(QStringLiteral("Size"))) {
234 uint size = reply.value().value(QStringLiteral("Size")).toUInt();
235 spRecord.setSize(size);
236 }
237
238 const QString &mimeType = reply.value().value(QStringLiteral("MIMEType")).toString();
239 if (!mimeType.isEmpty()) {
240 spRecord.setTypeInfo(mimeType);
241 }
242
243
244 return spRecord;
245 } else if (type == QStringLiteral("URI")) {
246 QNdefNfcUriRecord uriRecord;
247 uriRecord.setUri(QUrl(uri));
248 return uriRecord;
249 } else if (type == QStringLiteral("MIME")) {
250
251 } else if (type == QStringLiteral("AAR")) {
252
253 }
254
255 return QNdefRecord();
256}
257
258void QNearFieldTargetPrivateImpl::handleRecordFound(const QDBusObjectPath &path)
259{
260 m_recordPaths.append(path);
261 // FIXME: this timer only exists because neard doesn't currently supply enough
262 // information to let us know when all record interfaces have been added or
263 // how many records are actually contained on a tag. We assume that when no
264 // signal has been received for 100ms all record interfaces have been added.
265 m_recordPathsCollectedTimer.start(100);
266 // as soon as record paths have been added we can handle errors without the timer.
267 m_readErrorTimer.stop();
268}
269
270void QNearFieldTargetPrivateImpl::createNdefMessage()
271{
272 if (m_readRequested) {
273 qCDebug(QT_NFC_NEARD) << "creating Ndef message, reading" << m_recordPaths.length() << "record paths";
274 QNdefMessage newNdefMessage;
275 for (const QDBusObjectPath &recordPath : std::as_const(m_recordPaths))
276 newNdefMessage.append(readRecord(recordPath));
277
278 if (!newNdefMessage.isEmpty()) {
279 QMetaObject::invokeMethod(this, "ndefMessageRead", Qt::QueuedConnection,
280 Q_ARG(QNdefMessage, newNdefMessage));
281 // the request id in requestCompleted has to match the one created in readNdefMessages
282 QMetaObject::invokeMethod(this, [this]() {
283 Q_EMIT requestCompleted(m_currentReadRequestId);
285 } else {
286 reportError(QNearFieldTarget::UnknownError, m_currentReadRequestId);
287 }
288
289 m_readRequested = false;
290 // invalidate the current request id
291 m_currentReadRequestId = QNearFieldTarget::RequestId(0);
292 }
293}
294
295void QNearFieldTargetPrivateImpl::handleReadError()
296{
297 reportError(QNearFieldTarget::UnknownError, m_currentReadRequestId);
298 m_currentReadRequestId = QNearFieldTarget::RequestId(0);
299}
300
301void QNearFieldTargetPrivateImpl::handleWriteRequest()
302{
303 OrgNeardTagInterface tagInterface(QStringLiteral("org.neard"), m_tagPath.path(),
305 if (!tagInterface.isValid()) {
306 qCWarning(QT_NFC_NEARD) << "tag interface invalid";
307 } else {
309 reply = tagInterface.Write(m_currentWriteRequestData);
310 reply.waitForFinished();
311 if (reply.isError()) {
312 qCWarning(QT_NFC_NEARD) << "Error writing to NFC tag" << reply.error();
313 reportError(QNearFieldTarget::UnknownError, m_currentWriteRequestId);
314 }
315
316 QMetaObject::invokeMethod(this, [this]() {
317 Q_EMIT requestCompleted(m_currentWriteRequestId);
319 }
320
321 // invalidate current write request
322 m_currentWriteRequestId = QNearFieldTarget::RequestId(0);
323}
324
static NeardHelper * instance()
void recordFound(const QDBusObjectPath &)
\inmodule QtCore
Definition qbytearray.h:57
bool isValid() const
Returns true if this is a valid reference to a remote object.
static QDBusConnection systemBus()
Returns a QDBusConnection object opened with the system bus.
\inmodule QtDBus
QString path() const
Returns this object path.
bool isEmpty() const noexcept
Definition qlist.h:401
qsizetype length() const noexcept
Definition qlist.h:399
void append(parameter_type t)
Definition qlist.h:458
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
void clear()
Definition qmap.h:289
The QNdefMessage class provides an NFC NDEF message.
The QNdefNfcSmartPosterRecord class provides an NFC RTD-SmartPoster.
bool addTitle(const QNdefNfcTextRecord &text)
Attempts to add a title record text to the smart poster.
The QNdefNfcTextRecord class provides an NFC RTD-Text.
void setText(const QString text)
Sets the contents of the text record to text.
The QNdefNfcUriRecord class provides an NFC RTD-URI.
void setUri(const QUrl &uri)
Sets the URI of this URI record to uri.
The QNdefRecord class provides an NFC NDEF record.
Definition qndefrecord.h:16
QNearFieldTarget::RequestId writeNdefMessages(const QList< QNdefMessage > &messages) override
QNearFieldTarget::RequestId readNdefMessages() override
QNearFieldTarget::Type type() const override
QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override
QNearFieldTarget::AccessMethods accessMethods() const override
QByteArray uid() const override
void requestCompleted(const QNearFieldTarget::RequestId &id)
void reportError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
\inmodule QtNfc \inheaderfile QNearFieldTarget
bool isValid() const
Returns true if this is a valid request id; otherwise returns false.
Type
This enum describes the type of tag the target is detected as.
NetworkError error() const
Returns the error that was found during the processing of this request.
\inmodule QtCore
Definition qobject.h:103
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
void stop()
Stops the timer.
Definition qtimer.cpp:267
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
\inmodule QtCore
Definition qurl.h:94
list append(new Employee("Blackpool", "Stephen"))
Q_QML_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName)
Provides locale specific properties and formatted data.
Combined button and popup list for selecting options.
@ QueuedConnection
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const char * mimeType
QNearFieldTarget::RequestId requestId
#define qWarning
Definition qlogging.h:166
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
#define Q_ARG(Type, data)
Definition qobjectdefs.h:63
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum type
GLsizei const GLchar *const * path
#define QStringLiteral(str)
#define Q_EMIT
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
MyRecord record(int row) const
[0]
QNetworkReply * reply
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...