// Copyright (C) 2016 Centria research and development // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qnearfieldmanager_android_p.h" #include "qndefmessage.h" #include "qbytearray.h" #include "qcoreapplication.h" #include QT_BEGIN_NAMESPACE extern "C" { JNIEXPORT void JNICALL Java_org_qtproject_qt_android_nfc_QtNfcBroadcastReceiver_jniOnReceive( JNIEnv */*env*/, jobject /*javaObject*/, jlong qtObject, jint state) { QNearFieldManager::AdapterState adapterState = static_cast(state); auto obj = reinterpret_cast(qtObject); Q_ASSERT(obj != nullptr); obj->adapterStateChanged(adapterState); } } Q_GLOBAL_STATIC(QMainNfcNewIntentListener, newIntentListener) QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() : detecting(false) { qRegisterMetaType("QJniObject"); qRegisterMetaType("QNdefMessage"); broadcastReceiver = QJniObject::construct( reinterpret_cast(this), QNativeInterface::QAndroidApplication::context()); } QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() { broadcastReceiver.callMethod("unregisterReceiver"); } void QNearFieldManagerPrivateImpl::onTargetDetected(QNearFieldTargetPrivateImpl *target) { if (target->q_ptr) { Q_EMIT targetDetected(target->q_ptr); return; } Q_EMIT targetDetected(new QNearFieldTarget(target, this)); } void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *target) { Q_EMIT targetLost(target->q_ptr); } bool QNearFieldManagerPrivateImpl::isEnabled() const { return QtNfc::isEnabled(); } bool QNearFieldManagerPrivateImpl::isSupported(QNearFieldTarget::AccessMethod accessMethod) const { if (accessMethod == QNearFieldTarget::UnknownAccess) return false; return QtNfc::isSupported(); } bool QNearFieldManagerPrivateImpl::startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) { if (detecting) return false; // Already detecting targets if (newIntentListener.isDestroyed()) return false; detecting = true; requestedMethod = accessMethod; newIntentListener->registerListener(this); return true; } void QNearFieldManagerPrivateImpl::stopTargetDetection(const QString &) { detecting = false; if (newIntentListener.exists()) newIntentListener->unregisterListener(this); Q_EMIT targetDetectionStopped(); } void QNearFieldManagerPrivateImpl::newIntent(QJniObject intent) { // This function is called from different thread and is used to move intent to main thread. QMetaObject::invokeMethod(this, [this, intent] { this->onTargetDiscovered(intent); }, Qt::QueuedConnection); } QByteArray QNearFieldManagerPrivateImpl::getUid(const QJniObject &intent) { if (!intent.isValid()) return QByteArray(); QJniObject tag = QtNfc::getTag(intent); if (!tag.isValid()) return QByteArray(); return tag.callMethod("getId").toContainer(); } void QNearFieldManagerPrivateImpl::onTargetDiscovered(QJniObject intent) { // Getting UID QByteArray uid = getUid(intent); // Accepting all targets but only sending signal of requested types. QNearFieldTargetPrivateImpl *&target = detectedTargets[uid]; if (target) { target->setIntent(intent); // Updating existing target } else { target = new QNearFieldTargetPrivateImpl(intent, uid); if (target->accessMethods() & requestedMethod) { connect(target, &QNearFieldTargetPrivateImpl::targetDestroyed, this, &QNearFieldManagerPrivateImpl::onTargetDestroyed); connect(target, &QNearFieldTargetPrivateImpl::targetLost, this, &QNearFieldManagerPrivateImpl::onTargetLost); onTargetDetected(target); } else { delete target; detectedTargets.remove(uid); } } } void QNearFieldManagerPrivateImpl::onTargetDestroyed(const QByteArray &uid) { detectedTargets.remove(uid); } QT_END_NAMESPACE