Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjniobject.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJNIOBJECT_H
5#define QJNIOBJECT_H
6
7#include <QtCore/qsharedpointer.h>
8
9#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
10#include <jni.h>
11#include <QtCore/qjnienvironment.h>
12#include <QtCore/qxptype_traits.h>
13
14QT_BEGIN_NAMESPACE
15
16class QJniObjectPrivate;
17class QJniObject;
18
19namespace QtJniTypes
20{
21namespace Detail
22{
23// any type with an "jobject object()" member function stores a global reference
24template <typename T, typename = void> struct StoresGlobalRefTest : std::false_type {};
25template <typename T>
26struct StoresGlobalRefTest<T, std::void_t<decltype(std::declval<T>().object())>>
27 : std::is_same<decltype(std::declval<T>().object()), jobject>
28{};
29
30template <typename ...Args>
31struct LocalFrame {
32 mutable JNIEnv *env;
33 bool hasFrame = false;
34 explicit LocalFrame(JNIEnv *env = nullptr) noexcept
35 : env(env)
36 {
37 }
38 ~LocalFrame()
39 {
40 if (hasFrame)
41 env->PopLocalFrame(nullptr);
42 }
43 bool ensureFrame()
44 {
45 if (!hasFrame)
46 hasFrame = jniEnv()->PushLocalFrame(sizeof...(Args)) == 0;
47 return hasFrame;
48 }
49 JNIEnv *jniEnv() const
50 {
51 if (!env)
52 env = QJniEnvironment::getJniEnv();
53 return env;
54 }
55 bool checkAndClearExceptions()
56 {
57 return env ? QJniEnvironment::checkAndClearExceptions(env) : false;
58 }
59 template <typename T>
60 auto convertToJni(T &&value)
61 {
62 using Type = q20::remove_cvref_t<T>;
63 using ResultType = decltype(QtJniTypes::Traits<Type>::convertToJni(jniEnv(),
64 std::declval<T&&>()));
65 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>,
66 std::remove_pointer_t<ResultType>>) {
67 // Make sure the local frame is engaged if we create a jobject, unless
68 // we know that the value stores a global reference that it returns.
69 if constexpr (!qxp::is_detected_v<StoresGlobalRefTest, Type>) {
70 if (!ensureFrame())
71 return ResultType{};
72 }
73 }
74 return QtJniTypes::Traits<Type>::convertToJni(jniEnv(), std::forward<T>(value));
75 }
76 template <typename T>
77 auto convertFromJni(QJniObject &&object)
78 {
79 using Type = q20::remove_cvref_t<T>;
80 return QtJniTypes::Traits<Type>::convertFromJni(std::move(object));
81 }
82};
83}
84}
85
86class Q_CORE_EXPORT QJniObject
87{
88 template <typename ...Args> using LocalFrame = QtJniTypes::Detail::LocalFrame<Args...>;
89
90public:
91 QJniObject();
92 explicit QJniObject(const char *className);
93 explicit QJniObject(const char *className, const char *signature, ...);
94 template<typename ...Args
95#ifndef Q_QDOC
96 , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr
97#endif
98 >
99 explicit QJniObject(const char *className, Args &&...args)
100 : QJniObject(LocalFrame<Args...>{}, className, std::forward<Args>(args)...)
101 {
102 }
103private:
104 template<typename ...Args>
105 explicit QJniObject(LocalFrame<Args...> localFrame, const char *className, Args &&...args)
106 : QJniObject(className, QtJniTypes::constructorSignature<Args...>().data(),
107 localFrame.convertToJni(std::forward<Args>(args))...)
108 {
109 }
110public:
111 explicit QJniObject(jclass clazz);
112 explicit QJniObject(jclass clazz, const char *signature, ...);
113 template<typename ...Args
114#ifndef Q_QDOC
115 , std::enable_if_t<!std::disjunction_v<QtJniTypes::IsStringType<std::decay_t<Args>>...>>* = nullptr
116#endif
117 >
118 explicit QJniObject(jclass clazz, Args &&...args)
119 : QJniObject(clazz, QtJniTypes::constructorSignature<Args...>().data(),
120 std::forward<Args>(args)...)
121 {}
122 QJniObject(jobject globalRef);
123
124 QJniObject(const QJniObject &other) noexcept = default;
125 QJniObject(QJniObject &&other) noexcept = default;
126 QJniObject &operator=(const QJniObject &other) noexcept = default;
127 QJniObject &operator=(QJniObject &&other) noexcept = default;
128
129 ~QJniObject();
130
131 void swap(QJniObject &other) noexcept { d.swap(other.d); }
132
133 template<typename Class, typename ...Args>
134 static inline QJniObject construct(Args &&...args)
135 {
136 LocalFrame<Args...> frame;
137 return QJniObject(QtJniTypes::Traits<Class>::className().data(),
138 QtJniTypes::constructorSignature<Args...>().data(),
139 frame.convertToJni(std::forward<Args>(args))...);
140 }
141
142 jobject object() const;
143 template <typename T> T object() const
144 {
145 QtJniTypes::assertObjectType<T>();
146 return static_cast<T>(javaObject());
147 }
148
149 jclass objectClass() const;
150 QByteArray className() const;
151
152 template <typename Ret = void, typename ...Args
153#ifndef Q_QDOC
154 , QtJniTypes::IfValidFieldType<Ret> = true
155#endif
156 >
157 auto callMethod(const char *methodName, const char *signature, Args &&...args) const
158 {
159 LocalFrame<Args...> frame(jniEnv());
160 if constexpr (QtJniTypes::isObjectType<Ret>()) {
161 return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature,
162 frame.convertToJni(std::forward<Args>(args))...));
163 } else {
164 jmethodID id = getCachedMethodID(frame.jniEnv(), methodName, signature);
165 if (id) {
166 if constexpr (std::is_same_v<Ret, void>) {
167 callVoidMethodV(frame.jniEnv(), id,
168 frame.convertToJni(std::forward<Args>(args))...);
169 frame.checkAndClearExceptions();
170 } else {
171 Ret res{};
172 callMethodForType<Ret>(frame.jniEnv(), res, object(), id,
173 frame.convertToJni(std::forward<Args>(args))...);
174 if (frame.checkAndClearExceptions())
175 res = {};
176 return res;
177 }
178 }
179 if constexpr (!std::is_same_v<Ret, void>)
180 return Ret{};
181 }
182 }
183
184 template <typename Ret = void, typename ...Args
185#ifndef Q_QDOC
186 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
187#endif
188 >
189 auto callMethod(const char *methodName, Args &&...args) const
190 {
191 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
192 return callMethod<Ret>(methodName, signature.data(), std::forward<Args>(args)...);
193 }
194
195 template <typename Ret, typename ...Args
196#ifndef Q_QDOC
197 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
198#endif
199 >
200 QJniObject callObjectMethod(const char *methodName, Args &&...args) const
201 {
202 QtJniTypes::assertObjectType<Ret>();
203 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
204 LocalFrame<Args...> frame(jniEnv());
205 return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature,
206 frame.convertToJni(std::forward<Args>(args))...));
207 }
208
209 QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const;
210
211 template <typename Ret = void, typename ...Args>
212 static auto callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args)
213 {
214 JNIEnv *env = QJniEnvironment::getJniEnv();
215 jclass clazz = QJniObject::loadClass(className, env);
216 return callStaticMethod<Ret>(clazz, methodName, signature, std::forward<Args>(args)...);
217 }
218
219 template <typename Ret = void, typename ...Args>
220 static auto callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args)
221 {
222 JNIEnv *env = QJniEnvironment::getJniEnv();
223 jmethodID id = clazz ? getMethodID(env, clazz, methodName, signature, true)
224 : 0;
225 return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
226 }
227
228 template <typename Ret = void, typename ...Args
229#ifndef Q_QDOC
230 , QtJniTypes::IfValidFieldType<Ret> = true
231#endif
232 >
233 static auto callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args)
234 {
235 LocalFrame<Args...> frame;
236 if constexpr (QtJniTypes::isObjectType<Ret>()) {
237 return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodId,
238 frame.convertToJni(std::forward<Args>(args))...));
239 } else {
240 if (clazz && methodId) {
241 if constexpr (std::is_same_v<Ret, void>) {
242 callStaticMethodForVoid(frame.jniEnv(), clazz, methodId,
243 frame.convertToJni(std::forward<Args>(args))...);
244 frame.checkAndClearExceptions();
245 } else {
246 Ret res{};
247 callStaticMethodForType<Ret>(frame.jniEnv(), res, clazz, methodId,
248 frame.convertToJni(std::forward<Args>(args))...);
249 if (frame.checkAndClearExceptions())
250 res = {};
251 return res;
252 }
253 }
254 if constexpr (!std::is_same_v<Ret, void>)
255 return Ret{};
256 }
257 }
258
259 template <typename Ret = void, typename ...Args
260#ifndef Q_QDOC
261 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
262#endif
263 >
264 static auto callStaticMethod(const char *className, const char *methodName, Args &&...args)
265 {
266 JNIEnv *env = QJniEnvironment::getJniEnv();
267 jclass clazz = QJniObject::loadClass(className, env);
268 const jmethodID id = clazz ? getMethodID(env, clazz, methodName,
269 QtJniTypes::methodSignature<Ret, Args...>().data(), true)
270 : 0;
271 return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
272 }
273
274 template <typename Ret = void, typename ...Args
275#ifndef Q_QDOC
276 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
277#endif
278 >
279 static auto callStaticMethod(jclass clazz, const char *methodName, Args &&...args)
280 {
281 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
282 return callStaticMethod<Ret>(clazz, methodName, signature.data(), std::forward<Args>(args)...);
283 }
284 template <typename Klass, typename Ret = void, typename ...Args
285#ifndef Q_QDOC
286 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
287#endif
288 >
289 static auto callStaticMethod(const char *methodName, Args &&...args)
290 {
291 JNIEnv *env = QJniEnvironment::getJniEnv();
292 const jclass clazz = QJniObject::loadClass(QtJniTypes::Traits<Klass>::className().data(),
293 env);
294 const jmethodID id = clazz ? getMethodID(env, clazz, methodName,
295 QtJniTypes::methodSignature<Ret, Args...>().data(), true)
296 : 0;
297 return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
298 }
299
300 static QJniObject callStaticObjectMethod(const char *className, const char *methodName,
301 const char *signature, ...);
302
303 static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName,
304 const char *signature, ...);
305
306 static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...);
307
308
309 template <typename Ret, typename ...Args
310#ifndef Q_QDOC
311 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
312#endif
313 >
314 static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args)
315 {
316 QtJniTypes::assertObjectType<Ret>();
317 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
318 LocalFrame<Args...> frame;
319 return frame.template convertFromJni<Ret>(callStaticObjectMethod(className, methodName, signature.data(),
320 frame.convertToJni(std::forward<Args>(args))...));
321 }
322
323 template <typename Ret, typename ...Args
324#ifndef Q_QDOC
325 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
326#endif
327 >
328 static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args)
329 {
330 QtJniTypes::assertObjectType<Ret>();
331 constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
332 LocalFrame<Args...> frame;
333 return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodName, signature.data(),
334 frame.convertToJni(std::forward<Args>(args))...));
335 }
336
337 template <typename T
338#ifndef Q_QDOC
339 , QtJniTypes::IfValidFieldType<T> = true
340#endif
341 >
342 auto getField(const char *fieldName) const
343 {
344 LocalFrame<T> frame(jniEnv());
345 if constexpr (QtJniTypes::isObjectType<T>()) {
346 return frame.template convertFromJni<T>(getObjectField<T>(fieldName));
347 } else {
348 T res{};
349 constexpr auto signature = QtJniTypes::fieldSignature<T>();
350 jfieldID id = getCachedFieldID(frame.jniEnv(), fieldName, signature);
351 if (id) {
352 getFieldForType<T>(frame.jniEnv(), res, object(), id);
353 if (frame.checkAndClearExceptions())
354 res = {};
355 }
356 return res;
357 }
358 }
359
360 template <typename T
361#ifndef Q_QDOC
362 , QtJniTypes::IfValidFieldType<T> = true
363#endif
364 >
365 static auto getStaticField(const char *className, const char *fieldName)
366 {
367 LocalFrame<T> frame;
368 if constexpr (QtJniTypes::isObjectType<T>()) {
369 return frame.template convertFromJni<T>(getStaticObjectField<T>(className, fieldName));
370 } else {
371 jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
372 if (!clazz)
373 return T{};
374 return getStaticField<T>(clazz, fieldName);
375 }
376 }
377
378 template <typename T
379#ifndef Q_QDOC
380 , QtJniTypes::IfValidFieldType<T> = true
381#endif
382 >
383 static auto getStaticField(jclass clazz, const char *fieldName)
384 {
385 LocalFrame<T> frame;
386 if constexpr (QtJniTypes::isObjectType<T>()) {
387 return frame.template convertFromJni<T>(getStaticObjectField<T>(clazz, fieldName));
388 } else {
389 T res{};
390 constexpr auto signature = QtJniTypes::fieldSignature<T>();
391 jfieldID id = getFieldID(frame.jniEnv(), clazz, fieldName, signature, true);
392 if (id) {
393 getStaticFieldForType<T>(frame.jniEnv(), res, clazz, id);
394 if (frame.checkAndClearExceptions())
395 res = {};
396 }
397 return res;
398 }
399 }
400
401 template <typename Klass, typename T
402#ifndef Q_QDOC
403 , QtJniTypes::IfValidFieldType<T> = true
404#endif
405 >
406 static auto getStaticField(const char *fieldName)
407 {
408 return getStaticField<T>(QtJniTypes::Traits<Klass>::className(), fieldName);
409 }
410
411 template <typename T
412#ifndef Q_QDOC
413 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
414#endif
415 >
416 QJniObject getObjectField(const char *fieldName) const
417 {
418 constexpr auto signature = QtJniTypes::fieldSignature<T>();
419 return getObjectField(fieldName, signature);
420 }
421
422 QJniObject getObjectField(const char *fieldName, const char *signature) const;
423
424 template <typename T
425#ifndef Q_QDOC
426 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
427#endif
428 >
429 static QJniObject getStaticObjectField(const char *className, const char *fieldName)
430 {
431 constexpr auto signature = QtJniTypes::fieldSignature<T>();
432 return getStaticObjectField(className, fieldName, signature);
433 }
434
435 static QJniObject getStaticObjectField(const char *className,
436 const char *fieldName,
437 const char *signature);
438
439 template <typename T
440#ifndef Q_QDOC
441 , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
442#endif
443 >
444 static QJniObject getStaticObjectField(jclass clazz, const char *fieldName)
445 {
446 constexpr auto signature = QtJniTypes::fieldSignature<T>();
447 return getStaticObjectField(clazz, fieldName, signature);
448 }
449
450 static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
451 const char *signature);
452
453 template <typename T
454#ifndef Q_QDOC
455 , QtJniTypes::IfValidFieldType<T> = true
456#endif
457 >
458 void setField(const char *fieldName, T value)
459 {
460 constexpr auto signature = QtJniTypes::fieldSignature<T>();
461 jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
462 if (id) {
463 setFieldForType<T>(jniEnv(), object(), id, value);
464 QJniEnvironment::checkAndClearExceptions(jniEnv());
465 }
466 }
467
468 template <typename T
469#ifndef Q_QDOC
470 , QtJniTypes::IfValidFieldType<T> = true
471#endif
472 >
473 void setField(const char *fieldName, const char *signature, T value)
474 {
475 jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
476 if (id) {
477 setFieldForType<T>(jniEnv(), object(), id, value);
478 QJniEnvironment::checkAndClearExceptions(jniEnv());
479 }
480 }
481
482 template <typename T
483#ifndef Q_QDOC
484 , QtJniTypes::IfValidFieldType<T> = true
485#endif
486 >
487 static void setStaticField(const char *className, const char *fieldName, T value)
488 {
489 LocalFrame<T> frame;
490 jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
491 if (!clazz)
492 return;
493
494 constexpr auto signature = QtJniTypes::fieldSignature<T>();
495 jfieldID id = getCachedFieldID(frame.jniEnv(), clazz, className, fieldName,
496 signature, true);
497 if (!id)
498 return;
499
500 setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value);
501 frame.checkAndClearExceptions();
502 }
503
504 template <typename T
505#ifndef Q_QDOC
506 , QtJniTypes::IfValidFieldType<T> = true
507#endif
508 >
509 static void setStaticField(const char *className, const char *fieldName,
510 const char *signature, T value)
511 {
512 JNIEnv *env = QJniEnvironment::getJniEnv();
513 jclass clazz = QJniObject::loadClass(className, env);
514
515 if (!clazz)
516 return;
517
518 jfieldID id = getCachedFieldID(env, clazz, className, fieldName,
519 signature, true);
520 if (id) {
521 setStaticFieldForType<T>(env, clazz, id, value);
522 QJniEnvironment::checkAndClearExceptions(env);
523 }
524 }
525
526 template <typename T
527#ifndef Q_QDOC
528 , QtJniTypes::IfValidFieldType<T> = true
529#endif
530 >
531 static void setStaticField(jclass clazz, const char *fieldName,
532 const char *signature, T value)
533 {
534 JNIEnv *env = QJniEnvironment::getJniEnv();
535 jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
536
537 if (id) {
538 setStaticFieldForType<T>(env, clazz, id, value);
539 QJniEnvironment::checkAndClearExceptions(env);
540 }
541 }
542
543 template <typename T
544#ifndef Q_QDOC
545 , QtJniTypes::IfValidFieldType<T> = true
546#endif
547 >
548 static void setStaticField(jclass clazz, const char *fieldName, T value)
549 {
550 setStaticField(clazz, fieldName, QtJniTypes::fieldSignature<T>(), value);
551 }
552
553 template <typename Klass, typename T
554#ifndef Q_QDOC
555 , QtJniTypes::IfValidFieldType<T> = true
556#endif
557 >
558 static void setStaticField(const char *fieldName, T value)
559 {
560 setStaticField(QtJniTypes::Traits<Klass>::className(), fieldName, value);
561 }
562
563 static QJniObject fromString(const QString &string);
564 QString toString() const;
565
566 static bool isClassAvailable(const char *className);
567 bool isValid() const;
568
569 // This function takes ownership of the jobject and releases the local ref. before returning.
570 static QJniObject fromLocalRef(jobject lref);
571
572 template <typename T,
573 std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true>
574 QJniObject &operator=(T obj)
575 {
576 assign(static_cast<T>(obj));
577 return *this;
578 }
579
580protected:
581 QJniObject(Qt::Initialization) {}
582 JNIEnv *jniEnv() const noexcept;
583
584private:
585 static jclass loadClass(const QByteArray &className, JNIEnv *env);
586
587#if QT_CORE_REMOVED_SINCE(6, 7)
588 // these need to stay in the ABI as they were used in inline methods before 6.7
589 static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded);
590 static QByteArray toBinaryEncClassName(const QByteArray &className);
591 void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const;
592#endif
593
594 static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className,
595 const char *name, const char *signature,
596 bool isStatic = false);
597 jfieldID getCachedFieldID(JNIEnv *env, const char *name, const char *signature,
598 bool isStatic = false) const;
599 static jmethodID getCachedMethodID(JNIEnv *env, jclass clazz, const QByteArray &className,
600 const char *name, const char *signature,
601 bool isStatic = false);
602 jmethodID getCachedMethodID(JNIEnv *env, const char *name, const char *signature,
603 bool isStatic = false) const;
604
605 static jfieldID getFieldID(JNIEnv *env, jclass clazz, const char *name,
606 const char *signature, bool isStatic = false);
607 static jmethodID getMethodID(JNIEnv *env, jclass clazz, const char *name,
608 const char *signature, bool isStatic = false);
609
610 void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const;
611
612 bool isSameObject(jobject obj) const;
613 bool isSameObject(const QJniObject &other) const;
614 void assign(jobject obj);
615 jobject javaObject() const;
616
617 friend bool operator==(const QJniObject &, const QJniObject &);
618 friend bool operator!=(const QJniObject&, const QJniObject&);
619
620 template<typename T>
621 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, ...)
622 {
623 va_list args = {};
624 va_start(args, id);
625 QtJniTypes::Caller<T>::callMethodForType(env, res, obj, id, args);
626 va_end(args);
627 }
628
629 template<typename T>
630 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz,
631 jmethodID id, ...)
632 {
633 if (!clazz || !id)
634 return;
635 va_list args = {};
636 va_start(args, id);
637 QtJniTypes::Caller<T>::callStaticMethodForType(env, res, clazz, id, args);
638 va_end(args);
639 }
640
641 static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...)
642 {
643 if (!clazz || !id)
644 return;
645 va_list args;
646 va_start(args, id);
647 env->CallStaticVoidMethodV(clazz, id, args);
648 va_end(args);
649 }
650
651
652 template<typename T>
653 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
654 {
655 QtJniTypes::Caller<T>::getFieldForType(env, res, obj, id);
656 }
657
658 template<typename T>
659 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
660 {
661 QtJniTypes::Caller<T>::getStaticFieldForType(env, res, clazz, id);
662 }
663
664 template<typename T>
665 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value)
666 {
667 if constexpr (QtJniTypes::isObjectType<T>()) {
668 LocalFrame<T> frame(env);
669 env->SetObjectField(obj, id, static_cast<jobject>(frame.convertToJni(value)));
670 } else {
671 QtJniTypes::Caller<T>::setFieldForType(env, obj, id, value);
672 }
673 }
674
675 template<typename T>
676 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value)
677 {
678 if constexpr (QtJniTypes::isObjectType<T>()) {
679 LocalFrame<T> frame(env);
680 env->SetStaticObjectField(clazz, id, static_cast<jobject>(frame.convertToJni(value)));
681 } else {
682 QtJniTypes::Caller<T>::setStaticFieldForType(env, clazz, id, value);
683 }
684 }
685
686 friend QJniObjectPrivate;
687 QSharedPointer<QJniObjectPrivate> d;
688};
689
690inline bool operator==(const QJniObject &obj1, const QJniObject &obj2)
691{
692 return obj1.isSameObject(obj2);
693}
694
695inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
696{
697 return !obj1.isSameObject(obj2);
698}
699
700namespace QtJniTypes {
701struct QT_TECH_PREVIEW_API JObjectBase
702{
703 operator QJniObject() const { return m_object; }
704
705 bool isValid() const { return m_object.isValid(); }
706 jclass objectClass() const { return m_object.objectClass(); }
707 QString toString() const { return m_object.toString(); }
708
709 template <typename T = jobject>
710 T object() const {
711 return m_object.object<T>();
712 }
713
714protected:
715 JObjectBase() = default;
716 JObjectBase(const JObjectBase &) = default;
717 JObjectBase(JObjectBase &&) = default;
718 JObjectBase &operator=(const JObjectBase &) = default;
719 JObjectBase &operator=(JObjectBase &&) = default;
720 ~JObjectBase() = default;
721
722 Q_IMPLICIT JObjectBase(jobject object) : m_object(object) {}
723 Q_IMPLICIT JObjectBase(const QJniObject &object) : m_object(object) {}
724 Q_IMPLICIT JObjectBase(QJniObject &&object) noexcept : m_object(std::move(object)) {}
725
726 QJniObject m_object;
727};
728
729template<typename Type>
730class QT_TECH_PREVIEW_API JObject : public JObjectBase
731{
732public:
733 using Class = Type;
734
735 JObject()
736 : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className())}
737 {}
738 Q_IMPLICIT JObject(jobject object) : JObjectBase(object) {}
739 Q_IMPLICIT JObject(const QJniObject &object) : JObjectBase(object) {}
740 Q_IMPLICIT JObject(QJniObject &&object) noexcept : JObjectBase(std::move(object)) {}
741
742 // base class SMFs are protected, make them public:
743 JObject(const JObject &other) = default;
744 JObject(JObject &&other) noexcept = default;
745 JObject &operator=(const JObject &other) = default;
746 JObject &operator=(JObject &&other) noexcept = default;
747
748 ~JObject() = default;
749
750 template<typename Arg, typename ...Args
751 , std::enable_if_t<!std::is_same_v<q20::remove_cvref_t<Arg>, JObject>, bool> = true
752 , IfValidSignatureTypes<Arg, Args...> = true
753 >
754 explicit JObject(Arg && arg, Args &&...args)
755 : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className(),
756 std::forward<Arg>(arg), std::forward<Args>(args)...)}
757 {}
758
759 // named constructors avoid ambiguities
760 static JObject fromJObject(jobject object)
761 {
762 return JObject(object);
763 }
764 template <typename ...Args>
765 static JObject construct(Args &&...args)
766 {
767 return JObject(std::forward<Args>(args)...);
768 }
769 static JObject fromLocalRef(jobject lref)
770 {
771 return JObject(QJniObject::fromLocalRef(lref));
772 }
773
774 static bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
775 {
776 QJniEnvironment env;
777 return env.registerNativeMethods<Class>(methods);
778 }
779
780 // public API forwarding to QJniObject, with the implicit Class template parameter
781 template <typename Ret = void, typename ...Args
782#ifndef Q_QDOC
783 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
784#endif
785 >
786 static auto callStaticMethod(const char *name, Args &&...args)
787 {
788 return QJniObject::callStaticMethod<Class, Ret, Args...>(name,
789 std::forward<Args>(args)...);
790 }
791 template <typename T
792#ifndef Q_QDOC
793 , QtJniTypes::IfValidFieldType<T> = true
794#endif
795 >
796 static auto getStaticField(const char *field)
797 {
798 return QJniObject::getStaticField<Class, T>(field);
799 }
800 template <typename T
801#ifndef Q_QDOC
802 , QtJniTypes::IfValidFieldType<T> = true
803#endif
804 >
805 static void setStaticField(const char *field, T &&value)
806 {
807 QJniObject::setStaticField<Class, T>(field, std::forward<T>(value));
808 }
809
810 // keep only these overloads, the rest is made private
811 template <typename Ret = void, typename ...Args
812#ifndef Q_QDOC
813 , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
814#endif
815 >
816 auto callMethod(const char *method, Args &&...args) const
817 {
818 return m_object.callMethod<Ret>(method, std::forward<Args>(args)...);
819 }
820 template <typename T
821#ifndef Q_QDOC
822 , QtJniTypes::IfValidFieldType<T> = true
823#endif
824 >
825 auto getField(const char *fieldName) const
826 {
827 return m_object.getField<T>(fieldName);
828 }
829
830 template <typename T
831#ifndef Q_QDOC
832 , QtJniTypes::IfValidFieldType<T> = true
833#endif
834 >
835 void setField(const char *fieldName, T &&value)
836 {
837 m_object.setField(fieldName, std::forward<T>(value));
838 }
839
840 QByteArray className() const {
841 return QtJniTypes::Traits<Class>::className().data();
842 }
843
844 static bool isClassAvailable()
845 {
846 return QJniObject::isClassAvailable(QtJniTypes::Traits<Class>::className().data());
847 }
848
849private:
850 friend bool comparesEqual(const JObject &lhs, const JObject &rhs)
851 { return lhs.m_object == rhs.m_object; }
852 Q_DECLARE_EQUALITY_COMPARABLE_NON_NOEXCEPT(JObject);
853};
854
855template <typename T> struct Traits<JObject<T>> {
856 static constexpr auto signature() { return Traits<T>::signature(); }
857 static constexpr auto className() { return Traits<T>::className(); }
858 static auto convertToJni(JNIEnv *, const JObject<T> &value)
859 {
860 return value.object();
861 }
862 static auto convertFromJni(QJniObject &&object)
863 {
864 return JObject<T>(std::move(object));
865 }
866};
867
868template<>
869struct Traits<QJniObject>
870{
871 static constexpr auto className()
872 {
873 return CTString("java/lang/Object");
874 }
875
876 static constexpr auto signature()
877 {
878 return CTString("Ljava/lang/Object;");
879 }
880
881 static auto convertToJni(JNIEnv *, const QJniObject &value)
882 {
883 return value.object();
884 }
885 static auto convertFromJni(QJniObject &&object)
886 {
887 return std::move(object);
888 }
889};
890
891template<>
892struct Traits<QString>
893{
894 static constexpr auto className()
895 {
896 return CTString("java/lang/String");
897 }
898 static constexpr auto signature()
899 {
900 return CTString("Ljava/lang/String;");
901 }
902
903 static auto convertToJni(JNIEnv *env, const QString &value)
904 {
905 return QtJniTypes::Detail::fromQString(value, env);
906 }
907
908 static auto convertFromJni(QJniObject &&object)
909 {
910 return object.toString();
911 }
912};
913
914}
915
916QT_END_NAMESPACE
917
918#endif
919
920#endif // QJNIOBJECT_H
\inmodule QtCore
Definition qmutex.h:346
\preliminary \inmodule QtCorePrivate
Q_CORE_EXPORT void unregisterNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT int acuqireServiceSetup(int flags)
Q_CORE_EXPORT void registerNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT bool acquireAndroidDeadlockProtector()
Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handleResume()
Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void releaseAndroidDeadlockProtector()
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent)
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener)
Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handlePause()
Q_CORE_EXPORT bool isUncompressedNativeLibs()
Q_CORE_EXPORT void unregisterActivityResultListener(ActivityResultListener *listener)
Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data)
Q_CORE_EXPORT void waitForServiceSetup()
jobject classLoader()
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener)
Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames, { { Qt::DisplayRole, "display" }, { Qt::DecorationRole, "decoration" }, { Qt::EditRole, "edit" }, { Qt::ToolTipRole, "toolTip" }, { Qt::StatusTipRole, "statusTip" }, { Qt::WhatsThisRole, "whatsThis" }, }) const QHash< int
Q_DECLARE_JNI_NATIVE_METHOD(dispatchKeyEvent)
Q_DECLARE_JNI_NATIVE_METHOD(dispatchGenericMotionEvent)
static jobject g_jClassLoader
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, QtJniTypes::MotionEvent event)
static JavaVM * g_javaVM
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
static jobject g_jActivity
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")
static jboolean updateNativeActivity(JNIEnv *env, jclass=nullptr)
static jboolean dispatchKeyEvent(JNIEnv *, jclass, QtJniTypes::KeyEvent event)
static jobject g_jService