summaryrefslogtreecommitdiffstats
path: root/src/connectivity/nfc/qnearfieldmanager.cpp
blob: 46b7fbfedcbc2456cbfedcbb24a75f874a4b2315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qnearfieldmanager.h"
#include "qnearfieldmanager_p.h"

#if defined(QT_SIMULATOR)
#include "qnearfieldmanager_simulator_p.h"
#elif defined(Q_OS_SYMBIAN)
#include "qnearfieldmanager_symbian_p.h"
#elif defined(Q_WS_MAEMO_6) || defined (Q_WS_MEEGO)
#include "qnearfieldmanager_maemo6_p.h"
#else
#include "qnearfieldmanagerimpl_p.h"
#endif

#include <QtCore/QMetaType>
#include <QtCore/QMetaMethod>

QTM_BEGIN_NAMESPACE

/*!
    \class QNearFieldManager
    \brief The QNearFieldManager class provides access to notifications for NFC events.

    \ingroup connectivity-nfc
    \inmodule QtConnectivity
    \since 1.2

    NFC Forum devices support two modes of communications.  The first mode, peer-to-peer
    communications, is used to communicate between two NFC Forum devices.  The second mode,
    master/slave communications, is used to communicate between an NFC Forum device and an NFC
    Forum Tag or Contactless Card.  The targetDetected() signal is emitted when a target device
    enters communications range.  Communications can be initiated from the slot connected to this
    signal.

    NFC Forum devices generally operate as the master in master/slave communications. Some devices
    are also capable of operating as the slave, so called Card Emulation mode. In this mode the
    local NFC device emulates a NFC Forum Tag or Contactless Card and can be used to perform
    transactions. The transaction happens entirely within a secure element on the device and only a
    notification of the transaction is provided. The transactionDetected() signal is emitted
    whenever a transaction occurs.

    NFC Forum Tags can contain one or more messages in a standardized format. These messages are
    encapsulated by the QNdefMessage class. Use the registerNdefMessageHandler() functions to
    register message handlers with particular criteria. Handlers can be unregistered with the
    unregisterNdefMessageHandler() function.

    Applications can connect to the targetDetected() and targetLost() signals to get notified when
    an NFC Forum Device or NFC Forum Tag enters or leaves proximity. Before these signals are
    emitted target detection must be started with the startTargetDetection() function, which takes
    a parameter to limit the type of device or tags detected. Target detection can be stopped with
    the stopTargetDetection() function. Before a detected target can be accessed it is necessary to
    request access rights. This must be done before the target device is touched. The
    setTargetAccessModes() function is used to set the types of access the application wants to
    perform on the detected target. When access is no longer required the target access modes
    should be set to NoTargetAccess as other applications may be blocked from accessing targets.
    The current target access modes can be retried with the targetAccessModes() function.


    \section2 Automatically launching NDEF message handlers

    It is possible to pre-register an application to receive NDEF messages matching a given
    criteria. This is useful to get the system to automatically launch your application when a
    matching NDEF message is received. This removes the need to have the user manually launch NDEF
    handling applications, prior to touching a tag, or to have those applications always running
    and using system resources.

    The process of registering the handler is different on each platform. The platform specifics
    are documented in the sections below. Qt Mobility provides a tool, \c {ndefhandlergen}, to
    generate the platform specific registration files. The output of \c {ndefhandlergen -help} is
    reproduced here for convenience:

    \code
        Generate platform specific NFC message handler registration files.
        Usage: nfcxmlgen [options]

            -template TEMPLATE    Template to use.
            -appname APPNAME      Name of the application.
            -apppath APPPATH      Path to installed application binary.
            -datatype DATATYPE    URN of the NDEF message type to match.
            -match MATCHSTRING    Platform specific match string.

        The -datatype and -match options are mutually exclusive.

        Available templates: maemo6, symbian
    \endcode

    A typical invocation of the \c ndefhandlergen tool for Symbian^3 target:

    \code
        ndefhandlergen -template symbian -appname myapplication -datatype urn:nfc:ext:com.example:f
    \endcode

    and for Maemo6 target:

    \code
        ndefhandlergen -template maemo6 -appname myapplication -apppath /usr/bin/myapplication -datatype urn:nfc:ext:com.example:f
    \endcode

    Once the application has been registered as an NDEF message handler, the application only needs
    to call the registerNdefMessageHandler() function:

    \code
        QNearFieldManager *manager = new QNearFieldManager;
        manager->registerNdefMessageHandler(this,
                                            SLOT(handleNdefMessage(QNdefMessage,QNearFieldTarget)));
    \endcode

    \section3 Symbian^3

    On Symbian^3 an xml file needs to be created and installed into a particular directory on the
    device. The format of the xml is given below.

    \quotefile tools/ndefhandlergen/templates/symbian/symbian.xml

    The \i {%APPNAME%} tags need to be changed to match the name of the application. The
    \i description xml tags should be used to describe the application, however these values are
    not used. The \i {%DATATYPE%} tag must be set with the NDEF record type to match  For example
    the following would be used to match NDEF messages that contain a RTD-URI record:

    \code
        <customproperty key="datatype">urn:nfc:wkt:U</customproperty>
    \endcode

    The following would be used to match NDEF messages that contain a custom type
    urn:nfc:ext:example.com:f:

    \code
        <customproperty key="datatype">urn:nfc:ext:com.example:f</customproperty>
    \endcode

    The value of the \i customproperty xml tag can be set to any valid match string supported by
    the Symbian^3 platform.

    It is recommended to name the xml file after the application package name. For example
    myapplication.xml. To install the above xml file into the correct location the following should
    be added to the application .pro file:

    \code
        symbian {
            ndefhandler.sources = myapplication.xml
            ndefhandler.path = /private/2002AC7F/import/
            DEPLOYMENT += ndefhandler
        }
    \endcode

    \section3 Maemo6

    On Maemo6 the NDEF message handler notifications are passed over D-Bus. Registration of the
    NDEF message match criteria is done via a D-Bus call. The application must also ensure that it
    has registered a D-Bus service name so that the application can be automatically launched when
    a notification message is sent to the registered service.

    To register the D-Bus service the two files need to be created and installed into particular
    directories on the device. The first file is the D-Bus bus configuration file:

    \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.conf

    The \i {%APPNAME%} tag must be replaced with the name of your application binary.

    The second file is a D-Bus service file which is used by the D-Bus daemon to launch your
    application.

    \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.service

    The \i {%APPNAME%} tag must be replace with the name of your application binary and the
    \i {%APPPATH%} tag must be replaced with the path to your installed application binary.

    It is recommended to name these files after the application package name. For example
    myapplication.conf and myapplication.service. To install the above files into the correct
    location the following should be added to the application .pro file:

    \code
        maemo6 {
            ndefhandler_conf.sources = myapplication.conf
            ndefhandler_conf.path = /etc/dbus-1/system.d/

            ndefhandler_service.sources = myapplication.service
            ndefhandler_service.path = /usr/share/dbus-1/system-services/

            DEPLOYMENT += ndefhandler_conf ndefhandler_service
        }
    \endcode

    The NDEF message handler is registered with the following D-Bus command. Applications should
    ensure that the following command (or similar) is executed once at installation time. For
    example in the packages post-installation script.

    \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.postinst

    The \i {%APPNAME%} string must be replaced with the name of the application binary. The
    \i {%DATATYPE%} string must be replaced with the NDEF record type to match. For example the
    following would be used to match NDEF messages that contain a RTD-URI record:

    \code
        string:"urn:nfc:wkt:U[1:*];"
    \endcode

    The following would be used to match NDEF messages that contain a custom type
    urn:nfc:ext:example.com:f:

    \code
        string:"urn:nfc:ext:example.com:f[1:*];"
    \endcode

    Note that \c {[1:*]} indicates one or more records of the specified type must be in the NDEF
    message. The value of the datatype string argument can be set to any valid match string
    supported by the Maemo6 platform.

    The NDEF message handler should be unregistered at uninstallation time. For example in the
    packages pre-removal script.

    \quotefile tools/ndefhandlergen/templates/maemo6/maemo6.prerm

    The \i {%APPNAME%} string must be replace with the name of the application binary.
*/

/*!
    \enum QNearFieldManager::TargetAccessMode

    This enum describes the different access modes an application can have.

    \value NoTargetAccess           The application cannot access NFC capabilities.
    \value NdefReadTargetAccess     The application can read NDEF messages from targets by calling
                                    QNearFieldTarget::readNdefMessages().
    \value NdefWriteTargetAccess    The application can write NDEF messages to targets by calling
                                    QNearFieldTarget::writeNdefMessages().
    \value TagTypeSpecificTargetAccess  The application can access targets using raw commands by
                                        calling QNearFieldTarget::sendCommand().
*/

/*!
    \fn void QNearFieldManager::targetDetected(QNearFieldTarget *target)

    This signal is emitted whenever a target is detected. The \a target parameter represents the
    detected target.

    This signal will be emitted for all detected targets.

    QNearFieldManager maintains ownership of \a target, however, it will not be destroyed until
    the QNearFieldManager destructor is called. Ownership may be transferred by calling
    setParent().

    Do not delete \a target from the slot connected to this signal, instead call deleteLater().

    \note that if \a target is deleted before it moves out of proximity the targetLost() signal
    will not be emitted.

    \sa targetLost()
*/

/*!
    \fn void QNearFieldManager::targetLost(QNearFieldTarget *target)

    This signal is emitted whenever a target moves out of proximity. The \a target parameter
    represents the lost target.

    Do not delete \a target from the slot connected to this signal, instead use deleteLater().

    \sa QNearFieldTarget::disconnected()
*/

/*!
    \fn void QNearFieldManager::transactionDetected(const QByteArray &applicationIdentifier)

    This signal is emitted when ever a transaction is performed with the application identified by
    \a applicationIdentifier.

    The \a applicationIdentifier is a byte array of up to 16 bytes as defined by ISO 7816-4 and
    uniquely identifies the application and application vendor that was involved in the
    transaction.
*/

/*!
    \fn int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)

    Registers \a object to receive notifications on \a method when a tag has been detected and has
    an NDEF record that matches template argument.  The \a method on \a object should have the
    prototype 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.

    Returns an identifier, which can be used to unregister the handler, on success; otherwise
    returns -1.

    \note The \i target parameter of \a method may not be available on all platforms, in which case
    \i target will be 0.
*/

/*!
    Constructs a new near field manager with \a parent.
*/
QNearFieldManager::QNearFieldManager(QObject *parent)
:   QObject(parent), d_ptr(new QNearFieldManagerPrivateImpl)
{
    connect(d_ptr, SIGNAL(targetDetected(QNearFieldTarget*)),
            this, SIGNAL(targetDetected(QNearFieldTarget*)));
    connect(d_ptr, SIGNAL(targetLost(QNearFieldTarget*)),
            this, SIGNAL(targetLost(QNearFieldTarget*)));
}

/*!
    \internal

    Constructs a new near field manager with the specified \a backend and with \a parent.

    \note: This constructor is only enable for internal builds and is used for testing the
    simulator backend.
*/
QNearFieldManager::QNearFieldManager(QNearFieldManagerPrivate *backend, QObject *parent)
:   QObject(parent), d_ptr(backend)
{
    connect(d_ptr, SIGNAL(targetDetected(QNearFieldTarget*)),
            this, SIGNAL(targetDetected(QNearFieldTarget*)));
    connect(d_ptr, SIGNAL(targetLost(QNearFieldTarget*)),
            this, SIGNAL(targetLost(QNearFieldTarget*)));
}

/*!
    Destroys the near field manager.
*/
QNearFieldManager::~QNearFieldManager()
{
    delete d_ptr;
}

/*!
    Returns true if NFC functionality is available; otherwise returns false.
*/
bool QNearFieldManager::isAvailable() const
{
    Q_D(const QNearFieldManager);

    return d->isAvailable();
}

/*!
    Starts detecting targets of type \a targetTypes. Returns true if target detection is
    successfully started; otherwise returns false.

    Causes the targetDetected() signal to be emitted when a target with a type in \a targetTypes is
    within proximity. If \a targetTypes is empty targets of all types will be detected.

    \sa stopTargetDetection()
*/
bool QNearFieldManager::startTargetDetection(const QList<QNearFieldTarget::Type> &targetTypes)
{
    Q_D(QNearFieldManager);

    if (targetTypes.isEmpty())
        return d->startTargetDetection(QList<QNearFieldTarget::Type>() << QNearFieldTarget::AnyTarget);
    else
        return d->startTargetDetection(targetTypes);
}

/*!
    \overload

    Starts detecting targets of type \a targetType. Returns true if target detection is
    successfully started; otherwise returns false. Causes the targetDetected() signal to be emitted
    when a target with the type \a targetType is within proximity.
*/
bool QNearFieldManager::startTargetDetection(QNearFieldTarget::Type targetType)
{
    return startTargetDetection(QList<QNearFieldTarget::Type>() << targetType);
}

/*!
    Stops detecting targets.  The targetDetected() signal will no longer be emitted until another
    call to startTargetDetection() is made.
*/
void QNearFieldManager::stopTargetDetection()
{
    Q_D(QNearFieldManager);

    d->stopTargetDetection();
}

static QMetaMethod methodForSignature(QObject *object, const char *method)
{
    QByteArray normalizedMethod = QMetaObject::normalizedSignature(method);

    if (!QMetaObject::checkConnectArgs(SIGNAL(targetDetected(QNdefMessage,QNearFieldTarget*)),
                                       normalizedMethod)) {
        qWarning("Signatures do not match: %s:%d\n", __FILE__, __LINE__);
        return QMetaMethod();
    }

    quint8 memcode = (normalizedMethod.at(0) - '0') & 0x03;
    normalizedMethod = normalizedMethod.mid(1);

    int index;
    switch (memcode) {
    case QSLOT_CODE:
        index = object->metaObject()->indexOfSlot(normalizedMethod.constData());
        break;
    case QSIGNAL_CODE:
        index = object->metaObject()->indexOfSignal(normalizedMethod.constData());
        break;
    case QMETHOD_CODE:
        index = object->metaObject()->indexOfMethod(normalizedMethod.constData());
        break;
    default:
        index = -1;
    }

    if (index == -1)
        return QMetaMethod();

    return object->metaObject()->method(index);
}

/*!
    Registers \a object to receive notifications on \a method when a tag has been detected and has
    an NDEF record that matches \a typeNameFormat and \a type.  The \a method on \a object should
    have the prototype
    'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.

    Returns an identifier, which can be used to unregister the handler, on success; otherwise
    returns -1.

    \note The \i target parameter of \a method may not be available on all platforms, in which case
    \i target will be 0.
*/

int QNearFieldManager::registerNdefMessageHandler(QNdefRecord::TypeNameFormat typeNameFormat,
                                                  const QByteArray &type,
                                                  QObject *object, const char *method)
{
    QMetaMethod metaMethod = methodForSignature(object, method);
    if (!metaMethod.enclosingMetaObject())
        return -1;

    QNdefFilter filter;
    filter.appendRecord(typeNameFormat, type);

    Q_D(QNearFieldManager);

    return d->registerNdefMessageHandler(filter, object, metaMethod);
}

/*!
    Registers \a object to receive notifications on \a method when a tag has been detected and has
    an NDEF message that matches a pre-registered message format. The \a method on \a object should
    have the prototype
    'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.

    Returns an identifier, which can be used to unregister the handler, on success; otherwise
    returns -1.

    This function is used to register a QNearFieldManager instance to receive notifications when a
    NDEF message matching a pre-registered message format is received. See the section on
    \l {Automatically launching NDEF message handlers}.

    \note The \i target parameter of \a method may not be available on all platforms, in which case
    \i target will be 0.
*/
int QNearFieldManager::registerNdefMessageHandler(QObject *object, const char *method)
{
    QMetaMethod metaMethod = methodForSignature(object, method);
    if (!metaMethod.enclosingMetaObject())
        return -1;

    Q_D(QNearFieldManager);

    return d->registerNdefMessageHandler(object, metaMethod);
}

/*!
    Registers \a object to receive notifications on \a method when a tag has been detected and has
    an NDEF message that matches \a filter is detected. The \a method on \a object should have the
    prototype 'void targetDetected(const QNdefMessage &message, QNearFieldTarget *target)'.

    Returns an identifier, which can be used to unregister the handler, on success; otherwise
    returns -1.

    \note The \i target parameter of \a method may not be available on all platforms, in which case
    \i target will be 0.
*/
int QNearFieldManager::registerNdefMessageHandler(const QNdefFilter &filter,
                                                  QObject *object, const char *method)
{
    QMetaMethod metaMethod = methodForSignature(object, method);
    if (!metaMethod.enclosingMetaObject())
        return -1;

    Q_D(QNearFieldManager);

    return d->registerNdefMessageHandler(filter, object, metaMethod);
}

/*!
    Unregisters the target detect handler identified by \a handlerId.

    Returns true on success; otherwise returns false.
*/
bool QNearFieldManager::unregisterNdefMessageHandler(int handlerId)
{
    Q_D(QNearFieldManager);

    return d->unregisterNdefMessageHandler(handlerId);
}

/*!
    Sets the requested target access modes to \a accessModes.
*/
void QNearFieldManager::setTargetAccessModes(TargetAccessModes accessModes)
{
    Q_D(QNearFieldManager);

    TargetAccessModes removedModes = ~accessModes & d->m_requestedModes;
    if (removedModes)
        d->releaseAccess(removedModes);

    TargetAccessModes newModes = accessModes & ~d->m_requestedModes;
    if (newModes)
        d->requestAccess(newModes);
}

/*!
    Returns current requested target access modes.
*/
QNearFieldManager::TargetAccessModes QNearFieldManager::targetAccessModes() const
{
    Q_D(const QNearFieldManager);

    return d->m_requestedModes;
}

#include "moc_qnearfieldmanager.cpp"
#include "moc_qnearfieldmanager_p.cpp"

QTM_END_NAMESPACE