summaryrefslogtreecommitdiff
path: root/src/nfc
diff options
context:
space:
mode:
authorJuhana Jauhiainen <juhana.jauhiainen@gmail.com>2013-07-29 10:22:08 +0300
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-01-08 11:49:10 +0100
commitd50039ca0cc5c4168fa77579b524f9c5464ad186 (patch)
tree88e179d960f596d7ebc9a6d3824a8cf0d073dc5d /src/nfc
parentd9b50136b15a2236f4f4f01254034ecb87601673 (diff)
downloadqtconnectivity-d50039ca0cc5c4168fa77579b524f9c5464ad186.tar.gz
Squashed code contribtion for QtNfc on Android
The code was contributed by Juhana Jauhiainen <juhana.jauhiainen@gmail.com> osaukko <osaukko@gmail.com> waz <markus.liuska@gmail.fi> List of squashed commits: Preliminary Android support to QtNFC. Only receiving Ndef messages to QNearFieldManager. QNearFieldTarget and LLCP classes need to be implemented for Android ------------------ Added Android buildsettings to nfc.pro Including Android implementation in QNearFieldManager.h ------------------ QtNfc namespace removed. ------------------ Added Android support to QNearFieldManager::isAvailable() method ------------------ Improved isAvailable method ------------------ Fix QtNfc java module Added checking for NfcAdapter object so that calling QNearFieldManager::startTargetDetection() and QNearFieldManager::stopTargetDetection() methods will not crash application. ------------------ Added support for tag types. NFC tag type is now included in onNdefDiscovered() method call. Only showing information in debug messages for now. ------------------ Fixing missing return values and releasing acquired resources. ------------------ First proof of concept version of target creation for android. ------------------ Fix for include guards. ------------------ Added QHash container for NearFieldmanager Added QHash container for NearFieldManager which holds each discovered targets. Also added setters for NearFieldTarget. ------------------ Using signals and slots to move target information to main thread. Fixes problem when creating new targets as child of manager. ------------------ Fix for tag detection for tags without NDEF messages Tag type checking is not working if there is no NDEF messages currently. Need to find way to check tag type without Ndef object. ------------------ Added error reporting for QNearFieldTarget::readNdefMessages (Android) ------------------ Registering type name for QNearFieltTarget. Small refactoring for QNearFieldTarget android implementation. ------------------ Sending UID as bytearray. Also debug messages to show tech list added into QtNfc.java. ------------------ Trying different approach for android version of QtNfc module. In this approach we pass through intent object(Java) to NearFieldTarget object(c++). ------------------ Fixed nfc.pro so QtNfc.jar is built. ------------------ Added tech list into android version of QNearFieldTarget Could be used to detect availability of NDEF messages and also to detect tag type. ------------------ Fixed build files so both the C++ and Java libraries are built correctly. ------------------ Support for writing Ndef messages. ------------------ Implementation for NearFieldTarget::hasNdefMessage(). Also nice debug messages to show available technologies for current tag. ------------------ Support for NdefFormatable tags. ------------------ Support for writing NdefFormatable tags. ------------------ Removed debug messages. ------------------ Implemented type() method to Android's QNearFieldTarget. Conflicts: src/nfc/qnearfieldtarget_android.cpp src/nfc/qnearfieldtarget_android_p.h ------------------ Small fixes to remove some of the warnings. Conflicts: src/nfc/qnearfieldtarget_android.cpp src/nfc/qnearfieldtarget_android_p.h ------------------ Committing test code for targetLost signal (Because of Merge) Conflicts: src/nfc/qnearfieldtarget_android.cpp src/nfc/qnearfieldtarget_android_p.h ------------------ Added support for target lost signal ------------------ Using QString::fromUtf8 instead of QString() Conflicts: src/nfc/qnearfieldtarget_android.cpp ------------------ Fixed bug with targetLost not emitting when reading or writing Ndef messages. Added some untested code for sendCommand. ------------------ Refactoring. Conflicts: src/nfc/qnearfieldtarget_android_p.h ------------------ Refactoring and fixes. ------------------ Less debug messages. ------------------ Refactoring and cleaning. Conflicts: src/android/android.pro src/nfc/neard/neard_helper_p.h src/nfc/nfc.pro src/nfc/qdeclarativendefrecord.cpp src/nfc/qdeclarativendefrecord.h src/nfc/qllcpserver_p.h src/nfc/qllcpsocket.h src/nfc/qndefmessage.h src/nfc/qndefnfcsmartposterrecord_p.h src/nfc/qnearfieldmanager.cpp src/nfc/qnearfieldmanager_neard_p.h src/nfc/qnearfieldtarget.h src/nfc/qnfcglobal.h src/src.pro tests/nfctestserver/socketcontroller.h Change-Id: Ideb4c8c8064f46b431532ea4870207691bc49c99 Reviewed-by: Peter Rustler <peter.rustler@basyskom.com> Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com> Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/nfc')
-rw-r--r--src/nfc/android/androidglobal.h49
-rw-r--r--src/nfc/android/androidjninfc.cpp214
-rw-r--r--src/nfc/android/androidjninfc_p.h80
-rw-r--r--src/nfc/nfc.pro34
-rw-r--r--src/nfc/qllcpserver_android_p.cpp129
-rw-r--r--src/nfc/qllcpserver_android_p.h83
-rw-r--r--src/nfc/qllcpsocket_android_p.cpp326
-rw-r--r--src/nfc/qllcpsocket_android_p.h125
-rw-r--r--src/nfc/qnearfieldmanager.cpp2
-rw-r--r--src/nfc/qnearfieldmanager_android.cpp243
-rw-r--r--src/nfc/qnearfieldmanager_android_p.h98
-rw-r--r--src/nfc/qnearfieldtarget_android.cpp496
-rw-r--r--src/nfc/qnearfieldtarget_android_p.h110
13 files changed, 1988 insertions, 1 deletions
diff --git a/src/nfc/android/androidglobal.h b/src/nfc/android/androidglobal.h
new file mode 100644
index 00000000..271ab2c3
--- /dev/null
+++ b/src/nfc/android/androidglobal.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDGLOBAL_H
+#define ANDROIDGLOBAL_H
+
+#define QT_USE_ANDROIDNFC_NAMESPACE using namespace ::AndroidNfc;
+#define QT_BEGIN_ANDROIDNFC_NAMESPACE namespace AndroidNfc {
+#define QT_END_ANDROIDNFC_NAMESPACE }
+
+#endif // ANDROIDGLOBAL_H
diff --git a/src/nfc/android/androidjninfc.cpp b/src/nfc/android/androidjninfc.cpp
new file mode 100644
index 00000000..6a46c422
--- /dev/null
+++ b/src/nfc/android/androidjninfc.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjninfc_p.h"
+
+#include <android/log.h>
+
+#include "qglobal.h"
+#include "qlist.h"
+#include "qreadwritelock.h"
+#include "qbytearray.h"
+#include "qdebug.h"
+
+static JavaVM *javaVM = 0;
+static jclass nfcClass;
+
+static jmethodID startDiscoveryId;
+static jmethodID stopDiscoveryId;
+static jmethodID isAvailableId;
+
+static QList<AndroidNfc::AndroidNfcListenerInterface*> listeners;
+QReadWriteLock listenersLock;
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+AttachedJNIEnv::AttachedJNIEnv()
+{
+ Q_ASSERT_X(javaVM != 0, "constructor", "javaVM pointer is null");
+ attached = false;
+ if (javaVM->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) {
+ if (javaVM->AttachCurrentThread(&jniEnv, NULL) < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed");
+ jniEnv = 0;
+ return;
+ }
+ attached = true;
+ }
+}
+
+AttachedJNIEnv::~AttachedJNIEnv()
+{
+ if (attached)
+ javaVM->DetachCurrentThread();
+}
+
+bool startDiscovery()
+{
+ //__android_log_print(ANDROID_LOG_INFO, "Qt", "QtNfc::startDiscovery()");
+ AttachedJNIEnv aenv;
+ if (!aenv.jniEnv)
+ return false;
+
+ aenv.jniEnv->CallStaticObjectMethod(nfcClass, startDiscoveryId);
+ return true;
+}
+
+bool isAvailable()
+{
+ //__android_log_print(ANDROID_LOG_INFO, "Qt", "QtNfc::isAvailable()");
+ AttachedJNIEnv aenv;
+ if (!aenv.jniEnv)
+ return false;
+
+ return aenv.jniEnv->CallStaticBooleanMethod(nfcClass, isAvailableId);
+}
+
+bool stopDiscovery()
+{
+ AttachedJNIEnv aenv;
+ if (!aenv.jniEnv)
+ return false;
+
+ aenv.jniEnv->CallStaticObjectMethod(nfcClass, stopDiscoveryId);
+ return true;
+}
+
+bool registerListener(AndroidNfcListenerInterface *listener)
+{
+ listenersLock.lockForWrite();
+ listeners.push_back(listener);
+ listenersLock.unlock();
+ return true;
+}
+
+bool unregisterListener(AndroidNfcListenerInterface *listener)
+{
+ listenersLock.lockForWrite();
+ listeners.removeOne(listener);
+ listenersLock.unlock();
+ return true;
+}
+
+jobject getTag(JNIEnv *env, jobject intent)
+{
+ jclass intentClass = env->GetObjectClass(intent);
+ Q_ASSERT_X(intentClass != 0, "getTag", "could not get Intent class");
+
+ jmethodID getParcelableExtraMID = env->GetMethodID(intentClass,
+ "getParcelableExtra",
+ "(Ljava/lang/String;)Landroid/os/Parcelable;");
+ Q_ASSERT_X(getParcelableExtraMID != 0, "getTag", "could not get method ID for getParcelableExtra()");
+
+ jclass nfcAdapterClass = env->FindClass("android/nfc/NfcAdapter");
+ Q_ASSERT_X(nfcAdapterClass != 0, "getTag", "could not find NfcAdapter class");
+
+ jfieldID extraTagFID = env->GetStaticFieldID(nfcAdapterClass, "EXTRA_TAG", "Ljava/lang/String;");
+ Q_ASSERT_X(extraTagFID != 0, "getTag", "could not get field ID for EXTRA_TAG");
+
+ jobject extraTag = env->GetStaticObjectField(nfcAdapterClass, extraTagFID);
+ Q_ASSERT_X(extraTag != 0, "getTag", "could not get EXTRA_TAG");
+
+ jobject tag = env->CallObjectMethod(intent, getParcelableExtraMID, extraTag);
+ Q_ASSERT_X(tag != 0, "getTag", "could not get Tag object");
+
+ return tag;
+}
+
+QT_END_ANDROIDNFC_NAMESPACE
+
+static const char logTag[] = "Qt";
+static const char classErrorMsg[] = "Can't find class \"%s\"";
+static const char methodErrorMsg[] = "Can't find method \"%s%s\"";
+
+static void newIntent(JNIEnv *env, jobject obj, jobject intent)
+{
+ Q_UNUSED(obj);
+ listenersLock.lockForRead();
+ foreach (AndroidNfc::AndroidNfcListenerInterface *listener, listeners) {
+ // Making new global reference for each listener.
+ // Listeners must release reference when it is not used anymore.
+ jobject newIntentRef = env->NewGlobalRef(intent);
+ listener->newIntent(newIntentRef);
+ }
+ listenersLock.unlock();
+}
+
+static JNINativeMethod methods[] = {
+ {"newIntent", "(Landroid/content/Intent;)V", (void*)newIntent}
+};
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+ clazz = env->FindClass(CLASS_NAME); \
+ if (!clazz) { \
+ return JNI_FALSE; \
+ }
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ return JNI_FALSE; \
+ }
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
+{
+ //__android_log_print(ANDROID_LOG_INFO, "Qt", "JNI_OnLoad for QtNfc");
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/nfc/QtNfc");
+ nfcClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ if (env->RegisterNatives(nfcClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL, logTag, "RegisterNatives failed");
+ return JNI_FALSE;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(startDiscoveryId, nfcClass, "start", "()V");
+ GET_AND_CHECK_STATIC_METHOD(stopDiscoveryId, nfcClass, "stop", "()V");
+ GET_AND_CHECK_STATIC_METHOD(isAvailableId, nfcClass, "isAvailable", "()Z");
+ javaVM = vm;
+
+ return JNI_VERSION_1_6;
+}
diff --git a/src/nfc/android/androidjninfc_p.h b/src/nfc/android/androidjninfc_p.h
new file mode 100644
index 00000000..21e3087e
--- /dev/null
+++ b/src/nfc/android/androidjninfc_p.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNINFC_H
+#define ANDROIDJNINFC_H
+
+#include "androidglobal.h"
+#include "qglobal.h"
+
+#include <jni.h>
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+class AndroidNfcListenerInterface
+{
+public:
+ virtual ~AndroidNfcListenerInterface(){}
+ virtual void newIntent(jobject intent) = 0;
+};
+
+class AttachedJNIEnv
+{
+public:
+ AttachedJNIEnv();
+ virtual ~AttachedJNIEnv();
+ bool attached;
+ JNIEnv *jniEnv;
+
+private:
+ Q_DISABLE_COPY(AttachedJNIEnv)
+};
+
+bool startDiscovery();
+bool stopDiscovery();
+bool isAvailable();
+bool registerListener(AndroidNfcListenerInterface *listener);
+bool unregisterListener(AndroidNfcListenerInterface *listener);
+jobject getTag(JNIEnv *env, jobject intent);
+
+QT_END_ANDROIDNFC_NAMESPACE
+
+#endif
diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro
index 7c6b6ff7..30bf26c5 100644
--- a/src/nfc/nfc.pro
+++ b/src/nfc/nfc.pro
@@ -148,6 +148,37 @@ simulator {
qnearfieldsharetargetimpl_p.cpp
}
+# not supported for now
+0 {
+android {
+ NFC_BACKEND_AVAILABLE = yes
+ ANDROID_BUNDLED_JAR_DEPENDENCIES = \
+ jar/QtNfc-bundled.jar:org.qtproject.qt5.android.nfc.QtNfc
+ ANDROID_JAR_DEPENDENCIES = \
+ jar/QtNfc.jar:org.qtproject.qt5.android.nfc.QtNfc
+ DEFINES += ANDROID_NFC #QQNXNFC_DEBUG
+
+ PRIVATE_HEADERS += \
+ qllcpserver_android_p.h \
+ qllcpsocket_android_p.h \
+ android/androidjninfc_p.h \
+ qnearfieldmanager_android_p.h \
+ qnearfieldtarget_android_p.h \
+ qnearfieldsharemanagerimpl_p.h \
+ qnearfieldsharetargetimpl_p.h
+
+
+ SOURCES += \
+ qllcpserver_android_p.cpp \
+ qllcpsocket_android_p.cpp \
+ android/androidjninfc.cpp \
+ qnearfieldmanager_android.cpp \
+ qnearfieldtarget_android.cpp \
+ qnearfieldsharemanagerimpl_p.cpp \
+ qnearfieldsharetargetimpl_p.cpp
+}
+}
+
isEmpty(NFC_BACKEND_AVAILABLE) {
message("Unsupported NFC platform, will not build a working QtNfc library.")
@@ -166,4 +197,5 @@ isEmpty(NFC_BACKEND_AVAILABLE) {
qnearfieldsharetargetimpl_p.cpp
}
-HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS \
+ android/androidglobal.h
diff --git a/src/nfc/qllcpserver_android_p.cpp b/src/nfc/qllcpserver_android_p.cpp
new file mode 100644
index 00000000..19a1bc1b
--- /dev/null
+++ b/src/nfc/qllcpserver_android_p.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qllcpserver_android_p.h"
+//#include "qnx/qnxnfcmanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QLlcpServerPrivate::QLlcpServerPrivate(QLlcpServer *q)
+ : q_ptr(q), m_llcpSocket(0), m_connected(false)
+{
+}
+
+bool QLlcpServerPrivate::listen(const QString &serviceUri)
+{
+ /*//The server is already listening
+ if (isListening())
+ return false;
+
+ nfc_result_t result = nfc_llcp_register_connection_listener(NFC_LLCP_SERVER, 0, serviceUri.toStdString().c_str(), &m_conListener);
+ m_connected = true;
+ if (result == NFC_RESULT_SUCCESS) {
+ m_serviceUri = serviceUri;
+ qQNXNFCDebug() << "LLCP server registered" << serviceUri;
+ } else {
+ qWarning() << Q_FUNC_INFO << "Could not register for llcp connection listener";
+ return false;
+ }
+ QNXNFCManager::instance()->registerLLCPConnection(m_conListener, this);*/
+ return true;
+}
+
+bool QLlcpServerPrivate::isListening() const
+{
+ return m_connected;
+}
+
+void QLlcpServerPrivate::close()
+{
+ /*nfc_llcp_unregister_connection_listener(m_conListener);
+ QNXNFCManager::instance()->unregisterLLCPConnection(m_conListener);
+ m_serviceUri = QString();
+ m_connected = false;*/
+}
+
+QString QLlcpServerPrivate::serviceUri() const
+{
+ return m_serviceUri;
+}
+
+quint8 QLlcpServerPrivate::serverPort() const
+{
+ /*unsigned int sap;
+ if (nfc_llcp_get_local_sap(m_target, &sap) == NFC_RESULT_SUCCESS) {
+ return sap;
+ }*/
+ return -1;
+}
+
+bool QLlcpServerPrivate::hasPendingConnections() const
+{
+ return m_llcpSocket != 0;
+}
+
+QLlcpSocket *QLlcpServerPrivate::nextPendingConnection()
+{
+ /*QLlcpSocket *socket = m_llcpSocket;
+ m_llcpSocket = 0;
+ return socket;*/
+ return 0;
+}
+
+QLlcpSocket::SocketError QLlcpServerPrivate::serverError() const
+{
+ return QLlcpSocket::UnknownSocketError;
+}
+
+/*void QLlcpServerPrivate::connected(nfc_target_t *target)
+{
+ m_target = target;
+ if (m_llcpSocket != 0) {
+ qWarning() << Q_FUNC_INFO << "LLCP socket not cloesed properly";
+ return;
+ }
+ m_llcpSocket = new QLlcpSocket();
+ m_llcpSocket->bind(serverPort());
+}*/
+
+QT_END_NAMESPACE
+
+
diff --git a/src/nfc/qllcpserver_android_p.h b/src/nfc/qllcpserver_android_p.h
new file mode 100644
index 00000000..24e7854e
--- /dev/null
+++ b/src/nfc/qllcpserver_android_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLLCPSERVER_ANDROID_P_H
+#define QLLCPSERVER_ANDROID_P_H
+
+#include "qllcpserver_p.h"
+//#include "nfc/nfc.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLlcpServerPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QLlcpServerPrivate(QLlcpServer *q);
+
+ bool listen(const QString &serviceUri);
+ bool isListening() const;
+
+ void close();
+
+ QString serviceUri() const;
+ quint8 serverPort() const;
+
+ bool hasPendingConnections() const;
+ QLlcpSocket *nextPendingConnection();
+
+ QLlcpSocket::SocketError serverError() const;
+
+ //Q_INVOKABLE void connected(nfc_target_t *);
+
+private:
+ QLlcpServer *q_ptr;
+ QLlcpSocket *m_llcpSocket;
+ //We can not use m_conListener for the connection state
+ bool m_connected;
+ //nfc_llcp_connection_listener_t m_conListener;
+ QString m_serviceUri;
+ //nfc_target_t *m_target;
+};
+
+QT_END_NAMESPACE
+
+#endif // QLLCPSERVER_ANDROID_P_H
diff --git a/src/nfc/qllcpsocket_android_p.cpp b/src/nfc/qllcpsocket_android_p.cpp
new file mode 100644
index 00000000..db1bb972
--- /dev/null
+++ b/src/nfc/qllcpsocket_android_p.cpp
@@ -0,0 +1,326 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qllcpsocket_android_p.h"
+#include <unistd.h>
+
+QT_BEGIN_NAMESPACE
+
+QLlcpSocketPrivate::QLlcpSocketPrivate(QLlcpSocket *q)
+ : q_ptr(q), m_state(QLlcpSocket::UnconnectedState), m_server(false)
+{
+}
+
+QLlcpSocketPrivate::~QLlcpSocketPrivate()
+{
+ disconnectFromService();
+}
+
+void QLlcpSocketPrivate::connectToService(QNearFieldTarget *target, const QString &serviceUri)
+{
+ Q_UNUSED(target)
+ Q_UNUSED(serviceUri)
+ /*if (m_state != QLlcpSocket::UnconnectedState) {
+ qWarning() << Q_FUNC_INFO << "socket is already connected";
+ return;
+ }
+
+ m_state = QLlcpSocket::ConnectingState;
+ if (nfc_llcp_register_connection_listener(NFC_LLCP_CLIENT, 0, serviceUri.toLocal8Bit().constData(),
+ &m_conListener) != NFC_RESULT_SUCCESS) {
+ qWarning() << Q_FUNC_INFO << "could not register for connection listener";
+ return;
+ }
+
+ QNXNFCManager::instance()->registerLLCPConnection(m_conListener, this);
+
+ qQNXNFCDebug() << "Connecting client socket" << serviceUri << m_conListener;
+ connect(QNXNFCManager::instance(), SIGNAL(llcpDisconnected()), this, SLOT(disconnectFromService()));*/
+}
+
+void QLlcpSocketPrivate::disconnectFromService()
+{
+ /*Q_Q(QLlcpSocket);
+ QNXNFCManager::instance()->unregisterTargetLost(this);
+ qQNXNFCDebug() << "Shutting down LLCP socket";
+ if (!m_server && nfc_llcp_unregister_connection_listener(m_conListener) != NFC_RESULT_SUCCESS) {
+ qWarning() << Q_FUNC_INFO << "Error when trying to close LLCP socket";
+ }
+ QNXNFCManager::instance()->unregisterLLCPConnection(m_conListener);
+ disconnect(QNXNFCManager::instance(), SIGNAL(llcpDisconnected()), this, SLOT(disconnectFromService()));
+
+ q->disconnected();
+ m_conListener = 0;
+ m_state = QLlcpSocket::UnconnectedState;*/
+}
+
+bool QLlcpSocketPrivate::bind(quint8 port)
+{
+ Q_UNUSED(port);
+
+ /*m_state = QLlcpSocket::ConnectedState;
+ m_server = true;
+ connect(QNXNFCManager::instance(), SIGNAL(llcpDisconnected()), this, SLOT(disconnectFromService()));
+ connected(QNXNFCManager::instance()->getLastTarget());*/
+
+ return true;
+}
+
+bool QLlcpSocketPrivate::hasPendingDatagrams() const
+{
+ return !m_receivedDatagrams.isEmpty();
+}
+
+qint64 QLlcpSocketPrivate::pendingDatagramSize() const
+{
+ if (m_receivedDatagrams.isEmpty())
+ return -1;
+
+ return m_receivedDatagrams.first().length();
+}
+
+qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size)
+{
+ if (m_state == QLlcpSocket::ConnectedState)
+ return writeData(data, size);
+
+ return -1;
+}
+
+qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram)
+{
+ return writeDatagram(datagram.constData(), datagram.size());
+}
+
+qint64 QLlcpSocketPrivate::readDatagram(char *data, qint64 maxSize,
+ QNearFieldTarget **target, quint8 *port)
+{
+ Q_UNUSED(target);
+ Q_UNUSED(port);
+
+ if (m_state == QLlcpSocket::ConnectedState)
+ return readData(data, maxSize);
+
+ return -1;
+}
+
+qint64 QLlcpSocketPrivate::writeDatagram(const char *data, qint64 size,
+ QNearFieldTarget *target, quint8 port)
+{
+ Q_UNUSED(target);
+ Q_UNUSED(port);
+
+ return writeDatagram(data, size);
+}
+
+qint64 QLlcpSocketPrivate::writeDatagram(const QByteArray &datagram,
+ QNearFieldTarget *target, quint8 port)
+{
+ Q_UNUSED(datagram);
+ Q_UNUSED(target);
+ Q_UNUSED(port);
+
+ return writeDatagram(datagram.constData(), datagram.size()-1);
+}
+
+QLlcpSocket::SocketError QLlcpSocketPrivate::error() const
+{
+ return QLlcpSocket::UnknownSocketError;
+}
+
+QLlcpSocket::SocketState QLlcpSocketPrivate::state() const
+{
+ return m_state;
+}
+
+qint64 QLlcpSocketPrivate::readData(char *data, qint64 maxlen)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ if (m_receivedDatagrams.isEmpty())
+ return 0;
+
+ /*const QByteArray datagram = m_receivedDatagrams.takeFirst();
+ qint64 size = qMin(maxlen, qint64(datagram.length()));
+ memcpy(data, datagram.constData(), size);
+ return size;*/
+ return 0;
+}
+
+qint64 QLlcpSocketPrivate::writeData(const char *data, qint64 len)
+{
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+ /*if (socketState != Idle) {
+ m_writeQueue.append(QByteArray(data, len));
+ return len;
+ } else {
+ socketState = Writing;
+ qQNXNFCDebug() << "LLCP write";
+ nfc_result_t res = nfc_llcp_write(m_target, (uchar_t*)data, (size_t)len);
+ if (res == NFC_RESULT_SUCCESS) {
+ return len;
+ } else {
+ qWarning() << Q_FUNC_INFO << "Error writing to LLCP socket. Error" << res;
+ enteringIdle();
+ return -1;
+ }
+ }*/
+ return -1;
+}
+
+qint64 QLlcpSocketPrivate::bytesAvailable() const
+{
+ /*qint64 available = 0;
+ foreach (const QByteArray &datagram, m_receivedDatagrams)
+ available += datagram.length();
+
+ return available;*/
+ return 0;
+}
+
+bool QLlcpSocketPrivate::canReadLine() const
+{
+ /*foreach (const QByteArray &datagram, m_receivedDatagrams) {
+ if (datagram.contains('\n'))
+ return true;
+ }*/
+
+ return false;
+}
+
+bool QLlcpSocketPrivate::waitForReadyRead(int msecs)
+{
+ Q_UNUSED(msecs);
+
+ return false;
+}
+
+bool QLlcpSocketPrivate::waitForBytesWritten(int msecs)
+{
+ Q_UNUSED(msecs);
+
+ return false;
+}
+
+bool QLlcpSocketPrivate::waitForConnected(int msecs)
+{
+ Q_UNUSED(msecs);
+
+ return false;
+}
+
+bool QLlcpSocketPrivate::waitForDisconnected(int msecs)
+{
+ Q_UNUSED(msecs);
+
+ return false;
+}
+
+/*void QLlcpSocketPrivate::connected(nfc_target_t *target)
+{
+ Q_Q(QLlcpSocket);
+ m_target = target;
+
+ m_state = QLlcpSocket::ConnectedState;
+ emit q->connected();
+ qQNXNFCDebug() << "Socket connected";
+
+ unsigned int targetId;
+ nfc_get_target_connection_id(target, &targetId);
+ QNXNFCManager::instance()->requestTargetLost(this, targetId);
+ enteringIdle();
+}*/
+
+void QLlcpSocketPrivate::targetLost()
+{
+ disconnectFromService();
+ //qQNXNFCDebug() << "LLCP target lost...socket disconnected";
+}
+
+void QLlcpSocketPrivate::dataRead(QByteArray& data)
+{
+ Q_UNUSED(data);
+ /*Q_Q(QLlcpSocket);
+ if (!data.isEmpty()) {
+ m_receivedDatagrams.append(data);
+ emit q->readyRead();
+ }
+ socketState = Idle;
+ enteringIdle();*/
+}
+
+void QLlcpSocketPrivate::dataWritten()
+{
+ //enteringIdle();
+}
+
+void QLlcpSocketPrivate::read()
+{
+ /*if (socketState != Idle) {
+ qQNXNFCDebug() << "Trying to read but socket state not in idle..abort";
+ return;
+ }
+ socketState = Reading;
+ qQNXNFCDebug() << "LLCP read";
+ if (nfc_llcp_read(m_target, 128) != NFC_RESULT_SUCCESS) {
+ qWarning() << Q_FUNC_INFO << "Could not register for reading";
+ socketState = Idle;
+ }*/
+}
+
+void QLlcpSocketPrivate::enteringIdle()
+{
+ /*qQNXNFCDebug() << "entering idle; Socket state:" << socketState;
+ socketState = Idle;
+ if (m_state == QLlcpSocket::ConnectedState) {
+ if (m_writeQueue.isEmpty()) {
+ qQNXNFCDebug() << "Write queue empty, reading in 50ms";
+ QTimer::singleShot(50, this, SLOT(read()));
+ } else {
+ qQNXNFCDebug() << "Write first package in queue";
+ writeDatagram(m_writeQueue.takeFirst());
+ }
+ }*/
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/nfc/qllcpsocket_android_p.h b/src/nfc/qllcpsocket_android_p.h
new file mode 100644
index 00000000..afbc573e
--- /dev/null
+++ b/src/nfc/qllcpsocket_android_p.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLLCPSOCKET_ANDROID_P_H
+#define QLLCPSOCKET_ANDROID_P_H
+
+#include "qllcpsocket_p.h"
+
+//#include "qnearfieldtarget_ANDROID_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QLlcpSocketPrivate : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PUBLIC(QLlcpSocket)
+
+public:
+ QLlcpSocketPrivate(QLlcpSocket *q);
+
+ ~QLlcpSocketPrivate();
+
+ void connectToService(QNearFieldTarget *target, const QString &serviceUri);
+
+ bool bind(quint8 port);
+
+ bool hasPendingDatagrams() const;
+ qint64 pendingDatagramSize() const;
+
+ qint64 writeDatagram(const char *data, qint64 size);
+ qint64 writeDatagram(const QByteArray &datagram);
+
+ qint64 readDatagram(char *data, qint64 maxSize,
+ QNearFieldTarget **target = 0, quint8 *port = 0);
+ qint64 writeDatagram(const char *data, qint64 size,
+ QNearFieldTarget *target, quint8 port);
+ qint64 writeDatagram(const QByteArray &datagram, QNearFieldTarget *target, quint8 port);
+
+ QLlcpSocket::SocketError error() const;
+ QLlcpSocket::SocketState state() const;
+
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+ qint64 bytesAvailable() const;
+ bool canReadLine() const;
+
+ bool waitForReadyRead(int msecs);
+ bool waitForBytesWritten(int msecs);
+ bool waitForConnected(int msecs);
+ bool waitForDisconnected(int msecs);
+
+ //Q_INVOKABLE void connected(nfc_target_t *);
+ Q_INVOKABLE void targetLost();
+
+ void dataRead(QByteArray&);
+ void dataWritten();
+
+public Q_SLOTS:
+ void disconnectFromService();
+
+private:
+ QLlcpSocket *q_ptr;
+ unsigned int m_sap;
+ //nfc_llcp_connection_listener_t m_conListener;
+ //NearFieldTarget *m_target;
+ //nfc_target_t *m_target;
+
+ QLlcpSocket::SocketState m_state;
+
+ QList<QByteArray> m_receivedDatagrams;
+ QList<QByteArray> m_writeQueue;
+
+ bool m_server;
+
+ enum llcpState {
+ Idle, Reading, Writing
+ } socketState;
+
+private Q_SLOTS:
+ void read();
+ void enteringIdle();
+};
+
+QT_END_NAMESPACE
+
+#endif // QLLCPSOCKET_ANDROID_P_H
diff --git a/src/nfc/qnearfieldmanager.cpp b/src/nfc/qnearfieldmanager.cpp
index 7aaf0878..50bee6b1 100644
--- a/src/nfc/qnearfieldmanager.cpp
+++ b/src/nfc/qnearfieldmanager.cpp
@@ -40,6 +40,8 @@
#include "qnearfieldmanager_qnx_p.h"
#elif defined(NEARD_NFC)
#include "qnearfieldmanager_neard_p.h"
+#elif defined(ANDROID_NFC)
+#include "qnearfieldmanager_android_p.h"
#else
#include "qnearfieldmanagerimpl_p.h"
#endif
diff --git a/src/nfc/qnearfieldmanager_android.cpp b/src/nfc/qnearfieldmanager_android.cpp
new file mode 100644
index 00000000..157966e5
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_android.cpp
@@ -0,0 +1,243 @@
+/***************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnearfieldmanager_android_p.h"
+#include "qnearfieldtarget_android_p.h"
+
+#include "qndeffilter.h"
+#include "qndefmessage.h"
+#include "qndefrecord.h"
+#include "qbytearray.h"
+#include "qcoreapplication.h"
+#include "qdebug.h"
+#include "qlist.h"
+
+#include <QtCore/QMetaType>
+#include <QtCore/QMetaMethod>
+
+QT_BEGIN_NAMESPACE
+
+QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() :
+ m_detecting(false)
+{
+ qRegisterMetaType<jobject>("jobject");
+ qRegisterMetaType<QNdefMessage>("QNdefMessage");
+}
+
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+}
+
+bool QNearFieldManagerPrivateImpl::isAvailable() const
+{
+ return AndroidNfc::isAvailable();
+}
+
+bool QNearFieldManagerPrivateImpl::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes)
+{
+ if (m_detecting)
+ return false; // Already detecting targets
+
+ m_detectTargetTypes = targetTypes;
+ AndroidNfc::registerListener(this);
+ AndroidNfc::startDiscovery();
+ m_detecting = true;
+ return true;
+}
+
+void QNearFieldManagerPrivateImpl::stopTargetDetection()
+{
+ AndroidNfc::stopDiscovery();
+ AndroidNfc::unregisterListener(this);
+ m_detecting = false;
+}
+
+int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, const QMetaMethod &method)
+{
+ Q_UNUSED(object);
+ Q_UNUSED(method);
+ return -1;
+
+ //Not supported for now
+ /*
+ ndefMessageHandlers.append(QPair<QPair<int, QObject *>,
+ QMetaMethod>(QPair<int, QObject *>(m_handlerID, object), method));
+
+ //Returns the handler ID and increments it afterwards
+ return m_handlerID++;
+ */
+}
+
+int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter,
+ QObject *object, const QMetaMethod &method)
+{
+ Q_UNUSED(filter);
+ Q_UNUSED(object);
+ Q_UNUSED(method);
+ return -1;
+
+ //Not supported for now
+ /*
+ //If no record is set in the filter, we ignore the filter
+ if (filter.recordCount()==0)
+ return registerNdefMessageHandler(object, method);
+
+ ndefFilterHandlers.append(QPair<QPair<int, QObject*>, QPair<QNdefFilter, QMetaMethod> >
+ (QPair<int, QObject*>(m_handlerID, object),
+ QPair<QNdefFilter, QMetaMethod>(filter, method)));
+
+ // updateNdefFilter();
+
+ return m_handlerID++;
+ */
+}
+
+bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int handlerId)
+{
+ Q_UNUSED(handlerId);
+ return false;
+
+ //Not supported for now
+ /*
+ for (int i=0; i<ndefMessageHandlers.count(); i++) {
+ if (ndefMessageHandlers.at(i).first.first == handlerId) {
+ ndefMessageHandlers.removeAt(i);
+ // updateNdefFilter();
+ return true;
+ }
+ }
+ for (int i=0; i<ndefFilterHandlers.count(); i++) {
+ if (ndefFilterHandlers.at(i).first.first == handlerId) {
+ ndefFilterHandlers.removeAt(i);
+ // updateNdefFilter();
+ return true;
+ }
+ }
+ return false;
+ */
+}
+
+void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes)
+{
+ Q_UNUSED(accessModes);
+ //Do nothing, because we dont have access modes for the target
+}
+
+void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes)
+{
+ Q_UNUSED(accessModes);
+ //Do nothing, because we dont have access modes for the target
+}
+
+void QNearFieldManagerPrivateImpl::newIntent(jobject intent)
+{
+ // This function is called from different thread and is used to move intent to main thread.
+ QMetaObject::invokeMethod(this, "onTargetDiscovered", Qt::QueuedConnection, Q_ARG(jobject, intent));
+}
+
+QByteArray QNearFieldManagerPrivateImpl::getUid(jobject intent)
+{
+ if (intent == 0)
+ return QByteArray();
+
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ jobject tag = AndroidNfc::getTag(env, intent);
+
+ jclass tagClass = env->GetObjectClass(tag);
+ Q_ASSERT_X(tagClass != 0, "getUid", "could not get Tag class");
+
+ jmethodID getIdMID = env->GetMethodID(tagClass, "getId", "()[B");
+ Q_ASSERT_X(getIdMID != 0, "getUid", "could not get method ID for getId()");
+
+ jbyteArray tagId = reinterpret_cast<jbyteArray>(env->CallObjectMethod(tag, getIdMID));
+ Q_ASSERT_X(tagId != 0, "getUid", "getId() returned null object");
+
+ QByteArray uid;
+ jsize len = env->GetArrayLength(tagId);
+ uid.resize(len);
+ env->GetByteArrayRegion(tagId, 0, len, reinterpret_cast<jbyte*>(uid.data()));
+
+ return uid;
+}
+
+void QNearFieldManagerPrivateImpl::onTargetDiscovered(jobject intent)
+{
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ Q_ASSERT_X(env != 0, "onTargetDiscovered", "env pointer is null");
+
+ // Getting tag object and UID
+ jobject tag = AndroidNfc::getTag(env, intent);
+ QByteArray uid = getUid(env, tag);
+
+ // Accepting all targest but only sending signal of requested types.
+ NearFieldTarget *&target = m_detectedTargets[uid];
+ if (target) {
+ target->setIntent(intent); // Updating existing target
+ } else {
+ target = new NearFieldTarget(intent, uid, this);
+ connect(target, SIGNAL(targetDestroyed(QByteArray)), this, SLOT(onTargetDestroyed(QByteArray)));
+ connect(target, SIGNAL(targetLost(QNearFieldTarget*)), this, SIGNAL(targetLost(QNearFieldTarget*)));
+ }
+ if (m_detectTargetTypes.isEmpty() ||
+ m_detectTargetTypes.contains(target->type()))
+ emit targetDetected(target);
+}
+
+void QNearFieldManagerPrivateImpl::onTargetDestroyed(const QByteArray &uid)
+{
+ m_detectedTargets.remove(uid);
+}
+
+QByteArray QNearFieldManagerPrivateImpl::getUid(JNIEnv *env, jobject tag)
+{
+ jclass tagClass = env->GetObjectClass(tag);
+ jmethodID getIdMID = env->GetMethodID(tagClass, "getId", "()[B");
+ jbyteArray tagId = reinterpret_cast<jbyteArray>(env->CallObjectMethod(tag, getIdMID));
+ QByteArray uid;
+ jsize len = env->GetArrayLength(tagId);
+ uid.resize(len);
+ env->GetByteArrayRegion(tagId, 0, len, reinterpret_cast<jbyte*>(uid.data()));
+ return uid;
+}
+
+QT_END_NAMESPACE
diff --git a/src/nfc/qnearfieldmanager_android_p.h b/src/nfc/qnearfieldmanager_android_p.h
new file mode 100644
index 00000000..b534f564
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_android_p.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNEARFIELDMANAGER_ANDROID_P_H
+#define QNEARFIELDMANAGER_ANDROID_P_H
+
+#include "qnearfieldmanager_p.h"
+#include "qnearfieldmanager.h"
+#include "qnearfieldtarget.h"
+#include "android/androidjninfc_p.h"
+
+#include <QHash>
+
+QT_BEGIN_NAMESPACE
+
+typedef QList<QNdefMessage> QNdefMessageList;
+
+class NearFieldTarget;
+class QByteArray;
+class QNearFieldManagerPrivateImpl : public QNearFieldManagerPrivate, public AndroidNfc::AndroidNfcListenerInterface
+{
+ Q_OBJECT
+
+public:
+ QNearFieldManagerPrivateImpl();
+ ~QNearFieldManagerPrivateImpl();
+
+ virtual bool isAvailable() const;
+ virtual bool startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes);
+ virtual void stopTargetDetection();
+ virtual int registerNdefMessageHandler(QObject *object, const QMetaMethod &method);
+ virtual int registerNdefMessageHandler(const QNdefFilter &filter, QObject *object, const QMetaMethod &method);
+ virtual bool unregisterNdefMessageHandler(int handlerId);
+ virtual void requestAccess(QNearFieldManager::TargetAccessModes accessModes);
+ virtual void releaseAccess(QNearFieldManager::TargetAccessModes accessModes);
+ virtual void newIntent(jobject intent);
+ QByteArray getUid(jobject intent);
+
+public slots:
+ void onTargetDiscovered(jobject intent);
+ void onTargetDestroyed(const QByteArray &uid);
+
+protected:
+ static QByteArray getUid(JNIEnv *env, jobject tag);
+
+private:
+ bool m_detecting;
+ QList<QNearFieldTarget::Type> m_detectTargetTypes;
+ QHash<QByteArray, NearFieldTarget*> m_detectedTargets;
+
+ /*
+ int m_handlerID;
+ QList< QPair<QPair<int, QObject *>, QMetaMethod> > ndefMessageHandlers;
+ QList< QPair<QPair<int, QObject *>, QPair<QNdefFilter, QMetaMethod> > > ndefFilterHandlers;
+ */
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDMANAGER_ANDROID_P_H
diff --git a/src/nfc/qnearfieldtarget_android.cpp b/src/nfc/qnearfieldtarget_android.cpp
new file mode 100644
index 00000000..18dbaaec
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_android.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnearfieldtarget_android_p.h"
+#include "android/androidjninfc_p.h"
+#include "qdebug.h"
+
+const QString NearFieldTarget::NdefTechology = QString::fromUtf8("android.nfc.tech.Ndef");
+const QString NearFieldTarget::NdefFormatableTechnology = QString::fromUtf8("android.nfc.tech.NdefFormatable");
+const QString NearFieldTarget::NfcATechnology = QString::fromUtf8("android.nfc.tech.NfcA");
+const QString NearFieldTarget::NfcBTechnology = QString::fromUtf8("android.nfc.tech.NfcB");
+const QString NearFieldTarget::NfcFTechnology = QString::fromUtf8("android.nfc.tech.NfcF");
+const QString NearFieldTarget::NfcVTechnology = QString::fromUtf8("android.nfc.tech.NfcV");
+const QString NearFieldTarget::MifareClassicTechnology = QString::fromUtf8("android.nfc.tech.MifareClassic");
+const QString NearFieldTarget::MifareUltralightTechnology = QString::fromUtf8("android.nfc.tech.MifareUltralight");
+
+
+NearFieldTarget::NearFieldTarget(jobject intent, const QByteArray uid, QObject *parent) :
+ QNearFieldTarget(parent),
+ m_intent(intent),
+ m_uid(uid)
+{
+ updateTechList();
+ updateType();
+ setupTargetCheckTimer();
+}
+
+NearFieldTarget::~NearFieldTarget()
+{
+ releaseIntent();
+ emit targetDestroyed(m_uid);
+}
+
+QByteArray NearFieldTarget::uid() const
+{
+ return m_uid;
+}
+
+QNearFieldTarget::Type NearFieldTarget::type() const
+{
+ return m_type;
+}
+
+QNearFieldTarget::AccessMethods NearFieldTarget::accessMethods() const
+{
+ AccessMethods result = NdefAccess;
+ return result;
+}
+
+bool NearFieldTarget::hasNdefMessage()
+{
+ return m_techList.contains(NdefTechology);
+}
+
+QNearFieldTarget::RequestId NearFieldTarget::readNdefMessages()
+{
+ // Making sure that target has NDEF messages
+ if (!hasNdefMessage())
+ return QNearFieldTarget::RequestId();
+
+ // Making sure that target is still in range
+ QNearFieldTarget::RequestId requestId(new QNearFieldTarget::RequestIdPrivate);
+ if (m_intent == 0) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Getting Ndef technology object
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ Q_ASSERT_X(env != 0, "readNdefMessages", "env pointer is null");
+ jobject ndef = getTagTechnology(NdefTechology, env);
+ if (ndef == 0) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnsupportedError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Connect
+ jclass ndefClass = env->GetObjectClass(ndef);
+ jmethodID connectMID = env->GetMethodID(ndefClass, "connect", "()V");
+ env->CallVoidMethod(ndef, connectMID);
+ if (catchJavaExceptions(env)) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Get NdefMessage object
+ jmethodID getNdefMessageMID = env->GetMethodID(ndefClass, "getNdefMessage", "()Landroid/nfc/NdefMessage;");
+ jobject ndefMessage = env->CallObjectMethod(ndef, getNdefMessageMID);
+ if (catchJavaExceptions(env))
+ ndefMessage = 0;
+ if (ndefMessage == 0) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::NdefReadError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Convert to byte array
+ jclass ndefMessageClass = env->GetObjectClass(ndefMessage);
+ jmethodID toByteArrayMID = env->GetMethodID(ndefMessageClass, "toByteArray", "()[B");
+ jbyteArray ndefMessageBA = reinterpret_cast<jbyteArray>(env->CallObjectMethod(ndefMessage, toByteArrayMID));
+ QByteArray ndefMessageQBA = jbyteArrayToQByteArray(ndefMessageBA, env);
+
+ // Closing connection
+ jmethodID closeMID = env->GetMethodID(ndefClass, "close", "()V");
+ env->CallVoidMethod(ndef, closeMID);
+ catchJavaExceptions(env); // IOException at this point does not matter anymore.
+
+ // Sending QNdefMessage, requestCompleted and exit.
+ QNdefMessage qNdefMessage = QNdefMessage::fromByteArray(ndefMessageQBA);
+ QMetaObject::invokeMethod(this, "ndefMessageRead", Qt::QueuedConnection,
+ Q_ARG(const QNdefMessage&, qNdefMessage));
+ QMetaObject::invokeMethod(this, "requestCompleted", Qt::QueuedConnection,
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+}
+
+
+QNearFieldTarget::RequestId NearFieldTarget::sendCommand(const QByteArray &command)
+{
+ Q_UNUSED(command);
+ Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId());
+ return QNearFieldTarget::RequestId();
+
+ //Not supported for now
+ /*if (command.size() == 0) {
+ Q_EMIT QNearFieldTarget::error(QNearFieldTarget::InvalidParametersError, QNearFieldTarget::RequestId());
+ return QNearFieldTarget::RequestId();
+ }
+
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+
+ jobject tagTech;
+ 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 {
+ Q_EMIT QNearFieldTarget::error(QNearFieldTarget::UnsupportedError, QNearFieldTarget::RequestId());
+ return QNearFieldTarget::RequestId();
+ }
+
+ QByteArray ba(ba);
+
+ jclass techClass = env->GetObjectClass(tagTech);
+ jmethodID tranceiveMID = env->GetMethodID(techClass, "tranceive", "([B)[B");
+ Q_ASSERT_X(tranceiveMID != 0, "sendCommand", "could not find tranceive method");
+
+ jbyteArray jba = env->NewByteArray(ba.size());
+ env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
+
+ jbyteArray rsp = reinterpret_cast<jbyteArray>(env->CallObjectMethod(tagTech, tranceiveMID, jba));
+
+ jsize len = env->GetArrayLength(rsp);
+ QByteArray rspQBA;
+ rspQBA.resize(len);
+
+ env->GetByteArrayRegion(rsp, 0, len, reinterpret_cast<jbyte*>(rspQBA.data()));
+
+ qDebug() << "Send command returned QBA size: " << rspQBA.size();
+
+
+ env->DeleteLocalRef(jba);
+
+
+ return QNearFieldTarget::RequestId();*/
+}
+
+QNearFieldTarget::RequestId NearFieldTarget::sendCommands(const QList<QByteArray> &commands)
+{
+ QNearFieldTarget::RequestId requestId;
+ for (int i=0; i < commands.size(); i++){
+ requestId = sendCommand(commands.at(i));
+ }
+ return requestId;
+}
+
+QNearFieldTarget::RequestId NearFieldTarget::writeNdefMessages(const QList<QNdefMessage> &messages)
+{
+ if (messages.size() == 0)
+ return QNearFieldTarget::RequestId();
+
+ if (messages.size() > 1)
+ qWarning("QNearFieldTarget::writeNdefMessages: Android supports writing only one NDEF message per tag.");
+
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ jmethodID writeMethod;
+ jobject tagTechnology;
+ jclass tagClass;
+
+ // Getting write method
+ if (m_techList.contains(NdefFormatableTechnology)) {
+ tagTechnology = getTagTechnology(NdefFormatableTechnology, env);
+ tagClass = env->GetObjectClass(tagTechnology);
+ writeMethod = env->GetMethodID(tagClass, "format", "(Landroid/nfc/NdefMessage;)V");
+ } else if (m_techList.contains(NdefTechology)) {
+ tagTechnology = getTagTechnology(NdefTechology, env);
+ tagClass = env->GetObjectClass(tagTechnology);
+ writeMethod = env->GetMethodID(tagClass, "writeNdefMessage", "(Landroid/nfc/NdefMessage;)V");
+ } 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());
+ jclass ndefMessageClass = env->FindClass("android/nfc/NdefMessage");
+ jmethodID connectMethodID = env->GetMethodID(tagClass, "connect", "()V");
+ env->CallVoidMethod(tagTechnology, connectMethodID);
+ if (catchJavaExceptions(env)) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Making NdefMessage object
+ jmethodID ndefMessageInitMID = env->GetMethodID(ndefMessageClass, "<init>", "([B)V");
+ const QNdefMessage &message = messages.first();
+ QByteArray ba = message.toByteArray();
+ jbyteArray jba = env->NewByteArray(ba.size());
+ env->SetByteArrayRegion(jba, 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
+ jobject jmessage = env->NewObject(ndefMessageClass, ndefMessageInitMID, jba);
+ if (catchJavaExceptions(env)) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnknownError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Writing
+ env->CallVoidMethod(tagTechnology, writeMethod, jmessage);
+ bool gotException = catchJavaExceptions(env);
+ env->DeleteLocalRef(jba);
+ env->DeleteLocalRef(jmessage);
+ if (gotException) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::NdefWriteError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Closing connection, sending signal and exit
+ jmethodID closeMID = env->GetMethodID(tagClass, "close", "()V");
+ env->CallVoidMethod(tagTechnology, closeMID);
+ catchJavaExceptions(env); // IOException at this point does not matter anymore.
+ QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection);
+ return requestId;
+}
+
+void NearFieldTarget::setIntent(jobject intent)
+{
+ if (m_intent == intent)
+ return;
+
+ releaseIntent();
+ m_intent = intent;
+ if (m_intent) {
+ // Updating tech list and type in case of there is another tag with same UID as one before.
+ updateTechList();
+ updateType();
+ m_targetCheckTimer->start();
+ }
+}
+
+void NearFieldTarget::checkIsTargetLost()
+{
+ if (m_intent == 0 || m_techList.isEmpty()) {
+ handleTargetLost();
+ return;
+ }
+
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+
+ // Using first available technology to check connection
+ QString techStr = m_techList.first();
+ jobject tagTechObj = getTagTechnology(techStr, env);
+ jclass tagTechClass = env->GetObjectClass(tagTechObj);
+ jmethodID connectMID = env->GetMethodID(tagTechClass, "connect","()V");
+ jmethodID closeMID = env->GetMethodID(tagTechClass, "close","()V");
+
+ env->CallObjectMethod(tagTechObj, connectMID);
+ if (catchJavaExceptions(env)) {
+ handleTargetLost();
+ return;
+ }
+ env->CallObjectMethod(tagTechObj, closeMID);
+ if (catchJavaExceptions(env))
+ handleTargetLost();
+}
+
+void NearFieldTarget::releaseIntent()
+{
+ m_targetCheckTimer->stop();
+
+ if (m_intent == 0)
+ return;
+
+ AndroidNfc::AttachedJNIEnv aenv;
+ Q_ASSERT_X(aenv.jniEnv != 0, "releaseIntent", "aenv.jniEnv pointer is null");
+ aenv.jniEnv->DeleteGlobalRef(m_intent);
+ m_intent = 0;
+}
+
+void NearFieldTarget::updateTechList()
+{
+ if (m_intent == 0)
+ return;
+
+ // Getting tech list
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ jobject tag = AndroidNfc::getTag(env, m_intent);
+ jclass tagClass = env->GetObjectClass(tag);
+ jmethodID techListMID = env->GetMethodID(tagClass, "getTechList", "()[Ljava/lang/String;");
+ jobjectArray techListArray = reinterpret_cast<jobjectArray>(env->CallObjectMethod(tag, techListMID));
+ if (techListArray == 0) {
+ handleTargetLost();
+ return;
+ }
+
+ // Converting tech list array to QStringList.
+ m_techList.clear();
+ jsize techCount = env->GetArrayLength(techListArray);
+ for (jsize i = 0; i < techCount; ++i) {
+ jstring tech = reinterpret_cast<jstring>(env->GetObjectArrayElement(techListArray, i));
+ const char *techStr = env->GetStringUTFChars(tech, JNI_FALSE);
+ m_techList.append(QString::fromUtf8(techStr));
+ env->ReleaseStringUTFChars(tech, techStr);
+ }
+}
+
+void NearFieldTarget::updateType()
+{
+ m_type = getTagType();
+}
+
+QNearFieldTarget::Type NearFieldTarget::getTagType() const
+{
+ AndroidNfc::AttachedJNIEnv aenv;
+ JNIEnv *env = aenv.jniEnv;
+ Q_ASSERT_X(env != 0, "type", "env pointer is null");
+
+ if (m_techList.contains(NdefTechology)) {
+ jobject ndef = getTagTechnology(NdefTechology, env);
+ jclass ndefClass = env->GetObjectClass(ndef);
+
+ jmethodID typeMethodID = env->GetMethodID(ndefClass, "getType", "()Ljava/lang/String;");
+ jstring jtype = reinterpret_cast<jstring>(env->CallObjectMethod(ndef, typeMethodID));
+ const char *type_data = env->GetStringUTFChars(jtype, JNI_FALSE);
+ QString qtype = QString::fromUtf8(type_data);
+ env->ReleaseStringUTFChars(jtype, type_data);
+
+ QHash<QString, Type> types;
+ types.insert(QString::fromUtf8("com.nxp.ndef.mifareclassic"), MifareTag);
+ types.insert(QString::fromUtf8("org.nfcforum.ndef.type1"), NfcTagType1);
+ types.insert(QString::fromUtf8("org.nfcforum.ndef.type2"), NfcTagType2);
+ types.insert(QString::fromUtf8("org.nfcforum.ndef.type3"), NfcTagType3);
+ types.insert(QString::fromUtf8("org.nfcforum.ndef.type4"), NfcTagType4);
+ if (!types.contains(qtype))
+ return ProprietaryTag;
+ return types[qtype];
+ } 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
+ jobject nfca = getTagTechnology(NfcATechnology, env);
+ jclass nfcaClass = env->GetObjectClass(nfca);
+ jmethodID atqaMethodID = env->GetMethodID(nfcaClass, "getAtqa", "()[B");
+ jbyteArray atqaBA = reinterpret_cast<jbyteArray>(env->CallObjectMethod(nfca, atqaMethodID));
+ QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA, env);
+ if (atqaQBA.isEmpty())
+ return ProprietaryTag;
+ if ((atqaQBA[0] & 0x1F) == 0x00)
+ return NfcTagType1;
+
+ // Checking SAK/SEL_RES
+ // xxxx xxxx x00x x0xx: Identifies tag Type 2 platform
+ // xxxx xxxx x01x x0xx: Identifies tag Type 4 platform
+ jmethodID sakMethodID = env->GetMethodID(nfcaClass, "getSak", "()S");
+ jshort sakS = env->CallShortMethod(nfca, sakMethodID);
+ if ((sakS & 0x0064) == 0x0000)
+ return NfcTagType2;
+ else if ((sakS & 0x0064) == 0x0020)
+ return NfcTagType4;
+ return ProprietaryTag;
+ } else if (m_techList.contains(NfcBTechnology)) {
+ return NfcTagType4;
+ } else if (m_techList.contains(NfcFTechnology)) {
+ return NfcTagType3;
+ }
+
+ return ProprietaryTag;
+}
+
+void NearFieldTarget::setupTargetCheckTimer()
+{
+ m_targetCheckTimer = new QTimer(this);
+ m_targetCheckTimer->setInterval(1000);
+ connect(m_targetCheckTimer, SIGNAL(timeout()), this, SLOT(checkIsTargetLost()));
+ m_targetCheckTimer->start();
+}
+
+void NearFieldTarget::handleTargetLost()
+{
+ releaseIntent();
+ emit targetLost(this);
+}
+
+jobject NearFieldTarget::getTagTechnology(const QString &tech, JNIEnv *env) const
+{
+ QString techClass(tech);
+ techClass.replace(QLatin1Char('.'), QLatin1Char('/'));
+
+ // Getting requested technology
+ jobject tag = AndroidNfc::getTag(env, m_intent);
+ jclass tagClass = env->FindClass(techClass.toUtf8().constData());
+ const QString sig = QString::fromUtf8("(Landroid/nfc/Tag;)L%1;");
+ jmethodID getTagMethodID = env->GetStaticMethodID(tagClass, "get", sig.arg(techClass).toUtf8().constData());
+ jobject tagtech = env->CallStaticObjectMethod(tagClass, getTagMethodID, tag);
+ return tagtech;
+}
+
+QByteArray NearFieldTarget::jbyteArrayToQByteArray(const jbyteArray &byteArray, JNIEnv *env) const
+{
+ QByteArray resultArray;
+ jsize len = env->GetArrayLength(byteArray);
+ resultArray.resize(len);
+ env->GetByteArrayRegion(byteArray, 0, len, reinterpret_cast<jbyte*>(resultArray.data()));
+ return resultArray;
+}
+
+bool NearFieldTarget::catchJavaExceptions(JNIEnv *env) const
+{
+ jthrowable exc = env->ExceptionOccurred();
+ if (exc) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return true;
+ }
+ return false;
+}
diff --git a/src/nfc/qnearfieldtarget_android_p.h b/src/nfc/qnearfieldtarget_android_p.h
new file mode 100644
index 00000000..936ae85b
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_android_p.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QNEARFIELDTARGET_ANDROID_P_H
+#define QNEARFIELDTARGET_ANDROID_P_H
+
+#include "android/androidjninfc_p.h"
+#include "qnearfieldtarget.h"
+#include "qnearfieldtarget_p.h"
+#include "qndefmessage.h"
+#include "qlist.h"
+#include "qstringlist.h"
+#include <QTimer>
+
+
+QT_BEGIN_NAMESPACE
+
+class NearFieldTarget : public QNearFieldTarget
+{
+ Q_OBJECT
+public:
+ NearFieldTarget(jobject intent,
+ const QByteArray uid,
+ QObject *parent = 0);
+ virtual ~NearFieldTarget();
+ virtual QByteArray uid() const;
+ virtual Type type() const;
+ virtual AccessMethods accessMethods() const;
+ virtual bool hasNdefMessage();
+ virtual RequestId readNdefMessages();
+ virtual RequestId sendCommand(const QByteArray &command);
+ virtual RequestId sendCommands(const QList<QByteArray> &commands);
+ virtual RequestId writeNdefMessages(const QList<QNdefMessage> &messages);
+ void setIntent(jobject intent);
+
+signals:
+ void targetDestroyed(const QByteArray &tagId);
+ void targetLost(QNearFieldTarget *target);
+
+protected slots:
+ void checkIsTargetLost();
+
+protected:
+ void releaseIntent();
+ void updateTechList();
+ void updateType();
+ Type getTagType() const;
+ void setupTargetCheckTimer();
+ void handleTargetLost();
+ jobject getTagTechnology(const QString &tech, JNIEnv *env) const;
+ QByteArray jbyteArrayToQByteArray(const jbyteArray &byteArray, JNIEnv *env) const;
+ bool catchJavaExceptions(JNIEnv *env) const;
+
+protected:
+ jobject m_intent;
+ QByteArray m_uid;
+ QStringList m_techList;
+ Type m_type;
+ static const QString NdefTechology;
+ static const QString NdefFormatableTechnology;
+ static const QString NfcATechnology;
+ static const QString NfcBTechnology;
+ static const QString NfcFTechnology;
+ static const QString NfcVTechnology;
+ static const QString MifareClassicTechnology;
+ static const QString MifareUltralightTechnology;
+ QTimer *m_targetCheckTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTARGET_ANDROID_P_H