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  // NfcRecordClient override.
75  virtual Properties* GetProperties(
76      const dbus::ObjectPath& object_path) OVERRIDE {
77    return static_cast<Properties*>(
78        devices_and_tags_to_object_maps_.FindObjectProperties(object_path));
79  }
80
81 protected:
82  // DBusClient override.
83  virtual void Init(dbus::Bus* bus) OVERRIDE {
84    VLOG(1) << "Creating NfcRecordClient impl";
85    DCHECK(bus);
86    bus_ = bus;
87    DCHECK(device_client_);
88    DCHECK(tag_client_);
89    device_client_->AddObserver(this);
90    tag_client_->AddObserver(this);
91  }
92
93 private:
94  // NfcDeviceClient::Observer override.
95  virtual void DeviceAdded(const dbus::ObjectPath& object_path) OVERRIDE {
96    VLOG(1) << "Device added. Creating map for record proxies belonging to "
97            << "device: " << object_path.value();
98    devices_and_tags_to_object_maps_.CreateObjectMap(
99        object_path, nfc_record::kNfcRecordServiceName, this, bus_);
100  }
101
102  // NfcDeviceClient::Observer override.
103  virtual void DeviceRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
104    // Neard doesn't send out property changed signals for the records that
105    // are removed when the device they belong to is removed. Clean up the
106    // object proxies for records that belong to the removed device.
107    // Note: DBusObjectMap guarantees that the Properties structure for the
108    // removed adapter will be valid before this method returns.
109    VLOG(1) << "Device removed. Cleaning up record proxies belonging to "
110            << "device: " << object_path.value();
111    devices_and_tags_to_object_maps_.RemoveObjectMap(object_path);
112  }
113
114  // NfcDeviceClient::Observer override.
115  virtual void DevicePropertyChanged(
116      const dbus::ObjectPath& object_path,
117      const std::string& property_name) OVERRIDE {
118    // Update the record proxies using records from the device.
119    DCHECK(device_client_);
120    NfcDeviceClient::Properties* device_properties =
121        device_client_->GetProperties(object_path);
122
123    // Ignore changes to properties other than "Records".
124    if (property_name != device_properties->records.name())
125      return;
126
127    // Update known records.
128    VLOG(1) << "NFC records changed.";
129    const std::vector<dbus::ObjectPath>& received_records =
130        device_properties->records.value();
131    DBusObjectMap* object_map =
132        devices_and_tags_to_object_maps_.GetObjectMap(object_path);
133    DCHECK(object_map);
134    object_map->UpdateObjects(received_records);
135  }
136
137  // NfcTagClient::Observer override.
138  virtual void TagAdded(const dbus::ObjectPath& object_path) OVERRIDE {
139    VLOG(1) << "Tag added. Creating map for record proxies belonging to "
140            << "tag: " << object_path.value();
141    devices_and_tags_to_object_maps_.CreateObjectMap(
142        object_path, nfc_record::kNfcRecordServiceName, this, bus_);
143  }
144
145  // NfcTagClient::Observer override.
146  virtual void TagRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
147    // Neard doesn't send out property changed signals for the records that
148    // are removed when the tag they belong to is removed. Clean up the
149    // object proxies for records that belong to the removed tag.
150    // Note: DBusObjectMap guarantees that the Properties structure for the
151    // removed adapter will be valid before this method returns.
152    VLOG(1) << "Tag removed. Cleaning up record proxies belonging to "
153            << "tag: " << object_path.value();
154    devices_and_tags_to_object_maps_.RemoveObjectMap(object_path);
155  }
156
157  // NfcTagClient::Observer override.
158  virtual void TagPropertyChanged(const dbus::ObjectPath& object_path,
159                                  const std::string& property_name) OVERRIDE {
160    // Update the record proxies using records from the tag.
161    DCHECK(device_client_);
162    NfcTagClient::Properties* tag_properties =
163        tag_client_->GetProperties(object_path);
164
165    // Ignore changes to properties other than "Records".
166    if (property_name != tag_properties->records.name())
167      return;
168
169    // Update known records.
170    VLOG(1) << "NFC records changed.";
171    const std::vector<dbus::ObjectPath>& received_records =
172        tag_properties->records.value();
173    DBusObjectMap* object_map =
174        devices_and_tags_to_object_maps_.GetObjectMap(object_path);
175    DCHECK(object_map);
176    object_map->UpdateObjects(received_records);
177
178    // When rewriting the record to a tag, neard fires a property changed
179    // signal for the tags "Records" property, without creating a new object
180    // path. Sync the properties of all records here, in case Update objects
181    // doesn't do it.
182    VLOG(1) << "Fetch properties for all records.";
183    object_map->RefreshAllProperties();
184  }
185
186  // nfc_client_helpers::DBusObjectMap::Delegate override.
187  virtual NfcPropertySet* CreateProperties(
188      dbus::ObjectProxy* object_proxy) OVERRIDE {
189    Properties* properties = new Properties(
190        object_proxy,
191        base::Bind(&NfcRecordClientImpl::OnPropertyChanged,
192                   weak_ptr_factory_.GetWeakPtr(),
193                   object_proxy->object_path()));
194    properties->SetAllPropertiesReceivedCallback(
195        base::Bind(&NfcRecordClientImpl::OnPropertiesReceived,
196                   weak_ptr_factory_.GetWeakPtr(),
197                   object_proxy->object_path()));
198    return properties;
199  }
200
201  // nfc_client_helpers::DBusObjectMap::Delegate override.
202  virtual void ObjectAdded(const dbus::ObjectPath& object_path) OVERRIDE {
203    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
204                      RecordAdded(object_path));
205  }
206
207  // nfc_client_helpers::DBusObjectMap::Delegate override.
208  virtual void ObjectRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
209    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
210                      RecordRemoved(object_path));
211  }
212
213  // Called by NfcPropertySet when a property value is changed, either by
214  // result of a signal or response to a GetAll() or Get() call.
215  void OnPropertyChanged(const dbus::ObjectPath& object_path,
216                         const std::string& property_name) {
217    VLOG(1) << "Record property changed; Path: " << object_path.value()
218            << " Property: " << property_name;
219    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
220                      RecordPropertyChanged(object_path, property_name));
221  }
222
223  // Called by NfcPropertySet when all properties have been processed as a
224  // result of a call to GetAll.
225  void OnPropertiesReceived(const dbus::ObjectPath& object_path) {
226    VLOG(1) << "All record properties received; Path: " << object_path.value();
227    FOR_EACH_OBSERVER(NfcRecordClient::Observer, observers_,
228                      RecordPropertiesReceived(object_path));
229  }
230
231  // We maintain a pointer to the bus to be able to request proxies for
232  // new NFC records that appear.
233  dbus::Bus* bus_;
234
235  // List of observers interested in event notifications.
236  ObserverList<NfcRecordClient::Observer> observers_;
237
238  // Mapping from object paths to object proxies and properties structures that
239  // were already created by us. Record objects belong to either Tag or Device
240  // objects. This structure stores a different DBusObjectMap for each known
241  // device and tag.
242  ObjectProxyTree devices_and_tags_to_object_maps_;
243
244  // The device and tag clients that we listen to events notifications from.
245  NfcDeviceClient* device_client_;
246  NfcTagClient* tag_client_;
247  // Weak pointer factory for generating 'this' pointers that might live longer
248  // than we do.
249  // Note: This should remain the last member so it'll be destroyed and
250  // invalidate its weak pointers before any other members are destroyed.
251  base::WeakPtrFactory<NfcRecordClientImpl> weak_ptr_factory_;
252
253  DISALLOW_COPY_AND_ASSIGN(NfcRecordClientImpl);
254};
255
256NfcRecordClient::NfcRecordClient() {
257}
258
259NfcRecordClient::~NfcRecordClient() {
260}
261
262NfcRecordClient* NfcRecordClient::Create(NfcDeviceClient* device_client,
263                                         NfcTagClient* tag_client) {
264  return new NfcRecordClientImpl(device_client, tag_client);
265}
266
267}  // namespace chromeos
268