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.h" 13 #include "device/nfc/nfc_tag.h" 14 #include "third_party/cros_system_api/dbus/service_constants.h" 15 16 namespace chromeos { 17 18 NfcAdapterChromeOS::NfcAdapterChromeOS() 19 : weak_ptr_factory_(this) { 20 DBusThreadManager::Get()->GetNfcAdapterClient()->AddObserver(this); 21 DBusThreadManager::Get()->GetNfcDeviceClient()->AddObserver(this); 22 DBusThreadManager::Get()->GetNfcTagClient()->AddObserver(this); 23 24 const std::vector<dbus::ObjectPath>& object_paths = 25 DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters(); 26 if (!object_paths.empty()) { 27 VLOG(1) << object_paths.size() << " NFC adapter(s) available."; 28 SetAdapter(object_paths[0]); 29 } 30 } 31 32 NfcAdapterChromeOS::~NfcAdapterChromeOS() { 33 DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this); 34 DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this); 35 DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this); 36 } 37 38 void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) { 39 DCHECK(observer); 40 observers_.AddObserver(observer); 41 } 42 43 void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) { 44 DCHECK(observer); 45 observers_.RemoveObserver(observer); 46 } 47 48 bool NfcAdapterChromeOS::IsPresent() const { 49 return !object_path_.value().empty(); 50 } 51 52 bool NfcAdapterChromeOS::IsPowered() const { 53 if (!IsPresent()) 54 return false; 55 return DBusThreadManager::Get()->GetNfcAdapterClient()-> 56 GetProperties(object_path_)->powered.value(); 57 } 58 59 bool NfcAdapterChromeOS::IsPolling() const { 60 if (!IsPresent()) 61 return false; 62 return DBusThreadManager::Get()->GetNfcAdapterClient()-> 63 GetProperties(object_path_)->polling.value(); 64 } 65 66 bool NfcAdapterChromeOS::IsInitialized() const { 67 return true; 68 } 69 70 void NfcAdapterChromeOS::SetPowered(bool powered, 71 const base::Closure& callback, 72 const ErrorCallback& error_callback) { 73 if (!IsPresent()) { 74 LOG(WARNING) << "Adapter not present. Cannot power up the antenna."; 75 error_callback.Run(); 76 return; 77 } 78 DBusThreadManager::Get()->GetNfcAdapterClient()-> 79 GetProperties(object_path_)->powered.Set( 80 powered, 81 base::Bind(&NfcAdapterChromeOS::OnSetPowered, 82 weak_ptr_factory_.GetWeakPtr(), 83 callback, 84 error_callback)); 85 } 86 87 void NfcAdapterChromeOS::StartPolling(const base::Closure& callback, 88 const ErrorCallback& error_callback) { 89 // Always poll in "Initiator" mode. 90 DBusThreadManager::Get()->GetNfcAdapterClient()-> 91 StartPollLoop(object_path_, 92 nfc_adapter::kModeInitiator, 93 base::Bind(&NfcAdapterChromeOS::OnStartPolling, 94 weak_ptr_factory_.GetWeakPtr(), 95 callback), 96 base::Bind(&NfcAdapterChromeOS::OnStartPollingError, 97 weak_ptr_factory_.GetWeakPtr(), 98 error_callback)); 99 } 100 101 void NfcAdapterChromeOS::StopPolling(const base::Closure& callback, 102 const ErrorCallback& error_callback) { 103 DBusThreadManager::Get()->GetNfcAdapterClient()-> 104 StopPollLoop(object_path_, 105 base::Bind(&NfcAdapterChromeOS::OnStopPolling, 106 weak_ptr_factory_.GetWeakPtr(), 107 callback), 108 base::Bind(&NfcAdapterChromeOS::OnStopPollingError, 109 weak_ptr_factory_.GetWeakPtr(), 110 error_callback)); 111 } 112 113 void NfcAdapterChromeOS::AdapterAdded(const dbus::ObjectPath& object_path) { 114 // Set the adapter to the newly added adapter only if no adapter is present. 115 if (!IsPresent()) 116 SetAdapter(object_path); 117 } 118 119 void NfcAdapterChromeOS::AdapterRemoved(const dbus::ObjectPath& object_path) { 120 if (object_path != object_path_) 121 return; 122 123 // The current adapter was removed, so mark us as not present and clean up 124 // peers and tags. 125 RemoveAdapter(); 126 127 // There may still be other adapters present on the system. Set the next 128 // available adapter as the current one. 129 const std::vector<dbus::ObjectPath>& object_paths = 130 DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters(); 131 for (std::vector<dbus::ObjectPath>::const_iterator iter = 132 object_paths.begin(); 133 iter != object_paths.end(); ++iter) { 134 // The removed object will still be available until the call to 135 // AdapterRemoved returns. Make sure that we are not re-adding the 136 // removed adapter. 137 if (*iter == object_path) 138 continue; 139 SetAdapter(*iter); 140 } 141 } 142 143 void NfcAdapterChromeOS::AdapterPropertyChanged( 144 const dbus::ObjectPath& object_path, 145 const std::string& property_name) { 146 if (object_path != object_path_) 147 return; 148 NfcAdapterClient::Properties* properties = 149 DBusThreadManager::Get()->GetNfcAdapterClient()-> 150 GetProperties(object_path_); 151 if (property_name == properties->powered.name()) 152 PoweredChanged(properties->powered.value()); 153 else if (property_name == properties->polling.name()) 154 PollingChanged(properties->polling.value()); 155 } 156 157 void NfcAdapterChromeOS::DeviceAdded(const dbus::ObjectPath& object_path) { 158 VLOG(1) << "NFC device found: " << object_path.value(); 159 // TODO(armansito): Implement device logic. 160 } 161 162 void NfcAdapterChromeOS::DeviceRemoved(const dbus::ObjectPath& object_path) { 163 VLOG(1) << "NFC device lost: " << object_path.value(); 164 // TODO(armansito): Implement device logic. 165 } 166 167 void NfcAdapterChromeOS::DevicePropertyChanged( 168 const dbus::ObjectPath& object_path, 169 const std::string& property_name) { 170 // TODO(armansito): Implement device logic. 171 } 172 173 void NfcAdapterChromeOS::TagAdded(const dbus::ObjectPath& object_path) { 174 VLOG(1) << "NFC tag found: " << object_path.value(); 175 // TODO(armansito): Implement tag logic. 176 } 177 178 void NfcAdapterChromeOS::TagRemoved(const dbus::ObjectPath& object_path) { 179 VLOG(1) << "NFC tag found: " << object_path.value(); 180 // TODO(armansito): Implement tag logic. 181 } 182 183 void NfcAdapterChromeOS::TagPropertyChanged( 184 const dbus::ObjectPath& object_path, 185 const std::string& property_name) { 186 // TODO(armansito): Implement tag logic. 187 } 188 189 void NfcAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) { 190 DCHECK(!IsPresent()); 191 object_path_ = object_path; 192 VLOG(1) << "Using NFC adapter: " << object_path.value(); 193 194 NfcAdapterClient::Properties* properties = 195 DBusThreadManager::Get()->GetNfcAdapterClient()-> 196 GetProperties(object_path_); 197 PresentChanged(true); 198 if (properties->powered.value()) 199 PoweredChanged(true); 200 if (properties->polling.value()) 201 PollingChanged(true); 202 203 // TODO(armansito): Create device::NfcPeer and device::NfcTag instances for 204 // all peers and tags that exist, once they have been implemented for 205 // ChromeOS. 206 } 207 208 void NfcAdapterChromeOS::RemoveAdapter() { 209 DCHECK(IsPresent()); 210 VLOG(1) << "NFC adapter removed: " << object_path_.value(); 211 212 NfcAdapterClient::Properties* properties = 213 DBusThreadManager::Get()->GetNfcAdapterClient()-> 214 GetProperties(object_path_); 215 if (properties->powered.value()) 216 PoweredChanged(false); 217 if (properties->polling.value()) 218 PollingChanged(false); 219 220 // Copy the tags and peers here and clear the original containers so that 221 // GetPeers and GetTags return no values during the *Removed observer calls. 222 PeersMap peers = peers_; 223 TagsMap tags = tags_; 224 peers_.clear(); 225 tags_.clear(); 226 227 for (PeersMap::iterator iter = peers_.begin(); 228 iter != peers_.end(); ++iter) { 229 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 230 PeerLost(this, iter->second)); 231 delete iter->second; 232 } 233 for (TagsMap::iterator iter = tags_.begin(); 234 iter != tags_.end(); ++iter) { 235 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 236 TagLost(this, iter->second)); 237 delete iter->second; 238 } 239 240 object_path_ = dbus::ObjectPath(""); 241 PresentChanged(false); 242 } 243 244 void NfcAdapterChromeOS::PoweredChanged(bool powered) { 245 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 246 AdapterPoweredChanged(this, powered)); 247 } 248 249 void NfcAdapterChromeOS::PollingChanged(bool polling) { 250 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 251 AdapterPollingChanged(this, polling)); 252 } 253 254 void NfcAdapterChromeOS::PresentChanged(bool present) { 255 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, 256 AdapterPresentChanged(this, present)); 257 } 258 259 void NfcAdapterChromeOS::OnSetPowered(const base::Closure& callback, 260 const ErrorCallback& error_callback, 261 bool success) { 262 VLOG(1) << "NfcAdapterChromeOS::OnSetPowered result: " << success; 263 if (success) { 264 // TODO(armansito): There is a bug in neard 0.13 that causes it not to emit 265 // a signal when the "Powered" property changes. Sync the properties here, 266 // but remove it in neard 0.14. 267 if (IsPresent()) { 268 DBusThreadManager::Get()->GetNfcAdapterClient()-> 269 GetProperties(object_path_)->GetAll(); 270 } 271 callback.Run(); 272 } else { 273 LOG(WARNING) << "Failed to power up the NFC antenna radio."; 274 error_callback.Run(); 275 } 276 } 277 278 void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) { 279 callback.Run(); 280 } 281 282 void NfcAdapterChromeOS::OnStartPollingError( 283 const ErrorCallback& error_callback, 284 const std::string& error_name, 285 const std::string& error_message) { 286 LOG(WARNING) << object_path_.value() << ": Failed to start polling: " 287 << error_name << ": " << error_message; 288 error_callback.Run(); 289 } 290 291 void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) { 292 callback.Run(); 293 } 294 295 void NfcAdapterChromeOS::OnStopPollingError( 296 const ErrorCallback& error_callback, 297 const std::string& error_name, 298 const std::string& error_message) { 299 LOG(WARNING) << object_path_.value() << ": Failed to stop polling: " 300 << error_name << ": " << error_message; 301 error_callback.Run(); 302 } 303 304 } // namespace chromeos 305