File indexing completed on 2024-06-23 05:08:44
0001 /* 0002 SPDX-FileCopyrightText: 2019-2021 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #ifndef KANDROIDEXTRAS_JNIOBJECT_H 0008 #define KANDROIDEXTRAS_JNIOBJECT_H 0009 0010 #include "jnitypetraits.h" 0011 0012 namespace KAndroidExtras { 0013 0014 namespace java { namespace lang { struct String; } } 0015 0016 namespace Internal { struct FromHandleTag{}; } 0017 0018 namespace Jni { 0019 0020 template <typename T> class Object; 0021 0022 template <typename T> 0023 inline QJniObject handle(const T &wrapper) 0024 { 0025 return wrapper.jniHandle(); 0026 } 0027 0028 /** Convert an untyped JNI object handle to a typed wrapper. 0029 * This is essentially the JNI equivalent to a reinterpret_cast from a void*. 0030 * Only use this if you are sure @p handle has the correct type, otherwise 0031 * things will horribly go wrong. 0032 */ 0033 template <typename T> 0034 inline auto fromHandle(const QJniObject &handle) 0035 { 0036 if constexpr (Jni::is_object_wrapper<T>::value) { 0037 return T(handle, Internal::FromHandleTag()); 0038 } else { 0039 return Jni::Object<T>(handle); 0040 } 0041 } 0042 0043 template <typename T> 0044 inline auto fromHandle(jobject handle) 0045 { 0046 return fromHandle<T>(QJniObject(handle)); 0047 } 0048 0049 /** Wrapper for JNI objects with a convertible C++ type. 0050 * This provides implicit on-demand conversion to the C++ type, for types 0051 * that don't have a manually defined wrapper. 0052 */ 0053 template <typename T> 0054 class Object { 0055 private: 0056 template <typename DummyT> class _dummy_t {}; 0057 public: 0058 inline explicit Object(const QJniObject &v) : m_handle(v) {} 0059 0060 // implicit conversion from a compatible C++ type 0061 inline Object(const std::conditional_t<std::is_same_v<typename Jni::converter<T>::type, void>, 0062 _dummy_t<T>, typename Jni::converter<T>::type> &v) 0063 : m_handle(Jni::reverse_converter<T>::type::convert(v)) 0064 {} 0065 0066 // implicit conversion from a custom wrapper for the same type 0067 template <typename WrapperT, typename = std::enable_if_t<std::is_same_v<typename WrapperT::_jni_BaseType, T>, WrapperT>> 0068 inline Object(const WrapperT &w) 0069 : m_handle(Jni::handle(w)) 0070 {} 0071 0072 // special-case QString, as that often comes out of implicitly converted types, 0073 // and thus can't be consumed by another implicit conversion step 0074 template <typename StrT = QString, typename = std::enable_if_t<std::is_same_v<T, java::lang::String>, StrT>> 0075 inline Object(const QString &s) 0076 : m_handle(QJniObject::fromString(s)) 0077 {} 0078 0079 // special case for null values 0080 inline Object(std::nullptr_t) 0081 : m_handle((jobject)nullptr) 0082 {} 0083 0084 inline operator QJniObject() const { 0085 return m_handle; 0086 } 0087 inline operator typename Jni::converter<T>::type() const { 0088 return Jni::converter<T>::convert(m_handle); 0089 } 0090 0091 inline QJniObject jniHandle() const { 0092 return m_handle; 0093 } 0094 0095 // forward basic QJniObject API 0096 inline bool isValid() const { 0097 return m_handle.isValid(); 0098 } 0099 template <typename StrT = QString, typename = std::enable_if_t<std::is_same_v<T, java::lang::String>, StrT>> 0100 inline QString toString() const { 0101 return m_handle.toString(); 0102 } 0103 private: 0104 QJniObject m_handle; 0105 }; 0106 0107 /** Annotates a class for holding JNI method or property wrappers. 0108 * 0109 * Use this if the class only has static methods or constants. For methods 0110 * and properties, you either need to use @c JNI_OBJECT instead, or make 0111 * sure there is a @p jniHandle() method returning a @c QJniObject 0112 * representing the current instance. 0113 * 0114 * @param Class the name of the class this is added to. 0115 * @param BaseType the Java type this class represents, defined by the 0116 * @c JNI_TYPE or @c JNI_NESTED_TYPE macros. 0117 */ 0118 #define JNI_UNMANAGED_OBJECT(Class, BaseType) \ 0119 public: \ 0120 typedef Class _jni_ThisType; \ 0121 typedef BaseType _jni_BaseType; \ 0122 private: \ 0123 static inline constexpr const char *jniName() { return KAndroidExtras::Jni::typeName<BaseType>(); } \ 0124 friend constexpr const char* KAndroidExtras::Jni::typeName<Class>(); 0125 0126 /** Annotates a class for holding JNI method or property wrappers. 0127 * 0128 * @param Class the name of the class this is added to. 0129 * @param BaseType the Java type this class represents, defined by the 0130 * @c JNI_TYPE or @c JNI_NESTED_TYPE macros. 0131 */ 0132 #define JNI_OBJECT(Class, BaseType) \ 0133 JNI_UNMANAGED_OBJECT(Class, BaseType) \ 0134 private: \ 0135 QJniObject _m_jni_handle; \ 0136 inline QJniObject jniHandle() const { return _m_jni_handle; } \ 0137 inline void setJniHandle(const QJniObject &h) { _m_jni_handle = h; } \ 0138 friend QJniObject KAndroidExtras::Jni::handle<Class>(const Class&); \ 0139 friend auto KAndroidExtras::Jni::fromHandle<Class>(const QJniObject&); \ 0140 explicit inline Class(const QJniObject &handle, KAndroidExtras::Internal::FromHandleTag) : _m_jni_handle(handle) {} 0141 0142 } 0143 } 0144 0145 #endif