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
qiosnfcndefsessiondelegate.mm
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include "qndefmessage.h"
8
9#include <QtCore/qscopeguard.h>
10#include <QtCore/qbytearray.h>
11#include <QtCore/qstring.h>
12#include <QtCore/qdebug.h>
13
14#include <memory>
15
17
18dispatch_queue_t qt_Nfc_Queue()
19{
20 static dispatch_queue_t nfcQueue = []{
21 auto queue = dispatch_queue_create("qt-NFC-queue", DISPATCH_QUEUE_SERIAL);
22 if (!queue)
23 qCWarning(QT_IOS_NFC, "Failed to create the QtNfc's dispatch queue");
24 return queue;
25 }();
26 static const auto queueGuard = qScopeGuard([]{
27 if (nfcQueue)
28 dispatch_release(nfcQueue);
29 });
30 return nfcQueue;
31}
32
34
36
38{
39 std::unique_ptr<QNfcNdefNotifier> notifier;
41 NFCNDEFStatus tagStatus;
44}
45
46-(instancetype)initWithNotifier:(QNfcNdefNotifier *)aNotifier
47{
48 Q_ASSERT(aNotifier);
49
50 if (self = [super init]) {
51 auto queue = qt_Nfc_Queue();
52 if (!queue)
53 return self;
54
55 tagStatus = NFCNDEFStatusNotSupported;
56 capacity = 0;
57 notifier.reset(aNotifier);
58 }
59
60 return self;
61}
62
63-(void)dealloc
64{
65 [self abort];
66 [super dealloc];
67}
68
69-(QNfcNdefNotifier *)ndefNotifier
70{
71 return notifier.get();
72}
73
74-(void)abort
75{
76 notifier.reset(nullptr);
77 [self reset];
78}
79
80-(bool)startSession
81{
82 if (self.session)
83 return true;
84
85 auto queue = qt_Nfc_Queue();
87 self.session = [[NFCNDEFReaderSession alloc] initWithDelegate:self queue:queue invalidateAfterFirstRead:NO];
88 if (alertMessage.size())
89 self.session.alertMessage = alertMessage.toNSString();
90
91 if (!self.session)
92 return false;
93
94 qCDebug(QT_IOS_NFC, "Starting NFC NDEF reader session");
95 [self.session beginSession];
96 return true;
97}
98
99-(void)reset
100{
101 self.session = nil; // Strong property, releases.
102 self.ndefTag = nil; // Strong property, releases.
103 requestId = {};
104 tagStatus = NFCNDEFStatusNotSupported;
105 capacity = 0;
106}
107
108-(void)stopSession:(const QString &)message
109{
110 if (!self.session)
111 return;
112
113 if (self.ndefTag && notifier.get())
114 emit notifier->tagLost(self.ndefTag);
115
116 if (message.size())
117 [self.session invalidateSessionWithErrorMessage:message.toNSString()];
118 else
119 [self.session invalidateSession];
120
121 [self reset];
122}
123
124-(void)setAlertMessage:(const QString &)message
125{
127}
128
129-(void)readerSession:(NFCNDEFReaderSession *)session
130 didInvalidateWithError:(NSError *)error
131{
132 if (session != self.session) // If we stopped the session, this maybe the case.
133 return;
134
135 if (!notifier.get()) // Aborted.
136 return;
137
138 NSLog(@"session did invalidate with error %@", error);
139
140 if (error.code != NFCReaderSessionInvalidationErrorUserCanceled && error.code != NFCReaderErrorUnsupportedFeature) {
141 if (self.ndefTag)
143
144 emit notifier->invalidateWithError(true);
145 [self reset];
146 }
147
148 // Native errors:
149 //
150 // NFCReaderErrorRadioDisabled
151 // NFCReaderErrorUnsupportedFeature
152 // NFCReaderErrorSecurityViolation
153 // NFCReaderErrorInvalidParameter
154 // NFCReaderErrorParameterOutOfBound
155 // NFCReaderErrorInvalidParameterLength
156 // NFCReaderTransceiveErrorTagConnectionLost
157 // NFCReaderTransceiveErrorRetryExceeded
158 // NFCReaderTransceiveErrorSessionInvalidated
159 // NFCReaderTransceiveErrorTagNotConnected
160 // NFCReaderTransceiveErrorPacketTooLong
161 // NFCReaderSessionInvalidationErrorUserCanceled
162 // NFCReaderSessionInvalidationErrorSessionTimeout
163 // NFCReaderSessionInvalidationErrorSessionTerminatedUnexpectedly
164 // NFCReaderSessionInvalidationErrorSystemIsBusy
165 // NFCReaderSessionInvalidationErrorFirstNDEFTagRead
166 // NFCTagCommandConfigurationErrorInvalidParameters
167 // NFCNdefReaderSessionErrorTagNotWritable
168 // NFCNdefReaderSessionErrorTagUpdateFailure
169 // NFCNdefReaderSessionErrorTagSizeTooSmall
170 //NFCNdefReaderSessionErrorZeroLengthMessage
171
172 // And these are what Qt has ...
173 /*
174 enum Error {
175 NoError,
176 UnknownError,
177 UnsupportedError,
178 TargetOutOfRangeError,
179 NoResponseError,
180 ChecksumMismatchError,
181 InvalidParametersError,
182 ConnectionError,
183 NdefReadError,
184 NdefWriteError,
185 CommandError,
186 TimeoutError
187 };
188 */
189 // TODO: try to map those native errors to Qt ones ...
190}
191
192-(void)readerSession:(NFCNDEFReaderSession *)session
193 didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages
194{
195 Q_UNUSED(session);
196 Q_UNUSED(messages);
197 // It's intentionally a noop and should never be called, because
198 // we implement the other method, giving us access to a tag.
199 Q_UNREACHABLE();
200}
201
202-(void)restartPolling
203{
204 if (!self.session)
205 return;
206
207 auto queue = qt_Nfc_Queue();
209
210 dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
211 int64_t(100./1000. * NSEC_PER_SEC)),//100 ms
212 queue,
213 ^{
214 [self.session restartPolling];
215 });
216}
217
218-(void)tag:(id<NFCNDEFTag>)tag didUpdateNDEFStatus:(NFCNDEFStatus)status
219 capacity:(NSUInteger)aCapacity error:(NSError *)error
220{
221 if (!notifier.get()) // Aborted.
222 return;
223
224 if (tag != self.ndefTag)
225 return;
226
227 if (error) {
228 NSLog(@"Querying NDEF tag's status failed: %@, restarting polling ...", error);
229 self.ndefTag = nil;
230 return [self restartPolling];
231 }
232
233 tagStatus = status;
234 capacity = aCapacity;
235
236 if (status == NFCNDEFStatusNotSupported) {
237 qCDebug(QT_IOS_NFC, "The discovered tag does not support NDEF.");
238 return [self restartPolling];
239 }
240
241 if (status == NFCNDEFStatusReadWrite)
242 qCDebug(QT_IOS_NFC, "NDEF read/write capable tag found");
243
244 if (status == NFCNDEFStatusReadOnly)
245 qCDebug(QT_IOS_NFC, "The discovered tag is read only");
246
247 qCInfo(QT_IOS_NFC) << "The max message size for the tag is:" << capacity;
248
249 [self.session connectToTag:self.ndefTag completionHandler:^(NSError * _Nullable error) {
250 if (!error) {
251 if (notifier.get())
252 emit notifier->tagDetected(self.ndefTag);
253 } else {
254 NSLog(@"Failed to connect to NDEF-capable tag, error: %@", error);
255 [self restartPolling];
256 }
257 }];
258}
259
260
261-(void)readerSession:(NFCNDEFReaderSession *)session
262 didDetectTags:(NSArray<__kindof id<NFCNDEFTag>> *)tags
263{
264 if (!notifier.get())
265 return; // Aborted by Qt.
266
267 if (session != self.session) // We stopped _that_ session.
268 return;
269
270 if (tags.count != 1) {
271 qCWarning(QT_IOS_NFC, "Unexpected number of NDEF tags, restarting ...");
272 [self restartPolling];
273 return;
274 }
275
276 NSLog(@"detected a tag! %@", tags[0]);
277
278 id<NFCNDEFTag> tag = tags[0];
279 self.ndefTag = tag; // Strong reference, retains.
280 tagStatus = NFCNDEFStatusNotSupported;
281 capacity = 0;
282
283 [self.ndefTag queryNDEFStatusWithCompletionHandler:
284 ^(NFCNDEFStatus status, NSUInteger aCapacity, NSError * _Nullable error) {
285 [self tag:tag didUpdateNDEFStatus:status capacity:aCapacity error:error];
286 }];
287}
288
289-(void)readerSessionDidBecomeActive:(NFCNDEFReaderSession *)session
290{
291 if (session != self.session)
292 return [session invalidateSession];
293
294 qCInfo(QT_IOS_NFC, "session is active now");
295}
296
297@end
298
DarwinBluetooth::LECBManagerNotifier * notifier
\inmodule QtNfc \inheaderfile QNearFieldTarget
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
Combined button and popup list for selecting options.
QString self
Definition language.cpp:58
unsigned long NSUInteger
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError * error
NSUInteger capacity
QNearFieldTarget::RequestId requestId
QT_BEGIN_NAMESPACE dispatch_queue_t qt_Nfc_Queue()
NFCNDEFStatus tagStatus
QString alertMessage
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLuint GLsizei const GLchar * message
GLboolean reset
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define emit
#define Q_UNUSED(x)
QQueue< int > queue
[0]