summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@theqtcompany.com>2015-06-09 09:17:51 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-06-09 09:17:51 +0200
commit782c57a29fa03d795d96854daf51b8b9e523c933 (patch)
tree358520baf63a4bd8e7be441269c2fa4ead44dc65 /src
parent720118ea73431a0808f0c60dfec10f16fd85af7f (diff)
parent3f3d1289cc2f30b8fbc0837bf8fb7c767492e4e2 (diff)
Merge QtNfc on Android into dev/Qt 5.6
Diffstat (limited to 'src')
-rw-r--r--src/android/android.pro1
-rw-r--r--src/android/nfc/AndroidManifest.xml7
-rw-r--r--src/android/nfc/bundledjar.pro3
-rw-r--r--src/android/nfc/distributedjar.pro2
-rw-r--r--src/android/nfc/nfc.pri13
-rw-r--r--src/android/nfc/nfc.pro3
-rw-r--r--src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java166
-rw-r--r--src/imports/nfc/qdeclarativendeffilter.cpp12
-rw-r--r--src/imports/nfc/qdeclarativenearfield.cpp2
-rw-r--r--src/nfc/android/androidjninfc.cpp99
-rw-r--r--src/nfc/android/androidjninfc_p.h63
-rw-r--r--src/nfc/android/androidmainnewintentlistener.cpp130
-rw-r--r--src/nfc/android/androidmainnewintentlistener_p.h72
-rw-r--r--src/nfc/doc/src/nfc-android.qdoc69
-rw-r--r--src/nfc/doc/src/nfc-blackberry.qdoc52
-rw-r--r--src/nfc/nfc.pro37
-rw-r--r--src/nfc/qllcpserver_android_p.cpp121
-rw-r--r--src/nfc/qllcpserver_android_p.h75
-rw-r--r--src/nfc/qllcpsocket_android_p.cpp318
-rw-r--r--src/nfc/qllcpsocket_android_p.h117
-rw-r--r--src/nfc/qnearfieldmanager.cpp20
-rw-r--r--src/nfc/qnearfieldmanager_android.cpp308
-rw-r--r--src/nfc/qnearfieldmanager_android_p.h97
-rw-r--r--src/nfc/qnearfieldmanager_qnx.cpp59
-rw-r--r--src/nfc/qnearfieldmanagervirtualbase.cpp3
-rw-r--r--src/nfc/qnearfieldtarget_android.cpp448
-rw-r--r--src/nfc/qnearfieldtarget_android_p.h97
27 files changed, 2362 insertions, 32 deletions
diff --git a/src/android/android.pro b/src/android/android.pro
index 07feb78f..f8f5c05e 100644
--- a/src/android/android.pro
+++ b/src/android/android.pro
@@ -1,2 +1,3 @@
TEMPLATE = subdirs
qtHaveModule(bluetooth): SUBDIRS += bluetooth
+qtHaveModule(nfc): SUBDIRS += nfc
diff --git a/src/android/nfc/AndroidManifest.xml b/src/android/nfc/AndroidManifest.xml
new file mode 100644
index 00000000..2ba062ae
--- /dev/null
+++ b/src/android/nfc/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.qt5.android.nfc"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+</manifest>
diff --git a/src/android/nfc/bundledjar.pro b/src/android/nfc/bundledjar.pro
new file mode 100644
index 00000000..37f7fc82
--- /dev/null
+++ b/src/android/nfc/bundledjar.pro
@@ -0,0 +1,3 @@
+TARGET = QtNfc-bundled
+CONFIG += bundled_jar_file
+include(nfc.pri)
diff --git a/src/android/nfc/distributedjar.pro b/src/android/nfc/distributedjar.pro
new file mode 100644
index 00000000..ed65c50a
--- /dev/null
+++ b/src/android/nfc/distributedjar.pro
@@ -0,0 +1,2 @@
+TARGET = QtNfc
+include(nfc.pri)
diff --git a/src/android/nfc/nfc.pri b/src/android/nfc/nfc.pri
new file mode 100644
index 00000000..65f197ca
--- /dev/null
+++ b/src/android/nfc/nfc.pri
@@ -0,0 +1,13 @@
+CONFIG += java
+DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
+API_VERSION = android-10
+
+PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/nfc
+
+JAVACLASSPATH += $$PWD/src/
+JAVASOURCES += \
+ $$PWD/src/org/qtproject/qt5/android/nfc/QtNfc.java
+
+# install
+target.path = $$[QT_INSTALL_PREFIX]/jar
+INSTALLS += target
diff --git a/src/android/nfc/nfc.pro b/src/android/nfc/nfc.pro
new file mode 100644
index 00000000..70373fe1
--- /dev/null
+++ b/src/android/nfc/nfc.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += bundledjar.pro distributedjar.pro
+
diff --git a/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java b/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
new file mode 100644
index 00000000..566489c8
--- /dev/null
+++ b/src/android/nfc/src/org/qtproject/qt5/android/nfc/QtNfc.java
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+package org.qtproject.qt5.android.nfc;
+
+import java.lang.Thread;
+import java.lang.Runnable;
+
+import android.os.Parcelable;
+import android.os.Looper;
+import android.content.Context;
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.nfc.NfcAdapter;
+import android.content.IntentFilter.MalformedMimeTypeException;
+import android.os.Bundle;
+import android.util.Log;
+import android.content.BroadcastReceiver;
+
+public class QtNfc
+{
+ /* static final QtNfc m_nfc = new QtNfc(); */
+ static private final String TAG = "QtNfc";
+ static public NfcAdapter m_adapter = null;
+ static public PendingIntent m_pendingIntent = null;
+ static public IntentFilter[] m_filters;
+ static public Activity m_activity;
+
+ static public void setActivity(Activity activity, Object activityDelegate)
+ {
+ //Log.d(TAG, "setActivity " + activity);
+ m_activity = activity;
+ m_adapter = NfcAdapter.getDefaultAdapter(m_activity);
+ if (m_adapter == null) {
+ //Log.e(TAG, "No NFC available");
+ return;
+ }
+ m_pendingIntent = PendingIntent.getActivity(
+ m_activity,
+ 0,
+ new Intent(m_activity, m_activity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
+ 0);
+
+ //Log.d(TAG, "Pending intent:" + m_pendingIntent);
+
+ IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
+
+ m_filters = new IntentFilter[]{
+ filter
+ };
+
+ try {
+ filter.addDataType("*/*");
+ } catch(MalformedMimeTypeException e) {
+ throw new RuntimeException("Fail", e);
+ }
+
+ //Log.d(TAG, "Thread:" + Thread.currentThread().getId());
+ }
+
+ static public boolean start()
+ {
+ if (m_adapter == null) return false;
+ m_activity.runOnUiThread(new Runnable() {
+ public void run() {
+ //Log.d(TAG, "Enabling NFC");
+ IntentFilter[] filters = new IntentFilter[2];
+ filters[0] = new IntentFilter();
+ filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
+ filters[0].addCategory(Intent.CATEGORY_DEFAULT);
+ try {
+ filters[0].addDataType("*/*");
+ } catch (MalformedMimeTypeException e) {
+ throw new RuntimeException("Check your mime type.");
+ }
+ // some tags will report as tech, even if they are ndef formated/formatable.
+ filters[1] = new IntentFilter();
+ filters[1].addAction(NfcAdapter.ACTION_TECH_DISCOVERED);
+ String[][] techList = new String[][]{
+ {"android.nfc.tech.Ndef"},
+ {"android.nfc.tech.NdefFormatable"}
+ };
+ try {
+ m_adapter.enableForegroundDispatch(m_activity, m_pendingIntent, filters, techList);
+ } catch(IllegalStateException e) {
+ // On Android we must call enableForegroundDispatch when the activity is in foreground, only.
+ Log.d(TAG, "enableForegroundDispatch failed: " + e.toString());
+ }
+ }
+ });
+ return true;
+ }
+
+ static public boolean stop()
+ {
+ if (m_adapter == null) return false;
+ m_activity.runOnUiThread(new Runnable() {
+ public void run() {
+ //Log.d(TAG, "Disabling NFC");
+ try {
+ m_adapter.disableForegroundDispatch(m_activity);
+ } catch(IllegalStateException e) {
+ // On Android we must call disableForegroundDispatch when the activity is in foreground, only.
+ Log.d(TAG, "disableForegroundDispatch failed: " + e.toString());
+ }
+ }
+ });
+ return true;
+ }
+
+ static public boolean isAvailable()
+ {
+ m_adapter = NfcAdapter.getDefaultAdapter(m_activity);
+ if (m_adapter == null) {
+ //Log.e(TAG, "No NFC available (Adapter is null)");
+ return false;
+ }
+ return m_adapter.isEnabled();
+ }
+
+ static public Intent getStartIntent()
+ {
+ Log.d(TAG, "getStartIntent");
+ if (m_activity == null) return null;
+ Intent intent = m_activity.getIntent();
+ if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
+ NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) ||
+ NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
+ return intent;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/imports/nfc/qdeclarativendeffilter.cpp b/src/imports/nfc/qdeclarativendeffilter.cpp
index a3fb1581..508b9d2d 100644
--- a/src/imports/nfc/qdeclarativendeffilter.cpp
+++ b/src/imports/nfc/qdeclarativendeffilter.cpp
@@ -70,12 +70,18 @@
*/
/*!
+ \qmlproperty QQmlNdefRecord::TypeNameFormat NdefFilter::typeNameFormat
+
+ This property holds the NDEF record name format type \enum QQmlNdefRecord::TypeNameFormat.
+*/
+
+/*!
\qmlproperty int NdefFilter::minimum
This property holds the minimum number of records of the given type that must be in the NDEF
message for it match.
- To match any number of records set both the minimum and maximum properties to -1.
+ The default minimum is 1.
\sa maximum
*/
@@ -86,13 +92,13 @@
This property holds the maximum number of records of the given type that must be in the NDEF
message for it match.
- To match any number of records set both the minimum and maximum properties to -1.
+ The default maximum is UINT_MAX.
\sa minimum
*/
QDeclarativeNdefFilter::QDeclarativeNdefFilter(QObject *parent)
-: QObject(parent), m_minimum(-1), m_maximum(-1)
+: QObject(parent), m_minimum(1), m_maximum(UINT_MAX)
{
}
diff --git a/src/imports/nfc/qdeclarativenearfield.cpp b/src/imports/nfc/qdeclarativenearfield.cpp
index 3e45047b..17e6b177 100644
--- a/src/imports/nfc/qdeclarativenearfield.cpp
+++ b/src/imports/nfc/qdeclarativenearfield.cpp
@@ -92,6 +92,8 @@
This property indicates whether the order of records should be taken into account when matching
messages. This is not supported when using neard.
+
+ The default of orderMatch is false.
*/
/*!
diff --git a/src/nfc/android/androidjninfc.cpp b/src/nfc/android/androidjninfc.cpp
new file mode 100644
index 00000000..a95e2f98
--- /dev/null
+++ b/src/nfc/android/androidjninfc.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjninfc_p.h"
+
+#include <android/log.h>
+
+#include "androidmainnewintentlistener_p.h"
+
+#include "qglobal.h"
+#include "qbytearray.h"
+#include "qdebug.h"
+
+static const char *nfcClassName = "org/qtproject/qt5/android/nfc/QtNfc";
+
+static AndroidNfc::MainNfcNewIntentListener mainListener;
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+bool startDiscovery()
+{
+ return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"start");
+}
+
+bool isAvailable()
+{
+ return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"isAvailable");
+}
+
+bool stopDiscovery()
+{
+ return QAndroidJniObject::callStaticMethod<jboolean>(nfcClassName,"stop");
+}
+
+QAndroidJniObject getStartIntent()
+{
+ QAndroidJniObject ret = QAndroidJniObject::callStaticObjectMethod(nfcClassName, "getStartIntent", "()Landroid/content/Intent;");
+ return ret;
+}
+
+bool registerListener(AndroidNfcListenerInterface *listener)
+{
+ return mainListener.registerListener(listener);
+}
+
+bool unregisterListener(AndroidNfcListenerInterface *listener)
+{
+ return mainListener.unregisterListener(listener);
+}
+
+QAndroidJniObject getTag(const QAndroidJniObject &intent)
+{
+ QAndroidJniObject extraTag = QAndroidJniObject::getStaticObjectField("android/nfc/NfcAdapter", "EXTRA_TAG", "Ljava/lang/String;");
+ QAndroidJniObject tag = intent.callObjectMethod("getParcelableExtra", "(Ljava/lang/String;)Landroid/os/Parcelable;", extraTag.object<jstring>());
+ Q_ASSERT_X(tag.isValid(), "getTag", "could not get Tag object");
+ return tag;
+}
+
+QT_END_ANDROIDNFC_NAMESPACE
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
+{
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ 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..fd69412a
--- /dev/null
+++ b/src/nfc/android/androidjninfc_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef ANDROIDJNINFC_H
+#define ANDROIDJNINFC_H
+
+#include "qglobal.h"
+
+#include <QtAndroidExtras/QAndroidJniObject>
+
+#define QT_USE_ANDROIDNFC_NAMESPACE using namespace ::AndroidNfc;
+#define QT_BEGIN_ANDROIDNFC_NAMESPACE namespace AndroidNfc {
+#define QT_END_ANDROIDNFC_NAMESPACE }
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+class AndroidNfcListenerInterface
+{
+public:
+ virtual ~AndroidNfcListenerInterface(){}
+ virtual void newIntent(QAndroidJniObject intent) = 0;
+};
+
+bool startDiscovery();
+bool stopDiscovery();
+QAndroidJniObject getStartIntent();
+bool isAvailable();
+bool registerListener(AndroidNfcListenerInterface *listener);
+bool unregisterListener(AndroidNfcListenerInterface *listener);
+QAndroidJniObject getTag(const QAndroidJniObject &intent);
+
+QT_END_ANDROIDNFC_NAMESPACE
+
+#endif
diff --git a/src/nfc/android/androidmainnewintentlistener.cpp b/src/nfc/android/androidmainnewintentlistener.cpp
new file mode 100644
index 00000000..f5b06cbc
--- /dev/null
+++ b/src/nfc/android/androidmainnewintentlistener.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 BasysKom GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "androidmainnewintentlistener_p.h"
+#include "qdebug.h"
+#include <QtGui/QGuiApplication>
+#include <QtAndroidExtras/QAndroidJniObject>
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+MainNfcNewIntentListener::MainNfcNewIntentListener()
+ : listeners(), listenersLock(), paused(true), receiving(false)
+{
+ QtAndroidPrivate::registerNewIntentListener(this);
+ QtAndroidPrivate::registerResumePauseListener(this);
+}
+
+MainNfcNewIntentListener::~MainNfcNewIntentListener()
+{
+ QtAndroidPrivate::unregisterNewIntentListener(this);
+ QtAndroidPrivate::unregisterResumePauseListener(this);
+}
+
+bool MainNfcNewIntentListener::handleNewIntent(JNIEnv */*env*/, jobject intent)
+{
+ listenersLock.lockForRead();
+ foreach (AndroidNfc::AndroidNfcListenerInterface *listener, listeners) {
+ listener->newIntent(QAndroidJniObject(intent));
+ }
+ listenersLock.unlock();
+ return true;
+}
+
+bool MainNfcNewIntentListener::registerListener(AndroidNfcListenerInterface *listener)
+{
+ static bool firstListener = true;
+ if (firstListener) {
+ QAndroidJniObject intent = AndroidNfc::getStartIntent();
+ if (intent.isValid()) {
+ listener->newIntent(intent);
+ }
+ paused = static_cast<QGuiApplication*>(QGuiApplication::instance())->applicationState() != Qt::ApplicationActive;
+ }
+ firstListener = false;
+ listenersLock.lockForWrite();
+ if (!listeners.contains(listener))
+ listeners.push_back(listener);
+ listenersLock.unlock();
+ updateReceiveState();
+ return true;
+}
+
+bool MainNfcNewIntentListener::unregisterListener(AndroidNfcListenerInterface *listener)
+{
+ listenersLock.lockForWrite();
+ listeners.removeOne(listener);
+ listenersLock.unlock();
+ updateReceiveState();
+ return true;
+}
+
+void MainNfcNewIntentListener::handleResume()
+{
+ paused = false;
+ updateReceiveState();
+}
+
+void MainNfcNewIntentListener::handlePause()
+{
+ paused = true;
+ updateReceiveState();
+}
+
+void MainNfcNewIntentListener::updateReceiveState()
+{
+ if (paused) {
+ // We were paused while receiving, so we stop receiving.
+ if (receiving) {
+ AndroidNfc::stopDiscovery();
+ receiving = false;
+ }
+ return;
+ }
+
+ // We reach here, so we are not paused.
+ listenersLock.lockForRead();
+ // We have nfc listeners and do not receive. Switch on.
+ if (listeners.count() && !receiving)
+ receiving = AndroidNfc::startDiscovery();
+
+ // we have no nfc listeners and do receive. Switch off.
+ if (!listeners.count() && receiving) {
+ AndroidNfc::stopDiscovery();
+ receiving = false;
+ }
+ listenersLock.unlock();
+}
+
+QT_END_ANDROIDNFC_NAMESPACE
diff --git a/src/nfc/android/androidmainnewintentlistener_p.h b/src/nfc/android/androidmainnewintentlistener_p.h
new file mode 100644
index 00000000..6a016339
--- /dev/null
+++ b/src/nfc/android/androidmainnewintentlistener_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 BasysKom GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDMAINNEWINTENTLISTENER_P_H_
+#define ANDROIDMAINNEWINTENTLISTENER_P_H_
+
+#include <QtCore/private/qjnihelpers_p.h>
+
+#include "qlist.h"
+#include "qreadwritelock.h"
+#include "androidjninfc_p.h"
+
+QT_BEGIN_ANDROIDNFC_NAMESPACE
+
+class MainNfcNewIntentListener : public QtAndroidPrivate::NewIntentListener, QtAndroidPrivate::ResumePauseListener
+{
+public:
+ MainNfcNewIntentListener();
+ ~MainNfcNewIntentListener();
+
+ //QtAndroidPrivate::NewIntentListener
+ bool handleNewIntent(JNIEnv *env, jobject intent);
+
+ bool registerListener(AndroidNfcListenerInterface *listener);
+ bool unregisterListener(AndroidNfcListenerInterface *listener);
+
+ //QtAndroidPrivate::ResumePauseListener
+ void handleResume();
+ void handlePause();
+
+private:
+ void updateReceiveState();
+protected:
+ QList<AndroidNfc::AndroidNfcListenerInterface*> listeners;
+ QReadWriteLock listenersLock;
+ bool paused;
+ bool receiving;
+};
+
+QT_END_ANDROIDNFC_NAMESPACE
+
+#endif /* ANDROIDMAINNEWINTENTLISTENER_P_H_ */
diff --git a/src/nfc/doc/src/nfc-android.qdoc b/src/nfc/doc/src/nfc-android.qdoc
new file mode 100644
index 00000000..e7c43423
--- /dev/null
+++ b/src/nfc/doc/src/nfc-android.qdoc
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 BasysKom GmbH
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\ingroup connectivity-nfc
+\inmodule QtNfc
+\since 5.6
+\page nfc-android.html
+\title Qt NFC on Android
+\brief Notes on Nfc for Android.
+
+\section1 Automatically launching NDEF message handlers on Android
+Android, the registration of NDEF message handlers is done via the
+\l{http://developer.android.com/guide/topics/manifest/manifest-intro.html}{Android manifest file}.
+This means the application has to provide an AndroidManifest.xml file with proper
+\l{http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#manifest}{NFC intent-filter.}
+
+\code
+<intent-filter>
+ <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ <data android:mimeType="text/plain"/>
+</intent-filter>
+\endcode
+
+When the application is started it has to register an message handler with
+\l registerNdefMessageHandler().
+The first NDEF message arriving in the handler is the message that started the application.
+See the \l {corkboard}{CorkBoard} application for an example.
+
+\section2 Note:
+Supported tag types in Android are
+\l{http://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_NDEF_DISCOVERED}{NDEF_DISCOVERED}
+and
+\l{http://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_TECH_DISCOVERED}{ACTION_TAG_DISCOVERED}
+with
+\l{http://developer.android.com/reference/android/nfc/tech/TagTechnology.html}{TagTechnology}
+NdefFormatable or Ndef.
+If the application register other types in the
+\l{http://developer.android.com/guide/topics/manifest/manifest-intro.html}{Android manifest file}
+the application will be started, but the tag will never get delivered to the handler.
+The handler should be registered as early as possible. If the application has not registered a handler, the application
+will be started every time a new tag is in range and the Android device end up running multiple instances of the application.
+*/
+
diff --git a/src/nfc/doc/src/nfc-blackberry.qdoc b/src/nfc/doc/src/nfc-blackberry.qdoc
new file mode 100644
index 00000000..feebceb8
--- /dev/null
+++ b/src/nfc/doc/src/nfc-blackberry.qdoc
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\ingroup connectivity-nfc
+\inmodule QtNfc
+\since 5.6
+\page nfc-blackberry.html
+\title Qt NFC on Blackberry
+\brief Notes on Nfc for Blackberry.
+
+\section1 Automatically launching NDEF message handlers on Blackberry
+On BlackBerry the registration for NDEF message handlers is done over the
+\l{https://developer.blackberry.com/native/documentation/core/invocation_framework.html}{Invocation Framework}.
+This means that the application has to set an invoke target in the bar descriptor xml file when using
+\l registerNdefMessageHandler().
+
+\code
+<invoke-target id="com.myapp.id">
+ <type>APPLICATION</type>
+ <filter>
+ <action>bb.action.OPEN</action>
+ <mime-type>application/vnd.rim.nfc.ndef</mime-type>
+ </filter>
+</invoke-target>
+\endcode
+*/
+
diff --git a/src/nfc/nfc.pro b/src/nfc/nfc.pro
index 7c6b6ff7..83b8e236 100644
--- a/src/nfc/nfc.pro
+++ b/src/nfc/nfc.pro
@@ -98,9 +98,8 @@ CONFIG(blackberry) {
qnearfieldsharemanagerimpl_p.h \
qnearfieldsharetargetimpl_p.h
}
-}
-linux:qtHaveModule(dbus) {
+} else:linux:!android:qtHaveModule(dbus) {
NFC_BACKEND_AVAILABLE = yes
QT += dbus
@@ -123,9 +122,8 @@ linux:qtHaveModule(dbus) {
qnearfieldmanager_neard.cpp
include(neard/neard.pri)
-}
-simulator {
+} else:simulator {
NFC_BACKEND_AVAILABLE = yes
QT *= gui
@@ -146,6 +144,37 @@ simulator {
qllcpserver_simulator_p.cpp \
qnearfieldsharemanagerimpl_p.cpp \
qnearfieldsharetargetimpl_p.cpp
+} else:android:!android-no-sdk {
+ NFC_BACKEND_AVAILABLE = yes
+ ANDROID_PERMISSIONS = \
+ android.permission.NFC
+ 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
+ QT += core-private gui androidextras
+
+ 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 \
+ android/androidmainnewintentlistener_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 \
+ android/androidmainnewintentlistener.cpp
}
isEmpty(NFC_BACKEND_AVAILABLE) {
diff --git a/src/nfc/qllcpserver_android_p.cpp b/src/nfc/qllcpserver_android_p.cpp
new file mode 100644
index 00000000..ba97bcee
--- /dev/null
+++ b/src/nfc/qllcpserver_android_p.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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..be725719
--- /dev/null
+++ b/src/nfc/qllcpserver_android_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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..0dc425f0
--- /dev/null
+++ b/src/nfc/qllcpsocket_android_p.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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..02865823
--- /dev/null
+++ b/src/nfc/qllcpsocket_android_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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 dce1a9f3..84f00d91 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
@@ -100,20 +102,10 @@ QT_BEGIN_NAMESPACE
\snippet doc_src_qtnfc.cpp handleNdefMessage
- On BlackBerry the registration for NDEF message handlers is done over the
- \l{https://developer.blackberry.com/native/documentation/core/invocation_framework.html}{Invocation Framework}.
- This means that the application has to set an invoke target in the bar descriptor xml file when using
- \l registerNdefMessageHandler().
-
- \code
- <invoke-target id="com.myapp.id">
- <type>APPLICATION</type>
- <filter>
- <action>bb.action.OPEN</action>
- <mime-type>application/vnd.rim.nfc.ndef</mime-type>
- </filter>
- </invoke-target>
- \endcode
+ Automatically launching NDEF message handlers is supported on
+ \l{nfc-blackberry.html}{Blackberry}
+ and
+ \l{nfc-android.html}{Android}.
\section3 NFC on Linux
The \l{https://01.org/linux-nfc}{Linux NFC project} provides software to support NFC on Linux platforms.
diff --git a/src/nfc/qnearfieldmanager_android.cpp b/src/nfc/qnearfieldmanager_android.cpp
new file mode 100644
index 00000000..d1434840
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_android.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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), m_handlerID(0)
+{
+ qRegisterMetaType<QAndroidJniObject>("QAndroidJniObject");
+ qRegisterMetaType<QNdefMessage>("QNdefMessage");
+ connect(this, SIGNAL(targetDetected(QNearFieldTarget*)), this, SLOT(handlerTargetDetected(QNearFieldTarget*)));
+ connect(this, SIGNAL(targetLost(QNearFieldTarget*)), this, SLOT(handlerTargetLost(QNearFieldTarget*)));
+}
+
+QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
+{
+}
+
+void QNearFieldManagerPrivateImpl::handlerTargetDetected(QNearFieldTarget *target)
+{
+ if (ndefMessageHandlers.count() == 0 && ndefFilterHandlers.count() == 0) // if no handler is registered
+ return;
+ if (target->hasNdefMessage()) {
+ connect(target, SIGNAL(ndefMessageRead(const QNdefMessage &, const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerNdefMessageRead(const QNdefMessage &, const QNearFieldTarget::RequestId &)));
+ connect(target, SIGNAL(requestCompleted(const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerRequestCompleted(const QNearFieldTarget::RequestId &)));
+ connect(target, SIGNAL(error(QNearFieldTarget::Error, const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerError(QNearFieldTarget::Error, const QNearFieldTarget::RequestId &)));
+
+ QNearFieldTarget::RequestId id = target->readNdefMessages();
+ m_idToTarget.insert(id, target);
+ }
+}
+
+void QNearFieldManagerPrivateImpl::handlerTargetLost(QNearFieldTarget *target)
+{
+ disconnect(target, SIGNAL(ndefMessageRead(const QNdefMessage &, const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerNdefMessageRead(const QNdefMessage &, const QNearFieldTarget::RequestId &)));
+ disconnect(target, SIGNAL(requestCompleted(const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerRequestCompleted(const QNearFieldTarget::RequestId &)));
+ disconnect(target, SIGNAL(error(QNearFieldTarget::Error, const QNearFieldTarget::RequestId &)),
+ this, SLOT(handlerError(QNearFieldTarget::Error, const QNearFieldTarget::RequestId &)));
+ m_idToTarget.remove(m_idToTarget.key(target));
+}
+
+struct VerifyRecord
+{
+ QNdefFilter::Record filterRecord;
+ unsigned int count;
+};
+
+void QNearFieldManagerPrivateImpl::handlerNdefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id)
+{
+ QNearFieldTarget *target = m_idToTarget.value(id);
+ //For message handlers without filters
+ for (int i = 0; i < ndefMessageHandlers.count(); i++) {
+ ndefMessageHandlers.at(i).second.invoke(ndefMessageHandlers.at(i).first.second, Q_ARG(QNdefMessage, message), Q_ARG(QNearFieldTarget*, target));
+ }
+
+ //For message handlers that specified a filter
+ for (int i = 0; i < ndefFilterHandlers.count(); ++i) {
+ bool matched = true;
+
+ QNdefFilter filter = ndefFilterHandlers.at(i).second.first;
+
+ QList<VerifyRecord> filterRecords;
+ for (int j = 0; j < filter.recordCount(); ++j) {
+ VerifyRecord vr;
+ vr.count = 0;
+ vr.filterRecord = filter.recordAt(j);
+
+ filterRecords.append(vr);
+ }
+
+ foreach (const QNdefRecord &record, message) {
+ for (int j = 0; matched && (j < filterRecords.count()); ++j) {
+ VerifyRecord &vr = filterRecords[j];
+
+ if (vr.filterRecord.typeNameFormat == record.typeNameFormat() &&
+ ( vr.filterRecord.type == record.type() ||
+ vr.filterRecord.type.isEmpty()) ) {
+ ++vr.count;
+ break;
+ } else {
+ if (filter.orderMatch()) {
+ if (vr.filterRecord.minimum <= vr.count &&
+ vr.count <= vr.filterRecord.maximum) {
+ continue;
+ } else {
+ matched = false;
+ }
+ }
+ }
+ }
+ }
+
+ for (int j = 0; matched && (j < filterRecords.count()); ++j) {
+ const VerifyRecord &vr = filterRecords.at(j);
+
+ if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum)
+ continue;
+ else
+ matched = false;
+ }
+
+ if (matched) {
+ ndefFilterHandlers.at(i).second.second.invoke(ndefFilterHandlers.at(i).first.second, Q_ARG(QNdefMessage, message), Q_ARG(QNearFieldTarget*, target));
+ }
+ }
+}
+
+void QNearFieldManagerPrivateImpl::handlerRequestCompleted(const QNearFieldTarget::RequestId &id)
+{
+ m_idToTarget.remove(id);
+}
+
+void QNearFieldManagerPrivateImpl::handlerError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id)
+{
+ Q_UNUSED(error);
+ m_idToTarget.remove(id);
+}
+
+bool QNearFieldManagerPrivateImpl::isAvailable() const
+{
+ return AndroidNfc::isAvailable();
+}
+
+bool QNearFieldManagerPrivateImpl::startTargetDetection()
+{
+ if (m_detecting)
+ return false; // Already detecting targets
+
+ m_detecting = true;
+ updateReceiveState();
+ return true;
+}
+
+void QNearFieldManagerPrivateImpl::stopTargetDetection()
+{
+ m_detecting = false;
+ updateReceiveState();
+}
+
+int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, const QMetaMethod &method)
+{
+ ndefMessageHandlers.append(QPair<QPair<int, QObject *>, QMetaMethod>(QPair<int, QObject *>(m_handlerID, object), method));
+ updateReceiveState();
+ //Returns the handler ID and increments it afterwards
+ return m_handlerID++;
+}
+
+int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter,
+ QObject *object, const QMetaMethod &method)
+{
+ //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)));
+
+ updateReceiveState();
+
+ return m_handlerID++;
+}
+
+bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int handlerId)
+{
+ for (int i=0; i<ndefMessageHandlers.count(); ++i) {
+ if (ndefMessageHandlers.at(i).first.first == handlerId) {
+ ndefMessageHandlers.removeAt(i);
+ updateReceiveState();
+ return true;
+ }
+ }
+ for (int i=0; i<ndefFilterHandlers.count(); ++i) {
+ if (ndefFilterHandlers.at(i).first.first == handlerId) {
+ ndefFilterHandlers.removeAt(i);
+ updateReceiveState();
+ 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(QAndroidJniObject 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(QAndroidJniObject, intent));
+}
+
+QByteArray QNearFieldManagerPrivateImpl::getUid(const QAndroidJniObject &intent)
+{
+ if (!intent.isValid())
+ return QByteArray();
+
+ QAndroidJniEnvironment env;
+ QAndroidJniObject tag = AndroidNfc::getTag(intent);
+ return getUidforTag(tag);
+}
+
+void QNearFieldManagerPrivateImpl::onTargetDiscovered(QAndroidJniObject intent)
+{
+ // Getting UID
+ QByteArray uid = getUid(intent);
+
+ // Accepting all targets 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*)));
+ }
+ emit targetDetected(target);
+}
+
+void QNearFieldManagerPrivateImpl::onTargetDestroyed(const QByteArray &uid)
+{
+ m_detectedTargets.remove(uid);
+}
+
+QByteArray QNearFieldManagerPrivateImpl::getUidforTag(const QAndroidJniObject &tag)
+{
+ if (!tag.isValid())
+ return QByteArray();
+
+ QAndroidJniEnvironment env;
+ QAndroidJniObject tagId = tag.callObjectMethod("getId", "()[B");
+ QByteArray uid;
+ jsize len = env->GetArrayLength(tagId.object<jbyteArray>());
+ uid.resize(len);
+ env->GetByteArrayRegion(tagId.object<jbyteArray>(), 0, len, reinterpret_cast<jbyte*>(uid.data()));
+ return uid;
+}
+
+void QNearFieldManagerPrivateImpl::updateReceiveState()
+{
+ if (m_detecting) {
+ AndroidNfc::registerListener(this);
+ } else {
+ if (ndefMessageHandlers.count() || ndefFilterHandlers.count()) {
+ AndroidNfc::registerListener(this);
+ } else {
+ AndroidNfc::unregisterListener(this);
+ }
+ }
+}
+
+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..3d45b700
--- /dev/null
+++ b/src/nfc/qnearfieldmanager_android_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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>
+#include <QMap>
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+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();
+ 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(QAndroidJniObject intent);
+ QByteArray getUid(const QAndroidJniObject &intent);
+
+public slots:
+ void onTargetDiscovered(QAndroidJniObject intent);
+ void onTargetDestroyed(const QByteArray &uid);
+ void handlerTargetDetected(QNearFieldTarget *target);
+ void handlerTargetLost(QNearFieldTarget *target);
+ void handlerNdefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id);
+ void handlerRequestCompleted(const QNearFieldTarget::RequestId &id);
+ void handlerError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId &id);
+
+protected:
+ static QByteArray getUidforTag(const QAndroidJniObject &tag);
+ void updateReceiveState();
+
+private:
+ bool m_detecting;
+ QHash<QByteArray, NearFieldTarget*> m_detectedTargets;
+ QMap<QNearFieldTarget::RequestId, QNearFieldTarget*> m_idToTarget;
+
+ 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/qnearfieldmanager_qnx.cpp b/src/nfc/qnearfieldmanager_qnx.cpp
index 2c3c7077..f4508bd8 100644
--- a/src/nfc/qnearfieldmanager_qnx.cpp
+++ b/src/nfc/qnearfieldmanager_qnx.cpp
@@ -140,6 +140,12 @@ void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccess
//Do nothing, because we don't have access modes for the target
}
+struct VerifyRecord
+{
+ QNdefFilter::Record filterRecord;
+ unsigned int count;
+};
+
void QNearFieldManagerPrivateImpl::handleMessage(const QNdefMessage &message, QNearFieldTarget *target)
{
qQNXNFCDebug() << "Handling message in near field manager. Filtercount:"
@@ -151,20 +157,53 @@ void QNearFieldManagerPrivateImpl::handleMessage(const QNdefMessage &message, QN
//For message handlers that specified a filter
for (int i = 0; i < ndefFilterHandlers.count(); i++) {
+ bool matched = true;
+
QNdefFilter filter = ndefFilterHandlers.at(i).second.first;
- if (filter.recordCount() > message.count())
- continue;
-
- int j=0;
- for (j = 0; j < filter.recordCount();) {
- if (message.at(j).typeNameFormat() != filter.recordAt(j).typeNameFormat
- || message.at(j).type() != filter.recordAt(j).type ) {
- break;
+
+ QList<VerifyRecord> filterRecords;
+ for (int j = 0; j < filter.recordCount(); ++j) {
+ VerifyRecord vr;
+ vr.count = 0;
+ vr.filterRecord = filter.recordAt(j);
+
+ filterRecords.append(vr);
+ }
+
+ foreach (const QNdefRecord &record, message) {
+ for (int j = 0; matched && (j < filterRecords.count()); ++j) {
+ VerifyRecord &vr = filterRecords[j];
+
+ if (vr.filterRecord.typeNameFormat == record.typeNameFormat() &&
+ ( vr.filterRecord.type == record.type() ||
+ vr.filterRecord.type.isEmpty()) ) {
+ ++vr.count;
+ break;
+ } else {
+ if (filter.orderMatch()) {
+ if (vr.filterRecord.minimum <= vr.count &&
+ vr.count <= vr.filterRecord.maximum) {
+ continue;
+ } else {
+ matched = false;
+ }
+ }
+ }
}
- j++;
}
- if (j == filter.recordCount())
+
+ for (int j = 0; matched && (j < filterRecords.count()); ++j) {
+ const VerifyRecord &vr = filterRecords.at(j);
+
+ if (vr.filterRecord.minimum <= vr.count && vr.count <= vr.filterRecord.maximum)
+ continue;
+ else
+ matched = false;
+ }
+
+ if (matched) {
ndefFilterHandlers.at(i).second.second.invoke(ndefFilterHandlers.at(i).first.second, Q_ARG(QNdefMessage, message), Q_ARG(QNearFieldTarget*, target));
+ }
}
}
diff --git a/src/nfc/qnearfieldmanagervirtualbase.cpp b/src/nfc/qnearfieldmanagervirtualbase.cpp
index cf25ed2b..b0f77e2f 100644
--- a/src/nfc/qnearfieldmanagervirtualbase.cpp
+++ b/src/nfc/qnearfieldmanagervirtualbase.cpp
@@ -172,7 +172,8 @@ void QNearFieldManagerPrivateVirtualBase::ndefReceived(const QNdefMessage &messa
VerifyRecord &vr = filterRecords[j];
if (vr.filterRecord.typeNameFormat == record.typeNameFormat() &&
- vr.filterRecord.type == record.type()) {
+ ( vr.filterRecord.type == record.type() ||
+ vr.filterRecord.type.isEmpty()) ) {
++vr.count;
break;
} else {
diff --git a/src/nfc/qnearfieldtarget_android.cpp b/src/nfc/qnearfieldtarget_android.cpp
new file mode 100644
index 00000000..891ce3fc
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_android.cpp
@@ -0,0 +1,448 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qnearfieldtarget_android_p.h"
+#include "android/androidjninfc_p.h"
+#include "qdebug.h"
+
+#define NDEFTECHNOLOGY "android.nfc.tech.Ndef"
+#define NDEFFORMATABLETECHNOLOGY "android.nfc.tech.NdefFormatable"
+#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"
+
+NearFieldTarget::NearFieldTarget(QAndroidJniObject 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(QStringLiteral(NDEFTECHNOLOGY));
+}
+
+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.isValid()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Getting Ndef technology object
+ QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
+ if (!ndef.isValid()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnsupportedError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Connect
+ ndef.callMethod<void>("connect");
+ if (catchJavaExceptions()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Get NdefMessage object
+ QAndroidJniObject ndefMessage = ndef.callObjectMethod("getNdefMessage", "()Landroid/nfc/NdefMessage;");
+ if (catchJavaExceptions())
+ ndefMessage = QAndroidJniObject();
+ if (!ndefMessage.isValid()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::NdefReadError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Convert to byte array
+ 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.
+
+ // 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));
+ QMetaObject::invokeMethod(this, "ndefMessageRead", Qt::QueuedConnection,
+ Q_ARG(const QNdefMessage&, qNdefMessage),
+ 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(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 {
+ 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.");
+
+ QAndroidJniEnvironment env;
+ const char *writeMethod;
+ QAndroidJniObject tagTechnology;
+
+ // Getting write method
+ if (m_techList.contains(QStringLiteral(NDEFFORMATABLETECHNOLOGY))) {
+ tagTechnology = getTagTechnology(QStringLiteral(NDEFFORMATABLETECHNOLOGY));
+ writeMethod = "format";
+ } else if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))) {
+ tagTechnology = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
+ 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()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::TargetOutOfRangeError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Making NdefMessage object
+ const QNdefMessage &message = messages.first();
+ QByteArray ba = message.toByteArray();
+ QAndroidJniObject jba = env->NewByteArray(ba.size());
+ env->SetByteArrayRegion(jba.object<jbyteArray>(), 0, ba.size(), reinterpret_cast<jbyte*>(ba.data()));
+ QAndroidJniObject jmessage = QAndroidJniObject("android/nfc/NdefMessage", "([B)V", jba.object<jbyteArray>());
+ if (catchJavaExceptions()) {
+ QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
+ Q_ARG(QNearFieldTarget::Error, QNearFieldTarget::UnknownError),
+ Q_ARG(const QNearFieldTarget::RequestId&, requestId));
+ return requestId;
+ }
+
+ // Writing
+ tagTechnology.callMethod<void>(writeMethod, "(Landroid/nfc/NdefMessage;)V", jmessage.object<jobject>());
+ if (catchJavaExceptions()) {
+ 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
+ tagTechnology.callMethod<void>("close");
+ catchJavaExceptions(); // IOException at this point does not matter anymore.
+ QMetaObject::invokeMethod(this, "ndefMessagesWritten", Qt::QueuedConnection);
+ return requestId;
+}
+
+void NearFieldTarget::setIntent(QAndroidJniObject intent)
+{
+ if (m_intent == intent)
+ return;
+
+ releaseIntent();
+ m_intent = intent;
+ if (m_intent.isValid()) {
+ // 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.isValid() || m_techList.isEmpty()) {
+ handleTargetLost();
+ return;
+ }
+ // Using first available technology to check connection
+ QString techStr = m_techList.first();
+ QAndroidJniObject tagTech = getTagTechnology(techStr);
+ tagTech.callMethod<void>("connect");
+ if (catchJavaExceptions()) {
+ handleTargetLost();
+ return;
+ }
+ tagTech.callMethod<void>("close");
+ if (catchJavaExceptions())
+ handleTargetLost();
+}
+
+void NearFieldTarget::releaseIntent()
+{
+ m_targetCheckTimer->stop();
+
+ m_intent = QAndroidJniObject();
+}
+
+void NearFieldTarget::updateTechList()
+{
+ if (!m_intent.isValid())
+ return;
+
+ // Getting tech list
+ QAndroidJniEnvironment env;
+ QAndroidJniObject tag = AndroidNfc::getTag(m_intent);
+ QAndroidJniObject techListArray = tag.callObjectMethod("getTechList", "()[Ljava/lang/String;");
+ if (!techListArray.isValid()) {
+ handleTargetLost();
+ return;
+ }
+
+ // Converting tech list array to QStringList.
+ m_techList.clear();
+ jsize techCount = env->GetArrayLength(techListArray.object<jobjectArray>());
+ for (jsize i = 0; i < techCount; ++i) {
+ QAndroidJniObject tech = env->GetObjectArrayElement(techListArray.object<jobjectArray>(), i);
+ m_techList.append(tech.callObjectMethod<jstring>("toString").toString());
+ }
+}
+
+void NearFieldTarget::updateType()
+{
+ m_type = getTagType();
+}
+
+QNearFieldTarget::Type NearFieldTarget::getTagType() const
+{
+ QAndroidJniEnvironment env;
+
+ if (m_techList.contains(QStringLiteral(NDEFTECHNOLOGY))) {
+ QAndroidJniObject ndef = getTagTechnology(QStringLiteral(NDEFTECHNOLOGY));
+ QString qtype = ndef.callObjectMethod("getType", "()Ljava/lang/String;").toString();
+
+ if (qtype.compare(QStringLiteral(MIFARETAG)) == 0)
+ return MifareTag;
+ if (qtype.compare(QStringLiteral(NFCTAGTYPE1)) == 0)
+ return NfcTagType1;
+ if (qtype.compare(QStringLiteral(NFCTAGTYPE2)) == 0)
+ return NfcTagType2;
+ if (qtype.compare(QStringLiteral(NFCTAGTYPE3)) == 0)
+ return NfcTagType3;
+ if (qtype.compare(QStringLiteral(NFCTAGTYPE4)) == 0)
+ return NfcTagType4;
+ return ProprietaryTag;
+ } else if (m_techList.contains(QStringLiteral(NFCATECHNOLOGY))) {
+ if (m_techList.contains(QStringLiteral(MIFARECLASSICTECHNOLOGY)))
+ return MifareTag;
+
+ // Checking ATQA/SENS_RES
+ // xxx0 0000 xxxx xxxx: Identifies tag Type 1 platform
+ QAndroidJniObject nfca = getTagTechnology(QStringLiteral(NFCATECHNOLOGY));
+ QAndroidJniObject atqaBA = nfca.callObjectMethod("getAtqa", "()[B");
+ QByteArray atqaQBA = jbyteArrayToQByteArray(atqaBA.object<jbyteArray>());
+ 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
+ jshort sakS = nfca.callMethod<jshort>("getSak");
+ if ((sakS & 0x0064) == 0x0000)
+ return NfcTagType2;
+ else if ((sakS & 0x0064) == 0x0020)
+ return NfcTagType4;
+ return ProprietaryTag;
+ } else if (m_techList.contains(QStringLiteral(NFCBTECHNOLOGY))) {
+ return NfcTagType4;
+ } else if (m_techList.contains(QStringLiteral(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);
+}
+
+QAndroidJniObject NearFieldTarget::getTagTechnology(const QString &tech) const
+{
+ QString techClass(tech);
+ techClass.replace(QLatin1Char('.'), QLatin1Char('/'));
+
+ // 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",
+ sig.arg(techClass).toUtf8().constData(), tag.object<jobject>());
+ return tagtech;
+}
+
+QByteArray NearFieldTarget::jbyteArrayToQByteArray(const jbyteArray &byteArray) const
+{
+ QAndroidJniEnvironment env;
+ 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() const
+{
+ QAndroidJniEnvironment env;
+ if (env->ExceptionCheck()) {
+ 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..ef9b5fdc
--- /dev/null
+++ b/src/nfc/qnearfieldtarget_android_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Centria research and development
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNfc module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $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>
+
+#include <QtAndroidExtras/QAndroidJniObject>
+#include <QtAndroidExtras/QAndroidJniEnvironment>
+
+QT_BEGIN_NAMESPACE
+
+class NearFieldTarget : public QNearFieldTarget
+{
+ Q_OBJECT
+public:
+ NearFieldTarget(QAndroidJniObject 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(QAndroidJniObject intent);
+
+signals:
+ void targetDestroyed(const QByteArray &tagId);
+ void targetLost(QNearFieldTarget *target);
+ void ndefMessageRead(const QNdefMessage &message, const QNearFieldTarget::RequestId &id);
+
+protected slots:
+ void checkIsTargetLost();
+
+protected:
+ void releaseIntent();
+ void updateTechList();
+ void updateType();
+ Type getTagType() const;
+ void setupTargetCheckTimer();
+ void handleTargetLost();
+ QAndroidJniObject getTagTechnology(const QString &tech) const;
+ QByteArray jbyteArrayToQByteArray(const jbyteArray &byteArray) const;
+ bool catchJavaExceptions() const;
+
+protected:
+ QAndroidJniObject m_intent;
+ QByteArray m_uid;
+ QStringList m_techList;
+ Type m_type;
+ QTimer *m_targetCheckTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNEARFIELDTARGET_ANDROID_P_H