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_record_client.h"
6
7#include "base/bind.h"
8#include "base/memory/weak_ptr.h"
9#include "base/observer_list.h"
10#include "chromeos/dbus/nfc_device_client.h"
11#include "chromeos/dbus/nfc_tag_client.h"
12#include "dbus/bus.h"
13#include "third_party/cros_system_api/dbus/service_constants.h"
14
15using chromeos::nfc_client_helpers::DBusObjectMap;
16using chromeos::nfc_client_helpers::ObjectProxyTree;
17
18namespace chromeos {
19
20NfcRecordClient::Properties::Properties(
21    dbus::ObjectProxy* object_proxy,
22    const PropertyChangedCallback& callback)
23    : NfcPropertySet(object_proxy,
24                     nfc_record::kNfcRecordInterface,
25                     callback) {
26  RegisterProperty(nfc_record::kTypeProperty, &type);
27  RegisterProperty(nfc_record::kLanguageProperty, &language);
28  RegisterProperty(nfc_record::kEncodingProperty, &encoding);
29  RegisterProperty(nfc_record::kRepresentationProperty, &representation);
30  RegisterProperty(nfc_record::kUriProperty, &uri);
31  RegisterProperty(nfc_record::kMimeTypeProperty, &mime_type);
32  RegisterProperty(nfc_record::kSizeProperty, &size);
33  RegisterProperty(nfc_record::kActionProperty, &action);
34}
35
36NfcRecordClient::Properties::~Properties() {
37}
38
39// The NfcRecordClient implementation used in production.
40class NfcRecordClientImpl : public NfcRecordClient,
41                            public NfcDeviceClient::Observer,
42                            public NfcTagClient::Observer,
43                            public DBusObjectMap::Delegate {
44 public:
45  explicit NfcRecordClientImpl(NfcDeviceClient* device_client,
46                               NfcTagClient* tag_client)
47      : bus_(NULL),
48        device_client_(device_client),
49        tag_client_(tag_client),
50        weak_ptr_factory_(this) {
51    DCHECK(device_client);
52    DCHECK(tag_client);
53  }
54
55  virtual ~NfcRecordClientImpl() {
56    DCHECK(device_client_);
57    DCHECK(tag_client_);
58    device_client_->RemoveObserver(this);
59    tag_client_->RemoveObserver(this);
60  }
61
62  // NfcRecordClient override.
63  virtual void AddObserver(NfcRecordClient::Observer* observer) OVERRIDE {
64    DCHECK(observer);
65    observers_.AddObserver(observer);
66  }
67
68  // NfcRecordClient override.
69  virtual void RemoveObserver(NfcRecordClient::Observer* observer) OVERRIDE {
70    DCHECK(observer);
71    observers_.RemoveObserver(observer);
72  }
73
74  virtual std::vector<dbus::ObjectPath> GetRecordsForDevice(
75      const dbus::ObjectPath& device_path) OVERRIDE {
76    DBusObjectMap* object_map =
77        devices_and_tags_to_object_maps_.GetObjectMap(device_path);
78    if (!object_map)
79      return std::vector<dbus::ObjectPath>();
80    return object_map->GetObjectPaths();
81  }
82
83  virtual std::vector<dbus::ObjectPath> GetRecordsForTag(
84      const dbus::ObjectPath& tag_path) OVERRIDE {
85    return GetRecordsForDevice(tag_path);
86  }
87
88  // NfcRecordClient override.
89  virtual Properties* GetProperties(
90      const dbus::ObjectPath& object_path) OVERRIDE {
91    return static_cast<Properties*>(
92        devices_and_tags_to_object_maps_.FindObjectProperties(object_path));
93  }
94
95 protected:
96  // DBusClient override.
97  virtual void Init(dbus::Bus* bus) OVERRIDE {
98    VLOG(1) << "Creating NfcRecordClient impl";
99    DCHECK(bus);
100    bus_ = bus;
101    DCHECK(device_client_);
102    DCHECK(tag_client_);
103    device_client_->AddObserver(this);
104    tag_client_->AddObserver(this);
105  }
106
107 private:
108  // NfcDeviceClient::Observer override.
109  virtual void DeviceAdded(const dbus::ObjectPath& object_path) OVERRIDE {
110    VLOG(1) << "Device added. Creating map for record proxies belonging to "
111            << "device: " << object_path.value();
112    devices_and_tags_to_object_maps_.CreateObjectMap(
113        object_path, nfc_record::kNfcRecordServiceName, this, bus_);
114  }
115
116  // NfcDeviceClient::Observer override.
117  virtual void DeviceRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
118    // Neard doesn't send out property changed signals for the records that
119    // are removed when the device they belong to is removed. Clean up the
120    // object proxies for records that belong to the removed device.
121    // Note: DBusObjectMap guarantees that the Properties structure for the
122    // removed adapter will be valid before this method returns.
123    VLOG(1) << "Device removed. Cleaning up record proxies belonging to "
124            << "device: " << object_path.value();
125    devices_and_tags_to_object_maps_.RemoveObjectMap(object_path);
126  }
127
128  // NfcDeviceClient::Observer override.
129  virtual void DevicePropertyChanged(
130      const dbus::ObjectPath& object_path,
131      const std::string& property_name) OVERRIDE {
132    // Update the record proxies using records from the device.
133    DCHECK(device_client_);
134    NfcDeviceClient::Properties* device_properties =
135        device_client_->GetProperties(object_path);
136
137    // Ignore changes to properties other than "Records".
138    if (property_name != device_properties->records.name())
139      return;
140
141    // Update known records.
142    VLOG(1) << "NFC records changed.";
143    const std::vector<dbus::ObjectPath>& received_records =
144        device_properties->records.value();
145    DBusObjectMap* object_map =
146        devices_and_tags_to_object_maps_.GetObjectMap(object_path);
147    DCHECK(object_map);
148    object_map->UpdateObjects(received_records);
149  }
150
151  // NfcTagClient::Observer override.
152  virtual void TagAdded(const dbus::ObjectPath& object_path) OVERRIDE {
153    VLOG(1) << "Tag added. Creating map for record proxies belonging to "
154            << "tag: " << object_path.value();
155    devices_and_tags_to_object_maps_.CreateObjectMap(
156        object_path, nfc_record::kNfcRecordServiceName, this, bus_);
157  }
158
159  // NfcTagClient::Observer override.
160  virtual void TagRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
161    // Neard doesn't send out property changed signals for the records that
162    // are removed when the tag they belong to is removed. Clean up the
163    // object proxies for records that belong to the removed tag.
164    // Note: DBusObjectMap guarantees that the Properties structure for the
165    // removed adapter will be valid before this method returns.
166    VLOG(1) << "Tag removed. Cleaning up record proxies belonging to "
167            << "tag: " << object_path.value();
168    devices_and_tags_to_object_maps_.RemoveObjectMap(object_path);
169  }
170
171  // NfcTagClient::Observer override.
172  virtual void TagPropertyChanged(const dbus::ObjectPath& object_path,
173                                  const std::string& property_name) OVERRIDE {
174    // Update the record proxies using records from the tag.
175    DCHECK(device_client_);
176    NfcTagClient::Properties* tag_properties =
177        tag_client_->GetProperties(object_path);
178
179    // Ignore changes to properties other than "Records".
180    if (property_name != tag_properties->records.name())
181      return;
182
183    // Update known records.
184    VLOG(1) << "NFC records changed.";
185    const std::vector<dbus::ObjectPath>& received_records =
186        tag_properties->records.value();
187    DBusObjectMap* object_map =
188        devices_and_tags_to_object_maps_.GetObjectMap(object_path);
189    DCHECK(object_map);
190    object_map->UpdateObjects(received_records);
191
192    // When rewriting the record to a tag, neard fires a property changed
193    // signal for the tags "Records" property, without creating a new object
194    // path. Sync the properties of all records here, in case Update objects
195    // doesn't do it.
196    VLOG(1) << "Fetch properties for all records.";
197    object_map->RefreshAllProperties();
198  }
199
200  // nfc_client_helpers::DBusObjectMap::Delegate override.
201  virtual NfcPropertySet* CreateProperties(
202      dbus::ObjectProxy* object_proxy) OVERRIDE {
203    Properties* properties = new Properties(
204        object_proxy,
205        base::Bind(&NfcRecordClientImpl::OnPropertyChanged,
206                   weak_ptr_factory_.GetWeakPtr(),
207                   object_proxy->object_path()));
208    properties->SetAllPropertiesReceivedCallback(
209        base::Bind(&NfcRecordClientImpl::OnPropertiesReceived,
210                   weak_ptr_factory_.GetWeakPtr(),
211                   object_proxy->object_path()));
212    return properties;
213  }
214
215  // nfc_client_helpers::DBusObjectMap::Delegate override.
216  virtual void ObjectAdded(const dbus::ObjectPath& object_path) OVERRIDE {
217    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
218                      RecordAdded(object_path));
219  }
220
221  // nfc_client_helpers::DBusObjectMap::Delegate override.
222  virtual void ObjectRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
223    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
224                      RecordRemoved(object_path));
225  }
226
227  // Called by NfcPropertySet when a property value is changed, either by
228  // result of a signal or response to a GetAll() or Get() call.
229  void OnPropertyChanged(const dbus::ObjectPath& object_path,
230                         const std::string& property_name) {
231    VLOG(1) << "Record property changed; Path: " << object_path.value()
232            << " Property: " << property_name;
233    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
234                      RecordPropertyChanged(object_path, property_name));
235  }
236
237  // Called by NfcPropertySet when all properties have been processed as a
238  // result of a call to GetAll.
239  void OnPropertiesReceived(const dbus::ObjectPath& object_path) {
240    VLOG(1) << "All record properties received; Path: " << object_path.value();
241    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
242                      RecordPropertiesReceived(object_path));
243  }
244
245  // We maintain a pointer to the bus to be able to request proxies for
246  // new NFC records that appear.
247  dbus::Bus* bus_;
248
249  // List of observers interested in event notifications.
250  ObserverList<NfcRecordClient::Observer> observers_;
251
252  // Mapping from object paths to object proxies and properties structures that
253  // were already created by us. Record objects belong to either Tag or Device
254  // objects. This structure stores a different DBusObjectMap for each known
255  // device and tag.
256  ObjectProxyTree devices_and_tags_to_object_maps_;
257
258  // The device and tag clients that we listen to events notifications from.
259  NfcDeviceClient* device_client_;
260  NfcTagClient* tag_client_;
261  // Weak pointer factory for generating 'this' pointers that might live longer
262  // than we do.
263  // Note: This should remain the last member so it'll be destroyed and
264  // invalidate its weak pointers before any other members are destroyed.
265  base::WeakPtrFactory<NfcRecordClientImpl> weak_ptr_factory_;
266
267  DISALLOW_COPY_AND_ASSIGN(NfcRecordClientImpl);
268};
269
270NfcRecordClient::NfcRecordClient() {
271}
272
273NfcRecordClient::~NfcRecordClient() {
274}
275
276NfcRecordClient* NfcRecordClient::Create(NfcDeviceClient* device_client,
277                                         NfcTagClient* tag_client) {
278  return new NfcRecordClientImpl(device_client, tag_client);
279}
280
281}  // namespace chromeos
282