summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAssam Boudjelthia <[email protected]>2021-01-14 12:38:04 +0200
committerAssam Boudjelthia <[email protected]>2021-01-27 17:23:04 +0200
commit4e60681c879a54cf5b34862a30e27c492ed36363 (patch)
tree01c7d46ae34a6596fa235eea915846b66e7e8670
parent407ce5c0afd905b38a7d82980a76ed834fc971eb (diff)
Make QJniObject and QJniEnvironment public API
As part of Qt 6 restructring for the extras modules, this change exposes the Jni APIs which are very important for Android platform. This patch adds the APIs QJniObject, QJniEnvironment, QJniExceptionCleaner based from private QtCore and QtAndroidExtras. The Jni interface is cross-platform which justifies the name, but currently, this API is used mainly for Android, and the naming comes generic without Android keyword to avoid any future limitation on supporting other platforms. [ChangeLog][QtCore] Add new QJniObject, QJniEnvironment and QJniExceptionCleaner APIs. Task-number: QTBUG-89482 Fixes: QTBUG-89633 Change-Id: I4382dd53a225375759b9d042f6035a4a9810572b Reviewed-by: Ville Voutilainen <[email protected]>
-rw-r--r--src/corelib/CMakeLists.txt2
-rw-r--r--src/corelib/doc/snippets/jni/src_qjniobject.cpp133
-rw-r--r--src/corelib/global/qglobal.cpp6
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp8
-rw-r--r--src/corelib/global/qrandom.cpp5
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp50
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp16
-rw-r--r--src/corelib/kernel/qjni_p.h1
-rw-r--r--src/corelib/kernel/qjnienvironment.cpp283
-rw-r--r--src/corelib/kernel/qjnienvironment.h85
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp74
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h1
-rw-r--r--src/corelib/kernel/qjniobject.cpp1872
-rw-r--r--src/corelib/kernel/qjniobject.h207
-rw-r--r--src/corelib/kernel/qjnionload.cpp5
-rw-r--r--src/corelib/time/qtimezoneprivate_android.cpp48
-rw-r--r--src/corelib/time/qtimezoneprivate_p.h4
-rw-r--r--src/network/kernel/qnetworkproxy_android.cpp34
-rw-r--r--src/network/ssl/qsslsocket_openssl_android.cpp13
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.cpp37
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp10
-rw-r--r--src/plugins/platforms/android/androidjniclipboard.cpp60
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp46
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp100
-rw-r--r--src/plugins/platforms/android/androidjnimenu.cpp13
-rw-r--r--src/plugins/platforms/android/extract.cpp21
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp14
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp28
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp15
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.h10
-rw-r--r--src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp45
-rw-r--r--src/plugins/platforms/android/qandroidplatformfiledialoghelper.h15
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.h7
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp65
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenu.cpp9
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.cpp12
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.h12
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.h8
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp13
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp10
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.h10
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.cpp23
-rw-r--r--tests/auto/corelib/kernel/CMakeLists.txt4
-rw-r--r--tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt8
-rw-r--r--tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp106
-rw-r--r--tests/auto/corelib/kernel/qjniobject/CMakeLists.txt16
-rw-r--r--tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java177
-rw-r--r--tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp1054
48 files changed, 4384 insertions, 411 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 66ea5eef797..31ba8272fce 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -979,6 +979,8 @@ qt_internal_extend_target(Core CONDITION ANDROID AND NOT ANDROID_EMBEDDED
io/qstandardpaths_android.cpp
io/qstorageinfo_unix.cpp
kernel/qjni.cpp kernel/qjni_p.h
+ kernel/qjnienvironment.cpp kernel/qjnienvironment.h
+ kernel/qjniobject.cpp kernel/qjniobject.h
kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h
kernel/qjnionload.cpp
)
diff --git a/src/corelib/doc/snippets/jni/src_qjniobject.cpp b/src/corelib/doc/snippets/jni/src_qjniobject.cpp
new file mode 100644
index 00000000000..f3433134db9
--- /dev/null
+++ b/src/corelib/doc/snippets/jni/src_qjniobject.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2021 The Qt Company Ltd.
+ ** Contact: http://www.qt.io/licensing/
+ **
+ ** This file is part of the documentation of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:BSD$
+ ** 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 https://www.qt.io/terms-conditions. For further
+ ** information use the contact form at https://www.qt.io/contact-us.
+ **
+ ** BSD License Usage
+ ** Alternatively, you may use this file under the terms of the BSD license
+ ** as follows:
+ **
+ ** "Redistribution and use in source and binary forms, with or without
+ ** modification, are permitted provided that the following conditions are
+ ** met:
+ ** * Redistributions of source code must retain the above copyright
+ ** notice, this list of conditions and the following disclaimer.
+ ** * Redistributions in binary form must reproduce the above copyright
+ ** notice, this list of conditions and the following disclaimer in
+ ** the documentation and/or other materials provided with the
+ ** distribution.
+ ** * Neither the name of The Qt Company Ltd nor the names of its
+ ** contributors may be used to endorse or promote products derived
+ ** from this software without specific prior written permission.
+ **
+ **
+ ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+//! [Working with lists]
+QStringList getTrackTitles(const QJniObject &album) {
+ QStringList stringList;
+ QJniObject list = album.callObjectMethod("getTitles",
+ "()Ljava/util/List;");
+
+ if (list.isValid()) {
+ const int size = list.callMethod<jint>("size");
+ for (int i = 0; i < size; ++i) {
+ QJniObject title = list.callObjectMethod("get", "(I)Ljava/lang/Object;", i);
+ stringList.append(title.toString());
+ }
+ }
+ return stringList;
+}
+//! [Working with lists]
+
+//! [QJniObject scope]
+void functionScope()
+{
+ QString helloString("Hello");
+ jstring myJString = 0;
+ {
+ QJniObject string = QJniObject::fromString(helloString);
+ myJString = string.object<jstring>();
+ }
+
+ // Ops! myJString is no longer valid.
+}
+//! [QJniObject scope]
+
+//! [Registering native methods]
+static void fromJavaOne(JNIEnv *env, jobject thiz, jint x)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ qDebug() << x << "< 100";
+}
+
+static void fromJavaTwo(JNIEnv *env, jobject thiz, jint x)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ qDebug() << x << ">= 100";
+}
+
+void registerNativeMethods() {
+ JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
+ {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
+
+ QJniObject javaClass("my/java/project/FooJavaClass");
+ QJniEnvironment env;
+ jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
+ env->RegisterNatives(objectClass,
+ methods,
+ sizeof(methods) / sizeof(methods[0]));
+ env->DeleteLocalRef(objectClass);
+}
+
+void foo()
+{
+ QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 10); // Output: 10 < 100
+ QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 100); // Output: 100 >= 100
+}
+
+//! [Registering native methods]
+
+//! [Java native methods]
+class FooJavaClass
+{
+ public static void foo(int x)
+ {
+ if (x < 100)
+ callNativeOne(x);
+ else
+ callNativeTwo(x);
+ }
+
+private static native void callNativeOne(int x);
+private static native void callNativeTwo(int x);
+
+}
+//! [Java native methods]
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 139c8f3a30c..c046b8078de 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -78,7 +78,7 @@
#endif
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-#include <private/qjni_p.h>
+#include <qjniobject.h>
#endif
#if defined(Q_OS_SOLARIS)
@@ -2296,7 +2296,7 @@ Oreo
// https://source.android.com/source/build-numbers.html
// https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
- const int sdk_int = QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
+ const int sdk_int = QJniObject::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
}
#endif
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index a9388a97959..b6ab4435a78 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -50,7 +50,7 @@
#include <qdebug.h>
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-#include <private/qjni_p.h>
+#include <QJniObject>
#endif
QT_BEGIN_NAMESPACE
@@ -157,7 +157,7 @@ QOperatingSystemVersion QOperatingSystemVersion::current()
version.m_os = currentType();
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
#ifndef QT_BOOTSTRAPPED
- const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
+ const QVersionNumber v = QVersionNumber::fromString(QJniObject::getStaticObjectField(
"android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
if (!v.isNull()) {
version.m_major = v.majorVersion();
@@ -207,7 +207,7 @@ QOperatingSystemVersion QOperatingSystemVersion::current()
};
// This will give us at least the first 2 version components
- const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>(
+ const size_t versionIdx = size_t(QJniObject::getStaticField<jint>(
"android/os/Build$VERSION", "SDK_INT")) - 1;
if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
version.m_major = versions[versionIdx].major;
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index ca16566c1ca..eb7acc5edf1 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2020 Intel Corporation.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -72,10 +73,6 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando
}
#endif
-#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-# include <private/qjni_p.h>
-#endif
-
// This file is too low-level for regular Q_ASSERT (the logging framework may
// recurse back), so use regular assert()
#undef NDEBUG
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index 3aa310e1684..46f96e40370 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -41,7 +41,7 @@
#ifndef QT_NO_STANDARDPATHS
-#include <QtCore/private/qjni_p.h>
+#include <QJniObject>
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/qmap.h>
#include <QDir>
@@ -57,13 +57,13 @@ static QString testDir()
: QLatin1String("");
}
-static QJNIObjectPrivate applicationContext()
+static QJniObject applicationContext()
{
- static QJNIObjectPrivate appCtx;
+ static QJniObject appCtx;
if (appCtx.isValid())
return appCtx;
- QJNIObjectPrivate context(QtAndroidPrivate::activity());
+ QJniObject context(QtAndroidPrivate::activity());
if (!context.isValid()) {
context = QtAndroidPrivate::service();
if (!context.isValid())
@@ -75,10 +75,10 @@ static QJNIObjectPrivate applicationContext()
return appCtx;
}
-static inline QString getAbsolutePath(const QJNIObjectPrivate &file)
+static inline QString getAbsolutePath(const QJniObject &file)
{
- QJNIObjectPrivate path = file.callObjectMethod("getAbsolutePath",
- "()Ljava/lang/String;");
+ QJniObject path = file.callObjectMethod("getAbsolutePath",
+ "()Ljava/lang/String;");
if (!path.isValid())
return QString();
@@ -95,22 +95,22 @@ static QString getExternalFilesDir(const char *directoryField = nullptr)
if (!path.isEmpty())
return path;
- QJNIObjectPrivate appCtx = applicationContext();
+ QJniObject appCtx = applicationContext();
if (!appCtx.isValid())
return QString();
- QJNIObjectPrivate dirField = QJNIObjectPrivate::fromString(QLatin1String(""));
+ QJniObject dirField = QJniObject::fromString(QLatin1String(""));
if (directoryField && strlen(directoryField) > 0) {
- dirField = QJNIObjectPrivate::getStaticObjectField("android/os/Environment",
- directoryField,
- "Ljava/lang/String;");
+ dirField = QJniObject::getStaticObjectField("android/os/Environment",
+ directoryField,
+ "Ljava/lang/String;");
if (!dirField.isValid())
return QString();
}
- QJNIObjectPrivate file = appCtx.callObjectMethod("getExternalFilesDir",
- "(Ljava/lang/String;)Ljava/io/File;",
- dirField.object());
+ QJniObject file = appCtx.callObjectMethod("getExternalFilesDir",
+ "(Ljava/lang/String;)Ljava/io/File;",
+ dirField.object());
if (!file.isValid())
return QString();
@@ -128,12 +128,12 @@ static QString getExternalCacheDir()
if (!path.isEmpty())
return path;
- QJNIObjectPrivate appCtx = applicationContext();
+ QJniObject appCtx = applicationContext();
if (!appCtx.isValid())
return QString();
- QJNIObjectPrivate file = appCtx.callObjectMethod("getExternalCacheDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callObjectMethod("getExternalCacheDir",
+ "()Ljava/io/File;");
if (!file.isValid())
return QString();
@@ -150,12 +150,12 @@ static QString getCacheDir()
if (!path.isEmpty())
return path;
- QJNIObjectPrivate appCtx = applicationContext();
+ QJniObject appCtx = applicationContext();
if (!appCtx.isValid())
return QString();
- QJNIObjectPrivate file = appCtx.callObjectMethod("getCacheDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callObjectMethod("getCacheDir",
+ "()Ljava/io/File;");
if (!file.isValid())
return QString();
@@ -172,12 +172,12 @@ static QString getFilesDir()
if (!path.isEmpty())
return path;
- QJNIObjectPrivate appCtx = applicationContext();
+ QJniObject appCtx = applicationContext();
if (!appCtx.isValid())
return QString();
- QJNIObjectPrivate file = appCtx.callObjectMethod("getFilesDir",
- "()Ljava/io/File;");
+ QJniObject file = appCtx.callObjectMethod("getFilesDir",
+ "()Ljava/io/File;");
if (!file.isValid())
return QString();
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index d9a74c2828f..781791c971a 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
@@ -91,8 +91,8 @@
#endif // QT_NO_QOBJECT
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-# include <private/qjni_p.h>
-# include <private/qjnihelpers_p.h>
+#include <QJniObject>
+#include <private/qjnihelpers_p.h>
#endif
#ifdef Q_OS_MAC
@@ -170,17 +170,17 @@ QString QCoreApplicationPrivate::appVersion() const
# ifdef Q_OS_DARWIN
applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion"));
# elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
- QJNIObjectPrivate context(QtAndroidPrivate::context());
+ QJniObject context(QtAndroidPrivate::context());
if (context.isValid()) {
- QJNIObjectPrivate pm = context.callObjectMethod(
+ QJniObject pm = context.callObjectMethod(
"getPackageManager", "()Landroid/content/pm/PackageManager;");
- QJNIObjectPrivate pn = context.callObjectMethod<jstring>("getPackageName");
+ QJniObject pn = context.callObjectMethod<jstring>("getPackageName");
if (pm.isValid() && pn.isValid()) {
- QJNIObjectPrivate packageInfo = pm.callObjectMethod(
+ QJniObject packageInfo = pm.callObjectMethod(
"getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
pn.object(), 0);
if (packageInfo.isValid()) {
- QJNIObjectPrivate versionName = packageInfo.getObjectField(
+ QJniObject versionName = packageInfo.getObjectField(
"versionName", "Ljava/lang/String;");
if (versionName.isValid())
return versionName.toString();
diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h
index edca36e2bdf..57ec8a39b57 100644
--- a/src/corelib/kernel/qjni_p.h
+++ b/src/corelib/kernel/qjni_p.h
@@ -47,6 +47,7 @@
//
// We mean it.
//
+// FIXME: Remove this once the JNI API is used by other modules.
#ifndef QJNI_P_H
#define QJNI_P_H
diff --git a/src/corelib/kernel/qjnienvironment.cpp b/src/corelib/kernel/qjnienvironment.cpp
new file mode 100644
index 00000000000..04676cc29c7
--- /dev/null
+++ b/src/corelib/kernel/qjnienvironment.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjnienvironment.h"
+#include "qjniobject.h"
+#include "qjnihelpers_p.h"
+
+#include <QtCore/QThread>
+#include <QtCore/QThreadStorage>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QJniEnvironment
+ \inmodule QtCore
+ \brief The QJniEnvironment provides access to the JNI Environment.
+ \since 6.1
+
+ \note This API has been tested and meant to be mainly used for Android and it hasn't been tested
+ for other platforms.
+*/
+
+static const char qJniThreadName[] = "QtThread";
+
+class QJniEnvironmentPrivate
+{
+public:
+ JNIEnv *jniEnv = nullptr;
+};
+
+class QJniEnvironmentPrivateTLS
+{
+public:
+ inline ~QJniEnvironmentPrivateTLS()
+ {
+ QtAndroidPrivate::javaVM()->DetachCurrentThread();
+ }
+};
+
+struct QJniLocalRefDeleterPrivate
+{
+ static void cleanup(jobject obj)
+ {
+ if (!obj)
+ return;
+
+ QJniEnvironment env;
+ env->DeleteLocalRef(obj);
+ }
+};
+
+// To simplify this we only define it for jobjects.
+typedef QScopedPointer<_jobject, QJniLocalRefDeleterPrivate> QJniScopedLocalRefPrivate;
+
+
+Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS)
+
+
+
+/*!
+ \fn QJniEnvironment::QJniEnvironment()
+
+ Constructs a new QJniEnvironment object and attaches the current thread to the Java VM.
+*/
+QJniEnvironment::QJniEnvironment()
+ : d(new QJniEnvironmentPrivate{})
+{
+ JavaVM *vm = QtAndroidPrivate::javaVM();
+ const jint ret = vm->GetEnv((void**)&d->jniEnv, JNI_VERSION_1_6);
+ if (ret == JNI_OK) // Already attached
+ return;
+
+ if (ret == JNI_EDETACHED) { // We need to (re-)attach
+ JavaVMAttachArgs args = { JNI_VERSION_1_6, qJniThreadName, nullptr };
+ if (vm->AttachCurrentThread(&d->jniEnv, &args) != JNI_OK)
+ return;
+
+ if (!jniEnvTLS->hasLocalData()) // If we attached the thread we own it.
+ jniEnvTLS->setLocalData(new QJniEnvironmentPrivateTLS);
+ }
+}
+
+/*!
+ \fn QJniEnvironment::~QJniEnvironment()
+
+ Detaches the current thread from the Java VM and destroys the QJniEnvironment object.
+*/
+QJniEnvironment::~QJniEnvironment()
+{
+ exceptionCheckAndClear();
+}
+
+/*!
+ \fn JNIEnv *QJniEnvironment::operator->()
+
+ Provides access to the QJniEnvironment's JNIEnv pointer.
+*/
+JNIEnv *QJniEnvironment::operator->()
+{
+ return d->jniEnv;
+}
+
+/*!
+ \fn QJniEnvironment::operator JNIEnv *() const
+
+ Returns the JNI Environment pointer.
+*/
+QJniEnvironment::operator JNIEnv* () const
+{
+ return d->jniEnv;
+}
+
+/*!
+ \fn jclass QJniEnvironment::findClass(const char *className)
+
+ Searches for \a className using all available class loaders. Qt on Android
+ uses a custom class loader to load all the .jar files and it must be used
+ to find any classes that are created by that class loader because these
+ classes are not visible in the default class loader.
+
+ Returns the class pointer or null if is not found.
+
+ A use case for this function is searching for a custom class then calling
+ its memeber method. The following code snippet create an instance of the
+ class \c CustomClass and then calls \c printFromJava() method:
+
+ \code
+ QJniEnvironment env;
+ jclass javaClass = env.findClass("org/qtproject/example/android/CustomClass");
+ QJniObject classObject(javaClass);
+
+ QJniObject javaMessage = QJniObject::fromString("findClass example");
+ classObject.callMethod<void>("printFromJava",
+ "(Ljava/lang/String;)V",
+ javaMessage.object<jstring>());
+ \endcode
+
+ \since Qt 6.1
+*/
+jclass QJniEnvironment::findClass(const char *className)
+{
+ return QtAndroidPrivate::findClass(className, d->jniEnv);
+}
+
+/*!
+ \fn JavaVM *QJniEnvironment::javaVM()
+
+ Returns the Java VM interface.
+
+ \since Qt 6.1
+*/
+JavaVM *QJniEnvironment::javaVM()
+{
+ return QtAndroidPrivate::javaVM();
+}
+
+/*!
+ \fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[])
+
+ Registers the Java methods \a methods that can call native C++ functions from class \a
+ className. These methods must be registered before any attempt to call them.
+
+ Returns True if the registration is successful, otherwise False.
+
+ Each element in the methods array consists of:
+ \list
+ \li The Java method name
+ \li Method signature
+ \li The C++ functions that will be executed
+ \endlist
+
+ \code
+ JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
+ {"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
+ QJniEnvironment env;
+ env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods);
+ \endcode
+
+ \since Qt 6.1
+*/
+bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size)
+{
+ jclass clazz = findClass(className);
+
+ if (!clazz)
+ return false;
+
+ jclass gClazz = static_cast<jclass>(d->jniEnv->NewGlobalRef(clazz));
+
+ if (d->jniEnv->RegisterNatives(gClazz, methods, size / sizeof(methods[0])) < 0) {
+ exceptionCheckAndClear();
+ return false;
+ }
+
+ d->jniEnv->DeleteLocalRef(gClazz);
+
+ return true;
+}
+
+/*!
+ \enum QJniExceptionCleaner::OutputMode
+
+ \value Silent the exceptions are cleaned silently
+ \value Verbose describes the exceptions before cleaning them
+*/
+
+/*!
+ \fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Silent)
+
+ Cleans any pending exceptions either silently or with descriptions, depending on the \a outputMode.
+
+ \since 6.1
+*/
+bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputMode)
+{
+ if (Q_UNLIKELY(d->jniEnv->ExceptionCheck())) {
+ if (outputMode != OutputMode::Silent)
+ d->jniEnv->ExceptionDescribe();
+ d->jniEnv->ExceptionClear();
+
+ return true;
+ }
+
+ return false;
+}
+
+/*!
+ \fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Silent)
+
+ Cleans any pending exceptions for \a env, either silently or with descriptions, depending on the \a outputMode.
+
+ \since 6.1
+*/
+bool QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, QJniEnvironment::OutputMode outputMode)
+{
+ if (Q_UNLIKELY(env->ExceptionCheck())) {
+ if (outputMode != OutputMode::Silent)
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+
+ return true;
+ }
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h
new file mode 100644
index 00000000000..e19a3935da8
--- /dev/null
+++ b/src/corelib/kernel/qjnienvironment.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJNI_ENVIRONMENT_H
+#define QJNI_ENVIRONMENT_H
+
+#include <QScopedPointer>
+
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#include <jni.h>
+#else
+class JNIEnv;
+class JNINativeMethod;
+class JavaVM;
+class jclass;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QJniEnvironmentPrivate;
+
+class Q_CORE_EXPORT QJniEnvironment
+{
+public:
+ QJniEnvironment();
+ ~QJniEnvironment();
+ JNIEnv *operator->();
+ operator JNIEnv *() const;
+ jclass findClass(const char *className);
+ static JavaVM *javaVM();
+ bool registerNativeMethods(const char *className, JNINativeMethod methods[], int size);
+
+ enum class OutputMode {
+ Silent,
+ Verbose
+ };
+
+ bool exceptionCheckAndClear(OutputMode outputMode = OutputMode::Verbose);
+ static bool exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose);
+
+
+private:
+ Q_DISABLE_COPY_MOVE(QJniEnvironment)
+ QScopedPointer<QJniEnvironmentPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QJNI_ENVIRONMENT_H
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 14f9f389e8f..45f4a4d8952 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -37,14 +37,16 @@
**
****************************************************************************/
+#include "qcoreapplication.h"
+#include "qjnienvironment.h"
#include "qjnihelpers_p.h"
-#include "qjni_p.h"
-#include "qmutex.h"
+#include "qjniobject.h"
#include "qlist.h"
+#include "qmutex.h"
#include "qsemaphore.h"
#include "qsharedpointer.h"
#include "qthread.h"
-#include "qcoreapplication.h"
+
#include <QtCore/qrunnable.h>
#include <deque>
@@ -146,7 +148,7 @@ static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requ
std::unique_ptr<jint[]> results(new jint[size]);
env->GetIntArrayRegion(grantResults, 0, size, results.get());
for (int i = 0 ; i < size; ++i) {
- const auto &permission = QJNIObjectPrivate(env->GetObjectArrayElement(permissions, i)).toString();
+ const auto &permission = QJniObject(env->GetObjectArrayElement(permissions, i)).toString();
auto value = results[i] == PERMISSION_GRANTED ?
QtAndroidPrivate::PermissionsResult::Granted :
QtAndroidPrivate::PermissionsResult::Denied;
@@ -286,27 +288,14 @@ void QtAndroidPrivate::handleResume()
listeners.at(i)->handleResume();
}
-static inline bool exceptionCheck(JNIEnv *env)
-{
- if (env->ExceptionCheck()) {
-#ifdef QT_DEBUG
- env->ExceptionDescribe();
-#endif // QT_DEBUG
- env->ExceptionClear();
- return true;
- }
-
- return false;
-}
-
static void setAndroidSdkVersion(JNIEnv *env)
{
jclass androidVersionClass = env->FindClass("android/os/Build$VERSION");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return;
jfieldID androidSDKFieldID = env->GetStaticFieldID(androidVersionClass, "SDK_INT", "I");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return;
g_androidSdkVersion = env->GetStaticIntField(androidVersionClass, androidSDKFieldID);
@@ -342,42 +331,42 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
{
jclass jQtNative = env->FindClass("org/qtproject/qt/android/QtNative");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jmethodID activityMethodID = env->GetStaticMethodID(jQtNative,
"activity",
"()Landroid/app/Activity;");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jmethodID serviceMethodID = env->GetStaticMethodID(jQtNative,
"service",
"()Landroid/app/Service;");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jobject service = env->CallStaticObjectMethod(jQtNative, serviceMethodID);
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jmethodID classLoaderMethodID = env->GetStaticMethodID(jQtNative,
"classLoader",
"()Ljava/lang/ClassLoader;");
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
jobject classLoader = env->CallStaticObjectMethod(jQtNative, classLoaderMethodID);
- if (exceptionCheck(env))
+ if (QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
setAndroidSdkVersion(env);
@@ -405,7 +394,7 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
- if (!regOk && exceptionCheck(env))
+ if (!regOk && QJniEnvironment::exceptionCheckAndClear(env))
return JNI_ERR;
g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative,
@@ -495,7 +484,10 @@ void QtAndroidPrivate::runOnAndroidThreadSync(const QtAndroidPrivate::Runnable &
waitForSemaphore(timeoutMs, sem);
}
-void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permissions, const QtAndroidPrivate::PermissionsResultFunc &callbackFunc, bool directCall)
+void QtAndroidPrivate::requestPermissions(JNIEnv *env,
+ const QStringList &permissions,
+ const QtAndroidPrivate::PermissionsResultFunc &callbackFunc,
+ bool directCall)
{
if (androidSdkVersion() < 23 || !activity()) {
QHash<QString, QtAndroidPrivate::PermissionsResult> res;
@@ -517,12 +509,17 @@ void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permis
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
}
- QJNIEnvironmentPrivate env;
- auto array = env->NewObjectArray(permissions.size(), env->FindClass("java/lang/String"), nullptr);
+ QJniEnvironment env;
+ jclass clazz = env->FindClass("java/lang/String");
+
+ if (env.exceptionCheckAndClear())
+ return;
+
+ auto array = env->NewObjectArray(permissions.size(), clazz, nullptr);
int index = 0;
for (const auto &perm : permissions)
- env->SetObjectArrayElement(array, index++, QJNIObjectPrivate::fromString(perm).object());
- QJNIObjectPrivate(activity()).callMethod<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
+ env->SetObjectArrayElement(array, index++, QJniObject::fromString(perm).object());
+ QJniObject(activity()).callMethod<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
env->DeleteLocalRef(array);
}, env);
}
@@ -543,10 +540,10 @@ QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEn
QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission)
{
- const auto res = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
- "checkSelfPermission",
- "(Ljava/lang/String;)I",
- QJNIObjectPrivate::fromString(permission).object());
+ const auto res = QJniObject::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
+ "checkSelfPermission",
+ "(Ljava/lang/String;)I",
+ QJniObject::fromString(permission).object());
return res == PERMISSION_GRANTED ? PermissionsResult::Granted : PermissionsResult::Denied;
}
@@ -555,8 +552,9 @@ bool QtAndroidPrivate::shouldShowRequestPermissionRationale(const QString &permi
if (androidSdkVersion() < 23 || !activity())
return false;
- return QJNIObjectPrivate(activity()).callMethod<jboolean>("shouldShowRequestPermissionRationale", "(Ljava/lang/String;)Z",
- QJNIObjectPrivate::fromString(permission).object());
+ return QJniObject(activity()).callMethod<jboolean>("shouldShowRequestPermissionRationale",
+ "(Ljava/lang/String;)Z",
+ QJniObject::fromString(permission).object());
}
void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index c849013ba22..a0d9c219d7c 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -119,6 +119,7 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT jobject context();
Q_CORE_EXPORT JavaVM *javaVM();
Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env);
+ Q_CORE_EXPORT jclass findClass(const char *className, JNIEnv *env);
jobject classLoader();
Q_CORE_EXPORT jint androidSdkVersion();
Q_CORE_EXPORT void runOnAndroidThread(const Runnable &runnable, JNIEnv *env);
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
new file mode 100644
index 00000000000..ba7d0af7789
--- /dev/null
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -0,0 +1,1872 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qjnienvironment.h"
+#include "qjnihelpers_p.h"
+#include "qjniobject.h"
+
+#include <QtCore/QReadWriteLock>
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QJniObject
+ \inmodule QtCore
+ \brief Provides a convenient set of APIs to call Java code from C++ using the Java Native Interface (JNI).
+ \since 6.1
+
+ \sa QJniEnvironment
+
+ \section1 General Notes
+
+ \list
+ \li Class names needs to contain the fully-qualified class name, for example: \b"java/lang/String".
+ \li Method signatures are written as \b"(Arguments)ReturnType"
+ \li All object types are returned as a QJniObject.
+ \endlist
+
+ \note This API has been tested and meant to be mainly used for Android and it hasn't been tested
+ for other platforms.
+
+ \section1 Method Signatures
+
+ For functions that take no arguments, QJniObject provides convenience functions that will use
+ the correct signature based on the provided template type. For example:
+
+ \code
+ jint x = QJniObject::callMethod<jint>("getSize");
+ QJniObject::callMethod<void>("touch");
+ \endcode
+
+ In other cases you will need to supply the signature yourself, and it is important that the
+ signature matches the function you want to call. The signature structure is \b \(A\)R, where \b A
+ is the type of the argument\(s\) and \b R is the return type. Array types in the signature must
+ have the \b\[ suffix and the fully-qualified type names must have the \b L prefix and \b ; suffix.
+
+ The example below demonstrates how to call two different static functions.
+ \code
+ // Java class
+ package org.qtproject.qt;
+ class TestClass
+ {
+ static String fromNumber(int x) { ... }
+ static String[] stringArray(String s1, String s2) { ... }
+ }
+ \endcode
+
+ The signature for the first function is \b"\(I\)Ljava/lang/String;"
+
+ \code
+ // C++ code
+ QJniObject stringNumber = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass",
+ "fromNumber"
+ "(I)Ljava/lang/String;",
+ 10);
+ \endcode
+
+ and the signature for the second function is \b"\(Ljava/lang/String;Ljava/lang/String;\)\[Ljava/lang/String;"
+
+ \code
+ // C++ code
+ QJniObject string1 = QJniObject::fromString("String1");
+ QJniObject string2 = QJniObject::fromString("String2");
+ QJniObject stringArray = QJniObject::callStaticObjectMethod("org/qtproject/qt/TestClass",
+ "stringArray"
+ "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"
+ string1.object<jstring>(),
+ string2.object<jstring>());
+ \endcode
+
+
+ \section1 Handling Java Exception
+
+ When calling Java functions that might throw an exception, it is important that you check, handle
+ and clear out the exception before continuing.
+
+ \note It is unsafe to make a JNI call when there are exceptions pending. For more information,
+ see QJniEnvironment::exceptionCheckAndClear().
+
+ \section1 Java Native Methods
+
+ Java native methods makes it possible to call native code from Java, this is done by creating a
+ function declaration in Java and prefixing it with the \b native keyword.
+ Before a native function can be called from Java, you need to map the Java native function to a
+ native function in your code. Mapping functions can be done by calling the RegisterNatives() function
+ through the \l{QJniEnvironment}{JNI environment pointer}.
+
+ The example below demonstrates how this could be done.
+
+ Java implementation:
+ \snippet jni/src_qjniobject.cpp Java native methods
+
+ C++ Implementation:
+ \snippet jni/src_qjniobject.cpp Registering native methods
+
+ \section1 The Lifetime of a Java Object
+
+ Most \l{Object types}{objects} received from Java will be local references and will only stay valid
+ in the scope you received them. After that, the object becomes eligible for garbage collection. If you
+ want to keep a Java object alive you need to either create a new global reference to the object and
+ release it when you are done, or construct a new QJniObject and let it manage the lifetime of the Java object.
+ \sa object()
+
+ \note The QJniObject only manages its own references, if you construct a QJniObject from a
+ global or local reference that reference will not be released by the QJniObject.
+
+ \section1 JNI Types
+
+ \section2 Object Types
+ \table
+ \header
+ \li Type
+ \li Signature
+ \row
+ \li jobject
+ \li Ljava/lang/Object;
+ \row
+ \li jclass
+ \li Ljava/lang/Class;
+ \row
+ \li jstring
+ \li Ljava/lang/String;
+ \row
+ \li jthrowable
+ \li Ljava/lang/Throwable;
+ \row
+ \li jobjectArray
+ \li [Ljava/lang/Object;
+ \row
+ \li jarray
+ \li [\e<type>
+ \row
+ \li jbooleanArray
+ \li [Z
+ \row
+ \li jbyteArray
+ \li [B
+ \row
+ \li jcharArray
+ \li [C
+ \row
+ \li jshortArray
+ \li [S
+ \row
+ \li jintArray
+ \li [I
+ \row
+ \li jlongArray
+ \li [J
+ \row
+ \li jfloatArray
+ \li [F
+ \row
+ \li jdoubleArray
+ \li [D
+ \endtable
+
+ \section2 Primitive Types
+ \table
+ \header
+ \li Type
+ \li Signature
+ \row
+ \li jboolean
+ \li Z
+ \row
+ \li jbyte
+ \li B
+ \row
+ \li jchar
+ \li C
+ \row
+ \li jshort
+ \li S
+ \row
+ \li jint
+ \li I
+ \row
+ \li jlong
+ \li J
+ \row
+ \li jfloat
+ \li F
+ \row
+ \li jdouble
+ \li D
+ \endtable
+
+ \section2 Other
+ \table
+ \header
+ \li Type
+ \li Signature
+ \row
+ \li void
+ \li V
+ \row
+ \li \e{Custom type}
+ \li L\e<fully-qualified-name>;
+ \endtable
+
+ For more information about JNI see: \l http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
+*/
+
+/*!
+ \fn bool operator==(const QJniObject &o1, const QJniObject &o2)
+
+ \relates QJniObject
+
+ Returns true if both objects, \a o1 and \a o2, are referencing the same Java object, or if both
+ are NULL. In any other cases false will be returned.
+*/
+
+/*!
+ \fn bool operator!=(const QJniObject &o1, const QJniObject &o2)
+ \relates QJniObject
+
+ Returns true if \a o1 holds a reference to a different object than \a o2.
+*/
+
+static inline QLatin1String keyBase()
+{
+ return QLatin1String("%1%2:%3");
+}
+
+static QString qt_convertJString(jstring string)
+{
+ QJniEnvironment env;
+ int strLength = env->GetStringLength(string);
+ QString res(strLength, Qt::Uninitialized);
+ env->GetStringRegion(string, 0, strLength, reinterpret_cast<jchar *>(res.data()));
+ return res;
+}
+
+typedef QHash<QString, jclass> JClassHash;
+Q_GLOBAL_STATIC(JClassHash, cachedClasses)
+Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock)
+
+static QByteArray toBinaryEncClassName(const QByteArray &className)
+{
+ return QByteArray(className).replace('/', '.');
+}
+
+static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nullptr)
+{
+ QReadLocker locker(cachedClassesLock);
+ const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(QString::fromLatin1(classBinEnc));
+ const bool found = (it != cachedClasses->constEnd());
+
+ if (isCached)
+ *isCached = found;
+
+ return found ? it.value() : 0;
+}
+
+inline static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false)
+{
+ const QByteArray &binEncClassName = binEncoded ? className : toBinaryEncClassName(className);
+
+ bool isCached = false;
+ jclass clazz = getCachedClass(binEncClassName, &isCached);
+ if (clazz || isCached)
+ return clazz;
+
+ QJniObject classLoader(QtAndroidPrivate::classLoader());
+ if (!classLoader.isValid())
+ return nullptr;
+
+ QWriteLocker locker(cachedClassesLock);
+ // did we lose the race?
+ const QLatin1String key(binEncClassName);
+ const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
+ if (it != cachedClasses->constEnd())
+ return it.value();
+
+ QJniObject stringName = QJniObject::fromString(key);
+ QJniObject classObject = classLoader.callObjectMethod("loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;",
+ stringName.object());
+
+ if (!QJniEnvironment::exceptionCheckAndClear(env) && classObject.isValid())
+ clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+
+ cachedClasses->insert(key, clazz);
+ return clazz;
+}
+
+typedef QHash<QString, jmethodID> JMethodIDHash;
+Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID)
+Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock)
+
+static inline jmethodID getMethodID(JNIEnv *env,
+ jclass clazz,
+ const char *name,
+ const char *sig,
+ bool isStatic = false)
+{
+ jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, sig)
+ : env->GetMethodID(clazz, name, sig);
+
+ if (QJniEnvironment::exceptionCheckAndClear(env))
+ return nullptr;
+
+ return id;
+}
+
+static jmethodID getCachedMethodID(JNIEnv *env,
+ jclass clazz,
+ const QByteArray &className,
+ const char *name,
+ const char *sig,
+ bool isStatic = false)
+{
+ if (className.isEmpty())
+ return getMethodID(env, clazz, name, sig, isStatic);
+
+ const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig));
+ QHash<QString, jmethodID>::const_iterator it;
+
+ {
+ QReadLocker locker(cachedMethodIDLock);
+ it = cachedMethodID->constFind(key);
+ if (it != cachedMethodID->constEnd())
+ return it.value();
+ }
+
+ {
+ QWriteLocker locker(cachedMethodIDLock);
+ it = cachedMethodID->constFind(key);
+ if (it != cachedMethodID->constEnd())
+ return it.value();
+
+ jmethodID id = getMethodID(env, clazz, name, sig, isStatic);
+
+ cachedMethodID->insert(key, id);
+ return id;
+ }
+}
+
+typedef QHash<QString, jfieldID> JFieldIDHash;
+Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID)
+Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock)
+
+static inline jfieldID getFieldID(JNIEnv *env,
+ jclass clazz,
+ const char *name,
+ const char *sig,
+ bool isStatic = false)
+{
+ jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, sig)
+ : env->GetFieldID(clazz, name, sig);
+
+ if (QJniEnvironment::exceptionCheckAndClear(env))
+ return nullptr;
+
+ return id;
+}
+
+static jfieldID getCachedFieldID(JNIEnv *env,
+ jclass clazz,
+ const QByteArray &className,
+ const char *name,
+ const char *sig,
+ bool isStatic = false)
+{
+ if (className.isNull())
+ return getFieldID(env, clazz, name, sig, isStatic);
+
+ const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig));
+ QHash<QString, jfieldID>::const_iterator it;
+
+ {
+ QReadLocker locker(cachedFieldIDLock);
+ it = cachedFieldID->constFind(key);
+ if (it != cachedFieldID->constEnd())
+ return it.value();
+ }
+
+ {
+ QWriteLocker locker(cachedFieldIDLock);
+ it = cachedFieldID->constFind(key);
+ if (it != cachedFieldID->constEnd())
+ return it.value();
+
+ jfieldID id = getFieldID(env, clazz, name, sig, isStatic);
+
+ cachedFieldID->insert(key, id);
+ return id;
+ }
+}
+
+jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
+{
+ const QByteArray &classDotEnc = toBinaryEncClassName(className);
+ bool isCached = false;
+ jclass clazz = getCachedClass(classDotEnc, &isCached);
+
+ const bool found = clazz || (!clazz && isCached);
+
+ if (found)
+ return clazz;
+
+ const QLatin1String key(classDotEnc);
+ if (env) { // We got an env. pointer (We expect this to be the right env. and call FindClass())
+ QWriteLocker locker(cachedClassesLock);
+ const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
+ // Did we lose the race?
+ if (it != cachedClasses->constEnd())
+ return it.value();
+
+ jclass fclazz = env->FindClass(className);
+ if (!QJniEnvironment::exceptionCheckAndClear(env)) {
+ clazz = static_cast<jclass>(env->NewGlobalRef(fclazz));
+ env->DeleteLocalRef(fclazz);
+ }
+
+ if (clazz)
+ cachedClasses->insert(key, clazz);
+ }
+
+ if (!clazz) // We didn't get an env. pointer or we got one with the WRONG class loader...
+ clazz = loadClass(classDotEnc, QJniEnvironment(), true);
+
+ return clazz;
+}
+
+class QJniObjectPrivate
+{
+public:
+ QJniObjectPrivate() = default;
+ ~QJniObjectPrivate() {
+ QJniEnvironment env;
+ if (m_jobject)
+ env->DeleteGlobalRef(m_jobject);
+ if (m_jclass && m_own_jclass)
+ env->DeleteGlobalRef(m_jclass);
+ }
+
+ jobject m_jobject = nullptr;
+ jclass m_jclass = nullptr;
+ bool m_own_jclass = true;
+ QByteArray m_className;
+};
+
+/*!
+ \fn QJniObject::QJniObject()
+
+ Constructs an invalid QJniObject.
+
+ \sa isValid()
+*/
+QJniObject::QJniObject()
+ : d(new QJniObjectPrivate())
+{
+}
+
+/*!
+ \fn QJniObject::QJniObject(const char *className)
+
+ Constructs a new QJniObject by calling the default constructor of \a className.
+
+ \code
+ QJniObject myJavaString("java/lang/String");
+ \endcode
+*/
+QJniObject::QJniObject(const char *className)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ d->m_className = toBinaryEncClassName(className);
+ d->m_jclass = loadClass(d->m_className, env, true);
+ d->m_own_jclass = false;
+ if (d->m_jclass) {
+ // get default constructor
+ jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", "()V");
+ if (constructorId) {
+ jobject obj = env->NewObject(d->m_jclass, constructorId);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+}
+
+/*!
+ \fn QJniObject::QJniObject(const char *className, const char *signature, ...)
+
+ Constructs a new QJniObject by calling the constructor of \a className with \a signature
+ and arguments.
+
+ \code
+ QJniEnvironment env;
+ char* str = "Hello";
+ jstring myJStringArg = env->NewStringUTF(str);
+ QJniObject myNewJavaString("java/lang/String", "(Ljava/lang/String;)V", myJStringArg);
+ \endcode
+*/
+QJniObject::QJniObject(const char *className, const char *sig, ...)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ d->m_className = toBinaryEncClassName(className);
+ d->m_jclass = loadClass(d->m_className, env, true);
+ d->m_own_jclass = false;
+ if (d->m_jclass) {
+ jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", sig);
+ if (constructorId) {
+ va_list args;
+ va_start(args, sig);
+ jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
+ va_end(args);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+}
+
+QJniObject::QJniObject(const char *className, const char *sig, const QVaListPrivate &args)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ d->m_className = toBinaryEncClassName(className);
+ d->m_jclass = loadClass(d->m_className, env, true);
+ d->m_own_jclass = false;
+ if (d->m_jclass) {
+ jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "<init>", sig);
+ if (constructorId) {
+ jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+}
+
+/*!
+ \fn QJniObject::QJniObject(jclass clazz, const char *signature, ...)
+
+ Constructs a new QJniObject from \a clazz by calling the constructor with \a signature
+ and arguments.
+
+ \code
+ QJniEnvironment env;
+ jclass myClazz = env.findClass("org/qtproject/qt/TestClass");
+ QJniObject(myClazz, "(I)V", 3);
+ \endcode
+*/
+QJniObject::QJniObject(jclass clazz, const char *sig, ...)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ if (clazz) {
+ d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", sig);
+ if (constructorId) {
+ va_list args;
+ va_start(args, sig);
+ jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
+ va_end(args);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \fn QJniObject::QJniObject(jclass clazz)
+
+ Constructs a new QJniObject by calling the default constructor of \a clazz.
+
+ Note: The QJniObject will create a new reference to the class \a clazz
+ and releases it again when it is destroyed. References to the class created
+ outside the QJniObject need to be managed by the caller.
+*/
+
+QJniObject::QJniObject(jclass clazz)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ // get default constructor
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", "()V");
+ if (constructorId) {
+ jobject obj = env->NewObject(d->m_jclass, constructorId);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+}
+
+QJniObject::QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args)
+ : d(new QJniObjectPrivate())
+{
+ QJniEnvironment env;
+ if (clazz) {
+ d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", sig);
+ if (constructorId) {
+ jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
+ if (obj) {
+ d->m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \fn QJniObject::QJniObject(jobject object)
+
+ Constructs a new QJniObject around the Java object \a object.
+
+ \note The QJniObject will hold a reference to the Java object \a object
+ and release it when destroyed. Any references to the Java object \a object
+ outside QJniObject needs to be managed by the caller. In most cases you
+ should never call this function with a local reference unless you intend
+ to manage the local reference yourself. See QJniObject::fromLocalRef()
+ for converting a local reference to a QJniObject.
+
+ \sa fromLocalRef()
+*/
+QJniObject::QJniObject(jobject obj)
+ : d(new QJniObjectPrivate())
+{
+ if (!obj)
+ return;
+
+ QJniEnvironment env;
+ d->m_jobject = env->NewGlobalRef(obj);
+ jclass cls = env->GetObjectClass(obj);
+ d->m_jclass = static_cast<jclass>(env->NewGlobalRef(cls));
+ env->DeleteLocalRef(cls);
+}
+
+/*!
+ \fn QJniObject::~QJniObject()
+
+ Destroys the QJniObject and releases any references held by the QJniObject.
+*/
+QJniObject::~QJniObject()
+{}
+
+/*!
+ \fn template <typename T> T QJniObject::object() const
+
+ Returns the object held by the QJniObject as type T.
+
+ \code
+ QJniObject string = QJniObject::fromString("Hello, JNI");
+ jstring jstring = string.object<jstring>();
+ \endcode
+
+ \note The returned object is still owned by the QJniObject. If you want to keep the object valid
+ you should create a new QJniObject or make a new global reference to the object and
+ free it yourself.
+
+ \snippet jni/src_qjniobject.cpp QJniObject scope
+
+ \code
+ jobject object = jniObject.object();
+ \endcode
+*/
+Q_CORE_EXPORT jobject QJniObject::object() const
+{
+ return javaObject();
+}
+
+QJniObject QJniObject::callObjectMethodV(const char *methodName,
+ const char *sig,
+ va_list args) const
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);
+ if (id) {
+ res = env->CallObjectMethodV(d->m_jobject, id, args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+QJniObject QJniObject::callStaticObjectMethodV(const char *className,
+ const char *methodName,
+ const char *sig,
+ va_list args)
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jclass clazz = loadClass(className, env);
+ if (clazz) {
+ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true);
+ if (id) {
+ res = env->CallStaticObjectMethodV(clazz, id, args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ va_list args)
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true);
+ if (id) {
+ res = env->CallStaticObjectMethodV(clazz, id, args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callMethod(const char *methodName, const char *sig, ...) const
+
+ Calls the method \a methodName with a signature \a sig and returns the value.
+
+ \code
+ QJniObject myJavaString = ...;
+ jint index = myJavaString.callMethod<jint>("indexOf", "(I)I", 0x0051);
+ \endcode
+
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName, const char *sig, ...) const
+{
+ QJniEnvironment env;
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ env->CallVoidMethodV(d->m_jobject, id, args);
+ va_end(args);
+ env.exceptionCheckAndClear();
+ }
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callMethod(const char *methodName) const
+
+ Calls the method \a methodName and returns the value.
+
+ \code
+ QJniObject myJavaString = ...;
+ jint size = myJavaString.callMethod<jint>("length");
+ \endcode
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callMethod<void>(const char *methodName) const
+{
+ callMethod<void>(methodName, "()V");
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName, const char *signature, ...)
+
+ Calls the static method with \a methodName with \a signature on class \a className with optional arguments.
+
+ \code
+ ...
+ jint a = 2;
+ jint b = 4;
+ jint max = QJniObject::callStaticMethod<jint>("java/lang/Math", "max", "(II)I", a, b);
+ ...
+ \endcode
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ QJniEnvironment env;
+ jclass clazz = loadClass(className, env);
+ if (clazz) {
+ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className),
+ methodName, sig, true);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ env->CallStaticVoidMethodV(clazz, id, args);
+ va_end(args);
+ env.exceptionCheckAndClear();
+ }
+ }
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callStaticMethod(const char *className, const char *methodName)
+
+ Calls the static method \a methodName on class \a className and returns the value.
+
+ \code
+ jint value = QJniObject::callStaticMethod<jint>("MyClass", "staticMethod");
+ \endcode
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(const char *className, const char *methodName)
+{
+ callStaticMethod<void>(className, methodName, "()V");
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...)
+
+ Calls the static method \a methodName with \a signature on \a clazz and returns the value.
+
+ \code
+ ...
+ jclass javaMathClass = ...; // ("java/lang/Math")
+ jint a = 2;
+ jint b = 4;
+ jint max = QJniObject::callStaticMethod<jint>(javaMathClass, "max", "(II)I", a, b);
+ ...
+ \endcode
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ QJniEnvironment env;
+ if (clazz) {
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ env->CallStaticVoidMethodV(clazz, id, args);
+ va_end(args);
+ env.exceptionCheckAndClear();
+ }
+ }
+}
+
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(const char *className,
+ const char *methodName,
+ const char *sig,
+ va_list args)
+{
+ QJniEnvironment env;
+ jclass clazz = loadClass(className, env);
+ if (clazz) {
+ jmethodID id = getCachedMethodID(env, clazz,
+ toBinaryEncClassName(className), methodName,
+ sig, true);
+ if (id) {
+ env->CallStaticVoidMethodV(clazz, id, args);
+ env.exceptionCheckAndClear();
+ }
+ }
+}
+
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethodV<void>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ va_list args)
+{
+ QJniEnvironment env;
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true);
+ if (id) {
+ env->CallStaticVoidMethodV(clazz, id, args);
+ env.exceptionCheckAndClear();
+ }
+}
+
+/*!
+ \fn template <typename T> T QJniObject::callStaticMethod(jclass clazz, const char *methodName)
+
+ Calls the static method \a methodName on \a clazz and returns the value.
+
+ \code
+ ...
+ jclass javaMathClass = ...; // ("java/lang/Math")
+ jdouble randNr = QJniObject::callStaticMethod<jdouble>(javaMathClass, "random");
+ ...
+ \endcode
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::callStaticMethod<void>(jclass clazz, const char *methodName)
+{
+ callStaticMethod<void>(clazz, methodName, "()V");
+}
+
+template <>
+Q_CORE_EXPORT void QJniObject::callMethodV<void>(const char *methodName, const char *sig,
+ va_list args) const
+{
+ QJniEnvironment env;
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);
+ if (id) {
+ env->CallVoidMethodV(d->m_jobject, id, args);
+ env.exceptionCheckAndClear();
+ }
+}
+
+#define MAKE_JNI_METHODS(MethodName, Type, Signature) \
+template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName, \
+ const char *sig, ...) const \
+{ \
+ QJniEnvironment env; \
+ Type res = 0; \
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); \
+ if (id) { \
+ va_list args; \
+ va_start(args, sig); \
+ res = env->Call##MethodName##MethodV(d->m_jobject, id, args); \
+ va_end(args); \
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ } \
+ return res; \
+}\
+template <> Q_CORE_EXPORT Type QJniObject::callMethod<Type>(const char *methodName) const \
+{ \
+ return callMethod<Type>(methodName, Signature); \
+} \
+\
+template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \
+ const char *methodName, \
+ const char *sig, \
+ ...) \
+{ \
+ QJniEnvironment env; \
+ Type res = 0; \
+ jclass clazz = loadClass(className, env); \
+ if (clazz) { \
+ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, \
+ sig, true); \
+ if (id) { \
+ va_list args; \
+ va_start(args, sig); \
+ res = env->CallStatic##MethodName##MethodV(clazz, id, args); \
+ va_end(args); \
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ } \
+ } \
+ return res; \
+} \
+template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(const char *className, \
+ const char *methodName) \
+{ \
+ return callStaticMethod<Type>(className, methodName, Signature); \
+}\
+\
+template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \
+ const char *methodName, \
+ const char *sig, \
+ ...) \
+{ \
+ QJniEnvironment env; \
+ Type res = 0; \
+ if (clazz) { \
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true); \
+ if (id) { \
+ va_list args; \
+ va_start(args, sig); \
+ res = env->CallStatic##MethodName##MethodV(clazz, id, args); \
+ va_end(args); \
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ } \
+ } \
+ return res; \
+} \
+template <> Q_CORE_EXPORT Type QJniObject::callStaticMethod<Type>(jclass clazz, \
+ const char *methodName) \
+{ \
+ return callStaticMethod<Type>(clazz, methodName, Signature); \
+}\
+template <> \
+Q_CORE_EXPORT Type QJniObject::callMethodV<Type>(const char *methodName, const char *sig,\
+ va_list args) const\
+{\
+ QJniEnvironment env;\
+ Type res = 0;\
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);\
+ if (id) {\
+ res = env->Call##MethodName##MethodV(d->m_jobject, id, args);\
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ }\
+ return res;\
+}\
+template <>\
+Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(const char *className,\
+ const char *methodName,\
+ const char *sig,\
+ va_list args)\
+{\
+ QJniEnvironment env;\
+ Type res = 0;\
+ jclass clazz = loadClass(className, env);\
+ if (clazz) {\
+ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName,\
+ sig, true);\
+ if (id) {\
+ res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ }\
+ }\
+ return res;\
+}\
+template <>\
+Q_CORE_EXPORT Type QJniObject::callStaticMethodV<Type>(jclass clazz,\
+ const char *methodName,\
+ const char *sig,\
+ va_list args)\
+{\
+ QJniEnvironment env;\
+ Type res = 0;\
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true);\
+ if (id) {\
+ res = env->CallStatic##MethodName##MethodV(clazz, id, args);\
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ }\
+ return res;\
+}
+
+#define DECLARE_JNI_METHODS(MethodName, Type, Signature) MAKE_JNI_METHODS(MethodName, \
+ Type, \
+ Signature)
+DECLARE_JNI_METHODS(Boolean, jboolean, "()Z")
+DECLARE_JNI_METHODS(Byte, jbyte, "()B")
+DECLARE_JNI_METHODS(Char, jchar, "()C")
+DECLARE_JNI_METHODS(Short, jshort, "()S")
+DECLARE_JNI_METHODS(Int, jint, "()I")
+DECLARE_JNI_METHODS(Long, jlong, "()J")
+DECLARE_JNI_METHODS(Float, jfloat, "()F")
+DECLARE_JNI_METHODS(Double, jdouble, "()D")
+
+/*!
+ \fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
+
+ Calls the Java object's method \a methodName with the signature \a signature and arguments
+
+ \code
+ QJniObject myJavaString; ==> "Hello, Java"
+ QJniObject mySubstring = myJavaString.callObjectMethod("substring", "(II)Ljava/lang/String;", 7, 10);
+ \endcode
+*/
+QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sig, ...) const
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ res = env->CallObjectMethodV(d->m_jobject, id, args);
+ va_end(args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName, const char *signature, ...)
+
+ Calls the static method with \a methodName and \a signature on the class \a className.
+
+ \code
+ QJniObject thread = QJniObject::callStaticObjectMethod("java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
+ QJniObject string = QJniObject::callStaticObjectMethod("java/lang/String", "valueOf", "(I)Ljava/lang/String;", 10);
+ \endcode
+*/
+QJniObject QJniObject::callStaticObjectMethod(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jclass clazz = loadClass(className, env);
+ if (clazz) {
+ jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName,
+ sig, true);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ res = env->CallStaticObjectMethodV(clazz, id, args);
+ va_end(args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName, const char *signature, ...)
+
+ Calls the static method with \a methodName and \a signature on class \a clazz.
+*/
+QJniObject QJniObject::callStaticObjectMethod(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ if (clazz) {
+ jmethodID id = getMethodID(env, clazz, methodName, sig, true);
+ if (id) {
+ va_list args;
+ va_start(args, sig);
+ res = env->CallStaticObjectMethodV(clazz, id, args);
+ va_end(args);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+ }
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QJniObject QJniObject::callObjectMethod(const char *methodName) const
+
+ Calls the Java objects method \a methodName and returns a new QJniObject for
+ the returned Java object.
+
+ \code
+ ...
+ QJniObject myJavaString1 = ...;
+ QJniObject myJavaString2 = myJavaString1.callObjectMethod<jstring>("toString");
+ ...
+ \endcode
+*/
+
+/*!
+ \fn QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName)
+
+ Calls the static method with \a methodName on the class \a className.
+
+ \code
+ QJniObject string = QJniObject::callStaticObjectMethod<jstring>("CustomClass", "getClassName");
+ \endcode
+*/
+
+/*!
+ \fn QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName)
+
+ Calls the static method with \a methodName on \a clazz.
+
+*/
+
+/*!
+ \fn template <typename T> QJniObject &QJniObject::operator=(T object)
+
+ Replace the current object with \a object. The old Java object will be released.
+*/
+#define MAKE_JNI_OBJECT_METHODS(Type, Signature) \
+template <> \
+Q_CORE_EXPORT QJniObject QJniObject::callObjectMethod<Type>(const char *methodName) const \
+{ \
+ return callObjectMethod(methodName, Signature); \
+} \
+template <> \
+Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(const char *className, \
+ const char *methodName) \
+{ \
+ return callStaticObjectMethod(className, methodName, Signature); \
+} \
+template <> \
+Q_CORE_EXPORT QJniObject QJniObject::callStaticObjectMethod<Type>(jclass clazz, \
+ const char *methodName) \
+{ \
+ return callStaticObjectMethod(clazz, methodName, Signature); \
+}\
+template <>\
+Q_CORE_EXPORT Type QJniObject::object<Type>() const\
+{\
+ return static_cast<Type>(javaObject());\
+}\
+template <>\
+Q_CORE_EXPORT QJniObject &QJniObject::operator=(Type obj)\
+{\
+ assign(static_cast<jobject>(obj));\
+ return *this;\
+}
+
+#define DECLARE_JNI_OBJECT_METHODS(Type, Signature) MAKE_JNI_OBJECT_METHODS(Type, Signature)
+
+DECLARE_JNI_OBJECT_METHODS(jobject, "()Ljava/lang/Object;")
+DECLARE_JNI_OBJECT_METHODS(jclass, "()Ljava/lang/Class;")
+DECLARE_JNI_OBJECT_METHODS(jstring, "()Ljava/lang/String;")
+DECLARE_JNI_OBJECT_METHODS(jobjectArray, "()[Ljava/lang/Object;")
+DECLARE_JNI_OBJECT_METHODS(jbooleanArray, "()[Z")
+DECLARE_JNI_OBJECT_METHODS(jbyteArray, "()[B")
+DECLARE_JNI_OBJECT_METHODS(jshortArray, "()[S")
+DECLARE_JNI_OBJECT_METHODS(jintArray, "()[I")
+DECLARE_JNI_OBJECT_METHODS(jlongArray, "()[J")
+DECLARE_JNI_OBJECT_METHODS(jfloatArray, "()[F")
+DECLARE_JNI_OBJECT_METHODS(jdoubleArray, "()[D")
+DECLARE_JNI_OBJECT_METHODS(jcharArray, "()[C")
+DECLARE_JNI_OBJECT_METHODS(jthrowable, "()Ljava/lang/Throwable;")
+
+/*!
+ \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, const char *signature, T value);
+
+ Sets the static field with \a fieldName and \a signature to \a value on class named \a className.
+*/
+template <>
+Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(const char *className,
+ const char *fieldName,
+ const char *sig,
+ jobject value)
+{
+ QJniEnvironment env;
+ jclass clazz = loadClass(className, env);
+
+ if (!clazz)
+ return;
+
+ jfieldID id = getCachedFieldID(env, clazz, className, fieldName, sig, true);
+ if (id) {
+ env->SetStaticObjectField(clazz, id, value);
+ env.exceptionCheckAndClear();
+ }
+}
+
+/*!
+ \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, const char *signature, T value);
+
+ Sets the static field with \a fieldName and \a signature to \a value on class \a clazz.
+*/
+template <> Q_CORE_EXPORT void QJniObject::setStaticField<jobject>(jclass clazz,
+ const char *fieldName,
+ const char *sig,
+ jobject value)
+{
+ QJniEnvironment env;
+ jfieldID id = getFieldID(env, clazz, fieldName, sig, true);
+
+ if (id) {
+ env->SetStaticObjectField(clazz, id, value);
+ env.exceptionCheckAndClear();
+ }
+}
+
+/*!
+ \fn T QJniObject::getField(const char *fieldName) const
+
+ Retrieves the value of the field \a fieldName.
+
+ \code
+ QJniObject volumeControl = ...;
+ jint fieldValue = volumeControl.getField<jint>("MAX_VOLUME");
+ \endcode
+*/
+
+/*!
+ \fn T QJniObject::getStaticField(const char *className, const char *fieldName)
+
+ Retrieves the value from the static field \a fieldName on the class \a className.
+*/
+
+/*!
+ \fn T QJniObject::getStaticField(jclass clazz, const char *fieldName)
+
+ Retrieves the value from the static field \a fieldName on \a clazz.
+*/
+
+/*!
+ \fn template <typename T> void QJniObject::setStaticField(const char *className, const char *fieldName, T value)
+
+ Sets the static field \a fieldName of the class named \a className to \a value.
+*/
+
+/*!
+ \fn template <typename T> void QJniObject::setStaticField(jclass clazz, const char *fieldName, T value)
+
+ Sets the static field \a fieldName of the class \a clazz to \a value.
+*/
+#define MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) \
+template <> Q_CORE_EXPORT Type QJniObject::getField<Type>(const char *fieldName) const \
+{ \
+ QJniEnvironment env; \
+ Type res = 0; \
+ jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, Signature); \
+ if (id) {\
+ res = env->Get##FieldName##Field(d->m_jobject, id); \
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ } \
+ return res;\
+} \
+template <> \
+Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(const char *className, const char *fieldName) \
+{ \
+ QJniEnvironment env; \
+ jclass clazz = loadClass(className, env); \
+ if (!clazz) \
+ return 0; \
+ jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, \
+ Signature, true); \
+ if (!id) \
+ return 0; \
+ Type res = env->GetStatic##FieldName##Field(clazz, id); \
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ return res;\
+} \
+template <>\
+Q_CORE_EXPORT Type QJniObject::getStaticField<Type>(jclass clazz, const char *fieldName)\
+{\
+ QJniEnvironment env;\
+ Type res = 0;\
+ jfieldID id = getFieldID(env, clazz, fieldName, Signature, true);\
+ if (id) {\
+ res = env->GetStatic##FieldName##Field(clazz, id);\
+ if (env.exceptionCheckAndClear()) \
+ res = 0; \
+ }\
+ return res;\
+}\
+template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \
+ const char *fieldName, \
+ Type value) \
+{ \
+ QJniEnvironment env; \
+ jclass clazz = loadClass(className, env); \
+ if (!clazz) \
+ return; \
+ jfieldID id = getCachedFieldID(env, clazz, className, fieldName, Signature, true); \
+ if (!id) \
+ return; \
+ env->SetStatic##FieldName##Field(clazz, id, value); \
+ env.exceptionCheckAndClear(); \
+}\
+template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(jclass clazz,\
+ const char *fieldName,\
+ Type value)\
+{\
+ QJniEnvironment env;\
+ jfieldID id = getFieldID(env, clazz, fieldName, Signature, true);\
+ if (id) {\
+ env->SetStatic##FieldName##Field(clazz, id, value);\
+ env.exceptionCheckAndClear();\
+ }\
+}\
+template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \
+{ \
+ QJniEnvironment env; \
+ jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, Signature); \
+ if (id) { \
+ env->Set##FieldName##Field(d->m_jobject, id, value); \
+ env.exceptionCheckAndClear(); \
+ } \
+} \
+
+#define DECLARE_JNI_PRIMITIVE_FIELDS(FieldName, Type, Signature) MAKE_JNI_PRIMITIVE_FIELDS(FieldName, Type, \
+ Signature)
+DECLARE_JNI_PRIMITIVE_FIELDS(Boolean, jboolean, "Z")
+DECLARE_JNI_PRIMITIVE_FIELDS(Byte, jbyte, "B")
+DECLARE_JNI_PRIMITIVE_FIELDS(Char, jchar, "C")
+DECLARE_JNI_PRIMITIVE_FIELDS(Short, jshort, "S")
+DECLARE_JNI_PRIMITIVE_FIELDS(Int, jint, "I")
+DECLARE_JNI_PRIMITIVE_FIELDS(Long, jlong, "J")
+DECLARE_JNI_PRIMITIVE_FIELDS(Float, jfloat, "F")
+DECLARE_JNI_PRIMITIVE_FIELDS(Double, jdouble, "D")
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName, const char *signature)
+ Retrieves the object from the field with \a signature and \a fieldName on class \a className.
+
+ \note This function can be used without a template type.
+
+ \code
+ QJniObject jobj = QJniObject::getStaticObjectField("class/with/Fields", "FIELD_NAME", "Ljava/lang/String;");
+ \endcode
+*/
+QJniObject QJniObject::getStaticObjectField(const char *className,
+ const char *fieldName,
+ const char *sig)
+{
+ QJniEnvironment env;
+ jclass clazz = loadClass(className, env);
+ if (!clazz)
+ return QJniObject();
+ jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName,
+ sig, true);
+ if (!id)
+ return QJniObject();
+
+ jobject res = env->GetStaticObjectField(clazz, id);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName, const char *signature)
+ Retrieves the object from the field with \a signature and \a fieldName on \a clazz.
+
+ \note This function can be used without a template type.
+
+ \code
+ QJniObject jobj = QJniObject::getStaticObjectField(clazz, "FIELD_NAME", "Ljava/lang/String;");
+ \endcode
+*/
+QJniObject QJniObject::getStaticObjectField(jclass clazz,
+ const char *fieldName,
+ const char *sig)
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jfieldID id = getFieldID(env, clazz, fieldName, sig, true);
+ if (id) {
+ res = env->GetStaticObjectField(clazz, id);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature)
+
+ Retrieves the \a jobject from the field with \a signature and \a fieldName on \a clazz.
+*/
+template <>
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz,
+ const char *fieldName,
+ const char *sig)
+{
+ return getStaticObjectField(clazz, fieldName, sig);
+}
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField<jobject>(jclass clazz, const char *fieldName, const char *signature)
+
+ Retrieves the jobject from the field with \a signature and \a fieldName on class named \a className.
+*/
+template <>
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobject>(const char *className,
+ const char *fieldName,
+ const char *sig)
+{
+ return getStaticObjectField(className, fieldName, sig);
+}
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature)
+
+ Retrieves the jobjectArray from the field with \a signature and \a fieldName on \a clazz.
+*/
+template <>
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz,
+ const char *fieldName,
+ const char *sig)
+{
+ return getStaticObjectField(clazz, fieldName, sig);
+}
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField<jobjectArray>(jclass clazz, const char *fieldName, const char *signature)
+
+ Retrieves the jobjectArray from the field with \a signature and \a fieldName on the class named \a className.
+*/
+template <>
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<jobjectArray>(const char *className,
+ const char *fieldName,
+ const char *sig)
+{
+ return getStaticObjectField(className, fieldName, sig);
+}
+
+/*!
+ \fn template <typename T> void QJniObject::setField(const char *fieldName, const char *signature, T value)
+
+ Sets the value of \a fieldName with \a signature to \a value.
+
+ \code
+ QJniObject stringArray = ...;
+ QJniObject obj = ...;
+ obj.setField<jobjectArray>("KEY_VALUES", "([Ljava/lang/String;)V", stringArray.object<jobjectArray>())
+ \endcode
+*/
+template <> Q_CORE_EXPORT
+void QJniObject::setField<jobject>(const char *fieldName, const char *sig, jobject value)
+{
+ QJniEnvironment env;
+ jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig);
+ if (id) {
+ env->SetObjectField(d->m_jobject, id, value);
+ env.exceptionCheckAndClear();
+ }
+}
+
+template <> Q_CORE_EXPORT
+void QJniObject::setField<jobjectArray>(const char *fieldName, const char *sig, jobjectArray value)
+{
+ QJniEnvironment env;
+ jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig);
+ if (id) {
+ env->SetObjectField(d->m_jobject, id, value);
+ env.exceptionCheckAndClear();
+ }
+}
+
+/*!
+ \fn QJniObject QJniObject::getObjectField(const char *fieldName) const
+
+ Retrieves the object of field \a fieldName.
+
+ \code
+ QJniObject field = jniObject.getObjectField<jstring>("FIELD_NAME");
+ \endcode
+*/
+
+/*!
+ \fn QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const
+
+ Retrieves the object from the field with \a signature and \a fieldName.
+
+ \note This function can be used without a template type.
+
+ \code
+ QJniObject field = jniObject.getObjectField("FIELD_NAME", "Ljava/lang/String;");
+ \endcode
+*/
+QJniObject QJniObject::getObjectField(const char *fieldName, const char *sig) const
+{
+ QJniEnvironment env;
+ jobject res = nullptr;
+ jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig);
+ if (id) {
+ res = env->GetObjectField(d->m_jobject, id);
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn template <typename T> void QJniObject::setField(const char *fieldName, T value)
+
+ Sets the value of \a fieldName to \a value.
+
+ \code
+ ...
+ QJniObject obj;
+ obj.setField<jint>("AN_INT_FIELD", 10);
+ jstring myString = ...
+ obj.setField<jstring>("A_STRING_FIELD", myString);
+ ...
+ \endcode
+*/
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName)
+
+ Retrieves the object from the field \a fieldName on the class \a className.
+
+ \code
+ QJniObject jobj = QJniObject::getStaticObjectField<jstring>("class/with/Fields", "FIELD_NAME");
+ \endcode
+*/
+
+/*!
+ \fn QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName)
+
+ Retrieves the object from the field \a fieldName on \a clazz.
+
+ \code
+ QJniObject jobj = QJniObject::getStaticObjectField<jstring>(clazz, "FIELD_NAME");
+ \endcode
+*/
+
+#define MAKE_JNI_OBJECT_FILEDS(Type, Signature) \
+template <> Q_CORE_EXPORT void QJniObject::setField<Type>(const char *fieldName, Type value) \
+{ \
+ QJniObject::setField<jobject>(fieldName, Signature, value); \
+} \
+\
+template <> Q_CORE_EXPORT void QJniObject::setStaticField<Type>(const char *className, \
+ const char *fieldName, \
+ Type value) \
+{ \
+ QJniObject::setStaticField<jobject>(className, fieldName, Signature, value); \
+}\
+template <>\
+Q_CORE_EXPORT QJniObject QJniObject::getObjectField<Type>(const char *fieldName) const\
+{\
+ return getObjectField(fieldName, Signature);\
+}\
+template <>\
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(jclass clazz,\
+ const char *fieldName)\
+{\
+ return getStaticObjectField(clazz, fieldName, Signature);\
+}\
+template <>\
+Q_CORE_EXPORT QJniObject QJniObject::getStaticObjectField<Type>(const char *className,\
+ const char *fieldName)\
+{\
+ return getStaticObjectField(className, fieldName, Signature);\
+}\
+
+#define DECLARE_JNI_OBJECT_FILEDS(Type, Signature) MAKE_JNI_OBJECT_FILEDS(Type, Signature)
+
+DECLARE_JNI_OBJECT_FILEDS(jobject, "Ljava/lang/Object;")
+DECLARE_JNI_OBJECT_FILEDS(jobjectArray, "[Ljava/lang/Object;")
+DECLARE_JNI_OBJECT_FILEDS(jstring, "Ljava/lang/String;")
+DECLARE_JNI_OBJECT_FILEDS(jclass, "Ljava/lang/Class;")
+DECLARE_JNI_OBJECT_FILEDS(jthrowable, "Ljava/lang/Throwable;")
+DECLARE_JNI_OBJECT_FILEDS(jbooleanArray, "[Z")
+DECLARE_JNI_OBJECT_FILEDS(jbyteArray, "[B")
+DECLARE_JNI_OBJECT_FILEDS(jcharArray, "[C")
+DECLARE_JNI_OBJECT_FILEDS(jshortArray, "[S")
+DECLARE_JNI_OBJECT_FILEDS(jintArray, "[I")
+DECLARE_JNI_OBJECT_FILEDS(jlongArray, "[J")
+DECLARE_JNI_OBJECT_FILEDS(jfloatArray, "[F")
+DECLARE_JNI_OBJECT_FILEDS(jdoubleArray, "[D")
+
+/*!
+ \fn QJniObject QJniObject::fromString(const QString &string)
+
+ Creates a Java string from the QString \a string and returns a QJniObject holding that string.
+
+ \code
+ QString myQString = "QString";
+ QJniObject myJavaString = QJniObject::fromString(myQString);
+ \endcode
+
+ \sa toString()
+*/
+QJniObject QJniObject::fromString(const QString &string)
+{
+ QJniEnvironment env;
+ jstring res = env->NewString(reinterpret_cast<const jchar*>(string.constData()),
+ string.length());
+
+ if (env.exceptionCheckAndClear()) {
+ env->DeleteLocalRef(res);
+ res = nullptr;
+ }
+
+ QJniObject obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+/*!
+ \fn QString QJniObject::toString() const
+
+ Returns a QString with a string representation of the java object.
+ Calling this function on a Java String object is a convenient way of getting the actual string
+ data.
+
+ \code
+ QJniObject string = ...; // "Hello Java"
+ QString qstring = string.toString(); // "Hello Java"
+ \endcode
+
+ \sa fromString()
+*/
+QString QJniObject::toString() const
+{
+ if (!isValid())
+ return QString();
+
+ QJniObject string = callObjectMethod<jstring>("toString");
+ return qt_convertJString(static_cast<jstring>(string.object()));
+}
+
+/*!
+ \fn bool QJniObject::isClassAvailable(const char *className)
+
+ Returns true if the Java class \a className is available.
+
+ \code
+ if (QJniObject::isClassAvailable("java/lang/String")) {
+ // condition statement
+ }
+ \endcode
+*/
+bool QJniObject::isClassAvailable(const char *className)
+{
+ QJniEnvironment env;
+
+ if (!env)
+ return false;
+
+ return loadClass(className, env);;
+}
+
+/*!
+ \fn bool QJniObject::isValid() const
+
+ Returns true if this instance holds a valid Java object.
+
+ \code
+ QJniObject qjniObject; ==> isValid() == false
+ QJniObject qjniObject(0) ==> isValid() == false
+ QJniObject qjniObject("could/not/find/Class") ==> isValid() == false
+ \endcode
+*/
+bool QJniObject::isValid() const
+{
+ return d->m_jobject;
+}
+
+/*!
+ \fn QJniObject QJniObject::fromLocalRef(jobject localRef)
+ \since 6.1
+
+ Creates a QJniObject from the local JNI reference \a localRef.
+ This function takes ownership of \a localRef and frees it before returning.
+
+ \note Only call this function with a local JNI reference. For example, most raw JNI calls,
+ through the JNI environment, return local references to a java object.
+
+ \code
+ jobject localRef = env->GetObjectArrayElement(array, index);
+ QJniObject element = QJniObject::fromLocalRef(localRef);
+ \endcode
+*/
+QJniObject QJniObject::fromLocalRef(jobject lref)
+{
+ QJniObject obj(lref);
+ QJniEnvironment()->DeleteLocalRef(lref);
+ return obj;
+}
+
+bool QJniObject::isSameObject(jobject obj) const
+{
+ return QJniEnvironment()->IsSameObject(d->m_jobject, obj);
+}
+
+bool QJniObject::isSameObject(const QJniObject &other) const
+{
+ return isSameObject(other.d->m_jobject);
+}
+
+void QJniObject::assign(jobject obj)
+{
+ if (isSameObject(obj))
+ return;
+
+ jobject jobj = static_cast<jobject>(obj);
+ d = QSharedPointer<QJniObjectPrivate>::create();
+ if (obj) {
+ QJniEnvironment env;
+ d->m_jobject = env->NewGlobalRef(jobj);
+ jclass objectClass = env->GetObjectClass(jobj);
+ d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass));
+ env->DeleteLocalRef(objectClass);
+ }
+}
+
+jobject QJniObject::javaObject() const
+{
+ return d->m_jobject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
new file mode 100644
index 00000000000..2998c7b4e85
--- /dev/null
+++ b/src/corelib/kernel/qjniobject.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QJNIOBJECT_H
+#define QJNIOBJECT_H
+
+#include <QtCore/QSharedPointer>
+
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+#include <jni.h>
+#else
+class jclass;
+class jobject;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QJniObjectPrivate;
+
+class Q_CORE_EXPORT QJniObject
+{
+public:
+ QJniObject();
+ explicit QJniObject(const char *className);
+ explicit QJniObject(const char *className, const char *sig, ...);
+ explicit QJniObject(jclass clazz);
+ explicit QJniObject(jclass clazz, const char *sig, ...);
+ QJniObject(jobject globalRef);
+ ~QJniObject();
+
+ template <typename T>
+ T object() const;
+ jobject object() const;
+
+ template <typename T>
+ T callMethod(const char *methodName, const char *sig, ...) const;
+ template <typename T>
+ T callMethod(const char *methodName) const;
+ template <typename T>
+ QJniObject callObjectMethod(const char *methodName) const;
+ QJniObject callObjectMethod(const char *methodName, const char *sig, ...) const;
+
+ template <typename T>
+ static T callStaticMethod(const char *className, const char *methodName, const char *sig, ...);
+ template <typename T>
+ static T callStaticMethod(const char *className, const char *methodName);
+ template <typename T>
+ static T callStaticMethod(jclass clazz, const char *methodName, const char *sig, ...);
+ template <typename T>
+ static T callStaticMethod(jclass clazz, const char *methodName);
+
+ template <typename T>
+ static QJniObject callStaticObjectMethod(const char *className, const char *methodName);
+ static QJniObject callStaticObjectMethod(const char *className,
+ const char *methodName,
+ const char *sig, ...);
+
+ template <typename T>
+ static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName);
+ static QJniObject callStaticObjectMethod(jclass clazz,
+ const char *methodName,
+ const char *sig, ...);
+
+ template <typename T>
+ T getField(const char *fieldName) const;
+
+ template <typename T>
+ static T getStaticField(const char *className, const char *fieldName);
+ template <typename T>
+ static T getStaticField(jclass clazz, const char *fieldName);
+
+ template <typename T>
+ QJniObject getObjectField(const char *fieldName) const;
+ QJniObject getObjectField(const char *fieldName, const char *sig) const;
+
+ template <typename T>
+ static QJniObject getStaticObjectField(const char *className, const char *fieldName);
+ static QJniObject getStaticObjectField(const char *className,
+ const char *fieldName,
+ const char *sig);
+ template <typename T>
+ static QJniObject getStaticObjectField(const char *className,
+ const char *fieldName,
+ const char *sig);
+
+ template <typename T>
+ static QJniObject getStaticObjectField(jclass clazz, const char *fieldName);
+ static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
+ template <typename T>
+ static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
+
+ template <typename T>
+ void setField(const char *fieldName, T value);
+ template <typename T>
+ void setField(const char *fieldName, const char *sig, T value);
+ template <typename T>
+ static void setStaticField(const char *className, const char *fieldName, T value);
+ template <typename T>
+ static void setStaticField(const char *className, const char *fieldName,
+ const char *sig, T value);
+ template <typename T>
+ static void setStaticField(jclass clazz, const char *fieldName, const char *sig, T value);
+
+ template <typename T>
+ static void setStaticField(jclass clazz, const char *fieldName, T value);
+
+ static QJniObject fromString(const QString &string);
+ QString toString() const;
+
+ static bool isClassAvailable(const char *className);
+ bool isValid() const;
+
+ // This function takes ownership of the jobject and releases the local ref. before returning.
+ static QJniObject fromLocalRef(jobject lref);
+
+ template <typename T> QJniObject &operator=(T obj);
+
+private:
+ struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; };
+
+ QJniObject(const char *className, const char *sig, const QVaListPrivate &args);
+ QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args);
+
+ template <typename T>
+ T callMethodV(const char *methodName, const char *sig, va_list args) const;
+ QJniObject callObjectMethodV(const char *methodName, const char *sig, va_list args) const;
+ template <typename T>
+ static T callStaticMethodV(const char *className,
+ const char *methodName,
+ const char *sig,
+ va_list args);
+ template <typename T>
+ static T callStaticMethodV(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ va_list args);
+
+ static QJniObject callStaticObjectMethodV(const char *className,
+ const char *methodName,
+ const char *sig,
+ va_list args);
+
+ static QJniObject callStaticObjectMethodV(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ va_list args);
+
+ bool isSameObject(jobject obj) const;
+ bool isSameObject(const QJniObject &other) const;
+ void assign(jobject obj);
+ jobject javaObject() const;
+
+ friend bool operator==(const QJniObject &, const QJniObject &);
+ friend bool operator!=(const QJniObject&, const QJniObject&);
+
+ QSharedPointer<QJniObjectPrivate> d;
+};
+
+inline bool operator==(const QJniObject &obj1, const QJniObject &obj2)
+{
+ return obj1.isSameObject(obj2);
+}
+
+inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
+{
+ return !obj1.isSameObject(obj2);
+}
+
+QT_END_NAMESPACE
+
+#endif // QJNIOBJECT_H
diff --git a/src/corelib/kernel/qjnionload.cpp b/src/corelib/kernel/qjnionload.cpp
index ec56d3de66b..dbaee48ac60 100644
--- a/src/corelib/kernel/qjnionload.cpp
+++ b/src/corelib/kernel/qjnionload.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -37,8 +37,9 @@
**
****************************************************************************/
-#include <jni.h>
#include "qjnihelpers_p.h"
+
+#include <jni.h>
#include <android/log.h>
static const char logTag[] = "QtCore";
diff --git a/src/corelib/time/qtimezoneprivate_android.cpp b/src/corelib/time/qtimezoneprivate_android.cpp
index da82832455b..20f7f2df68b 100644
--- a/src/corelib/time/qtimezoneprivate_android.cpp
+++ b/src/corelib/time/qtimezoneprivate_android.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2014 Drew Parsons <[email protected]>
** Contact: https://www.qt.io/licensing/
**
@@ -38,10 +38,12 @@
**
****************************************************************************/
-#include <QtCore/QSet>
#include "qtimezone.h"
#include "qtimezoneprivate_p.h"
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QSet>
+
QT_BEGIN_NAMESPACE
/*
@@ -49,7 +51,7 @@ QT_BEGIN_NAMESPACE
Android implementation
- Note that a QJNIObjectPrivate manages a global reference, so it serves as an
+ Note that a QJniObject manages a global reference, so it serves as an
owning smart-pointer, ensuring an object doesn't get garbage-collected
before we're done with it.
*/
@@ -59,9 +61,9 @@ QAndroidTimeZonePrivate::QAndroidTimeZonePrivate()
: QTimeZonePrivate()
{
// Keep in sync with systemTimeZoneId():
- androidTimeZone = QJNIObjectPrivate::callStaticObjectMethod(
+ androidTimeZone = QJniObject::callStaticObjectMethod(
"java.util.TimeZone", "getDefault", "()Ljava/util/TimeZone;");
- const QJNIObjectPrivate id = androidTimeZone.callObjectMethod("getID", "()Ljava/lang/String;");
+ const QJniObject id = androidTimeZone.callObjectMethod("getID", "()Ljava/lang/String;");
m_id = id.toString().toUtf8();
}
@@ -83,16 +85,16 @@ QAndroidTimeZonePrivate::~QAndroidTimeZonePrivate()
{
}
-static QJNIObjectPrivate getDisplayName(QJNIObjectPrivate zone, jint style, jboolean dst,
+static QJniObject getDisplayName(QJniObject zone, jint style, jboolean dst,
const QLocale &locale)
{
- QJNIObjectPrivate jlanguage
- = QJNIObjectPrivate::fromString(QLocale::languageToString(locale.language()));
- QJNIObjectPrivate jcountry
- = QJNIObjectPrivate::fromString(QLocale::countryToString(locale.country()));
- QJNIObjectPrivate
- jvariant = QJNIObjectPrivate::fromString(QLocale::scriptToString(locale.script()));
- QJNIObjectPrivate jlocale("java.util.Locale",
+ QJniObject jlanguage
+ = QJniObject::fromString(QLocale::languageToString(locale.language()));
+ QJniObject jcountry
+ = QJniObject::fromString(QLocale::countryToString(locale.country()));
+ QJniObject
+ jvariant = QJniObject::fromString(QLocale::scriptToString(locale.script()));
+ QJniObject jlocale("java.util.Locale",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
static_cast<jstring>(jlanguage.object()),
static_cast<jstring>(jcountry.object()),
@@ -106,12 +108,12 @@ static QJNIObjectPrivate getDisplayName(QJNIObjectPrivate zone, jint style, jboo
void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
{
const QString iana = QString::fromUtf8(ianaId);
- androidTimeZone = QJNIObjectPrivate::callStaticObjectMethod(
+ androidTimeZone = QJniObject::callStaticObjectMethod(
"java.util.TimeZone", "getTimeZone", "(Ljava/lang/String;)Ljava/util/TimeZone;",
- static_cast<jstring>(QJNIObjectPrivate::fromString(iana).object()));
+ static_cast<jstring>(QJniObject::fromString(iana).object()));
// The ID or display name of the zone we've got, if it looks like what we asked for:
- const auto match = [iana](const QJNIObjectPrivate &jname) -> QByteArray {
+ const auto match = [iana](const QJniObject &jname) -> QByteArray {
const QString name = jname.toString();
if (iana.compare(name, Qt::CaseInsensitive) == 0)
return name.toUtf8();
@@ -205,7 +207,7 @@ bool QAndroidTimeZonePrivate::hasDaylightTime() const
bool QAndroidTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
{
if ( androidTimeZone.isValid() ) {
- QJNIObjectPrivate jDate( "java/util/Date", "(J)V", static_cast<jlong>(atMSecsSinceEpoch) );
+ QJniObject jDate( "java/util/Date", "(J)V", static_cast<jlong>(atMSecsSinceEpoch) );
return androidTimeZone.callMethod<jboolean>("inDaylightTime", "(Ljava/util/Date;)Z", jDate.object() );
}
else
@@ -250,24 +252,24 @@ QTimeZonePrivate::Data QAndroidTimeZonePrivate::previousTransition(qint64 before
QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const
{
// Keep in sync with default constructor:
- QJNIObjectPrivate androidSystemTimeZone = QJNIObjectPrivate::callStaticObjectMethod(
+ QJniObject androidSystemTimeZone = QJniObject::callStaticObjectMethod(
"java.util.TimeZone", "getDefault", "()Ljava/util/TimeZone;");
- const QJNIObjectPrivate id = androidSystemTimeZone.callObjectMethod<jstring>("getID");
+ const QJniObject id = androidSystemTimeZone.callObjectMethod<jstring>("getID");
return id.toString().toUtf8();
}
QList<QByteArray> QAndroidTimeZonePrivate::availableTimeZoneIds() const
{
QList<QByteArray> availableTimeZoneIdList;
- QJNIObjectPrivate androidAvailableIdList = QJNIObjectPrivate::callStaticObjectMethod("java.util.TimeZone", "getAvailableIDs", "()[Ljava/lang/String;");
+ QJniObject androidAvailableIdList = QJniObject::callStaticObjectMethod("java.util.TimeZone", "getAvailableIDs", "()[Ljava/lang/String;");
- QJNIEnvironmentPrivate jniEnv;
+ QJniEnvironment jniEnv;
int androidTZcount = jniEnv->GetArrayLength( static_cast<jarray>(androidAvailableIdList.object()) );
- // need separate jobject and QAndroidJniObject here so that we can delete (DeleteLocalRef) the reference to the jobject
+ // need separate jobject and QJniObject here so that we can delete (DeleteLocalRef) the reference to the jobject
// (or else the JNI reference table fills after 512 entries from GetObjectArrayElement)
jobject androidTZobject;
- QJNIObjectPrivate androidTZ;
+ QJniObject androidTZ;
for (int i=0; i<androidTZcount; i++ ) {
androidTZobject = jniEnv->GetObjectArrayElement( static_cast<jobjectArray>( androidAvailableIdList.object() ), i );
androidTZ = androidTZobject;
diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h
index d15d7ccfea7..b6ae3764b12 100644
--- a/src/corelib/time/qtimezoneprivate_p.h
+++ b/src/corelib/time/qtimezoneprivate_p.h
@@ -70,7 +70,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
#endif // Q_OS_WIN
#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
-#include <QtCore/private/qjni_p.h>
+#include <QJniObject>
#endif
QT_BEGIN_NAMESPACE
@@ -496,7 +496,7 @@ public:
private:
void init(const QByteArray &zoneId);
- QJNIObjectPrivate androidTimeZone;
+ QJniObject androidTimeZone;
};
#endif // Q_OS_ANDROID
diff --git a/src/network/kernel/qnetworkproxy_android.cpp b/src/network/kernel/qnetworkproxy_android.cpp
index 1a6fe2b70e1..a09593bf3c0 100644
--- a/src/network/kernel/qnetworkproxy_android.cpp
+++ b/src/network/kernel/qnetworkproxy_android.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -38,7 +38,9 @@
****************************************************************************/
#include "qnetworkproxy.h"
-#include <QtCore/private/qjni_p.h>
+
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <QtCore/private/qjnihelpers_p.h>
#ifndef QT_NO_NETWORKPROXY
@@ -58,18 +60,18 @@ static const char networkClass[] = "org/qtproject/qt/android/network/QtNetwork";
ProxyInfoObject::ProxyInfoObject()
{
- QJNIObjectPrivate::callStaticMethod<void>(networkClass,
- "registerReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
+ QJniObject::callStaticMethod<void>(networkClass,
+ "registerReceiver",
+ "(Landroid/content/Context;)V",
+ QtAndroidPrivate::context());
}
ProxyInfoObject::~ProxyInfoObject()
{
- QJNIObjectPrivate::callStaticMethod<void>(networkClass,
- "unregisterReceiver",
- "(Landroid/content/Context;)V",
- QtAndroidPrivate::context());
+ QJniObject::callStaticMethod<void>(networkClass,
+ "unregisterReceiver",
+ "(Landroid/content/Context;)V",
+ QtAndroidPrivate::context());
}
QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
@@ -78,18 +80,18 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
if (!proxyInfoInstance)
return proxyList;
- QJNIObjectPrivate proxyInfo = QJNIObjectPrivate::callStaticObjectMethod(networkClass,
+ QJniObject proxyInfo = QJniObject::callStaticObjectMethod(networkClass,
"getProxyInfo",
"(Landroid/content/Context;)Landroid/net/ProxyInfo;",
QtAndroidPrivate::context());
if (proxyInfo.isValid()) {
- QJNIObjectPrivate exclusionList = proxyInfo.callObjectMethod("getExclusionList",
- "()[Ljava/lang/String;");
+ QJniObject exclusionList = proxyInfo.callObjectMethod("getExclusionList",
+ "()[Ljava/lang/String;");
bool exclude = false;
if (exclusionList.isValid()) {
jobjectArray listObject = static_cast<jobjectArray>(exclusionList.object());
- QJNIEnvironmentPrivate env;
- QJNIObjectPrivate entry;
+ QJniEnvironment env;
+ QJniObject entry;
const int size = env->GetArrayLength(listObject);
QUrl host = QUrl(query.url().host());
for (int i = 0; i < size; ++i) {
@@ -101,7 +103,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
}
}
if (!exclude) {
- QJNIObjectPrivate hostName = proxyInfo.callObjectMethod<jstring>("getHost");
+ QJniObject hostName = proxyInfo.callObjectMethod<jstring>("getHost");
const int port = proxyInfo.callMethod<jint>("getPort");
QNetworkProxy proxy(QNetworkProxy::HttpProxy, hostName.toString(), port);
proxyList << proxy;
diff --git a/src/network/ssl/qsslsocket_openssl_android.cpp b/src/network/ssl/qsslsocket_openssl_android.cpp
index deec1532a21..8d0c9a69eee 100644
--- a/src/network/ssl/qsslsocket_openssl_android.cpp
+++ b/src/network/ssl/qsslsocket_openssl_android.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -53,7 +53,8 @@
****************************************************************************/
#include "qsslsocket_openssl_p.h"
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -61,13 +62,13 @@ QList<QByteArray> QSslSocketPrivate::fetchSslCertificateData()
{
QList<QByteArray> certificateData;
- QJNIObjectPrivate certificates = QJNIObjectPrivate::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
- "getSSLCertificates",
- "()[[B");
+ QJniObject certificates = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
+ "getSSLCertificates",
+ "()[[B");
if (!certificates.isValid())
return certificateData;
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
jobjectArray jcertificates = static_cast<jobjectArray>(certificates.object());
const jint nCertificates = env->GetArrayLength(jcertificates);
certificateData.reserve(static_cast<int>(nCertificates));
diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp
index 749ce136b67..149bc1139dc 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.cpp
+++ b/src/plugins/platforms/android/androidcontentfileengine.cpp
@@ -39,7 +39,8 @@
#include "androidcontentfileengine.h"
-#include <private/qjni_p.h>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
#include <private/qjnihelpers_p.h>
#include <QDebug>
@@ -65,12 +66,12 @@ bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode)
openModeStr += QLatin1Char('a');
}
- const auto fd = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
+ const auto fd = QJniObject::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
"openFdForContentUrl",
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)I",
QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object(),
- QJNIObjectPrivate::fromString(openModeStr).object());
+ QJniObject::fromString(fileName(DefaultName)).object(),
+ QJniObject::fromString(openModeStr).object());
if (fd < 0) {
return false;
@@ -81,10 +82,10 @@ bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode)
qint64 AndroidContentFileEngine::size() const
{
- const jlong size = QJNIObjectPrivate::callStaticMethod<jlong>(
+ const jlong size = QJniObject::callStaticMethod<jlong>(
"org/qtproject/qt/android/QtNative", "getSize",
"(Landroid/content/Context;Ljava/lang/String;)J", QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
+ QJniObject::fromString(fileName(DefaultName)).object());
return (qint64)size;
}
@@ -92,25 +93,25 @@ AndroidContentFileEngine::FileFlags AndroidContentFileEngine::fileFlags(FileFlag
{
FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
FileFlags flags;
- const bool isDir = QJNIObjectPrivate::callStaticMethod<jboolean>(
+ const bool isDir = QJniObject::callStaticMethod<jboolean>(
"org/qtproject/qt/android/QtNative", "checkIfDir",
"(Landroid/content/Context;Ljava/lang/String;)Z", QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
+ QJniObject::fromString(fileName(DefaultName)).object());
// If it is a directory then we know it exists so there is no reason to explicitly check
- const bool exists = isDir ? true : QJNIObjectPrivate::callStaticMethod<jboolean>(
+ const bool exists = isDir ? true : QJniObject::callStaticMethod<jboolean>(
"org/qtproject/qt/android/QtNative", "checkFileExists",
"(Landroid/content/Context;Ljava/lang/String;)Z", QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
+ QJniObject::fromString(fileName(DefaultName)).object());
if (!exists && !isDir)
return flags;
if (isDir) {
flags = DirectoryType | commonFlags;
} else {
flags = FileType | commonFlags;
- const bool writable = QJNIObjectPrivate::callStaticMethod<jboolean>(
+ const bool writable = QJniObject::callStaticMethod<jboolean>(
"org/qtproject/qt/android/QtNative", "checkIfWritable",
"(Landroid/content/Context;Ljava/lang/String;)Z", QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
+ QJniObject::fromString(fileName(DefaultName)).object());
if (writable)
flags |= WriteOwnerPerm|WriteUserPerm|WriteGroupPerm|WriteOtherPerm;
}
@@ -182,22 +183,22 @@ bool AndroidContentFileEngineIterator::hasNext() const
if (m_index == -1) {
if (path().isEmpty())
return false;
- const bool isDir = QJNIObjectPrivate::callStaticMethod<jboolean>(
+ const bool isDir = QJniObject::callStaticMethod<jboolean>(
"org/qtproject/qt/android/QtNative", "checkIfDir",
"(Landroid/content/Context;Ljava/lang/String;)Z",
QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(path()).object());
+ QJniObject::fromString(path()).object());
if (isDir) {
- QJNIObjectPrivate objArray = QJNIObjectPrivate::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
+ QJniObject objArray = QJniObject::callStaticObjectMethod("org/qtproject/qt/android/QtNative",
"listContentsFromTreeUri",
"(Landroid/content/Context;Ljava/lang/String;)[Ljava/lang/String;",
QtAndroidPrivate::context(),
- QJNIObjectPrivate::fromString(path()).object());
+ QJniObject::fromString(path()).object());
if (objArray.isValid()) {
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
const jsize length = env->GetArrayLength(static_cast<jarray>(objArray.object()));
for (int i = 0; i != length; ++i) {
- m_entries << QJNIObjectPrivate(env->GetObjectArrayElement(
+ m_entries << QJniObject(env->GetObjectArrayElement(
static_cast<jobjectArray>(objArray.object()), i)).toString();
}
}
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index a4e88d84d46..62460f5e6d6 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -48,11 +48,9 @@
#include "QtGui/qaccessible.h"
#include <QtCore/qmath.h>
#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
#include <QtGui/private/qhighdpiscaling_p.h>
-#include "qdebug.h"
-
static const char m_qtTag[] = "Qt A11Y";
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
@@ -77,8 +75,8 @@ namespace QtAndroidAccessibility
void initialize()
{
- QJNIObjectPrivate::callStaticMethod<void>(QtAndroid::applicationClass(),
- "initializeAccessibility");
+ QJniObject::callStaticMethod<void>(QtAndroid::applicationClass(),
+ "initializeAccessibility");
}
bool isActive()
diff --git a/src/plugins/platforms/android/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp
index c20ac456b19..597a56eb1ad 100644
--- a/src/plugins/platforms/android/androidjniclipboard.cpp
+++ b/src/plugins/platforms/android/androidjniclipboard.cpp
@@ -39,7 +39,8 @@
#include "androidjniclipboard.h"
#include <QtCore/QUrl>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
+#include <QtCore/QJniEnvironment>
QT_BEGIN_NAMESPACE
@@ -55,9 +56,9 @@ namespace QtAndroidClipboard
void setClipboardManager(QAndroidPlatformClipboard *manager)
{
m_manager = manager;
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "registerClipboardManager");
+ QJniObject::callStaticMethod<void>(applicationClass(), "registerClipboardManager");
jclass appClass = QtAndroid::applicationClass();
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
return;
@@ -65,29 +66,30 @@ namespace QtAndroidClipboard
}
void clearClipboardData()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "clearClipData");
+ QJniObject::callStaticMethod<void>(applicationClass(), "clearClipData");
}
void setClipboardMimeData(QMimeData *data)
{
clearClipboardData();
if (data->hasText()) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "setClipboardText", "(Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(data->text()).object());
+ QJniObject::callStaticMethod<void>(applicationClass(),
+ "setClipboardText", "(Ljava/lang/String;)V",
+ QJniObject::fromString(data->text()).object());
}
if (data->hasHtml()) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "setClipboardHtml",
- "(Ljava/lang/String;Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(data->text()).object(),
- QJNIObjectPrivate::fromString(data->html()).object());
+ QJniObject::callStaticMethod<void>(applicationClass(),
+ "setClipboardHtml",
+ "(Ljava/lang/String;Ljava/lang/String;)V",
+ QJniObject::fromString(data->text()).object(),
+ QJniObject::fromString(data->html()).object());
}
if (data->hasUrls()) {
QList<QUrl> urls = data->urls();
for (const auto &u : qAsConst(urls)) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "setClipboardUri",
- "(Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(u.toEncoded()).object());
+ QJniObject::callStaticMethod<void>(applicationClass(),
+ "setClipboardUri",
+ "(Ljava/lang/String;)V",
+ QJniObject::fromString(u.toEncoded()).object());
}
}
}
@@ -95,28 +97,28 @@ namespace QtAndroidClipboard
QMimeData *getClipboardMimeData()
{
QMimeData *data = new QMimeData;
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardText")) {
- data->setText(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardText",
- "()Ljava/lang/String;").toString());
+ if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardText")) {
+ data->setText(QJniObject::callStaticObjectMethod(applicationClass(),
+ "getClipboardText",
+ "()Ljava/lang/String;").toString());
}
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardHtml")) {
- data->setHtml(QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardHtml",
- "()Ljava/lang/String;").toString());
+ if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardHtml")) {
+ data->setHtml(QJniObject::callStaticObjectMethod(applicationClass(),
+ "getClipboardHtml",
+ "()Ljava/lang/String;").toString());
}
- if (QJNIObjectPrivate::callStaticMethod<jboolean>(applicationClass(), "hasClipboardUri")) {
- QJNIObjectPrivate uris = QJNIObjectPrivate::callStaticObjectMethod(applicationClass(),
- "getClipboardUris",
- "()[Ljava/lang/String;");
+ if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardUri")) {
+ QJniObject uris = QJniObject::callStaticObjectMethod(applicationClass(),
+ "getClipboardUris",
+ "()[Ljava/lang/String;");
if (uris.isValid()) {
QList<QUrl> urls;
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
jobjectArray juris = static_cast<jobjectArray>(uris.object());
const jint nUris = env->GetArrayLength(juris);
urls.reserve(static_cast<int>(nUris));
for (int i = 0; i < nUris; ++i)
- urls << QUrl(QJNIObjectPrivate(env->GetObjectArrayElement(juris, i)).toString());
+ urls << QUrl(QJniObject(env->GetObjectArrayElement(juris, i)).toString());
data->setUrls(urls);
}
}
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index 5e4d271fcce..a72682dd236 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -49,7 +49,6 @@
#include <QPointer>
#include <QGuiApplication>
-#include <QDebug>
#include <QtMath>
QT_BEGIN_NAMESPACE
@@ -71,27 +70,26 @@ namespace QtAndroidInput
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
#endif
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "updateSelection",
- "(IIII)V",
- selStart,
- selEnd,
- candidatesStart,
- candidatesEnd);
+ QJniObject::callStaticMethod<void>(applicationClass(),
+ "updateSelection",
+ "(IIII)V",
+ selStart,
+ selEnd,
+ candidatesStart,
+ candidatesEnd);
}
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(),
- "showSoftwareKeyboard",
- "(IIIIII)V",
- left,
- top,
- width,
- height,
- inputHints,
- enterKeyType
- );
+ QJniObject::callStaticMethod<void>(applicationClass(),
+ "showSoftwareKeyboard",
+ "(IIIIII)V",
+ left,
+ top,
+ width,
+ height,
+ inputHints,
+ enterKeyType);
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
#endif
@@ -99,7 +97,7 @@ namespace QtAndroidInput
void resetSoftwareKeyboard()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard");
+ QJniObject::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard");
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ RESETSOFTWAREKEYBOARD");
#endif
@@ -107,7 +105,7 @@ namespace QtAndroidInput
void hideSoftwareKeyboard()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard");
+ QJniObject::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard");
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug("@@@ HIDESOFTWAREKEYBOARD");
#endif
@@ -125,10 +123,10 @@ namespace QtAndroidInput
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
- mode, editMenuPos.x(), editMenuPos.y(), editButtons,
- cursor.x(), cursor.y(),
- anchor.x(), anchor.y(), rtl);
+ QJniObject::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
+ mode, editMenuPos.x(), editMenuPos.y(), editButtons,
+ cursor.x(), cursor.y(),
+ anchor.x(), anchor.y(), rtl);
}
static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 559cdc6e570..bdd7f492ac2 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <[email protected]>
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -40,30 +40,30 @@
#include <dlfcn.h>
#include <pthread.h>
-#include <semaphore.h>
#include <qplugin.h>
-#include <qdebug.h>
+#include <semaphore.h>
-#include "androidjnimain.h"
+#include "androidcontentfileengine.h"
+#include "androiddeadlockprotector.h"
#include "androidjniaccessibility.h"
-#include "androidjniinput.h"
#include "androidjniclipboard.h"
+#include "androidjniinput.h"
+#include "androidjnimain.h"
#include "androidjnimenu.h"
-#include "androidcontentfileengine.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidassetsfileenginehandler.h"
+#include "qandroideventdispatcher.h"
#include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h"
-#include "qandroidassetsfileenginehandler.h"
-#include <android/bitmap.h>
-#include <android/asset_manager_jni.h>
-#include "qandroideventdispatcher.h"
#include <android/api-level.h>
+#include <android/asset_manager_jni.h>
+#include <android/bitmap.h>
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
#include <QtCore/qresource.h>
#include <QtCore/qthread.h>
-#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
@@ -205,22 +205,22 @@ namespace QtAndroid
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
+ QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
}
void notifyAccessibilityLocationChange()
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyAccessibilityLocationChange");
+ QJniObject::callStaticMethod<void>(m_applicationClass, "notifyAccessibilityLocationChange");
}
void notifyObjectHide(uint accessibilityObjectId)
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyObjectHide","(I)V", accessibilityObjectId);
+ QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectHide","(I)V", accessibilityObjectId);
}
void notifyObjectFocus(uint accessibilityObjectId)
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyObjectFocus","(I)V", accessibilityObjectId);
+ QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectFocus","(I)V", accessibilityObjectId);
}
jobject createBitmap(QImage img, JNIEnv *env)
@@ -311,15 +311,15 @@ namespace QtAndroid
QString deviceName()
{
- QString manufacturer = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
- QString model = QJNIObjectPrivate::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
+ QString manufacturer = QJniObject::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
+ QString model = QJniObject::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
return manufacturer + QLatin1Char(' ') + model;
}
int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
{
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
if (!env)
return -1;
@@ -355,26 +355,26 @@ namespace QtAndroid
if (!geometry.isNull())
geometry.getRect(&x, &y, &w, &h);
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "insertNativeView",
- "(ILandroid/view/View;IIII)V",
- surfaceId,
- view,
- x,
- y,
- qMax(w, 1),
- qMax(h, 1));
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "insertNativeView",
+ "(ILandroid/view/View;IIII)V",
+ surfaceId,
+ view,
+ x,
+ y,
+ qMax(w, 1),
+ qMax(h, 1));
return surfaceId;
}
void setViewVisibility(jobject view, bool visible)
{
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "setViewVisibility",
- "(Landroid/view/View;Z)V",
- view,
- visible);
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "setViewVisibility",
+ "(Landroid/view/View;Z)V",
+ view,
+ visible);
}
void setSurfaceGeometry(int surfaceId, const QRect &geometry)
@@ -382,7 +382,7 @@ namespace QtAndroid
if (surfaceId == -1)
return;
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
if (!env)
return;
jint x = 0, y = 0, w = -1, h = -1;
@@ -393,9 +393,9 @@ namespace QtAndroid
h = geometry.height();
}
env->CallStaticVoidMethod(m_applicationClass,
- m_setSurfaceGeometryMethodID,
- surfaceId,
- x, y, w, h);
+ m_setSurfaceGeometryMethodID,
+ surfaceId,
+ x, y, w, h);
}
@@ -411,11 +411,11 @@ namespace QtAndroid
m_surfaces.erase(it);
}
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
if (env)
env->CallStaticVoidMethod(m_applicationClass,
- m_destroySurfaceMethodID,
- surfaceId);
+ m_destroySurfaceMethodID,
+ surfaceId);
}
void bringChildToFront(int surfaceId)
@@ -423,10 +423,10 @@ namespace QtAndroid
if (surfaceId == -1)
return;
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "bringChildToFront",
- "(I)V",
- surfaceId);
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "bringChildToFront",
+ "(I)V",
+ surfaceId);
}
void bringChildToBack(int surfaceId)
@@ -434,10 +434,10 @@ namespace QtAndroid
if (surfaceId == -1)
return;
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
- "bringChildToBack",
- "(I)V",
- surfaceId);
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "bringChildToBack",
+ "(I)V",
+ surfaceId);
}
bool blockEventLoopsWhenSuspended()
@@ -550,7 +550,7 @@ static jboolean startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
if (m_applicationClass) {
qWarning("exit app 0");
- QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
+ QJniObject::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
}
sem_post(&m_terminateSemaphore);
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp
index fe5de1f8823..9b491403350 100644
--- a/src/plugins/platforms/android/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/androidjnimenu.cpp
@@ -37,10 +37,10 @@
**
****************************************************************************/
-#include "androidjnimenu.h"
#include "androidjnimain.h"
-#include "qandroidplatformmenubar.h"
+#include "androidjnimenu.h"
#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenuitem.h"
#include <QMutex>
@@ -50,7 +50,7 @@
#include <QSet>
#include <QWindow>
#include <QtCore/private/qjnihelpers_p.h>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -82,12 +82,12 @@ namespace QtAndroidMenu
void resetMenuBar()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "resetOptionsMenu");
+ QJniObject::callStaticMethod<void>(applicationClass(), "resetOptionsMenu");
}
void openOptionsMenu()
{
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "openOptionsMenu");
+ QJniObject::callStaticMethod<void>(applicationClass(), "openOptionsMenu");
}
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env)
@@ -104,13 +104,14 @@ namespace QtAndroidMenu
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) {
- QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "closeContextMenu");
+ QJniObject::callStaticMethod<void>(applicationClass(), "closeContextMenu");
pendingContextMenus.clear();
} else {
pendingContextMenus.removeOne(menu);
}
}
+ // FIXME
void syncMenu(QAndroidPlatformMenu */*menu*/)
{
// QMutexLocker lock(&visibleMenuMutex);
diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp
index c68dae31e9c..bac3c3709ef 100644
--- a/src/plugins/platforms/android/extract.cpp
+++ b/src/plugins/platforms/android/extract.cpp
@@ -39,10 +39,12 @@
-#include <jni.h>
+#include <QtCore/QJniEnvironment>
+
+#include <alloca.h>
#include <android/log.h>
#include <extract.h>
-#include <alloca.h>
+#include <jni.h>
#include <stdlib.h>
#define LOG_TAG "extractSyleInfo"
@@ -133,12 +135,15 @@ Java_org_qtproject_qt_android_ExtractStyle_extractChunkInfo20(JNIEnv *env, jobje
env->GetByteArrayRegion(chunkObj, 0, chunkSize,
reinterpret_cast<jbyte*>(storage));
- if (!env->ExceptionCheck())
- return Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(env, obj,
- long(storage));
- else
- env->ExceptionClear();
- return 0;
+ if (QJniEnvironment::exceptionCheckAndClear(env))
+ return 0;
+
+ jintArray res = Java_org_qtproject_qt_android_ExtractStyle_extractNativeChunkInfo20(env, obj,
+ long(storage));
+ if (QJniEnvironment::exceptionCheckAndClear(env))
+ res = nullptr;
+
+ return res;
}
static inline void fill9patchOffsets(Res_png_9patch20* patch) {
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
index 6edddf4a66f..2dbb1044f02 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
@@ -37,13 +37,15 @@
**
****************************************************************************/
-#include "qandroidassetsfileenginehandler.h"
#include "androidjnimain.h"
+#include "qandroidassetsfileenginehandler.h"
+
#include <optional>
#include <QCoreApplication>
#include <QList>
-#include <QtCore/private/qjni_p.h>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -139,16 +141,16 @@ public:
FolderIterator(const QString &path)
: m_path(path)
{
- QJNIObjectPrivate files = QJNIObjectPrivate::callStaticObjectMethod(QtAndroid::applicationClass(),
+ QJniObject files = QJniObject::callStaticObjectMethod(QtAndroid::applicationClass(),
"listAssetContent",
"(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;",
- QtAndroid::assets(), QJNIObjectPrivate::fromString(path).object());
+ QtAndroid::assets(), QJniObject::fromString(path).object());
if (files.isValid()) {
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
jobjectArray jFiles = static_cast<jobjectArray>(files.object());
const jint nFiles = env->GetArrayLength(jFiles);
for (int i = 0; i < nFiles; ++i) {
- AssetItem item{QJNIObjectPrivate::fromLocalRef(env->GetObjectArrayElement(jFiles, i)).toString()};
+ AssetItem item{QJniObject::fromLocalRef(env->GetObjectArrayElement(jFiles, i)).toString()};
insert(std::upper_bound(begin(), end(), item, [](const auto &a, const auto &b){
return a.name < b.name;
}), item);
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index e39f17a26f9..06947c9c322 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -41,26 +41,24 @@
#include <android/log.h>
-#include "qandroidinputcontext.h"
-#include "androidjnimain.h"
+#include "androiddeadlockprotector.h"
#include "androidjniinput.h"
+#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidinputcontext.h"
#include "qandroidplatformintegration.h"
-#include <QDebug>
+
+#include <QTextBoundaryFinder>
+#include <QTextCharFormat>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <private/qhighdpiscaling_p.h>
#include <qevent.h>
#include <qguiapplication.h>
+#include <qinputmethod.h>
#include <qsharedpointer.h>
#include <qthread.h>
-#include <qinputmethod.h>
#include <qwindow.h>
-#include <QtCore/private/qjni_p.h>
-#include <private/qhighdpiscaling_p.h>
-
-#include <QTextCharFormat>
-#include <QTextBoundaryFinder>
-
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -434,7 +432,8 @@ QAndroidInputContext::QAndroidInputContext()
, m_batchEditNestingLevel(0)
, m_focusObject(0)
{
- jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName);
+ QJniEnvironment env;
+ jclass clazz = env.findClass(QtNativeInputConnectionClassName);
if (Q_UNLIKELY(!clazz)) {
qCritical() << "Native registration unable to find class '"
<< QtNativeInputConnectionClassName
@@ -442,7 +441,6 @@ QAndroidInputContext::QAndroidInputContext()
return;
}
- QJNIEnvironmentPrivate env;
if (Q_UNLIKELY(env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0)) {
qCritical() << "RegisterNatives failed for '"
<< QtNativeInputConnectionClassName
@@ -450,7 +448,7 @@ QAndroidInputContext::QAndroidInputContext()
return;
}
- clazz = QJNIEnvironmentPrivate::findClass(QtExtractedTextClassName);
+ clazz = env.findClass(QtExtractedTextClassName);
if (Q_UNLIKELY(!clazz)) {
qCritical() << "Native registration unable to find class '"
<< QtExtractedTextClassName
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index 9ce63dceecb..334dd31d9a2 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -90,19 +90,19 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
QString str = htmlText(opt->windowTitle());
if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJniObject::fromString(str).object());
str = htmlText(opt->text());
if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJniObject::fromString(str).object());
str = htmlText(opt->informativeText());
if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJniObject::fromString(str).object());
str = htmlText(opt->detailedText());
if (!str.isEmpty())
- m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
+ m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJniObject::fromString(str).object());
const int * currentLayout = buttonLayout(Qt::Horizontal, AndroidLayout);
while (*currentLayout != QPlatformDialogHelper::EOL) {
@@ -123,7 +123,7 @@ void QAndroidPlatformMessageDialogHelper::addButtons(QSharedPointer<QMessageDial
QString label = b.label;
label.remove(QChar('&'));
m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", b.id,
- QJNIObjectPrivate::fromString(label).object());
+ QJniObject::fromString(label).object());
}
}
@@ -131,7 +131,7 @@ void QAndroidPlatformMessageDialogHelper::addButtons(QSharedPointer<QMessageDial
StandardButton b = static_cast<StandardButton>(i);
if (buttonRole(b) == role && (opt->standardButtons() & i)) {
const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(b);
- m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJNIObjectPrivate::fromString(text).object());
+ m_javaMessageDialog.callMethod<void>("addButton", "(ILjava/lang/String;)V", i, QJniObject::fromString(text).object());
}
}
}
@@ -183,7 +183,8 @@ static JNINativeMethod methods[] = {
bool registerNatives(JNIEnv *env)
{
- jclass clazz = QJNIEnvironmentPrivate::findClass(QtMessageHandlerHelperClassName, env);
+ QJniEnvironment qenv;
+ jclass clazz = qenv.findClass(QtMessageHandlerHelperClassName);
if (!clazz) {
__android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt()
, QtMessageHandlerHelperClassName);
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
index 694b4c75804..1953b842d56 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 BogDan Vatra <[email protected]>
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -39,10 +40,13 @@
#ifndef QANDROIDPLATFORMDIALOGHELPERS_H
#define QANDROIDPLATFORMDIALOGHELPERS_H
+
#include <jni.h>
-#include <qpa/qplatformdialoghelper.h>
+
#include <QEventLoop>
-#include <private/qjni_p.h>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
@@ -68,7 +72,7 @@ private:
private:
int m_buttonId;
QEventLoop m_loop;
- QJNIObjectPrivate m_javaMessageDialog;
+ QJniObject m_javaMessageDialog;
bool m_shown;
};
diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
index acfa4542a1a..0b539d1af39 100644
--- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -40,10 +41,10 @@
#include "qandroidplatformfiledialoghelper.h"
#include <androidjnimain.h>
-#include <jni.h>
+#include <QtCore/QJniObject>
-#include <QMimeType>
#include <QMimeDatabase>
+#include <QMimeType>
#include <QRegularExpression>
QT_BEGIN_NAMESPACE
@@ -71,9 +72,9 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
return true;
}
- const QJNIObjectPrivate intent = QJNIObjectPrivate::fromLocalRef(data);
+ const QJniObject intent = QJniObject::fromLocalRef(data);
- const QJNIObjectPrivate uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;");
+ const QJniObject uri = intent.callObjectMethod("getData", "()Landroid/net/Uri;");
if (uri.isValid()) {
takePersistableUriPermission(uri);
m_selectedFile.append(QUrl(uri.toString()));
@@ -83,15 +84,15 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
return true;
}
- const QJNIObjectPrivate uriClipData =
+ const QJniObject uriClipData =
intent.callObjectMethod("getClipData", "()Landroid/content/ClipData;");
if (uriClipData.isValid()) {
const int size = uriClipData.callMethod<jint>("getItemCount");
for (int i = 0; i < size; ++i) {
- QJNIObjectPrivate item = uriClipData.callObjectMethod(
+ QJniObject item = uriClipData.callObjectMethod(
"getItemAt", "(I)Landroid/content/ClipData$Item;", i);
- QJNIObjectPrivate itemUri = item.callObjectMethod("getUri", "()Landroid/net/Uri;");
+ QJniObject itemUri = item.callObjectMethod("getUri", "()Landroid/net/Uri;");
takePersistableUriPermission(itemUri);
m_selectedFile.append(itemUri.toString());
}
@@ -102,17 +103,17 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
return true;
}
-void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJNIObjectPrivate &uri)
+void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJniObject &uri)
{
- int modeFlags = QJNIObjectPrivate::getStaticField<jint>(
+ int modeFlags = QJniObject::getStaticField<jint>(
JniIntentClass, "FLAG_GRANT_READ_URI_PERMISSION");
if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
- modeFlags |= QJNIObjectPrivate::getStaticField<jint>(
+ modeFlags |= QJniObject::getStaticField<jint>(
JniIntentClass, "FLAG_GRANT_WRITE_URI_PERMISSION");
}
- QJNIObjectPrivate contentResolver = m_activity.callObjectMethod(
+ QJniObject contentResolver = m_activity.callObjectMethod(
"getContentResolver", "()Landroid/content/ContentResolver;");
contentResolver.callMethod<void>("takePersistableUriPermission", "(Landroid/net/Uri;I)V",
uri.object(), modeFlags);
@@ -120,16 +121,16 @@ void QAndroidPlatformFileDialogHelper::takePersistableUriPermission(const QJNIOb
void QAndroidPlatformFileDialogHelper::setIntentTitle(const QString &title)
{
- const QJNIObjectPrivate extraTitle = QJNIObjectPrivate::getStaticObjectField(
+ const QJniObject extraTitle = QJniObject::getStaticObjectField(
JniIntentClass, "EXTRA_TITLE", "Ljava/lang/String;");
m_intent.callObjectMethod("putExtra",
"(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
- extraTitle.object(), QJNIObjectPrivate::fromString(title).object());
+ extraTitle.object(), QJniObject::fromString(title).object());
}
void QAndroidPlatformFileDialogHelper::setOpenableCategory()
{
- const QJNIObjectPrivate CATEGORY_OPENABLE = QJNIObjectPrivate::getStaticObjectField(
+ const QJniObject CATEGORY_OPENABLE = QJniObject::getStaticObjectField(
JniIntentClass, "CATEGORY_OPENABLE", "Ljava/lang/String;");
m_intent.callObjectMethod("addCategory", "(Ljava/lang/String;)Landroid/content/Intent;",
CATEGORY_OPENABLE.object());
@@ -137,7 +138,7 @@ void QAndroidPlatformFileDialogHelper::setOpenableCategory()
void QAndroidPlatformFileDialogHelper::setAllowMultipleSelections(bool allowMultiple)
{
- const QJNIObjectPrivate allowMultipleSelections = QJNIObjectPrivate::getStaticObjectField(
+ const QJniObject allowMultipleSelections = QJniObject::getStaticObjectField(
JniIntentClass, "EXTRA_ALLOW_MULTIPLE", "Ljava/lang/String;");
m_intent.callObjectMethod("putExtra", "(Ljava/lang/String;Z)Landroid/content/Intent;",
allowMultipleSelections.object(), allowMultiple);
@@ -169,17 +170,17 @@ void QAndroidPlatformFileDialogHelper::setMimeTypes()
QString type = !mimeTypes.isEmpty() ? mimeTypes.at(0) : QLatin1String("*/*");
m_intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;",
- QJNIObjectPrivate::fromString(type).object());
+ QJniObject::fromString(type).object());
if (!mimeTypes.isEmpty()) {
- const QJNIObjectPrivate extraMimeType = QJNIObjectPrivate::getStaticObjectField(
+ const QJniObject extraMimeType = QJniObject::getStaticObjectField(
JniIntentClass, "EXTRA_MIME_TYPES", "Ljava/lang/String;");
- QJNIObjectPrivate mimeTypesArray = QJNIObjectPrivate::callStaticObjectMethod(
+ QJniObject mimeTypesArray = QJniObject::callStaticObjectMethod(
"org/qtproject/qt/android/QtNative",
"getStringArray",
"(Ljava/lang/String;)[Ljava/lang/String;",
- QJNIObjectPrivate::fromString(mimeTypes.join(",")).object());
+ QJniObject::fromString(mimeTypes.join(",")).object());
m_intent.callObjectMethod(
"putExtra", "(Ljava/lang/String;[Ljava/lang/String;)Landroid/content/Intent;",
@@ -187,11 +188,11 @@ void QAndroidPlatformFileDialogHelper::setMimeTypes()
}
}
-QJNIObjectPrivate QAndroidPlatformFileDialogHelper::getFileDialogIntent(const QString &intentType)
+QJniObject QAndroidPlatformFileDialogHelper::getFileDialogIntent(const QString &intentType)
{
- const QJNIObjectPrivate ACTION_OPEN_DOCUMENT = QJNIObjectPrivate::getStaticObjectField(
+ const QJniObject ACTION_OPEN_DOCUMENT = QJniObject::getStaticObjectField(
JniIntentClass, intentType.toLatin1(), "Ljava/lang/String;");
- return QJNIObjectPrivate(JniIntentClass, "(Ljava/lang/String;)V",
+ return QJniObject(JniIntentClass, "(Ljava/lang/String;)V",
ACTION_OPEN_DOCUMENT.object());
}
diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
index a7f9aaa3582..2d3cb49a96f 100644
--- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
+++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -41,11 +42,11 @@
#define QANDROIDPLATFORMFILEDIALOGHELPER_H
#include <jni.h>
+
#include <QEventLoop>
-#include <qpa/qplatformdialoghelper.h>
+#include <QtCore/QJniObject>
#include <QtCore/private/qjnihelpers_p.h>
-#include <private/qjni_p.h>
-#include <QEventLoop>
+#include <qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
@@ -73,8 +74,8 @@ public:
bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override;
private:
- QJNIObjectPrivate getFileDialogIntent(const QString &intentType);
- void takePersistableUriPermission(const QJNIObjectPrivate &uri);
+ QJniObject getFileDialogIntent(const QString &intentType);
+ void takePersistableUriPermission(const QJniObject &uri);
void setIntentTitle(const QString &title);
void setOpenableCategory();
void setAllowMultipleSelections(bool allowMultiple);
@@ -82,8 +83,8 @@ private:
QEventLoop m_eventLoop;
QList<QUrl> m_selectedFile;
- QJNIObjectPrivate m_intent;
- const QJNIObjectPrivate m_activity;
+ QJniObject m_intent;
+ const QJniObject m_activity;
};
}
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
index af1eee5499a..8e453958384 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -42,7 +42,8 @@
#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h"
-#include <QtCore/private/qjni_p.h>
+
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -61,7 +62,7 @@ public:
private:
int m_surfaceId;
- QJNIObjectPrivate m_view;
+ QJniObject m_view;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 8048bd6cff4..14683438317 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 BogDan Vatra <[email protected]>
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -39,35 +40,34 @@
#include "qandroidplatformintegration.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtGui/private/qguiapplication_p.h>
-#include <QGuiApplication>
-#include <QOpenGLContext>
-#include <QOffscreenSurface>
-#include <QtGui/private/qoffscreensurface_p.h>
-#include <QThread>
-
-#include <QtGui/private/qeglpbuffer_p.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformwindow.h>
-#include <qpa/qplatformoffscreensurface.h>
-
-#include "androidjnimain.h"
#include "androidjniaccessibility.h"
+#include "androidjnimain.h"
#include "qabstracteventdispatcher.h"
#include "qandroideventdispatcher.h"
-#include "qandroidplatformbackingstore.h"
#include "qandroidplatformaccessibility.h"
+#include "qandroidplatformbackingstore.h"
#include "qandroidplatformclipboard.h"
-#include "qandroidplatformforeignwindow.h"
#include "qandroidplatformfontdatabase.h"
+#include "qandroidplatformforeignwindow.h"
+#include "qandroidplatformoffscreensurface.h"
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformscreen.h"
#include "qandroidplatformservices.h"
#include "qandroidplatformtheme.h"
#include "qandroidsystemlocale.h"
-#include "qandroidplatformoffscreensurface.h"
+
+#include <QGuiApplication>
+#include <QOffscreenSurface>
+#include <QOpenGLContext>
+#include <QThread>
+#include <QtCore/QJniObject>
+#include <QtGui/private/qeglpbuffer_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qoffscreensurface_p.h>
+#include <qpa/qplatformoffscreensurface.h>
+#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
#include <jni.h>
@@ -200,17 +200,17 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
m_accessibility = new QAndroidPlatformAccessibility();
#endif // QT_NO_ACCESSIBILITY
- QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ QJniObject javaActivity(QtAndroid::activity());
if (!javaActivity.isValid())
javaActivity = QtAndroid::service();
if (javaActivity.isValid()) {
- QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
- QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
+ QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
+ QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
int touchScreen = configuration.getField<jint>("touchscreen");
- if (touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
- || touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
+ if (touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
+ || touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
{
m_touchDevice = new QPointingDevice;
m_touchDevice->setType(QInputDevice::DeviceType::TouchScreen);
@@ -219,16 +219,16 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
| QPointingDevice::Capability::Pressure
| QPointingDevice::Capability::NormalizedPosition);
- QJNIObjectPrivate pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
+ QJniObject pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
Q_ASSERT(pm.isValid());
if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND", "Ljava/lang/String;").object())) {
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND", "Ljava/lang/String;").object())) {
m_touchDevice->setMaximumTouchPoints(10);
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT", "Ljava/lang/String;").object())) {
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT", "Ljava/lang/String;").object())) {
m_touchDevice->setMaximumTouchPoints(4);
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
- QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH", "Ljava/lang/String;").object())) {
+ QJniObject::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH", "Ljava/lang/String;").object())) {
m_touchDevice->setMaximumTouchPoints(2);
}
QWindowSystemInterface::registerInputDevice(m_touchDevice);
@@ -236,11 +236,14 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
Q_ASSERT(contentResolver.isValid());
- QJNIObjectPrivate txtShowPassValue = QJNIObjectPrivate::callStaticObjectMethod("android/provider/Settings$System",
- "getString",
- "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
- contentResolver.object(),
- QJNIObjectPrivate::getStaticObjectField("android/provider/Settings$System", "TEXT_SHOW_PASSWORD", "Ljava/lang/String;").object());
+ QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
+ "android/provider/Settings$System",
+ "getString",
+ "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
+ contentResolver.object(),
+ QJniObject::getStaticObjectField("android/provider/Settings$System",
+ "TEXT_SHOW_PASSWORD",
+ "Ljava/lang/String;").object());
if (txtShowPassValue.isValid()) {
bool ok = false;
const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp
index 3431997a536..1ac836faf26 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 BogDan Vatra <[email protected]>
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -37,10 +38,12 @@
**
****************************************************************************/
+#include "androidjnimenu.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
-#include "androidjnimenu.h"
-#include <QtCore/private/qjni_p.h>
+
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
QT_BEGIN_NAMESPACE
@@ -152,7 +155,7 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t
Q_UNUSED(parentWindow);
Q_UNUSED(item);
setVisible(true);
- QtAndroidMenu::showContextMenu(this, targetRect, QJNIEnvironmentPrivate());
+ QtAndroidMenu::showContextMenu(this, targetRect, QJniEnvironment());
}
QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
index 333fc2a25f8..f69e9e389f6 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
@@ -40,20 +40,20 @@
#include "qandroidplatformopenglwindow.h"
-#include "qandroidplatformscreen.h"
+#include "androiddeadlockprotector.h"
#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidplatformscreen.h"
#include <QSurfaceFormat>
#include <QtGui/private/qwindow_p.h>
#include <QtGui/qguiapplication.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformscreen.h>
#include <QtGui/private/qeglconvenience_p.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@@ -175,9 +175,9 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
{
clearEgl();
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object());
- m_androidSurfaceObject = QJNIObjectPrivate();
+ m_androidSurfaceObject = QJniObject();
m_eglSurface = eglCreateWindowSurface(m_eglDisplay, config, m_nativeWindow, NULL);
m_format = q_glFormatFromConfig(m_eglDisplay, config, window()->requestedFormat());
if (Q_UNLIKELY(m_eglSurface == EGL_NO_SURFACE)) {
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
index d3072f766d5..b8f1a5f9fc8 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
@@ -41,13 +41,15 @@
#ifndef QANDROIDPLATFORMOPENGLWINDOW_H
#define QANDROIDPLATFORMOPENGLWINDOW_H
-#include <EGL/egl.h>
-#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
-
#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h"
+#include <QWaitCondition>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+
+#include <EGL/egl.h>
+
QT_BEGIN_NAMESPACE
class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient
@@ -77,7 +79,7 @@ private:
EGLNativeWindowType m_nativeWindow = nullptr;
int m_nativeSurfaceId = -1;
- QJNIObjectPrivate m_androidSurfaceObject;
+ QJniObject m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h
index 5dc158e351b..4cdb0351bdf 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.h
+++ b/src/plugins/platforms/android/qandroidplatformscreen.h
@@ -41,14 +41,14 @@
#ifndef QANDROIDPLATFORMSCREEN_H
#define QANDROIDPLATFORMSCREEN_H
-#include <qpa/qplatformscreen.h>
+#include "androidsurfaceclient.h"
+
#include <QList>
#include <QPainter>
#include <QTimer>
#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
-
-#include "androidsurfaceclient.h"
+#include <QtCore/QJniObject>
+#include <qpa/qplatformscreen.h>
#include <android/native_window.h>
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index c095613ce7c..b5f829d3d35 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -38,11 +38,12 @@
****************************************************************************/
#include "qandroidplatformservices.h"
-#include <QUrl>
-#include <QFile>
+
#include <QDebug>
+#include <QFile>
#include <QMimeDatabase>
-#include <QtCore/private/qjni_p.h>
+#include <QUrl>
+#include <QtCore/QJniObject>
#include <private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE
@@ -66,9 +67,9 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl)
mime = mimeDb.mimeTypeForUrl(url).name();
}
- QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString());
- QJNIObjectPrivate mimeString = QJNIObjectPrivate::fromString(mime);
- return QJNIObjectPrivate::callStaticMethod<jboolean>(
+ QJniObject urlString = QJniObject::fromString(url.toString());
+ QJniObject mimeString = QJniObject::fromString(mime);
+ return QJniObject::callStaticMethod<jboolean>(
QtAndroid::applicationClass(), "openURL",
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Z",
QtAndroidPrivate::context(), urlString.object(), mimeString.object());
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
index 6a1a51b2720..8f2a37626ac 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
@@ -37,15 +37,15 @@
**
****************************************************************************/
-#include "qandroidplatformvulkanwindow.h"
-#include "qandroidplatformscreen.h"
+#include "androiddeadlockprotector.h"
#include "androidjnimain.h"
#include "qandroideventdispatcher.h"
-#include "androiddeadlockprotector.h"
+#include "qandroidplatformscreen.h"
+#include "qandroidplatformvulkanwindow.h"
#include <QSurfaceFormat>
-#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
@@ -172,7 +172,7 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
return &m_vkSurface;
- QJNIEnvironmentPrivate env;
+ QJniEnvironment env;
m_nativeWindow = ANativeWindow_fromSurface(env, m_androidSurfaceObject.object());
VkAndroidSurfaceCreateInfoKHR surfaceInfo;
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
index 19eca987200..bc11f468d6c 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
@@ -46,13 +46,13 @@
#define VK_USE_PLATFORM_ANDROID_KHR
-#include <QWaitCondition>
-#include <QtCore/private/qjni_p.h>
-
#include "androidsurfaceclient.h"
+#include "qandroidplatformvulkaninstance.h"
#include "qandroidplatformwindow.h"
-#include "qandroidplatformvulkaninstance.h"
+#include <QWaitCondition>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -77,7 +77,7 @@ private:
int m_nativeSurfaceId;
ANativeWindow *m_nativeWindow;
- QJNIObjectPrivate m_androidSurfaceObject;
+ QJniObject m_androidSurfaceObject;
QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp
index bb6aa0dda1c..45387b53c70 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.cpp
+++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp
@@ -37,14 +37,15 @@
**
****************************************************************************/
-#include "qandroidsystemlocale.h"
#include "androidjnimain.h"
-#include <QtCore/private/qjni_p.h>
-#include <QtCore/private/qjnihelpers_p.h>
+#include "qandroidsystemlocale.h"
#include "qdatetime.h"
#include "qstringlist.h"
#include "qvariant.h"
+#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/QJniObject>
+
QT_BEGIN_NAMESPACE
QAndroidSystemLocale::QAndroidSystemLocale() : m_locale(QLocale::C)
@@ -55,17 +56,17 @@ void QAndroidSystemLocale::getLocaleFromJava() const
{
QWriteLocker locker(&m_lock);
- QJNIObjectPrivate javaLocaleObject;
- QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ QJniObject javaLocaleObject;
+ QJniObject javaActivity(QtAndroid::activity());
if (!javaActivity.isValid())
javaActivity = QtAndroid::service();
if (javaActivity.isValid()) {
- QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
- QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
+ QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
+ QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
javaLocaleObject = configuration.getObjectField("locale", "Ljava/util/Locale;");
} else {
- javaLocaleObject = QJNIObjectPrivate::callStaticObjectMethod("java/util/Locale", "getDefault", "()Ljava/util/Locale;");
+ javaLocaleObject = QJniObject::callStaticObjectMethod("java/util/Locale", "getDefault", "()Ljava/util/Locale;");
}
QString languageCode = javaLocaleObject.callObjectMethod("getLanguage", "()Ljava/lang/String;").toString();
@@ -165,9 +166,9 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen.");
case UILanguages: {
if (QtAndroidPrivate::androidSdkVersion() >= 24) {
- QJNIObjectPrivate localeListObject =
- QJNIObjectPrivate::callStaticObjectMethod("android/os/LocaleList", "getDefault",
- "()Landroid/os/LocaleList;");
+ QJniObject localeListObject =
+ QJniObject::callStaticObjectMethod("android/os/LocaleList", "getDefault",
+ "()Landroid/os/LocaleList;");
if (localeListObject.isValid()) {
QString lang = localeListObject.callObjectMethod("toLanguageTags",
"()Ljava/lang/String;").toString();
diff --git a/tests/auto/corelib/kernel/CMakeLists.txt b/tests/auto/corelib/kernel/CMakeLists.txt
index bb7a665c76c..33260707274 100644
--- a/tests/auto/corelib/kernel/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/CMakeLists.txt
@@ -45,3 +45,7 @@ endif()
if(QT_FEATURE_private_tests)
add_subdirectory(qproperty)
endif()
+if(ANDROID AND NOT ANDROID_EMBEDDED)
+ add_subdirectory(qjnienvironment)
+ add_subdirectory(qjniobject)
+endif()
diff --git a/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt b/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt
new file mode 100644
index 00000000000..b6c88ede331
--- /dev/null
+++ b/tests/auto/corelib/kernel/qjnienvironment/CMakeLists.txt
@@ -0,0 +1,8 @@
+#####################################################################
+## tst_qjnienvironment Test:
+#####################################################################
+
+qt_internal_add_test(tst_qjnienvironment
+ SOURCES
+ tst_qjnienvironment.cpp
+)
diff --git a/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp
new file mode 100644
index 00000000000..08cf0e48314
--- /dev/null
+++ b/tests/auto/corelib/kernel/qjnienvironment/tst_qjnienvironment.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QJniEnvironment>
+#include <QtTest/QtTest>
+
+class tst_QJniEnvironment : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void jniEnv();
+ void javaVM();
+};
+
+void tst_QJniEnvironment::jniEnv()
+{
+ QJniEnvironment env;
+ JavaVM *javaVM = env.javaVM();
+ QVERIFY(javaVM);
+
+ {
+ // JNI environment should now be attached to the current thread
+ JNIEnv *jni = 0;
+ QCOMPARE(javaVM->GetEnv((void**)&jni, JNI_VERSION_1_6), JNI_OK);
+
+ JNIEnv *e = env;
+ QVERIFY(e);
+
+ QCOMPARE(env->GetVersion(), JNI_VERSION_1_6);
+
+ // try to find an existing class
+ QVERIFY(env->FindClass("java/lang/Object"));
+ QVERIFY(!env->ExceptionCheck());
+
+ // try to find a nonexistent class
+ QVERIFY(!env->FindClass("this/doesnt/Exist"));
+ QVERIFY(env->ExceptionCheck());
+ env->ExceptionClear();
+
+ QVERIFY(env->FindClass("java/lang/Object"));
+ QVERIFY(!QJniEnvironment::exceptionCheckAndClear(env));
+
+ // try to find a nonexistent class
+ QVERIFY(!env->FindClass("this/doesnt/Exist"));
+ QVERIFY(QJniEnvironment::exceptionCheckAndClear(env));
+
+ // try to find an existing class with QJniEnvironment
+ QJniEnvironment env;
+ QVERIFY(env.findClass("java/lang/Object"));
+
+ // try to find a nonexistent class
+ QVERIFY(!env.findClass("this/doesnt/Exist"));
+
+ // clear exception with member function
+ QVERIFY(!env->FindClass("this/doesnt/Exist"));
+ QVERIFY(env.exceptionCheckAndClear());
+ }
+
+ // The env does not detach automatically, even if it goes out of scope. The only way it can
+ // be detached is if it's done explicitly, or if the thread we attached to gets killed (TLS clean-up).
+ JNIEnv *jni = nullptr;
+ QCOMPARE(javaVM->GetEnv((void**)&jni, JNI_VERSION_1_6), JNI_OK);
+}
+
+void tst_QJniEnvironment::javaVM()
+{
+ QJniEnvironment env;
+ JavaVM *javaVM = env.javaVM();
+ QVERIFY(javaVM);
+
+ QCOMPARE(env.javaVM(), javaVM);
+
+ JavaVM *vm = 0;
+ QCOMPARE(env->GetJavaVM(&vm), JNI_OK);
+ QCOMPARE(env.javaVM(), vm);
+}
+
+QTEST_MAIN(tst_QJniEnvironment)
+
+#include "tst_qjnienvironment.moc"
diff --git a/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt b/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt
new file mode 100644
index 00000000000..b0f5d0b6408
--- /dev/null
+++ b/tests/auto/corelib/kernel/qjniobject/CMakeLists.txt
@@ -0,0 +1,16 @@
+#####################################################################
+## tst_qjniobject Test:
+#####################################################################
+
+qt_internal_add_test(tst_qjniobject
+ SOURCES
+ tst_qjniobject.cpp
+)
+
+if(ANDROID)
+ set_property(TARGET tst_qjniobject APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/testdata
+ )
+ # QTBUG-88840 # special case
+ qt_android_generate_deployment_settings(tst_qjniobject) # special case
+endif()
diff --git a/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java
new file mode 100644
index 00000000000..4d6db749a56
--- /dev/null
+++ b/tests/auto/corelib/kernel/qjniobject/testdata/src/org/qtproject/qt/android/testdata/QtJniObjectTestClass.java
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+package org.qtproject.qt.android.testdatapackage;
+
+public class QtJniObjectTestClass
+{
+ static final byte A_BYTE_VALUE = 127;
+ static final short A_SHORT_VALUE = 32767;
+ static final int A_INT_VALUE = 060701;
+ static final long A_LONG_VALUE = 060701;
+ static final float A_FLOAT_VALUE = 1.0f;
+ static final double A_DOUBLE_VALUE = 1.0;
+ static final boolean A_BOOLEAN_VALUE = true;
+ static final char A_CHAR_VALUE = 'Q';
+ static final String A_STRING_OBJECT = "TEST_DATA_STRING";
+ static final Class A_CLASS_OBJECT = QtJniObjectTestClass.class;
+ static final Object A_OBJECT_OBJECT = new QtJniObjectTestClass();
+ static final Throwable A_THROWABLE_OBJECT = new Throwable(A_STRING_OBJECT);
+
+ // --------------------------------------------------------------------------------------------
+ public static void staticVoidMethod() { return; }
+ public static void staticVoidMethodWithArgs(int a, boolean b, char c) { return; }
+
+ public void voidMethod() { return; }
+ public void voidMethodWithArgs(int a, boolean b, char c) { return; }
+
+ // --------------------------------------------------------------------------------------------
+ public static boolean staticBooleanMethod() { return A_BOOLEAN_VALUE; }
+ public static boolean staticBooleanMethodWithArgs(boolean a, boolean b, boolean c)
+ { return staticBooleanMethod(); }
+
+ public boolean booleanMethod() { return staticBooleanMethod(); }
+ public boolean booleanMethodWithArgs(boolean a, boolean b, boolean c)
+ { return staticBooleanMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static byte staticByteMethod() { return A_BYTE_VALUE; }
+ public static byte staticByteMethodWithArgs(byte a, byte b, byte c) { return staticByteMethod(); }
+
+ public byte byteMethod() { return staticByteMethod(); }
+ public byte byteMethodWithArgs(byte a, byte b, byte c)
+ { return staticByteMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static char staticCharMethod() { return A_CHAR_VALUE; }
+ public static char staticCharMethodWithArgs(char a, char b, char c) { return staticCharMethod(); }
+
+ public char charMethod() { return staticCharMethod(); }
+ public char charMethodWithArgs(char a, char b, char c)
+ { return staticCharMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static short staticShortMethod() { return A_SHORT_VALUE; }
+ public static short staticShortMethodWithArgs(short a, short b, short c) { return staticShortMethod(); }
+
+ public short shortMethod() { return staticShortMethod(); }
+ public short shortMethodWithArgs(short a, short b, short c)
+ { return staticShortMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static int staticIntMethod() { return A_INT_VALUE; }
+ public static int staticIntMethodWithArgs(int a, int b, int c) { return staticIntMethod(); }
+
+ public int intMethod() { return staticIntMethod(); }
+ public int intMethodWithArgs(int a, int b, int c) { return staticIntMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static long staticLongMethod() { return A_LONG_VALUE; }
+ public static long staticLongMethodWithArgs(long a, long b, long c) { return staticLongMethod(); }
+
+ public long longMethod() { return staticLongMethod(); }
+ public long longMethodWithArgs(long a, long b, long c)
+ { return staticLongMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static float staticFloatMethod() { return A_FLOAT_VALUE; }
+ public static float staticFloatMethodWithArgs(float a, float b, float c) { return staticFloatMethod(); }
+
+ public float floatMethod() { return staticFloatMethod(); }
+ public float floatMethodWithArgs(float a, float b, float c)
+ { return staticFloatMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static double staticDoubleMethod() { return A_DOUBLE_VALUE; }
+ public static double staticDoubleMethodWithArgs(double a, double b, double c)
+ { return staticDoubleMethod(); }
+
+ public double doubleMethod() { return staticDoubleMethod(); }
+ public double doubleMethodWithArgs(double a, double b, double c)
+ { return staticDoubleMethodWithArgs(a, b, c); }
+
+ // --------------------------------------------------------------------------------------------
+ public static Object staticObjectMethod() { return A_OBJECT_OBJECT; }
+ public Object objectMethod() { return staticObjectMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static Class staticClassMethod() { return A_CLASS_OBJECT; }
+ public Class classMethod() { return staticClassMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static String staticStringMethod() { return A_STRING_OBJECT; }
+ public String stringMethod() { return staticStringMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static Throwable staticThrowableMethod() { return A_THROWABLE_OBJECT; }
+ public Throwable throwableMethod() { return staticThrowableMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static Object[] staticObjectArrayMethod()
+ { Object[] array = { new Object(), new Object(), new Object() }; return array; }
+ public Object[] objectArrayMethod() { return staticObjectArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static boolean[] staticBooleanArrayMethod()
+ { boolean[] array = { true, true, true }; return array; }
+ public boolean[] booleanArrayMethod() { return staticBooleanArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static byte[] staticByteArrayMethod()
+ { byte[] array = { 'a', 'b', 'c' }; return array; }
+ public byte[] byteArrayMethod() { return staticByteArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static char[] staticCharArrayMethod()
+ { char[] array = { 'a', 'b', 'c' }; return array; }
+ public char[] charArrayMethod() { return staticCharArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static short[] staticShortArrayMethod() { short[] array = { 3, 2, 1 }; return array; }
+ public short[] shortArrayMethod() { return staticShortArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static int[] staticIntArrayMethod() { int[] array = { 3, 2, 1 }; return array; }
+ public int[] intArrayMethod() { return staticIntArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static long[] staticLongArrayMethod()
+ { long[] array = { 3, 2, 1 }; return array; }
+ public long[] longArrayMethod() { return staticLongArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static float[] staticFloatArrayMethod()
+ { float[] array = { 1.0f, 2.0f, 3.0f }; return array; }
+ public float[] floatArrayMethod() { return staticFloatArrayMethod(); }
+
+ // --------------------------------------------------------------------------------------------
+ public static double[] staticDoubleArrayMethod()
+ { double[] array = { 3.0, 2.0, 1.0 }; return array; }
+ public double[] doubleArrayMethod() { return staticDoubleArrayMethod(); }
+}
+
diff --git a/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp
new file mode 100644
index 00000000000..96637a72a66
--- /dev/null
+++ b/tests/auto/corelib/kernel/qjniobject/tst_qjniobject.cpp
@@ -0,0 +1,1054 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <QtTest>
+
+static const char testClassName[] = "org/qtproject/qt/android/testdatapackage/QtJniObjectTestClass";
+
+static const jbyte A_BYTE_VALUE = 127;
+static const jshort A_SHORT_VALUE = 32767;
+static const jint A_INT_VALUE = 060701;
+static const jlong A_LONG_VALUE = 060701;
+static const jfloat A_FLOAT_VALUE = 1.0;
+static const jdouble A_DOUBLE_VALUE = 1.0;
+static const jchar A_CHAR_VALUE = 'Q';
+
+static QString A_STRING_OBJECT()
+{
+ return QStringLiteral("TEST_DATA_STRING");
+}
+
+class tst_QJniObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QJniObject();
+
+private slots:
+ void initTestCase();
+
+ void ctor();
+ void callMethodTest();
+ void callObjectMethodTest();
+ void stringConvertionTest();
+ void compareOperatorTests();
+ void callStaticObjectMethodClassName();
+ void callStaticObjectMethod();
+ void callStaticBooleanMethodClassName();
+ void callStaticBooleanMethod();
+ void callStaticCharMethodClassName();
+ void callStaticCharMethod();
+ void callStaticIntMethodClassName();
+ void callStaticIntMethod();
+ void callStaticByteMethodClassName();
+ void callStaticByteMethod();
+ void callStaticDoubleMethodClassName();
+ void callStaticDoubleMethod();
+ void callStaticFloatMethodClassName();
+ void callStaticFloatMethod();
+ void callStaticLongMethodClassName();
+ void callStaticLongMethod();
+ void callStaticShortMethodClassName();
+ void callStaticShortMethod();
+ void getStaticObjectFieldClassName();
+ void getStaticObjectField();
+ void getStaticIntFieldClassName();
+ void getStaticIntField();
+ void getStaticByteFieldClassName();
+ void getStaticByteField();
+ void getStaticLongFieldClassName();
+ void getStaticLongField();
+ void getStaticDoubleFieldClassName();
+ void getStaticDoubleField();
+ void getStaticFloatFieldClassName();
+ void getStaticFloatField();
+ void getStaticShortFieldClassName();
+ void getStaticShortField();
+ void getStaticCharFieldClassName();
+ void getStaticCharField();
+ void getBooleanField();
+ void getIntField();
+ void templateApiCheck();
+ void isClassAvailable();
+ void fromLocalRef();
+
+ void cleanupTestCase();
+};
+
+tst_QJniObject::tst_QJniObject()
+{
+}
+
+void tst_QJniObject::initTestCase()
+{
+}
+
+void tst_QJniObject::cleanupTestCase()
+{
+}
+
+void tst_QJniObject::ctor()
+{
+ {
+ QJniObject object;
+ QVERIFY(!object.isValid());
+ }
+
+ {
+ QJniObject object("java/lang/String");
+ QVERIFY(object.isValid());
+ }
+
+ {
+ QJniObject string = QJniObject::fromString(QLatin1String("Hello, Java"));
+ QJniObject object("java/lang/String", "(Ljava/lang/String;)V", string.object<jstring>());
+ QVERIFY(object.isValid());
+ QCOMPARE(string.toString(), object.toString());
+ }
+
+ {
+ QJniEnvironment env;
+ jclass javaStringClass = env->FindClass("java/lang/String");
+ QJniObject string(javaStringClass);
+ QVERIFY(string.isValid());
+ }
+
+ {
+ QJniEnvironment env;
+ const QString qString = QLatin1String("Hello, Java");
+ jclass javaStringClass = env->FindClass("java/lang/String");
+ QJniObject string = QJniObject::fromString(qString);
+ QJniObject stringCpy(javaStringClass, "(Ljava/lang/String;)V", string.object<jstring>());
+ QVERIFY(stringCpy.isValid());
+ QCOMPARE(qString, stringCpy.toString());
+ }
+}
+
+void tst_QJniObject::callMethodTest()
+{
+ {
+ QJniObject jString1 = QJniObject::fromString(QLatin1String("Hello, Java"));
+ QJniObject jString2 = QJniObject::fromString(QLatin1String("hELLO, jAVA"));
+ QVERIFY(jString1 != jString2);
+
+ const jboolean isEmpty = jString1.callMethod<jboolean>("isEmpty");
+ QVERIFY(!isEmpty);
+
+ const jint ret = jString1.callMethod<jint>("compareToIgnoreCase",
+ "(Ljava/lang/String;)I",
+ jString2.object<jstring>());
+ QVERIFY(0 == ret);
+ }
+
+ {
+ jlong jLong = 100;
+ QJniObject longObject("java/lang/Long", "(J)V", jLong);
+ jlong ret = longObject.callMethod<jlong>("longValue");
+ QCOMPARE(ret, jLong);
+ }
+}
+
+void tst_QJniObject::callObjectMethodTest()
+{
+ const QString qString = QLatin1String("Hello, Java");
+ QJniObject jString = QJniObject::fromString(qString);
+ const QString qStringRet = jString.callObjectMethod<jstring>("toUpperCase").toString();
+ QCOMPARE(qString.toUpper(), qStringRet);
+
+ QJniObject subString = jString.callObjectMethod("substring",
+ "(II)Ljava/lang/String;",
+ 0, 4);
+ QCOMPARE(subString.toString(), qString.mid(0, 4));
+}
+
+void tst_QJniObject::stringConvertionTest()
+{
+ const QString qString(QLatin1String("Hello, Java"));
+ QJniObject jString = QJniObject::fromString(qString);
+ QVERIFY(jString.isValid());
+ QString qStringRet = jString.toString();
+ QCOMPARE(qString, qStringRet);
+}
+
+void tst_QJniObject::compareOperatorTests()
+{
+ QString str("hello!");
+ QJniObject stringObject = QJniObject::fromString(str);
+
+ jobject obj = stringObject.object();
+ jobject jobj = stringObject.object<jobject>();
+ jstring jsobj = stringObject.object<jstring>();
+
+ QVERIFY(obj == stringObject);
+ QVERIFY(jobj == stringObject);
+ QVERIFY(stringObject == jobj);
+ QVERIFY(jsobj == stringObject);
+ QVERIFY(stringObject == jsobj);
+
+ QJniObject stringObject3 = stringObject.object<jstring>();
+ QVERIFY(stringObject3 == stringObject);
+
+ QJniObject stringObject2 = QJniObject::fromString(str);
+ QVERIFY(stringObject != stringObject2);
+
+ jstring jstrobj = 0;
+ QJniObject invalidStringObject;
+ QVERIFY(invalidStringObject == jstrobj);
+
+ QVERIFY(jstrobj != stringObject);
+ QVERIFY(stringObject != jstrobj);
+ QVERIFY(!invalidStringObject.isValid());
+}
+
+void tst_QJniObject::callStaticObjectMethodClassName()
+{
+ QJniObject formatString = QJniObject::fromString(QLatin1String("test format"));
+ QVERIFY(formatString.isValid());
+
+ QVERIFY(QJniObject::isClassAvailable("java/lang/String"));
+ QJniObject returnValue = QJniObject::callStaticObjectMethod("java/lang/String",
+ "format",
+ "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;",
+ formatString.object<jstring>(),
+ jobjectArray(0));
+ QVERIFY(returnValue.isValid());
+
+ QString returnedString = returnValue.toString();
+
+ QCOMPARE(returnedString, QString::fromLatin1("test format"));
+}
+
+void tst_QJniObject::callStaticObjectMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/String");
+ QVERIFY(cls != 0);
+
+ QJniObject formatString = QJniObject::fromString(QLatin1String("test format"));
+ QVERIFY(formatString.isValid());
+
+ QJniObject returnValue = QJniObject::callStaticObjectMethod(cls,
+ "format",
+ "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;",
+ formatString.object<jstring>(),
+ jobjectArray(0));
+ QVERIFY(returnValue.isValid());
+
+ QString returnedString = returnValue.toString();
+
+ QCOMPARE(returnedString, QString::fromLatin1("test format"));
+}
+
+void tst_QJniObject::callStaticBooleanMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Boolean");
+ QVERIFY(cls != 0);
+
+ {
+ QJniObject parameter = QJniObject::fromString("true");
+ QVERIFY(parameter.isValid());
+
+ jboolean b = QJniObject::callStaticMethod<jboolean>(cls,
+ "parseBoolean",
+ "(Ljava/lang/String;)Z",
+ parameter.object<jstring>());
+ QVERIFY(b);
+ }
+
+ {
+ QJniObject parameter = QJniObject::fromString("false");
+ QVERIFY(parameter.isValid());
+
+ jboolean b = QJniObject::callStaticMethod<jboolean>(cls,
+ "parseBoolean",
+ "(Ljava/lang/String;)Z",
+ parameter.object<jstring>());
+ QVERIFY(!b);
+ }
+}
+
+void tst_QJniObject::callStaticBooleanMethodClassName()
+{
+ {
+ QJniObject parameter = QJniObject::fromString("true");
+ QVERIFY(parameter.isValid());
+
+ jboolean b = QJniObject::callStaticMethod<jboolean>("java/lang/Boolean",
+ "parseBoolean",
+ "(Ljava/lang/String;)Z",
+ parameter.object<jstring>());
+ QVERIFY(b);
+ }
+
+ {
+ QJniObject parameter = QJniObject::fromString("false");
+ QVERIFY(parameter.isValid());
+
+ jboolean b = QJniObject::callStaticMethod<jboolean>("java/lang/Boolean",
+ "parseBoolean",
+ "(Ljava/lang/String;)Z",
+ parameter.object<jstring>());
+ QVERIFY(!b);
+ }
+}
+
+void tst_QJniObject::callStaticByteMethodClassName()
+{
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jbyte returnValue = QJniObject::callStaticMethod<jbyte>("java/lang/Byte",
+ "parseByte",
+ "(Ljava/lang/String;)B",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, jbyte(number.toInt()));
+}
+
+void tst_QJniObject::callStaticByteMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Byte");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jbyte returnValue = QJniObject::callStaticMethod<jbyte>(cls,
+ "parseByte",
+ "(Ljava/lang/String;)B",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, jbyte(number.toInt()));
+}
+
+void tst_QJniObject::callStaticIntMethodClassName()
+{
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jint returnValue = QJniObject::callStaticMethod<jint>("java/lang/Integer",
+ "parseInt",
+ "(Ljava/lang/String;)I",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toInt());
+}
+
+
+void tst_QJniObject::callStaticIntMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Integer");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jint returnValue = QJniObject::callStaticMethod<jint>(cls,
+ "parseInt",
+ "(Ljava/lang/String;)I",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toInt());
+}
+
+void tst_QJniObject::callStaticCharMethodClassName()
+{
+ jchar returnValue = QJniObject::callStaticMethod<jchar>("java/lang/Character",
+ "toUpperCase",
+ "(C)C",
+ jchar('a'));
+ QCOMPARE(returnValue, jchar('A'));
+}
+
+
+void tst_QJniObject::callStaticCharMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Character");
+ QVERIFY(cls != 0);
+
+ jchar returnValue = QJniObject::callStaticMethod<jchar>(cls,
+ "toUpperCase",
+ "(C)C",
+ jchar('a'));
+ QCOMPARE(returnValue, jchar('A'));
+}
+
+void tst_QJniObject::callStaticDoubleMethodClassName ()
+{
+ QString number = QString::number(123.45);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jdouble returnValue = QJniObject::callStaticMethod<jdouble>("java/lang/Double",
+ "parseDouble",
+ "(Ljava/lang/String;)D",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toDouble());
+}
+
+
+void tst_QJniObject::callStaticDoubleMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Double");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123.45);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jdouble returnValue = QJniObject::callStaticMethod<jdouble>(cls,
+ "parseDouble",
+ "(Ljava/lang/String;)D",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toDouble());
+}
+
+void tst_QJniObject::callStaticFloatMethodClassName()
+{
+ QString number = QString::number(123.45);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jfloat returnValue = QJniObject::callStaticMethod<jfloat>("java/lang/Float",
+ "parseFloat",
+ "(Ljava/lang/String;)F",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toFloat());
+}
+
+
+void tst_QJniObject::callStaticFloatMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Float");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123.45);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jfloat returnValue = QJniObject::callStaticMethod<jfloat>(cls,
+ "parseFloat",
+ "(Ljava/lang/String;)F",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toFloat());
+}
+
+void tst_QJniObject::callStaticShortMethodClassName()
+{
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jshort returnValue = QJniObject::callStaticMethod<jshort>("java/lang/Short",
+ "parseShort",
+ "(Ljava/lang/String;)S",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toShort());
+}
+
+
+void tst_QJniObject::callStaticShortMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Short");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jshort returnValue = QJniObject::callStaticMethod<jshort>(cls,
+ "parseShort",
+ "(Ljava/lang/String;)S",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, number.toShort());
+}
+
+void tst_QJniObject::callStaticLongMethodClassName()
+{
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jlong returnValue = QJniObject::callStaticMethod<jlong>("java/lang/Long",
+ "parseLong",
+ "(Ljava/lang/String;)J",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, jlong(number.toLong()));
+}
+
+void tst_QJniObject::callStaticLongMethod()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Long");
+ QVERIFY(cls != 0);
+
+ QString number = QString::number(123);
+ QJniObject parameter = QJniObject::fromString(number);
+
+ jlong returnValue = QJniObject::callStaticMethod<jlong>(cls,
+ "parseLong",
+ "(Ljava/lang/String;)J",
+ parameter.object<jstring>());
+ QCOMPARE(returnValue, jlong(number.toLong()));
+}
+
+void tst_QJniObject::getStaticObjectFieldClassName()
+{
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField<jobject>("java/lang/Boolean",
+ "FALSE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(!booleanValue);
+ }
+
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField<jobject>("java/lang/Boolean",
+ "TRUE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(booleanValue);
+ }
+
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField("java/lang/Boolean",
+ "FALSE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(!booleanValue);
+ }
+}
+
+void tst_QJniObject::getStaticObjectField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Boolean");
+ QVERIFY(cls != 0);
+
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField<jobject>(cls,
+ "FALSE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(!booleanValue);
+ }
+
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField<jobject>(cls,
+ "TRUE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(booleanValue);
+ }
+
+ {
+ QJniObject boolObject = QJniObject::getStaticObjectField(cls,
+ "FALSE",
+ "Ljava/lang/Boolean;");
+ QVERIFY(boolObject.isValid());
+
+ jboolean booleanValue = boolObject.callMethod<jboolean>("booleanValue");
+ QVERIFY(!booleanValue);
+ }
+}
+
+void tst_QJniObject::getStaticIntFieldClassName()
+{
+ jint i = QJniObject::getStaticField<jint>("java/lang/Double", "SIZE");
+ QCOMPARE(i, 64);
+}
+
+void tst_QJniObject::getStaticIntField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Double");
+ QVERIFY(cls != 0);
+
+ jint i = QJniObject::getStaticField<jint>(cls, "SIZE");
+ QCOMPARE(i, 64);
+}
+
+void tst_QJniObject::getStaticByteFieldClassName()
+{
+ jbyte i = QJniObject::getStaticField<jbyte>("java/lang/Byte", "MAX_VALUE");
+ QCOMPARE(i, jbyte(127));
+}
+
+void tst_QJniObject::getStaticByteField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Byte");
+ QVERIFY(cls != 0);
+
+ jbyte i = QJniObject::getStaticField<jbyte>(cls, "MAX_VALUE");
+ QCOMPARE(i, jbyte(127));
+}
+
+void tst_QJniObject::getStaticLongFieldClassName()
+{
+ jlong i = QJniObject::getStaticField<jlong>("java/lang/Long", "MAX_VALUE");
+ QCOMPARE(i, jlong(9223372036854775807L));
+}
+
+void tst_QJniObject::getStaticLongField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Long");
+ QVERIFY(cls != 0);
+
+ jlong i = QJniObject::getStaticField<jlong>(cls, "MAX_VALUE");
+ QCOMPARE(i, jlong(9223372036854775807L));
+}
+
+void tst_QJniObject::getStaticDoubleFieldClassName()
+{
+ jdouble i = QJniObject::getStaticField<jdouble>("java/lang/Double", "NaN");
+ jlong *k = reinterpret_cast<jlong*>(&i);
+ QCOMPARE(*k, jlong(0x7ff8000000000000L));
+}
+
+void tst_QJniObject::getStaticDoubleField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Double");
+ QVERIFY(cls != 0);
+
+ jdouble i = QJniObject::getStaticField<jdouble>(cls, "NaN");
+ jlong *k = reinterpret_cast<jlong*>(&i);
+ QCOMPARE(*k, jlong(0x7ff8000000000000L));
+}
+
+void tst_QJniObject::getStaticFloatFieldClassName()
+{
+ jfloat i = QJniObject::getStaticField<jfloat>("java/lang/Float", "NaN");
+ unsigned *k = reinterpret_cast<unsigned*>(&i);
+ QCOMPARE(*k, unsigned(0x7fc00000));
+}
+
+void tst_QJniObject::getStaticFloatField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Float");
+ QVERIFY(cls != 0);
+
+ jfloat i = QJniObject::getStaticField<jfloat>(cls, "NaN");
+ unsigned *k = reinterpret_cast<unsigned*>(&i);
+ QCOMPARE(*k, unsigned(0x7fc00000));
+}
+
+void tst_QJniObject::getStaticShortFieldClassName()
+{
+ jshort i = QJniObject::getStaticField<jshort>("java/lang/Short", "MAX_VALUE");
+ QCOMPARE(i, jshort(32767));
+}
+
+void tst_QJniObject::getStaticShortField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Short");
+ QVERIFY(cls != 0);
+
+ jshort i = QJniObject::getStaticField<jshort>(cls, "MAX_VALUE");
+ QCOMPARE(i, jshort(32767));
+}
+
+void tst_QJniObject::getStaticCharFieldClassName()
+{
+ jchar i = QJniObject::getStaticField<jchar>("java/lang/Character", "MAX_VALUE");
+ QCOMPARE(i, jchar(0xffff));
+}
+
+void tst_QJniObject::getStaticCharField()
+{
+ QJniEnvironment env;
+ jclass cls = env->FindClass("java/lang/Character");
+ QVERIFY(cls != 0);
+
+ jchar i = QJniObject::getStaticField<jchar>(cls, "MAX_VALUE");
+ QCOMPARE(i, jchar(0xffff));
+}
+
+
+void tst_QJniObject::getBooleanField()
+{
+ QJniObject obj("org/qtproject/qt/android/QtActivityDelegate");
+
+ QVERIFY(obj.isValid());
+ QVERIFY(!obj.getField<jboolean>("m_fullScreen"));
+}
+
+void tst_QJniObject::getIntField()
+{
+ QJniObject obj("org/qtproject/qt/android/QtActivityDelegate");
+
+ QVERIFY(obj.isValid());
+ jint res = obj.getField<jint>("m_currentRotation");
+ QCOMPARE(res, -1);
+}
+
+void tst_QJniObject::templateApiCheck()
+{
+ QJniObject testClass(testClassName);
+ QVERIFY(testClass.isValid());
+
+ // void ---------------------------------------------------------------------------------------
+ QJniObject::callStaticMethod<void>(testClassName, "staticVoidMethod");
+ QJniObject::callStaticMethod<void>(testClassName,
+ "staticVoidMethodWithArgs",
+ "(IZC)V",
+ 1,
+ true,
+ 'c');
+
+ testClass.callMethod<void>("voidMethod");
+ testClass.callMethod<void>("voidMethodWithArgs", "(IZC)V", 1, true, 'c');
+
+ // jboolean -----------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jboolean>(testClassName, "staticBooleanMethod"));
+ QVERIFY(QJniObject::callStaticMethod<jboolean>(testClassName,
+ "staticBooleanMethodWithArgs",
+ "(ZZZ)Z",
+ true,
+ true,
+ true));
+
+ QVERIFY(testClass.callMethod<jboolean>("booleanMethod"));
+ QVERIFY(testClass.callMethod<jboolean>("booleanMethodWithArgs",
+ "(ZZZ)Z",
+ true,
+ true,
+ true));
+
+ // jbyte --------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jbyte>(testClassName,
+ "staticByteMethod") == A_BYTE_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jbyte>(testClassName,
+ "staticByteMethodWithArgs",
+ "(BBB)B",
+ 1,
+ 1,
+ 1) == A_BYTE_VALUE);
+
+ QVERIFY(testClass.callMethod<jbyte>("byteMethod") == A_BYTE_VALUE);
+ QVERIFY(testClass.callMethod<jbyte>("byteMethodWithArgs", "(BBB)B", 1, 1, 1) == A_BYTE_VALUE);
+
+ // jchar --------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jchar>(testClassName,
+ "staticCharMethod") == A_CHAR_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jchar>(testClassName,
+ "staticCharMethodWithArgs",
+ "(CCC)C",
+ jchar(1),
+ jchar(1),
+ jchar(1)) == A_CHAR_VALUE);
+
+ QVERIFY(testClass.callMethod<jchar>("charMethod") == A_CHAR_VALUE);
+ QVERIFY(testClass.callMethod<jchar>("charMethodWithArgs",
+ "(CCC)C",
+ jchar(1),
+ jchar(1),
+ jchar(1)) == A_CHAR_VALUE);
+
+ // jshort -------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jshort>(testClassName,
+ "staticShortMethod") == A_SHORT_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jshort>(testClassName,
+ "staticShortMethodWithArgs",
+ "(SSS)S",
+ jshort(1),
+ jshort(1),
+ jshort(1)) == A_SHORT_VALUE);
+
+ QVERIFY(testClass.callMethod<jshort>("shortMethod") == A_SHORT_VALUE);
+ QVERIFY(testClass.callMethod<jshort>("shortMethodWithArgs",
+ "(SSS)S",
+ jshort(1),
+ jshort(1),
+ jshort(1)) == A_SHORT_VALUE);
+
+ // jint ---------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jint>(testClassName,
+ "staticIntMethod") == A_INT_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jint>(testClassName,
+ "staticIntMethodWithArgs",
+ "(III)I",
+ jint(1),
+ jint(1),
+ jint(1)) == A_INT_VALUE);
+
+ QVERIFY(testClass.callMethod<jint>("intMethod") == A_INT_VALUE);
+ QVERIFY(testClass.callMethod<jint>("intMethodWithArgs",
+ "(III)I",
+ jint(1),
+ jint(1),
+ jint(1)) == A_INT_VALUE);
+
+ // jlong --------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jlong>(testClassName,
+ "staticLongMethod") == A_LONG_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jlong>(testClassName,
+ "staticLongMethodWithArgs",
+ "(JJJ)J",
+ jlong(1),
+ jlong(1),
+ jlong(1)) == A_LONG_VALUE);
+
+ QVERIFY(testClass.callMethod<jlong>("longMethod") == A_LONG_VALUE);
+ QVERIFY(testClass.callMethod<jlong>("longMethodWithArgs",
+ "(JJJ)J",
+ jlong(1),
+ jlong(1),
+ jlong(1)) == A_LONG_VALUE);
+
+ // jfloat -------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jfloat>(testClassName,
+ "staticFloatMethod") == A_FLOAT_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jfloat>(testClassName,
+ "staticFloatMethodWithArgs",
+ "(FFF)F",
+ jfloat(1.1),
+ jfloat(1.1),
+ jfloat(1.1)) == A_FLOAT_VALUE);
+
+ QVERIFY(testClass.callMethod<jfloat>("floatMethod") == A_FLOAT_VALUE);
+ QVERIFY(testClass.callMethod<jfloat>("floatMethodWithArgs",
+ "(FFF)F",
+ jfloat(1.1),
+ jfloat(1.1),
+ jfloat(1.1)) == A_FLOAT_VALUE);
+
+ // jdouble ------------------------------------------------------------------------------------
+ QVERIFY(QJniObject::callStaticMethod<jdouble>(testClassName,
+ "staticDoubleMethod") == A_DOUBLE_VALUE);
+ QVERIFY(QJniObject::callStaticMethod<jdouble>(testClassName,
+ "staticDoubleMethodWithArgs",
+ "(DDD)D",
+ jdouble(1.1),
+ jdouble(1.1),
+ jdouble(1.1)) == A_DOUBLE_VALUE);
+
+ QVERIFY(testClass.callMethod<jdouble>("doubleMethod") == A_DOUBLE_VALUE);
+ QVERIFY(testClass.callMethod<jdouble>("doubleMethodWithArgs",
+ "(DDD)D",
+ jdouble(1.1),
+ jdouble(1.1),
+ jdouble(1.1)) == A_DOUBLE_VALUE);
+
+ // jobject ------------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jobject>(testClassName,
+ "staticObjectMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jobject>("objectMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jclass -------------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jclass>(testClassName,
+ "staticClassMethod");
+ QVERIFY(res.isValid());
+ QJniEnvironment env;
+ QVERIFY(env->IsInstanceOf(testClass.object(), res.object<jclass>()));
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jclass>("classMethod");
+ QVERIFY(res.isValid());
+ QJniEnvironment env;
+ QVERIFY(env->IsInstanceOf(testClass.object(), res.object<jclass>()));
+ }
+ // jstring ------------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jstring>(testClassName,
+ "staticStringMethod");
+ QVERIFY(res.isValid());
+ QVERIFY(res.toString() == A_STRING_OBJECT());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jstring>("stringMethod");
+ QVERIFY(res.isValid());
+ QVERIFY(res.toString() == A_STRING_OBJECT());
+
+ }
+ // jthrowable ---------------------------------------------------------------------------------
+ {
+ // The Throwable object the same message (see: "getMessage()") as A_STRING_OBJECT
+ QJniObject res = QJniObject::callStaticObjectMethod<jthrowable>(testClassName,
+ "staticThrowableMethod");
+ QVERIFY(res.isValid());
+ QVERIFY(res.callObjectMethod<jstring>("getMessage").toString() == A_STRING_OBJECT());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jthrowable>("throwableMethod");
+ QVERIFY(res.isValid());
+ QVERIFY(res.callObjectMethod<jstring>("getMessage").toString() == A_STRING_OBJECT());
+ }
+
+ // jobjectArray -------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jobjectArray>(testClassName,
+ "staticObjectArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jobjectArray>("objectArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jbooleanArray ------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jbooleanArray>(testClassName,
+ "staticBooleanArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jbooleanArray>("booleanArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jbyteArray ---------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jbyteArray>(testClassName,
+ "staticByteArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jbyteArray>("byteArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jcharArray ---------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jcharArray>(testClassName,
+ "staticCharArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jcharArray>("charArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jshortArray --------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jshortArray>(testClassName,
+ "staticShortArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jshortArray>("shortArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jintArray ----------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jintArray>(testClassName,
+ "staticIntArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jintArray>("intArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jlongArray ---------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jlongArray>(testClassName,
+ "staticLongArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jlongArray>("longArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jfloatArray --------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jfloatArray>(testClassName,
+ "staticFloatArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jfloatArray>("floatArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ // jdoubleArray -------------------------------------------------------------------------------
+ {
+ QJniObject res = QJniObject::callStaticObjectMethod<jdoubleArray>(testClassName,
+ "staticDoubleArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+ {
+ QJniObject res = testClass.callObjectMethod<jdoubleArray>("doubleArrayMethod");
+ QVERIFY(res.isValid());
+ }
+
+}
+
+void tst_QJniObject::isClassAvailable()
+{
+ QVERIFY(QJniObject::isClassAvailable("java/lang/String"));
+ QVERIFY(!QJniObject::isClassAvailable("class/not/Available"));
+ QVERIFY(QJniObject::isClassAvailable("org/qtproject/qt/android/QtActivityDelegate"));
+}
+
+void tst_QJniObject::fromLocalRef()
+{
+ const int limit = 512 + 1;
+ QJniEnvironment env;
+ for (int i = 0; i != limit; ++i)
+ QJniObject o = QJniObject::fromLocalRef(env->FindClass("java/lang/String"));
+}
+
+QTEST_MAIN(tst_QJniObject)
+
+#include "tst_qjniobject.moc"