blob: 374e8ac83e94901efc4e87b28e7899f58c846e73 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/nfc/nfc_adapter_chromeos.h"
#include <vector>
#include "base/callback.h"
#include "base/logging.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "device/nfc/nfc_peer_chromeos.h"
#include "device/nfc/nfc_tag_chromeos.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
namespace {
typedef std::vector<dbus::ObjectPath> ObjectPathVector;
} // namespace
NfcAdapterChromeOS::NfcAdapterChromeOS()
: weak_ptr_factory_(this) {
DBusThreadManager::Get()->GetNfcAdapterClient()->AddObserver(this);
DBusThreadManager::Get()->GetNfcDeviceClient()->AddObserver(this);
DBusThreadManager::Get()->GetNfcTagClient()->AddObserver(this);
const ObjectPathVector& object_paths =
DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters();
if (!object_paths.empty()) {
VLOG(1) << object_paths.size() << " NFC adapter(s) available.";
SetAdapter(object_paths[0]);
}
}
NfcAdapterChromeOS::~NfcAdapterChromeOS() {
DBusThreadManager::Get()->GetNfcAdapterClient()->RemoveObserver(this);
DBusThreadManager::Get()->GetNfcDeviceClient()->RemoveObserver(this);
DBusThreadManager::Get()->GetNfcTagClient()->RemoveObserver(this);
}
void NfcAdapterChromeOS::AddObserver(NfcAdapter::Observer* observer) {
DCHECK(observer);
observers_.AddObserver(observer);
}
void NfcAdapterChromeOS::RemoveObserver(NfcAdapter::Observer* observer) {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
bool NfcAdapterChromeOS::IsPresent() const {
return !object_path_.value().empty();
}
bool NfcAdapterChromeOS::IsPowered() const {
if (!IsPresent())
return false;
return DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_)->powered.value();
}
bool NfcAdapterChromeOS::IsPolling() const {
if (!IsPresent())
return false;
return DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_)->polling.value();
}
bool NfcAdapterChromeOS::IsInitialized() const {
return true;
}
void NfcAdapterChromeOS::SetPowered(bool powered,
const base::Closure& callback,
const ErrorCallback& error_callback) {
if (!IsPresent()) {
LOG(WARNING) << "Adapter not present. Cannot power up the antenna.";
error_callback.Run();
return;
}
DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_)->powered.Set(
powered,
base::Bind(&NfcAdapterChromeOS::OnSetPowered,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
void NfcAdapterChromeOS::StartPolling(const base::Closure& callback,
const ErrorCallback& error_callback) {
// Always poll in "Initiator" mode.
DBusThreadManager::Get()->GetNfcAdapterClient()->
StartPollLoop(object_path_,
nfc_adapter::kModeInitiator,
base::Bind(&NfcAdapterChromeOS::OnStartPolling,
weak_ptr_factory_.GetWeakPtr(),
callback),
base::Bind(&NfcAdapterChromeOS::OnStartPollingError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
}
void NfcAdapterChromeOS::StopPolling(const base::Closure& callback,
const ErrorCallback& error_callback) {
DBusThreadManager::Get()->GetNfcAdapterClient()->
StopPollLoop(object_path_,
base::Bind(&NfcAdapterChromeOS::OnStopPolling,
weak_ptr_factory_.GetWeakPtr(),
callback),
base::Bind(&NfcAdapterChromeOS::OnStopPollingError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
}
void NfcAdapterChromeOS::AdapterAdded(const dbus::ObjectPath& object_path) {
// Set the adapter to the newly added adapter only if no adapter is present.
if (!IsPresent())
SetAdapter(object_path);
}
void NfcAdapterChromeOS::AdapterRemoved(const dbus::ObjectPath& object_path) {
if (object_path != object_path_)
return;
// The current adapter was removed, so mark us as not present and clean up
// peers and tags.
RemoveAdapter();
// There may still be other adapters present on the system. Set the next
// available adapter as the current one.
const ObjectPathVector& object_paths =
DBusThreadManager::Get()->GetNfcAdapterClient()->GetAdapters();
for (ObjectPathVector::const_iterator iter =
object_paths.begin();
iter != object_paths.end(); ++iter) {
// The removed object will still be available until the call to
// AdapterRemoved returns. Make sure that we are not re-adding the
// removed adapter.
if (*iter == object_path)
continue;
SetAdapter(*iter);
}
}
void NfcAdapterChromeOS::AdapterPropertyChanged(
const dbus::ObjectPath& object_path,
const std::string& property_name) {
if (object_path != object_path_)
return;
NfcAdapterClient::Properties* properties =
DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_);
if (property_name == properties->powered.name())
PoweredChanged(properties->powered.value());
else if (property_name == properties->polling.name())
PollingChanged(properties->polling.value());
}
void NfcAdapterChromeOS::DeviceAdded(const dbus::ObjectPath& object_path) {
if (!IsPresent())
return;
if (GetPeer(object_path.value()))
return;
VLOG(1) << "NFC device found: " << object_path.value();
// Check to see if the device belongs to this adapter.
const ObjectPathVector& devices =
DBusThreadManager::Get()->GetNfcDeviceClient()->
GetDevicesForAdapter(object_path_);
bool device_found = false;
for (ObjectPathVector::const_iterator iter = devices.begin();
iter != devices.end(); ++iter) {
if (*iter == object_path) {
device_found = true;
break;
}
}
if (!device_found) {
VLOG(1) << "Found peer device does not belong to the current adapter.";
return;
}
// Create the peer object.
NfcPeerChromeOS* peer_chromeos = new NfcPeerChromeOS(object_path);
SetPeer(object_path.value(), peer_chromeos);
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
PeerFound(this, peer_chromeos));
}
void NfcAdapterChromeOS::DeviceRemoved(const dbus::ObjectPath& object_path) {
VLOG(1) << "NFC device lost: " << object_path.value();
device::NfcPeer* peer = RemovePeer(object_path.value());
if (!peer) {
VLOG(1) << "Removed peer device does not belong to the current adapter.";
return;
}
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, PeerLost(this, peer));
delete peer;
}
void NfcAdapterChromeOS::TagAdded(const dbus::ObjectPath& object_path) {
if (!IsPresent())
return;
if (GetTag(object_path.value()))
return;
VLOG(1) << "NFC tag found: " << object_path.value();
// Check to see if the tag belongs to this adapter.
const std::vector<dbus::ObjectPath>& tags =
DBusThreadManager::Get()->GetNfcTagClient()->
GetTagsForAdapter(object_path_);
bool tag_found = false;
for (std::vector<dbus::ObjectPath>::const_iterator iter = tags.begin();
iter != tags.end(); ++iter) {
if (*iter == object_path) {
tag_found = true;
break;
}
}
if (!tag_found) {
VLOG(1) << "Found tag does not belong to the current adapter.";
return;
}
// Create the tag object.
NfcTagChromeOS* tag_chromeos = new NfcTagChromeOS(object_path);
SetTag(object_path.value(), tag_chromeos);
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
TagFound(this, tag_chromeos));
}
void NfcAdapterChromeOS::TagRemoved(const dbus::ObjectPath& object_path) {
VLOG(1) << "NFC tag lost : " << object_path.value();
device::NfcTag* tag = RemoveTag(object_path.value());
if (!tag) {
VLOG(1) << "Removed tag does not belong to the current adapter.";
return;
}
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_, TagLost(this, tag));
delete tag;
}
void NfcAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) {
DCHECK(!IsPresent());
object_path_ = object_path;
VLOG(1) << "Using NFC adapter: " << object_path.value();
NfcAdapterClient::Properties* properties =
DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_);
PresentChanged(true);
if (properties->powered.value())
PoweredChanged(true);
if (properties->polling.value())
PollingChanged(true);
// Create peer objects for peers that were added before the adapter was set.
const ObjectPathVector& devices =
DBusThreadManager::Get()->GetNfcDeviceClient()->
GetDevicesForAdapter(object_path_);
for (ObjectPathVector::const_iterator iter = devices.begin();
iter != devices.end(); ++iter) {
const dbus::ObjectPath& object_path = *iter;
if (GetPeer(object_path.value()))
continue;
NfcPeerChromeOS* peer_chromeos = new NfcPeerChromeOS(object_path);
SetPeer(object_path.value(), peer_chromeos);
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
PeerFound(this, peer_chromeos));
}
// Create tag objects for tags that were added before the adapter was set.
const std::vector<dbus::ObjectPath>& tags =
DBusThreadManager::Get()->GetNfcTagClient()->
GetTagsForAdapter(object_path_);
for (std::vector<dbus::ObjectPath>::const_iterator iter = tags.begin();
iter != tags.end(); ++iter) {
const dbus::ObjectPath& object_path = *iter;
if (GetTag(object_path.value()))
continue;
NfcTagChromeOS* tag_chromeos = new NfcTagChromeOS(object_path);
SetTag(object_path.value(), tag_chromeos);
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
TagFound(this, tag_chromeos));
}
}
void NfcAdapterChromeOS::RemoveAdapter() {
DCHECK(IsPresent());
VLOG(1) << "NFC adapter removed: " << object_path_.value();
NfcAdapterClient::Properties* properties =
DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_);
if (properties->powered.value())
PoweredChanged(false);
if (properties->polling.value())
PollingChanged(false);
// Copy the tags and peers here and clear the original containers so that
// GetPeers and GetTags return no values during the *Removed observer calls.
PeerList peers;
TagList tags;
GetPeers(&peers);
GetTags(&tags);
ClearPeers();
ClearTags();
for (PeerList::iterator iter = peers.begin();
iter != peers.end(); ++iter) {
device::NfcPeer* peer = *iter;
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
PeerLost(this, peer));
delete peer;
}
for (TagList::iterator iter = tags.begin();
iter != tags.end(); ++iter) {
device::NfcTag* tag = *iter;
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
TagLost(this, tag));
delete tag;
}
object_path_ = dbus::ObjectPath("");
PresentChanged(false);
}
void NfcAdapterChromeOS::PoweredChanged(bool powered) {
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
AdapterPoweredChanged(this, powered));
}
void NfcAdapterChromeOS::PollingChanged(bool polling) {
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
AdapterPollingChanged(this, polling));
}
void NfcAdapterChromeOS::PresentChanged(bool present) {
FOR_EACH_OBSERVER(NfcAdapter::Observer, observers_,
AdapterPresentChanged(this, present));
}
void NfcAdapterChromeOS::OnSetPowered(const base::Closure& callback,
const ErrorCallback& error_callback,
bool success) {
VLOG(1) << "NfcAdapterChromeOS::OnSetPowered result: " << success;
if (success) {
// TODO(armansito): There is a bug in neard 0.13 that causes it not to emit
// a signal when the "Powered" property changes. Sync the properties here,
// but remove it in neard 0.14.
if (IsPresent()) {
DBusThreadManager::Get()->GetNfcAdapterClient()->
GetProperties(object_path_)->GetAll();
}
callback.Run();
} else {
LOG(ERROR) << "Failed to power up the NFC antenna radio.";
error_callback.Run();
}
}
void NfcAdapterChromeOS::OnStartPolling(const base::Closure& callback) {
callback.Run();
}
void NfcAdapterChromeOS::OnStartPollingError(
const ErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
LOG(ERROR) << object_path_.value() << ": Failed to start polling: "
<< error_name << ": " << error_message;
error_callback.Run();
}
void NfcAdapterChromeOS::OnStopPolling(const base::Closure& callback) {
callback.Run();
}
void NfcAdapterChromeOS::OnStopPollingError(
const ErrorCallback& error_callback,
const std::string& error_name,
const std::string& error_message) {
LOG(ERROR) << object_path_.value() << ": Failed to stop polling: "
<< error_name << ": " << error_message;
error_callback.Run();
}
} // namespace chromeos