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

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