nfc_adapter_client.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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_adapter_client.h"
6
7#include <map>
8#include <utility>
9
10#include "base/bind.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/observer_list.h"
13#include "base/strings/stringprintf.h"
14#include "chromeos/dbus/fake_nfc_adapter_client.h"
15#include "chromeos/dbus/nfc_manager_client.h"
16#include "dbus/bus.h"
17#include "dbus/message.h"
18#include "third_party/cros_system_api/dbus/service_constants.h"
19
20namespace chromeos {
21
22NfcAdapterClient::Properties::Properties(
23    dbus::ObjectProxy* object_proxy,
24    const PropertyChangedCallback& callback)
25    : NfcPropertySet(object_proxy,
26                     nfc_adapter::kNfcAdapterInterface,
27                     callback) {
28  RegisterProperty(nfc_adapter::kModeProperty, &mode);
29  RegisterProperty(nfc_adapter::kPoweredProperty, &powered);
30  RegisterProperty(nfc_adapter::kPollingProperty, &polling);
31  RegisterProperty(nfc_adapter::kProtocolsProperty, &protocols);
32  RegisterProperty(nfc_adapter::kTagsProperty, &tags);
33  RegisterProperty(nfc_adapter::kDevicesProperty, &devices);
34}
35
36NfcAdapterClient::Properties::~Properties() {
37}
38
39// The NfcAdapterClient implementation used in production.
40class NfcAdapterClientImpl
41    : public NfcAdapterClient,
42      public NfcManagerClient::Observer,
43      public nfc_client_helpers::DBusObjectMap::Delegate {
44 public:
45  explicit NfcAdapterClientImpl(NfcManagerClient* manager_client)
46      : initial_adapters_received_(false),
47        bus_(NULL),
48        manager_client_(manager_client),
49        weak_ptr_factory_(this) {
50    DCHECK(manager_client);
51  }
52
53  virtual ~NfcAdapterClientImpl() {
54    manager_client_->RemoveObserver(this);
55  }
56
57  // NfcAdapterClient override.
58  virtual void AddObserver(NfcAdapterClient::Observer* observer) OVERRIDE {
59    DCHECK(observer);
60    observers_.AddObserver(observer);
61  }
62
63  // NfcAdapterClient override.
64  virtual void RemoveObserver(NfcAdapterClient::Observer* observer) OVERRIDE {
65    DCHECK(observer);
66    observers_.RemoveObserver(observer);
67  }
68
69  // NfcAdapterClient override.
70  virtual Properties* GetProperties(const dbus::ObjectPath& object_path)
71      OVERRIDE {
72    return static_cast<Properties*>(
73        object_map_->GetObjectProperties(object_path));
74  }
75
76  // NfcAdapterClient override.
77  virtual void StartPollLoop(
78      const dbus::ObjectPath& object_path,
79      const std::string& mode,
80      const base::Closure& callback,
81      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE {
82    dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path);
83    if (!object_proxy) {
84      std::string error_message =
85          base::StringPrintf("NFC adapter with object path \"%s\" does not "
86                             "exist.", object_path.value().c_str());
87      LOG(ERROR) << error_message;
88      error_callback.Run(nfc_client_helpers::kUnknownObjectError,
89                         error_message);
90      return;
91    }
92    dbus::MethodCall method_call(nfc_adapter::kNfcAdapterInterface,
93                                 nfc_adapter::kStartPollLoop);
94    dbus::MessageWriter writer(&method_call);
95    writer.AppendString(mode);
96    object_proxy->CallMethodWithErrorCallback(
97        &method_call,
98        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
99        base::Bind(&nfc_client_helpers::OnSuccess, callback),
100        base::Bind(&nfc_client_helpers::OnError, error_callback));
101  }
102
103  // NfcAdapterClient override.
104  virtual void StopPollLoop(
105      const dbus::ObjectPath& object_path,
106      const base::Closure& callback,
107      const nfc_client_helpers::ErrorCallback& error_callback) OVERRIDE {
108    dbus::ObjectProxy* object_proxy = object_map_->GetObjectProxy(object_path);
109    if (!object_proxy) {
110      std::string error_message =
111          base::StringPrintf("NFC adapter with object path \"%s\" does not "
112                             "exist.", object_path.value().c_str());
113      LOG(ERROR) << error_message;
114      error_callback.Run(nfc_client_helpers::kUnknownObjectError,
115                         error_message);
116      return;
117    }
118    dbus::MethodCall method_call(nfc_adapter::kNfcAdapterInterface,
119                                 nfc_adapter::kStopPollLoop);
120    object_proxy->CallMethodWithErrorCallback(
121        &method_call,
122        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
123        base::Bind(&nfc_client_helpers::OnSuccess, callback),
124        base::Bind(&nfc_client_helpers::OnError, error_callback));
125  }
126
127 protected:
128  // DBusClient override.
129  virtual void Init(dbus::Bus* bus) OVERRIDE {
130    VLOG(1) << "Creating NfcAdapterClientImpl";
131    DCHECK(bus);
132    bus_ = bus;
133    object_map_.reset(new nfc_client_helpers::DBusObjectMap(
134        nfc_adapter::kNfcAdapterServiceName, this, bus));
135    DCHECK(manager_client_);
136    manager_client_->AddObserver(this);
137  }
138
139 private:
140  // NfcManagerClient::Observer override.
141  virtual void AdapterAdded(const dbus::ObjectPath& object_path) OVERRIDE {
142    VLOG(1) << "AdapterAdded: " << object_path.value();
143    // Initialize the object proxy here, so that observers can start receiving
144    // notifications for it and it is cached for reuse. Note that, even if we
145    // miss this signal, a proxy will be created on demand for any object paths
146    // that are passed to the public methods later.
147    object_map_->AddObject(object_path);
148    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
149                      AdapterAdded(object_path));
150  }
151
152  // NfcManagerClient::Observer override.
153  virtual void AdapterRemoved(const dbus::ObjectPath& object_path) OVERRIDE {
154    VLOG(1) << "AdapterRemoved: " << object_path.value();
155    // Remove the object proxy, as we know that the adapter no longer exists.
156    // Note that this doesn't prevent a client from recreating a proxy for an
157    // object path that is no longer valid, as proxies are created on demand as
158    // necessary by the public methods.
159    object_map_->RemoveObject(object_path);
160    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
161                      AdapterRemoved(object_path));
162  }
163
164  // NfcManagerClient::Observer override.
165  virtual void ManagerPropertyChanged(const std::string& property_name)
166        OVERRIDE {
167    NfcManagerClient::Properties* manager_properties =
168        manager_client_->GetProperties();
169    if (!initial_adapters_received_ &&
170        property_name == manager_properties->adapters.name()) {
171      initial_adapters_received_ = true;
172      VLOG(1) << "Initial set of adapters received.";
173      // Create proxies for all adapters that are known to the manager, so that
174      // observers can start getting notified for any signals emitted by
175      // adapters. We use the PropertyChanged signal from manager only to
176      // create proxies for the initial fetch. We rely on the AdapterAdded and
177      // AdapterRemoved signals after that.
178      std::vector<dbus::ObjectPath> adapters =
179          manager_properties->adapters.value();
180      for (std::vector<dbus::ObjectPath>::iterator iter = adapters.begin();
181           iter != adapters.end(); ++iter) {
182        VLOG(1) << "Creating proxy for: " << iter->value();
183        object_map_->AddObject(*iter);
184      }
185    }
186  }
187
188  // nfc_client_helpers::DBusObjectMap::Delegate override.
189  virtual NfcPropertySet* CreateProperties(
190      dbus::ObjectProxy* object_proxy) OVERRIDE {
191    return new Properties(
192        object_proxy,
193        base::Bind(&NfcAdapterClientImpl::OnPropertyChanged,
194                   weak_ptr_factory_.GetWeakPtr(),
195                   object_proxy->object_path()));
196  }
197
198  // Called by NfcPropertySet when a property value is changed, either by
199  // result of a signal or response to a GetAll() or Get() call.
200  void OnPropertyChanged(const dbus::ObjectPath& object_path,
201                         const std::string& property_name) {
202    VLOG(1) << "Adapter property changed; Path: " << object_path.value()
203            << " Property: " << property_name;
204    FOR_EACH_OBSERVER(NfcAdapterClient::Observer, observers_,
205                      AdapterPropertyChanged(object_path, property_name));
206  }
207
208  // This variable stores whether or not we have ever been notified of
209  // ManagerPropertiesChanged. This is used to bootstrap adapter proxies
210  // after receiving the initial set of properties from the NFC manager.
211  bool initial_adapters_received_;
212
213  // We maintain a pointer to the bus to be able to request proxies for
214  // new NFC adapters that appear.
215  dbus::Bus* bus_;
216
217  // Mapping from object paths to object proxies and properties structures that
218  // were already created by us.
219  scoped_ptr<nfc_client_helpers::DBusObjectMap> object_map_;
220
221  // The manager client that we listen to events notifications from.
222  NfcManagerClient* manager_client_;
223
224  // List of observers interested in event notifications.
225  ObserverList<NfcAdapterClient::Observer> observers_;
226
227  // Weak pointer factory for generating 'this' pointers that might live longer
228  // than we do.
229  // Note: This should remain the last member so it'll be destroyed and
230  // invalidate its weak pointers before any other members are destroyed.
231  base::WeakPtrFactory<NfcAdapterClientImpl> weak_ptr_factory_;
232
233  DISALLOW_COPY_AND_ASSIGN(NfcAdapterClientImpl);
234};
235
236NfcAdapterClient::NfcAdapterClient() {
237}
238
239NfcAdapterClient::~NfcAdapterClient() {
240}
241
242NfcAdapterClient* NfcAdapterClient::Create(DBusClientImplementationType type,
243                                           NfcManagerClient* manager_client) {
244  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
245    return new NfcAdapterClientImpl(manager_client);
246  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
247  return new FakeNfcAdapterClient();
248}
249
250}  // namespace chromeos
251