1// Copyright (C) 2016 - 2012 Research In Motion
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qndefnfcsmartposterrecord.h>
5#include "qndefnfcsmartposterrecord_p.h"
6#include <qndefmessage.h>
7
8#include <QtCore/QString>
9#include <QtCore/QStringList>
10#include <QtCore/QUrl>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \class QNdefNfcIconRecord
16 \brief The QNdefNfcIconRecord class provides an NFC MIME record to hold an
17 icon.
18
19 \ingroup connectivity-nfc
20 \inmodule QtNfc
21 \since Qt 5.2
22
23 This class wraps the image data into an NDEF message.
24 It provides an NDEF record of type \l QNdefRecord::Mime.
25 The \l {QNdefRecord::}{payload}() contains the raw image data.
26*/
27
28/*!
29 \fn QNdefNfcIconRecord::QNdefNfcIconRecord()
30
31 Constructs an empty NDEF record of type \l QNdefRecord::Mime.
32*/
33
34/*!
35 \fn QNdefNfcIconRecord::QNdefNfcIconRecord(const QNdefRecord &other)
36
37 Constructs an NDEF icon record that is a copy of \a other.
38*/
39
40/*!
41 \class QNdefNfcSmartPosterRecord
42 \brief The QNdefNfcSmartPosterRecord class provides an NFC RTD-SmartPoster.
43
44 \ingroup connectivity-nfc
45 \inmodule QtNfc
46 \since Qt 5.2
47
48 RTD-SmartPoster encapsulates a Smart Poster.
49 */
50
51/*!
52 \enum QNdefNfcSmartPosterRecord::Action
53
54 This enum describes the course of action that a device should take with the content.
55
56 \value UnspecifiedAction The action is not defined.
57 \value DoAction Do the action (send the SMS, launch the browser, make the telephone call).
58 \value SaveAction Save for later (store the SMS in INBOX, put the URI in a bookmark, save the telephone number in contacts).
59 \value EditAction Open for editing (open an SMS in the SMS editor, open the URI in a URI editor, open the telephone number for editing).
60 */
61
62/*!
63 Constructs a new empty smart poster.
64*/
65QNdefNfcSmartPosterRecord::QNdefNfcSmartPosterRecord()
66 : QNdefRecord(QNdefRecord::NfcRtd, "Sp"),
67 d(new QNdefNfcSmartPosterRecordPrivate)
68{
69}
70
71/*!
72 Constructs a new smart poster that is a copy of \a other.
73*/
74QNdefNfcSmartPosterRecord::QNdefNfcSmartPosterRecord(const QNdefRecord &other)
75 : QNdefRecord(other, QNdefRecord::NfcRtd, "Sp"),
76 d(new QNdefNfcSmartPosterRecordPrivate)
77{
78 // Need to set payload again to create internal structure
79 setPayload(other.payload());
80}
81
82/*!
83 Constructs a new smart poster that is a copy of \a other.
84*/
85QNdefNfcSmartPosterRecord::QNdefNfcSmartPosterRecord(const QNdefNfcSmartPosterRecord &other)
86 : QNdefRecord(other, QNdefRecord::NfcRtd, "Sp"), d(other.d)
87{
88}
89
90/*!
91 Assigns the \a other smart poster record to this record and returns a reference to
92 this record.
93*/
94QNdefNfcSmartPosterRecord &QNdefNfcSmartPosterRecord::operator=(const QNdefNfcSmartPosterRecord &other)
95{
96 if (this != &other)
97 d = other.d;
98
99 return *this;
100}
101
102/*!
103 Destroys the smart poster.
104*/
105QNdefNfcSmartPosterRecord::~QNdefNfcSmartPosterRecord()
106{
107}
108
109void QNdefNfcSmartPosterRecord::cleanup()
110{
111 if (d) {
112 // Clean-up existing internal structure
113 d->m_titleList.clear();
114 if (d->m_uri) delete d->m_uri;
115 if (d->m_action) delete d->m_action;
116 d->m_iconList.clear();
117 if (d->m_size) delete d->m_size;
118 if (d->m_type) delete d->m_type;
119 }
120}
121
122/*!
123 \internal
124 Sets the payload of the NDEF record to \a payload
125*/
126void QNdefNfcSmartPosterRecord::setPayload(const QByteArray &payload)
127{
128 QNdefRecord::setPayload(payload);
129
130 cleanup();
131
132 if (!payload.isEmpty()) {
133 // Create new structure
134 const QNdefMessage message = QNdefMessage::fromByteArray(message: payload);
135
136 // Iterate through all the records contained in the payload's message.
137 for (const QNdefRecord& record : message) {
138 // Title
139 if (record.isRecordType<QNdefNfcTextRecord>()) {
140 addTitleInternal(text: record);
141 }
142
143 // URI
144 else if (record.isRecordType<QNdefNfcUriRecord>()) {
145 d->m_uri = new QNdefNfcUriRecord(record);
146 }
147
148 // Action
149 else if (record.isRecordType<QNdefNfcActRecord>()) {
150 d->m_action = new QNdefNfcActRecord(record);
151 }
152
153 // Icon
154 else if (record.isRecordType<QNdefNfcIconRecord>()) {
155 addIconInternal(icon: record);
156 }
157
158 // Size
159 else if (record.isRecordType<QNdefNfcSizeRecord>()) {
160 d->m_size = new QNdefNfcSizeRecord(record);
161 }
162
163 // Type
164 else if (record.isRecordType<QNdefNfcTypeRecord>()) {
165 d->m_type = new QNdefNfcTypeRecord(record);
166 }
167 }
168 }
169}
170
171void QNdefNfcSmartPosterRecord::convertToPayload()
172{
173 QNdefMessage message;
174
175 // Title
176 for (qsizetype t = 0; t < titleCount(); t++)
177 message.append(t: titleRecord(index: t));
178
179 // URI
180 if (d->m_uri)
181 message.append(t: *(d->m_uri));
182
183 // Action
184 if (d->m_action)
185 message.append(t: *(d->m_action));
186
187 // Icon
188 for (qsizetype i = 0; i < iconCount(); i++)
189 message.append(t: iconRecord(index: i));
190
191 // Size
192 if (d->m_size)
193 message.append(t: *(d->m_size));
194
195 // Type
196 if (d->m_type)
197 message.append(t: *(d->m_type));
198
199 QNdefRecord::setPayload(message.toByteArray());
200}
201
202/*!
203 Returns \c true if the smart poster contains a title record using the locale
204 \a locale. If \a locale is empty, then \c true is returned if the smart
205 poster contains at least one title record. In all other cases, \c false is
206 returned.
207 */
208bool QNdefNfcSmartPosterRecord::hasTitle(const QString &locale) const
209{
210 for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
211 const QNdefNfcTextRecord &text = d->m_titleList[i];
212
213 if (locale.isEmpty() || text.locale() == locale)
214 return true;
215 }
216
217 return false;
218}
219
220/*!
221 Returns \c true if the smart poster contains an action record, otherwise
222 returns \c false.
223 */
224bool QNdefNfcSmartPosterRecord::hasAction() const
225{
226 return d->m_action != nullptr;
227}
228
229/*!
230 Returns \c true if the smart poster contains an icon record using the type
231 \a mimetype. If \a mimetype is empty, then \c true is returned if the smart
232 poster contains at least one icon record.
233 In all other cases, \c false is returned.
234 */
235bool QNdefNfcSmartPosterRecord::hasIcon(const QByteArray &mimetype) const
236{
237 for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
238 const QNdefNfcIconRecord &icon = d->m_iconList[i];
239
240 if (mimetype.isEmpty() || icon.type() == mimetype)
241 return true;
242 }
243
244 return false;
245}
246
247/*!
248 Returns \c true if the smart poster contains a size record, otherwise
249 returns \c false.
250 */
251bool QNdefNfcSmartPosterRecord::hasSize() const
252{
253 return d->m_size != nullptr;
254}
255
256/*!
257 Returns \c true if the smart poster contains a type record, otherwise
258 returns \c false.
259 */
260bool QNdefNfcSmartPosterRecord::hasTypeInfo() const
261{
262 return d->m_type != nullptr;
263}
264
265/*!
266 Returns the number of title records contained inside the smart poster.
267 */
268qsizetype QNdefNfcSmartPosterRecord::titleCount() const
269{
270 return d->m_titleList.size();
271}
272
273/*!
274 Returns the title record corresponding to the index \a index inside the
275 smart poster, where \a index is a value between 0 and titleCount() - 1.
276 Values outside of this range return an empty record.
277 */
278QNdefNfcTextRecord QNdefNfcSmartPosterRecord::titleRecord(qsizetype index) const
279{
280 if (index >= 0 && index < d->m_titleList.size())
281 return d->m_titleList[index];
282
283 return QNdefNfcTextRecord();
284}
285
286/*!
287 Returns the title record text associated with locale \a locale if available. If \a locale
288 is empty then the title text of the first available record is returned. In all other
289 cases an empty string is returned.
290 */
291QString QNdefNfcSmartPosterRecord::title(const QString &locale) const
292{
293 for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
294 const QNdefNfcTextRecord &text = d->m_titleList[i];
295
296 if (locale.isEmpty() || text.locale() == locale)
297 return text.text();
298 }
299
300 return QString();
301}
302
303/*!
304 Returns a copy of all title records inside the smart poster.
305 */
306QList<QNdefNfcTextRecord> QNdefNfcSmartPosterRecord::titleRecords() const
307{
308 return d->m_titleList;
309}
310
311/*!
312 Attempts to add a title record \a text to the smart poster. If the smart poster does not already
313 contain a title record with the same locale as title record \a text, then the title record is added
314 and the function returns \c true. Otherwise \c false is returned.
315 */
316bool QNdefNfcSmartPosterRecord::addTitle(const QNdefNfcTextRecord &text)
317{
318 const bool status = addTitleInternal(text);
319
320 // Convert to payload if the title is added
321 if (status)
322 convertToPayload();
323
324 return status;
325}
326
327bool QNdefNfcSmartPosterRecord::addTitleInternal(const QNdefNfcTextRecord &text)
328{
329 for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
330 const QNdefNfcTextRecord &rec = d->m_titleList[i];
331
332 if (rec.locale() == text.locale())
333 return false;
334 }
335
336 d->m_titleList.append(t: text);
337 return true;
338}
339
340/*!
341 Attempts to add a new title record with title \a text, locale \a locale and encoding \a encoding.
342 If the smart poster does not already contain a title record with locale \a locale, then the title record
343 is added and the function returns \c true. Otherwise \c false is returned.
344 */
345bool QNdefNfcSmartPosterRecord::addTitle(const QString &text, const QString &locale, QNdefNfcTextRecord::Encoding encoding)
346{
347 QNdefNfcTextRecord rec;
348 rec.setText(text);
349 rec.setLocale(locale);
350 rec.setEncoding(encoding);
351
352 return addTitle(text: rec);
353}
354
355/*!
356 Attempts to remove the title record \a text from the smart poster. Removes
357 the record and returns \c true if the smart poster contains a matching
358 record, otherwise \c false is returned.
359 */
360bool QNdefNfcSmartPosterRecord::removeTitle(const QNdefNfcTextRecord &text)
361{
362 bool status = false;
363
364 for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
365 const QNdefNfcTextRecord &rec = d->m_titleList[i];
366
367 if (rec.text() == text.text() && rec.locale() == text.locale() && rec.encoding() == text.encoding()) {
368 d->m_titleList.removeAt(i);
369 status = true;
370 break;
371 }
372 }
373
374 // Convert to payload if the title list has changed
375 if (status)
376 convertToPayload();
377
378 return status;
379}
380
381/*!
382 Attempts to remove a title record with the locale \a locale from the smart
383 poster. Removes the record and returns \c true if the smart poster contains
384 a matching record, otherwise \c false is returned.
385 */
386bool QNdefNfcSmartPosterRecord::removeTitle(const QString &locale)
387{
388 bool status = false;
389
390 for (qsizetype i = 0; i < d->m_titleList.size(); ++i) {
391 const QNdefNfcTextRecord &rec = d->m_titleList[i];
392
393 if (rec.locale() == locale) {
394 d->m_titleList.removeAt(i);
395 status = true;
396 break;
397 }
398 }
399
400 // Convert to payload if the title list has changed
401 if (status)
402 convertToPayload();
403
404 return status;
405}
406
407/*!
408 Adds the title record list \a titles to the smart poster. Any existing records are overwritten.
409 */
410void QNdefNfcSmartPosterRecord::setTitles(const QList<QNdefNfcTextRecord> &titles)
411{
412 d->m_titleList.clear();
413
414 for (qsizetype i = 0; i < titles.size(); ++i) {
415 d->m_titleList.append(t: titles[i]);
416 }
417
418 // Convert to payload
419 convertToPayload();
420}
421
422/*!
423 Returns the URI from the smart poster's URI record if set. Otherwise an empty URI is returned.
424 */
425QUrl QNdefNfcSmartPosterRecord::uri() const
426{
427 if (d->m_uri)
428 return d->m_uri->uri();
429
430 return QUrl();
431}
432
433/*!
434 Returns the smart poster's URI record if set. Otherwise an empty URI is returned.
435 */
436QNdefNfcUriRecord QNdefNfcSmartPosterRecord::uriRecord() const
437{
438 if (d->m_uri)
439 return *(d->m_uri);
440
441 return QNdefNfcUriRecord();
442}
443
444/*!
445 Sets the URI record to \a url
446 */
447void QNdefNfcSmartPosterRecord::setUri(const QNdefNfcUriRecord &url)
448{
449 if (d->m_uri)
450 delete d->m_uri;
451
452 d->m_uri = new QNdefNfcUriRecord(url);
453
454 // Convert to payload
455 convertToPayload();
456}
457
458/*!
459 Constructs a URI record and sets its content inside the smart poster to \a url
460 */
461void QNdefNfcSmartPosterRecord::setUri(const QUrl &url)
462{
463 QNdefNfcUriRecord rec;
464 rec.setUri(url);
465
466 setUri(rec);
467}
468
469/*!
470 Returns the action from the action record if available. Otherwise \l UnspecifiedAction is returned.
471 */
472QNdefNfcSmartPosterRecord::Action QNdefNfcSmartPosterRecord::action() const
473{
474 if (d->m_action)
475 return d->m_action->action();
476
477 return UnspecifiedAction;
478}
479
480/*!
481 Sets the action record to \a act
482 */
483void QNdefNfcSmartPosterRecord::setAction(Action act)
484{
485 if (!d->m_action)
486 d->m_action = new QNdefNfcActRecord();
487
488 d->m_action->setAction(act);
489
490 // Convert to payload
491 convertToPayload();
492}
493
494/*!
495 Returns the number of icon records contained inside the smart poster.
496 */
497qsizetype QNdefNfcSmartPosterRecord::iconCount() const
498{
499 return d->m_iconList.size();
500}
501
502/*!
503 Returns the icon record corresponding to the index \a index inside the smart
504 poster, where \a index is a value between 0 and \l iconCount() - 1.
505 Values outside of this range return an empty record.
506 */
507QNdefNfcIconRecord QNdefNfcSmartPosterRecord::iconRecord(qsizetype index) const
508{
509 if (index >= 0 && index < d->m_iconList.size())
510 return d->m_iconList[index];
511
512 return QNdefNfcIconRecord();
513}
514
515/*!
516 Returns the associated icon record data if the smart poster contains an icon record with MIME type \a mimetype.
517 If \a mimetype is omitted or empty then the first icon's record data is returned. In all other cases, an empty array is returned.
518 */
519QByteArray QNdefNfcSmartPosterRecord::icon(const QByteArray& mimetype) const
520{
521 for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
522 const QNdefNfcIconRecord &icon = d->m_iconList[i];
523
524 if (mimetype.isEmpty() || icon.type() == mimetype)
525 return icon.data();
526 }
527
528 return QByteArray();
529}
530
531/*!
532 Returns a copy of all icon records inside the smart poster.
533 */
534QList<QNdefNfcIconRecord> QNdefNfcSmartPosterRecord::iconRecords() const
535{
536 return d->m_iconList;
537}
538
539/*!
540 Adds an icon record \a icon to the smart poster. If the smart poster already contains an icon
541 record with the same type then the existing icon record is replaced.
542 */
543void QNdefNfcSmartPosterRecord::addIcon(const QNdefNfcIconRecord &icon)
544{
545 addIconInternal(icon);
546
547 // Convert to payload
548 convertToPayload();
549}
550
551void QNdefNfcSmartPosterRecord::addIconInternal(const QNdefNfcIconRecord &icon)
552{
553 for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
554 const QNdefNfcIconRecord &rec = d->m_iconList[i];
555
556 if (rec.type() == icon.type())
557 d->m_iconList.removeAt(i);
558 }
559
560 d->m_iconList.append(t: icon);
561}
562
563/*!
564 Adds an icon record with type \a type and data \a data to the smart poster. If the smart poster
565 already contains an icon record with the same type then the existing icon record is replaced.
566 */
567void QNdefNfcSmartPosterRecord::addIcon(const QByteArray &type, const QByteArray &data)
568{
569 QNdefNfcIconRecord rec;
570 rec.setType(type);
571 rec.setData(data);
572
573 addIcon(icon: rec);
574}
575
576/*!
577 Attempts to remove the icon record \a icon from the smart poster.
578 Removes the record and returns \c true if the smart poster contains
579 a matching record, otherwise \c false is returned.
580 */
581bool QNdefNfcSmartPosterRecord::removeIcon(const QNdefNfcIconRecord &icon)
582{
583 bool status = false;
584
585 for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
586 const QNdefNfcIconRecord &rec = d->m_iconList[i];
587
588 if (rec.type() == icon.type() && rec.data() == icon.data()) {
589 d->m_iconList.removeAt(i);
590 status = true;
591 break;
592 }
593 }
594
595 // Convert to payload if the icon list has changed
596 if (status)
597 convertToPayload();
598
599 return status;
600}
601
602/*!
603 Attempts to remove the icon record with the type \a type from the smart
604 poster. Removes the record and returns \c true if the smart poster contains
605 a matching record, otherwise \c false is returned.
606 */
607bool QNdefNfcSmartPosterRecord::removeIcon(const QByteArray &type)
608{
609 bool status = false;
610
611 for (qsizetype i = 0; i < d->m_iconList.size(); ++i) {
612 const QNdefNfcIconRecord &rec = d->m_iconList[i];
613
614 if (rec.type() == type) {
615 d->m_iconList.removeAt(i);
616 status = true;
617 break;
618 }
619 }
620
621 // Convert to payload if the icon list has changed
622 if (status)
623 convertToPayload();
624
625 return status;
626}
627
628/*!
629 Adds the icon record list \a icons to the smart poster.
630 Any existing records are overwritten.
631
632 \sa hasIcon(), icon()
633 */
634void QNdefNfcSmartPosterRecord::setIcons(const QList<QNdefNfcIconRecord> &icons)
635{
636 d->m_iconList.clear();
637
638 for (qsizetype i = 0; i < icons.size(); ++i) {
639 d->m_iconList.append(t: icons[i]);
640 }
641
642 // Convert to payload
643 convertToPayload();
644}
645
646/*!
647 Returns the size from the size record if available; otherwise returns 0.
648
649 The value is optional and contains the size in bytes of the object
650 that the URI refers to. It may be used by the device to determine
651 whether it can accommodate the object.
652
653 \sa setSize()
654 */
655quint32 QNdefNfcSmartPosterRecord::size() const
656{
657 if (d->m_size)
658 return d->m_size->size();
659
660 return 0;
661}
662
663/*!
664 Sets the record \a size. The value contains the size in bytes of
665 the object that the URI refers to.
666
667 \sa size(), hasSize()
668 */
669void QNdefNfcSmartPosterRecord::setSize(quint32 size)
670{
671 if (!d->m_size)
672 d->m_size = new QNdefNfcSizeRecord();
673
674 d->m_size->setSize(size);
675
676 // Convert to payload
677 convertToPayload();
678}
679
680/*!
681 Returns the MIME type that describes the type of the objects that can be
682 reached via uri().
683
684 If the type is not known, the returned QString is empty.
685
686 \sa setTypeInfo(), hasTypeInfo()
687 */
688QString QNdefNfcSmartPosterRecord::typeInfo() const
689{
690 if (d->m_type)
691 return d->m_type->typeInfo();
692
693 return QString();
694}
695
696/*!
697 Sets the type record to \a type. \a type describes the type of the object
698 referenced by uri().
699
700 \sa typeInfo()
701 */
702void QNdefNfcSmartPosterRecord::setTypeInfo(const QString &type)
703{
704 if (d->m_type)
705 delete d->m_type;
706
707 d->m_type = new QNdefNfcTypeRecord();
708 d->m_type->setTypeInfo(type);
709
710 // Convert to payload
711 convertToPayload();
712}
713
714void QNdefNfcActRecord::setAction(QNdefNfcSmartPosterRecord::Action action)
715{
716 QByteArray data(1, action);
717
718 setPayload(data);
719}
720
721QNdefNfcSmartPosterRecord::Action QNdefNfcActRecord::action() const
722{
723 const QByteArray p = payload();
724 QNdefNfcSmartPosterRecord::Action value =
725 QNdefNfcSmartPosterRecord::UnspecifiedAction;
726
727 if (!p.isEmpty())
728 value = QNdefNfcSmartPosterRecord::Action(static_cast<signed char>(p[0]));
729
730 return value;
731}
732
733/*!
734 Sets the contents of the icon record to \a data.
735*/
736void QNdefNfcIconRecord::setData(const QByteArray &data)
737{
738 setPayload(data);
739}
740
741/*!
742 Returns the icon data as \l QByteArray.
743*/
744QByteArray QNdefNfcIconRecord::data() const
745{
746 return payload();
747}
748
749void QNdefNfcSizeRecord::setSize(quint32 size)
750{
751 QByteArray data(4, 0);
752
753 data[0] = (int) ((size & 0xFF000000) >> 24);
754 data[1] = (int) ((size & 0x00FF0000) >> 16);
755 data[2] = (int) ((size & 0x0000FF00) >> 8);
756 data[3] = (int) ((size & 0x000000FF));
757
758 setPayload(data);
759}
760
761quint32 QNdefNfcSizeRecord::size() const
762{
763 const QByteArray p = payload();
764
765 if (p.isEmpty())
766 return 0;
767
768 return ((p[0] << 24) & 0xFF000000) + ((p[1] << 16) & 0x00FF0000)
769 + ((p[2] << 8) & 0x0000FF00) + (p[3] & 0x000000FF);
770}
771
772void QNdefNfcTypeRecord::setTypeInfo(const QString &type)
773{
774 setPayload(type.toUtf8());
775}
776
777QString QNdefNfcTypeRecord::typeInfo() const
778{
779 return QString::fromUtf8(ba: payload());
780}
781
782QT_END_NAMESPACE
783

source code of qtconnectivity/src/nfc/qndefnfcsmartposterrecord.cpp