Revision control

Copy as Markdown

// 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 <QtCore/QMetaType>
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<QNearFieldManager::AdapterState>(state);
auto obj = reinterpret_cast<QNearFieldManagerPrivateImpl *>(qtObject);
Q_ASSERT(obj != nullptr);
obj->adapterStateChanged(adapterState);
}
}
Q_GLOBAL_STATIC(QMainNfcNewIntentListener, newIntentListener)
QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() :
detecting(false)
{
qRegisterMetaType<QJniObject>("QJniObject");
qRegisterMetaType<QNdefMessage>("QNdefMessage");
broadcastReceiver = QJniObject::construct<QtJniTypes::QtNfcBroadcastReceiver>(
reinterpret_cast<jlong>(this), QNativeInterface::QAndroidApplication::context());
}
QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl()
{
broadcastReceiver.callMethod<void>("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<jbyte[]>("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