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
NfcAdapterChromeOS()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
~NfcAdapterChromeOS()32 NfcAdapterChromeOS::~NfcAdapterChromeOS() {
33 DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this);
34 DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this);
35 DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this);
36 }
37
AddObserver(NfcAdapter::Observer * observer)38 void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) {
39 DCHECK(observer);
40 observers_.AddObserver(observer);
41 }
42
RemoveObserver(NfcAdapter::Observer * observer)43 void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) {
44 DCHECK(observer);
45 observers_.RemoveObserver(observer);
46 }
47
IsPresent() const48 bool NfcAdapterChromeOS::IsPresent() const {
49 return !object_path_.value().empty();
50 }
51
IsPowered() const52 bool NfcAdapterChromeOS::IsPowered() const {
53 if (!IsPresent())
54 return false;
55 return DBusThreadManager::Get()->GetNfcAdapterClient()->
56 GetProperties(object_path_)->powered.value();
57 }
58
IsPolling() const59 bool NfcAdapterChromeOS::IsPolling() const {
60 if (!IsPresent())
61 return false;
62 return DBusThreadManager::Get()->GetNfcAdapterClient()->
63 GetProperties(object_path_)->polling.value();
64 }
65
IsInitialized() const66 bool NfcAdapterChromeOS::IsInitialized() const {
67 return true;
68 }
69
SetPowered(bool powered,const base::Closure & callback,const ErrorCallback & error_callback)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
StartPolling(const base::Closure & callback,const ErrorCallback & error_callback)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
StopPolling(const base::Closure & callback,const ErrorCallback & error_callback)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
AdapterAdded(const dbus::ObjectPath & object_path)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
AdapterRemoved(const dbus::ObjectPath & object_path)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
AdapterPropertyChanged(const dbus::ObjectPath & object_path,const std::string & property_name)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
DeviceAdded(const dbus::ObjectPath & object_path)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
DeviceRemoved(const dbus::ObjectPath & object_path)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
DevicePropertyChanged(const dbus::ObjectPath & object_path,const std::string & property_name)167 void NfcAdapterChromeOS::DevicePropertyChanged(
168 const dbus::ObjectPath& object_path,
169 const std::string& property_name) {
170 // TODO(armansito): Implement device logic.
171 }
172
TagAdded(const dbus::ObjectPath & object_path)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
TagRemoved(const dbus::ObjectPath & object_path)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
TagPropertyChanged(const dbus::ObjectPath & object_path,const std::string & property_name)183 void NfcAdapterChromeOS::TagPropertyChanged(
184 const dbus::ObjectPath& object_path,
185 const std::string& property_name) {
186 // TODO(armansito): Implement tag logic.
187 }
188
SetAdapter(const dbus::ObjectPath & object_path)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
RemoveAdapter()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
PoweredChanged(bool powered)244 void NfcAdapterChromeOS::PoweredChanged(bool powered) {
245 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
246 AdapterPoweredChanged(this, powered));
247 }
248
PollingChanged(bool polling)249 void NfcAdapterChromeOS::PollingChanged(bool polling) {
250 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
251 AdapterPollingChanged(this, polling));
252 }
253
PresentChanged(bool present)254 void NfcAdapterChromeOS::PresentChanged(bool present) {
255 FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
256 AdapterPresentChanged(this, present));
257 }
258
OnSetPowered(const base::Closure & callback,const ErrorCallback & error_callback,bool success)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
OnStartPolling(const base::Closure & callback)278 void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) {
279 callback.Run();
280 }
281
OnStartPollingError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)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
OnStopPolling(const base::Closure & callback)291 void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) {
292 callback.Run();
293 }
294
OnStopPollingError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)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