diff options
Diffstat (limited to 'src/nfc/qnearfieldmanager_maemo6.cpp')
-rw-r--r-- | src/nfc/qnearfieldmanager_maemo6.cpp | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/src/nfc/qnearfieldmanager_maemo6.cpp b/src/nfc/qnearfieldmanager_maemo6.cpp new file mode 100644 index 00000000..a8c21bac --- /dev/null +++ b/src/nfc/qnearfieldmanager_maemo6.cpp @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnearfieldmanager_maemo6_p.h" +#include "qnearfieldtarget_maemo6_p.h" +#include "manager_interface.h" +#include "maemo6/adapter_interface_p.h" +#include "maemo6/target_interface_p.h" +#include "maemo6/tag_interface_p.h" +#include "ndefhandler_adaptor.h" +#include "accessrequestor_adaptor.h" + +#include <qnearfieldtagtype1.h> + +#include <QtDBus/QDBusConnection> + +using namespace com::nokia::nfc; + +static QAtomicInt handlerId = 0; +static const char * const registeredHandlerPath = "/com/nokia/nfc/ndefhandler"; +static const char * const accessRequesterPath = "/com/nokia/nfc/accessRequester/"; +static const char * const connectionUuid = "46a15ee4-b5ce-4395-9d76-c440cc3838c6"; + +static inline bool matchesTarget(QNearFieldTarget::Type type, + const QList<QNearFieldTarget::Type> &types) +{ + return types.contains(type) || types.contains(QNearFieldTarget::AnyTarget); +} + +NdefHandler::NdefHandler(QNearFieldManagerPrivateImpl *manager, const QString &serviceName, + const QString &path, QObject *object, const QMetaMethod &method) +: m_manager(manager), m_adaptor(0), m_object(object), m_method(method), + m_serviceName(serviceName), m_path(path) +{ + QDBusConnection handlerConnection = + QDBusConnection::connectToBus(QDBusConnection::SystemBus, connectionUuid); + if (serviceName != handlerConnection.baseService()) { + handlerConnection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, serviceName); + + if (!handlerConnection.registerService(serviceName)) + return; + } + + m_adaptor = new NDEFHandlerAdaptor(this); + + if (!handlerConnection.registerObject(path, this)) { + delete m_adaptor; + m_adaptor = 0; + } +} + +NdefHandler::~NdefHandler() +{ + delete m_adaptor; +} + +bool NdefHandler::isValid() const +{ + return m_adaptor; +} + +QString NdefHandler::serviceName() const +{ + return m_serviceName; +} + +QString NdefHandler::path() const +{ + return m_path; +} + +void NdefHandler::NDEFData(const QDBusObjectPath &target, const QByteArray &message) +{ + m_method.invoke(m_object, Q_ARG(QNdefMessage, QNdefMessage::fromByteArray(message)), + Q_ARG(QNearFieldTarget *, m_manager->targetForPath(target.path()))); +} + +QNearFieldManagerPrivateImpl::QNearFieldManagerPrivateImpl() +: m_connection(QDBusConnection::connectToBus(QDBusConnection::SystemBus, + QLatin1String(connectionUuid))), + m_accessAgent(0) +{ + qDBusRegisterMetaType<QList<QByteArray> >(); + + m_manager = new Manager(QLatin1String("com.nokia.nfc"), QLatin1String("/"), m_connection); + + QDBusObjectPath defaultAdapterPath = m_manager->DefaultAdapter(); + + m_adapter = new Adapter(QLatin1String("com.nokia.nfc"), defaultAdapterPath.path(), + m_connection); + + if (!m_adapter->isValid()) + return; +} + +QNearFieldManagerPrivateImpl::~QNearFieldManagerPrivateImpl() +{ + foreach (int id, m_registeredHandlers.keys()) + unregisterNdefMessageHandler(id); + + delete m_manager; + delete m_adapter; +} + +bool QNearFieldManagerPrivateImpl::isAvailable() const +{ + return m_manager->isValid(); +} + +bool QNearFieldManagerPrivateImpl::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes) +{ + m_detectTargetTypes = targetTypes; + + connect(m_adapter, SIGNAL(TargetDetected(QDBusObjectPath)), + this, SLOT(_q_targetDetected(QDBusObjectPath))); + connect(m_adapter, SIGNAL(TargetLost(QDBusObjectPath)), + this, SLOT(_q_targetLost(QDBusObjectPath))); + + return true; +} + +void QNearFieldManagerPrivateImpl::stopTargetDetection() +{ + m_detectTargetTypes.clear(); + + disconnect(m_adapter, SIGNAL(TargetDetected(QDBusObjectPath)), + this, SLOT(_q_targetDetected(QDBusObjectPath))); + disconnect(m_adapter, SIGNAL(TargetLost(QDBusObjectPath)), + this, SLOT(_q_targetLost(QDBusObjectPath))); +} + +QNearFieldTarget *QNearFieldManagerPrivateImpl::targetForPath(const QString &path) +{ + QNearFieldTarget *nearFieldTarget = m_targets.value(path).data(); + + if (!nearFieldTarget) { + Target *target = new Target(QLatin1String("com.nokia.nfc"), path, m_connection); + + const QString type = target->type(); + + if (type == QLatin1String("tag")) { + Tag *tag = new Tag(QLatin1String("com.nokia.nfc"), path, m_connection); + + const QString tagTechnology = tag->technology(); + if (tagTechnology == QLatin1String("jewel")) + nearFieldTarget = new TagType1(this, target, tag); + else if (tagTechnology == QLatin1String("mifare-ul")) + nearFieldTarget = new TagType2(this, target, tag); + else if (tagTechnology == QLatin1String("felica")) + nearFieldTarget = new TagType3(this, target, tag); + else if (tagTechnology == QLatin1String("iso-4a")) + nearFieldTarget = new TagType4(this, target, tag); + else + nearFieldTarget = new NearFieldTarget<QNearFieldTarget>(this, target, tag); + } else if (type == QLatin1String("device")) { + Device *device = new Device(QLatin1String("com.nokia.nfc"), path, m_connection); + nearFieldTarget = new NearFieldTarget<QNearFieldTarget>(this, target, device); + } + + if (nearFieldTarget) + m_targets.insert(path, nearFieldTarget); + } + + return nearFieldTarget; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QString &filter, + QObject *object, + const QMetaMethod &method) +{ + int id = handlerId.fetchAndAddOrdered(1); + const QString handlerPath = + QLatin1String(registeredHandlerPath) + QLatin1Char('/') + QString::number(id); + + NdefHandler *handler = new NdefHandler(this, m_connection.baseService(), + handlerPath, object, method); + if (!handler->isValid()) { + delete handler; + return -1; + } + + QDBusPendingReply<> reply = + m_manager->RegisterNDEFHandler(QLatin1String("system"), + m_connection.baseService(), + QDBusObjectPath(handlerPath), + QLatin1String("any"), + filter, + QCoreApplication::applicationName()); + + if (reply.isError()) { + delete handler; + return -1; + } + + m_registeredHandlers[id] = handler; + + return id; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(QObject *object, + const QMetaMethod &method) +{ + QFileInfo fi(qApp->applicationFilePath()); + const QString serviceName = QLatin1String("com.nokia.qt.nfc.") + fi.baseName(); + + int id = handlerId.fetchAndAddOrdered(1); + + const QString handlerPath = QLatin1String(registeredHandlerPath); + + NdefHandler *handler = new NdefHandler(this, serviceName, handlerPath, object, method); + if (!handler->isValid()) { + delete handler; + return -1; + } + + m_registeredHandlers[id] = handler; + + return id; +} + +int QNearFieldManagerPrivateImpl::registerNdefMessageHandler(const QNdefFilter &filter, + QObject *object, + const QMetaMethod &method) +{ + QString matchString; + + if (filter.orderMatch()) + matchString += QLatin1String("sequence:"); + else + matchString += QLatin1String("unordered:"); + + for (int i = 0; i < filter.recordCount(); ++i) { + QNdefFilter::Record record = filter.recordAt(i); + + QString type; + + switch (record.typeNameFormat) { + case QNdefRecord::NfcRtd: + type = QLatin1String("urn:nfc:wkt:") + record.type; + break; + case QNdefRecord::ExternalRtd: + type = QLatin1String("urn:nfc:ext:") + record.type; + break; + case QNdefRecord::Mime: + type = record.type; + break; + default: + qWarning("Unsupported filter type"); + return -1; + } + + matchString += QLatin1Char('\'') + type + QLatin1Char('\''); + matchString += QLatin1Char('['); + + if (record.minimum == UINT_MAX) + matchString += QLatin1Char('*'); + else + matchString += QString::number(record.minimum); + + matchString += QLatin1Char(':'); + + if (record.maximum == UINT_MAX) + matchString += QLatin1Char('*'); + else + matchString += QString::number(record.maximum); + + matchString += QLatin1Char(']'); + + if (i == filter.recordCount() - 1) + matchString += QLatin1Char(';'); + else + matchString += QLatin1Char(','); + } + + return registerNdefMessageHandler(matchString, object, method); +} + +bool QNearFieldManagerPrivateImpl::unregisterNdefMessageHandler(int id) +{ + if (id < 0) + return false; + + NdefHandler *handler = m_registeredHandlers.take(id); + + QDBusPendingReply<> reply = m_manager->UnregisterNDEFHandler(QLatin1String("system"), + handler->serviceName(), + QDBusObjectPath(handler->path())); + + delete handler; + + return true; +} + +static QStringList accessModesToKind(QNearFieldManager::TargetAccessModes accessModes) +{ + QStringList kind; + + if (accessModes & QNearFieldManager::NdefReadTargetAccess) + kind.append(QLatin1String("tag.ndef.read")); + + if (accessModes & QNearFieldManager::NdefWriteTargetAccess) + kind.append(QLatin1String("tag.ndef.write")); + + if (accessModes & QNearFieldManager::TagTypeSpecificTargetAccess) + kind.append(QLatin1String("tag.raw")); + + return kind; +} + +void QNearFieldManagerPrivateImpl::requestAccess(QNearFieldManager::TargetAccessModes accessModes) +{ + const QString requesterPath = + QLatin1String(accessRequesterPath) + QString::number(quintptr(this)); + + if (!m_accessAgent) { + m_accessAgent = new AccessRequestorAdaptor(this); + if (!m_connection.registerObject(requesterPath, this)) { + delete m_accessAgent; + m_accessAgent = 0; + return; + } + } + + foreach (const QString &kind, accessModesToKind(accessModes)) + m_adapter->RequestAccess(QDBusObjectPath(requesterPath), kind); + + QNearFieldManagerPrivate::requestAccess(accessModes); +} + +void QNearFieldManagerPrivateImpl::releaseAccess(QNearFieldManager::TargetAccessModes accessModes) +{ + const QString requesterPath = + QLatin1String(accessRequesterPath) + QString::number(quintptr(this)); + + foreach (const QString &kind, accessModesToKind(accessModes)) + m_adapter->CancelAccessRequest(QDBusObjectPath(requesterPath), kind); + + QNearFieldManagerPrivate::releaseAccess(accessModes); +} + +void QNearFieldManagerPrivateImpl::AccessFailed(const QDBusObjectPath &target, const QString &kind, + const QString &error) +{ + qDebug() << "Access for" << target.path() << kind << "failed with error:" << error; +} + +void QNearFieldManagerPrivateImpl::AccessGranted(const QDBusObjectPath &target, + const QString &kind) +{ + Q_UNUSED(kind); + + if (m_pendingDetectedTargets.contains(target.path())) { + m_pendingDetectedTargets[target.path()].stop(); + m_pendingDetectedTargets.remove(target.path()); + } + + emitTargetDetected(target.path()); +} + +void QNearFieldManagerPrivateImpl::timerEvent(QTimerEvent *event) +{ + QMutableMapIterator<QString, QBasicTimer> i(m_pendingDetectedTargets); + while (i.hasNext()) { + i.next(); + + if (i.value().timerId() == event->timerId()) { + i.value().stop(); + + const QString target = i.key(); + + i.remove(); + + emitTargetDetected(target); + + break; + } + } +} + +void QNearFieldManagerPrivateImpl::emitTargetDetected(const QString &targetPath) +{ + QNearFieldTarget *target = targetForPath(targetPath); + if (target && matchesTarget(target->type(), m_detectTargetTypes)) + emit targetDetected(target); +} + +void QNearFieldManagerPrivateImpl::_q_targetDetected(const QDBusObjectPath &targetPath) +{ + if (!m_requestedModes) + emitTargetDetected(targetPath.path()); + else + m_pendingDetectedTargets[targetPath.path()].start(500, this); +} + +void QNearFieldManagerPrivateImpl::_q_targetLost(const QDBusObjectPath &targetPath) +{ + QNearFieldTarget *nearFieldTarget = m_targets.value(targetPath.path()).data(); + + // haven't seen target so just drop this event + if (!nearFieldTarget) { + // We either haven't seen target (started after target was detected by system) or the + // application deleted the target. Remove from map and don't emit anything. + m_targets.remove(targetPath.path()); + return; + } + + if (matchesTarget(nearFieldTarget->type(), m_detectTargetTypes)) + emit targetLost(nearFieldTarget); +} + +#include "moc_qnearfieldmanager_maemo6_p.cpp" |