29 addConnection(info.signalName, info.argTypes, info.listener, info.id);
38 static const QHash<QByteArray, QMetaType::Type> javaToQMetaTypeMap = {
39 {
"java/lang/Void", QMetaType::Type::Void },
40 {
"java/lang/String", QMetaType::Type::QString },
41 {
"java/lang/Integer", QMetaType::Type::Int },
42 {
"java/lang/Double", QMetaType::Type::Double },
43 {
"java/lang/Float", QMetaType::Type::Float },
44 {
"java/lang/Boolean", QMetaType::Type::Bool }
47 QList<QByteArray> qmlArgTypes;
48 for (
const auto javaArgClass : javaArgClasses) {
49 const auto javaArgClassName = QJniObject(javaArgClass).className();
50 const auto javaArgMetaType =
51 javaToQMetaTypeMap.value(javaArgClassName, QMetaType::Type::UnknownType);
53 if (javaArgMetaType == QMetaType::Type::UnknownType) {
54 qWarning() <<
"Unknown type for signal argument" << javaArgClassName;
58 qmlArgTypes.emplace_back(QMetaType(javaArgMetaType).name());
60 return qmlArgTypes.join(
',');
98bool QAndroidViewSignalManager::addConnection(
const QString &signalName,
99 const QJniArray<jclass> &argTypes,
100 const QJniObject &listener,
103 if (m_view->status() == QQuickView::Error) {
104 qWarning(
"Can not connect to signals due to errors while loading the view");
108 if (m_view->status() != QQuickView::Ready) {
109 return queueConnection(signalName, argTypes, listener, id);
112 const auto *rootMetaObject = m_view->rootObject()->metaObject();
113 int signalIndex = indexOfSignal(*rootMetaObject, signalName, argTypes);
114 if (signalIndex == -1) {
115 qWarning(
"Failed to find matching signal from root object for signal: %s",
116 qPrintable(signalName));
120 if (m_connections.contains(signalIndex))
124 const auto connection =
125 QMetaObject::connect(m_view->rootObject(), signalIndex,
this,
126 QObject::metaObject()->methodCount(), Qt::QueuedConnection);
128 const auto signal = rootMetaObject->method(signalIndex);
129 const auto propertyIndex = propertyIndexForSignal(signal, *rootMetaObject);
130 const auto argumentTypes = metaMethodArgumentTypes(signal);
132 m_connections.insert(signalIndex,
133 { .connection = connection,
134 .listenerObject = listener,
135 .qmlSignalName = signalName,
136 .qmlArgumentTypes = argumentTypes,
137 .isPropertySignal = propertyIndex.has_value(),
138 .qmlPropertyIndex = propertyIndex,
139 .connectionId = id });
161 case QMetaType::Type::Bool:
162 return QtJniTypes::Boolean::construct(*
reinterpret_cast<
const bool *>(data));
163 case QMetaType::Type::Int:
164 return QtJniTypes::Integer::construct(*
reinterpret_cast<
const int *>(data));
165 case QMetaType::Type::Double:
166 return QtJniTypes::Double::construct(*
reinterpret_cast<
const double *>(data));
167 case QMetaType::Type::Float:
168 return QtJniTypes::Float::construct(*
reinterpret_cast<
const float *>(data));
169 case QMetaType::Type::QString:
170 return QtJniTypes::String::construct(*
reinterpret_cast<
const QString *>(data));
172 qWarning() <<
"Unknown type for signal argument" << type;
180 const auto type = data.metaType().id();
182 case QMetaType::Type::Bool:
183 return QtJniTypes::Boolean::construct(data.toBool());
184 case QMetaType::Type::Int:
185 return QtJniTypes::Integer::construct(data.toInt());
186 case QMetaType::Type::Double:
187 return QtJniTypes::Double::construct(data.toDouble());
188 case QMetaType::Type::Float:
189 return QtJniTypes::Float::construct(data.toFloat());
190 case QMetaType::Type::QString:
191 return QtJniTypes::String::construct(data.toString());
193 qWarning() <<
"Unknown type for signal argument" << type;
199int QAndroidViewSignalManager::qt_metacall(QMetaObject::Call call,
int methodId,
void **args)
202 if (!m_connections.contains(senderSignalIndex())) {
203 qWarning() <<
"QAndroidViewSignalManager::qt_metacall received unexpected signal";
207 const auto connection = m_connections.value(senderSignalIndex());
209 if (connection.isPropertySignal) {
210 const auto senderMetaObject = sender()->metaObject();
211 const auto property = senderMetaObject->property(connection.qmlPropertyIndex.value());
212 const auto data = property.read(sender());
214 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", connection.qmlSignalName,
215 qVariantToQJniObject(data));
217 QJniArray<QJniObject> data(connection.qmlArgumentTypes.size());
218 for (
auto i = 0; i < connection.qmlArgumentTypes.size(); ++i) {
219 const auto argType = connection.qmlArgumentTypes.at(i);
220 const auto receivedRawData = args[i + 1];
222 if (receivedRawData ==
nullptr) {
223 qWarning() <<
"Received null data for signal" << connection.qmlSignalName;
227 const auto receivedData = voidStarToQJniObject(argType, receivedRawData);
228 if (!receivedData.isValid()) {
229 qWarning() <<
"Received invalid data for signal" << connection.qmlSignalName;
233 data.setValue(i, receivedData);
236 if (data.size() == 0) {
237 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection] {
238 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
239 connection.qmlSignalName,
240 QtJniTypes::Void::construct().object());
242 }
else if (data.size() == 1) {
243 QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
244 [connection, signalArg = data.at(0)] {
245 connection.listenerObject.callMethod<
void>(
"onSignalEmitted",
246 connection.qmlSignalName,
250 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([connection, data] {
251 connection.listenerObject.callMethod<
void>(
"onSignalEmitted", data);
267void QAndroidViewSignalManager::removeConnection(connection_key_t key)
269 if (hasConnection(key)) {
270 m_connections.removeIf([key](
const auto &iter) {
271 if (iter->connectionId == key)
272 return QObject::disconnect(iter->connection);
276 QMutexLocker lock(&m_queueMutex);
277 m_queuedConnections.removeIf([key](
const auto &info) {
return info.id == key; });