Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chromeos / dbus / fake_bluetooth_gatt_characteristic_client.cc
1 // Copyright 2014 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_gatt_characteristic_client.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/rand_util.h"
10 #include "base/time/time.h"
11 #include "chromeos/dbus/dbus_thread_manager.h"
12 #include "chromeos/dbus/fake_bluetooth_gatt_descriptor_client.h"
13 #include "third_party/cros_system_api/dbus/service_constants.h"
14
15 namespace chromeos {
16
17 namespace {
18
19 const int kStartNotifyResponseIntervalMs = 200;
20 const int kHeartRateMeasurementNotificationIntervalMs = 2000;
21
22 }  // namespace
23
24 FakeBluetoothGattCharacteristicClient::DelayedCallback::DelayedCallback(
25     base::Closure callback,
26     size_t delay)
27     : callback_(callback), delay_(delay) {
28 }
29
30 FakeBluetoothGattCharacteristicClient::DelayedCallback::~DelayedCallback() {
31 }
32
33 // static
34 const char FakeBluetoothGattCharacteristicClient::
35     kHeartRateMeasurementPathComponent[] = "char0000";
36 const char FakeBluetoothGattCharacteristicClient::
37     kBodySensorLocationPathComponent[] = "char0001";
38 const char FakeBluetoothGattCharacteristicClient::
39     kHeartRateControlPointPathComponent[] = "char0002";
40
41 // static
42 const char FakeBluetoothGattCharacteristicClient::kHeartRateMeasurementUUID[] =
43     "00002a37-0000-1000-8000-00805f9b34fb";
44 const char FakeBluetoothGattCharacteristicClient::kBodySensorLocationUUID[] =
45     "00002a38-0000-1000-8000-00805f9b34fb";
46 const char FakeBluetoothGattCharacteristicClient::kHeartRateControlPointUUID[] =
47     "00002a39-0000-1000-8000-00805f9b34fb";
48
49 FakeBluetoothGattCharacteristicClient::Properties::Properties(
50     const PropertyChangedCallback& callback)
51     : BluetoothGattCharacteristicClient::Properties(
52           NULL,
53           bluetooth_gatt_characteristic::kBluetoothGattCharacteristicInterface,
54           callback) {
55 }
56
57 FakeBluetoothGattCharacteristicClient::Properties::~Properties() {
58 }
59
60 void FakeBluetoothGattCharacteristicClient::Properties::Get(
61     dbus::PropertyBase* property,
62     dbus::PropertySet::GetCallback callback) {
63   VLOG(1) << "Get " << property->name();
64   callback.Run(true);
65 }
66
67 void FakeBluetoothGattCharacteristicClient::Properties::GetAll() {
68   VLOG(1) << "GetAll";
69 }
70
71 void FakeBluetoothGattCharacteristicClient::Properties::Set(
72     dbus::PropertyBase* property,
73     dbus::PropertySet::SetCallback callback) {
74   VLOG(1) << "Set " << property->name();
75   callback.Run(false);
76 }
77
78 FakeBluetoothGattCharacteristicClient::FakeBluetoothGattCharacteristicClient()
79     : heart_rate_visible_(false),
80       authorized_(true),
81       authenticated_(true),
82       calories_burned_(0),
83       extra_requests_(0),
84       weak_ptr_factory_(this) {
85 }
86
87 FakeBluetoothGattCharacteristicClient::
88     ~FakeBluetoothGattCharacteristicClient() {
89   for (const auto& it : action_extra_requests_) {
90     delete it.second;
91   }
92   action_extra_requests_.clear();
93 }
94
95 void FakeBluetoothGattCharacteristicClient::Init(dbus::Bus* bus) {
96 }
97
98 void FakeBluetoothGattCharacteristicClient::AddObserver(Observer* observer) {
99   observers_.AddObserver(observer);
100 }
101
102 void FakeBluetoothGattCharacteristicClient::RemoveObserver(Observer* observer) {
103   observers_.RemoveObserver(observer);
104 }
105
106 std::vector<dbus::ObjectPath>
107 FakeBluetoothGattCharacteristicClient::GetCharacteristics() {
108   std::vector<dbus::ObjectPath> paths;
109   if (IsHeartRateVisible()) {
110     paths.push_back(dbus::ObjectPath(heart_rate_measurement_path_));
111     paths.push_back(dbus::ObjectPath(body_sensor_location_path_));
112     paths.push_back(dbus::ObjectPath(heart_rate_control_point_path_));
113   }
114   return paths;
115 }
116
117 FakeBluetoothGattCharacteristicClient::Properties*
118 FakeBluetoothGattCharacteristicClient::GetProperties(
119     const dbus::ObjectPath& object_path) {
120   if (object_path.value() == heart_rate_measurement_path_) {
121     DCHECK(heart_rate_measurement_properties_.get());
122     return heart_rate_measurement_properties_.get();
123   }
124   if (object_path.value() == body_sensor_location_path_) {
125     DCHECK(body_sensor_location_properties_.get());
126     return body_sensor_location_properties_.get();
127   }
128   if (object_path.value() == heart_rate_control_point_path_) {
129     DCHECK(heart_rate_control_point_properties_.get());
130     return heart_rate_control_point_properties_.get();
131   }
132   return NULL;
133 }
134
135 void FakeBluetoothGattCharacteristicClient::ReadValue(
136     const dbus::ObjectPath& object_path,
137     const ValueCallback& callback,
138     const ErrorCallback& error_callback) {
139   if (!authenticated_) {
140     error_callback.Run("org.bluez.Error.NotPaired", "Please login");
141     return;
142   }
143
144   if (!authorized_) {
145     error_callback.Run("org.bluez.Error.NotAuthorized", "Authorize first");
146     return;
147   }
148
149   if (object_path.value() == heart_rate_control_point_path_) {
150     error_callback.Run("org.bluez.Error.ReadNotPermitted",
151                        "Reads of this value are not allowed");
152     return;
153   }
154
155   if (object_path.value() == heart_rate_measurement_path_) {
156     error_callback.Run("org.bluez.Error.NotSupported",
157                        "Action not supported on this characteristic");
158     return;
159   }
160
161   if (object_path.value() != body_sensor_location_path_) {
162     error_callback.Run(kUnknownCharacteristicError, "");
163     return;
164   }
165
166   if (action_extra_requests_.find("ReadValue") !=
167       action_extra_requests_.end()) {
168     DelayedCallback* delayed = action_extra_requests_["ReadValue"];
169     delayed->delay_--;
170     error_callback.Run("org.bluez.Error.InProgress",
171                        "Another read is currenty in progress");
172     if (delayed->delay_ == 0) {
173       delayed->callback_.Run();
174       action_extra_requests_.erase("ReadValue");
175       delete delayed;
176     }
177     return;
178   }
179   base::Closure completed_callback;
180   if (!IsHeartRateVisible()) {
181     completed_callback =
182         base::Bind(error_callback, kUnknownCharacteristicError, "");
183   } else {
184     std::vector<uint8> value;
185     value.push_back(0x06);  // Location is "foot".
186     completed_callback = base::Bind(callback, value);
187   }
188
189   if (extra_requests_ > 0) {
190     action_extra_requests_["ReadValue"] =
191         new DelayedCallback(completed_callback, extra_requests_);
192     return;
193   }
194   completed_callback.Run();
195 }
196
197 void FakeBluetoothGattCharacteristicClient::WriteValue(
198     const dbus::ObjectPath& object_path,
199     const std::vector<uint8>& value,
200     const base::Closure& callback,
201     const ErrorCallback& error_callback) {
202   if (!authenticated_) {
203     error_callback.Run("org.bluez.Error.NotPaired", "Please login");
204     return;
205   }
206
207   if (!authorized_) {
208     error_callback.Run("org.bluez.Error.NotAuthorized", "Authorize first");
209     return;
210   }
211
212   if (!IsHeartRateVisible()) {
213     error_callback.Run(kUnknownCharacteristicError, "");
214     return;
215   }
216
217   if (object_path.value() == heart_rate_measurement_path_) {
218     error_callback.Run("org.bluez.Error.NotSupported",
219                        "Action not supported on this characteristic");
220     return;
221   }
222
223   if (object_path.value() != heart_rate_control_point_path_) {
224     error_callback.Run("org.bluez.Error.WriteNotPermitted",
225                        "Writes of this value are not allowed");
226     return;
227   }
228
229   DCHECK(heart_rate_control_point_properties_.get());
230   if (action_extra_requests_.find("WriteValue") !=
231       action_extra_requests_.end()) {
232     DelayedCallback* delayed = action_extra_requests_["WriteValue"];
233     delayed->delay_--;
234     error_callback.Run("org.bluez.Error.InProgress",
235                        "Another write is in progress");
236     if (delayed->delay_ == 0) {
237       delayed->callback_.Run();
238       action_extra_requests_.erase("WriteValue");
239       delete delayed;
240     }
241     return;
242   }
243   base::Closure completed_callback;
244   if (value.size() != 1) {
245     completed_callback = base::Bind(error_callback,
246                                     "org.bluez.Error.InvalidValueLength",
247                                     "Invalid length for write");
248   } else if (value[0] > 1) {
249     completed_callback = base::Bind(error_callback,
250                                     "org.bluez.Error.Failed",
251                                     "Invalid value given for write");
252   } else if (value[0] == 1) {
253     // TODO(jamuraa): make this happen when the callback happens
254     calories_burned_ = 0;
255     completed_callback = callback;
256   }
257
258   if (extra_requests_ > 0) {
259     action_extra_requests_["WriteValue"] =
260         new DelayedCallback(completed_callback, extra_requests_);
261     return;
262   }
263   completed_callback.Run();
264 }
265
266 void FakeBluetoothGattCharacteristicClient::StartNotify(
267     const dbus::ObjectPath& object_path,
268     const base::Closure& callback,
269     const ErrorCallback& error_callback) {
270   if (!IsHeartRateVisible()) {
271     error_callback.Run(kUnknownCharacteristicError, "");
272     return;
273   }
274
275   if (object_path.value() != heart_rate_measurement_path_) {
276     error_callback.Run("org.bluez.Error.NotSupported",
277                        "This characteristic does not support notifications");
278     return;
279   }
280
281   if (heart_rate_measurement_properties_->notifying.value()) {
282     error_callback.Run("org.bluez.Error.InProgress",
283                        "Characteristic already notifying");
284     return;
285   }
286
287   heart_rate_measurement_properties_->notifying.ReplaceValue(true);
288   ScheduleHeartRateMeasurementValueChange();
289
290   // Respond asynchronously.
291   base::MessageLoop::current()->PostDelayedTask(
292       FROM_HERE,
293       callback,
294       base::TimeDelta::FromMilliseconds(kStartNotifyResponseIntervalMs));
295 }
296
297 void FakeBluetoothGattCharacteristicClient::StopNotify(
298     const dbus::ObjectPath& object_path,
299     const base::Closure& callback,
300     const ErrorCallback& error_callback) {
301   if (!IsHeartRateVisible()) {
302     error_callback.Run(kUnknownCharacteristicError, "");
303     return;
304   }
305
306   if (object_path.value() != heart_rate_measurement_path_) {
307     error_callback.Run("org.bluez.Error.NotSupported",
308                        "This characteristic does not support notifications");
309     return;
310   }
311
312   if (!heart_rate_measurement_properties_->notifying.value()) {
313     error_callback.Run("org.bluez.Error.Failed", "Not notifying");
314     return;
315   }
316
317   heart_rate_measurement_properties_->notifying.ReplaceValue(false);
318
319   callback.Run();
320 }
321
322 void FakeBluetoothGattCharacteristicClient::ExposeHeartRateCharacteristics(
323     const dbus::ObjectPath& service_path) {
324   if (IsHeartRateVisible()) {
325     VLOG(2) << "Fake Heart Rate characteristics are already visible.";
326     return;
327   }
328
329   VLOG(2) << "Exposing fake Heart Rate characteristics.";
330
331   std::vector<std::string> flags;
332
333   // ==== Heart Rate Measurement Characteristic ====
334   heart_rate_measurement_path_ =
335       service_path.value() + "/" + kHeartRateMeasurementPathComponent;
336   heart_rate_measurement_properties_.reset(new Properties(base::Bind(
337       &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
338       weak_ptr_factory_.GetWeakPtr(),
339       dbus::ObjectPath(heart_rate_measurement_path_))));
340   heart_rate_measurement_properties_->uuid.ReplaceValue(
341       kHeartRateMeasurementUUID);
342   heart_rate_measurement_properties_->service.ReplaceValue(service_path);
343   flags.push_back(bluetooth_gatt_characteristic::kFlagNotify);
344   heart_rate_measurement_properties_->flags.ReplaceValue(flags);
345
346   // ==== Body Sensor Location Characteristic ====
347   body_sensor_location_path_ =
348       service_path.value() + "/" + kBodySensorLocationPathComponent;
349   body_sensor_location_properties_.reset(new Properties(base::Bind(
350       &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
351       weak_ptr_factory_.GetWeakPtr(),
352       dbus::ObjectPath(body_sensor_location_path_))));
353   body_sensor_location_properties_->uuid.ReplaceValue(kBodySensorLocationUUID);
354   body_sensor_location_properties_->service.ReplaceValue(service_path);
355   flags.clear();
356   flags.push_back(bluetooth_gatt_characteristic::kFlagRead);
357   body_sensor_location_properties_->flags.ReplaceValue(flags);
358
359   // ==== Heart Rate Control Point Characteristic ====
360   heart_rate_control_point_path_ =
361       service_path.value() + "/" + kHeartRateControlPointPathComponent;
362   heart_rate_control_point_properties_.reset(new Properties(base::Bind(
363       &FakeBluetoothGattCharacteristicClient::OnPropertyChanged,
364       weak_ptr_factory_.GetWeakPtr(),
365       dbus::ObjectPath(heart_rate_control_point_path_))));
366   heart_rate_control_point_properties_->uuid.ReplaceValue(
367       kHeartRateControlPointUUID);
368   heart_rate_control_point_properties_->service.ReplaceValue(service_path);
369   flags.clear();
370   flags.push_back(bluetooth_gatt_characteristic::kFlagWrite);
371   heart_rate_control_point_properties_->flags.ReplaceValue(flags);
372
373   heart_rate_visible_ = true;
374
375   NotifyCharacteristicAdded(dbus::ObjectPath(heart_rate_measurement_path_));
376   NotifyCharacteristicAdded(dbus::ObjectPath(body_sensor_location_path_));
377   NotifyCharacteristicAdded(dbus::ObjectPath(heart_rate_control_point_path_));
378
379   // Expose CCC descriptor for Heart Rate Measurement characteristic.
380   FakeBluetoothGattDescriptorClient* descriptor_client =
381       static_cast<FakeBluetoothGattDescriptorClient*>(
382           DBusThreadManager::Get()->GetBluetoothGattDescriptorClient());
383   dbus::ObjectPath ccc_path(descriptor_client->ExposeDescriptor(
384       dbus::ObjectPath(heart_rate_measurement_path_),
385       FakeBluetoothGattDescriptorClient::
386           kClientCharacteristicConfigurationUUID));
387   DCHECK(ccc_path.IsValid());
388   heart_rate_measurement_ccc_desc_path_ = ccc_path.value();
389
390   std::vector<dbus::ObjectPath> desc_paths;
391   desc_paths.push_back(ccc_path);
392
393   heart_rate_measurement_properties_->descriptors.ReplaceValue(desc_paths);
394 }
395
396 void FakeBluetoothGattCharacteristicClient::HideHeartRateCharacteristics() {
397   VLOG(2) << "Hiding fake Heart Rate characteristics.";
398
399   // Hide the descriptors.
400   FakeBluetoothGattDescriptorClient* descriptor_client =
401       static_cast<FakeBluetoothGattDescriptorClient*>(
402           DBusThreadManager::Get()->GetBluetoothGattDescriptorClient());
403   descriptor_client->HideDescriptor(
404       dbus::ObjectPath(heart_rate_measurement_ccc_desc_path_));
405
406   // Notify the observers before deleting the properties structures so that they
407   // can be accessed from the observer method.
408   NotifyCharacteristicRemoved(dbus::ObjectPath(heart_rate_measurement_path_));
409   NotifyCharacteristicRemoved(dbus::ObjectPath(body_sensor_location_path_));
410   NotifyCharacteristicRemoved(dbus::ObjectPath(heart_rate_control_point_path_));
411
412   heart_rate_measurement_properties_.reset();
413   body_sensor_location_properties_.reset();
414   heart_rate_control_point_properties_.reset();
415
416   heart_rate_measurement_path_.clear();
417   body_sensor_location_path_.clear();
418   heart_rate_control_point_path_.clear();
419   heart_rate_visible_ = false;
420 }
421
422 void FakeBluetoothGattCharacteristicClient::SetExtraProcessing(
423     size_t requests) {
424   extra_requests_ = requests;
425   if (extra_requests_ == 0) {
426     for (const auto& it : action_extra_requests_) {
427       it.second->callback_.Run();
428       delete it.second;
429     }
430     action_extra_requests_.clear();
431     return;
432   }
433   VLOG(2) << "Requests SLOW now, " << requests << " InProgress errors each.";
434 }
435
436 size_t FakeBluetoothGattCharacteristicClient::GetExtraProcessing() const {
437   return extra_requests_;
438 }
439
440 dbus::ObjectPath
441 FakeBluetoothGattCharacteristicClient::GetHeartRateMeasurementPath() const {
442   return dbus::ObjectPath(heart_rate_measurement_path_);
443 }
444
445 dbus::ObjectPath
446 FakeBluetoothGattCharacteristicClient::GetBodySensorLocationPath() const {
447   return dbus::ObjectPath(body_sensor_location_path_);
448 }
449
450 dbus::ObjectPath
451 FakeBluetoothGattCharacteristicClient::GetHeartRateControlPointPath() const {
452   return dbus::ObjectPath(heart_rate_control_point_path_);
453 }
454
455 void FakeBluetoothGattCharacteristicClient::OnPropertyChanged(
456     const dbus::ObjectPath& object_path,
457     const std::string& property_name) {
458   VLOG(2) << "Characteristic property changed: " << object_path.value()
459           << ": " << property_name;
460
461   FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
462                     GattCharacteristicPropertyChanged(
463                         object_path, property_name));
464 }
465
466 void FakeBluetoothGattCharacteristicClient::NotifyCharacteristicAdded(
467     const dbus::ObjectPath& object_path) {
468   VLOG(2) << "GATT characteristic added: " << object_path.value();
469   FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
470                     GattCharacteristicAdded(object_path));
471 }
472
473 void FakeBluetoothGattCharacteristicClient::NotifyCharacteristicRemoved(
474     const dbus::ObjectPath& object_path) {
475   VLOG(2) << "GATT characteristic removed: " << object_path.value();
476   FOR_EACH_OBSERVER(BluetoothGattCharacteristicClient::Observer, observers_,
477                     GattCharacteristicRemoved(object_path));
478 }
479
480 void FakeBluetoothGattCharacteristicClient::
481     ScheduleHeartRateMeasurementValueChange() {
482   if (!IsHeartRateVisible())
483     return;
484
485   // Don't send updates if the characteristic is not notifying.
486   if (!heart_rate_measurement_properties_->notifying.value())
487     return;
488
489   VLOG(2) << "Updating heart rate value.";
490   std::vector<uint8> measurement = GetHeartRateMeasurementValue();
491
492   FOR_EACH_OBSERVER(
493       BluetoothGattCharacteristicClient::Observer,
494       observers_,
495       GattCharacteristicValueUpdated(
496           dbus::ObjectPath(heart_rate_measurement_path_), measurement));
497
498   base::MessageLoop::current()->PostDelayedTask(
499       FROM_HERE,
500       base::Bind(&FakeBluetoothGattCharacteristicClient::
501                      ScheduleHeartRateMeasurementValueChange,
502                  weak_ptr_factory_.GetWeakPtr()),
503                  base::TimeDelta::FromMilliseconds(
504                      kHeartRateMeasurementNotificationIntervalMs));
505 }
506
507 std::vector<uint8>
508 FakeBluetoothGattCharacteristicClient::GetHeartRateMeasurementValue() {
509   // TODO(armansito): We should make sure to properly pack this struct to ensure
510   // correct byte alignment and endianness. It doesn't matter too much right now
511   // as this is a fake and GCC on Linux seems to do the right thing.
512   struct {
513     uint8 flags;
514     uint8 bpm;
515     uint16 energy_expanded;
516     uint16 rr_interval;
517   } value;
518
519   // Flags in LSB:     0       11   1 1 000
520   //                   |       |    | | |
521   // 8-bit bpm format --       |    | | |
522   // Sensor contact supported --    | | |
523   // Energy expanded field present -- | |
524   // RR-Interval values present ------- |
525   // Reserved for future use ------------
526   value.flags = 0x0;
527   value.flags |= (0x03 << 1);
528   value.flags |= (0x01 << 3);
529   value.flags |= (0x01 << 4);
530
531   // Pick a value between 117 bpm and 153 bpm for heart rate.
532   value.bpm = static_cast<uint8>(base::RandInt(117, 153));
533
534   // Total calories burned in kJoules since the last reset. Increment this by 1
535   // every time. It's fine if it overflows: it becomes 0 when the user resets
536   // the heart rate monitor (or pretend that he had a lot of cheeseburgers).
537   value.energy_expanded = calories_burned_++;
538
539   // Include one RR-Interval value, in seconds.
540   value.rr_interval = 60/value.bpm;
541
542   // Return the bytes in an array.
543   uint8* bytes = reinterpret_cast<uint8*>(&value);
544   std::vector<uint8> return_value;
545   return_value.assign(bytes, bytes + sizeof(value));
546   return return_value;
547 }
548
549 bool FakeBluetoothGattCharacteristicClient::IsHeartRateVisible() const {
550   DCHECK(heart_rate_visible_ != heart_rate_measurement_path_.empty());
551   DCHECK(heart_rate_visible_ != body_sensor_location_path_.empty());
552   DCHECK(heart_rate_visible_ != heart_rate_control_point_path_.empty());
553   DCHECK(heart_rate_visible_ == !!heart_rate_measurement_properties_.get());
554   DCHECK(heart_rate_visible_ == !!body_sensor_location_properties_.get());
555   DCHECK(heart_rate_visible_ == !!heart_rate_control_point_properties_.get());
556   return heart_rate_visible_;
557 }
558
559 }  // namespace chromeos