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,
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 QJniObject propertyValue(value);
119 const QVariant variantToWrite = QAndroidTypeConverter::toQVariant(propertyValue);
121 if (!variantToWrite.isValid()) {
122 qWarning(
"Setting the property type of %s is not supported.",
123 propertyValue.className().data());
125 QMetaObject::invokeMethod(rootObject,
126 [metaProperty = rootMetaObject->property(propertyIndex),
127 rootObject = rootObject,
129 metaProperty.write(rootObject, variantToWrite);
135 jstring propertyName)
140 const QString property = QJniObject(propertyName).toString();
141 auto [_, rootObject] = getViewAndRootObject(windowReference);
147 const QMetaObject *rootMetaObject = rootObject->metaObject();
148 int propertyIndex = rootMetaObject->indexOfProperty(property.toUtf8().constData());
149 if (propertyIndex < 0) {
150 qWarning(
"Cannot get property %s as it does not exist in the root QML object.",
151 qPrintable(property));
155 QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
156 QVariant propertyValue;
157 if (QCoreApplication::instance()->thread()->isCurrentThread()) {
158 propertyValue = metaProperty.read(rootObject);
160 QMetaObject::invokeMethod(rootObject,
161 [&propertyValue, &metaProperty, rootObject = rootObject] {
162 propertyValue = metaProperty.read(rootObject);
163 }, Qt::BlockingQueuedConnection);
165 jobject jObject = QAndroidTypeConverter::toJavaObject(propertyValue, env);
167 qWarning(
"Property %s cannot be converted to a supported Java data type.",
168 qPrintable(property));
174 jstring signalName, QJniArray<jclass> argTypes,
175 jobject listener, jint id)
179 auto [view, _] = getViewAndRootObject(windowReference);
181 qWarning(
"Cannot connect to signal %s %s",
186 QAndroidViewSignalManager *signalManager = view->signalManager();
187 return signalManager->addConnection(QJniObject(signalName).toString(), argTypes,
188 QJniObject(listener), id);
234 for (
auto i = object.methodOffset(); i < object.methodCount(); ++i) {
235 QMetaMethod method = object.method(i);
236 const auto paramMatch = method.parameterCount() == paramCount;
237 const auto nameMatch = method.name() == name.toUtf8();
238 if (paramMatch && nameMatch)
241 return QMetaMethod();
245 QJniArray<jobject> jniParams)
247 auto [_, rootObject] = getViewAndRootObject(viewReference);
249 qWarning() <<
"Cannot invoke QML method" << methodName.toString()
250 <<
"as the QML view has not been loaded yet.";
254 const auto paramCount = jniParams.size();
256 findMethod(methodName.toString(), paramCount, *rootObject->metaObject());
257 if (!method.isValid()) {
258 qWarning() <<
"Failed to find method" << QJniObject(methodName).toString()
264 if (paramCount == 0) {
265 method.invoke(rootObject, Qt::QueuedConnection);
269 QList<QVariant> variants;
270 variants.reserve(jniParams.size());
271 variants.emplace_back(QVariant{});
273 for (
auto i = 0; i < paramCount; ++i) {
274 const auto type = method.parameterType(i);
275 if (type == QMetaType::UnknownType) {
276 qWarning(
"Unknown metatypes are not supported.");
280 jobject rawParam = jniParams.at(i);
281 auto variant = variants.emplace_back(
282 jobjectToVariant(
static_cast<QMetaType::Type>(type), rawParam));
283 if (variant.isNull()) {
284 auto className = QJniObject(rawParam).className();
285 qWarning(
"Failed to convert param with class name '%s' to QVariant",
286 className.constData());
293 const int paramsCount = method.parameterCount() + 1;
294 const auto paramTypes =
std::make_unique<
const char *[]>(paramsCount);
295 const auto params =
std::make_unique<
const void *[]>(paramsCount);
296 const auto metaTypes =
297 std::make_unique<
const QtPrivate::QMetaTypeInterface *[]>(paramsCount);
300 paramTypes[0] =
nullptr;
302 metaTypes[0] =
nullptr;
304 for (
auto i = 1; i < variants.size(); ++i) {
305 const auto &variant = variants.at(i);
306 paramTypes[i] = variant.typeName();
307 params[i] = variant.data();
308 metaTypes[i] = variant.metaType().iface();
311 auto reason = QMetaMethodInvoker::invokeImpl(method,
313 Qt::QueuedConnection,
319 if (reason != QMetaMethodInvoker::InvokeFailReason::None)
320 qWarning() <<
"Failed to invoke function" << methodName.toString()
321 <<
", Reason:" <<
int(reason);
325 return env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtQuickView>::className(),
326 {Q_JNI_NATIVE_SCOPED_METHOD(createQuickView,
327 QtAndroidQuickViewEmbedding),
328 Q_JNI_NATIVE_SCOPED_METHOD(setRootObjectProperty,
329 QtAndroidQuickViewEmbedding),
330 Q_JNI_NATIVE_SCOPED_METHOD(getRootObjectProperty,
331 QtAndroidQuickViewEmbedding),
332 Q_JNI_NATIVE_SCOPED_METHOD(addRootObjectSignalListener,
333 QtAndroidQuickViewEmbedding),
334 Q_JNI_NATIVE_SCOPED_METHOD(removeRootObjectSignalListener,
335 QtAndroidQuickViewEmbedding),
336 Q_JNI_NATIVE_SCOPED_METHOD(invokeMethod,
337 QtAndroidQuickViewEmbedding)});