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_android.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Centria research and development
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qdebug.h"
7
8#define NDEFTECHNOLOGY QStringLiteral("android.nfc.tech.Ndef")
9#define NDEFFORMATABLETECHNOLOGY QStringLiteral("android.nfc.tech.NdefFormatable")
10#define ISODEPTECHNOLOGY QStringLiteral("android.nfc.tech.IsoDep")
11#define NFCATECHNOLOGY QStringLiteral("android.nfc.tech.NfcA")
12#define NFCBTECHNOLOGY QStringLiteral("android.nfc.tech.NfcB")
13#define NFCFTECHNOLOGY QStringLiteral("android.nfc.tech.NfcF")
14#define NFCVTECHNOLOGY QStringLiteral("android.nfc.tech.NfcV")
15#define MIFARECLASSICTECHNOLOGY QStringLiteral("android.nfc.tech.MifareClassic")
16#define MIFARECULTRALIGHTTECHNOLOGY QStringLiteral("android.nfc.tech.MifareUltralight")
17
18#define MIFARETAG QStringLiteral("com.nxp.ndef.mifareclassic")
19#define NFCTAGTYPE1 QStringLiteral("org.nfcforum.ndef.type1")
20#define NFCTAGTYPE2 QStringLiteral("org.nfcforum.ndef.type2")
21#define NFCTAGTYPE3 QStringLiteral("org.nfcforum.ndef.type3")
22#define NFCTAGTYPE4 QStringLiteral("org.nfcforum.ndef.type4")
23
25 const QByteArray uid,
26 QObject *parent)
28 targetIntent(intent),
29 targetUid(uid)
30{
32 updateType();
34}
35
41
46
51
52QNearFieldTarget::AccessMethods QNearFieldTargetPrivateImpl::accessMethods() const
53{
54 QNearFieldTarget::AccessMethods result = QNearFieldTarget::UnknownAccess;
55
56 if (techList.contains(NDEFTECHNOLOGY)
59
60 if (techList.contains(ISODEPTECHNOLOGY)
61 || techList.contains(NFCATECHNOLOGY)
62 || techList.contains(NFCBTECHNOLOGY)
63 || techList.contains(NFCFTECHNOLOGY)
64 || techList.contains(NFCVTECHNOLOGY))
66
67 return result;
68}
69
71{
72 if (!tagTech.isValid())
73 return false;
75 bool connected = tagTech.callMethod<jboolean>("isConnected");
76 if (!connected)
77 return false;
78 auto methodId = env.findMethod<void>(tagTech.objectClass(), "close");
79 if (!methodId)
80 return false;
81 env->CallVoidMethod(tagTech.object(), methodId);
82 return !env.checkAndClearExceptions();
83}
84
89
91{
92 // Making sure that target has NDEF messages
93 if (!hasNdefMessage())
95
96 // Making sure that target is still in range
98 if (!targetIntent.isValid()) {
100 return requestId;
101 }
102
103 // Getting Ndef technology object
106 return requestId;
107 }
108
109 // Connect
110 if (!connect()) {
112 return requestId;
113 }
114
115 // Get NdefMessage object
116 QJniObject ndefMessage = tagTech.callMethod<QtJniTypes::NdefMessage>("getNdefMessage");
117 if (!ndefMessage.isValid()) {
119 return requestId;
120 }
121
122 // Convert to byte array
123 QJniObject ndefMessageBA = ndefMessage.callMethod<jbyteArray>("toByteArray");
124 QByteArray ndefMessageQBA = jbyteArrayToQByteArray(ndefMessageBA.object<jbyteArray>());
125
126 // Sending QNdefMessage, requestCompleted and exit.
127 QNdefMessage qNdefMessage = QNdefMessage::fromByteArray(ndefMessageQBA);
128 QMetaObject::invokeMethod(this, [this, qNdefMessage]() {
129 Q_EMIT this->q_ptr->ndefMessageRead(qNdefMessage);
131 QMetaObject::invokeMethod(this, [this, requestId]() {
132 Q_EMIT this->requestCompleted(requestId);
134 QMetaObject::invokeMethod(this, [this, qNdefMessage, requestId]() {
135 //TODO This is an Android specific signal in NearFieldTarget.
136 // We need to check if it is still necessary.
137 Q_EMIT this->ndefMessageRead(qNdefMessage, requestId);
139 return requestId;
140}
141
143{
145 if (techList.contains(ISODEPTECHNOLOGY))
147 else if (techList.contains(NFCATECHNOLOGY))
149 else if (techList.contains(NFCBTECHNOLOGY))
151 else if (techList.contains(NFCFTECHNOLOGY))
153 else if (techList.contains(NFCVTECHNOLOGY))
155 else
156 return 0;
157
158 return tagTech.callMethod<jint>("getMaxTransceiveLength");
159}
160
162{
163 if (command.size() == 0 || command.size() > maxCommandLength()) {
166 }
167
168 // Making sure that target has commands
171
172 QJniEnvironment env;
173
177 }
178
179 // Connecting
181 if (!connect()) {
183 return requestId;
184 }
185
186 // Making QByteArray
187 QByteArray ba(command);
188 jbyteArray jba = env->NewByteArray(ba.size());
189 env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
190
191 // Writing
192 QJniObject myNewVal = tagTech.callMethod<jbyteArray>("transceive", jba);
193 if (!myNewVal.isValid()) {
194 // Some devices (Samsung, Huawei) throw an exception when the card is lost:
195 // "android.nfc.TagLostException: Tag was lost". But there seems to be a bug that
196 // isConnected still reports true. So we need to invalidate the target as soon as
197 // possible and treat the card as lost.
199
201 return requestId;
202 }
203 QByteArray result = jbyteArrayToQByteArray(myNewVal.object<jbyteArray>());
204 env->DeleteLocalRef(jba);
205
207
208 QMetaObject::invokeMethod(this, [this, requestId]() {
209 Q_EMIT this->requestCompleted(requestId);
211
212 return requestId;
213}
214
216{
217 if (messages.size() == 0)
219
220 if (messages.size() > 1)
221 qWarning("QNearFieldTarget::writeNdefMessages: Android supports writing only one NDEF message per tag.");
222
223 QJniEnvironment env;
224 const char *writeMethod;
225
228
229 // Getting write method
231 writeMethod = "format";
232 else
233 writeMethod = "writeNdefMessage";
234
235 // Connecting
237 if (!connect()) {
239 return requestId;
240 }
241
242 // Making NdefMessage object
243 const QNdefMessage &message = messages.first();
244 QByteArray ba = message.toByteArray();
245 QJniObject jba = env->NewByteArray(ba.size());
246 env->SetByteArrayRegion(jba.object<jbyteArray>(), 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
247 QJniObject jmessage = QJniObject::construct<QtJniTypes::NdefMessage>(jba.object<jbyteArray>());
248 if (!jmessage.isValid()) {
250 return requestId;
251 }
252
253 // Writing
254 auto methodId =
255 env.findMethod<void, QtJniTypes::NdefMessage>(tagTech.objectClass(), writeMethod);
256 if (methodId)
257 env->CallVoidMethod(tagTech.object(), methodId, jmessage.object<jobject>());
258 if (!methodId || env.checkAndClearExceptions()) {
260 return requestId;
261 }
262
263 QMetaObject::invokeMethod(this, [this, requestId]() {
264 Q_EMIT this->requestCompleted(requestId);
266 return requestId;
267}
268
270{
271 if (targetIntent == intent)
272 return;
273
275 targetIntent = intent;
276 if (targetIntent.isValid()) {
277 // Updating tech list and type in case of there is another tag with same UID as one before.
279 updateType();
281 }
282}
283
285{
286 if (!targetIntent.isValid() || !setTagTechnology({selectedTech})) {
288 return;
289 }
290
291 QJniEnvironment env;
292 bool connected = false;
293 auto methodId = env.findMethod<jboolean>(tagTech.objectClass(), "isConnected");
294 if (methodId)
295 connected = env->CallBooleanMethod(tagTech.object(), methodId);
296 if (!methodId || env.checkAndClearExceptions()) {
298 return;
299 }
300
301 if (connected)
302 return;
303
304 methodId = env.findMethod<void>(tagTech.objectClass(), "connect");
305 if (methodId)
306 env->CallVoidMethod(tagTech.object(), methodId);
307 if (!methodId || env.checkAndClearExceptions(QJniEnvironment::OutputMode::Silent)) {
309 return;
310 }
311 methodId = env.findMethod<void>(tagTech.objectClass(), "close");
312 if (methodId)
313 env->CallVoidMethod(tagTech.object(), methodId);
314 if (!methodId || env.checkAndClearExceptions(QJniEnvironment::OutputMode::Silent))
316}
317
324
326{
327 if (!targetIntent.isValid())
328 return;
329
330 // Getting tech list
331 QJniEnvironment env;
333 Q_ASSERT_X(tag.isValid(), "updateTechList", "could not get Tag object");
334
335 QJniObject techListArray = tag.callMethod<QtJniTypes::StringArray>("getTechList");
336 if (!techListArray.isValid()) {
338 return;
339 }
340
341 // Converting tech list array to QStringList.
342 techList.clear();
343 jsize techCount = env->GetArrayLength(techListArray.object<jobjectArray>());
344 for (jsize i = 0; i < techCount; ++i) {
345 QJniObject tech = env->GetObjectArrayElement(techListArray.object<jobjectArray>(), i);
346 techList.append(tech.callMethod<jstring>("toString").toString());
347 }
348}
349
354
356{
357 if (techList.contains(NDEFTECHNOLOGY)) {
359 QString qtype = ndef.callMethod<jstring>("getType").toString();
360
361 if (qtype.compare(MIFARETAG) == 0)
363 if (qtype.compare(NFCTAGTYPE1) == 0)
365 if (qtype.compare(NFCTAGTYPE2) == 0)
367 if (qtype.compare(NFCTAGTYPE3) == 0)
369 if (qtype.compare(NFCTAGTYPE4) == 0)
372 } else if (techList.contains(NFCATECHNOLOGY)) {
373 if (techList.contains(MIFARECLASSICTECHNOLOGY))
375
376 // Checking ATQA/SENS_RES
377 // xxx0 0000 xxxx xxxx: Identifies tag Type 1 platform
379 QJniObject atqaBA = nfca.callMethod<jbyteArray>("getAtqa");
380 QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA.object<jbyteArray>());
381 if (atqaQBA.isEmpty())
383 if ((atqaQBA[0] & 0x1F) == 0x00)
385
386 // Checking SAK/SEL_RES
387 // xxxx xxxx x00x x0xx: Identifies tag Type 2 platform
388 // xxxx xxxx x01x x0xx: Identifies tag Type 4 platform
389 jshort sakS = nfca.callMethod<jshort>("getSak");
390 if ((sakS & 0x0064) == 0x0000)
392 else if ((sakS & 0x0064) == 0x0020)
395 } else if (techList.contains(NFCBTECHNOLOGY)) {
397 } else if (techList.contains(NFCFTECHNOLOGY)) {
399 }
400
402}
403
411
417
419{
420 QString techClass(tech);
421 techClass.replace(QLatin1Char('.'), QLatin1Char('/'));
422
423 // Getting requested technology
425 Q_ASSERT_X(tag.isValid(), "getTagTechnology", "could not get Tag object");
426
427 const QString sig = QString::fromUtf8("(Landroid/nfc/Tag;)L%1;");
428 QJniObject tagTech = QJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get",
429 sig.arg(techClass).toUtf8().constData(), tag.object<jobject>());
430
431 return tagTech;
432}
433
435{
436 for (const QString &tech : technologies) {
437 if (techList.contains(tech)) {
438 if (selectedTech == tech) {
439 return true;
440 }
441 selectedTech = tech;
443 return tagTech.isValid();
444 }
445 }
446
447 return false;
448}
449
451{
452 if (!tagTech.isValid())
453 return false;
454
455 QJniEnvironment env;
456 auto methodId = env.findMethod<jboolean>(tagTech.objectClass(), "isConnected");
457 bool connected = false;
458 if (methodId)
459 connected = env->CallBooleanMethod(tagTech.object(), methodId);
460 if (!methodId || env.checkAndClearExceptions())
461 return false;
462
463 if (connected)
464 return true;
465
466 setCommandTimeout(2000);
467 methodId = env.findMethod<void>(tagTech.objectClass(), "connect");
468 if (!methodId)
469 return false;
470 env->CallVoidMethod(tagTech.object(), methodId);
471 return !env.checkAndClearExceptions();
472}
473
475{
476 if (!tagTech.isValid())
477 return false;
478
479 QJniEnvironment env;
480 auto methodId = env.findMethod<void, jint>(tagTech.objectClass(), "setTimeout");
481 if (methodId)
482 env->CallVoidMethod(tagTech.object(), methodId, timeout);
483 return methodId && !env.checkAndClearExceptions();
484}
485
487{
488 QJniEnvironment env;
489 QByteArray resultArray;
490 jsize len = env->GetArrayLength(byteArray);
491 resultArray.resize(len);
492 env->GetByteArrayRegion(byteArray, 0, len, reinterpret_cast<jbyte*>(resultArray.data()));
493 return resultArray;
494}
bool connected
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
\inmodule QtCore
The QNdefMessage class provides an NFC NDEF message.
static Q_NFC_EXPORT QNdefMessage fromByteArray(const QByteArray &message)
Returns an NDEF message parsed from the contents of message.
void targetDestroyed(const QByteArray &tagId)
QJniObject getTagTechnology(const QString &tech) const
void targetLost(QNearFieldTargetPrivateImpl *target)
QNearFieldTarget::RequestId writeNdefMessages(const QList< QNdefMessage > &messages) override
bool setTagTechnology(const QStringList &technologies)
QNearFieldTarget::Type getTagType() const
QNearFieldTarget::RequestId readNdefMessages() override
QNearFieldTargetPrivateImpl(QJniObject intent, const QByteArray uid, QObject *parent=nullptr)
void ndefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id)
QNearFieldTarget::Type type() const override
QNearFieldTarget::RequestId sendCommand(const QByteArray &command) override
QByteArray jbyteArrayToQByteArray(const jbyteArray &byteArray) const
QNearFieldTarget::AccessMethods accessMethods() const override
QByteArray uid() const override
virtual void setResponseForRequest(const QNearFieldTarget::RequestId &id, const QVariant &response, bool emitRequestCompleted=true)
void requestCompleted(const QNearFieldTarget::RequestId &id)
void reportError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
\inmodule QtNfc \inheaderfile QNearFieldTarget
Type
This enum describes the type of tag the target is detected as.
void ndefMessageRead(const QNdefMessage &message)
This signal is emitted when a complete NDEF message has been read from the target.
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8870
QByteArray toUtf8() const &
Definition qstring.h:634
\inmodule QtCore
Definition qtimer.h:20
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
void setInterval(int msec)
Definition qtimer.cpp:579
void stop()
Stops the timer.
Definition qtimer.cpp:267
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
QJniObject getTag(const QJniObject &intent)
@ QueuedConnection
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
QNearFieldTarget::RequestId requestId
#define qWarning
Definition qlogging.h:166
#define NFCBTECHNOLOGY
#define NFCTAGTYPE4
#define MIFARETAG
#define MIFARECLASSICTECHNOLOGY
#define NFCVTECHNOLOGY
#define NFCTAGTYPE1
#define NFCATECHNOLOGY
#define NFCFTECHNOLOGY
#define NDEFTECHNOLOGY
#define NFCTAGTYPE2
#define ISODEPTECHNOLOGY
#define NFCTAGTYPE3
#define NDEFFORMATABLETECHNOLOGY
GLbitfield GLuint64 timeout
[4]
GLuint GLsizei const GLchar * message
GLuint64EXT * result
[6]
GLenum GLsizei len
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define Q_EMIT
QByteArray ba
[0]
char * toString(const MyType &t)
[31]
\inmodule QtCore \reentrant
Definition qchar.h:18
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...