summaryrefslogtreecommitdiffstats
path: root/src/nfc/qnearfieldtarget_android.cpp
diff options
context:
space:
mode:
authorLars Schmertmann <Lars.Schmertmann@governikus.de>2017-01-05 13:43:57 +0100
committerLars Schmertmann <lars.schmertmann@governikus.de>2017-01-18 09:33:47 +0000
commitd977db44ed57fd74562f049e70f336800ff9d585 (patch)
tree8115226741874730604ce3bc66c848643e689544 /src/nfc/qnearfieldtarget_android.cpp
parent44401721f66bdd72da197a14241a66fdb3d11cf4 (diff)
QNearfieldTarget: Introduce (set)keepConnection() and disconnect()
For the communication with a German ID card its required to execute several commands in a row, whereby a state is generated. Every command works on the state created by the command before. Depending on the Android version the state gets lost when the connection is closed. With this change it is possible to keep the connection as long as needed and close it manually. Because of backward compatibility the connection is created and closed automatically by default. With the use of setKeepConnection(true) the communication with the target is also a lot of faster. [ChangeLog][QNearfieldTarget] Introduce (set)keepConnection() and disconnect() to keep the state of a target and speed up communication. Change-Id: I5778c9bdaf04cfeae78b3222bef4475f4cd7c436 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'src/nfc/qnearfieldtarget_android.cpp')
-rw-r--r--src/nfc/qnearfieldtarget_android.cpp252
1 files changed, 152 insertions, 100 deletions
diff --git a/src/nfc/qnearfieldtarget_android.cpp b/src/nfc/qnearfieldtarget_android.cpp
index f41b0b2e..04718fc5 100644
--- a/src/nfc/qnearfieldtarget_android.cpp
+++ b/src/nfc/qnearfieldtarget_android.cpp
@@ -41,26 +41,27 @@
#include "android/androidjninfc_p.h"
#include "qdebug.h"
-#define NDEFTECHNOLOGY "android.nfc.tech.Ndef"
-#define NDEFFORMATABLETECHNOLOGY "android.nfc.tech.NdefFormatable"
-#define ISODEPTECHNOLOGY "android.nfc.tech.IsoDep"
-#define NFCATECHNOLOGY "android.nfc.tech.NfcA"
-#define NFCBTECHNOLOGY "android.nfc.tech.NfcB"
-#define NFCFTECHNOLOGY "android.nfc.tech.NfcF"
-#define NFCVTECHNOLOGY "android.nfc.tech.NfcV"
-#define MIFARECLASSICTECHNOLOGY "android.nfc.tech.MifareClassic"
-#define MIFARECULTRALIGHTTECHNOLOGY "android.nfc.tech.MifareUltralight"
-
-#define MIFARETAG "com.nxp.ndef.mifareclassic"
-#define NFCTAGTYPE1 "org.nfcforum.ndef.type1"
-#define NFCTAGTYPE2 "org.nfcforum.ndef.type2"
-#define NFCTAGTYPE3 "org.nfcforum.ndef.type3"
-#define NFCTAGTYPE4 "org.nfcforum.ndef.type4"
+#define NDEFTECHNOLOGY QStringLiteral("android.nfc.tech.Ndef")
+#define NDEFFORMATABLETECHNOLOGY QStringLiteral("android.nfc.tech.NdefFormatable")
+#define ISODEPTECHNOLOGY QStringLiteral("android.nfc.tech.IsoDep")
+#define NFCATECHNOLOGY QStringLiteral("android.nfc.tech.NfcA")
+#define NFCBTECHNOLOGY QStringLiteral("android.nfc.tech.NfcB")
+#define NFCFTECHNOLOGY QStringLiteral("android.nfc.tech.NfcF")
+#define NFCVTECHNOLOGY QStringLiteral("android.nfc.tech.NfcV")
+#define MIFARECLASSICTECHNOLOGY QStringLiteral("android.nfc.tech.MifareClassic")
+#define MIFARECULTRALIGHTTECHNOLOGY QStringLiteral("android.nfc.tech.MifareUltralight")
+
+#define MIFARETAG QStringLiteral("com.nxp.ndef.mifareclassic")
+#define NFCTAGTYPE1 QStringLiteral("org.nfcforum.ndef.type1")
+#define NFCTAGTYPE2 QStringLiteral("org.nfcforum.ndef.type2")
+#define NFCTAGTYPE3 QStringLiteral("org.nfcforum.ndef.type3")
+#define NFCTAGTYPE4 QStringLiteral("org.nfcforum.ndef.type4")
NearFieldTarget::NearFieldTarget(QAndroidJniObject intent, const QByteArray uid, QObject *parent) :
QNearFieldTarget(parent),
m_intent(intent),
- m_uid(uid)
+ m_uid(uid),
+ m_keepConnection(false)
{
updateTechList();
updateType();
@@ -87,23 +88,54 @@ QNearFieldTarget::AccessMethods NearFieldTarget::accessMethods() const
{
AccessMethods result = UnknownAccess;
- if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))
- || m_techList.contains(QStringLiteral(NDEFFORMATABLETECHNOLOGY)))
+ if (m_techList.contains(NDEFTECHNOLOGY)
+ || m_techList.contains(NDEFFORMATABLETECHNOLOGY))
result |= NdefAccess;
- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))
- || m_techList.contains(QStringLiteral(NFCATECHNOLOGY))
- || m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))
- || m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))
- || m_techList.contains(QStringLiteral(NFCVTECHNOLOGY)))
+ if (m_techList.contains(ISODEPTECHNOLOGY)
+ || m_techList.contains(NFCATECHNOLOGY)
+ || m_techList.contains(NFCBTECHNOLOGY)
+ || m_techList.contains(NFCFTECHNOLOGY)
+ || m_techList.contains(NFCVTECHNOLOGY))
result |= TagTypeSpecificAccess;
return result;
}
+bool NearFieldTarget::keepConnection() const
+{
+ return m_keepConnection;
+}
+
+bool NearFieldTarget::setKeepConnection(bool isPersistent)
+{
+ m_keepConnection = isPersistent;
+
+ if (!m_keepConnection)
+ disconnect();
+
+ return true;
+}
+
+bool NearFieldTarget::disconnect()
+{
+ if (!m_tagTech.isValid())
+ return false;
+
+ bool connected = m_tagTech.callMethod<jboolean>("isConnected");
+ if (catchJavaExceptions())
+ return false;
+
+ if (!connected)
+ return false;
+
+ m_tagTech.callMethod<void>("close");
+ return !catchJavaExceptions();
+}
+
bool NearFieldTarget::hasNdefMessage()
{
- return m_techList.contains(QStringLiteral(NDEFTECHNOLOGY));
+ return m_techList.contains(NDEFTECHNOLOGY);
}
QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
@@ -122,8 +154,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
}
// Getting Ndef technology object
- QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
- if (!ndef.isValid()) {
+ if (!setTagTechnology({NDEFTECHNOLOGY})) {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnsupportedError),
Q_ARG(const QNearFieldTarget::RequestId&, requestId));
@@ -131,8 +162,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
}
// Connect
- ndef.callMethod<void>("connect");
- if (catchJavaExceptions()) {
+ if (!connect()) {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
Q_ARG(const QNearFieldTarget::RequestId&, requestId));
@@ -140,7 +170,7 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
}
// Get NdefMessage object
- QAndroidJniObject ndefMessage = ndef.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;");
+ QAndroidJniObject ndefMessage = m_tagTech.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;");
if (catchJavaExceptions())
ndefMessage = QAndroidJniObject();
if (!ndefMessage.isValid()) {
@@ -154,9 +184,10 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
QAndroidJniObject ndefMessageBA = ndefMessage.callObjectMethod("toByteArray", "()[B");
QByteArray ndefMessageQBA = jbyteArrayToQByteArray(ndefMessageBA.object<jbyteArray>());
- // Closing connection
- ndef.callMethod<void>("close");
- catchJavaExceptions(); // IOException at this point does not matter anymore.
+ if (!m_keepConnection) {
+ // Closing connection
+ disconnect(); // IOException at this point does not matter anymore.
+ }
// Sending QNdefMessage, requestCompleted and exit.
QNdefMessage qNdefMessage = QNdefMessage::fromByteArray(ndefMessageQBA);
@@ -173,24 +204,22 @@ QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
int NearFieldTarget::maxCommandLength() const
{
QAndroidJniObject tagTech;
- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCFTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCVTECHNOLOGY));
- } else {
+ if (m_techList.contains(ISODEPTECHNOLOGY))
+ tagTech = getTagTechnology(ISODEPTECHNOLOGY);
+ else if (m_techList.contains(NFCATECHNOLOGY))
+ tagTech = getTagTechnology(NFCATECHNOLOGY);
+ else if (m_techList.contains(NFCBTECHNOLOGY))
+ tagTech = getTagTechnology(NFCBTECHNOLOGY);
+ else if (m_techList.contains(NFCFTECHNOLOGY))
+ tagTech = getTagTechnology(NFCFTECHNOLOGY);
+ else if (m_techList.contains(NFCVTECHNOLOGY))
+ tagTech = getTagTechnology(NFCVTECHNOLOGY);
+ else
return 0;
- }
int returnVal = tagTech.callMethod<jint>("getMaxTransceiveLength");
- if (catchJavaExceptions()) {
+ if (catchJavaExceptions())
return 0;
- }
return returnVal;
}
@@ -208,26 +237,14 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
QAndroidJniEnvironment env;
- QAndroidJniObject tagTech;
- if (m_techList.contains(QStringLiteral(ISODEPTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(ISODEPTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCATECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCBTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCFTECHNOLOGY));
- } else if (m_techList.contains(QStringLiteral(NFCVTECHNOLOGY))) {
- tagTech = getTagTechnology(QStringLiteral(NFCVTECHNOLOGY));
- } else {
+ if (!setTagTechnology({ISODEPTECHNOLOGY, NFCATECHNOLOGY, NFCBTECHNOLOGY, NFCFTECHNOLOGY, NFCVTECHNOLOGY})) {
Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId());
return QNearFieldTarget::RequestId();
}
// Connecting
QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
- tagTech.callMethod<void>("connect");
- if (catchJavaExceptions()) {
+ if (!connect()) {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
Q_ARG(const QNearFieldTarget::RequestId&, requestId));
@@ -240,7 +257,7 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
// Writing
- QAndroidJniObject myNewVal = tagTech.callObjectMethod("transceive", "([B)[B", jba);
+ QAndroidJniObject myNewVal = m_tagTech.callObjectMethod("transceive", "([B)[B", jba);
if (catchJavaExceptions()) {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::CommandError),
@@ -252,9 +269,10 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
handleResponse(requestId, result);
- // Closing connection, sending signal and exit
- tagTech.callMethod<void>("close");
- catchJavaExceptions(); // IOException at this point does not matter anymore.
+ if (!m_keepConnection) {
+ // Closing connection
+ disconnect(); // IOException at this point does not matter anymore.
+ }
QMetaObject::invokeMethod(this, "requestCompleted", Qt::QueuedConnection,
Q_ARG(const QNearFieldTarget::RequestId&, requestId));
@@ -264,9 +282,8 @@ QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &comma
QNearFieldTarget::RequestId NearFieldTarget::sendCommands(const QList<QByteArray> &commands)
{
QNearFieldTarget::RequestId requestId;
- for (int i=0; i < commands.size(); i++){
+ for (int i=0; i < commands.size(); i++)
requestId = sendCommand(commands.at(i));
- }
return requestId;
}
@@ -282,22 +299,18 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdef
const char *writeMethod;
QAndroidJniObject tagTechnology;
+ if (!setTagTechnology({NDEFFORMATABLETECHNOLOGY, NDEFTECHNOLOGY}))
+ return QNearFieldTarget::RequestId();
+
// Getting write method
- if (m_techList.contains(QStringLiteral(NDEFFORMATABLETECHNOLOGY))) {
- tagTechnology = getTagTechnology(QStringLiteral(NDEFFORMATABLETECHNOLOGY));
+ if (m_tech == NDEFFORMATABLETECHNOLOGY)
writeMethod = "format";
- } else if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))) {
- tagTechnology = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
+ else
writeMethod = "writeNdefMessage";
- } else {
- // An invalid request id will be returned if the target does not support writing NDEF messages.
- return QNearFieldTarget::RequestId();
- }
// Connecting
QNearFieldTarget::RequestId requestId = QNearFieldTarget::RequestId(new QNearFieldTarget::RequestIdPrivate());
- tagTechnology.callMethod<void>("connect");
- if (catchJavaExceptions()) {
+ if (!connect()) {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
Q_ARG(const QNearFieldTarget::RequestId&, requestId));
@@ -326,9 +339,8 @@ QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdef
return requestId;
}
- // Closing connection, sending signal and exit
- tagTechnology.callMethod<void>("close");
- catchJavaExceptions(); // IOException at this point does not matter anymore.
+ if (!m_keepConnection)
+ disconnect(); // IOException at this point does not matter anymore.
QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection);
return requestId;
}
@@ -350,19 +362,26 @@ void NearFieldTarget::setIntent(QAndroidJniObject intent)
void NearFieldTarget::checkIsTargetLost()
{
- if (!m_intent.isValid() || m_techList.isEmpty()) {
+ if (!m_intent.isValid() || !setTagTechnology(m_techList)) {
handleTargetLost();
return;
}
- // Using first available technology to check connection
- QString techStr = m_techList.first();
- QAndroidJniObject tagTech = getTagTechnology(techStr);
- tagTech.callMethod<void>("connect");
+
+ bool connected = m_tagTech.callMethod<jboolean>("isConnected");
+ if (catchJavaExceptions()) {
+ handleTargetLost();
+ return;
+ }
+
+ if (connected)
+ return;
+
+ m_tagTech.callMethod<void>("connect");
if (catchJavaExceptions(false)) {
handleTargetLost();
return;
}
- tagTech.callMethod<void>("close");
+ m_tagTech.callMethod<void>("close");
if (catchJavaExceptions(false))
handleTargetLost();
}
@@ -406,28 +425,28 @@ QNearFieldTarget::Type NearFieldTarget::getTagType() const
{
QAndroidJniEnvironment env;
- if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))) {
- QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
+ if (m_techList.contains(NDEFTECHNOLOGY)) {
+ QAndroidJniObject ndef = getTagTechnology(NDEFTECHNOLOGY);
QString qtype = ndef.callObjectMethod("getType", "()Ljava/lang/String;").toString();
- if (qtype.compare(QStringLiteral(MIFARETAG)) == 0)
+ if (qtype.compare(MIFARETAG) == 0)
return MifareTag;
- if (qtype.compare(QStringLiteral(NFCTAGTYPE1)) == 0)
+ if (qtype.compare(NFCTAGTYPE1) == 0)
return NfcTagType1;
- if (qtype.compare(QStringLiteral(NFCTAGTYPE2)) == 0)
+ if (qtype.compare(NFCTAGTYPE2) == 0)
return NfcTagType2;
- if (qtype.compare(QStringLiteral(NFCTAGTYPE3)) == 0)
+ if (qtype.compare(NFCTAGTYPE3) == 0)
return NfcTagType3;
- if (qtype.compare(QStringLiteral(NFCTAGTYPE4)) == 0)
+ if (qtype.compare(NFCTAGTYPE4) == 0)
return NfcTagType4;
return ProprietaryTag;
- } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) {
- if (m_techList.contains(QStringLiteral(MIFARECLASSICTECHNOLOGY)))
+ } else if (m_techList.contains(NFCATECHNOLOGY)) {
+ if (m_techList.contains(MIFARECLASSICTECHNOLOGY))
return MifareTag;
// Checking ATQA/SENS_RES
// xxx0 0000 xxxx xxxx: Identifies tag Type 1 platform
- QAndroidJniObject nfca = getTagTechnology(QStringLiteral(NFCATECHNOLOGY));
+ QAndroidJniObject nfca = getTagTechnology(NFCATECHNOLOGY);
QAndroidJniObject atqaBA = nfca.callObjectMethod("getAtqa", "()[B");
QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA.object<jbyteArray>());
if (atqaQBA.isEmpty())
@@ -444,9 +463,9 @@ QNearFieldTarget::Type NearFieldTarget::getTagType() const
else if ((sakS & 0x0064) == 0x0020)
return NfcTagType4;
return ProprietaryTag;
- } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) {
+ } else if (m_techList.contains(NFCBTECHNOLOGY)) {
return NfcTagType4;
- } else if (m_techList.contains(QStringLiteral(NFCFTECHNOLOGY))) {
+ } else if (m_techList.contains(NFCFTECHNOLOGY)) {
return NfcTagType3;
}
@@ -457,7 +476,7 @@ void NearFieldTarget::setupTargetCheckTimer()
{
m_targetCheckTimer = new QTimer(this);
m_targetCheckTimer->setInterval(1000);
- connect(m_targetCheckTimer, SIGNAL(timeout()), this, SLOT(checkIsTargetLost()));
+ QObject::connect(m_targetCheckTimer, &QTimer::timeout, this, &NearFieldTarget::checkIsTargetLost);
m_targetCheckTimer->start();
}
@@ -475,9 +494,42 @@ QAndroidJniObject NearFieldTarget::getTagTechnology(const QString &tech) const
// Getting requested technology
QAndroidJniObject tag = AndroidNfc::getTag(m_intent);
const QString sig = QString::fromUtf8("(Landroid/nfc/Tag;)L%1;");
- QAndroidJniObject tagtech = QAndroidJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get",
+ QAndroidJniObject tagTech = QAndroidJniObject::callStaticObjectMethod(techClass.toUtf8().constData(), "get",
sig.arg(techClass).toUtf8().constData(), tag.object<jobject>());
- return tagtech;
+
+ return tagTech;
+}
+
+bool NearFieldTarget::setTagTechnology(const QStringList &techList)
+{
+ for (const QString &tech : techList) {
+ if (m_techList.contains(tech)) {
+ if (m_tech == tech) {
+ return true;
+ }
+ m_tech = tech;
+ m_tagTech = getTagTechnology(tech);
+ return m_tagTech.isValid();
+ }
+ }
+
+ return false;
+}
+
+bool NearFieldTarget::connect()
+{
+ if (!m_tagTech.isValid())
+ return false;
+
+ bool connected = m_tagTech.callMethod<jboolean>("isConnected");
+ if (catchJavaExceptions())
+ return false;
+
+ if (connected)
+ return true;
+
+ m_tagTech.callMethod<void>("connect");
+ return !catchJavaExceptions();
}
QByteArray NearFieldTarget::jbyteArrayToQByteArray(const jbyteArray &byteArray) const