• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "device/nfc/nfc_ndef_record_utils_chromeos.h"
6 
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"
11 
12 using device::NfcNdefRecord;
13 
14 namespace chromeos {
15 namespace nfc_ndef_record_utils {
16 
17 namespace {
18 
19 // Maps the NDEF type |type| as returned by neard to the corresponding
20 // device::NfcNdefRecord::Type value.
DBusRecordTypeValueToNfcNdefRecordType(const std::string & type)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;
36 }
37 
38 // Maps the NDEF type |type| given as a NFC C++ API enumeration to the
39 // corresponding string value defined by neard.
NfcRecordTypeEnumToPropertyValue(NfcNdefRecord::Type type)40 std::string NfcRecordTypeEnumToPropertyValue(NfcNdefRecord::Type type) {
41   switch (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;
54     default:
55       return "";
56   }
57 }
58 
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
62 // special handling.
NdefRecordFieldToDBusProperty(const std::string & field_name)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;
76   return "";
77 }
78 
NfcNdefRecordActionValueToDBusActionValue(const std::string & action)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)
84     return "Do";
85   if (action == device::NfcNdefRecord::kSmartPosterActionSave)
86     return "Save";
87   if (action == device::NfcNdefRecord::kSmartPosterActionOpen)
88     return "Edit";
89   return "";
90 }
91 
DBusActionValueToNfcNdefRecordActionValue(const std::string & action)92 std::string DBusActionValueToNfcNdefRecordActionValue(
93     const std::string& action) {
94   // TODO(armansito): Add bindings for values returned by neard to
95   // service_constants.h.
96   if (action == "Do")
97     return device::NfcNdefRecord::kSmartPosterActionDo;
98   if (action == "Save")
99     return device::NfcNdefRecord::kSmartPosterActionSave;
100   if (action == "Edit")
101     return device::NfcNdefRecord::kSmartPosterActionOpen;
102   return "";
103 }
104 
105 
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
109 // error occurs.
ConvertNdefFieldsToDBusAttributes(const base::DictionaryValue & fields,base::DictionaryValue * out)110 bool ConvertNdefFieldsToDBusAttributes(
111     const base::DictionaryValue& fields,
112     base::DictionaryValue* out) {
113   DCHECK(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.";
131         return false;
132       }
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);
138       std::string action =
139           NfcNdefRecordActionValueToDBusActionValue(action_value);
140       if (action.empty()) {
141         VLOG(1) << "Invalid action value: \"" << action_value << "\"";
142         return false;
143       }
144       out->SetString(nfc_record::kActionProperty, action);
145     } else {
146       std::string dbus_property = NdefRecordFieldToDBusProperty(iter.key());
147       if (dbus_property.empty()) {
148         LOG(ERROR) << "Invalid field: " << iter.key();
149         return false;
150       }
151       out->Set(dbus_property, iter.value().DeepCopy());
152     }
153   }
154   return true;
155 }
156 
157 }  // namespace
158 
NfcNdefRecordToDBusAttributes(const NfcNdefRecord * record,base::DictionaryValue * out)159 bool NfcNdefRecordToDBusAttributes(
160       const NfcNdefRecord* record,
161       base::DictionaryValue* out) {
162   DCHECK(record);
163   DCHECK(out);
164   if (!record->IsPopulated()) {
165     LOG(ERROR) << "Record is not populated.";
166     return false;
167   }
168   out->SetString(nfc_record::kTypeProperty,
169                  NfcRecordTypeEnumToPropertyValue(record->type()));
170   return ConvertNdefFieldsToDBusAttributes(record->data(), out);
171 }
172 
RecordPropertiesToNfcNdefRecord(const NfcRecordClient::Properties * properties,device::NfcNdefRecord * out)173 bool RecordPropertiesToNfcNdefRecord(
174       const NfcRecordClient::Properties* properties,
175       device::NfcNdefRecord* out) {
176   if (out->IsPopulated()) {
177     LOG(ERROR) << "Record is already populated!";
178     return false;
179   }
180   NfcNdefRecord::Type type =
181       DBusRecordTypeValueToNfcNdefRecordType(properties->type.value());
182   if (type == NfcNdefRecord::kTypeUnknown) {
183     LOG(ERROR) << "Record type is unknown.";
184     return false;
185   }
186 
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());
194   }
195   if (properties->size.value() != 0) {
196     attributes.SetDouble(NfcNdefRecord::kFieldTargetSize,
197                          static_cast<double>(properties->size.value()));
198   }
199   std::string action_value =
200     DBusActionValueToNfcNdefRecordActionValue(properties->action.value());
201   if (!action_value.empty())
202     attributes.SetString(NfcNdefRecord::kFieldAction, action_value);
203 
204   // The "representation", "encoding", and "language" properties will be stored
205   // differently, depending on whether the record type is "SmartPoster" or
206   // "Text".
207   {
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());
213     }
214     if (!properties->encoding.value().empty()) {
215       text_attributes->SetString(NfcNdefRecord::kFieldEncoding,
216                                  properties->encoding.value());
217     }
218     if (!properties->language.value().empty()) {
219       text_attributes->SetString(NfcNdefRecord::kFieldLanguageCode,
220                                  properties->language.value());
221     }
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);
227       } else {
228         attributes.MergeDictionary(text_attributes.get());
229       }
230     }
231   }
232 
233   // Populate the given record.
234   return out->Populate(type, &attributes);
235 }
236 
237 }  // namespace nfc_ndef_record_utils
238 }  // namespace chromeos
239