34 QAndroidQuickView::Status status)
36 auto future = QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
37 [qtViewObject, status] {
38 qtViewObject.callMethod<
void>(
"handleStatusChange", status);
39 }, QDeadlineTimer(1000));
40 future.waitForFinished();
43 void createQuickView(JNIEnv *, jobject nativeWindow, jstring qmlUri, jint width, jint height,
44 jlong parentWindowReference, jlong viewReference,
45 const QJniArray<jstring> &qmlImportPaths)
47 static_assert (
sizeof(jlong) >=
sizeof(
void*),
48 "Insufficient size of Java type to hold the c++ pointer");
49 const QUrl qmlUrl(QJniObject(qmlUri).toString());
51 const QStringList importPaths = qmlImportPaths.toContainer();
52 QMetaObject::invokeMethod(qApp, [qtViewObject = QJniObject(nativeWindow),
53 parentWindowReference,
61 QAndroidQuickView *view =
reinterpret_cast<QAndroidQuickView *>(viewReference);
63 QWindow *parentWindow =
reinterpret_cast<QWindow *>(parentWindowReference);
64 view =
new QAndroidQuickView(parentWindow);
66 view, &QAndroidQuickView::statusChanged,
67 std::bind(&onQQuickViewStatusChanged, qtViewObject, std::placeholders::_1));
68 view->setResizeMode(QAndroidQuickView::SizeRootObjectToView);
69 view->setColor(QColor(Qt::transparent));
70 view->setWidth(width);
71 view->setHeight(height);
72 QQmlEngine *engine = view->engine();
73 for (
const QString &path : importPaths)
74 engine->addImportPath(path);
76 QObject::connect(engine, &QQmlEngine::quit, QCoreApplication::instance(),
77 &QCoreApplication::quit);
79 const QtJniTypes::QtWindow window =
reinterpret_cast<jobject>(view->winId());
80 qtViewObject.callMethod<
void>(
"addQtWindow",
82 reinterpret_cast<jlong>(view),
83 parentWindowReference);
85 view->setSource(qmlUrl);
97 jstring propertyName, jobject value)
102 auto [_, rootObject] = getViewAndRootObject(windowReference);
104 qWarning(
"Cannot set property %s %s", qPrintable(QJniObject(propertyName).toString()),
109 const QString property = QJniObject(propertyName).toString();
110 const QMetaObject *rootMetaObject = rootObject->metaObject();
111 int propertyIndex = rootMetaObject->indexOfProperty(qPrintable(property));
112 if (propertyIndex < 0) {
113 qWarning(
"Property %s does not exist in the root QML object.", qPrintable(property));
117 const QJniObject propertyValue(value);
118 const QVariant variantToWrite = QAndroidTypeConverter::toQVariant(propertyValue);
120 if (!variantToWrite.isValid()) {
121 qWarning(
"Setting the property type of %s is not supported.",
122 propertyValue.className().data());
124 QMetaObject::invokeMethod(rootObject,
125 [metaProperty = rootMetaObject->property(propertyIndex),
126 rootObject = rootObject,
128 metaProperty.write(rootObject, variantToWrite);
134 jstring propertyName)
139 const QString property = QJniObject(propertyName).toString();
140 auto [_, rootObject] = getViewAndRootObject(windowReference);
146 const QMetaObject *rootMetaObject = rootObject->metaObject();
147 int propertyIndex = rootMetaObject->indexOfProperty(property.toUtf8().constData());
148 if (propertyIndex < 0) {
149 qWarning(
"Cannot get property %s as it does not exist in the root QML object.",
150 qPrintable(property));
154 QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
155 QVariant propertyValue;
156 if (QCoreApplication::instance()->thread()->isCurrentThread()) {
157 propertyValue = metaProperty.read(rootObject);
159 QMetaObject::invokeMethod(rootObject,
160 [&propertyValue, &metaProperty, rootObject = rootObject] {
161 propertyValue = metaProperty.read(rootObject);
162 }, Qt::BlockingQueuedConnection);
164 jobject jObject = QAndroidTypeConverter::toJavaObject(propertyValue, env);
166 qWarning(
"Property %s cannot be converted to a supported Java data type.",
167 qPrintable(property));
173 jstring signalName, QJniArray<jclass> argTypes,
174 jobject listener, jint id)
178 auto [view, _] = getViewAndRootObject(windowReference);
180 qWarning(
"Cannot connect to signal %s %s",
185 QAndroidViewSignalManager *signalManager = view->signalManager();
186 return signalManager->addConnection(QJniObject(signalName).toString(), argTypes,
187 QJniObject(listener), id);
233 for (
auto i = object.methodOffset(); i < object.methodCount(); ++i) {
234 QMetaMethod method = object.method(i);
235 const auto paramMatch = method.parameterCount() == paramCount;
236 const auto nameMatch = method.name() == name.toUtf8();
237 if (paramMatch && nameMatch)
240 return QMetaMethod();
244 QJniArray<jobject> jniParams)
246 auto [_, rootObject] = getViewAndRootObject(viewReference);
248 qWarning() <<
"Cannot invoke QML method" << methodName.toString()
249 <<
"as the QML view has not been loaded yet.";
253 const auto paramCount = jniParams.size();
255 findMethod(methodName.toString(), paramCount, *rootObject->metaObject());
256 if (!method.isValid()) {
257 qWarning() <<
"Failed to find method" << QJniObject(methodName).toString()
263 if (paramCount == 0) {
264 method.invoke(rootObject, Qt::QueuedConnection);
268 QList<QVariant> variants;
269 variants.reserve(jniParams.size());
270 variants.emplace_back(QVariant{});
272 for (
auto i = 0; i < paramCount; ++i) {
273 const auto type = method.parameterType(i);
274 if (type == QMetaType::UnknownType) {
275 qWarning(
"Unknown metatypes are not supported.");
279 jobject rawParam = jniParams.at(i);
280 auto variant = variants.emplace_back(
281 jobjectToVariant(
static_cast<QMetaType::Type>(type), rawParam));
282 if (variant.isNull()) {
283 auto className = QJniObject(rawParam).className();
284 qWarning(
"Failed to convert param with class name '%s' to QVariant",
285 className.constData());
292 const int paramsCount = method.parameterCount() + 1;
293 const auto paramTypes =
std::make_unique<
const char *[]>(paramsCount);
294 const auto params =
std::make_unique<
const void *[]>(paramsCount);
295 const auto metaTypes =
296 std::make_unique<
const QtPrivate::QMetaTypeInterface *[]>(paramsCount);
299 paramTypes[0] =
nullptr;
301 metaTypes[0] =
nullptr;
303 for (
auto i = 1; i < variants.size(); ++i) {
304 const auto &variant = variants.at(i);
305 paramTypes[i] = variant.typeName();
306 params[i] = variant.data();
307 metaTypes[i] = variant.metaType().iface();
310 auto reason = QMetaMethodInvoker::invokeImpl(method,
312 Qt::QueuedConnection,
318 if (reason != QMetaMethodInvoker::InvokeFailReason::None)
319 qWarning() <<
"Failed to invoke function" << methodName.toString()
320 <<
", Reason:" <<
int(reason);
324 return env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtQuickView>::className(),
325 {Q_JNI_NATIVE_SCOPED_METHOD(createQuickView,
326 QtAndroidQuickViewEmbedding),
327 Q_JNI_NATIVE_SCOPED_METHOD(setRootObjectProperty,
328 QtAndroidQuickViewEmbedding),
329 Q_JNI_NATIVE_SCOPED_METHOD(getRootObjectProperty,
330 QtAndroidQuickViewEmbedding),
331 Q_JNI_NATIVE_SCOPED_METHOD(addRootObjectSignalListener,
332 QtAndroidQuickViewEmbedding),
333 Q_JNI_NATIVE_SCOPED_METHOD(removeRootObjectSignalListener,
334 QtAndroidQuickViewEmbedding),
335 Q_JNI_NATIVE_SCOPED_METHOD(invokeMethod,
336 QtAndroidQuickViewEmbedding)});