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