Return specific types for frequently used Java objects
This allows us to specialize JNI type signature templates for e.g. the context object, which in Java signatures is "android/content/Context". Introduce a Q_DECLARE_JNI_TYPE macro that takes care of the plumbing. The types declared this way live in the QtJniTypes namespace, and transparently convert from and to jobject. Since jobject is a typedef to _jobject* we cannot create a subclass. Use a "Object" superclass that we can provide a QJniObject constructor for so that we don't require the QJniObject declaration to be able to use the macro. The APIs in the QNativeInterface namespace doesn't provide source or binary compatibility guarantees, so we can change the return types. Change-Id: I4cf9fa734ec9a5550b6fddeb14ef0ffd72663f29 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
f6e89e901b
commit
367092d7e0
@ -18,6 +18,7 @@
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_CLANG_QDOC)
|
||||
#include <QtCore/qjnitypes.h>
|
||||
#if QT_CONFIG(future) && !defined(QT_NO_QOBJECT)
|
||||
#include <QtCore/qfuture.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
@ -31,13 +32,21 @@ typedef _jobject* jobject;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
Q_DECLARE_JNI_TYPE(Context, "Landroid/content/Context;")
|
||||
#endif
|
||||
|
||||
namespace QNativeInterface
|
||||
{
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_CLANG_QDOC)
|
||||
struct Q_CORE_EXPORT QAndroidApplication
|
||||
{
|
||||
QT_DECLARE_NATIVE_INTERFACE(QAndroidApplication, 1, QCoreApplication)
|
||||
#ifdef Q_CLANG_QDOC
|
||||
static jobject context();
|
||||
#else
|
||||
static QtJniTypes::Context context();
|
||||
#endif
|
||||
static bool isActivityContext();
|
||||
static int sdkVersion();
|
||||
static void hideSplashScreen(int duration = 0);
|
||||
|
@ -289,18 +289,18 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
jobject QtAndroidPrivate::activity()
|
||||
QtJniTypes::Activity QtAndroidPrivate::activity()
|
||||
{
|
||||
QReadLocker locker(g_updateMutex());
|
||||
return g_jActivity;
|
||||
}
|
||||
|
||||
jobject QtAndroidPrivate::service()
|
||||
QtJniTypes::Service QtAndroidPrivate::service()
|
||||
{
|
||||
return g_jService;
|
||||
}
|
||||
|
||||
jobject QtAndroidPrivate::context()
|
||||
QtJniTypes::Context QtAndroidPrivate::context()
|
||||
{
|
||||
QReadLocker locker(g_updateMutex());
|
||||
if (g_jActivity)
|
||||
|
@ -18,9 +18,13 @@
|
||||
#include <jni.h>
|
||||
#include <functional>
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <QtCore/qcoreapplication_platform.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_JNI_TYPE(Activity, "Landroid/app/Activity;")
|
||||
Q_DECLARE_JNI_TYPE(Service, "Landroid/app/Service;")
|
||||
|
||||
namespace QtAndroidPrivate
|
||||
{
|
||||
class Q_CORE_EXPORT ActivityResultListener
|
||||
@ -66,9 +70,9 @@ namespace QtAndroidPrivate
|
||||
virtual jobject onBind(jobject intent) = 0;
|
||||
};
|
||||
|
||||
Q_CORE_EXPORT jobject activity();
|
||||
Q_CORE_EXPORT jobject service();
|
||||
Q_CORE_EXPORT jobject context();
|
||||
Q_CORE_EXPORT QtJniTypes::Activity activity();
|
||||
Q_CORE_EXPORT QtJniTypes::Service service();
|
||||
Q_CORE_EXPORT QtJniTypes::Context 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);
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
std::forward<Args>(args)...)
|
||||
{}
|
||||
QJniObject(jobject globalRef);
|
||||
inline QJniObject(QtJniTypes::Object wrapper) noexcept : QJniObject(jobject(wrapper)) {}
|
||||
~QJniObject();
|
||||
|
||||
jobject object() const;
|
||||
|
@ -227,7 +227,8 @@ static constexpr bool isObjectType()
|
||||
return true;
|
||||
} else {
|
||||
constexpr auto signature = typeSignature<T>();
|
||||
return signature.startsWith('L') && signature.endsWith(';');
|
||||
return (signature.startsWith('L') || signature.startsWith('['))
|
||||
&& signature.endsWith(';');
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,8 +274,35 @@ static constexpr auto constructorSignature()
|
||||
return methodSignature<void, Args...>();
|
||||
}
|
||||
|
||||
// A generic thin wrapper around jobject, convertible to jobject.
|
||||
// We need this as a baseclass so that QJniObject can be implicitly
|
||||
// constructed from the various subclasses - we can't provide an
|
||||
// operator QJniObject() here as the class is not declared.
|
||||
struct Object
|
||||
{
|
||||
jobject _object;
|
||||
constexpr operator jobject() const { return _object; }
|
||||
};
|
||||
|
||||
} // namespace QtJniTypes
|
||||
|
||||
#define Q_DECLARE_JNI_TYPE(Type, Signature) \
|
||||
namespace QtJniTypes { \
|
||||
struct Type : Object \
|
||||
{ \
|
||||
constexpr Type(jobject o) noexcept : Object{o} {} \
|
||||
}; \
|
||||
} \
|
||||
template<> \
|
||||
constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
|
||||
{ \
|
||||
static_assert((Signature[0] == 'L' || Signature[0] == '[') \
|
||||
&& Signature[sizeof(Signature) - 2] == ';', \
|
||||
"Type signature needs to start with 'L' or '['" \
|
||||
" and end with ';'"); \
|
||||
return QtJniTypes::String(Signature); \
|
||||
} \
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
@ -38,14 +38,14 @@ static QBasicMutex g_pendingRunnablesMutex;
|
||||
QT_DEFINE_NATIVE_INTERFACE(QAndroidApplication);
|
||||
|
||||
/*!
|
||||
\fn jobject QNativeInterface::QAndroidApplication::context()
|
||||
\fn jobject QNativeInterface::QAndroidApplication::context()
|
||||
|
||||
Returns the Android context as a \c jobject. The context is an \c Activity
|
||||
if the main activity object is valid. Otherwise, the context is a \c Service.
|
||||
|
||||
\since 6.2
|
||||
*/
|
||||
jobject QNativeInterface::QAndroidApplication::context()
|
||||
QtJniTypes::Context QNativeInterface::QAndroidApplication::context()
|
||||
{
|
||||
return QtAndroidPrivate::context();
|
||||
}
|
||||
|
@ -43,9 +43,9 @@ static jmethodID m_loadClassMethodID = nullptr;
|
||||
static AAssetManager *m_assetManager = nullptr;
|
||||
static jobject m_assets = nullptr;
|
||||
static jobject m_resourcesObj = nullptr;
|
||||
static jobject m_activityObject = nullptr;
|
||||
static QtJniTypes::Activity m_activityObject = nullptr;
|
||||
static jmethodID m_createSurfaceMethodID = nullptr;
|
||||
static jobject m_serviceObject = nullptr;
|
||||
static QtJniTypes::Service m_serviceObject = nullptr;
|
||||
static jmethodID m_setSurfaceGeometryMethodID = nullptr;
|
||||
static jmethodID m_destroySurfaceMethodID = nullptr;
|
||||
|
||||
@ -159,12 +159,12 @@ namespace QtAndroid
|
||||
return m_applicationClass;
|
||||
}
|
||||
|
||||
jobject activity()
|
||||
QtJniTypes::Activity activity()
|
||||
{
|
||||
return m_activityObject;
|
||||
}
|
||||
|
||||
jobject service()
|
||||
QtJniTypes::Service service()
|
||||
{
|
||||
return m_serviceObject;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <android/asset_manager.h>
|
||||
|
||||
#include <QImage>
|
||||
#include <private/qjnihelpers_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -49,8 +50,8 @@ namespace QtAndroid
|
||||
jobject assets();
|
||||
AAssetManager *assetManager();
|
||||
jclass applicationClass();
|
||||
jobject activity();
|
||||
jobject service();
|
||||
QtJniTypes::Activity activity();
|
||||
QtJniTypes::Service service();
|
||||
|
||||
// Keep synchronized with flags in ActivityDelegate.java
|
||||
enum SystemUiVisibility {
|
||||
|
@ -40,6 +40,11 @@ static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/a
|
||||
static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() != "Ljava/lang/Object;");
|
||||
static_assert(!(QtJniTypes::typeSignature<QtJavaWrapper>() == "X"));
|
||||
|
||||
Q_DECLARE_JNI_TYPE(JavaType, "Lorg/qtproject/qt/JavaType;");
|
||||
static_assert(QtJniTypes::typeSignature<QtJniTypes::JavaType>() == "Lorg/qtproject/qt/JavaType;");
|
||||
Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;")
|
||||
static_assert(QtJniTypes::typeSignature<QtJniTypes::ArrayType>() == "[Lorg/qtproject/qt/ArrayType;");
|
||||
|
||||
static_assert(QtJniTypes::fieldSignature<jint>() == "I");
|
||||
static_assert(QtJniTypes::fieldSignature<jint>() != "X");
|
||||
static_assert(QtJniTypes::fieldSignature<jint>() != "Ljava/lang/Object;");
|
||||
@ -57,6 +62,8 @@ static_assert(QtJniTypes::methodSignature<void, jint>() == "(I)V");
|
||||
static_assert(QtJniTypes::methodSignature<void, jint, jstring>() == "(ILjava/lang/String;)V");
|
||||
static_assert(QtJniTypes::methodSignature<jlong, jint, jclass>() == "(ILjava/lang/Class;)J");
|
||||
static_assert(QtJniTypes::methodSignature<jobject, jint, jstring>() == "(ILjava/lang/String;)Ljava/lang/Object;");
|
||||
static_assert(QtJniTypes::methodSignature<QtJniTypes::JavaType, jint, jstring>()
|
||||
== "(ILjava/lang/String;)Lorg/qtproject/qt/JavaType;");
|
||||
|
||||
static_assert(QtJniTypes::isPrimitiveType<jint>());
|
||||
static_assert(QtJniTypes::isPrimitiveType<void>());
|
||||
@ -66,6 +73,7 @@ static_assert(!QtJniTypes::isPrimitiveType<QtCustomJniObject>());
|
||||
static_assert(!QtJniTypes::isObjectType<jint>());
|
||||
static_assert(!QtJniTypes::isObjectType<void>());
|
||||
static_assert(QtJniTypes::isObjectType<jobject>());
|
||||
static_assert(QtJniTypes::isObjectType<jobjectArray>());
|
||||
static_assert(QtJniTypes::isObjectType<QtCustomJniObject>());
|
||||
|
||||
static_assert(QtJniTypes::String("ABCDE").startsWith("ABC"));
|
||||
@ -86,6 +94,7 @@ static_assert(!QtJniTypes::String("ABCDE").endsWith('F'));
|
||||
|
||||
void tst_QJniTypes::initTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QJniTypes)
|
||||
|
Loading…
x
Reference in New Issue
Block a user