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(
',');
99bool QAndroidViewSignalManager::addConnection(
const QString &signalName,
100 const QJniArray<jclass> &argTypes,
101 const QJniObject &listener,
104 if (m_view->status() == QQuickView::Error) {
105 qWarning(
"Can not connect to signals due to errors while loading the view");
109 if (m_view->status() != QQuickView::Ready) {
110 return queueConnection(signalName, argTypes, listener, id);
113 const auto *rootMetaObject = m_view->rootObject()->metaObject();
114 int signalIndex = indexOfSignal(*rootMetaObject, signalName, argTypes);
115 if (signalIndex == -1) {
116 qWarning(
"Failed to find matching signal from root object for signal: %s",
117 qPrintable(signalName));
121 if (m_connections.contains(signalIndex))
125 const auto connection =
126 QMetaObject::connect(m_view->rootObject(), signalIndex,
this,
127 QObject::metaObject()->methodCount(), Qt::QueuedConnection);
129 const auto signal = rootMetaObject->method(signalIndex);
130 const auto propertyIndex = propertyIndexForSignal(signal, *rootMetaObject);
131 const auto argumentTypes = metaMethodArgumentTypes(signal);
133 m_connections.insert(signalIndex,
134 { .connection = connection,
135 .listenerObject = listener,
136 .qmlSignalName = signalName,
137 .qmlArgumentTypes = argumentTypes,
138 .isPropertySignal = propertyIndex.has_value(),
139 .qmlPropertyIndex = propertyIndex,
140 .connectionId = id });
162 case QMetaType::Type::Bool:
163 return QtJniTypes::Boolean::construct(*
reinterpret_cast<
const bool *>(data));
164 case QMetaType::Type::Int:
165 return QtJniTypes::Integer::construct(*
reinterpret_cast<
const int *>(data));
166 case QMetaType::Type::Double:
167 return QtJniTypes::Double::construct(*
reinterpret_cast<
const double *>(data));
168 case QMetaType::Type::Float:
169 return QtJniTypes::Float::construct(*
reinterpret_cast<
const float *>(data));
170 case QMetaType::Type::QString:
171 return QtJniTypes::String::construct(*
reinterpret_cast<
const QString *>(data));
173 qWarning() <<
"Unknown type for signal argument" << type;
181 const auto type = data.metaType().id();
183 case QMetaType::Type::Bool:
184 return QtJniTypes::Boolean::construct(data.toBool());
185 case QMetaType::Type::Int:
186 return QtJniTypes::Integer::construct(data.toInt());
187 case QMetaType::Type::Double:
188 return QtJniTypes::Double::construct(data.toDouble());
189 case QMetaType::Type::Float:
190 return QtJniTypes::Float::construct(data.toFloat());
191 case QMetaType::Type::QString:
192 return QtJniTypes::String::construct(data.toString());
194 qWarning() <<
"Unknown type for signal argument" << type;
200int QAndroidViewSignalManager::qt_metacall(QMetaObject::Call call,
int methodId,
void **args)
203 if (!m_connections.contains(senderSignalIndex())) {
204 qWarning() <<
"QAndroidViewSignalManager::qt_metacall received unexpected signal";
208 const auto connection = m_connections.value(senderSignalIndex());
210 if (connection.isPropertySignal) {
211 const auto senderMetaObject = sender()->metaObject();
212 const auto property = senderMetaObject->property(connection.qmlPropertyIndex.value());
213 const auto data = property.read(sender());
215 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", connection.qmlSignalName,
216 qVariantToQJniObject(data));
218 QJniArray<QJniObject> data(connection.qmlArgumentTypes.size());
219 for (
auto i = 0; i < connection.qmlArgumentTypes.size(); ++i) {
220 const auto argType = connection.qmlArgumentTypes.at(i);
221 const auto receivedRawData = args[i + 1];
223 if (receivedRawData ==
nullptr) {
224 qWarning() <<
"Received null data for signal" << connection.qmlSignalName;
228 const auto receivedData = voidStarToQJniObject(argType, receivedRawData);
229 if (!receivedData.isValid()) {
230 qWarning() <<
"Received invalid data for signal" << connection.qmlSignalName;
234 data.setValue(i, receivedData);
237 if (data.size() == 0) {
238 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection] {
239 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
240 connection.qmlSignalName,
241 QtJniTypes::Void::construct().object());
243 }
else if (data.size() == 1) {
244 QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
245 [connection, signalArg = data.at(0)] {
246 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
247 connection.qmlSignalName,
251 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection, data] {
252 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", data);
268void QAndroidViewSignalManager::removeConnection(connection_key_t key)
270 if (hasConnection(key)) {
271 m_connections.removeIf([key](
const auto &iter) {
272 if (iter->connectionId == key)
273 return QObject::disconnect(iter->connection);
277 QMutexLocker lock(&m_queueMutex);
278 m_queuedConnections.removeIf([key](
const auto &info) {
return info.id == key; });