Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnearfieldmanager_ios.mm
Go to the documentation of this file.
1// Copyright (C) 2020 Governikus GmbH & Co. KG
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
9
11
12#include <QDateTime>
13
14#include <memory>
15
16#import <CoreNFC/NFCReaderSession.h>
17#import <CoreNFC/NFCNDEFReaderSession.h>
18#import <CoreNFC/NFCTagReaderSession.h>
19
21
23{
24 auto notifier = std::make_unique<QNfcNdefNotifier>();
25
26 if (@available(iOS 13, *))
27 delegate = [[QT_MANGLE_NAMESPACE(QIosTagReaderDelegate) alloc] initWithListener:this];
28
30 this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
33 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
35
36 ndefDelegate = [[QIosNfcNdefSessionDelegate alloc] initWithNotifier:notifier.get()];
37 if (ndefDelegate) {
38 auto watchDog = notifier.release(); // Delegate took the ownership.
39
41 this, &QNearFieldManagerPrivateImpl::onTagDiscovered,
44 this, &QNearFieldManagerPrivateImpl::onDidInvalidateWithError,
46 } else {
47 qCWarning(QT_IOS_NFC, "Failed to allocate NDEF reading session's delegate");
48 }
49
50 sessionTimer.setInterval(2000);
51 sessionTimer.setSingleShot(true);
52 connect(&sessionTimer, &QTimer::timeout, this, &QNearFieldManagerPrivateImpl::onSessionTimer);
53}
54
56{
57 if (@available(iOS 13, *))
58 [delegate release];
59
60 if (!ndefDelegate)
61 return;
62
63 if (auto queue = qt_Nfc_Queue()) {
64 dispatch_sync(queue, ^{
65 [ndefDelegate abort];
66 });
67 }
68
69 [ndefDelegate release];
70}
71
73{
74 switch (accessMethod) {
77 return NFCNDEFReaderSession.readingAvailable;
79 if (@available(iOS 13, *))
80 return NFCTagReaderSession.readingAvailable;
83 return false;
84 }
85}
86
88{
89 if (detectionRunning)
90 return false;
91
92 activeAccessMethod = QNearFieldTarget::UnknownAccess;
93
94 switch (accessMethod) {
97 return false;
99 if (@available(iOS 13, *))
100 if (NFCTagReaderSession.readingAvailable) {
101 detectionRunning = scheduleSession(accessMethod);
102 if (detectionRunning)
103 activeAccessMethod = accessMethod;
104 return detectionRunning;
105 }
106 return false;
108 if (NFCNDEFReaderSession.readingAvailable) {
109 detectionRunning = scheduleSession(accessMethod);
110 if (detectionRunning)
111 activeAccessMethod = accessMethod;
112 return detectionRunning;
113 }
114 return false;
115 }
116
117 return false;
118}
119
121{
122 if (!detectionRunning)
123 return;
124
125 isSessionScheduled = false;
126
127 if (activeAccessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
128 stopSession(errorMessage);
129 } else if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
130 stopNdefSession(errorMessage);
131 } else {
132 qCWarning(QT_IOS_NFC, "Unknown access method, cannot stop target detection");
133 return;
134 }
135
136 detectionRunning = false;
138}
139
140bool QNearFieldManagerPrivateImpl::scheduleSession(QNearFieldTarget::AccessMethod accessMethod)
141{
142 if (sessionTimer.isActive()) {
143 isSessionScheduled = true;
144 return true;
145 }
146 isSessionScheduled = false;
147
148 if (accessMethod == QNearFieldTarget::TagTypeSpecificAccess) {
149 startSession();
150 return true;
151 } else if (accessMethod == QNearFieldTarget::NdefAccess) {
152 return startNdefSession();
153 }
154
155 return false;
156}
157
158void QNearFieldManagerPrivateImpl::startSession()
159{
160 if (@available(iOS 13, *)) {
161 [delegate startSession];
162 }
163}
164
165bool QNearFieldManagerPrivateImpl::startNdefSession()
166{
167 if (!ndefDelegate)
168 return false;
169
170 if (auto queue = qt_Nfc_Queue()) {
171 __block bool startSessionSucceded = false;
172 dispatch_sync(queue, ^{ startSessionSucceded = [ndefDelegate startSession]; });
173 return startSessionSucceded;
174 }
175
176 return false;
177}
178
179void QNearFieldManagerPrivateImpl::stopSession(const QString &error)
180{
182
183 clearTargets();
184
185 if (@available(iOS 13, *)) {
186 [delegate stopSession:error];
187 }
188}
189
190void QNearFieldManagerPrivateImpl::stopNdefSession(const QString &error)
191{
192 Q_ASSERT(activeAccessMethod == QNearFieldTarget::NdefAccess);
193
194 clearTargets();
195
196 if (auto queue = qt_Nfc_Queue()) {
197 dispatch_sync(queue, ^{
198 [ndefDelegate stopSession:error];
199 });
200 }
201}
202
203void QNearFieldManagerPrivateImpl::clearTargets()
204{
205 auto i = detectedTargets.begin();
206 while (i != detectedTargets.end()) {
207 (*i)->invalidate();
208 i = detectedTargets.erase(i);
209 }
210}
211
212
214{
215 if (activeAccessMethod != QNearFieldTarget::NdefAccess)
216 [delegate alertMessage:message];
217
218 if (detectionRunning) {
219 // Too late!
220 qCWarning(QT_IOS_NFC,
221 "User information must be set prior before the target detection started");
222 return;
223 }
224
225 if (auto queue = qt_Nfc_Queue()) {
226 dispatch_sync(queue, ^{
227 [ndefDelegate setAlertMessage:message];
228 });
229 }
230}
231
232void QNearFieldManagerPrivateImpl::onTagDiscovered(void *tag)
233{
235 if (activeAccessMethod == QNearFieldTarget::NdefAccess) {
236 [id(tag) retain];
237 target = new QNearFieldTargetPrivateImpl(ndefDelegate, tag);
238 } else {
240 }
241
242 detectedTargets += target;
243
245 this, &QNearFieldManagerPrivateImpl::onTargetLost);
247}
248
249void QNearFieldManagerPrivateImpl::onTargetLost(QNearFieldTargetPrivateImpl *target)
250{
251 detectedTargets.removeOne(target);
252 Q_EMIT targetLost(target->q_ptr);
253
254 if (detectionRunning && detectedTargets.isEmpty())
255 onDidInvalidateWithError(true);
256}
257
258void QNearFieldManagerPrivateImpl::onDidInvalidateWithError(bool doRestart)
259{
260 clearTargets();
261 sessionTimer.start();
262
263 if (detectionRunning && doRestart && scheduleSession(activeAccessMethod))
264 return;
265
266 detectionRunning = false;
268}
269
270void QNearFieldManagerPrivateImpl::onSessionTimer()
271{
272 if (isSessionScheduled && !scheduleSession(activeAccessMethod)) {
273 detectionRunning = false;
275 }
276}
277
DarwinBluetooth::LECBManagerNotifier * notifier
std::unique_ptr< QTimer > watchDog
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
iterator erase(const_iterator it)
Definition qhash.h:1233
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:928
void didInvalidateWithError(bool doRestart)
bool isSupported(QNearFieldTarget::AccessMethod accessMethod) const override
void tagDiscovered(void *tag)
bool startTargetDetection(QNearFieldTarget::AccessMethod accessMethod) override
void setUserInformation(const QString &message) override
void stopTargetDetection(const QString &errorMessage) override
void targetDetected(QNearFieldTarget *target)
void targetLost(QNearFieldTarget *target)
void targetLost(QNearFieldTargetPrivateImpl *target)
The QNearFieldTarget class provides an interface for communicating with a target device.
AccessMethod
This enum describes the access methods a near field target supports.
void tagDetected(void *tag)
void invalidateWithError(bool restart)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void setSingleShot(bool singleShot)
Definition qtimer.cpp:552
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
void setInterval(int msec)
Definition qtimer.cpp:579
bool isActive() const
Returns true if the timer is running (pending); otherwise returns false.
Definition qtimer.cpp:167
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
Combined button and popup list for selecting options.
@ QueuedConnection
#define Q_FALLTHROUGH()
AudioChannelLayoutTag tag
DBusConnection const char DBusError * error
QT_BEGIN_NAMESPACE dispatch_queue_t qt_Nfc_Queue()
QString alertMessage
#define qCWarning(category,...)
GLenum GLuint id
[7]
GLenum target
GLuint GLsizei const GLchar * message
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QT_MANGLE_NAMESPACE(name)
#define Q_EMIT
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3517
sem release()
QQueue< int > queue
[0]