1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "device/nfc/nfc_ndef_record_utils_chromeos.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "device/nfc/nfc_ndef_record.h"
10 #include "third_party/cros_system_api/dbus/service_constants.h"
12 using device::NfcNdefRecord
;
15 namespace nfc_ndef_record_utils
{
19 // Maps the NDEF type |type| as returned by neard to the corresponding
20 // device::NfcNdefRecord::Type value.
21 NfcNdefRecord::Type
DBusRecordTypeValueToNfcNdefRecordType(
22 const std::string
& type
) {
23 if (type
== nfc_record::kTypeSmartPoster
)
24 return NfcNdefRecord::kTypeSmartPoster
;
25 if (type
== nfc_record::kTypeText
)
26 return NfcNdefRecord::kTypeText
;
27 if (type
== nfc_record::kTypeUri
)
28 return NfcNdefRecord::kTypeURI
;
29 if (type
== nfc_record::kTypeHandoverRequest
)
30 return NfcNdefRecord::kTypeHandoverRequest
;
31 if (type
== nfc_record::kTypeHandoverSelect
)
32 return NfcNdefRecord::kTypeHandoverSelect
;
33 if (type
== nfc_record::kTypeHandoverCarrier
)
34 return NfcNdefRecord::kTypeHandoverCarrier
;
35 return NfcNdefRecord::kTypeUnknown
;
38 // Maps the NDEF type |type| given as a NFC C++ API enumeration to the
39 // corresponding string value defined by neard.
40 std::string
NfcRecordTypeEnumToPropertyValue(NfcNdefRecord::Type type
) {
42 case NfcNdefRecord::kTypeSmartPoster
:
43 return nfc_record::kTypeSmartPoster
;
44 case NfcNdefRecord::kTypeText
:
45 return nfc_record::kTypeText
;
46 case NfcNdefRecord::kTypeURI
:
47 return nfc_record::kTypeUri
;
48 case NfcNdefRecord::kTypeHandoverRequest
:
49 return nfc_record::kTypeHandoverRequest
;
50 case NfcNdefRecord::kTypeHandoverSelect
:
51 return nfc_record::kTypeHandoverSelect
;
52 case NfcNdefRecord::kTypeHandoverCarrier
:
53 return nfc_record::kTypeHandoverCarrier
;
59 // Maps the field name |field_name| given as defined in NfcNdefRecord to the
60 // Neard Record D-Bus property name. This handles all fields except for
61 // NfcNdefRecord::kFieldTitles and NfcNdefRecord::kFieldAction, which need
63 std::string
NdefRecordFieldToDBusProperty(const std::string
& field_name
) {
64 if (field_name
== NfcNdefRecord::kFieldEncoding
)
65 return nfc_record::kEncodingProperty
;
66 if (field_name
== NfcNdefRecord::kFieldLanguageCode
)
67 return nfc_record::kLanguageProperty
;
68 if (field_name
== NfcNdefRecord::kFieldText
)
69 return nfc_record::kRepresentationProperty
;
70 if (field_name
== NfcNdefRecord::kFieldURI
)
71 return nfc_record::kUriProperty
;
72 if (field_name
== NfcNdefRecord::kFieldMimeType
)
73 return nfc_record::kMimeTypeProperty
;
74 if (field_name
== NfcNdefRecord::kFieldTargetSize
)
75 return nfc_record::kSizeProperty
;
79 std::string
NfcNdefRecordActionValueToDBusActionValue(
80 const std::string
& action
) {
81 // TODO(armansito): Add bindings for values returned by neard to
82 // service_constants.h.
83 if (action
== device::NfcNdefRecord::kSmartPosterActionDo
)
85 if (action
== device::NfcNdefRecord::kSmartPosterActionSave
)
87 if (action
== device::NfcNdefRecord::kSmartPosterActionOpen
)
92 std::string
DBusActionValueToNfcNdefRecordActionValue(
93 const std::string
& action
) {
94 // TODO(armansito): Add bindings for values returned by neard to
95 // service_constants.h.
97 return device::NfcNdefRecord::kSmartPosterActionDo
;
99 return device::NfcNdefRecord::kSmartPosterActionSave
;
100 if (action
== "Edit")
101 return device::NfcNdefRecord::kSmartPosterActionOpen
;
106 // Translates the given dictionary of NDEF fields by recursively converting
107 // each key in |record_data| to its corresponding Record property name defined
108 // by the Neard D-Bus API. The output is stored in |out|. Returns false if an
110 bool ConvertNdefFieldsToDBusAttributes(
111 const base::DictionaryValue
& fields
,
112 base::DictionaryValue
* out
) {
114 for (base::DictionaryValue::Iterator
iter(fields
);
115 !iter
.IsAtEnd(); iter
.Advance()) {
116 // Special case the "titles" and "action" fields.
117 if (iter
.key() == NfcNdefRecord::kFieldTitles
) {
118 const base::ListValue
* titles
= NULL
;
119 bool value_result
= iter
.value().GetAsList(&titles
);
120 DCHECK(value_result
);
121 DCHECK(titles
->GetSize() != 0);
122 // TODO(armansito): For now, pick the first title in the list and write
123 // its contents directly to the top level of the field. This is due to an
124 // error in the Neard D-Bus API design. This code will need to be updated
125 // if the neard API changes to correct this.
126 const base::DictionaryValue
* first_title
= NULL
;
127 value_result
= titles
->GetDictionary(0, &first_title
);
128 DCHECK(value_result
);
129 if (!ConvertNdefFieldsToDBusAttributes(*first_title
, out
)) {
130 LOG(ERROR
) << "Invalid title field.";
133 } else if (iter
.key() == NfcNdefRecord::kFieldAction
) {
134 // The value of the action field needs to be translated.
135 std::string action_value
;
136 bool value_result
= iter
.value().GetAsString(&action_value
);
137 DCHECK(value_result
);
139 NfcNdefRecordActionValueToDBusActionValue(action_value
);
140 if (action
.empty()) {
141 VLOG(1) << "Invalid action value: \"" << action_value
<< "\"";
144 out
->SetString(nfc_record::kActionProperty
, action
);
146 std::string dbus_property
= NdefRecordFieldToDBusProperty(iter
.key());
147 if (dbus_property
.empty()) {
148 LOG(ERROR
) << "Invalid field: " << iter
.key();
151 out
->Set(dbus_property
, iter
.value().DeepCopy());
159 bool NfcNdefRecordToDBusAttributes(
160 const NfcNdefRecord
* record
,
161 base::DictionaryValue
* out
) {
164 if (!record
->IsPopulated()) {
165 LOG(ERROR
) << "Record is not populated.";
168 out
->SetString(nfc_record::kTypeProperty
,
169 NfcRecordTypeEnumToPropertyValue(record
->type()));
170 return ConvertNdefFieldsToDBusAttributes(record
->data(), out
);
173 bool RecordPropertiesToNfcNdefRecord(
174 const NfcRecordClient::Properties
* properties
,
175 device::NfcNdefRecord
* out
) {
176 if (out
->IsPopulated()) {
177 LOG(ERROR
) << "Record is already populated!";
180 NfcNdefRecord::Type type
=
181 DBusRecordTypeValueToNfcNdefRecordType(properties
->type
.value());
182 if (type
== NfcNdefRecord::kTypeUnknown
) {
183 LOG(ERROR
) << "Record type is unknown.";
187 // Extract each property.
188 base::DictionaryValue attributes
;
189 if (!properties
->uri
.value().empty())
190 attributes
.SetString(NfcNdefRecord::kFieldURI
, properties
->uri
.value());
191 if (!properties
->mime_type
.value().empty()) {
192 attributes
.SetString(NfcNdefRecord::kFieldMimeType
,
193 properties
->mime_type
.value());
195 if (properties
->size
.value() != 0) {
196 attributes
.SetDouble(NfcNdefRecord::kFieldTargetSize
,
197 static_cast<double>(properties
->size
.value()));
199 std::string action_value
=
200 DBusActionValueToNfcNdefRecordActionValue(properties
->action
.value());
201 if (!action_value
.empty())
202 attributes
.SetString(NfcNdefRecord::kFieldAction
, action_value
);
204 // The "representation", "encoding", and "language" properties will be stored
205 // differently, depending on whether the record type is "SmartPoster" or
208 scoped_ptr
<base::DictionaryValue
> text_attributes(
209 new base::DictionaryValue());
210 if (!properties
->representation
.value().empty()) {
211 text_attributes
->SetString(NfcNdefRecord::kFieldText
,
212 properties
->representation
.value());
214 if (!properties
->encoding
.value().empty()) {
215 text_attributes
->SetString(NfcNdefRecord::kFieldEncoding
,
216 properties
->encoding
.value());
218 if (!properties
->language
.value().empty()) {
219 text_attributes
->SetString(NfcNdefRecord::kFieldLanguageCode
,
220 properties
->language
.value());
222 if (!text_attributes
->empty()) {
223 if (type
== NfcNdefRecord::kTypeSmartPoster
) {
224 base::ListValue
* titles
= new base::ListValue();
225 titles
->Append(text_attributes
.release());
226 attributes
.Set(NfcNdefRecord::kFieldTitles
, titles
);
228 attributes
.MergeDictionary(text_attributes
.get());
233 // Populate the given record.
234 return out
->Populate(type
, &attributes
);
237 } // namespace nfc_ndef_record_utils
238 } // namespace chromeos