30 addConnection(info.signalName, info.argTypes, info.listener, info.id);
39 static const QHash<QByteArray, QMetaType::Type> javaToQMetaTypeMap = {
40 {
"java/lang/Void", QMetaType::Type::Void },
41 {
"java/lang/String", QMetaType::Type::QString },
42 {
"java/lang/Integer", QMetaType::Type::Int },
43 {
"java/lang/Double", QMetaType::Type::Double },
44 {
"java/lang/Float", QMetaType::Type::Float },
45 {
"java/lang/Boolean", QMetaType::Type::Bool }
48 QList<QByteArray> qmlArgTypes;
49 for (
const auto javaArgClass : javaArgClasses) {
50 const auto javaArgClassName = QJniObject(javaArgClass).className();
51 const auto javaArgMetaType =
52 javaToQMetaTypeMap.value(javaArgClassName, QMetaType::Type::UnknownType);
54 if (javaArgMetaType == QMetaType::Type::UnknownType) {
55 qWarning() <<
"Unknown type for signal argument" << javaArgClassName;
59 qmlArgTypes.emplace_back(QMetaType(javaArgMetaType).name());
61 return qmlArgTypes.join(
',');
79int indexOfSignal(
const QMetaObject &metaObject,
const QString &signalName,
80 const QJniArray<jclass> &javaArgClasses)
82 int signalIndex = metaObject.indexOfSignal(qmlSignalSignature(signalName, javaArgClasses));
83 if (signalIndex != -1)
87 QString signature = signalName;
88 if (!signature.contains(u'('))
89 signature += QStringLiteral(
"()");
90 signalIndex = metaObject.indexOfSignal(QMetaObject::normalizedSignature(qPrintable(signature)));
91 if (signalIndex != -1)
95 const int propertyIndex = metaObject.indexOfProperty(qPrintable(signalName));
96 return propertyIndex == -1 ? -1 : metaObject.property(propertyIndex).notifySignalIndex();
109bool QAndroidViewSignalManager::addConnection(
const QString &signalName,
110 const QJniArray<jclass> &argTypes,
111 const QJniObject &listener,
114 if (m_view->status() == QQuickView::Error) {
115 qWarning(
"Can not connect to signals due to errors while loading the view");
119 if (m_view->status() != QQuickView::Ready) {
120 return queueConnection(signalName, argTypes, listener, id);
123 const auto *rootMetaObject = m_view->rootObject()->metaObject();
124 int signalIndex = indexOfSignal(*rootMetaObject, signalName, argTypes);
125 if (signalIndex == -1) {
126 qWarning(
"Failed to find matching signal from root object for signal: %s",
127 qPrintable(signalName));
131 if (m_connections.contains(signalIndex))
135 const auto connection =
136 QMetaObject::connect(m_view->rootObject(), signalIndex,
this,
137 QObject::metaObject()->methodCount(), Qt::QueuedConnection);
139 const auto signal = rootMetaObject->method(signalIndex);
140 const auto propertyIndex = propertyIndexForSignal(signal, *rootMetaObject);
141 const auto argumentTypes = metaMethodArgumentTypes(signal);
143 m_connections.insert(signalIndex,
144 { .connection = connection,
145 .listenerObject = listener,
146 .qmlSignalName = signalName,
147 .qmlArgumentTypes = argumentTypes,
148 .isPropertySignal = propertyIndex.has_value(),
149 .qmlPropertyIndex = propertyIndex,
150 .connectionId = id });
172 case QMetaType::Type::Bool:
173 return QtJniTypes::Boolean::construct(*
reinterpret_cast<
const bool *>(data));
174 case QMetaType::Type::Int:
175 return QtJniTypes::Integer::construct(*
reinterpret_cast<
const int *>(data));
176 case QMetaType::Type::Double:
177 return QtJniTypes::Double::construct(*
reinterpret_cast<
const double *>(data));
178 case QMetaType::Type::Float:
179 return QtJniTypes::Float::construct(*
reinterpret_cast<
const float *>(data));
180 case QMetaType::Type::QString:
181 return QtJniTypes::String::construct(*
reinterpret_cast<
const QString *>(data));
183 qWarning() <<
"Unknown type for signal argument" << type;
191 const auto type = data.metaType().id();
193 case QMetaType::Type::Bool:
194 return QtJniTypes::Boolean::construct(data.toBool());
195 case QMetaType::Type::Int:
196 return QtJniTypes::Integer::construct(data.toInt());
197 case QMetaType::Type::Double:
198 return QtJniTypes::Double::construct(data.toDouble());
199 case QMetaType::Type::Float:
200 return QtJniTypes::Float::construct(data.toFloat());
201 case QMetaType::Type::QString:
202 return QtJniTypes::String::construct(data.toString());
204 qWarning() <<
"Unknown type for signal argument" << type;
210int QAndroidViewSignalManager::qt_metacall(QMetaObject::Call call,
int methodId,
void **args)
213 if (!m_connections.contains(senderSignalIndex())) {
214 qWarning() <<
"QAndroidViewSignalManager::qt_metacall received unexpected signal";
218 const auto connection = m_connections.value(senderSignalIndex());
220 if (connection.isPropertySignal) {
221 const auto senderMetaObject = sender()->metaObject();
222 const auto property = senderMetaObject->property(connection.qmlPropertyIndex.value());
223 const auto data = property.read(sender());
225 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", connection.qmlSignalName,
226 qVariantToQJniObject(data));
228 QJniArray<QJniObject> data(connection.qmlArgumentTypes.size());
229 for (
auto i = 0; i < connection.qmlArgumentTypes.size(); ++i) {
230 const auto argType = connection.qmlArgumentTypes.at(i);
231 const auto receivedRawData = args[i + 1];
233 if (receivedRawData ==
nullptr) {
234 qWarning() <<
"Received null data for signal" << connection.qmlSignalName;
238 const auto receivedData = voidStarToQJniObject(argType, receivedRawData);
239 if (!receivedData.isValid()) {
240 qWarning() <<
"Received invalid data for signal" << connection.qmlSignalName;
244 data.setValue(i, receivedData);
247 if (data.size() == 0) {
248 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection] {
249 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
250 connection.qmlSignalName,
251 QtJniTypes::Void::construct().object());
253 }
else if (data.size() == 1) {
254 QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
255 [connection, signalArg = data.at(0)] {
256 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
257 connection.qmlSignalName,
261 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection, data] {
262 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", data);
278void QAndroidViewSignalManager::removeConnection(connection_key_t key)
280 if (hasConnection(key)) {
281 m_connections.removeIf([key](
const auto &iter) {
282 if (iter->connectionId == key)
283 return QObject::disconnect(iter->connection);
287 QMutexLocker lock(&m_queueMutex);
288 m_queuedConnections.removeIf([key](
const auto &info) {
return info.id == key; });