1// Copyright (c) 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/fake_bluetooth_adapter_client.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "base/time/time.h"
11#include "chromeos/dbus/dbus_thread_manager.h"
12#include "chromeos/dbus/fake_bluetooth_device_client.h"
13#include "dbus/object_path.h"
14#include "third_party/cros_system_api/dbus/service_constants.h"
15
16namespace {
17
18// Amount of time to wait after a command before performing it.
19const int kCommandEffectsTimeMs = 500;
20
21}
22
23namespace chromeos {
24
25const char FakeBluetoothAdapterClient::kAdapterPath[] =
26    "/fake/hci0";
27const char FakeBluetoothAdapterClient::kAdapterName[] =
28    "Fake Adapter";
29const char FakeBluetoothAdapterClient::kAdapterAddress[] =
30    "01:1a:2b:1a:2b:03";
31
32const char FakeBluetoothAdapterClient::kSecondAdapterPath[] =
33    "/fake/hci1";
34const char FakeBluetoothAdapterClient::kSecondAdapterName[] =
35    "Second Fake Adapter";
36const char FakeBluetoothAdapterClient::kSecondAdapterAddress[] =
37    "00:de:51:10:01:00";
38
39FakeBluetoothAdapterClient::Properties::Properties(
40    const PropertyChangedCallback& callback)
41    : BluetoothAdapterClient::Properties(
42        NULL,
43        bluetooth_adapter::kBluetoothAdapterInterface,
44        callback) {
45}
46
47FakeBluetoothAdapterClient::Properties::~Properties() {
48}
49
50void FakeBluetoothAdapterClient::Properties::Get(
51    dbus::PropertyBase* property,
52    dbus::PropertySet::GetCallback callback) {
53  VLOG(1) << "Get " << property->name();
54  callback.Run(false);
55}
56
57void FakeBluetoothAdapterClient::Properties::GetAll() {
58  VLOG(1) << "GetAll";
59}
60
61void FakeBluetoothAdapterClient::Properties::Set(
62    dbus::PropertyBase *property,
63    dbus::PropertySet::SetCallback callback) {
64  VLOG(1) << "Set " << property->name();
65  if (property->name() == powered.name() || property->name() == alias.name()) {
66    callback.Run(true);
67    property->ReplaceValueWithSetValue();
68  } else {
69    callback.Run(false);
70  }
71}
72
73
74FakeBluetoothAdapterClient::FakeBluetoothAdapterClient()
75    : visible_(true),
76      second_visible_(false),
77      discovering_count_(0) {
78  properties_.reset(new Properties(base::Bind(
79      &FakeBluetoothAdapterClient::OnPropertyChanged,
80      base::Unretained(this))));
81
82  properties_->address.ReplaceValue(kAdapterAddress);
83  properties_->name.ReplaceValue("Fake Adapter (Name)");
84  properties_->alias.ReplaceValue(kAdapterName);
85  properties_->pairable.ReplaceValue(true);
86
87  second_properties_.reset(new Properties(base::Bind(
88      &FakeBluetoothAdapterClient::OnPropertyChanged,
89      base::Unretained(this))));
90
91  second_properties_->address.ReplaceValue(kSecondAdapterAddress);
92  second_properties_->name.ReplaceValue("Second Fake Adapter (Name)");
93  second_properties_->alias.ReplaceValue(kSecondAdapterName);
94  second_properties_->pairable.ReplaceValue(true);
95}
96
97FakeBluetoothAdapterClient::~FakeBluetoothAdapterClient() {
98}
99
100void FakeBluetoothAdapterClient::AddObserver(Observer* observer) {
101  observers_.AddObserver(observer);
102}
103
104void FakeBluetoothAdapterClient::RemoveObserver(Observer* observer) {
105  observers_.RemoveObserver(observer);
106}
107
108std::vector<dbus::ObjectPath> FakeBluetoothAdapterClient::GetAdapters() {
109  std::vector<dbus::ObjectPath> object_paths;
110  if (visible_)
111    object_paths.push_back(dbus::ObjectPath(kAdapterPath));
112  if (second_visible_)
113    object_paths.push_back(dbus::ObjectPath(kSecondAdapterPath));
114  return object_paths;
115}
116
117FakeBluetoothAdapterClient::Properties*
118FakeBluetoothAdapterClient::GetProperties(const dbus::ObjectPath& object_path) {
119  if (object_path == dbus::ObjectPath(kAdapterPath))
120    return properties_.get();
121  else if (object_path == dbus::ObjectPath(kSecondAdapterPath))
122    return second_properties_.get();
123  else
124    return NULL;
125}
126
127void FakeBluetoothAdapterClient::StartDiscovery(
128    const dbus::ObjectPath& object_path,
129    const base::Closure& callback,
130    const ErrorCallback& error_callback) {
131  if (object_path != dbus::ObjectPath(kAdapterPath)) {
132    error_callback.Run(kNoResponseError, "");
133    return;
134  }
135
136  ++discovering_count_;
137  VLOG(1) << "StartDiscovery: " << object_path.value() << ", "
138          << "count is now " << discovering_count_;
139  callback.Run();
140
141  if (discovering_count_ == 1) {
142    properties_->discovering.ReplaceValue(true);
143
144    FakeBluetoothDeviceClient* device_client =
145        static_cast<FakeBluetoothDeviceClient*>(
146            DBusThreadManager::Get()->GetBluetoothDeviceClient());
147    device_client->BeginDiscoverySimulation(dbus::ObjectPath(kAdapterPath));
148  }
149}
150
151void FakeBluetoothAdapterClient::StopDiscovery(
152    const dbus::ObjectPath& object_path,
153    const base::Closure& callback,
154    const ErrorCallback& error_callback) {
155  if (object_path != dbus::ObjectPath(kAdapterPath)) {
156    error_callback.Run(kNoResponseError, "");
157    return;
158  }
159
160  if (!discovering_count_) {
161    LOG(WARNING) << "StopDiscovery called when not discovering";
162    error_callback.Run(kNoResponseError, "");
163    return;
164  }
165
166  --discovering_count_;
167  VLOG(1) << "StopDiscovery: " << object_path.value() << ", "
168          << "count is now " << discovering_count_;
169  callback.Run();
170
171  if (discovering_count_ == 0) {
172    FakeBluetoothDeviceClient* device_client =
173        static_cast<FakeBluetoothDeviceClient*>(
174            DBusThreadManager::Get()->GetBluetoothDeviceClient());
175    device_client->EndDiscoverySimulation(dbus::ObjectPath(kAdapterPath));
176
177    properties_->discovering.ReplaceValue(false);
178  }
179}
180
181void FakeBluetoothAdapterClient::RemoveDevice(
182    const dbus::ObjectPath& object_path,
183    const dbus::ObjectPath& device_path,
184    const base::Closure& callback,
185    const ErrorCallback& error_callback) {
186  if (object_path != dbus::ObjectPath(kAdapterPath)) {
187    error_callback.Run(kNoResponseError, "");
188    return;
189  }
190
191  VLOG(1) << "RemoveDevice: " << object_path.value()
192          << " " << device_path.value();
193  callback.Run();
194
195  FakeBluetoothDeviceClient* device_client =
196      static_cast<FakeBluetoothDeviceClient*>(
197          DBusThreadManager::Get()->GetBluetoothDeviceClient());
198  device_client->RemoveDevice(dbus::ObjectPath(kAdapterPath), device_path);
199}
200
201void FakeBluetoothAdapterClient::SetVisible(
202    bool visible) {
203  if (visible && !visible_) {
204    // Adapter becoming visible
205    visible_ = visible;
206
207    FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
208                      AdapterAdded(dbus::ObjectPath(kAdapterPath)));
209
210  } else if (visible_ && !visible) {
211    // Adapter becoming invisible
212    visible_ = visible;
213
214    FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
215                      AdapterRemoved(dbus::ObjectPath(kAdapterPath)));
216  }
217}
218
219void FakeBluetoothAdapterClient::SetSecondVisible(
220    bool visible) {
221  if (visible && !second_visible_) {
222    // Second adapter becoming visible
223    second_visible_ = visible;
224
225    FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
226                      AdapterAdded(dbus::ObjectPath(kSecondAdapterPath)));
227
228  } else if (second_visible_ && !visible) {
229    // Second adapter becoming invisible
230    second_visible_ = visible;
231
232    FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
233                      AdapterRemoved(dbus::ObjectPath(kSecondAdapterPath)));
234  }
235}
236
237void FakeBluetoothAdapterClient::OnPropertyChanged(
238    const std::string& property_name) {
239  if (property_name == properties_->powered.name() &&
240      !properties_->powered.value()) {
241    VLOG(1) << "Adapter powered off";
242
243    if (discovering_count_) {
244      discovering_count_ = 0;
245      properties_->discovering.ReplaceValue(false);
246    }
247  }
248
249  FOR_EACH_OBSERVER(BluetoothAdapterClient::Observer, observers_,
250                    AdapterPropertyChanged(dbus::ObjectPath(kAdapterPath),
251                                           property_name));
252}
253
254}  // namespace chromeos
255