Home | History | Annotate | Download | only in dbus
      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 "chromeos/dbus/nfc_tag_client.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/weak_ptr.h"
      9 #include "base/observer_list.h"
     10 #include "base/strings/stringprintf.h"
     11 #include "chromeos/dbus/nfc_adapter_client.h"
     12 #include "dbus/bus.h"
     13 #include "dbus/message.h"
     14 #include "dbus/values_util.h"
     15 #include "third_party/cros_system_api/dbus/service_constants.h"
     16 
     17 using chromeos::nfc_client_helpers::DBusObjectMap;
     18 using chromeos::nfc_client_helpers::ObjectProxyTree;
     19 
     20 namespace chromeos {
     21 
     22 NfcTagClient::Properties::Properties(
     23     dbus::ObjectProxy* object_proxy,
     24     const PropertyChangedCallback& callback)
     25     : NfcPropertySet(object_proxy,
     26                      nfc_tag::kNfcTagInterface,
     27                      callback) {
     28   RegisterProperty(nfc_tag::kTypeProperty, &type);
     29   RegisterProperty(nfc_tag::kProtocolProperty, &protocol);
     30   RegisterProperty(nfc_tag::kRecordsProperty, &records);
     31   RegisterProperty(nfc_tag::kReadOnlyProperty, &read_only);
     32 }
     33 
     34 NfcTagClient::Properties::~Properties() {
     35 }
     36 
     37 // The NfcTagClient implementation used in production.
     38 class NfcTagClientImpl : public NfcTagClient,
     39                          public NfcAdapterClient::Observer,
     40                          public DBusObjectMap::Delegate {
     41  public:
     42   explicit NfcTagClientImpl(NfcAdapterClient* adapter_client)
     43       : bus_(NULL),
     44         adapter_client_(adapter_client),
     45         weak_ptr_factory_(this) {
     46     DCHECK(adapter_client);
     47   }
     48 
     49   virtual ~NfcTagClientImpl() {
     50     DCHECK(adapter_client_);
     51     adapter_client_->RemoveObserver(this);
     52   }
     53 
     54   // NfcTagClient override.
     55   virtual void AddObserver(NfcTagClient::Observer* observer) OVERRIDE {
     56     DCHECK(observer);
     57     observers_.AddObserver(observer);
     58   }
     59 
     60   // NfcTagClient override.
     61   virtual void RemoveObserver(NfcTagClient::Observer* observer) OVERRIDE {
     62     DCHECK(observer);
     63     observers_.RemoveObserver(observer);
     64   }
     65 
     66   // NfcTagClient override.
     67   virtual std::vector<dbus::ObjectPath> GetTagsForAdapter(
     68       const dbus::ObjectPath& adapter_path) OVERRIDE {
     69     DBusObjectMap* object_map =
     70         adapters_to_object_maps_.GetObjectMap(adapter_path);
     71     if (!object_map)
     72       return std::vector<dbus::ObjectPath>();
     73     return object_map->GetObjectPaths();
     74   }
     75 
     76   // NfcTagClient override.
     77   virtual Properties* GetProperties(
     78       const dbus::ObjectPath& object_path) OVERRIDE {
     79     return static_cast<Properties*>(
     80         adapters_to_object_maps_.FindObjectProperties(object_path));
     81   }
     82 
     83   // NfcTagClient override.
     84   virtual void Write(
     85       const dbus::ObjectPath& object_path,
     86       const base::DictionaryValue& attributes,
     87       const base::Closure& callback,
     88       const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE {
     89     dbus::ObjectProxy* object_proxy =
     90         adapters_to_object_maps_.FindObjectProxy(object_path);
     91     if (!object_proxy) {
     92       std::string error_message =
     93           base::StringPrintf("NFC tag with object path \"%s\" does not exist.",
     94                              object_path.value().c_str());
     95       LOG(ERROR) << error_message;
     96       error_callback.Run(nfc_client_helpers::kUnknownObjectError,
     97                          error_message);
     98       return;
     99     }
    100 
    101     // |attributes| should not be empty.
    102     if (attributes.empty()) {
    103       std::string error_message =
    104           "Cannot write data to tag with empty arguments.";
    105       LOG(ERROR) << error_message;
    106       error_callback.Run(nfc_error::kInvalidArguments, error_message);
    107       return;
    108     }
    109 
    110     // Create the arguments.
    111     dbus::MethodCall method_call(nfc_tag::kNfcTagInterface, nfc_tag::kWrite);
    112     dbus::MessageWriter writer(&method_call);
    113     dbus::AppendValueData(&writer, attributes);
    114 
    115     object_proxy->CallMethodWithErrorCallback(
    116         &method_call,
    117         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    118         base::Bind(&nfc_client_helpers::OnSuccess, callback),
    119         base::Bind(&nfc_client_helpers::OnError, error_callback));
    120   }
    121 
    122  protected:
    123   // DBusClient override.
    124   virtual void Init(dbus::Bus* bus) OVERRIDE {
    125     VLOG(1) << "Creating NfcTagClientImpl";
    126     DCHECK(bus);
    127     bus_ = bus;
    128     DCHECK(adapter_client_);
    129     adapter_client_->AddObserver(this);
    130   }
    131 
    132  private:
    133   // NfcAdapterClient::Observer override.
    134   virtual void AdapterAdded(const dbus::ObjectPath& object_path) OVERRIDE {
    135     VLOG(1) << "Adapter added. Creating map for tag proxies belonging to "
    136             << "adapter: " << object_path.value();
    137     adapters_to_object_maps_.CreateObjectMap(
    138         object_path, nfc_tag::kNfcTagServiceName, this, bus_);
    139   }
    140 
    141   // NfcAdapterClient::Observer override.
    142   virtual void AdapterRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
    143     // Neard doesn't send out property changed signals for the tags that
    144     // are removed when the adapter they belong to is removed. Clean up the
    145     // object proxies for devices that are managed by the removed adapter.
    146     // Note: DBusObjectMap guarantees that the Properties structure for the
    147     // removed adapter will be valid before this method returns.
    148     VLOG(1) << "Adapter removed. Cleaning up tag proxies belonging to "
    149             << "adapter: " << object_path.value();
    150     adapters_to_object_maps_.RemoveObjectMap(object_path);
    151   }
    152 
    153   // NfcAdapterClient::Observer override.
    154   virtual void AdapterPropertyChanged(
    155       const dbus::ObjectPath& object_path,
    156       const std::string& property_name) OVERRIDE {
    157     // Update the tag proxies.
    158     DCHECK(adapter_client_);
    159     NfcAdapterClient::Properties *adapter_properties =
    160         adapter_client_->GetProperties(object_path);
    161     DCHECK(adapter_properties);
    162     if (!adapter_properties) {
    163       LOG(ERROR) << "No property structure found for adapter: "
    164                  << object_path.value();
    165       return;
    166     }
    167 
    168     // Ignore changes to properties other than "Tags".
    169     if (property_name != adapter_properties->tags.name())
    170       return;
    171 
    172     // Update the known tags.
    173     VLOG(1) << "NFC tags changed.";
    174     const std::vector<dbus::ObjectPath>& received_tags =
    175         adapter_properties->tags.value();
    176     DBusObjectMap* object_map =
    177         adapters_to_object_maps_.GetObjectMap(object_path);
    178     DCHECK(object_map);
    179     object_map->UpdateObjects(received_tags);
    180   }
    181 
    182   // nfc_client_helpers::DBusObjectMap::Delegate override.
    183   virtual NfcPropertySet* CreateProperties(
    184       dbus::ObjectProxy* object_proxy) OVERRIDE {
    185     Properties* properties = new Properties(
    186         object_proxy,
    187         base::Bind(&NfcTagClientImpl::OnPropertyChanged,
    188                    weak_ptr_factory_.GetWeakPtr(),
    189                    object_proxy->object_path()));
    190     properties->SetAllPropertiesReceivedCallback(
    191         base::Bind(&NfcTagClientImpl::OnPropertiesReceived,
    192                    weak_ptr_factory_.GetWeakPtr(),
    193                    object_proxy->object_path()));
    194     return properties;
    195   }
    196 
    197   // nfc_client_helpers::DBusObjectMap::Delegate override.
    198   virtual void ObjectAdded(const dbus::ObjectPath& object_path) OVERRIDE {
    199     FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_,
    200                       TagAdded(object_path));
    201   }
    202 
    203   virtual void ObjectRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
    204     FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_,
    205                       TagRemoved(object_path));
    206   }
    207 
    208   // Called by NfcPropertySet when a property value is changed, either by
    209   // result of a signal or response to a GetAll() or Get() call.
    210   void OnPropertyChanged(const dbus::ObjectPath& object_path,
    211                          const std::string& property_name) {
    212     VLOG(1) << "Tag property changed; Path: " << object_path.value()
    213             << " Property: " << property_name;
    214     FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_,
    215                       TagPropertyChanged(object_path, property_name));
    216   }
    217 
    218   // Called by NfcPropertySet when all properties have been processed as a
    219   // result of a call to GetAll.
    220   void OnPropertiesReceived(const dbus::ObjectPath& object_path) {
    221     VLOG(1) << "All tag properties received; Path: " << object_path.value();
    222     FOR_EACH_OBSERVER(NfcTagClient::Observer, observers_,
    223                       TagPropertiesReceived(object_path));
    224   }
    225 
    226   // We maintain a pointer to the bus to be able to request proxies for
    227   // new NFC tags that appear.
    228   dbus::Bus* bus_;
    229 
    230   // List of observers interested in event notifications.
    231   ObserverList<NfcTagClient::Observer> observers_;
    232 
    233   // Mapping from object paths to object proxies and properties structures that
    234   // were already created by us. This stucture stores a different DBusObjectMap
    235   // for each known NFC adapter object path.
    236   ObjectProxyTree adapters_to_object_maps_;
    237 
    238   // The adapter client that we listen to events notifications from.
    239   NfcAdapterClient* adapter_client_;
    240 
    241   // Weak pointer factory for generating 'this' pointers that might live longer
    242   // than we do.
    243   // Note: This should remain the last member so it'll be destroyed and
    244   // invalidate its weak pointers before any other members are destroyed.
    245   base::WeakPtrFactory<NfcTagClientImpl> weak_ptr_factory_;
    246 
    247   DISALLOW_COPY_AND_ASSIGN(NfcTagClientImpl);
    248 };
    249 
    250 NfcTagClient::NfcTagClient() {
    251 }
    252 
    253 NfcTagClient::~NfcTagClient() {
    254 }
    255 
    256 NfcTagClient* NfcTagClient::Create(NfcAdapterClient* adapter_client) {
    257   return new NfcTagClientImpl(adapter_client);
    258 }
    259 
    260 }  // namespace chromeos
    261