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 "chromeos/dbus/nfc_tag_client.h" 6 7 #include "base/bind.h" 8 #include "base/memory/weak_ptr.h" 9 #include "base/observer_list.h" 10 #include "base/strings/stringprintf.h" 11 #include "chromeos/dbus/nfc_adapter_client.h" 12 #include "dbus/bus.h" 13 #include "dbus/message.h" 14 #include "dbus/values_util.h" 15 #include "third_party/cros_system_api/dbus/service_constants.h" 16 17 using chromeos::nfc_client_helpers::DBusObjectMap; 18 using chromeos::nfc_client_helpers::ObjectProxyTree; 19 20 namespace chromeos { 21 22 NfcTagClient::Properties::Properties( 23 dbus::ObjectProxy* object_proxy, 24 const PropertyChangedCallback& callback) 25 : NfcPropertySet(object_proxy, 26 nfc_tag::kNfcTagInterface, 27 callback) { 28 RegisterProperty(nfc_tag::kTypeProperty, &type); 29 RegisterProperty(nfc_tag::kProtocolProperty, &protocol); 30 RegisterProperty(nfc_tag::kRecordsProperty, &records); 31 RegisterProperty(nfc_tag::kReadOnlyProperty, &read_only); 32 } 33 34 NfcTagClient::Properties::~Properties() { 35 } 36 37 // The NfcTagClient implementation used in production. 38 class NfcTagClientImpl : public NfcTagClient, 39 public NfcAdapterClient::Observer, 40 public DBusObjectMap::Delegate { 41 public: 42 explicit NfcTagClientImpl(NfcAdapterClient* adapter_client) 43 : bus_(NULL), 44 adapter_client_(adapter_client), 45 weak_ptr_factory_(this) { 46 DCHECK(adapter_client); 47 } 48 49 virtual ~NfcTagClientImpl() { 50 DCHECK(adapter_client_); 51 adapter_client_->RemoveObserver(this); 52 } 53 54 // NfcTagClient override. 55 virtual void AddObserver(NfcTagClient::Observer* observer) OVERRIDE { 56 DCHECK(observer); 57 observers_.AddObserver(observer); 58 } 59 60 // NfcTagClient override. 61 virtual void RemoveObserver(NfcTagClient::Observer* observer) OVERRIDE { 62 DCHECK(observer); 63 observers_.RemoveObserver(observer); 64 } 65 66 // NfcTagClient override. 67 virtual std::vector<dbus::ObjectPath> GetTagsForAdapter( 68 const dbus::ObjectPath& adapter_path) OVERRIDE { 69 DBusObjectMap* object_map = 70 adapters_to_object_maps_.GetObjectMap(adapter_path); 71 if (!object_map) 72 return std::vector<dbus::ObjectPath>(); 73 return object_map->GetObjectPaths(); 74 } 75 76 // NfcTagClient override. 77 virtual Properties* GetProperties( 78 const dbus::ObjectPath& object_path) OVERRIDE { 79 return static_cast<Properties*>( 80 adapters_to_object_maps_.FindObjectProperties(object_path)); 81 } 82 83 // NfcTagClient override. 84 virtual void Write( 85 const dbus::ObjectPath& object_path, 86 const base::DictionaryValue& attributes, 87 const base::Closure& callback, 88 const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE { 89 dbus::ObjectProxy* object_proxy = 90 adapters_to_object_maps_.FindObjectProxy(object_path); 91 if (!object_proxy) { 92 std::string error_message = 93 base::StringPrintf("NFC tag with object path \"%s\" does not exist.", 94 object_path.value().c_str()); 95 LOG(ERROR) << error_message; 96 error_callback.Run(nfc_client_helpers::kUnknownObjectError, 97 error_message); 98 return; 99 } 100 101 // |attributes| should not be empty. 102 if (attributes.empty()) { 103 std::string error_message = 104 "Cannot write data to tag with empty arguments."; 105 LOG(ERROR) << error_message; 106 error_callback.Run(nfc_error::kInvalidArguments, error_message); 107 return; 108 } 109 110 // Create the arguments. 111 dbus::MethodCall method_call(nfc_tag::kNfcTagInterface, nfc_tag::kWrite); 112 dbus::MessageWriter writer(&method_call); 113 dbus::AppendValueData(&writer, attributes); 114 115 object_proxy->CallMethodWithErrorCallback( 116 &method_call, 117 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 118 base::Bind(&nfc_client_helpers::OnSuccess, callback), 119 base::Bind(&nfc_client_helpers::OnError, error_callback)); 120 } 121 122 protected: 123 // DBusClient override. 124 virtual void Init(dbus::Bus* bus) OVERRIDE { 125 VLOG(1) << "Creating NfcTagClientImpl"; 126 DCHECK(bus); 127 bus_ = bus; 128 DCHECK(adapter_client_); 129 adapter_client_->AddObserver(this); 130 } 131 132 private: 133 // NfcAdapterClient::Observer override. 134 virtual void AdapterAdded(const dbus::ObjectPath& object_path) OVERRIDE { 135 VLOG(1) << "Adapter added. Creating map for tag proxies belonging to " 136 << "adapter: " << object_path.value(); 137 adapters_to_object_maps_.CreateObjectMap( 138 object_path, nfc_tag::kNfcTagServiceName, this, bus_); 139 } 140 141 // NfcAdapterClient::Observer override. 142 virtual void AdapterRemoved(const dbus::ObjectPath& object_path) OVERRIDE { 143 // Neard doesn't send out property changed signals for the tags that 144 // are removed when the adapter they belong to is removed. Clean up the 145 // object proxies for devices that are managed by the removed adapter. 146 // Note: DBusObjectMap guarantees that the Properties structure for the 147 // removed adapter will be valid before this method returns. 148 VLOG(1) << "Adapter removed. Cleaning up tag proxies belonging to " 149 << "adapter: " << object_path.value(); 150 adapters_to_object_maps_.RemoveObjectMap(object_path); 151 } 152 153 // NfcAdapterClient::Observer override. 154 virtual void AdapterPropertyChanged( 155 const dbus::ObjectPath& object_path, 156 const std::string& property_name) OVERRIDE { 157 // Update the tag proxies. 158 DCHECK(adapter_client_); 159 NfcAdapterClient::Properties *adapter_properties = 160 adapter_client_->GetProperties(object_path); 161 DCHECK(adapter_properties); 162 if (!adapter_properties) { 163 LOG(ERROR) << "No property structure found for adapter: " 164 << object_path.value(); 165 return; 166 } 167 168 // Ignore changes to properties other than "Tags". 169 if (property_name != adapter_properties->tags.name()) 170 return; 171 172 // Update the known tags. 173 VLOG(1) << "NFC tags changed."; 174 const std::vector<dbus::ObjectPath>& received_tags = 175 adapter_properties->tags.value(); 176 DBusObjectMap* object_map = 177 adapters_to_object_maps_.GetObjectMap(object_path); 178 DCHECK(object_map); 179 object_map->UpdateObjects(received_tags); 180 } 181 182 // nfc_client_helpers::DBusObjectMap::Delegate override. 183 virtual NfcPropertySet* CreateProperties( 184 dbus::ObjectProxy* object_proxy) OVERRIDE { 185 Properties* properties = new Properties( 186 object_proxy, 187 base::Bind(&NfcTagClientImpl::OnPropertyChanged, 188 weak_ptr_factory_.GetWeakPtr(), 189 object_proxy->object_path())); 190 properties->SetAllPropertiesReceivedCallback( 191 base::Bind(&NfcTagClientImpl::OnPropertiesReceived, 192 weak_ptr_factory_.GetWeakPtr(), 193 object_proxy->object_path())); 194 return properties; 195 } 196 197 // nfc_client_helpers::DBusObjectMap::Delegate override. 198 virtual void ObjectAdded(const dbus::ObjectPath& object_path) OVERRIDE { 199 FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, 200 TagAdded(object_path)); 201 } 202 203 virtual void ObjectRemoved(const dbus::ObjectPath& object_path) OVERRIDE { 204 FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, 205 TagRemoved(object_path)); 206 } 207 208 // Called by NfcPropertySet when a property value is changed, either by 209 // result of a signal or response to a GetAll() or Get() call. 210 void OnPropertyChanged(const dbus::ObjectPath& object_path, 211 const std::string& property_name) { 212 VLOG(1) << "Tag property changed; Path: " << object_path.value() 213 << " Property: " << property_name; 214 FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, 215 TagPropertyChanged(object_path, property_name)); 216 } 217 218 // Called by NfcPropertySet when all properties have been processed as a 219 // result of a call to GetAll. 220 void OnPropertiesReceived(const dbus::ObjectPath& object_path) { 221 VLOG(1) << "All tag properties received; Path: " << object_path.value(); 222 FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, 223 TagPropertiesReceived(object_path)); 224 } 225 226 // We maintain a pointer to the bus to be able to request proxies for 227 // new NFC tags that appear. 228 dbus::Bus* bus_; 229 230 // List of observers interested in event notifications. 231 ObserverList<NfcTagClient::Observer> observers_; 232 233 // Mapping from object paths to object proxies and properties structures that 234 // were already created by us. This stucture stores a different DBusObjectMap 235 // for each known NFC adapter object path. 236 ObjectProxyTree adapters_to_object_maps_; 237 238 // The adapter client that we listen to events notifications from. 239 NfcAdapterClient* adapter_client_; 240 241 // Weak pointer factory for generating 'this' pointers that might live longer 242 // than we do. 243 // Note: This should remain the last member so it'll be destroyed and 244 // invalidate its weak pointers before any other members are destroyed. 245 base::WeakPtrFactory<NfcTagClientImpl> weak_ptr_factory_; 246 247 DISALLOW_COPY_AND_ASSIGN(NfcTagClientImpl); 248 }; 249 250 NfcTagClient::NfcTagClient() { 251 } 252 253 NfcTagClient::~NfcTagClient() { 254 } 255 256 NfcTagClient* NfcTagClient::Create(NfcAdapterClient* adapter_client) { 257 return new NfcTagClientImpl(adapter_client); 258 } 259 260 } // namespace chromeos 261