summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 66ea5eef79..31ba8272fc 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 0000000000..f3433134db
--- /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 139c8f3a30..c046b8078d 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 a9388a9795..b6ab4435a7 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 ca16566c1c..eb7acc5edf 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 3aa310e168..46f96e4037 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 d9a74c2828..781791c971 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 edca36e2bd..57ec8a39b5 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 0000000000..04676cc29c
--- /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 0000000000..e19a3935da
--- /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 14f9f389e8..45f4a4d895 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 c849013ba2..a0d9c219d7 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 0000000000..ba7d0af778
--- /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 0000000000..2998c7b4e8
--- /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 ec56d3de66..dbaee48ac6 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 da82832455..20f7f2df68 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 <dparsons@emerall.com>
** 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 d15d7ccfea..b6ae3764b1 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 1a6fe2b70e..a09593bf3c 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 deec1532a2..8d0c9a69ee 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 749ce136b6..149bc1139d 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 a4e88d84d4..62460f5e6d 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 c20ac456b1..597a56eb1a 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 5e4d271fcc..a72682dd23 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 559cdc6e57..bdd7f492ac 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** 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 fe5de1f882..9b49140335 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 c68dae31e9..bac3c3709e 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 6edddf4a66..2dbb1044f0 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 e39f17a26f..06947c9c32 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 9ce63dceec..334dd31d9a 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 694b4c7580..1953b842d5 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org>
+** 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 acfa4542a1..0b539d1af3 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 a7f9aaa358..2d3cb49a96 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 af1eee5499..8e45395838 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 8048bd6cff..1468343831 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** 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 3431997a53..1ac836faf2 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** 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 333fc2a25f..f69e9e389f 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 d3072f766d..b8f1a5f9fc 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 5dc158e351..4cdb0351bd 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 c095613ce7..b5f829d3d3 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 6a1a51b272..8f2a37626a 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 19eca98720..bc11f468d6 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 bb6aa0dda1..45387b53c7 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 bb7a665c76..3326070727 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 0000000000..b6c88ede33
--- /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 0000000000..08cf0e4831
--- /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 0000000000..b0f5d0b640
--- /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 0000000000..4d6db749a5
--- /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 0000000000..96637a72a6
--- /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"