35 QAndroidQuickView::Status status)
37 auto future = QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
38 [qtViewObject, status] {
39 qtViewObject.callMethod<
void>(
"handleStatusChange", status);
40 }, QDeadlineTimer(1000));
41 future.waitForFinished();
44 void createQuickView(JNIEnv *, jobject nativeWindow, jstring qmlUri, jint width, jint height,
45 jlong parentWindowReference, jlong viewReference,
46 const QJniArray<jstring> &qmlImportPaths)
48 static_assert (
sizeof(jlong) >=
sizeof(
void*),
49 "Insufficient size of Java type to hold the c++ pointer");
50 const QUrl qmlUrl(QJniObject(qmlUri).toString());
52 const QStringList importPaths = qmlImportPaths.toContainer();
53 QMetaObject::invokeMethod(qApp, [qtViewObject = QJniObject(nativeWindow),
54 parentWindowReference,
62 QAndroidQuickView *view =
reinterpret_cast<QAndroidQuickView *>(viewReference);
64 QWindow *parentWindow =
reinterpret_cast<QWindow *>(parentWindowReference);
65 view =
new QAndroidQuickView(parentWindow);
67 view, &QAndroidQuickView::statusChanged, view,
68 std::bind(&onQQuickViewStatusChanged, qtViewObject, std::placeholders::_1));
69 view->setResizeMode(QAndroidQuickView::SizeRootObjectToView);
70 view->setColor(QColor(Qt::transparent));
71 view->setWidth(width);
72 view->setHeight(height);
73 QQmlEngine *engine = view->engine();
74 for (
const QString &path : importPaths)
75 engine->addImportPath(path);
77 QObject::connect(engine, &QQmlEngine::quit, QCoreApplication::instance(),
78 &QCoreApplication::quit);
80 const QtJniTypes::QtWindow window =
reinterpret_cast<jobject>(view->winId());
81 qtViewObject.callMethod<
void>(
"addQtWindow",
83 reinterpret_cast<jlong>(view),
84 parentWindowReference);
86 view->setSource(qmlUrl);
98 jstring propertyName, jobject value)
103 auto [_, rootObject] = getViewAndRootObject(windowReference);
105 qWarning(
"Cannot set property %s %s", qPrintable(QJniObject(propertyName).toString()),
110 const QString property = QJniObject(propertyName).toString();
111 const QMetaObject *rootMetaObject = rootObject->metaObject();
112 int propertyIndex = rootMetaObject->indexOfProperty(qPrintable(property));
113 if (propertyIndex < 0) {
114 qWarning(
"Property %s does not exist in the root QML object.", qPrintable(property));
118 const QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
119 if (!metaProperty.isWritable()) {
120 qWarning(
"Property %s of the root QML object is not writable.",
121 qPrintable(property));
125 const QJniObject propertyValue(value);
126 const QVariant variantToWrite = QAndroidTypeConverter::toQVariant(propertyValue);
128 if (!variantToWrite.isValid()) {
129 qWarning(
"Setting the property type of %s is not supported.",
130 propertyValue.className().data());
132 QMetaObject::invokeMethod(rootObject,
133 [metaProperty, rootObject = rootObject, variantToWrite, property] {
134 if (!metaProperty.write(rootObject, variantToWrite)) {
135 qWarning(
"Failed to write property %s of the root QML object.",
136 qPrintable(property));
143 jstring propertyName)
148 const QString property = QJniObject(propertyName).toString();
149 auto [_, rootObject] = getViewAndRootObject(windowReference);
155 const QMetaObject *rootMetaObject = rootObject->metaObject();
156 int propertyIndex = rootMetaObject->indexOfProperty(property.toUtf8().constData());
157 if (propertyIndex < 0) {
158 qWarning(
"Cannot get property %s as it does not exist in the root QML object.",
159 qPrintable(property));
163 QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
164 QVariant propertyValue;
165 if (QCoreApplication::instance()->thread()->isCurrentThread()) {
166 propertyValue = metaProperty.read(rootObject);
168 QMetaObject::invokeMethod(rootObject,
169 [&propertyValue, &metaProperty, rootObject = rootObject] {
170 propertyValue = metaProperty.read(rootObject);
171 }, Qt::BlockingQueuedConnection);
173 jobject jObject = QAndroidTypeConverter::toJavaObject(propertyValue, env);
175 qWarning(
"Property %s cannot be converted to a supported Java data type.",
176 qPrintable(property));
182 jstring signalName, QJniArray<jclass> argTypes,
183 jobject listener, jint id)
187 auto [view, _] = getViewAndRootObject(windowReference);
189 qWarning(
"Cannot connect to signal %s %s",
194 QAndroidViewSignalManager *signalManager = view->signalManager();
195 return signalManager->addConnection(QJniObject(signalName).toString(), argTypes,
196 QJniObject(listener), id);
242 for (
auto i = object.methodOffset(); i < object.methodCount(); ++i) {
243 QMetaMethod method = object.method(i);
244 const auto paramMatch = method.parameterCount() == paramCount;
245 const auto nameMatch = method.name() == name.toUtf8();
246 if (paramMatch && nameMatch)
249 return QMetaMethod();
253 QJniArray<jobject> jniParams)
255 auto [_, rootObject] = getViewAndRootObject(viewReference);
257 qWarning() <<
"Cannot invoke QML method" << methodName.toString()
258 <<
"as the QML view has not been loaded yet.";
262 const auto paramCount = jniParams.size();
264 findMethod(methodName.toString(), paramCount, *rootObject->metaObject());
265 if (!method.isValid()) {
266 qWarning() <<
"Failed to find method" << QJniObject(methodName).toString()
272 if (paramCount == 0) {
273 method.invoke(rootObject, Qt::QueuedConnection);
277 QList<QVariant> variants;
278 variants.reserve(jniParams.size());
279 variants.emplace_back(QVariant{});
281 for (
auto i = 0; i < paramCount; ++i) {
282 const auto type = method.parameterType(i);
283 if (type == QMetaType::UnknownType) {
284 qWarning(
"Unknown metatypes are not supported.");
288 jobject rawParam = jniParams.at(i);
289 auto variant = variants.emplace_back(
290 jobjectToVariant(
static_cast<QMetaType::Type>(type), rawParam));
291 if (variant.isNull()) {
292 auto className = QJniObject(rawParam).className();
293 qWarning(
"Failed to convert param with class name '%s' to QVariant",
294 className.constData());
301 const int paramsCount = method.parameterCount() + 1;
302 const auto paramTypes =
std::make_unique<
const char *[]>(paramsCount);
303 const auto params =
std::make_unique<
const void *[]>(paramsCount);
304 const auto metaTypes =
305 std::make_unique<
const QtPrivate::QMetaTypeInterface *[]>(paramsCount);
308 paramTypes[0] =
nullptr;
310 metaTypes[0] =
nullptr;
312 for (
auto i = 1; i < variants.size(); ++i) {
313 const auto &variant = variants.at(i);
314 paramTypes[i] = variant.typeName();
315 params[i] = variant.data();
316 metaTypes[i] = variant.metaType().iface();
319 auto reason = QMetaMethodInvoker::invokeImpl(method,
321 Qt::QueuedConnection,
327 if (reason != QMetaMethodInvoker::InvokeFailReason::None)
328 qWarning() <<
"Failed to invoke function" << methodName.toString()
329 <<
", Reason:" <<
int(reason);
333 return env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtQuickView>::className(),
334 {Q_JNI_NATIVE_SCOPED_METHOD(createQuickView,
335 QtAndroidQuickViewEmbedding),
336 Q_JNI_NATIVE_SCOPED_METHOD(setRootObjectProperty,
337 QtAndroidQuickViewEmbedding),
338 Q_JNI_NATIVE_SCOPED_METHOD(getRootObjectProperty,
339 QtAndroidQuickViewEmbedding),
340 Q_JNI_NATIVE_SCOPED_METHOD(addRootObjectSignalListener,
341 QtAndroidQuickViewEmbedding),
342 Q_JNI_NATIVE_SCOPED_METHOD(removeRootObjectSignalListener,
343 QtAndroidQuickViewEmbedding),
344 Q_JNI_NATIVE_SCOPED_METHOD(invokeMethod,
345 QtAndroidQuickViewEmbedding)});