From 124eaa6b2239e1eff8ddde7705c21499f8160a7a Mon Sep 17 00:00:00 2001 From: Petri Virkkunen Date: Mon, 4 Mar 2024 15:01:21 +0200 Subject: [PATCH] Android: Implement backend register class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This class will be used by java delegates to register their supported functionalities to the Qt/C++ side. It registers two native functions: register- and unregisterBackend, which will be used by the aforementioned delegates. It will be used by C++ classes which currently use QtAndroid::qtActivityDelegate() to access a JNI object which implements all these features in one big class. Task-number: QTBUG-118874 Change-Id: I23a7e433104c20b96c08b682a96cfaec98ecb4a9 Reviewed-by: Tinja Paavoseppä Reviewed-by: Assam Boudjelthia --- src/android/jar/CMakeLists.txt | 1 + .../qtproject/qt/android/BackendRegister.java | 9 +++ src/plugins/platforms/android/CMakeLists.txt | 1 + .../android/androidbackendregister.cpp | 52 ++++++++++++++ .../android/androidbackendregister.h | 67 +++++++++++++++++++ .../platforms/android/androidjnimain.cpp | 13 +++- .../platforms/android/androidjnimain.h | 2 + 7 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 src/android/jar/src/org/qtproject/qt/android/BackendRegister.java create mode 100644 src/plugins/platforms/android/androidbackendregister.cpp create mode 100644 src/plugins/platforms/android/androidbackendregister.h diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index c36bbdf75b..9d07e87a93 100644 --- a/src/android/jar/CMakeLists.txt +++ b/src/android/jar/CMakeLists.txt @@ -40,6 +40,7 @@ set(java_sources src/org/qtproject/qt/android/QtView.java src/org/qtproject/qt/android/QtEmbeddedViewInterface.java src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java + src/org/qtproject/qt/android/BackendRegister.java ) qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android diff --git a/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java b/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java new file mode 100644 index 0000000000..b66a593ec6 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java @@ -0,0 +1,9 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +package org.qtproject.qt.android; + +class BackendRegister +{ + static native void registerBackend(Class interfaceType, Object interfaceObject); + static native void unregisterBackend(Class interfaceType); +} diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt index 1e22a5c1cc..aaf62dd7e7 100644 --- a/src/plugins/platforms/android/CMakeLists.txt +++ b/src/plugins/platforms/android/CMakeLists.txt @@ -41,6 +41,7 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin qandroidplatformwindow.cpp qandroidplatformwindow.h qandroidsystemlocale.cpp qandroidsystemlocale.h androidwindowembedding.cpp androidwindowembedding.h + androidbackendregister.cpp androidbackendregister.h NO_UNITY_BUILD_SOURCES # Conflicting symbols and macros with androidjnimain.cpp # TODO: Unify the usage of FIND_AND_CHECK_CLASS, and similar diff --git a/src/plugins/platforms/android/androidbackendregister.cpp b/src/plugins/platforms/android/androidbackendregister.cpp new file mode 100644 index 0000000000..bfd86138aa --- /dev/null +++ b/src/plugins/platforms/android/androidbackendregister.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "androidbackendregister.h" + +#include "androidjnimain.h" + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcAndroidBackendRegister, "qt.qpa.androidbackendregister") + +Q_DECLARE_JNI_CLASS(BackendRegister, "org/qtproject/qt/android/BackendRegister"); + +bool AndroidBackendRegister::registerNatives() +{ + return QtJniTypes::BackendRegister::registerNativeMethods( + { Q_JNI_NATIVE_SCOPED_METHOD(registerBackend, AndroidBackendRegister), + Q_JNI_NATIVE_SCOPED_METHOD(unregisterBackend, AndroidBackendRegister) }); +} + +void AndroidBackendRegister::registerBackend(JNIEnv *, jclass, jclass interfaceClass, + jobject interface) +{ + if (AndroidBackendRegister *reg = QtAndroid::backendRegister()) { + const QJniObject classObject(static_cast(interfaceClass)); + QString name = classObject.callMethod("getName").toString(); + name.replace('.', '/'); + + QMutexLocker lock(®->m_registerMutex); + reg->m_register[name] = QJniObject(interface); + } else { + qCWarning(lcAndroidBackendRegister) + << "AndroidBackendRegister pointer is null, cannot register functionality"; + } +} + +void AndroidBackendRegister::unregisterBackend(JNIEnv *, jclass, jclass interfaceClass) +{ + if (AndroidBackendRegister *reg = QtAndroid::backendRegister()) { + const QJniObject classObject(static_cast(interfaceClass)); + QString name = classObject.callMethod("getName").toString(); + name.replace('.', '/'); + + QMutexLocker lock(®->m_registerMutex); + reg->m_register.remove(name); + } else { + qCWarning(lcAndroidBackendRegister) + << "AndroidBackendRegister pointer is null, cannot unregister functionality"; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/androidbackendregister.h b/src/plugins/platforms/android/androidbackendregister.h new file mode 100644 index 0000000000..c186f7e107 --- /dev/null +++ b/src/plugins/platforms/android/androidbackendregister.h @@ -0,0 +1,67 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef ANDROIDBACKENDREGISTER_H +#define ANDROIDBACKENDREGISTER_H + +#include + +#include +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcAndroidBackendRegister) + +template +using ValidInterfaceType = std::enable_if_t, bool>; + +class AndroidBackendRegister +{ +public: + static bool registerNatives(); + + template = true> + [[nodiscard]] T getInterface() + { + QMutexLocker lock(&m_registerMutex); + return m_register.value(QString(QtJniTypes::Traits::className().data())); + } + + template + using IsObjectType = + typename std::disjunction, + std::is_base_of>; + + template = true> + auto callInterface(const char *func, Args... args) + { + if (const auto obj = getInterface(); obj.isValid()) + return obj.template callMethod(func, std::forward(args)...); + + if constexpr (IsObjectType::value) + return Ret(QJniObject()); + if constexpr (!std::is_same_v) + return Ret{}; + } + +private: + QMutex m_registerMutex; + QMap m_register; + + static void registerBackend(JNIEnv *, jclass, jclass interfaceClass, jobject interface); + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(registerBackend) + static void unregisterBackend(JNIEnv *, jclass, jclass interfaceClass); + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(unregisterBackend) +}; + +QT_END_NAMESPACE + +#endif // ANDROIDBACKENDREGISTER_H diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 9fdcf3936b..b02b2a7d7c 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -85,7 +85,7 @@ static double m_density = 1.0; static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = nullptr; static AndroidContentFileEngineHandler *m_androidContentFileEngineHandler = nullptr; - +static AndroidBackendRegister *m_backendRegister = nullptr; static const char m_qtTag[] = "Qt"; static const char m_classErrorMsg[] = "Can't find class \"%s\""; @@ -387,6 +387,11 @@ namespace QtAndroid return m_assets; } + AndroidBackendRegister *backendRegister() + { + return m_backendRegister; + } + } // namespace QtAndroid static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString) @@ -397,6 +402,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler(); m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler(); m_mainLibraryHnd = nullptr; + m_backendRegister = new AndroidBackendRegister(); const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString()); @@ -544,6 +550,8 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) m_androidPlatformIntegration = nullptr; delete m_androidAssetsFileEngineHandler; m_androidAssetsFileEngineHandler = nullptr; + delete m_backendRegister; + m_backendRegister = nullptr; sem_post(&m_exitSemaphore); } @@ -891,7 +899,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) || !QtAndroidDialogHelpers::registerNatives(env) || !QAndroidPlatformClipboard::registerNatives(env) || !QAndroidPlatformWindow::registerNatives(env) - || !QtAndroidWindowEmbedding::registerNatives(env)) { + || !QtAndroidWindowEmbedding::registerNatives(env) + || !AndroidBackendRegister::registerNatives()) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 99fff96d2b..755b69ad72 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -13,6 +13,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -33,6 +34,7 @@ namespace QtAndroid { QBasicMutex *platformInterfaceMutex(); QAndroidPlatformIntegration *androidPlatformIntegration(); + AndroidBackendRegister *backendRegister(); void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); void setQtThread(QThread *thread); void setViewVisibility(jobject view, bool visible);