1 // Copyright 2014 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_tag_technology_chromeos.h" 6 7 #include "base/stl_util.h" 8 #include "chromeos/dbus/dbus_thread_manager.h" 9 #include "device/nfc/nfc_ndef_record_utils_chromeos.h" 10 #include "device/nfc/nfc_tag_chromeos.h" 11 12 using device::NfcNdefMessage; 13 using device::NfcNdefRecord; 14 15 namespace chromeos { 16 17 namespace { 18 19 typedef std::vector<dbus::ObjectPath> ObjectPathVector; 20 21 } // namespace 22 23 NfcNdefTagTechnologyChromeOS::NfcNdefTagTechnologyChromeOS(NfcTagChromeOS* tag) 24 : NfcNdefTagTechnology(tag), 25 object_path_(tag->object_path()), 26 weak_ptr_factory_(this) { 27 DCHECK(tag); 28 // Create record objects for all records that were received before. 29 const ObjectPathVector& records = 30 DBusThreadManager::Get()->GetNfcRecordClient()-> 31 GetRecordsForTag(object_path_); 32 for (ObjectPathVector::const_iterator iter = records.begin(); 33 iter != records.end(); ++iter) { 34 AddRecord(*iter); 35 } 36 DBusThreadManager::Get()->GetNfcRecordClient()->AddObserver(this); 37 } 38 39 NfcNdefTagTechnologyChromeOS::~NfcNdefTagTechnologyChromeOS() { 40 DBusThreadManager::Get()->GetNfcRecordClient()->RemoveObserver(this); 41 STLDeleteValues(&records_); 42 } 43 44 void NfcNdefTagTechnologyChromeOS::AddObserver( 45 NfcNdefTagTechnology::Observer* observer) { 46 observers_.AddObserver(observer); 47 } 48 49 void NfcNdefTagTechnologyChromeOS::RemoveObserver( 50 NfcNdefTagTechnology::Observer* observer) { 51 observers_.RemoveObserver(observer); 52 } 53 54 const NfcNdefMessage& NfcNdefTagTechnologyChromeOS::GetNdefMessage() const { 55 return message_; 56 } 57 58 void NfcNdefTagTechnologyChromeOS::WriteNdef( 59 const device::NfcNdefMessage& message, 60 const base::Closure& callback, 61 const ErrorCallback& error_callback) { 62 if (message.records().empty()) { 63 LOG(ERROR) << "Given NDEF message is empty. Cannot write it."; 64 error_callback.Run(); 65 return; 66 } 67 if (!tag()->IsReady()) { 68 LOG(ERROR) << "The tag is not ready yet: " << tag()->GetIdentifier(); 69 error_callback.Run(); 70 return; 71 } 72 // TODO(armansito): neard currently supports writing only one NDEF record 73 // to a tag and won't support multiple records until 0.15. Until then, report 74 // failure if |message| contains more than one record. 75 if (message.records().size() > 1) { 76 LOG(ERROR) << "Currently, writing only 1 NDEF record is supported."; 77 error_callback.Run(); 78 return; 79 } 80 const NfcNdefRecord* record = message.records()[0]; 81 base::DictionaryValue attributes; 82 if (!nfc_ndef_record_utils::NfcNdefRecordToDBusAttributes( 83 record, &attributes)) { 84 LOG(ERROR) << "Failed to extract NDEF record fields for NDEF push."; 85 error_callback.Run(); 86 return; 87 } 88 DBusThreadManager::Get()->GetNfcTagClient()->Write( 89 object_path_, 90 attributes, 91 base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage, 92 weak_ptr_factory_.GetWeakPtr(), callback), 93 base::Bind(&NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError, 94 weak_ptr_factory_.GetWeakPtr(), error_callback)); 95 } 96 97 void NfcNdefTagTechnologyChromeOS::RecordAdded( 98 const dbus::ObjectPath& object_path) { 99 // Don't create the record object yet. Instead, wait until all record 100 // properties have been received and construct the object and notify observers 101 // then. 102 VLOG(1) << "Record added: " << object_path.value() << ". Waiting until " 103 "all properties have been fetched to create record object."; 104 } 105 106 void NfcNdefTagTechnologyChromeOS::RecordRemoved( 107 const dbus::ObjectPath& object_path) { 108 NdefRecordMap::iterator iter = records_.find(object_path); 109 if (iter == records_.end()) 110 return; 111 VLOG(1) << "Lost remote NDEF record object: " << object_path.value() 112 << ", removing record."; 113 NfcNdefRecord* record = iter->second; 114 message_.RemoveRecord(record); 115 delete record; 116 records_.erase(iter); 117 } 118 119 void NfcNdefTagTechnologyChromeOS::RecordPropertiesReceived( 120 const dbus::ObjectPath& object_path) { 121 VLOG(1) << "Record properties received for: " << object_path.value(); 122 123 // Check if the found record belongs to this tag. 124 bool record_found = false; 125 const ObjectPathVector& records = 126 DBusThreadManager::Get()->GetNfcRecordClient()-> 127 GetRecordsForTag(object_path_); 128 for (ObjectPathVector::const_iterator iter = records.begin(); 129 iter != records.end(); ++iter) { 130 if (*iter == object_path) { 131 record_found = true; 132 break; 133 } 134 } 135 if (!record_found) { 136 VLOG(1) << "Record \"" << object_path.value() << "\" doesn't belong to this" 137 << " tag. Ignoring."; 138 return; 139 } 140 AddRecord(object_path); 141 } 142 143 void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessage( 144 const base::Closure& callback) { 145 callback.Run(); 146 } 147 148 void NfcNdefTagTechnologyChromeOS::OnWriteNdefMessageError( 149 const ErrorCallback& error_callback, 150 const std::string& error_name, 151 const std::string& error_message) { 152 LOG(ERROR) << object_path_.value() << ": Failed to Push NDEF message: " 153 << error_name << ": " << error_message; 154 error_callback.Run(); 155 } 156 157 void NfcNdefTagTechnologyChromeOS::AddRecord( 158 const dbus::ObjectPath& object_path) { 159 // Ignore this call if an entry for this record already exists. 160 if (records_.find(object_path) != records_.end()) { 161 VLOG(1) << "Record object for remote \"" << object_path.value() 162 << "\" already exists."; 163 return; 164 } 165 166 NfcRecordClient::Properties* record_properties = 167 DBusThreadManager::Get()->GetNfcRecordClient()-> 168 GetProperties(object_path); 169 DCHECK(record_properties); 170 171 NfcNdefRecord* record = new NfcNdefRecord(); 172 if (!nfc_ndef_record_utils::RecordPropertiesToNfcNdefRecord( 173 record_properties, record)) { 174 LOG(ERROR) << "Failed to create record object for record with object " 175 << "path \"" << object_path.value() << "\""; 176 delete record; 177 return; 178 } 179 180 message_.AddRecord(record); 181 records_[object_path] = record; 182 FOR_EACH_OBSERVER(NfcNdefTagTechnology::Observer, observers_, 183 RecordReceived(tag(), record)); 184 } 185 186 } // namespace chromeos 187