Home | History | Annotate | Download | only in nfc
      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 
     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 
     38 NfcAdapterChromeOS::~NfcAdapterChromeOS() {
     39   DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this);
     40   DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this);
     41   DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this);
     42 }
     43 
     44 void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) {
     45   DCHECK(observer);
     46   observers_.AddObserver(observer);
     47 }
     48 
     49 void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) {
     50   DCHECK(observer);
     51   observers_.RemoveObserver(observer);
     52 }
     53 
     54 bool NfcAdapterChromeOS::IsPresent() const {
     55   return !object_path_.value().empty();
     56 }
     57 
     58 bool NfcAdapterChromeOS::IsPowered() const {
     59   if (!IsPresent())
     60     return false;
     61   return DBusThreadManager::Get()->GetNfcAdapterClient()->
     62       GetProperties(object_path_)->powered.value();
     63 }
     64 
     65 bool NfcAdapterChromeOS::IsPolling() const {
     66   if (!IsPresent())
     67     return false;
     68   return DBusThreadManager::Get()->GetNfcAdapterClient()->
     69       GetProperties(object_path_)->polling.value();
     70 }
     71 
     72 bool NfcAdapterChromeOS::IsInitialized() const {
     73   return true;
     74 }
     75 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    336 void NfcAdapterChromeOS::PoweredChanged(bool powered) {
    337   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
    338                     AdapterPoweredChanged(this, powered));
    339 }
    340 
    341 void NfcAdapterChromeOS::PollingChanged(bool polling) {
    342   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
    343                     AdapterPollingChanged(this, polling));
    344 }
    345 
    346 void NfcAdapterChromeOS::PresentChanged(bool present) {
    347   FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
    348                     AdapterPresentChanged(this, present));
    349 }
    350 
    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 
    370 void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) {
    371   callback.Run();
    372 }
    373 
    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 
    383 void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) {
    384   callback.Run();
    385 }
    386 
    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