• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 namespace chromeos {
17 
18 namespace {
19 
20 typedef std::vector<dbus::ObjectPath> ObjectPathVector;
21 
22 }  // namespace
23 
NfcAdapterChromeOS()24 NfcAdapterChromeOS::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 
~NfcAdapterChromeOS()38 NfcAdapterChromeOS::~NfcAdapterChromeOS() {
39   DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this);
40   DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this);
41   DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this);
42 }
43 
AddObserver(NfcAdapter::Observer * observer)44 void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) {
45   DCHECK(observer);
46   observers_.AddObserver(observer);
47 }
48 
RemoveObserver(NfcAdapter::Observer * observer)49 void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) {
50   DCHECK(observer);
51   observers_.RemoveObserver(observer);
52 }
53 
IsPresent() const54 bool NfcAdapterChromeOS::IsPresent() const {
55   return !object_path_.value().empty();
56 }
57 
IsPowered() const58 bool NfcAdapterChromeOS::IsPowered() const {
59   if (!IsPresent())
60     return false;
61   return DBusThreadManager::Get()->GetNfcAdapterClient()->
62       GetProperties(object_path_)->powered.value();
63 }
64 
IsPolling() const65 bool NfcAdapterChromeOS::IsPolling() const {
66   if (!IsPresent())
67     return false;
68   return DBusThreadManager::Get()->GetNfcAdapterClient()->
69       GetProperties(object_path_)->polling.value();
70 }
71 
IsInitialized() const72 bool NfcAdapterChromeOS::IsInitialized() const {
73   return true;
74 }
75 
SetPowered(bool powered,const base::Closure & callback,const ErrorCallback & error_callback)76 void 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 
StartPolling(const base::Closure & callback,const ErrorCallback & error_callback)93 void 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 
StopPolling(const base::Closure & callback,const ErrorCallback & error_callback)107 void 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 
AdapterAdded(const dbus::ObjectPath & object_path)119 void 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 
AdapterRemoved(const dbus::ObjectPath & object_path)125 void 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 
AdapterPropertyChanged(const dbus::ObjectPath & object_path,const std::string & property_name)149 void 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 
DeviceAdded(const dbus::ObjectPath & object_path)163 void 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 
DeviceRemoved(const dbus::ObjectPath & object_path)196 void 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 
TagAdded(const dbus::ObjectPath & object_path)207 void 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 
TagRemoved(const dbus::ObjectPath & object_path)240 void 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 
SetAdapter(const dbus::ObjectPath & object_path)251 void 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 
RemoveAdapter()296 void 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 
PoweredChanged(bool powered)336 void NfcAdapterChromeOS::PoweredChanged(bool powered) {
337   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
338                     AdapterPoweredChanged(this, powered));
339 }
340 
PollingChanged(bool polling)341 void NfcAdapterChromeOS::PollingChanged(bool polling) {
342   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
343                     AdapterPollingChanged(this, polling));
344 }
345 
PresentChanged(bool present)346 void NfcAdapterChromeOS::PresentChanged(bool present) {
347   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
348                     AdapterPresentChanged(this, present));
349 }
350 
OnSetPowered(const base::Closure & callback,const ErrorCallback & error_callback,bool success)351 void 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 
OnStartPolling(const base::Closure & callback)370 void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) {
371   callback.Run();
372 }
373 
OnStartPollingError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)374 void 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 
OnStopPolling(const base::Closure & callback)383 void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) {
384   callback.Run();
385 }
386 
OnStopPollingError(const ErrorCallback & error_callback,const std::string & error_name,const std::string & error_message)387 void 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