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_adapter_chromeos.h" 6 7#include <vector> 8 9#include "base/callback.h" 10#include "base/logging.h" 11#include "chromeos/dbus/dbus_thread_manager.h" 12#include "device/nfc/nfc_peer_chromeos.h" 13#include "device/nfc/nfc_tag_chromeos.h" 14#include "third_party/cros_system_api/dbus/service_constants.h" 15 16namespace chromeos { 17 18namespace { 19 20typedef std::vector<dbus::ObjectPath> ObjectPathVector; 21 22} // namespace 23 24NfcAdapterChromeOS::NfcAdapterChromeOS() 25 : weak_ptr_factory_(this) { 26 DBusThreadManager::Get()->GetNfcAdapterClient()->AddObserver(this); 27 DBusThreadManager::Get()->GetNfcDeviceClient()->AddObserver(this); 28 DBusThreadManager::Get()->GetNfcTagClient()->AddObserver(this); 29 30 const ObjectPathVector& object_paths = 31 DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters(); 32 if (!object_paths.empty()) { 33 VLOG(1) << object_paths.size() << " NFC adapter(s) available."; 34 SetAdapter(object_paths[0]); 35 } 36} 37 38NfcAdapterChromeOS::~NfcAdapterChromeOS() { 39 DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this); 40 DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this); 41 DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this); 42} 43 44void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) { 45 DCHECK(observer); 46 observers_.AddObserver(observer); 47} 48 49void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) { 50 DCHECK(observer); 51 observers_.RemoveObserver(observer); 52} 53 54bool NfcAdapterChromeOS::IsPresent() const { 55 return !object_path_.value().empty(); 56} 57 58bool NfcAdapterChromeOS::IsPowered() const { 59 if (!IsPresent()) 60 return false; 61 return DBusThreadManager::Get()->GetNfcAdapterClient()-> 62 GetProperties(object_path_)->powered.value(); 63} 64 65bool NfcAdapterChromeOS::IsPolling() const { 66 if (!IsPresent()) 67 return false; 68 return DBusThreadManager::Get()->GetNfcAdapterClient()-> 69 GetProperties(object_path_)->polling.value(); 70} 71 72bool NfcAdapterChromeOS::IsInitialized() const { 73 return true; 74} 75 76void NfcAdapterChromeOS::SetPowered(bool powered, 77 const base::Closure& callback, 78 const ErrorCallback& error_callback) { 79 if (!IsPresent()) { 80 LOG(WARNING) << "Adapter not present. Cannot power up the antenna."; 81 error_callback.Run(); 82 return; 83 } 84 DBusThreadManager::Get()->GetNfcAdapterClient()-> 85 GetProperties(object_path_)->powered.Set( 86 powered, 87 base::Bind(&NfcAdapterChromeOS::OnSetPowered, 88 weak_ptr_factory_.GetWeakPtr(), 89 callback, 90 error_callback)); 91} 92 93void NfcAdapterChromeOS::StartPolling(const base::Closure& callback, 94 const ErrorCallback& error_callback) { 95 // Always poll in "Initiator" mode. 96 DBusThreadManager::Get()->GetNfcAdapterClient()-> 97 StartPollLoop(object_path_, 98 nfc_adapter::kModeInitiator, 99 base::Bind(&NfcAdapterChromeOS::OnStartPolling, 100 weak_ptr_factory_.GetWeakPtr(), 101 callback), 102 base::Bind(&NfcAdapterChromeOS::OnStartPollingError, 103 weak_ptr_factory_.GetWeakPtr(), 104 error_callback)); 105} 106 107void NfcAdapterChromeOS::StopPolling(const base::Closure& callback, 108 const ErrorCallback& error_callback) { 109 DBusThreadManager::Get()->GetNfcAdapterClient()-> 110 StopPollLoop(object_path_, 111 base::Bind(&NfcAdapterChromeOS::OnStopPolling, 112 weak_ptr_factory_.GetWeakPtr(), 113 callback), 114 base::Bind(&NfcAdapterChromeOS::OnStopPollingError, 115 weak_ptr_factory_.GetWeakPtr(), 116 error_callback)); 117} 118 119void NfcAdapterChromeOS::AdapterAdded(const dbus::ObjectPath& object_path) { 120 // Set the adapter to the newly added adapter only if no adapter is present. 121 if (!IsPresent()) 122 SetAdapter(object_path); 123} 124 125void NfcAdapterChromeOS::AdapterRemoved(const dbus::ObjectPath& object_path) { 126 if (object_path != object_path_) 127 return; 128 129 // The current adapter was removed, so mark us as not present and clean up 130 // peers and tags. 131 RemoveAdapter(); 132 133 // There may still be other adapters present on the system. Set the next 134 // available adapter as the current one. 135 const ObjectPathVector& object_paths = 136 DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters(); 137 for (ObjectPathVector::const_iterator iter = 138 object_paths.begin(); 139 iter != object_paths.end(); ++iter) { 140 // The removed object will still be available until the call to 141 // AdapterRemoved returns. Make sure that we are not re-adding the 142 // removed adapter. 143 if (*iter == object_path) 144 continue; 145 SetAdapter(*iter); 146 } 147} 148 149void NfcAdapterChromeOS::AdapterPropertyChanged( 150 const dbus::ObjectPath& object_path, 151 const std::string& property_name) { 152 if (object_path != object_path_) 153 return; 154 NfcAdapterClient::Properties* properties = 155 DBusThreadManager::Get()->GetNfcAdapterClient()-> 156 GetProperties(object_path_); 157 if (property_name == properties->powered.name()) 158 PoweredChanged(properties->powered.value()); 159 else if (property_name == properties->polling.name()) 160 PollingChanged(properties->polling.value()); 161} 162 163void NfcAdapterChromeOS::DeviceAdded(const dbus::ObjectPath& object_path) { 164 if (!IsPresent()) 165 return; 166 167 if (GetPeer(object_path.value())) 168 return; 169 170 VLOG(1) << "NFC device found: " << object_path.value(); 171 172 // Check to see if the device belongs to this adapter. 173 const ObjectPathVector& devices = 174 DBusThreadManager::Get()->GetNfcDeviceClient()-> 175 GetDevicesForAdapter(object_path_); 176 bool device_found = false; 177 for (ObjectPathVector::const_iterator iter = devices.begin(); 178 iter != devices.end(); ++iter) { 179 if (*iter == object_path) { 180 device_found = true; 181 break; 182 } 183 } 184 if (!device_found) { 185 VLOG(1) << "Found peer device does not belong to the current adapter."; 186 return; 187 } 188 189 // Create the peer object. 190 NfcPeerChromeOS* peer_chromeos = new NfcPeerChromeOS(object_path); 191 SetPeer(object_path.value(), peer_chromeos); 192 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 193 PeerFound(this, peer_chromeos)); 194} 195 196void NfcAdapterChromeOS::DeviceRemoved(const dbus::ObjectPath& object_path) { 197 VLOG(1) << "NFC device lost: " << object_path.value(); 198 device::NfcPeer* peer = RemovePeer(object_path.value()); 199 if (!peer) { 200 VLOG(1) << "Removed peer device does not belong to the current adapter."; 201 return; 202 } 203 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, PeerLost(this, peer)); 204 delete peer; 205} 206 207void NfcAdapterChromeOS::TagAdded(const dbus::ObjectPath& object_path) { 208 if (!IsPresent()) 209 return; 210 211 if (GetTag(object_path.value())) 212 return; 213 214 VLOG(1) << "NFC tag found: " << object_path.value(); 215 216 // Check to see if the tag belongs to this adapter. 217 const std::vector<dbus::ObjectPath>& tags = 218 DBusThreadManager::Get()->GetNfcTagClient()-> 219 GetTagsForAdapter(object_path_); 220 bool tag_found = false; 221 for (std::vector<dbus::ObjectPath>::const_iterator iter = tags.begin(); 222 iter != tags.end(); ++iter) { 223 if (*iter == object_path) { 224 tag_found = true; 225 break; 226 } 227 } 228 if (!tag_found) { 229 VLOG(1) << "Found tag does not belong to the current adapter."; 230 return; 231 } 232 233 // Create the tag object. 234 NfcTagChromeOS* tag_chromeos = new NfcTagChromeOS(object_path); 235 SetTag(object_path.value(), tag_chromeos); 236 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 237 TagFound(this, tag_chromeos)); 238} 239 240void NfcAdapterChromeOS::TagRemoved(const dbus::ObjectPath& object_path) { 241 VLOG(1) << "NFC tag lost : " << object_path.value(); 242 device::NfcTag* tag = RemoveTag(object_path.value()); 243 if (!tag) { 244 VLOG(1) << "Removed tag does not belong to the current adapter."; 245 return; 246 } 247 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, TagLost(this, tag)); 248 delete tag; 249} 250 251void NfcAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) { 252 DCHECK(!IsPresent()); 253 object_path_ = object_path; 254 VLOG(1) << "Using NFC adapter: " << object_path.value(); 255 256 NfcAdapterClient::Properties* properties = 257 DBusThreadManager::Get()->GetNfcAdapterClient()-> 258 GetProperties(object_path_); 259 PresentChanged(true); 260 if (properties->powered.value()) 261 PoweredChanged(true); 262 if (properties->polling.value()) 263 PollingChanged(true); 264 265 // Create peer objects for peers that were added before the adapter was set. 266 const ObjectPathVector& devices = 267 DBusThreadManager::Get()->GetNfcDeviceClient()-> 268 GetDevicesForAdapter(object_path_); 269 for (ObjectPathVector::const_iterator iter = devices.begin(); 270 iter != devices.end(); ++iter) { 271 const dbus::ObjectPath& object_path = *iter; 272 if (GetPeer(object_path.value())) 273 continue; 274 NfcPeerChromeOS* peer_chromeos = new NfcPeerChromeOS(object_path); 275 SetPeer(object_path.value(), peer_chromeos); 276 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 277 PeerFound(this, peer_chromeos)); 278 } 279 280 // Create tag objects for tags that were added before the adapter was set. 281 const std::vector<dbus::ObjectPath>& tags = 282 DBusThreadManager::Get()->GetNfcTagClient()-> 283 GetTagsForAdapter(object_path_); 284 for (std::vector<dbus::ObjectPath>::const_iterator iter = tags.begin(); 285 iter != tags.end(); ++iter) { 286 const dbus::ObjectPath& object_path = *iter; 287 if (GetTag(object_path.value())) 288 continue; 289 NfcTagChromeOS* tag_chromeos = new NfcTagChromeOS(object_path); 290 SetTag(object_path.value(), tag_chromeos); 291 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 292 TagFound(this, tag_chromeos)); 293 } 294} 295 296void NfcAdapterChromeOS::RemoveAdapter() { 297 DCHECK(IsPresent()); 298 VLOG(1) << "NFC adapter removed: " << object_path_.value(); 299 300 NfcAdapterClient::Properties* properties = 301 DBusThreadManager::Get()->GetNfcAdapterClient()-> 302 GetProperties(object_path_); 303 if (properties->powered.value()) 304 PoweredChanged(false); 305 if (properties->polling.value()) 306 PollingChanged(false); 307 308 // Copy the tags and peers here and clear the original containers so that 309 // GetPeers and GetTags return no values during the *Removed observer calls. 310 PeerList peers; 311 TagList tags; 312 GetPeers(&peers); 313 GetTags(&tags); 314 ClearPeers(); 315 ClearTags(); 316 317 for (PeerList::iterator iter = peers.begin(); 318 iter != peers.end(); ++iter) { 319 device::NfcPeer* peer = *iter; 320 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 321 PeerLost(this, peer)); 322 delete peer; 323 } 324 for (TagList::iterator iter = tags.begin(); 325 iter != tags.end(); ++iter) { 326 device::NfcTag* tag = *iter; 327 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 328 TagLost(this, tag)); 329 delete tag; 330 } 331 332 object_path_ = dbus::ObjectPath(""); 333 PresentChanged(false); 334} 335 336void NfcAdapterChromeOS::PoweredChanged(bool powered) { 337 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 338 AdapterPoweredChanged(this, powered)); 339} 340 341void NfcAdapterChromeOS::PollingChanged(bool polling) { 342 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 343 AdapterPollingChanged(this, polling)); 344} 345 346void NfcAdapterChromeOS::PresentChanged(bool present) { 347 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 348 AdapterPresentChanged(this, present)); 349} 350 351void NfcAdapterChromeOS::OnSetPowered(const base::Closure& callback, 352 const ErrorCallback& error_callback, 353 bool success) { 354 VLOG(1) << "NfcAdapterChromeOS::OnSetPowered result: " << success; 355 if (success) { 356 // TODO(armansito): There is a bug in neard 0.13 that causes it not to emit 357 // a signal when the "Powered" property changes. Sync the properties here, 358 // but remove it in neard 0.14. 359 if (IsPresent()) { 360 DBusThreadManager::Get()->GetNfcAdapterClient()-> 361 GetProperties(object_path_)->GetAll(); 362 } 363 callback.Run(); 364 } else { 365 LOG(ERROR) << "Failed to power up the NFC antenna radio."; 366 error_callback.Run(); 367 } 368} 369 370void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) { 371 callback.Run(); 372} 373 374void NfcAdapterChromeOS::OnStartPollingError( 375 const ErrorCallback& error_callback, 376 const std::string& error_name, 377 const std::string& error_message) { 378 LOG(ERROR) << object_path_.value() << ": Failed to start polling: " 379 << error_name << ": " << error_message; 380 error_callback.Run(); 381} 382 383void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) { 384 callback.Run(); 385} 386 387void NfcAdapterChromeOS::OnStopPollingError( 388 const ErrorCallback& error_callback, 389 const std::string& error_name, 390 const std::string& error_message) { 391 LOG(ERROR) << object_path_.value() << ": Failed to stop polling: " 392 << error_name << ": " << error_message; 393 error_callback.Run(); 394} 395 396} // namespace chromeos 397