diff options
Diffstat (limited to 'chromeos/dbus/nfc_tag_client.cc')
-rw-r--r-- | chromeos/dbus/nfc_tag_client.cc | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/chromeos/dbus/nfc_tag_client.cc b/chromeos/dbus/nfc_tag_client.cc new file mode 100644 index 0000000..37f3c0a --- /dev/null +++ b/chromeos/dbus/nfc_tag_client.cc @@ -0,0 +1,250 @@ +// 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 "chromeos/dbus/nfc_tag_client.h" + +#include <set> + +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "chromeos/dbus/fake_nfc_tag_client.h" +#include "chromeos/dbus/nfc_adapter_client.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using chromeos::nfc_client_helpers::DBusObjectMap; + +namespace chromeos { + +namespace { + +typedef std::vector<dbus::ObjectPath> ObjectPathVector; + +} // namespace + +NfcTagClient::Properties::Properties( + dbus::ObjectProxy* object_proxy, + const PropertyChangedCallback& callback) + : NfcPropertySet(object_proxy, + nfc_tag::kNfcTagInterface, + callback) { + RegisterProperty(nfc_tag::kTypeProperty, &type); + RegisterProperty(nfc_tag::kProtocolProperty, &protocol); + RegisterProperty(nfc_tag::kRecordsProperty, &records); + RegisterProperty(nfc_tag::kReadOnlyProperty, &read_only); +} + +NfcTagClient::Properties::~Properties() { +} + +// The NfcTagClient implementation used in production. +class NfcTagClientImpl : public NfcTagClient, + public NfcAdapterClient::Observer, + public nfc_client_helpers::DBusObjectMap::Delegate { + public: + explicit NfcTagClientImpl(NfcAdapterClient* adapter_client) + : bus_(NULL), + adapter_client_(adapter_client), + weak_ptr_factory_(this) { + DCHECK(adapter_client); + } + + virtual ~NfcTagClientImpl() { + adapter_client_->RemoveObserver(this); + } + + // NfcTagClient override. + virtual void AddObserver(NfcTagClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.AddObserver(observer); + } + + // NfcTagClient override. + virtual void RemoveObserver(NfcTagClient::Observer* observer) OVERRIDE { + DCHECK(observer); + observers_.RemoveObserver(observer); + } + + // NfcTagClient override. + virtual Properties* GetProperties(const dbus::ObjectPath& object_path) + OVERRIDE { + return static_cast<Properties*>( + object_map_->GetObjectProperties(object_path)); + } + + // NfcTagClient override. + virtual void Write( + const dbus::ObjectPath& object_path, + const RecordAttributes& attributes, + const base::Closure& callback, + const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE { + dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path); + if (!object_proxy) { + std::string error_message = + base::StringPrintf("NFC tag with object path \"%s\" does not exist.", + object_path.value().c_str()); + LOG(ERROR) << error_message; + error_callback.Run(nfc_client_helpers::kUnknownObjectError, + error_message); + return; + } + + // |attributes| should not be empty. + if (attributes.empty()) { + std::string error_message = + "Cannot write data to tag with empty arguments."; + LOG(ERROR) << error_message; + error_callback.Run(nfc_error::kInvalidArguments, error_message); + return; + } + + // Create the arguments. + dbus::MethodCall method_call(nfc_tag::kNfcTagInterface, nfc_tag::kWrite); + dbus::MessageWriter writer(&method_call); + dbus::MessageWriter array_writer(NULL); + dbus::MessageWriter dict_entry_writer(NULL); + writer.OpenArray("{sv}", &array_writer); + for (RecordAttributes::const_iterator iter = attributes.begin(); + iter != attributes.end(); ++iter) { + array_writer.OpenDictEntry(&dict_entry_writer); + dict_entry_writer.AppendString(iter->first); + dict_entry_writer.AppendVariantOfString(iter->second); + array_writer.CloseContainer(&dict_entry_writer); + } + writer.CloseContainer(&array_writer); + + object_proxy->CallMethodWithErrorCallback( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&nfc_client_helpers::OnSuccess, callback), + base::Bind(&nfc_client_helpers::OnError, error_callback)); + } + + protected: + // DBusClient override. + virtual void Init(dbus::Bus* bus) OVERRIDE { + VLOG(1) << "Creating NfcTagClientImpl"; + DCHECK(bus); + bus_ = bus; + object_map_.reset(new nfc_client_helpers::DBusObjectMap( + nfc_tag::kNfcTagServiceName, this, bus)); + DCHECK(adapter_client_); + adapter_client_->AddObserver(this); + } + + private: + // NfcAdapterClient::Observer override. + virtual void AdapterPropertyChanged( + const dbus::ObjectPath& object_path, + const std::string& property_name) OVERRIDE { + // Update the tag proxies. + DCHECK(adapter_client_); + NfcAdapterClient::Properties *adapter_properties = + adapter_client_->GetProperties(object_path); + + // Ignore changes to properties other than "Tags". + if (property_name != adapter_properties->tags.name()) + return; + + VLOG(1) << "NFC tags changed."; + + // Add all the new tags. + const ObjectPathVector& received_tags = + adapter_properties->tags.value(); + for (ObjectPathVector::const_iterator iter = received_tags.begin(); + iter != received_tags.end(); ++iter) { + const dbus::ObjectPath &tag_path = *iter; + if (object_map_->AddObject(tag_path)) { + VLOG(1) << "Found NFC tag: " << tag_path.value(); + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagFound(tag_path, object_path)); + } + } + + // Remove all tags that were lost. + const DBusObjectMap::ObjectMap& known_tags = + object_map_->object_map(); + std::set<dbus::ObjectPath> tags_set(received_tags.begin(), + received_tags.end()); + DBusObjectMap::ObjectMap::const_iterator iter = known_tags.begin(); + while (iter != known_tags.end()) { + // Make a copy here, as the iterator will be invalidated by + // DBusObjectMap::RemoveObject below, but |device_path| is needed to + // notify observers right after. We want to make sure that we notify + // the observers AFTER we remove the object, so that method calls + // to the removed object paths in observer implementations fail + // gracefully. + dbus::ObjectPath tag_path = iter->first; + ++iter; + if (!ContainsKey(tags_set, tag_path)) { + VLOG(1) << "Lost NFC tag: " << tag_path.value(); + object_map_->RemoveObject(tag_path); + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagLost(tag_path, object_path)); + } + } + } + + // nfc_client_helpers::DBusObjectMap::Delegate override. + virtual NfcPropertySet* CreateProperties( + dbus::ObjectProxy* object_proxy) OVERRIDE { + return new Properties( + object_proxy, + base::Bind(&NfcTagClientImpl::OnPropertyChanged, + weak_ptr_factory_.GetWeakPtr(), + object_proxy->object_path())); + } + + // Called by NfcPropertySet when a property value is changed, either by + // result of a signal or response to a GetAll() or Get() call. + void OnPropertyChanged(const dbus::ObjectPath& object_path, + const std::string& property_name) { + VLOG(1) << "Tag property changed; Path: " << object_path.value() + << " Property: " << property_name; + FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_, + TagPropertyChanged(object_path, property_name)); + } + + // We maintain a pointer to the bus to be able to request proxies for + // new NFC tags that appear. + dbus::Bus* bus_; + + // Mapping from object paths to object proxies and properties structures that + // were already created by us. + scoped_ptr<nfc_client_helpers::DBusObjectMap> object_map_; + + // The manager client that we listen to events notifications from. + NfcAdapterClient* adapter_client_; + + // List of observers interested in event notifications. + ObserverList<NfcTagClient::Observer> observers_; + + // Weak pointer factory for generating 'this' pointers that might live longer + // than we do. + // Note: This should remain the last member so it'll be destroyed and + // invalidate its weak pointers before any other members are destroyed. + base::WeakPtrFactory<NfcTagClientImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(NfcTagClientImpl); +}; + +NfcTagClient::NfcTagClient() { +} + +NfcTagClient::~NfcTagClient() { +} + +NfcTagClient* NfcTagClient::Create(DBusClientImplementationType type, + NfcAdapterClient* adapter_client) { + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) + return new NfcTagClientImpl(adapter_client); + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); + return new FakeNfcTagClient(); +} + +} // namespace chromeos |